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