linera_chain/certificate/
confirmed.rs1use std::{borrow::Cow, ops::Deref};
6
7use allocative::Allocative;
8use linera_base::{
9 crypto::{CryptoHash, ValidatorPublicKey, ValidatorSignature},
10 data_types::{Epoch, Round},
11 identifiers::ChainId,
12};
13use linera_execution::committee::Committee;
14use serde::{Deserialize, Deserializer, Serialize, Serializer};
15
16use super::{generic::GenericCertificate, Certificate, Certified, LiteCertificate};
17use crate::{
18 block::{Block, ConfirmedBlock, ConversionError},
19 data_types::MessageBundle,
20 justification::JustificationChain,
21 ChainError,
22};
23
24#[derive(serde::Serialize, serde::Deserialize)]
28#[serde(rename = "ConfirmedBlockCertificate")]
29struct Repr<'a> {
30 value: Cow<'a, ConfirmedBlock>,
31 round: Round,
32 first_round: bool,
33 justification_commitment: Option<CryptoHash>,
34 signatures: Cow<'a, [(ValidatorPublicKey, ValidatorSignature)]>,
35 justification: Cow<'a, JustificationChain>,
36}
37
38#[derive(Clone, Debug, Allocative)]
45#[cfg_attr(with_testing, derive(Eq, PartialEq))]
46pub struct ConfirmedBlockCertificate {
47 quorum: GenericCertificate<ConfirmedBlock>,
49 justification: JustificationChain,
53}
54
55impl ConfirmedBlockCertificate {
56 pub fn new(
58 value: ConfirmedBlock,
59 round: Round,
60 signatures: Vec<(ValidatorPublicKey, ValidatorSignature)>,
61 ) -> Self {
62 Self {
63 quorum: GenericCertificate::new(value, round, signatures),
64 justification: JustificationChain::default(),
65 }
66 }
67
68 pub fn from_parts(
70 quorum: GenericCertificate<ConfirmedBlock>,
71 justification: JustificationChain,
72 ) -> Self {
73 Self {
74 quorum,
75 justification,
76 }
77 }
78
79 pub fn quorum(&self) -> &GenericCertificate<ConfirmedBlock> {
81 &self.quorum
82 }
83
84 pub fn justification(&self) -> &JustificationChain {
86 &self.justification
87 }
88
89 pub fn into_parts(self) -> (GenericCertificate<ConfirmedBlock>, JustificationChain) {
91 (self.quorum, self.justification)
92 }
93
94 pub fn round(&self) -> Round {
96 self.quorum.round()
97 }
98
99 pub fn into_value(self) -> ConfirmedBlock {
101 self.quorum.into_value()
102 }
103
104 pub fn into_inner(self) -> ConfirmedBlock {
106 self.quorum.into_inner()
107 }
108
109 pub fn check(&self, committee: &Committee) -> Result<(), ChainError> {
126 self.lite_certificate().check(committee)?;
127 Ok(())
128 }
129
130 pub fn lite_certificate(&self) -> LiteCertificate<'_> {
132 let mut lite = self.quorum.lite_certificate_without_justification();
133 lite.justification = Cow::Borrowed(&self.justification);
134 lite
135 }
136}
137
138impl Deref for ConfirmedBlockCertificate {
139 type Target = GenericCertificate<ConfirmedBlock>;
140
141 fn deref(&self) -> &Self::Target {
142 &self.quorum
143 }
144}
145
146impl Certified for ConfirmedBlockCertificate {
147 type Value = ConfirmedBlock;
148
149 fn value(&self) -> &ConfirmedBlock {
150 self.quorum.value()
151 }
152
153 fn round(&self) -> Round {
154 ConfirmedBlockCertificate::round(self)
155 }
156
157 fn unlocking_round(&self) -> Option<Round> {
158 self.quorum.unlocking_round()
159 }
160
161 fn signatures(&self) -> &Vec<(ValidatorPublicKey, ValidatorSignature)> {
162 self.quorum.signatures()
163 }
164
165 fn lite_certificate(&self) -> LiteCertificate<'_> {
166 ConfirmedBlockCertificate::lite_certificate(self)
167 }
168
169 fn check(&self, committee: &Committee) -> Result<(), ChainError> {
170 ConfirmedBlockCertificate::check(self, committee)
171 }
172}
173
174impl GenericCertificate<ConfirmedBlock> {
175 pub fn block(&self) -> &Block {
177 self.inner().block()
178 }
179
180 pub fn message_bundles_for(
184 &self,
185 recipient: ChainId,
186 ) -> impl Iterator<Item = (Epoch, MessageBundle)> + '_ {
187 let certificate_hash = self.hash();
188 self.block()
189 .message_bundles_for(recipient, certificate_hash)
190 }
191
192 #[cfg(with_testing)]
194 pub fn outgoing_message_count(&self) -> usize {
195 self.block().messages().iter().map(Vec::len).sum()
196 }
197}
198
199impl TryFrom<Certificate> for ConfirmedBlockCertificate {
200 type Error = ConversionError;
201
202 fn try_from(cert: Certificate) -> Result<Self, Self::Error> {
203 match cert {
204 Certificate::Confirmed(confirmed) => Ok(confirmed),
205 _ => Err(ConversionError::ConfirmedBlock),
206 }
207 }
208}
209
210impl From<ConfirmedBlockCertificate> for Certificate {
211 fn from(cert: ConfirmedBlockCertificate) -> Certificate {
212 Certificate::Confirmed(cert)
213 }
214}
215
216impl From<&ConfirmedBlockCertificate> for Certificate {
217 fn from(cert: &ConfirmedBlockCertificate) -> Certificate {
218 Certificate::Confirmed(cert.clone())
219 }
220}
221
222impl Serialize for ConfirmedBlockCertificate {
223 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
224 where
225 S: Serializer,
226 {
227 Repr {
228 value: Cow::Borrowed(self.quorum.inner()),
229 round: self.quorum.round(),
230 first_round: self.quorum.first_round(),
231 justification_commitment: self.quorum.justification_commitment(),
232 signatures: Cow::Borrowed(self.quorum.signatures().as_slice()),
233 justification: Cow::Borrowed(&self.justification),
234 }
235 .serialize(serializer)
236 }
237}
238
239impl<'de> Deserialize<'de> for ConfirmedBlockCertificate {
240 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
241 where
242 D: Deserializer<'de>,
243 {
244 let helper = Repr::deserialize(deserializer)?;
245 let signatures = helper.signatures.into_owned();
246 if !crate::data_types::is_strictly_ordered(&signatures) {
247 Err(serde::de::Error::custom("Vector is not strictly sorted"))
248 } else {
249 Ok(Self::from_parts(
250 GenericCertificate::new_with_payload(
251 helper.value.into_owned(),
252 helper.round,
253 None,
254 helper.first_round,
255 helper.justification_commitment,
256 signatures,
257 ),
258 helper.justification.into_owned(),
259 ))
260 }
261 }
262}