linera_chain/certificate/
lite.rs1use std::{borrow::Cow, ops::Deref};
6
7use allocative::{Allocative, Key, Visitor};
8use linera_base::{
9 crypto::{ValidatorPublicKey, ValidatorSignature},
10 data_types::Round,
11};
12use linera_execution::committee::Committee;
13use serde::{Deserialize, Serialize};
14
15use super::{CertificateValue, GenericCertificate};
16use crate::{
17 data_types::{check_signatures, LiteValue, LiteVote},
18 ChainError,
19};
20
21#[derive(Clone, Debug, Serialize, Deserialize)]
23#[cfg_attr(with_testing, derive(Eq, PartialEq))]
24pub struct LiteCertificate<'a> {
25 pub value: LiteValue,
27 pub round: Round,
29 pub signatures: Cow<'a, [(ValidatorPublicKey, ValidatorSignature)]>,
31}
32
33impl Allocative for LiteCertificate<'_> {
34 fn visit<'a, 'b: 'a>(&self, visitor: &'a mut Visitor<'b>) {
35 visitor.visit_field(Key::new("LiteCertificate_value"), &self.value);
36 visitor.visit_field(Key::new("LiteCertificate_round"), &self.round);
37 if matches!(self.signatures, Cow::Owned(_)) {
38 for (public_key, signature) in self.signatures.deref() {
39 visitor.visit_field(Key::new("ValidatorPublicKey"), public_key);
40 visitor.visit_field(Key::new("ValidatorSignature"), signature);
41 }
42 }
43 }
44}
45
46impl LiteCertificate<'_> {
47 pub fn new(
48 value: LiteValue,
49 round: Round,
50 mut signatures: Vec<(ValidatorPublicKey, ValidatorSignature)>,
51 ) -> Self {
52 signatures.sort_by_key(|&(validator_name, _)| validator_name);
53
54 let signatures = Cow::Owned(signatures);
55 Self {
56 value,
57 round,
58 signatures,
59 }
60 }
61
62 pub fn try_from_votes(
65 votes: impl IntoIterator<Item = (ValidatorPublicKey, LiteVote)>,
66 ) -> Option<Self> {
67 let mut votes = votes.into_iter();
68 let (
69 public_key,
70 LiteVote {
71 value,
72 round,
73 signature,
74 },
75 ) = votes.next()?;
76 let mut signatures = vec![(public_key, signature)];
77 for (validator_key, vote) in votes {
78 if vote.value.value_hash != value.value_hash || vote.round != round {
79 return None;
80 }
81 signatures.push((validator_key, vote.signature));
82 }
83 Some(LiteCertificate::new(value, round, signatures))
84 }
85
86 pub fn check(&self, committee: &Committee) -> Result<&LiteValue, ChainError> {
88 check_signatures(
89 self.value.value_hash,
90 self.value.kind,
91 self.round,
92 &self.signatures,
93 committee,
94 )?;
95 Ok(&self.value)
96 }
97
98 pub fn check_value<T: CertificateValue>(&self, value: &T) -> bool {
100 self.value.chain_id == value.chain_id()
101 && T::KIND == self.value.kind
102 && self.value.value_hash == value.hash()
103 }
104
105 pub fn with_value<T: CertificateValue>(self, value: T) -> Option<GenericCertificate<T>> {
107 if self.value.chain_id != value.chain_id()
108 || T::KIND != self.value.kind
109 || self.value.value_hash != value.hash()
110 {
111 return None;
112 }
113 Some(GenericCertificate::new(
114 value,
115 self.round,
116 self.signatures.into_owned(),
117 ))
118 }
119
120 pub fn cloned(&self) -> LiteCertificate<'static> {
122 LiteCertificate {
123 value: self.value.clone(),
124 round: self.round,
125 signatures: Cow::Owned(self.signatures.clone().into_owned()),
126 }
127 }
128}