linera_chain/certificate/
validated.rs1use std::{borrow::Cow, ops::Deref};
6
7use allocative::Allocative;
8use linera_base::{
9 crypto::{CryptoHash, ValidatorPublicKey, ValidatorSignature},
10 data_types::Round,
11};
12use linera_execution::committee::Committee;
13use serde::{
14 ser::{Serialize, Serializer},
15 Deserialize, Deserializer,
16};
17
18use super::{generic::GenericCertificate, Certificate, Certified, LiteCertificate};
19use crate::{
20 block::{Block, ConversionError, ValidatedBlock},
21 justification::JustificationChain,
22 ChainError,
23};
24
25#[derive(serde::Serialize, serde::Deserialize)]
29#[serde(rename = "ValidatedBlockCertificate")]
30struct Repr<'a> {
31 value: Cow<'a, ValidatedBlock>,
32 round: Round,
33 unlocking_round: Option<Round>,
34 justification_commitment: Option<CryptoHash>,
35 signatures: Cow<'a, [(ValidatorPublicKey, ValidatorSignature)]>,
36 justification: Cow<'a, JustificationChain>,
37}
38
39#[derive(Clone, Debug, Allocative)]
47#[cfg_attr(with_testing, derive(Eq, PartialEq))]
48pub struct ValidatedBlockCertificate {
49 quorum: GenericCertificate<ValidatedBlock>,
52 justification: JustificationChain,
56}
57
58impl ValidatedBlockCertificate {
59 pub fn new(
61 value: ValidatedBlock,
62 round: Round,
63 signatures: Vec<(ValidatorPublicKey, ValidatorSignature)>,
64 ) -> Self {
65 Self {
66 quorum: GenericCertificate::new(value, round, signatures),
67 justification: JustificationChain::default(),
68 }
69 }
70
71 pub fn from_parts(
73 quorum: GenericCertificate<ValidatedBlock>,
74 justification: JustificationChain,
75 ) -> Self {
76 Self {
77 quorum,
78 justification,
79 }
80 }
81
82 pub fn quorum(&self) -> &GenericCertificate<ValidatedBlock> {
84 &self.quorum
85 }
86
87 pub fn justification(&self) -> &JustificationChain {
89 &self.justification
90 }
91
92 pub fn into_parts(self) -> (GenericCertificate<ValidatedBlock>, JustificationChain) {
94 (self.quorum, self.justification)
95 }
96
97 pub fn round(&self) -> Round {
99 self.quorum.round()
100 }
101
102 pub fn into_value(self) -> ValidatedBlock {
104 self.quorum.into_value()
105 }
106
107 pub fn into_inner(self) -> ValidatedBlock {
109 self.quorum.into_inner()
110 }
111
112 pub fn full_justification(&self) -> JustificationChain {
116 self.justification
117 .append(self.quorum.round(), self.quorum.signatures().clone())
118 }
119
120 pub fn full_justification_commitment(&self) -> CryptoHash {
126 crate::justification::CommittedQuorum {
127 value_hash: self.hash(),
128 round: self.quorum.round(),
129 unlocking_round: self.quorum.unlocking_round(),
130 previous: self.quorum.justification_commitment(),
131 signatures: self.quorum.signatures().clone(),
132 }
133 .commitment()
134 }
135
136 pub fn check(&self, committee: &Committee) -> Result<(), ChainError> {
141 self.lite_certificate().check(committee)?;
142 Ok(())
143 }
144
145 pub fn lite_certificate(&self) -> LiteCertificate<'_> {
147 let mut lite = self.quorum.lite_certificate_without_justification();
148 lite.justification = Cow::Borrowed(&self.justification);
149 lite
150 }
151}
152
153impl Deref for ValidatedBlockCertificate {
154 type Target = GenericCertificate<ValidatedBlock>;
155
156 fn deref(&self) -> &Self::Target {
157 &self.quorum
158 }
159}
160
161impl Certified for ValidatedBlockCertificate {
162 type Value = ValidatedBlock;
163
164 fn value(&self) -> &ValidatedBlock {
165 self.quorum.value()
166 }
167
168 fn round(&self) -> Round {
169 ValidatedBlockCertificate::round(self)
170 }
171
172 fn unlocking_round(&self) -> Option<Round> {
173 self.quorum.unlocking_round()
174 }
175
176 fn signatures(&self) -> &Vec<(ValidatorPublicKey, ValidatorSignature)> {
177 self.quorum.signatures()
178 }
179
180 fn lite_certificate(&self) -> LiteCertificate<'_> {
181 ValidatedBlockCertificate::lite_certificate(self)
182 }
183
184 fn check(&self, committee: &Committee) -> Result<(), ChainError> {
185 ValidatedBlockCertificate::check(self, committee)
186 }
187}
188
189impl GenericCertificate<ValidatedBlock> {
190 #[cfg(with_testing)]
192 pub fn outgoing_message_count(&self) -> usize {
193 self.block().messages().iter().map(Vec::len).sum()
194 }
195
196 pub fn block(&self) -> &Block {
198 self.inner().block()
199 }
200}
201
202impl TryFrom<Certificate> for ValidatedBlockCertificate {
203 type Error = ConversionError;
204
205 fn try_from(cert: Certificate) -> Result<Self, Self::Error> {
206 match cert {
207 Certificate::Validated(validated) => Ok(validated),
208 _ => Err(ConversionError::ValidatedBlock),
209 }
210 }
211}
212
213impl From<ValidatedBlockCertificate> for Certificate {
214 fn from(cert: ValidatedBlockCertificate) -> Certificate {
215 Certificate::Validated(cert)
216 }
217}
218
219impl Serialize for ValidatedBlockCertificate {
220 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
221 Repr {
222 value: Cow::Borrowed(self.quorum.inner()),
223 round: self.quorum.round(),
224 unlocking_round: self.quorum.unlocking_round(),
225 justification_commitment: self.quorum.justification_commitment(),
226 signatures: Cow::Borrowed(self.quorum.signatures().as_slice()),
227 justification: Cow::Borrowed(&self.justification),
228 }
229 .serialize(serializer)
230 }
231}
232
233impl<'de> Deserialize<'de> for ValidatedBlockCertificate {
234 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
235 where
236 D: Deserializer<'de>,
237 {
238 let inner = Repr::deserialize(deserializer)?;
239 let signatures = inner.signatures.into_owned();
240 if !crate::data_types::is_strictly_ordered(&signatures) {
241 Err(serde::de::Error::custom(
242 "Signatures are not strictly ordered",
243 ))
244 } else {
245 Ok(Self::from_parts(
246 GenericCertificate::new_with_payload(
247 inner.value.into_owned(),
248 inner.round,
249 inner.unlocking_round,
250 false,
251 inner.justification_commitment,
252 signatures,
253 ),
254 inner.justification.into_owned(),
255 ))
256 }
257 }
258}