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