Skip to main content

hotshot_types/
simple_vote.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 vote types.
8
9use std::{
10    borrow::Borrow,
11    fmt::Debug,
12    hash::Hash,
13    marker::PhantomData,
14    ops::{Deref, DerefMut},
15};
16
17use alloy_primitives::FixedBytes;
18use committable::{Commitment, Committable};
19use hotshot_utils::anytrace::*;
20use jf_utils::canonical;
21use serde::{Deserialize, Serialize};
22use vbs::version::Version;
23
24use crate::{
25    data::{EpochNumber, Leaf, Leaf2, VidCommitment, ViewNumber},
26    light_client::{CircuitField, LightClientState, StakeTableState},
27    message::UpgradeLock,
28    traits::{
29        node_implementation::NodeType,
30        signature_key::{SignatureKey, StateSignatureKey},
31    },
32    utils::epoch_from_block_number,
33    vote::{HasViewNumber, Vote},
34};
35
36/// Marker that data should use the quorum cert type
37pub trait QuorumMarker {}
38
39/// Data used for a yes vote.
40#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
41#[serde(bound(deserialize = ""))]
42pub struct QuorumData<TYPES: NodeType> {
43    /// Commitment to the leaf
44    pub leaf_commit: Commitment<Leaf<TYPES>>,
45}
46
47/// Data used for a yes vote.
48#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Hash, Eq)]
49#[serde(bound(deserialize = ""))]
50pub struct QuorumData2<TYPES: NodeType> {
51    /// Commitment to the leaf
52    pub leaf_commit: Commitment<Leaf2<TYPES>>,
53    /// An epoch to which the data belongs to. Relevant for validating against the correct stake table
54    pub epoch: Option<EpochNumber>,
55    /// Block number of the leaf. It's optional to be compatible with pre-epoch version.
56    pub block_number: Option<u64>,
57}
58
59impl<T: NodeType> QuorumData2<T> {
60    pub fn is_well_formed(&self, epoch_height: u64) -> bool {
61        let Some(epoch) = self.epoch else {
62            return false;
63        };
64        let Some(block) = self.block_number else {
65            return false;
66        };
67        epoch == epoch_from_block_number(block, epoch_height).into()
68    }
69}
70
71/// Data used for a yes vote. Used to distinguish votes sent by the next epoch nodes.
72#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
73#[serde(bound(deserialize = ""))]
74pub struct NextEpochQuorumData2<TYPES: NodeType>(QuorumData2<TYPES>);
75
76/// Data used for a DA vote.
77#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
78pub struct DaData {
79    /// Commitment to a block payload
80    pub payload_commit: VidCommitment,
81}
82
83/// Data used for a DA vote.
84#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
85pub struct DaData2 {
86    /// Commitment to a block payload
87    pub payload_commit: VidCommitment,
88    /// An optional commitment to a block payload calculated for the next epoch (epoch + 1)
89    pub next_epoch_payload_commit: Option<VidCommitment>,
90    /// Epoch number
91    pub epoch: Option<EpochNumber>,
92}
93
94/// Data used for a timeout vote.
95#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
96pub struct TimeoutData {
97    /// View the timeout is for
98    pub view: ViewNumber,
99}
100
101/// Data used for a timeout vote.
102#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
103pub struct TimeoutData2 {
104    /// View the timeout is for
105    pub view: ViewNumber,
106    /// Epoch number
107    pub epoch: Option<EpochNumber>,
108}
109
110/// Data used for a timeout vote, binding the epoch the vote was cast in and
111/// the lock its signer held when it timed out.
112#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
113pub struct TimeoutData3 {
114    /// View the timeout is for
115    pub view: ViewNumber,
116    /// Epoch number
117    pub epoch: EpochNumber,
118    /// The signer's lock, `None` while it is locked on nothing but genesis.
119    pub lock: Option<LockView>,
120}
121
122/// Where a lock sits in the order locks are compared by: epoch first, then view.
123///
124/// A certificate of a later epoch is later than any certificate of an earlier
125/// one, whatever their views.
126#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
127pub struct LockView {
128    /// Field order is the comparison order: epoch, then view.
129    pub epoch: EpochNumber,
130    pub view: ViewNumber,
131}
132
133impl LockView {
134    /// The position of the lock a `Certificate1` (`QuorumCertificate2`) gives.
135    pub fn of<T: NodeType>(cert: &crate::simple_certificate::QuorumCertificate2<T>) -> Self {
136        Self {
137            epoch: cert.data.epoch.unwrap_or_else(EpochNumber::genesis),
138            view: cert.view_number(),
139        }
140    }
141}
142
143/// The lock a timeout vote or certificate of some epoch carries, by what is
144/// checked of it.
145///
146/// A proposal after a timeout certificate is of the certificate's epoch, and a
147/// lock of an earlier epoch admits any parent, so whether an older lock is
148/// genuine changes nothing. Only a recent lock's certificate is verified, its
149/// committee looked up and the lock adopted, which keeps a peer from starting
150/// catchups for old epochs. A vote with a stale lock still counts: an honest
151/// node back from several epochs away holds such a lock until it adopts a newer
152/// one.
153#[derive(Debug)]
154pub enum TimeoutLock<'a, T: NodeType> {
155    /// Locked on nothing but genesis.
156    None,
157    /// Of an epoch before the one before: only its position is bound.
158    Stale(LockView),
159    /// Of the vote's epoch or the one before: its certificate is verified
160    /// against that epoch's committee.
161    Recent(&'a crate::simple_certificate::QuorumCertificate2<T>),
162}
163
164impl<'a, T: NodeType> TimeoutLock<'a, T> {
165    pub fn of(
166        cert: Option<&'a crate::simple_certificate::QuorumCertificate2<T>>,
167        epoch: EpochNumber,
168    ) -> Self {
169        let Some(cert) = cert else {
170            return Self::None;
171        };
172        let lock = LockView::of(cert);
173        if lock.epoch.saturating_add(1) >= *epoch {
174            Self::Recent(cert)
175        } else {
176            Self::Stale(lock)
177        }
178    }
179
180    /// The certificate of a recent lock.
181    pub fn recent(self) -> Option<&'a crate::simple_certificate::QuorumCertificate2<T>> {
182        match self {
183            Self::Recent(cert) => Some(cert),
184            Self::None | Self::Stale(_) => None,
185        }
186    }
187
188    /// The epoch whose committee verifies a recent lock's certificate.
189    pub fn verified_in(self) -> Option<EpochNumber> {
190        self.recent().map(|cert| LockView::of(cert).epoch)
191    }
192}
193
194impl std::fmt::Display for LockView {
195    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
196        write!(f, "{}@{}", self.epoch, self.view)
197    }
198}
199
200/// Data used for a Pre Commit vote.
201#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
202pub struct ViewSyncPreCommitData {
203    /// The relay this vote is intended for
204    pub relay: u64,
205    /// The view number we are trying to sync on
206    pub round: ViewNumber,
207}
208
209/// Data used for a Pre Commit vote.
210#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
211pub struct ViewSyncPreCommitData2 {
212    /// The relay this vote is intended for
213    pub relay: u64,
214    /// The view number we are trying to sync on
215    pub round: ViewNumber,
216    /// Epoch number
217    pub epoch: Option<EpochNumber>,
218}
219
220/// Data used for a Commit vote.
221#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
222pub struct ViewSyncCommitData {
223    /// The relay this vote is intended for
224    pub relay: u64,
225    /// The view number we are trying to sync on
226    pub round: ViewNumber,
227}
228
229/// Data used for a Commit vote.
230#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
231pub struct ViewSyncCommitData2 {
232    /// The relay this vote is intended for
233    pub relay: u64,
234    /// The view number we are trying to sync on
235    pub round: ViewNumber,
236    /// Epoch number
237    pub epoch: Option<EpochNumber>,
238}
239
240/// Data used for a Finalize vote.
241#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
242pub struct ViewSyncFinalizeData {
243    /// The relay this vote is intended for
244    pub relay: u64,
245    /// The view number we are trying to sync on
246    pub round: ViewNumber,
247}
248
249/// Data used for a Finalize vote.
250#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
251pub struct ViewSyncFinalizeData2 {
252    /// The relay this vote is intended for
253    pub relay: u64,
254    /// The view number we are trying to sync on
255    pub round: ViewNumber,
256    /// Epoch number
257    pub epoch: Option<EpochNumber>,
258}
259
260/// Data used for a Upgrade vote.
261#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
262pub struct UpgradeProposalData {
263    /// The old version that we are upgrading from.
264    pub old_version: Version,
265    /// The new version that we are upgrading to.
266    pub new_version: Version,
267    /// The last view in which we are allowed to reach a decide on this upgrade.
268    /// If it is not decided by that view, we discard it.
269    pub decide_by: ViewNumber,
270    /// A unique identifier for the specific protocol being voted on.
271    #[serde(with = "serde_bytes")]
272    pub new_version_hash: Vec<u8>,
273    /// The last block for which the old version will be in effect.
274    pub old_version_last_view: ViewNumber,
275    /// The first block for which the new version will be in effect.
276    pub new_version_first_view: ViewNumber,
277}
278
279/// Data used for an upgrade vote, binding the epoch the vote was cast in.
280#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
281pub struct UpgradeProposalData2 {
282    /// The old version that we are upgrading from.
283    pub old_version: Version,
284    /// The new version that we are upgrading to.
285    pub new_version: Version,
286    /// The last view in which we are allowed to reach a decide on this upgrade.
287    /// If it is not decided by that view, we discard it.
288    pub decide_by: ViewNumber,
289    /// A unique identifier for the specific protocol being voted on.
290    #[serde(with = "serde_bytes")]
291    pub new_version_hash: Vec<u8>,
292    /// The last block for which the old version will be in effect.
293    pub old_version_last_view: ViewNumber,
294    /// The first block for which the new version will be in effect.
295    pub new_version_first_view: ViewNumber,
296    /// The epoch whose stake table tallies the votes and verifies the certificate.
297    pub epoch: EpochNumber,
298}
299
300impl UpgradeProposalData2 {
301    /// The data without its epoch, as a `Leaf2` carries it.
302    pub fn strip_epoch(self) -> UpgradeProposalData {
303        UpgradeProposalData {
304            old_version: self.old_version,
305            new_version: self.new_version,
306            decide_by: self.decide_by,
307            new_version_hash: self.new_version_hash,
308            old_version_last_view: self.old_version_last_view,
309            new_version_first_view: self.new_version_first_view,
310        }
311    }
312
313    /// Inverse of [`Self::strip_epoch`].
314    pub fn restore_epoch(data: UpgradeProposalData, epoch: EpochNumber) -> Self {
315        Self {
316            old_version: data.old_version,
317            new_version: data.new_version,
318            decide_by: data.decide_by,
319            new_version_hash: data.new_version_hash,
320            old_version_last_view: data.old_version_last_view,
321            new_version_first_view: data.new_version_first_view,
322            epoch,
323        }
324    }
325}
326
327/// Data used for a yes vote.
328#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
329#[serde(bound(deserialize = ""))]
330pub struct Vote2Data<T: NodeType> {
331    pub leaf_commit: Commitment<Leaf2<T>>,
332    pub epoch: EpochNumber,
333    pub block_number: u64,
334}
335
336impl<T: NodeType> QuorumMarker for Vote2Data<T> {}
337
338impl<T: NodeType> Vote2Data<T> {
339    pub fn is_well_formed(&self, epoch_height: u64) -> bool {
340        self.epoch == epoch_from_block_number(self.block_number, epoch_height).into()
341    }
342}
343
344impl<T: NodeType> HasEpoch for Vote2Data<T> {
345    fn epoch(&self) -> Option<EpochNumber> {
346        Some(self.epoch)
347    }
348}
349
350impl<T: NodeType> Committable for Vote2Data<T> {
351    fn commit(&self) -> Commitment<Self> {
352        committable::RawCommitmentBuilder::new("Vote2Data")
353            .var_size_bytes(self.leaf_commit.as_ref())
354            .u64(*self.epoch)
355            .u64(self.block_number)
356            .constant_str("Vote2")
357            .finalize()
358    }
359}
360
361/// Marker trait for data or commitments that can be voted on.
362/// Only structs in this file can implement voteable.  This is enforced with the `Sealed` trait
363/// Sealing this trait prevents creating new vote types outside this file.
364pub trait Voteable<TYPES: NodeType>:
365    sealed::Sealed + Committable + Clone + Serialize + Debug + PartialEq + Hash + Eq
366{
367}
368
369/// Marker trait for data or commitments that can be voted on.
370/// Only structs in this file can implement voteable.  This is enforced with the `Sealed` trait
371/// Sealing this trait prevents creating new vote types outside this file.
372pub trait Voteable2<TYPES: NodeType>:
373    sealed::Sealed + HasEpoch + Committable + Clone + Serialize + Debug + PartialEq + Hash + Eq
374{
375}
376
377/// Sealed is used to make sure no other files can implement the Voteable trait.
378/// All simple voteable types should be implemented here.  This prevents us from
379/// creating/using improper types when using the vote types.
380mod sealed {
381    use committable::Committable;
382
383    /// Only structs in this file can impl `Sealed`
384    pub trait Sealed {}
385
386    // TODO: Does the implement for things outside this file that are committable?
387    impl<C: Committable> Sealed for C {}
388}
389
390impl<T: NodeType> QuorumMarker for QuorumData<T> {}
391impl<T: NodeType> QuorumMarker for QuorumData2<T> {}
392impl<T: NodeType> QuorumMarker for NextEpochQuorumData2<T> {}
393impl QuorumMarker for TimeoutData {}
394impl QuorumMarker for TimeoutData2 {}
395impl QuorumMarker for TimeoutData3 {}
396impl QuorumMarker for ViewSyncPreCommitData {}
397impl QuorumMarker for ViewSyncCommitData {}
398impl QuorumMarker for ViewSyncFinalizeData {}
399impl QuorumMarker for ViewSyncPreCommitData2 {}
400impl QuorumMarker for ViewSyncCommitData2 {}
401impl QuorumMarker for ViewSyncFinalizeData2 {}
402impl QuorumMarker for UpgradeProposalData {}
403impl QuorumMarker for UpgradeProposalData2 {}
404
405/// A simple yes vote over some votable type.
406#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
407pub struct SimpleVote<TYPES: NodeType, DATA: Voteable<TYPES>> {
408    /// The signature share associated with this vote
409    pub signature: (
410        TYPES::SignatureKey,
411        <TYPES::SignatureKey as SignatureKey>::PureAssembledSignatureType,
412    ),
413    /// The leaf commitment being voted on.
414    pub data: DATA,
415    /// The view this vote was cast for
416    pub view_number: ViewNumber,
417}
418
419impl<TYPES: NodeType, DATA: Voteable<TYPES> + 'static> HasViewNumber for SimpleVote<TYPES, DATA> {
420    fn view_number(&self) -> ViewNumber {
421        self.view_number
422    }
423}
424
425impl<TYPES: NodeType, DATA: Voteable<TYPES> + 'static> Vote<TYPES> for SimpleVote<TYPES, DATA> {
426    type Commitment = DATA;
427
428    fn signing_key(&self) -> <TYPES as NodeType>::SignatureKey {
429        self.signature.0.clone()
430    }
431
432    fn signature(&self) -> <TYPES::SignatureKey as SignatureKey>::PureAssembledSignatureType {
433        self.signature.1.clone()
434    }
435
436    fn date(&self) -> &DATA {
437        &self.data
438    }
439
440    fn data_commitment(&self) -> Commitment<DATA> {
441        self.data.commit()
442    }
443}
444
445impl<TYPES: NodeType, DATA: Voteable<TYPES> + 'static> SimpleVote<TYPES, DATA> {
446    /// Creates and signs a simple vote
447    /// # Errors
448    /// If we are unable to sign the data
449    pub fn create_signed_vote(
450        data: DATA,
451        view: ViewNumber,
452        pub_key: &TYPES::SignatureKey,
453        private_key: &<TYPES::SignatureKey as SignatureKey>::PrivateKey,
454        upgrade_lock: &UpgradeLock<TYPES>,
455    ) -> Result<Self> {
456        let commit = VersionedVoteData::new(data.clone(), view, upgrade_lock)?.commit();
457
458        let signature = (
459            pub_key.clone(),
460            TYPES::SignatureKey::sign(private_key, commit.as_ref())
461                .wrap()
462                .context(error!("Failed to sign vote"))?,
463        );
464
465        Ok(Self {
466            signature,
467            data,
468            view_number: view,
469        })
470    }
471}
472
473#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
474/// A wrapper for vote data that carries a view number and an `upgrade_lock`, allowing switching the commitment calculation dynamically depending on the version
475pub struct VersionedVoteData<TYPES: NodeType, DATA: Voteable<TYPES>> {
476    /// underlying vote data
477    data: DATA,
478
479    /// view number
480    view: ViewNumber,
481
482    /// version applied to the view number
483    version: Version,
484
485    /// phantom data
486    _pd: PhantomData<TYPES>,
487}
488
489impl<TYPES: NodeType, DATA: Voteable<TYPES>> VersionedVoteData<TYPES, DATA> {
490    /// Create a new `VersionedVoteData` struct
491    ///
492    /// # Errors
493    ///
494    /// Returns an error if `upgrade_lock.version(view)` is unable to return a version we support
495    pub fn new(data: DATA, view: ViewNumber, upgrade_lock: &UpgradeLock<TYPES>) -> Result<Self> {
496        let version = upgrade_lock.version(view)?;
497
498        Ok(Self {
499            data,
500            view,
501            version,
502            _pd: PhantomData,
503        })
504    }
505
506    /// Create a new `VersionedVoteData` struct
507    ///
508    /// This function cannot error, but may use an invalid version.
509    pub fn new_infallible(data: DATA, view: ViewNumber, upgrade_lock: &UpgradeLock<TYPES>) -> Self {
510        let version = upgrade_lock.version_infallible(view);
511
512        Self {
513            data,
514            view,
515            version,
516            _pd: PhantomData,
517        }
518    }
519}
520
521impl<TYPES: NodeType, DATA: Voteable<TYPES>> Committable for VersionedVoteData<TYPES, DATA> {
522    fn commit(&self) -> Commitment<Self> {
523        committable::RawCommitmentBuilder::new("Vote")
524            .var_size_bytes(self.data.commit().as_ref())
525            .u64(*self.view)
526            .finalize()
527    }
528}
529
530impl<TYPES: NodeType> Committable for QuorumData<TYPES> {
531    fn commit(&self) -> Commitment<Self> {
532        committable::RawCommitmentBuilder::new("Quorum data")
533            .var_size_bytes(self.leaf_commit.as_ref())
534            .finalize()
535    }
536}
537
538impl<TYPES: NodeType> Committable for QuorumData2<TYPES> {
539    fn commit(&self) -> Commitment<Self> {
540        let QuorumData2 {
541            leaf_commit,
542            epoch,
543            block_number,
544        } = self;
545
546        let mut cb = committable::RawCommitmentBuilder::new("Quorum data")
547            .var_size_bytes(leaf_commit.as_ref());
548
549        if let Some(ref epoch) = *epoch {
550            cb = cb.u64_field("epoch number", **epoch);
551        }
552
553        if let Some(ref block_number) = *block_number {
554            cb = cb.u64_field("block number", *block_number);
555        }
556
557        cb.finalize()
558    }
559}
560
561impl<TYPES: NodeType> Committable for NextEpochQuorumData2<TYPES> {
562    fn commit(&self) -> Commitment<Self> {
563        let NextEpochQuorumData2(QuorumData2 {
564            leaf_commit,
565            epoch,
566            block_number,
567        }) = self;
568
569        let mut cb = committable::RawCommitmentBuilder::new("Quorum data")
570            .var_size_bytes(leaf_commit.as_ref());
571
572        if let Some(ref epoch) = *epoch {
573            cb = cb.u64_field("epoch number", **epoch);
574        }
575
576        if let Some(ref block_number) = *block_number {
577            cb = cb.u64_field("block number", *block_number);
578        }
579
580        cb.finalize()
581    }
582}
583
584impl Committable for TimeoutData {
585    fn commit(&self) -> Commitment<Self> {
586        committable::RawCommitmentBuilder::new("Timeout data")
587            .u64(*self.view)
588            .finalize()
589    }
590}
591
592impl Committable for TimeoutData2 {
593    fn commit(&self) -> Commitment<Self> {
594        let TimeoutData2 { view, epoch: _ } = self;
595
596        committable::RawCommitmentBuilder::new("Timeout data")
597            .u64(**view)
598            .finalize()
599    }
600}
601
602impl Committable for TimeoutData3 {
603    fn commit(&self) -> Commitment<Self> {
604        let TimeoutData3 { view, epoch, lock } = self;
605
606        let builder = committable::RawCommitmentBuilder::new("Timeout data v3")
607            .u64_field("view number", **view)
608            .u64_field("epoch number", **epoch);
609        match lock {
610            None => builder.u64_field("lock", 0),
611            Some(lock) => builder
612                .u64_field("lock", 1)
613                .u64_field("lock epoch", *lock.epoch)
614                .u64_field("lock view", *lock.view),
615        }
616        .finalize()
617    }
618}
619
620impl Committable for DaData {
621    fn commit(&self) -> Commitment<Self> {
622        committable::RawCommitmentBuilder::new("DA data")
623            .var_size_bytes(self.payload_commit.as_ref())
624            .finalize()
625    }
626}
627
628impl Committable for DaData2 {
629    fn commit(&self) -> Commitment<Self> {
630        let DaData2 {
631            payload_commit,
632            next_epoch_payload_commit,
633            epoch,
634        } = self;
635
636        let mut cb = committable::RawCommitmentBuilder::new("DA data")
637            .var_size_bytes(payload_commit.as_ref());
638
639        if let Some(ref next_epoch_payload_commit) = *next_epoch_payload_commit {
640            cb = cb.var_size_bytes(next_epoch_payload_commit.as_ref());
641        }
642
643        if let Some(ref epoch) = *epoch {
644            cb = cb.u64_field("epoch number", **epoch);
645        }
646
647        cb.finalize()
648    }
649}
650
651impl Committable for UpgradeProposalData {
652    fn commit(&self) -> Commitment<Self> {
653        let builder = committable::RawCommitmentBuilder::new("Upgrade data");
654        builder
655            .u64(*self.decide_by)
656            .u64(*self.new_version_first_view)
657            .u64(*self.old_version_last_view)
658            .var_size_bytes(self.new_version_hash.as_slice())
659            .u16(self.new_version.minor)
660            .u16(self.new_version.major)
661            .u16(self.old_version.minor)
662            .u16(self.old_version.major)
663            .finalize()
664    }
665}
666
667impl Committable for UpgradeProposalData2 {
668    fn commit(&self) -> Commitment<Self> {
669        let builder = committable::RawCommitmentBuilder::new("Upgrade data v2");
670        builder
671            .u64(*self.decide_by)
672            .u64(*self.new_version_first_view)
673            .u64(*self.old_version_last_view)
674            .var_size_bytes(self.new_version_hash.as_slice())
675            .u16(self.new_version.minor)
676            .u16(self.new_version.major)
677            .u16(self.old_version.minor)
678            .u16(self.old_version.major)
679            .u64_field("epoch number", *self.epoch)
680            .finalize()
681    }
682}
683
684/// This implements commit for all the types which contain a view and relay public key.
685fn view_and_relay_commit<T: Committable>(
686    view: ViewNumber,
687    relay: u64,
688    epoch: Option<EpochNumber>,
689    tag: &str,
690) -> Commitment<T> {
691    let builder = committable::RawCommitmentBuilder::new(tag);
692    let mut cb = builder.u64(*view).u64(relay);
693
694    if let Some(epoch) = epoch {
695        cb = cb.u64_field("epoch number", *epoch);
696    }
697
698    cb.finalize()
699}
700
701impl Committable for ViewSyncPreCommitData {
702    fn commit(&self) -> Commitment<Self> {
703        view_and_relay_commit(self.round, self.relay, None, "View Sync Precommit")
704    }
705}
706
707impl Committable for ViewSyncPreCommitData2 {
708    fn commit(&self) -> Commitment<Self> {
709        let ViewSyncPreCommitData2 {
710            relay,
711            round,
712            epoch,
713        } = self;
714
715        view_and_relay_commit(*round, *relay, *epoch, "View Sync Precommit")
716    }
717}
718
719impl Committable for ViewSyncFinalizeData {
720    fn commit(&self) -> Commitment<Self> {
721        view_and_relay_commit(self.round, self.relay, None, "View Sync Finalize")
722    }
723}
724
725impl Committable for ViewSyncFinalizeData2 {
726    fn commit(&self) -> Commitment<Self> {
727        let ViewSyncFinalizeData2 {
728            relay,
729            round,
730            epoch,
731        } = self;
732
733        view_and_relay_commit(*round, *relay, *epoch, "View Sync Finalize")
734    }
735}
736
737impl Committable for ViewSyncCommitData {
738    fn commit(&self) -> Commitment<Self> {
739        view_and_relay_commit(self.round, self.relay, None, "View Sync Commit")
740    }
741}
742
743impl Committable for ViewSyncCommitData2 {
744    fn commit(&self) -> Commitment<Self> {
745        let ViewSyncCommitData2 {
746            relay,
747            round,
748            epoch,
749        } = self;
750
751        view_and_relay_commit(*round, *relay, *epoch, "View Sync Commit")
752    }
753}
754
755/// A trait for types belonging for specific epoch
756pub trait HasEpoch {
757    /// Returns `Epoch`
758    fn epoch(&self) -> Option<EpochNumber>;
759}
760
761/// Helper macro for trivial implementation of the `HasEpoch` trait
762#[macro_export]
763macro_rules! impl_has_epoch {
764    ($($t:ty),*) => {
765        $(
766            impl HasEpoch for $t {
767                fn epoch(&self) -> Option<EpochNumber> {
768                    self.epoch
769                }
770            }
771        )*
772    };
773}
774
775impl<NODE: NodeType> HasEpoch for QuorumData2<NODE> {
776    fn epoch(&self) -> Option<EpochNumber> {
777        self.epoch
778    }
779}
780
781impl<NODE: NodeType> HasEpoch for NextEpochQuorumData2<NODE> {
782    fn epoch(&self) -> Option<EpochNumber> {
783        self.0.epoch
784    }
785}
786
787impl HasEpoch for TimeoutData3 {
788    fn epoch(&self) -> Option<EpochNumber> {
789        Some(self.epoch)
790    }
791}
792
793impl HasEpoch for UpgradeProposalData2 {
794    fn epoch(&self) -> Option<EpochNumber> {
795        Some(self.epoch)
796    }
797}
798
799impl_has_epoch!(
800    DaData2,
801    TimeoutData2,
802    ViewSyncPreCommitData2,
803    ViewSyncCommitData2,
804    ViewSyncFinalizeData2
805);
806
807/// Helper macro for trivial implementation of the `HasEpoch` trait for types that have no epoch
808#[macro_export]
809macro_rules! impl_has_none_epoch {
810    ($($t:ty),*) => {
811        $(
812            impl HasEpoch for $t {
813                fn epoch(&self) -> Option<EpochNumber> {
814                    None
815                }
816            }
817        )*
818    };
819}
820
821impl<NODE: NodeType> HasEpoch for QuorumData<NODE> {
822    fn epoch(&self) -> Option<EpochNumber> {
823        None
824    }
825}
826
827impl_has_none_epoch!(
828    DaData,
829    TimeoutData,
830    ViewSyncPreCommitData,
831    ViewSyncCommitData,
832    ViewSyncFinalizeData,
833    UpgradeProposalData
834);
835
836impl<TYPES: NodeType, DATA: Voteable<TYPES> + HasEpoch> HasEpoch for SimpleVote<TYPES, DATA> {
837    fn epoch(&self) -> Option<EpochNumber> {
838        self.data.epoch()
839    }
840}
841
842// impl votable for all the data types in this file sealed marker should ensure nothing is accidentally
843// implemented for structs that aren't "voteable"
844impl<
845    TYPES: NodeType,
846    V: sealed::Sealed + Committable + Clone + Serialize + Debug + PartialEq + Hash + Eq,
847> Voteable<TYPES> for V
848{
849}
850
851// impl votable for all the data types in this file sealed marker should ensure nothing is accidentally
852// implemented for structs that aren't "voteable"
853impl<
854    TYPES: NodeType,
855    V: sealed::Sealed + HasEpoch + Committable + Clone + Serialize + Debug + PartialEq + Hash + Eq,
856> Voteable2<TYPES> for V
857{
858}
859
860impl<TYPES: NodeType> QuorumVote<TYPES> {
861    /// Convert a `QuorumVote` to a `QuorumVote2`
862    pub fn to_vote2(self) -> QuorumVote2<TYPES> {
863        let bytes: [u8; 32] = self.data.leaf_commit.into();
864
865        let signature = self.signature;
866        let data = QuorumData2 {
867            leaf_commit: Commitment::from_raw(bytes),
868            epoch: None,
869            block_number: None,
870        };
871        let view_number = self.view_number;
872
873        SimpleVote {
874            signature,
875            data,
876            view_number,
877        }
878    }
879}
880
881impl<TYPES: NodeType> QuorumVote2<TYPES> {
882    /// Convert a `QuorumVote2` to a `QuorumVote`
883    pub fn to_vote(self) -> QuorumVote<TYPES> {
884        let bytes: [u8; 32] = self.data.leaf_commit.into();
885
886        let signature = self.signature.clone();
887        let data = QuorumData {
888            leaf_commit: Commitment::from_raw(bytes),
889        };
890        let view_number = self.view_number;
891
892        SimpleVote {
893            signature,
894            data,
895            view_number,
896        }
897    }
898}
899
900impl<TYPES: NodeType> DaVote<TYPES> {
901    /// Convert a `QuorumVote` to a `QuorumVote2`
902    pub fn to_vote2(self) -> DaVote2<TYPES> {
903        let signature = self.signature;
904        let data = DaData2 {
905            payload_commit: self.data.payload_commit,
906            next_epoch_payload_commit: None,
907            epoch: None,
908        };
909        let view_number = self.view_number;
910
911        SimpleVote {
912            signature,
913            data,
914            view_number,
915        }
916    }
917}
918
919impl<TYPES: NodeType> DaVote2<TYPES> {
920    /// Convert a `QuorumVote2` to a `QuorumVote`
921    pub fn to_vote(self) -> DaVote<TYPES> {
922        let signature = self.signature;
923        let data = DaData {
924            payload_commit: self.data.payload_commit,
925        };
926        let view_number = self.view_number;
927
928        SimpleVote {
929            signature,
930            data,
931            view_number,
932        }
933    }
934}
935
936impl<TYPES: NodeType> TimeoutVote<TYPES> {
937    /// Convert a `TimeoutVote` to a `TimeoutVote2`
938    pub fn to_vote2(self) -> TimeoutVote2<TYPES> {
939        let signature = self.signature;
940        let data = TimeoutData2 {
941            view: self.data.view,
942            epoch: None,
943        };
944        let view_number = self.view_number;
945
946        SimpleVote {
947            signature,
948            data,
949            view_number,
950        }
951    }
952}
953
954impl<TYPES: NodeType> TimeoutVote2<TYPES> {
955    /// Convert a `QuorumVote2` to a `QuorumVote`
956    pub fn to_vote(self) -> TimeoutVote<TYPES> {
957        let signature = self.signature;
958        let data = TimeoutData {
959            view: self.data.view,
960        };
961        let view_number = self.view_number;
962
963        SimpleVote {
964            signature,
965            data,
966            view_number,
967        }
968    }
969}
970
971impl<TYPES: NodeType> ViewSyncPreCommitVote<TYPES> {
972    /// Convert a `ViewSyncPreCommitVote` to a `ViewSyncPreCommitVote2`
973    pub fn to_vote2(self) -> ViewSyncPreCommitVote2<TYPES> {
974        let signature = self.signature;
975        let data = ViewSyncPreCommitData2 {
976            relay: self.data.relay,
977            round: self.data.round,
978            epoch: None,
979        };
980        let view_number = self.view_number;
981
982        SimpleVote {
983            signature,
984            data,
985            view_number,
986        }
987    }
988}
989
990impl<TYPES: NodeType> ViewSyncPreCommitVote2<TYPES> {
991    /// Convert a `ViewSyncPreCommitVote2` to a `ViewSyncPreCommitVote`
992    pub fn to_vote(self) -> ViewSyncPreCommitVote<TYPES> {
993        let signature = self.signature;
994        let data = ViewSyncPreCommitData {
995            relay: self.data.relay,
996            round: self.data.round,
997        };
998        let view_number = self.view_number;
999
1000        SimpleVote {
1001            signature,
1002            data,
1003            view_number,
1004        }
1005    }
1006}
1007
1008impl<TYPES: NodeType> ViewSyncCommitVote<TYPES> {
1009    /// Convert a `ViewSyncCommitVote` to a `ViewSyncCommitVote2`
1010    pub fn to_vote2(self) -> ViewSyncCommitVote2<TYPES> {
1011        let signature = self.signature;
1012        let data = ViewSyncCommitData2 {
1013            relay: self.data.relay,
1014            round: self.data.round,
1015            epoch: None,
1016        };
1017        let view_number = self.view_number;
1018
1019        SimpleVote {
1020            signature,
1021            data,
1022            view_number,
1023        }
1024    }
1025}
1026
1027impl<TYPES: NodeType> ViewSyncCommitVote2<TYPES> {
1028    /// Convert a `ViewSyncCommitVote2` to a `ViewSyncCommitVote`
1029    pub fn to_vote(self) -> ViewSyncCommitVote<TYPES> {
1030        let signature = self.signature;
1031        let data = ViewSyncCommitData {
1032            relay: self.data.relay,
1033            round: self.data.round,
1034        };
1035        let view_number = self.view_number;
1036
1037        SimpleVote {
1038            signature,
1039            data,
1040            view_number,
1041        }
1042    }
1043}
1044
1045impl<TYPES: NodeType> ViewSyncFinalizeVote<TYPES> {
1046    /// Convert a `ViewSyncFinalizeVote` to a `ViewSyncFinalizeVote2`
1047    pub fn to_vote2(self) -> ViewSyncFinalizeVote2<TYPES> {
1048        let signature = self.signature;
1049        let data = ViewSyncFinalizeData2 {
1050            relay: self.data.relay,
1051            round: self.data.round,
1052            epoch: None,
1053        };
1054        let view_number = self.view_number;
1055
1056        SimpleVote {
1057            signature,
1058            data,
1059            view_number,
1060        }
1061    }
1062}
1063
1064impl<TYPES: NodeType> ViewSyncFinalizeVote2<TYPES> {
1065    /// Convert a `ViewSyncFinalizeVote2` to a `ViewSyncFinalizeVote`
1066    pub fn to_vote(self) -> ViewSyncFinalizeVote<TYPES> {
1067        let signature = self.signature;
1068        let data = ViewSyncFinalizeData {
1069            relay: self.data.relay,
1070            round: self.data.round,
1071        };
1072        let view_number = self.view_number;
1073
1074        SimpleVote {
1075            signature,
1076            data,
1077            view_number,
1078        }
1079    }
1080}
1081
1082// Type aliases for simple use of all the main votes.  We should never see `SimpleVote` outside this file
1083
1084/// Quorum vote Alias
1085pub type QuorumVote<TYPES> = SimpleVote<TYPES, QuorumData<TYPES>>;
1086// Type aliases for simple use of all the main votes.  We should never see `SimpleVote` outside this file
1087/// Quorum vote Alias
1088pub type QuorumVote2<TYPES> = SimpleVote<TYPES, QuorumData2<TYPES>>;
1089/// Quorum vote Alias. This type is useful to distinguish the next epoch nodes' votes.
1090pub type NextEpochQuorumVote2<TYPES> = SimpleVote<TYPES, NextEpochQuorumData2<TYPES>>;
1091/// DA vote type alias
1092pub type DaVote<TYPES> = SimpleVote<TYPES, DaData>;
1093/// DA vote 2 type alias
1094pub type DaVote2<TYPES> = SimpleVote<TYPES, DaData2>;
1095
1096/// Timeout Vote type alias
1097pub type TimeoutVote<TYPES> = SimpleVote<TYPES, TimeoutData>;
1098/// Timeout Vote 2 type alias
1099pub type TimeoutVote2<TYPES> = SimpleVote<TYPES, TimeoutData2>;
1100/// Type alias for a `TimeoutVote3`, which is a `SimpleVote` over `TimeoutData3`
1101pub type TimeoutVote3<TYPES> = SimpleVote<TYPES, TimeoutData3>;
1102
1103/// View Sync Pre Commit Vote type alias
1104pub type ViewSyncPreCommitVote<TYPES> = SimpleVote<TYPES, ViewSyncPreCommitData>;
1105/// View Sync Pre Commit Vote 2 type alias
1106pub type ViewSyncPreCommitVote2<TYPES> = SimpleVote<TYPES, ViewSyncPreCommitData2>;
1107/// View Sync Finalize Vote type alias
1108pub type ViewSyncFinalizeVote<TYPES> = SimpleVote<TYPES, ViewSyncFinalizeData>;
1109/// View Sync Finalize Vote 2 type alias
1110pub type ViewSyncFinalizeVote2<TYPES> = SimpleVote<TYPES, ViewSyncFinalizeData2>;
1111/// View Sync Commit Vote type alias
1112pub type ViewSyncCommitVote<TYPES> = SimpleVote<TYPES, ViewSyncCommitData>;
1113/// View Sync Commit Vote 2 type alias
1114pub type ViewSyncCommitVote2<TYPES> = SimpleVote<TYPES, ViewSyncCommitData2>;
1115/// Upgrade proposal vote
1116pub type UpgradeVote<TYPES> = SimpleVote<TYPES, UpgradeProposalData>;
1117/// Upgrade vote binding its epoch
1118pub type UpgradeVote2<TYPES> = SimpleVote<TYPES, UpgradeProposalData2>;
1119
1120impl<TYPES: NodeType> Borrow<QuorumData2<TYPES>> for NextEpochQuorumData2<TYPES> {
1121    fn borrow(&self) -> &QuorumData2<TYPES> {
1122        &self.0
1123    }
1124}
1125impl<TYPES: NodeType> Deref for NextEpochQuorumData2<TYPES> {
1126    type Target = QuorumData2<TYPES>;
1127    fn deref(&self) -> &Self::Target {
1128        &self.0
1129    }
1130}
1131impl<TYPES: NodeType> DerefMut for NextEpochQuorumData2<TYPES> {
1132    fn deref_mut(&mut self) -> &mut Self::Target {
1133        &mut self.0
1134    }
1135}
1136impl<TYPES: NodeType> From<QuorumData2<TYPES>> for NextEpochQuorumData2<TYPES> {
1137    fn from(data: QuorumData2<TYPES>) -> Self {
1138        Self(QuorumData2 {
1139            epoch: data.epoch,
1140            leaf_commit: data.leaf_commit,
1141            block_number: data.block_number,
1142        })
1143    }
1144}
1145
1146impl<TYPES: NodeType> From<QuorumVote2<TYPES>> for NextEpochQuorumVote2<TYPES> {
1147    fn from(qvote: QuorumVote2<TYPES>) -> Self {
1148        Self {
1149            data: qvote.data.into(),
1150            view_number: qvote.view_number,
1151            signature: qvote.signature.clone(),
1152        }
1153    }
1154}
1155
1156/// Type for light client state update vote
1157#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
1158pub struct LightClientStateUpdateVote<TYPES: NodeType> {
1159    /// The epoch number
1160    pub epoch: EpochNumber,
1161    /// The light client state
1162    pub light_client_state: LightClientState,
1163    /// The next stake table state
1164    pub next_stake_table_state: StakeTableState,
1165    /// The signature to the light client state
1166    pub signature: <TYPES::StateSignatureKey as StateSignatureKey>::StateSignature,
1167}
1168
1169/// Type for light client state update vote
1170#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
1171pub struct LightClientStateUpdateVote2<TYPES: NodeType> {
1172    /// The epoch number
1173    pub epoch: EpochNumber,
1174    /// The light client state
1175    pub light_client_state: LightClientState,
1176    /// The next stake table state
1177    pub next_stake_table_state: StakeTableState,
1178    /// The signature to the light client state
1179    pub signature: <TYPES::StateSignatureKey as StateSignatureKey>::StateSignature,
1180    /// The signature to the light client V2 state
1181    pub v2_signature: <TYPES::StateSignatureKey as StateSignatureKey>::StateSignature,
1182    /// The auth root
1183    pub auth_root: FixedBytes<32>,
1184    /// The signed state digest used for LCV3
1185    /// WARN: this field cannot be trusted, you need to verify that it's consistent with other fields in this struct.
1186    /// It's here because it's hard to derive in the implementation of `LightClientStateUpdateVoteAccumulator`.
1187    #[serde(with = "canonical")]
1188    pub signed_state_digest: CircuitField,
1189}
1190
1191impl<TYPES: NodeType> LightClientStateUpdateVote<TYPES> {
1192    pub fn to_vote2(self) -> LightClientStateUpdateVote2<TYPES> {
1193        LightClientStateUpdateVote2 {
1194            epoch: self.epoch,
1195            light_client_state: self.light_client_state,
1196            next_stake_table_state: self.next_stake_table_state,
1197            signature: self.signature.clone(),
1198            v2_signature: self.signature,
1199            auth_root: Default::default(),
1200            signed_state_digest: Default::default(),
1201        }
1202    }
1203}
1204
1205impl<TYPES: NodeType> LightClientStateUpdateVote2<TYPES> {
1206    pub fn to_vote(self) -> LightClientStateUpdateVote<TYPES> {
1207        LightClientStateUpdateVote {
1208            epoch: self.epoch,
1209            light_client_state: self.light_client_state,
1210            next_stake_table_state: self.next_stake_table_state,
1211            signature: self.v2_signature,
1212        }
1213    }
1214}
1215
1216impl<TYPES: NodeType> HasViewNumber for LightClientStateUpdateVote<TYPES> {
1217    fn view_number(&self) -> ViewNumber {
1218        ViewNumber::new(self.light_client_state.view_number)
1219    }
1220}
1221
1222impl<TYPES: NodeType> HasEpoch for LightClientStateUpdateVote<TYPES> {
1223    fn epoch(&self) -> Option<EpochNumber> {
1224        Some(self.epoch)
1225    }
1226}
1227
1228#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
1229#[serde(bound(deserialize = "QuorumVote2<TYPES>:for<'a> Deserialize<'a>"))]
1230pub struct EpochRootQuorumVote<TYPES: NodeType> {
1231    pub vote: QuorumVote2<TYPES>,
1232    pub state_vote: LightClientStateUpdateVote<TYPES>,
1233}
1234
1235#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
1236#[serde(bound(deserialize = "QuorumVote2<TYPES>:for<'a> Deserialize<'a>"))]
1237pub struct EpochRootQuorumVote2<TYPES: NodeType> {
1238    pub vote: QuorumVote2<TYPES>,
1239    pub state_vote: LightClientStateUpdateVote2<TYPES>,
1240}
1241
1242impl<TYPES: NodeType> EpochRootQuorumVote<TYPES> {
1243    pub fn to_vote2(self) -> EpochRootQuorumVote2<TYPES> {
1244        EpochRootQuorumVote2 {
1245            vote: self.vote,
1246            state_vote: self.state_vote.to_vote2(),
1247        }
1248    }
1249}
1250
1251impl<TYPES: NodeType> EpochRootQuorumVote2<TYPES> {
1252    pub fn to_vote(self) -> EpochRootQuorumVote<TYPES> {
1253        EpochRootQuorumVote {
1254            vote: self.vote,
1255            state_vote: self.state_vote.to_vote(),
1256        }
1257    }
1258}
1259
1260impl<TYPES: NodeType> HasViewNumber for EpochRootQuorumVote<TYPES> {
1261    fn view_number(&self) -> ViewNumber {
1262        self.vote.view_number()
1263    }
1264}
1265
1266impl<TYPES: NodeType> HasEpoch for EpochRootQuorumVote<TYPES> {
1267    fn epoch(&self) -> Option<EpochNumber> {
1268        self.vote.epoch()
1269    }
1270}
1271
1272impl<TYPES: NodeType> HasViewNumber for EpochRootQuorumVote2<TYPES> {
1273    fn view_number(&self) -> ViewNumber {
1274        self.vote.view_number()
1275    }
1276}
1277
1278impl<TYPES: NodeType> HasEpoch for EpochRootQuorumVote2<TYPES> {
1279    fn epoch(&self) -> Option<EpochNumber> {
1280        self.vote.epoch()
1281    }
1282}