Skip to main content

linera_chain/certificate/
mod.rs

1// Copyright (c) Facebook, Inc. and its affiliates.
2// Copyright (c) Zefchain Labs, Inc.
3// SPDX-License-Identifier: Apache-2.0
4
5mod confirmed;
6mod generic;
7mod lite;
8mod timeout;
9mod validated;
10
11use std::collections::BTreeSet;
12
13use allocative::Allocative;
14pub use confirmed::ConfirmedBlockCertificate;
15pub use generic::GenericCertificate;
16use linera_base::{
17    crypto::{CryptoHash, ValidatorPublicKey, ValidatorSignature},
18    data_types::{BlockHeight, Epoch, Round},
19    identifiers::{BlobId, ChainId},
20};
21use linera_execution::committee::Committee;
22pub use lite::LiteCertificate;
23use serde::{Deserialize, Serialize};
24pub use validated::ValidatedBlockCertificate;
25
26use crate::{
27    types::{ConfirmedBlock, Timeout, ValidatedBlock},
28    ChainError,
29};
30
31/// Certificate for a [`Timeout`] instance.
32/// A timeout certificate means that the next consensus round has begun.
33pub type TimeoutCertificate = GenericCertificate<Timeout>;
34
35/// The common read interface shared by all certificate types: the signed value, the round and
36/// unlocking round it was certified under, its signatures, and verification.
37pub trait Certified {
38    /// The kind of value this certificate certifies.
39    type Value: CertificateValue;
40
41    /// Returns a reference to the certified value.
42    fn value(&self) -> &Self::Value;
43
44    /// Returns the round in which the value was certified.
45    fn round(&self) -> Round;
46
47    /// Returns the unlocking round the `ValidatedBlock` voters signed, if any.
48    fn unlocking_round(&self) -> Option<Round>;
49
50    /// Returns the validator signatures certifying this value.
51    fn signatures(&self) -> &Vec<(ValidatorPublicKey, ValidatorSignature)>;
52
53    /// Returns the certified value's hash.
54    fn hash(&self) -> CryptoHash {
55        self.value().hash()
56    }
57
58    /// Returns the [`LiteCertificate`] corresponding to this certificate, without the value but
59    /// with the justification chain.
60    fn lite_certificate(&self) -> LiteCertificate<'_>;
61
62    /// Verifies the certificate, including its justification chain.
63    fn check(&self, committee: &Committee) -> Result<(), ChainError>;
64
65    /// Returns whether the validator is among the signatories of this certificate.
66    fn is_signed_by(&self, validator_name: &ValidatorPublicKey) -> bool {
67        self.signatures()
68            .binary_search_by(|(name, _)| name.cmp(validator_name))
69            .is_ok()
70    }
71}
72
73impl<T: CertificateValue> Certified for GenericCertificate<T> {
74    type Value = T;
75
76    fn value(&self) -> &T {
77        GenericCertificate::value(self)
78    }
79
80    fn round(&self) -> Round {
81        GenericCertificate::round(self)
82    }
83
84    fn unlocking_round(&self) -> Option<Round> {
85        GenericCertificate::unlocking_round(self)
86    }
87
88    fn signatures(&self) -> &Vec<(ValidatorPublicKey, ValidatorSignature)> {
89        GenericCertificate::signatures(self)
90    }
91
92    fn lite_certificate(&self) -> LiteCertificate<'_> {
93        GenericCertificate::lite_certificate_without_justification(self)
94    }
95
96    fn check(&self, committee: &Committee) -> Result<(), ChainError> {
97        GenericCertificate::check(self, committee)
98    }
99}
100
101/// Enum wrapping all types of certificates that can be created.
102/// A certified statement from the committee.
103/// Every certificate is a statement signed by the quorum of the committee.
104#[derive(Debug, Clone, Serialize, Deserialize)]
105#[cfg_attr(with_testing, derive(Eq, PartialEq))]
106pub enum Certificate {
107    /// Certificate for [`ValidatedBlock`].
108    Validated(ValidatedBlockCertificate),
109    /// Certificate for [`ConfirmedBlock`].
110    Confirmed(ConfirmedBlockCertificate),
111    /// Certificate for [`Timeout`].
112    Timeout(TimeoutCertificate),
113}
114
115impl Certificate {
116    /// Returns the consensus round in which this certificate was created.
117    pub fn round(&self) -> Round {
118        match self {
119            Certificate::Validated(cert) => cert.round(),
120            Certificate::Confirmed(cert) => cert.round(),
121            Certificate::Timeout(cert) => cert.round(),
122        }
123    }
124
125    /// Returns the block height this certificate applies to.
126    pub fn height(&self) -> BlockHeight {
127        match self {
128            Certificate::Validated(cert) => cert.value().block().header.height,
129            Certificate::Confirmed(cert) => cert.value().block().header.height,
130            Certificate::Timeout(cert) => cert.value().height(),
131        }
132    }
133
134    /// Returns the ID of the chain this certificate applies to.
135    pub fn chain_id(&self) -> ChainId {
136        match self {
137            Certificate::Validated(cert) => cert.value().block().header.chain_id,
138            Certificate::Confirmed(cert) => cert.value().block().header.chain_id,
139            Certificate::Timeout(cert) => cert.value().chain_id(),
140        }
141    }
142
143    /// Returns the validator signatures that certify this value.
144    pub fn signatures(&self) -> &Vec<(ValidatorPublicKey, ValidatorSignature)> {
145        match self {
146            Certificate::Validated(cert) => cert.signatures(),
147            Certificate::Confirmed(cert) => cert.signatures(),
148            Certificate::Timeout(cert) => cert.signatures(),
149        }
150    }
151}
152
153/// The kind of value a certificate certifies.
154#[derive(Clone, Copy, Debug, Serialize, Deserialize, Hash, Eq, PartialEq, Allocative)]
155#[repr(u8)]
156#[allow(missing_docs)]
157pub enum CertificateKind {
158    Timeout = 0,
159    Validated = 1,
160    Confirmed = 2,
161}
162
163/// A value that can be certified by a quorum of validators.
164pub trait CertificateValue: Clone {
165    /// The kind of certificate this value produces.
166    const KIND: CertificateKind;
167
168    /// Returns the ID of the chain this value applies to.
169    fn chain_id(&self) -> ChainId;
170
171    /// Returns the epoch this value belongs to.
172    fn epoch(&self) -> Epoch;
173
174    /// Returns the block height this value applies to.
175    fn height(&self) -> BlockHeight;
176
177    /// Returns the IDs of all blobs required to validate this value.
178    fn required_blob_ids(&self) -> BTreeSet<BlobId>;
179
180    /// Returns the hash that uniquely identifies this value.
181    fn hash(&self) -> CryptoHash;
182}
183
184impl CertificateValue for Timeout {
185    const KIND: CertificateKind = CertificateKind::Timeout;
186
187    fn chain_id(&self) -> ChainId {
188        self.chain_id()
189    }
190
191    fn epoch(&self) -> Epoch {
192        self.epoch()
193    }
194
195    fn height(&self) -> BlockHeight {
196        self.height()
197    }
198
199    fn required_blob_ids(&self) -> BTreeSet<BlobId> {
200        BTreeSet::new()
201    }
202
203    fn hash(&self) -> CryptoHash {
204        self.inner().hash()
205    }
206}
207
208impl CertificateValue for ValidatedBlock {
209    const KIND: CertificateKind = CertificateKind::Validated;
210
211    fn chain_id(&self) -> ChainId {
212        self.block().header.chain_id
213    }
214
215    fn epoch(&self) -> Epoch {
216        self.block().header.epoch
217    }
218
219    fn height(&self) -> BlockHeight {
220        self.block().header.height
221    }
222
223    fn required_blob_ids(&self) -> BTreeSet<BlobId> {
224        self.block().required_blob_ids()
225    }
226
227    fn hash(&self) -> CryptoHash {
228        self.inner().hash()
229    }
230}
231
232impl CertificateValue for ConfirmedBlock {
233    const KIND: CertificateKind = CertificateKind::Confirmed;
234
235    fn chain_id(&self) -> ChainId {
236        self.block().header.chain_id
237    }
238
239    fn epoch(&self) -> Epoch {
240        self.block().header.epoch
241    }
242
243    fn height(&self) -> BlockHeight {
244        self.block().header.height
245    }
246
247    fn required_blob_ids(&self) -> BTreeSet<BlobId> {
248        self.block().required_blob_ids()
249    }
250
251    fn hash(&self) -> CryptoHash {
252        self.inner().hash()
253    }
254}