hotshot_types/
simple_certificate.rs

1// Copyright (c) 2021-2024 Espresso Systems (espressosys.com)
2// This file is part of the HotShot repository.
3
4// You should have received a copy of the MIT License
5// along with the HotShot repository. If not, see <https://mit-license.org/>.
6
7//! Implementations of the simple certificate type.  Used for Quorum, DA, and Timeout Certificates
8
9use std::{
10    fmt::{self, Debug, Display, Formatter},
11    future::Future,
12    hash::Hash,
13    marker::PhantomData,
14};
15
16use alloy::primitives::U256;
17use committable::{Commitment, Committable};
18use hotshot_utils::anytrace::*;
19use serde::{Deserialize, Serialize};
20
21use crate::{
22    data::serialize_signature2,
23    epoch_membership::EpochMembership,
24    light_client::{LightClientState, StakeTableState},
25    message::UpgradeLock,
26    simple_vote::{
27        DaData, DaData2, HasEpoch, NextEpochQuorumData2, QuorumData, QuorumData2, QuorumMarker,
28        TimeoutData, TimeoutData2, UpgradeProposalData, VersionedVoteData, ViewSyncCommitData,
29        ViewSyncCommitData2, ViewSyncFinalizeData, ViewSyncFinalizeData2, ViewSyncPreCommitData,
30        ViewSyncPreCommitData2, Voteable,
31    },
32    stake_table::{HSStakeTable, StakeTableEntries},
33    traits::{
34        node_implementation::{ConsensusTime, NodeType, Versions},
35        signature_key::{SignatureKey, StateSignatureKey},
36    },
37    vote::{Certificate, HasViewNumber},
38    PeerConfig,
39};
40
41/// Trait which allows use to inject different threshold calculations into a Certificate type
42pub trait Threshold<TYPES: NodeType> {
43    /// Calculate a threshold based on the membership
44    fn threshold(membership: &EpochMembership<TYPES>) -> impl Future<Output = U256> + Send;
45}
46
47/// Defines a threshold which is 2f + 1 (Amount needed for Quorum)
48#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
49pub struct SuccessThreshold {}
50
51impl<TYPES: NodeType> Threshold<TYPES> for SuccessThreshold {
52    async fn threshold(membership: &EpochMembership<TYPES>) -> U256 {
53        membership.success_threshold().await
54    }
55}
56
57/// Defines a threshold which is f + 1 (i.e at least one of the stake is honest)
58#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
59pub struct OneHonestThreshold {}
60
61impl<TYPES: NodeType> Threshold<TYPES> for OneHonestThreshold {
62    async fn threshold(membership: &EpochMembership<TYPES>) -> U256 {
63        membership.failure_threshold().await
64    }
65}
66
67/// Defines a threshold which is 0.9n + 1 (i.e. over 90% of the nodes with stake)
68#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
69pub struct UpgradeThreshold {}
70
71impl<TYPES: NodeType> Threshold<TYPES> for UpgradeThreshold {
72    async fn threshold(membership: &EpochMembership<TYPES>) -> U256 {
73        membership.upgrade_threshold().await
74    }
75}
76
77/// A certificate which can be created by aggregating many simple votes on the commitment.
78#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
79pub struct SimpleCertificate<
80    TYPES: NodeType,
81    VOTEABLE: Voteable<TYPES>,
82    THRESHOLD: Threshold<TYPES>,
83> {
84    /// The data this certificate is for.  I.e the thing that was voted on to create this Certificate
85    pub data: VOTEABLE,
86    /// commitment of all the votes this cert should be signed over
87    vote_commitment: Commitment<VOTEABLE>,
88    /// Which view this QC relates to
89    pub view_number: TYPES::View,
90    /// assembled signature for certificate aggregation
91    pub signatures: Option<<TYPES::SignatureKey as SignatureKey>::QcType>,
92    /// phantom data for `THRESHOLD` and `TYPES`
93    pub _pd: PhantomData<(TYPES, THRESHOLD)>,
94}
95
96impl<TYPES: NodeType, VOTEABLE: Voteable<TYPES>, THRESHOLD: Threshold<TYPES>>
97    SimpleCertificate<TYPES, VOTEABLE, THRESHOLD>
98{
99    /// Creates a new instance of `SimpleCertificate`
100    pub fn new(
101        data: VOTEABLE,
102        vote_commitment: Commitment<VOTEABLE>,
103        view_number: TYPES::View,
104        signatures: Option<<TYPES::SignatureKey as SignatureKey>::QcType>,
105        pd: PhantomData<(TYPES, THRESHOLD)>,
106    ) -> Self {
107        Self {
108            data,
109            vote_commitment,
110            view_number,
111            signatures,
112            _pd: pd,
113        }
114    }
115}
116
117impl<TYPES: NodeType, VOTEABLE: Voteable<TYPES> + Committable, THRESHOLD: Threshold<TYPES>>
118    Committable for SimpleCertificate<TYPES, VOTEABLE, THRESHOLD>
119{
120    fn commit(&self) -> Commitment<Self> {
121        let signature_bytes = match self.signatures.as_ref() {
122            Some(sigs) => serialize_signature2::<TYPES>(sigs),
123            None => vec![],
124        };
125        committable::RawCommitmentBuilder::new("Certificate")
126            .field("data", self.data.commit())
127            .field("vote_commitment", self.vote_commitment)
128            .field("view number", self.view_number.commit())
129            .var_size_field("signatures", &signature_bytes)
130            .finalize()
131    }
132}
133
134impl<TYPES: NodeType, THRESHOLD: Threshold<TYPES>> Certificate<TYPES, DaData>
135    for SimpleCertificate<TYPES, DaData, THRESHOLD>
136{
137    type Voteable = DaData;
138    type Threshold = THRESHOLD;
139
140    fn create_signed_certificate<V: Versions>(
141        vote_commitment: Commitment<VersionedVoteData<TYPES, DaData, V>>,
142        data: Self::Voteable,
143        sig: <TYPES::SignatureKey as SignatureKey>::QcType,
144        view: TYPES::View,
145    ) -> Self {
146        let vote_commitment_bytes: [u8; 32] = vote_commitment.into();
147
148        SimpleCertificate {
149            data,
150            vote_commitment: Commitment::from_raw(vote_commitment_bytes),
151            view_number: view,
152            signatures: Some(sig),
153            _pd: PhantomData,
154        }
155    }
156    async fn is_valid_cert<V: Versions>(
157        &self,
158        stake_table: &[<TYPES::SignatureKey as SignatureKey>::StakeTableEntry],
159        threshold: U256,
160        upgrade_lock: &UpgradeLock<TYPES, V>,
161    ) -> Result<()> {
162        if self.view_number == TYPES::View::genesis() {
163            return Ok(());
164        }
165        let real_qc_pp =
166            <TYPES::SignatureKey as SignatureKey>::public_parameter(stake_table, threshold);
167        let commit = self.data_commitment(upgrade_lock).await?;
168
169        <TYPES::SignatureKey as SignatureKey>::check(
170            &real_qc_pp,
171            commit.as_ref(),
172            self.signatures.as_ref().unwrap(),
173        )
174        .wrap()
175        .context(|e| warn!("Signature check failed: {}", e))
176    }
177    /// Proxy's to `Membership.stake`
178    async fn stake_table_entry(
179        membership: &EpochMembership<TYPES>,
180        pub_key: &TYPES::SignatureKey,
181    ) -> Option<PeerConfig<TYPES>> {
182        membership.da_stake(pub_key).await
183    }
184
185    /// Proxy's to `Membership.da_stake_table`
186    async fn stake_table(membership: &EpochMembership<TYPES>) -> HSStakeTable<TYPES> {
187        membership.da_stake_table().await
188    }
189    /// Proxy's to `Membership.da_total_nodes`
190    async fn total_nodes(membership: &EpochMembership<TYPES>) -> usize {
191        membership.da_total_nodes().await
192    }
193    async fn threshold(membership: &EpochMembership<TYPES>) -> U256 {
194        membership.da_success_threshold().await
195    }
196    fn data(&self) -> &Self::Voteable {
197        &self.data
198    }
199    async fn data_commitment<V: Versions>(
200        &self,
201        upgrade_lock: &UpgradeLock<TYPES, V>,
202    ) -> Result<Commitment<VersionedVoteData<TYPES, DaData, V>>> {
203        Ok(
204            VersionedVoteData::new(self.data.clone(), self.view_number, upgrade_lock)
205                .await?
206                .commit(),
207        )
208    }
209}
210
211impl<TYPES: NodeType, THRESHOLD: Threshold<TYPES>> Certificate<TYPES, DaData2<TYPES>>
212    for SimpleCertificate<TYPES, DaData2<TYPES>, THRESHOLD>
213{
214    type Voteable = DaData2<TYPES>;
215    type Threshold = THRESHOLD;
216
217    fn create_signed_certificate<V: Versions>(
218        vote_commitment: Commitment<VersionedVoteData<TYPES, DaData2<TYPES>, V>>,
219        data: Self::Voteable,
220        sig: <TYPES::SignatureKey as SignatureKey>::QcType,
221        view: TYPES::View,
222    ) -> Self {
223        let vote_commitment_bytes: [u8; 32] = vote_commitment.into();
224
225        SimpleCertificate {
226            data,
227            vote_commitment: Commitment::from_raw(vote_commitment_bytes),
228            view_number: view,
229            signatures: Some(sig),
230            _pd: PhantomData,
231        }
232    }
233    async fn is_valid_cert<V: Versions>(
234        &self,
235        stake_table: &[<TYPES::SignatureKey as SignatureKey>::StakeTableEntry],
236        threshold: U256,
237        upgrade_lock: &UpgradeLock<TYPES, V>,
238    ) -> Result<()> {
239        if self.view_number == TYPES::View::genesis() {
240            return Ok(());
241        }
242        let real_qc_pp =
243            <TYPES::SignatureKey as SignatureKey>::public_parameter(stake_table, threshold);
244        let commit = self.data_commitment(upgrade_lock).await?;
245
246        <TYPES::SignatureKey as SignatureKey>::check(
247            &real_qc_pp,
248            commit.as_ref(),
249            self.signatures.as_ref().unwrap(),
250        )
251        .wrap()
252        .context(|e| warn!("Signature check failed: {}", e))
253    }
254    /// Proxy's to `Membership.stake`
255    async fn stake_table_entry(
256        membership: &EpochMembership<TYPES>,
257        pub_key: &TYPES::SignatureKey,
258    ) -> Option<PeerConfig<TYPES>> {
259        membership.da_stake(pub_key).await
260    }
261
262    /// Proxy's to `Membership.da_stake_table`
263    async fn stake_table(membership: &EpochMembership<TYPES>) -> HSStakeTable<TYPES> {
264        membership.da_stake_table().await
265    }
266    /// Proxy's to `Membership.da_total_nodes`
267    async fn total_nodes(membership: &EpochMembership<TYPES>) -> usize {
268        membership.da_total_nodes().await
269    }
270    async fn threshold(membership: &EpochMembership<TYPES>) -> U256 {
271        membership.da_success_threshold().await
272    }
273    fn data(&self) -> &Self::Voteable {
274        &self.data
275    }
276    async fn data_commitment<V: Versions>(
277        &self,
278        upgrade_lock: &UpgradeLock<TYPES, V>,
279    ) -> Result<Commitment<VersionedVoteData<TYPES, DaData2<TYPES>, V>>> {
280        Ok(
281            VersionedVoteData::new(self.data.clone(), self.view_number, upgrade_lock)
282                .await?
283                .commit(),
284        )
285    }
286}
287
288impl<
289        TYPES: NodeType,
290        VOTEABLE: Voteable<TYPES> + 'static + QuorumMarker,
291        THRESHOLD: Threshold<TYPES>,
292    > Certificate<TYPES, VOTEABLE> for SimpleCertificate<TYPES, VOTEABLE, THRESHOLD>
293{
294    type Voteable = VOTEABLE;
295    type Threshold = THRESHOLD;
296
297    fn create_signed_certificate<V: Versions>(
298        vote_commitment: Commitment<VersionedVoteData<TYPES, VOTEABLE, V>>,
299        data: Self::Voteable,
300        sig: <TYPES::SignatureKey as SignatureKey>::QcType,
301        view: TYPES::View,
302    ) -> Self {
303        let vote_commitment_bytes: [u8; 32] = vote_commitment.into();
304
305        SimpleCertificate {
306            data,
307            vote_commitment: Commitment::from_raw(vote_commitment_bytes),
308            view_number: view,
309            signatures: Some(sig),
310            _pd: PhantomData,
311        }
312    }
313    async fn is_valid_cert<V: Versions>(
314        &self,
315        stake_table: &[<TYPES::SignatureKey as SignatureKey>::StakeTableEntry],
316        threshold: U256,
317        upgrade_lock: &UpgradeLock<TYPES, V>,
318    ) -> Result<()> {
319        if self.view_number == TYPES::View::genesis() {
320            return Ok(());
321        }
322        let real_qc_pp =
323            <TYPES::SignatureKey as SignatureKey>::public_parameter(stake_table, threshold);
324        let commit = self.data_commitment(upgrade_lock).await?;
325
326        <TYPES::SignatureKey as SignatureKey>::check(
327            &real_qc_pp,
328            commit.as_ref(),
329            self.signatures.as_ref().unwrap(),
330        )
331        .wrap()
332        .context(|e| warn!("Signature check failed: {}", e))
333    }
334    async fn threshold(membership: &EpochMembership<TYPES>) -> U256 {
335        THRESHOLD::threshold(membership).await
336    }
337
338    async fn stake_table_entry(
339        membership: &EpochMembership<TYPES>,
340        pub_key: &TYPES::SignatureKey,
341    ) -> Option<PeerConfig<TYPES>> {
342        membership.stake(pub_key).await
343    }
344
345    async fn stake_table(membership: &EpochMembership<TYPES>) -> HSStakeTable<TYPES> {
346        membership.stake_table().await
347    }
348
349    /// Proxy's to `Membership.total_nodes`
350    async fn total_nodes(membership: &EpochMembership<TYPES>) -> usize {
351        membership.total_nodes().await
352    }
353
354    fn data(&self) -> &Self::Voteable {
355        &self.data
356    }
357    async fn data_commitment<V: Versions>(
358        &self,
359        upgrade_lock: &UpgradeLock<TYPES, V>,
360    ) -> Result<Commitment<VersionedVoteData<TYPES, VOTEABLE, V>>> {
361        Ok(
362            VersionedVoteData::new(self.data.clone(), self.view_number, upgrade_lock)
363                .await?
364                .commit(),
365        )
366    }
367}
368
369impl<TYPES: NodeType, VOTEABLE: Voteable<TYPES> + 'static, THRESHOLD: Threshold<TYPES>>
370    HasViewNumber<TYPES> for SimpleCertificate<TYPES, VOTEABLE, THRESHOLD>
371{
372    fn view_number(&self) -> TYPES::View {
373        self.view_number
374    }
375}
376
377impl<
378        TYPES: NodeType,
379        VOTEABLE: Voteable<TYPES> + HasEpoch<TYPES> + 'static,
380        THRESHOLD: Threshold<TYPES>,
381    > HasEpoch<TYPES> for SimpleCertificate<TYPES, VOTEABLE, THRESHOLD>
382{
383    fn epoch(&self) -> Option<TYPES::Epoch> {
384        self.data.epoch()
385    }
386}
387
388impl<TYPES: NodeType> Display for QuorumCertificate<TYPES> {
389    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
390        write!(f, "view: {:?}", self.view_number)
391    }
392}
393
394impl<TYPES: NodeType> UpgradeCertificate<TYPES> {
395    /// Determines whether or not a certificate is relevant (i.e. we still have time to reach a
396    /// decide)
397    ///
398    /// # Errors
399    /// Returns an error when the certificate is no longer relevant
400    pub async fn is_relevant(&self, view_number: TYPES::View) -> Result<()> {
401        ensure!(
402            self.data.new_version_first_view >= view_number,
403            "Upgrade certificate is no longer relevant."
404        );
405
406        Ok(())
407    }
408
409    /// Validate an upgrade certificate.
410    /// # Errors
411    /// Returns an error when the upgrade certificate is invalid.
412    pub async fn validate<V: Versions>(
413        upgrade_certificate: &Option<Self>,
414        membership: &EpochMembership<TYPES>,
415        epoch: Option<TYPES::Epoch>,
416        upgrade_lock: &UpgradeLock<TYPES, V>,
417    ) -> Result<()> {
418        ensure!(epoch == membership.epoch(), "Epochs don't match!");
419        if let Some(ref cert) = upgrade_certificate {
420            let membership_stake_table = membership.stake_table().await;
421            let membership_upgrade_threshold = membership.upgrade_threshold().await;
422
423            cert.is_valid_cert(
424                &StakeTableEntries::<TYPES>::from(membership_stake_table).0,
425                membership_upgrade_threshold,
426                upgrade_lock,
427            )
428            .await
429            .context(|e| warn!("Invalid upgrade certificate: {}", e))?;
430        }
431
432        Ok(())
433    }
434
435    /// Given an upgrade certificate and a view, tests whether the view is in the period
436    /// where we are upgrading, which requires that we propose with null blocks.
437    pub fn upgrading_in(&self, view: TYPES::View) -> bool {
438        view > self.data.old_version_last_view && view < self.data.new_version_first_view
439    }
440}
441
442impl<TYPES: NodeType> QuorumCertificate<TYPES> {
443    /// Convert a `QuorumCertificate` into a `QuorumCertificate2`
444    pub fn to_qc2(self) -> QuorumCertificate2<TYPES> {
445        let bytes: [u8; 32] = self.data.leaf_commit.into();
446        let data = QuorumData2 {
447            leaf_commit: Commitment::from_raw(bytes),
448            epoch: None,
449            block_number: None,
450        };
451
452        let bytes: [u8; 32] = self.vote_commitment.into();
453        let vote_commitment = Commitment::from_raw(bytes);
454
455        SimpleCertificate {
456            data,
457            vote_commitment,
458            view_number: self.view_number,
459            signatures: self.signatures.clone(),
460            _pd: PhantomData,
461        }
462    }
463}
464
465impl<TYPES: NodeType> QuorumCertificate2<TYPES> {
466    /// Convert a `QuorumCertificate2` into a `QuorumCertificate`
467    pub fn to_qc(self) -> QuorumCertificate<TYPES> {
468        let bytes: [u8; 32] = self.data.leaf_commit.into();
469        let data = QuorumData {
470            leaf_commit: Commitment::from_raw(bytes),
471        };
472
473        let bytes: [u8; 32] = self.vote_commitment.into();
474        let vote_commitment = Commitment::from_raw(bytes);
475
476        SimpleCertificate {
477            data,
478            vote_commitment,
479            view_number: self.view_number,
480            signatures: self.signatures.clone(),
481            _pd: PhantomData,
482        }
483    }
484}
485
486impl<TYPES: NodeType> DaCertificate<TYPES> {
487    /// Convert a `DaCertificate` into a `DaCertificate2`
488    pub fn to_dac2(self) -> DaCertificate2<TYPES> {
489        let data = DaData2 {
490            payload_commit: self.data.payload_commit,
491            next_epoch_payload_commit: None,
492            epoch: None,
493        };
494
495        let bytes: [u8; 32] = self.vote_commitment.into();
496        let vote_commitment = Commitment::from_raw(bytes);
497
498        SimpleCertificate {
499            data,
500            vote_commitment,
501            view_number: self.view_number,
502            signatures: self.signatures.clone(),
503            _pd: PhantomData,
504        }
505    }
506}
507
508impl<TYPES: NodeType> DaCertificate2<TYPES> {
509    /// Convert a `DaCertificate` into a `DaCertificate2`
510    pub fn to_dac(self) -> DaCertificate<TYPES> {
511        let data = DaData {
512            payload_commit: self.data.payload_commit,
513        };
514
515        let bytes: [u8; 32] = self.vote_commitment.into();
516        let vote_commitment = Commitment::from_raw(bytes);
517
518        SimpleCertificate {
519            data,
520            vote_commitment,
521            view_number: self.view_number,
522            signatures: self.signatures.clone(),
523            _pd: PhantomData,
524        }
525    }
526}
527
528impl<TYPES: NodeType> ViewSyncPreCommitCertificate<TYPES> {
529    /// Convert a `DaCertificate` into a `DaCertificate2`
530    pub fn to_vsc2(self) -> ViewSyncPreCommitCertificate2<TYPES> {
531        let data = ViewSyncPreCommitData2 {
532            relay: self.data.relay,
533            round: self.data.round,
534            epoch: None,
535        };
536
537        let bytes: [u8; 32] = self.vote_commitment.into();
538        let vote_commitment = Commitment::from_raw(bytes);
539
540        SimpleCertificate {
541            data,
542            vote_commitment,
543            view_number: self.view_number,
544            signatures: self.signatures.clone(),
545            _pd: PhantomData,
546        }
547    }
548}
549
550impl<TYPES: NodeType> ViewSyncPreCommitCertificate2<TYPES> {
551    /// Convert a `DaCertificate` into a `DaCertificate2`
552    pub fn to_vsc(self) -> ViewSyncPreCommitCertificate<TYPES> {
553        let data = ViewSyncPreCommitData {
554            relay: self.data.relay,
555            round: self.data.round,
556        };
557
558        let bytes: [u8; 32] = self.vote_commitment.into();
559        let vote_commitment = Commitment::from_raw(bytes);
560
561        SimpleCertificate {
562            data,
563            vote_commitment,
564            view_number: self.view_number,
565            signatures: self.signatures.clone(),
566            _pd: PhantomData,
567        }
568    }
569}
570
571impl<TYPES: NodeType> ViewSyncCommitCertificate<TYPES> {
572    /// Convert a `DaCertificate` into a `DaCertificate2`
573    pub fn to_vsc2(self) -> ViewSyncCommitCertificate2<TYPES> {
574        let data = ViewSyncCommitData2 {
575            relay: self.data.relay,
576            round: self.data.round,
577            epoch: None,
578        };
579
580        let bytes: [u8; 32] = self.vote_commitment.into();
581        let vote_commitment = Commitment::from_raw(bytes);
582
583        SimpleCertificate {
584            data,
585            vote_commitment,
586            view_number: self.view_number,
587            signatures: self.signatures.clone(),
588            _pd: PhantomData,
589        }
590    }
591}
592
593impl<TYPES: NodeType> ViewSyncCommitCertificate2<TYPES> {
594    /// Convert a `DaCertificate` into a `DaCertificate2`
595    pub fn to_vsc(self) -> ViewSyncCommitCertificate<TYPES> {
596        let data = ViewSyncCommitData {
597            relay: self.data.relay,
598            round: self.data.round,
599        };
600
601        let bytes: [u8; 32] = self.vote_commitment.into();
602        let vote_commitment = Commitment::from_raw(bytes);
603
604        SimpleCertificate {
605            data,
606            vote_commitment,
607            view_number: self.view_number,
608            signatures: self.signatures.clone(),
609            _pd: PhantomData,
610        }
611    }
612}
613
614impl<TYPES: NodeType> ViewSyncFinalizeCertificate<TYPES> {
615    /// Convert a `DaCertificate` into a `DaCertificate2`
616    pub fn to_vsc2(self) -> ViewSyncFinalizeCertificate2<TYPES> {
617        let data = ViewSyncFinalizeData2 {
618            relay: self.data.relay,
619            round: self.data.round,
620            epoch: None,
621        };
622
623        let bytes: [u8; 32] = self.vote_commitment.into();
624        let vote_commitment = Commitment::from_raw(bytes);
625
626        SimpleCertificate {
627            data,
628            vote_commitment,
629            view_number: self.view_number,
630            signatures: self.signatures.clone(),
631            _pd: PhantomData,
632        }
633    }
634}
635
636impl<TYPES: NodeType> ViewSyncFinalizeCertificate2<TYPES> {
637    /// Convert a `DaCertificate` into a `DaCertificate2`
638    pub fn to_vsc(self) -> ViewSyncFinalizeCertificate<TYPES> {
639        let data = ViewSyncFinalizeData {
640            relay: self.data.relay,
641            round: self.data.round,
642        };
643
644        let bytes: [u8; 32] = self.vote_commitment.into();
645        let vote_commitment = Commitment::from_raw(bytes);
646
647        SimpleCertificate {
648            data,
649            vote_commitment,
650            view_number: self.view_number,
651            signatures: self.signatures.clone(),
652            _pd: PhantomData,
653        }
654    }
655}
656
657impl<TYPES: NodeType> TimeoutCertificate<TYPES> {
658    /// Convert a `DaCertificate` into a `DaCertificate2`
659    pub fn to_tc2(self) -> TimeoutCertificate2<TYPES> {
660        let data = TimeoutData2 {
661            view: self.data.view,
662            epoch: None,
663        };
664
665        let bytes: [u8; 32] = self.vote_commitment.into();
666        let vote_commitment = Commitment::from_raw(bytes);
667
668        SimpleCertificate {
669            data,
670            vote_commitment,
671            view_number: self.view_number,
672            signatures: self.signatures.clone(),
673            _pd: PhantomData,
674        }
675    }
676}
677
678impl<TYPES: NodeType> TimeoutCertificate2<TYPES> {
679    /// Convert a `DaCertificate` into a `DaCertificate2`
680    pub fn to_tc(self) -> TimeoutCertificate<TYPES> {
681        let data = TimeoutData {
682            view: self.data.view,
683        };
684
685        let bytes: [u8; 32] = self.vote_commitment.into();
686        let vote_commitment = Commitment::from_raw(bytes);
687
688        SimpleCertificate {
689            data,
690            vote_commitment,
691            view_number: self.view_number,
692            signatures: self.signatures.clone(),
693            _pd: PhantomData,
694        }
695    }
696}
697
698/// Type alias for a `QuorumCertificate`, which is a `SimpleCertificate` over `QuorumData`
699pub type QuorumCertificate<TYPES> = SimpleCertificate<TYPES, QuorumData<TYPES>, SuccessThreshold>;
700/// Type alias for a `QuorumCertificate2`, which is a `SimpleCertificate` over `QuorumData2`
701pub type QuorumCertificate2<TYPES> = SimpleCertificate<TYPES, QuorumData2<TYPES>, SuccessThreshold>;
702/// Type alias for a `QuorumCertificate2`, which is a `SimpleCertificate` over `QuorumData2`
703pub type NextEpochQuorumCertificate2<TYPES> =
704    SimpleCertificate<TYPES, NextEpochQuorumData2<TYPES>, SuccessThreshold>;
705/// Type alias for a `DaCertificate`, which is a `SimpleCertificate` over `DaData`
706pub type DaCertificate<TYPES> = SimpleCertificate<TYPES, DaData, SuccessThreshold>;
707/// Type alias for a `DaCertificate2`, which is a `SimpleCertificate` over `DaData2`
708pub type DaCertificate2<TYPES> = SimpleCertificate<TYPES, DaData2<TYPES>, SuccessThreshold>;
709/// Type alias for a Timeout certificate over a view number
710pub type TimeoutCertificate<TYPES> = SimpleCertificate<TYPES, TimeoutData<TYPES>, SuccessThreshold>;
711/// Type alias for a `TimeoutCertificate2`, which is a `SimpleCertificate` over `TimeoutData2`
712pub type TimeoutCertificate2<TYPES> =
713    SimpleCertificate<TYPES, TimeoutData2<TYPES>, SuccessThreshold>;
714/// Type alias for a `ViewSyncPreCommit` certificate over a view number
715pub type ViewSyncPreCommitCertificate<TYPES> =
716    SimpleCertificate<TYPES, ViewSyncPreCommitData<TYPES>, OneHonestThreshold>;
717/// Type alias for a `ViewSyncPreCommitCertificate2`, which is a `SimpleCertificate` over `ViewSyncPreCommitData2`
718pub type ViewSyncPreCommitCertificate2<TYPES> =
719    SimpleCertificate<TYPES, ViewSyncPreCommitData2<TYPES>, OneHonestThreshold>;
720/// Type alias for a `ViewSyncCommit` certificate over a view number
721pub type ViewSyncCommitCertificate<TYPES> =
722    SimpleCertificate<TYPES, ViewSyncCommitData<TYPES>, SuccessThreshold>;
723/// Type alias for a `ViewSyncCommitCertificate2`, which is a `SimpleCertificate` over `ViewSyncCommitData2`
724pub type ViewSyncCommitCertificate2<TYPES> =
725    SimpleCertificate<TYPES, ViewSyncCommitData2<TYPES>, SuccessThreshold>;
726/// Type alias for a `ViewSyncFinalize` certificate over a view number
727pub type ViewSyncFinalizeCertificate<TYPES> =
728    SimpleCertificate<TYPES, ViewSyncFinalizeData<TYPES>, SuccessThreshold>;
729/// Type alias for a `ViewSyncFinalizeCertificate2`, which is a `SimpleCertificate` over `ViewSyncFinalizeData2`
730pub type ViewSyncFinalizeCertificate2<TYPES> =
731    SimpleCertificate<TYPES, ViewSyncFinalizeData2<TYPES>, SuccessThreshold>;
732/// Type alias for a `UpgradeCertificate`, which is a `SimpleCertificate` of `UpgradeProposalData`
733pub type UpgradeCertificate<TYPES> =
734    SimpleCertificate<TYPES, UpgradeProposalData<TYPES>, UpgradeThreshold>;
735
736/// Type for light client state update certificate
737#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
738pub struct LightClientStateUpdateCertificate<TYPES: NodeType> {
739    /// The epoch of the light client state
740    pub epoch: TYPES::Epoch,
741    /// Light client state for epoch transition
742    pub light_client_state: LightClientState,
743    /// Next epoch stake table state
744    pub next_stake_table_state: StakeTableState,
745    /// Signatures to the light client state
746    pub signatures: Vec<(
747        TYPES::StateSignatureKey,
748        <TYPES::StateSignatureKey as StateSignatureKey>::StateSignature,
749    )>,
750}
751
752impl<TYPES: NodeType> HasViewNumber<TYPES> for LightClientStateUpdateCertificate<TYPES> {
753    fn view_number(&self) -> TYPES::View {
754        TYPES::View::new(self.light_client_state.view_number)
755    }
756}
757
758impl<TYPES: NodeType> HasEpoch<TYPES> for LightClientStateUpdateCertificate<TYPES> {
759    fn epoch(&self) -> Option<TYPES::Epoch> {
760        Some(self.epoch)
761    }
762}
763
764impl<TYPES: NodeType> LightClientStateUpdateCertificate<TYPES> {
765    pub fn genesis() -> Self {
766        Self {
767            epoch: TYPES::Epoch::genesis(),
768            light_client_state: Default::default(),
769            next_stake_table_state: Default::default(),
770            signatures: vec![],
771        }
772    }
773}
774
775#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
776#[serde(bound(deserialize = "QuorumCertificate2<TYPES>:for<'a> Deserialize<'a>"))]
777pub struct EpochRootQuorumCertificate<TYPES: NodeType> {
778    pub qc: QuorumCertificate2<TYPES>,
779    pub state_cert: LightClientStateUpdateCertificate<TYPES>,
780}
781
782impl<TYPES: NodeType> HasViewNumber<TYPES> for EpochRootQuorumCertificate<TYPES> {
783    fn view_number(&self) -> TYPES::View {
784        self.qc.view_number()
785    }
786}
787
788impl<TYPES: NodeType> HasEpoch<TYPES> for EpochRootQuorumCertificate<TYPES> {
789    fn epoch(&self) -> Option<TYPES::Epoch> {
790        self.qc.epoch()
791    }
792}