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::{de::DeserializeOwned, Deserialize, Serialize};
21use vbs::version::Version;
22
23use crate::{
24    data::{Leaf, Leaf2, VidCommitment},
25    light_client::{CircuitField, LightClientState, StakeTableState},
26    message::UpgradeLock,
27    traits::{
28        node_implementation::{ConsensusTime, NodeType, Versions},
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<TYPES::Epoch>,
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<TYPES: NodeType> {
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<TYPES::Epoch>,
74}
75#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
76/// Data used for a timeout vote.
77pub struct TimeoutData<TYPES: NodeType> {
78    /// View the timeout is for
79    pub view: TYPES::View,
80}
81#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
82/// Data used for a timeout vote.
83pub struct TimeoutData2<TYPES: NodeType> {
84    /// View the timeout is for
85    pub view: TYPES::View,
86    /// Epoch number
87    pub epoch: Option<TYPES::Epoch>,
88}
89#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
90/// Data used for a Pre Commit vote.
91pub struct ViewSyncPreCommitData<TYPES: NodeType> {
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: TYPES::View,
96}
97#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
98/// Data used for a Pre Commit vote.
99pub struct ViewSyncPreCommitData2<TYPES: NodeType> {
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: TYPES::View,
104    /// Epoch number
105    pub epoch: Option<TYPES::Epoch>,
106}
107#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
108/// Data used for a Commit vote.
109pub struct ViewSyncCommitData<TYPES: NodeType> {
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: TYPES::View,
114}
115#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
116/// Data used for a Commit vote.
117pub struct ViewSyncCommitData2<TYPES: NodeType> {
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: TYPES::View,
122    /// Epoch number
123    pub epoch: Option<TYPES::Epoch>,
124}
125#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
126/// Data used for a Finalize vote.
127pub struct ViewSyncFinalizeData<TYPES: NodeType> {
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: TYPES::View,
132}
133#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
134/// Data used for a Finalize vote.
135pub struct ViewSyncFinalizeData2<TYPES: NodeType> {
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: TYPES::View,
140    /// Epoch number
141    pub epoch: Option<TYPES::Epoch>,
142}
143#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
144/// Data used for a Upgrade vote.
145pub struct UpgradeProposalData<TYPES: NodeType + DeserializeOwned> {
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: TYPES::View,
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: TYPES::View,
157    /// The first block for which the new version will be in effect.
158    pub new_version_first_view: TYPES::View,
159}
160
161/// Data used for an upgrade once epochs are implemented
162pub struct UpgradeData2<TYPES: NodeType> {
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<TYPES::Epoch>,
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<TYPES> + 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<T: NodeType> QuorumMarker for TimeoutData<T> {}
206impl<T: NodeType> QuorumMarker for TimeoutData2<T> {}
207impl<T: NodeType> QuorumMarker for ViewSyncPreCommitData<T> {}
208impl<T: NodeType> QuorumMarker for ViewSyncCommitData<T> {}
209impl<T: NodeType> QuorumMarker for ViewSyncFinalizeData<T> {}
210impl<T: NodeType> QuorumMarker for ViewSyncPreCommitData2<T> {}
211impl<T: NodeType> QuorumMarker for ViewSyncCommitData2<T> {}
212impl<T: NodeType> QuorumMarker for ViewSyncFinalizeData2<T> {}
213impl<T: NodeType + DeserializeOwned> QuorumMarker for UpgradeProposalData<T> {}
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: TYPES::View,
227}
228
229impl<TYPES: NodeType, DATA: Voteable<TYPES> + 'static> HasViewNumber<TYPES>
230    for SimpleVote<TYPES, DATA>
231{
232    fn view_number(&self) -> <TYPES as NodeType>::View {
233        self.view_number
234    }
235}
236
237impl<TYPES: NodeType, DATA: Voteable<TYPES> + 'static> Vote<TYPES> for SimpleVote<TYPES, DATA> {
238    type Commitment = DATA;
239
240    fn signing_key(&self) -> <TYPES as NodeType>::SignatureKey {
241        self.signature.0.clone()
242    }
243
244    fn signature(&self) -> <TYPES::SignatureKey as SignatureKey>::PureAssembledSignatureType {
245        self.signature.1.clone()
246    }
247
248    fn date(&self) -> &DATA {
249        &self.data
250    }
251
252    fn data_commitment(&self) -> Commitment<DATA> {
253        self.data.commit()
254    }
255}
256
257impl<TYPES: NodeType, DATA: Voteable<TYPES> + 'static> SimpleVote<TYPES, DATA> {
258    /// Creates and signs a simple vote
259    /// # Errors
260    /// If we are unable to sign the data
261    pub async fn create_signed_vote<V: Versions>(
262        data: DATA,
263        view: TYPES::View,
264        pub_key: &TYPES::SignatureKey,
265        private_key: &<TYPES::SignatureKey as SignatureKey>::PrivateKey,
266        upgrade_lock: &UpgradeLock<TYPES, V>,
267    ) -> Result<Self> {
268        let commit = VersionedVoteData::new(data.clone(), view, upgrade_lock)
269            .await?
270            .commit();
271
272        let signature = (
273            pub_key.clone(),
274            TYPES::SignatureKey::sign(private_key, commit.as_ref())
275                .wrap()
276                .context(error!("Failed to sign vote"))?,
277        );
278
279        Ok(Self {
280            signature,
281            data,
282            view_number: view,
283        })
284    }
285}
286
287#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
288/// A wrapper for vote data that carries a view number and an `upgrade_lock`, allowing switching the commitment calculation dynamically depending on the version
289pub struct VersionedVoteData<TYPES: NodeType, DATA: Voteable<TYPES>, V: Versions> {
290    /// underlying vote data
291    data: DATA,
292
293    /// view number
294    view: TYPES::View,
295
296    /// version applied to the view number
297    version: Version,
298
299    /// phantom data
300    _pd: PhantomData<V>,
301}
302
303impl<TYPES: NodeType, DATA: Voteable<TYPES>, V: Versions> VersionedVoteData<TYPES, DATA, V> {
304    /// Create a new `VersionedVoteData` struct
305    ///
306    /// # Errors
307    ///
308    /// Returns an error if `upgrade_lock.version(view)` is unable to return a version we support
309    pub async fn new(
310        data: DATA,
311        view: TYPES::View,
312        upgrade_lock: &UpgradeLock<TYPES, V>,
313    ) -> Result<Self> {
314        let version = upgrade_lock.version(view).await?;
315
316        Ok(Self {
317            data,
318            view,
319            version,
320            _pd: PhantomData,
321        })
322    }
323
324    /// Create a new `VersionedVoteData` struct
325    ///
326    /// This function cannot error, but may use an invalid version.
327    pub async fn new_infallible(
328        data: DATA,
329        view: TYPES::View,
330        upgrade_lock: &UpgradeLock<TYPES, V>,
331    ) -> Self {
332        let version = upgrade_lock.version_infallible(view).await;
333
334        Self {
335            data,
336            view,
337            version,
338            _pd: PhantomData,
339        }
340    }
341}
342
343impl<TYPES: NodeType, DATA: Voteable<TYPES>, V: Versions> Committable
344    for VersionedVoteData<TYPES, DATA, V>
345{
346    fn commit(&self) -> Commitment<Self> {
347        committable::RawCommitmentBuilder::new("Vote")
348            .var_size_bytes(self.data.commit().as_ref())
349            .u64(*self.view)
350            .finalize()
351    }
352}
353
354impl<TYPES: NodeType> Committable for QuorumData<TYPES> {
355    fn commit(&self) -> Commitment<Self> {
356        committable::RawCommitmentBuilder::new("Quorum data")
357            .var_size_bytes(self.leaf_commit.as_ref())
358            .finalize()
359    }
360}
361
362impl<TYPES: NodeType> Committable for QuorumData2<TYPES> {
363    fn commit(&self) -> Commitment<Self> {
364        let QuorumData2 {
365            leaf_commit,
366            epoch,
367            block_number,
368        } = self;
369
370        let mut cb = committable::RawCommitmentBuilder::new("Quorum data")
371            .var_size_bytes(leaf_commit.as_ref());
372
373        if let Some(ref epoch) = *epoch {
374            cb = cb.u64_field("epoch number", **epoch);
375        }
376
377        if let Some(ref block_number) = *block_number {
378            cb = cb.u64_field("block number", *block_number);
379        }
380
381        cb.finalize()
382    }
383}
384
385impl<TYPES: NodeType> Committable for NextEpochQuorumData2<TYPES> {
386    fn commit(&self) -> Commitment<Self> {
387        let NextEpochQuorumData2(QuorumData2 {
388            leaf_commit,
389            epoch,
390            block_number,
391        }) = self;
392
393        let mut cb = committable::RawCommitmentBuilder::new("Quorum data")
394            .var_size_bytes(leaf_commit.as_ref());
395
396        if let Some(ref epoch) = *epoch {
397            cb = cb.u64_field("epoch number", **epoch);
398        }
399
400        if let Some(ref block_number) = *block_number {
401            cb = cb.u64_field("block number", *block_number);
402        }
403
404        cb.finalize()
405    }
406}
407
408impl<TYPES: NodeType> Committable for TimeoutData<TYPES> {
409    fn commit(&self) -> Commitment<Self> {
410        committable::RawCommitmentBuilder::new("Timeout data")
411            .u64(*self.view)
412            .finalize()
413    }
414}
415
416impl<TYPES: NodeType> Committable for TimeoutData2<TYPES> {
417    fn commit(&self) -> Commitment<Self> {
418        let TimeoutData2 { view, epoch: _ } = self;
419
420        committable::RawCommitmentBuilder::new("Timeout data")
421            .u64(**view)
422            .finalize()
423    }
424}
425
426impl Committable for DaData {
427    fn commit(&self) -> Commitment<Self> {
428        committable::RawCommitmentBuilder::new("DA data")
429            .var_size_bytes(self.payload_commit.as_ref())
430            .finalize()
431    }
432}
433
434impl<TYPES: NodeType> Committable for DaData2<TYPES> {
435    fn commit(&self) -> Commitment<Self> {
436        let DaData2 {
437            payload_commit,
438            next_epoch_payload_commit,
439            epoch,
440        } = self;
441
442        let mut cb = committable::RawCommitmentBuilder::new("DA data")
443            .var_size_bytes(payload_commit.as_ref());
444
445        if let Some(ref next_epoch_payload_commit) = *next_epoch_payload_commit {
446            cb = cb.var_size_bytes(next_epoch_payload_commit.as_ref());
447        }
448
449        if let Some(ref epoch) = *epoch {
450            cb = cb.u64_field("epoch number", **epoch);
451        }
452
453        cb.finalize()
454    }
455}
456
457impl<TYPES: NodeType> Committable for UpgradeProposalData<TYPES> {
458    fn commit(&self) -> Commitment<Self> {
459        let builder = committable::RawCommitmentBuilder::new("Upgrade data");
460        builder
461            .u64(*self.decide_by)
462            .u64(*self.new_version_first_view)
463            .u64(*self.old_version_last_view)
464            .var_size_bytes(self.new_version_hash.as_slice())
465            .u16(self.new_version.minor)
466            .u16(self.new_version.major)
467            .u16(self.old_version.minor)
468            .u16(self.old_version.major)
469            .finalize()
470    }
471}
472
473impl<TYPES: NodeType> Committable for UpgradeData2<TYPES> {
474    fn commit(&self) -> Commitment<Self> {
475        let UpgradeData2 {
476            old_version,
477            new_version,
478            hash,
479            epoch,
480        } = self;
481
482        let mut cb = committable::RawCommitmentBuilder::new("Upgrade data")
483            .u16(old_version.minor)
484            .u16(old_version.major)
485            .u16(new_version.minor)
486            .u16(new_version.major)
487            .var_size_bytes(hash.as_slice());
488
489        if let Some(ref epoch) = *epoch {
490            cb = cb.u64_field("epoch number", **epoch);
491        }
492
493        cb.finalize()
494    }
495}
496
497/// This implements commit for all the types which contain a view and relay public key.
498fn view_and_relay_commit<TYPES: NodeType, T: Committable>(
499    view: TYPES::View,
500    relay: u64,
501    epoch: Option<TYPES::Epoch>,
502    tag: &str,
503) -> Commitment<T> {
504    let builder = committable::RawCommitmentBuilder::new(tag);
505    let mut cb = builder.u64(*view).u64(relay);
506
507    if let Some(epoch) = epoch {
508        cb = cb.u64_field("epoch number", *epoch);
509    }
510
511    cb.finalize()
512}
513
514impl<TYPES: NodeType> Committable for ViewSyncPreCommitData<TYPES> {
515    fn commit(&self) -> Commitment<Self> {
516        view_and_relay_commit::<TYPES, Self>(self.round, self.relay, None, "View Sync Precommit")
517    }
518}
519
520impl<TYPES: NodeType> Committable for ViewSyncPreCommitData2<TYPES> {
521    fn commit(&self) -> Commitment<Self> {
522        let ViewSyncPreCommitData2 {
523            relay,
524            round,
525            epoch,
526        } = self;
527
528        view_and_relay_commit::<TYPES, Self>(*round, *relay, *epoch, "View Sync Precommit")
529    }
530}
531
532impl<TYPES: NodeType> Committable for ViewSyncFinalizeData<TYPES> {
533    fn commit(&self) -> Commitment<Self> {
534        view_and_relay_commit::<TYPES, Self>(self.round, self.relay, None, "View Sync Finalize")
535    }
536}
537
538impl<TYPES: NodeType> Committable for ViewSyncFinalizeData2<TYPES> {
539    fn commit(&self) -> Commitment<Self> {
540        let ViewSyncFinalizeData2 {
541            relay,
542            round,
543            epoch,
544        } = self;
545
546        view_and_relay_commit::<TYPES, Self>(*round, *relay, *epoch, "View Sync Finalize")
547    }
548}
549
550impl<TYPES: NodeType> Committable for ViewSyncCommitData<TYPES> {
551    fn commit(&self) -> Commitment<Self> {
552        view_and_relay_commit::<TYPES, Self>(self.round, self.relay, None, "View Sync Commit")
553    }
554}
555
556impl<TYPES: NodeType> Committable for ViewSyncCommitData2<TYPES> {
557    fn commit(&self) -> Commitment<Self> {
558        let ViewSyncCommitData2 {
559            relay,
560            round,
561            epoch,
562        } = self;
563
564        view_and_relay_commit::<TYPES, Self>(*round, *relay, *epoch, "View Sync Commit")
565    }
566}
567
568/// A trait for types belonging for specific epoch
569pub trait HasEpoch<TYPES: NodeType> {
570    /// Returns `Epoch`
571    fn epoch(&self) -> Option<TYPES::Epoch>;
572}
573
574/// Helper macro for trivial implementation of the `HasEpoch` trait
575#[macro_export]
576macro_rules! impl_has_epoch {
577    ($($t:ty),*) => {
578        $(
579            impl<TYPES: NodeType> HasEpoch<TYPES> for $t {
580                fn epoch(&self) -> Option<TYPES::Epoch> {
581                    self.epoch
582                }
583            }
584        )*
585    };
586}
587
588impl_has_epoch!(
589    QuorumData2<TYPES>,
590    NextEpochQuorumData2<TYPES>,
591    DaData2<TYPES>,
592    TimeoutData2<TYPES>,
593    ViewSyncPreCommitData2<TYPES>,
594    ViewSyncCommitData2<TYPES>,
595    ViewSyncFinalizeData2<TYPES>,
596    UpgradeData2<TYPES>
597);
598
599/// Helper macro for trivial implementation of the `HasEpoch` trait for types that have no epoch
600#[macro_export]
601macro_rules! impl_has_none_epoch {
602    ($($t:ty),*) => {
603        $(
604            impl<TYPES: NodeType> HasEpoch<TYPES> for $t {
605                fn epoch(&self) -> Option<TYPES::Epoch> {
606                    None
607                }
608            }
609        )*
610    };
611}
612
613impl_has_none_epoch!(
614    QuorumData<TYPES>,
615    DaData,
616    TimeoutData<TYPES>,
617    ViewSyncPreCommitData<TYPES>,
618    ViewSyncCommitData<TYPES>,
619    ViewSyncFinalizeData<TYPES>,
620    UpgradeProposalData<TYPES>
621);
622
623impl<TYPES: NodeType, DATA: Voteable<TYPES> + HasEpoch<TYPES>> HasEpoch<TYPES>
624    for SimpleVote<TYPES, DATA>
625{
626    fn epoch(&self) -> Option<TYPES::Epoch> {
627        self.data.epoch()
628    }
629}
630
631// impl votable for all the data types in this file sealed marker should ensure nothing is accidentally
632// implemented for structs that aren't "voteable"
633impl<
634        TYPES: NodeType,
635        V: sealed::Sealed + Committable + Clone + Serialize + Debug + PartialEq + Hash + Eq,
636    > Voteable<TYPES> for V
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
645            + HasEpoch<TYPES>
646            + Committable
647            + Clone
648            + Serialize
649            + Debug
650            + PartialEq
651            + Hash
652            + Eq,
653    > Voteable2<TYPES> for V
654{
655}
656
657impl<TYPES: NodeType> QuorumVote<TYPES> {
658    /// Convert a `QuorumVote` to a `QuorumVote2`
659    pub fn to_vote2(self) -> QuorumVote2<TYPES> {
660        let bytes: [u8; 32] = self.data.leaf_commit.into();
661
662        let signature = self.signature;
663        let data = QuorumData2 {
664            leaf_commit: Commitment::from_raw(bytes),
665            epoch: None,
666            block_number: None,
667        };
668        let view_number = self.view_number;
669
670        SimpleVote {
671            signature,
672            data,
673            view_number,
674        }
675    }
676}
677
678impl<TYPES: NodeType> QuorumVote2<TYPES> {
679    /// Convert a `QuorumVote2` to a `QuorumVote`
680    pub fn to_vote(self) -> QuorumVote<TYPES> {
681        let bytes: [u8; 32] = self.data.leaf_commit.into();
682
683        let signature = self.signature.clone();
684        let data = QuorumData {
685            leaf_commit: Commitment::from_raw(bytes),
686        };
687        let view_number = self.view_number;
688
689        SimpleVote {
690            signature,
691            data,
692            view_number,
693        }
694    }
695}
696
697impl<TYPES: NodeType> DaVote<TYPES> {
698    /// Convert a `QuorumVote` to a `QuorumVote2`
699    pub fn to_vote2(self) -> DaVote2<TYPES> {
700        let signature = self.signature;
701        let data = DaData2 {
702            payload_commit: self.data.payload_commit,
703            next_epoch_payload_commit: None,
704            epoch: None,
705        };
706        let view_number = self.view_number;
707
708        SimpleVote {
709            signature,
710            data,
711            view_number,
712        }
713    }
714}
715
716impl<TYPES: NodeType> DaVote2<TYPES> {
717    /// Convert a `QuorumVote2` to a `QuorumVote`
718    pub fn to_vote(self) -> DaVote<TYPES> {
719        let signature = self.signature;
720        let data = DaData {
721            payload_commit: self.data.payload_commit,
722        };
723        let view_number = self.view_number;
724
725        SimpleVote {
726            signature,
727            data,
728            view_number,
729        }
730    }
731}
732
733impl<TYPES: NodeType> TimeoutVote<TYPES> {
734    /// Convert a `TimeoutVote` to a `TimeoutVote2`
735    pub fn to_vote2(self) -> TimeoutVote2<TYPES> {
736        let signature = self.signature;
737        let data = TimeoutData2 {
738            view: self.data.view,
739            epoch: None,
740        };
741        let view_number = self.view_number;
742
743        SimpleVote {
744            signature,
745            data,
746            view_number,
747        }
748    }
749}
750
751impl<TYPES: NodeType> TimeoutVote2<TYPES> {
752    /// Convert a `QuorumVote2` to a `QuorumVote`
753    pub fn to_vote(self) -> TimeoutVote<TYPES> {
754        let signature = self.signature;
755        let data = TimeoutData {
756            view: self.data.view,
757        };
758        let view_number = self.view_number;
759
760        SimpleVote {
761            signature,
762            data,
763            view_number,
764        }
765    }
766}
767
768impl<TYPES: NodeType> ViewSyncPreCommitVote<TYPES> {
769    /// Convert a `ViewSyncPreCommitVote` to a `ViewSyncPreCommitVote2`
770    pub fn to_vote2(self) -> ViewSyncPreCommitVote2<TYPES> {
771        let signature = self.signature;
772        let data = ViewSyncPreCommitData2 {
773            relay: self.data.relay,
774            round: self.data.round,
775            epoch: None,
776        };
777        let view_number = self.view_number;
778
779        SimpleVote {
780            signature,
781            data,
782            view_number,
783        }
784    }
785}
786
787impl<TYPES: NodeType> ViewSyncPreCommitVote2<TYPES> {
788    /// Convert a `ViewSyncPreCommitVote2` to a `ViewSyncPreCommitVote`
789    pub fn to_vote(self) -> ViewSyncPreCommitVote<TYPES> {
790        let signature = self.signature;
791        let data = ViewSyncPreCommitData {
792            relay: self.data.relay,
793            round: self.data.round,
794        };
795        let view_number = self.view_number;
796
797        SimpleVote {
798            signature,
799            data,
800            view_number,
801        }
802    }
803}
804
805impl<TYPES: NodeType> ViewSyncCommitVote<TYPES> {
806    /// Convert a `ViewSyncCommitVote` to a `ViewSyncCommitVote2`
807    pub fn to_vote2(self) -> ViewSyncCommitVote2<TYPES> {
808        let signature = self.signature;
809        let data = ViewSyncCommitData2 {
810            relay: self.data.relay,
811            round: self.data.round,
812            epoch: None,
813        };
814        let view_number = self.view_number;
815
816        SimpleVote {
817            signature,
818            data,
819            view_number,
820        }
821    }
822}
823
824impl<TYPES: NodeType> ViewSyncCommitVote2<TYPES> {
825    /// Convert a `ViewSyncCommitVote2` to a `ViewSyncCommitVote`
826    pub fn to_vote(self) -> ViewSyncCommitVote<TYPES> {
827        let signature = self.signature;
828        let data = ViewSyncCommitData {
829            relay: self.data.relay,
830            round: self.data.round,
831        };
832        let view_number = self.view_number;
833
834        SimpleVote {
835            signature,
836            data,
837            view_number,
838        }
839    }
840}
841
842impl<TYPES: NodeType> ViewSyncFinalizeVote<TYPES> {
843    /// Convert a `ViewSyncFinalizeVote` to a `ViewSyncFinalizeVote2`
844    pub fn to_vote2(self) -> ViewSyncFinalizeVote2<TYPES> {
845        let signature = self.signature;
846        let data = ViewSyncFinalizeData2 {
847            relay: self.data.relay,
848            round: self.data.round,
849            epoch: None,
850        };
851        let view_number = self.view_number;
852
853        SimpleVote {
854            signature,
855            data,
856            view_number,
857        }
858    }
859}
860
861impl<TYPES: NodeType> ViewSyncFinalizeVote2<TYPES> {
862    /// Convert a `ViewSyncFinalizeVote2` to a `ViewSyncFinalizeVote`
863    pub fn to_vote(self) -> ViewSyncFinalizeVote<TYPES> {
864        let signature = self.signature;
865        let data = ViewSyncFinalizeData {
866            relay: self.data.relay,
867            round: self.data.round,
868        };
869        let view_number = self.view_number;
870
871        SimpleVote {
872            signature,
873            data,
874            view_number,
875        }
876    }
877}
878
879// Type aliases for simple use of all the main votes.  We should never see `SimpleVote` outside this file
880
881/// Quorum vote Alias
882pub type QuorumVote<TYPES> = SimpleVote<TYPES, QuorumData<TYPES>>;
883// Type aliases for simple use of all the main votes.  We should never see `SimpleVote` outside this file
884/// Quorum vote Alias
885pub type QuorumVote2<TYPES> = SimpleVote<TYPES, QuorumData2<TYPES>>;
886/// Quorum vote Alias. This type is useful to distinguish the next epoch nodes' votes.
887pub type NextEpochQuorumVote2<TYPES> = SimpleVote<TYPES, NextEpochQuorumData2<TYPES>>;
888/// DA vote type alias
889pub type DaVote<TYPES> = SimpleVote<TYPES, DaData>;
890/// DA vote 2 type alias
891pub type DaVote2<TYPES> = SimpleVote<TYPES, DaData2<TYPES>>;
892
893/// Timeout Vote type alias
894pub type TimeoutVote<TYPES> = SimpleVote<TYPES, TimeoutData<TYPES>>;
895/// Timeout Vote 2 type alias
896pub type TimeoutVote2<TYPES> = SimpleVote<TYPES, TimeoutData2<TYPES>>;
897
898/// View Sync Pre Commit Vote type alias
899pub type ViewSyncPreCommitVote<TYPES> = SimpleVote<TYPES, ViewSyncPreCommitData<TYPES>>;
900/// View Sync Pre Commit Vote 2 type alias
901pub type ViewSyncPreCommitVote2<TYPES> = SimpleVote<TYPES, ViewSyncPreCommitData2<TYPES>>;
902/// View Sync Finalize Vote type alias
903pub type ViewSyncFinalizeVote<TYPES> = SimpleVote<TYPES, ViewSyncFinalizeData<TYPES>>;
904/// View Sync Finalize Vote 2 type alias
905pub type ViewSyncFinalizeVote2<TYPES> = SimpleVote<TYPES, ViewSyncFinalizeData2<TYPES>>;
906/// View Sync Commit Vote type alias
907pub type ViewSyncCommitVote<TYPES> = SimpleVote<TYPES, ViewSyncCommitData<TYPES>>;
908/// View Sync Commit Vote 2 type alias
909pub type ViewSyncCommitVote2<TYPES> = SimpleVote<TYPES, ViewSyncCommitData2<TYPES>>;
910/// Upgrade proposal vote
911pub type UpgradeVote<TYPES> = SimpleVote<TYPES, UpgradeProposalData<TYPES>>;
912/// Upgrade proposal 2 vote
913pub type UpgradeVote2<TYPES> = SimpleVote<TYPES, UpgradeData2<TYPES>>;
914
915impl<TYPES: NodeType> Deref for NextEpochQuorumData2<TYPES> {
916    type Target = QuorumData2<TYPES>;
917    fn deref(&self) -> &Self::Target {
918        &self.0
919    }
920}
921impl<TYPES: NodeType> DerefMut for NextEpochQuorumData2<TYPES> {
922    fn deref_mut(&mut self) -> &mut Self::Target {
923        &mut self.0
924    }
925}
926impl<TYPES: NodeType> From<QuorumData2<TYPES>> for NextEpochQuorumData2<TYPES> {
927    fn from(data: QuorumData2<TYPES>) -> Self {
928        Self(QuorumData2 {
929            epoch: data.epoch,
930            leaf_commit: data.leaf_commit,
931            block_number: data.block_number,
932        })
933    }
934}
935
936impl<TYPES: NodeType> From<QuorumVote2<TYPES>> for NextEpochQuorumVote2<TYPES> {
937    fn from(qvote: QuorumVote2<TYPES>) -> Self {
938        Self {
939            data: qvote.data.into(),
940            view_number: qvote.view_number,
941            signature: qvote.signature.clone(),
942        }
943    }
944}
945
946/// Type for light client state update vote
947#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
948pub struct LightClientStateUpdateVote<TYPES: NodeType> {
949    /// The epoch number
950    pub epoch: TYPES::Epoch,
951    /// The light client state
952    pub light_client_state: LightClientState,
953    /// The next stake table state
954    pub next_stake_table_state: StakeTableState,
955    /// The signature to the light client state
956    pub signature: <TYPES::StateSignatureKey as StateSignatureKey>::StateSignature,
957    /// The signature to the light client V2 state
958    pub v2_signature: <TYPES::StateSignatureKey as StateSignatureKey>::StateSignature,
959    /// The auth root
960    pub auth_root: FixedBytes<32>,
961    /// The signed state digest used for LCV3
962    /// WARN: this field cannot be trusted, you need to verify that it's consistent with other fields in this struct.
963    /// It's here because it's hard to derive in the implementation of `LightClientStateUpdateVoteAccumulator`.
964    #[serde(with = "canonical")]
965    pub signed_state_digest: CircuitField,
966}
967
968impl<TYPES: NodeType> HasViewNumber<TYPES> for LightClientStateUpdateVote<TYPES> {
969    fn view_number(&self) -> TYPES::View {
970        TYPES::View::new(self.light_client_state.view_number)
971    }
972}
973
974impl<TYPES: NodeType> HasEpoch<TYPES> for LightClientStateUpdateVote<TYPES> {
975    fn epoch(&self) -> Option<TYPES::Epoch> {
976        Some(self.epoch)
977    }
978}
979
980#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
981#[serde(bound(deserialize = "QuorumVote2<TYPES>:for<'a> Deserialize<'a>"))]
982pub struct EpochRootQuorumVote<TYPES: NodeType> {
983    pub vote: QuorumVote2<TYPES>,
984    pub state_vote: LightClientStateUpdateVote<TYPES>,
985}
986
987impl<TYPES: NodeType> HasViewNumber<TYPES> for EpochRootQuorumVote<TYPES> {
988    fn view_number(&self) -> TYPES::View {
989        self.vote.view_number()
990    }
991}
992
993impl<TYPES: NodeType> HasEpoch<TYPES> for EpochRootQuorumVote<TYPES> {
994    fn epoch(&self) -> Option<TYPES::Epoch> {
995        self.vote.epoch()
996    }
997}