hotshot_example_types/
node_types.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/>.
6use std::{
7    hash::{Hash, Hasher},
8    marker::PhantomData,
9};
10
11use hotshot::traits::{
12    implementations::{Cliquenet, CombinedNetworks, Libp2pNetwork, MemoryNetwork, PushCdnNetwork},
13    NodeImplementation,
14};
15use hotshot_types::{
16    constants::TEST_UPGRADE_CONSTANTS,
17    data::{EpochNumber, ViewNumber},
18    signature_key::{BLSPubKey, BuilderKey, SchnorrPubKey},
19    traits::node_implementation::{NodeType, Versions},
20    upgrade_config::UpgradeConstants,
21};
22use serde::{Deserialize, Serialize};
23use vbs::version::StaticVersion;
24
25pub use crate::membership::helpers::{RandomOverlapQuorumFilterConfig, StableQuorumFilterConfig};
26use crate::{
27    block_types::{TestBlockHeader, TestBlockPayload, TestTransaction},
28    membership::{
29        helpers::QuorumFilterConfig, randomized_committee::RandomizedStakeTable,
30        randomized_committee_members::RandomizedCommitteeMembers, stake_table::TestStakeTable,
31        static_committee::StaticStakeTable,
32        static_committee_leader_two_views::StaticStakeTableLeaderForTwoViews,
33        strict_membership::StrictMembership, two_static_committees::TwoStakeTables,
34    },
35    state_types::{TestInstanceState, TestValidatedState},
36    storage_types::TestStorage,
37};
38
39#[derive(
40    Copy,
41    Clone,
42    Debug,
43    Default,
44    Hash,
45    PartialEq,
46    Eq,
47    PartialOrd,
48    Ord,
49    serde::Serialize,
50    serde::Deserialize,
51)]
52/// filler struct to implement node type and allow us
53/// to select our traits
54pub struct TestTypes;
55impl NodeType for TestTypes {
56    const UPGRADE_CONSTANTS: UpgradeConstants = TEST_UPGRADE_CONSTANTS;
57
58    type View = ViewNumber;
59    type Epoch = EpochNumber;
60    type BlockHeader = TestBlockHeader;
61    type BlockPayload = TestBlockPayload;
62    type SignatureKey = BLSPubKey;
63    type Transaction = TestTransaction;
64    type ValidatedState = TestValidatedState;
65    type InstanceState = TestInstanceState;
66    type Membership = StrictMembership<TestTypes, StaticStakeTable<BLSPubKey, SchnorrPubKey>>;
67    type BuilderSignatureKey = BuilderKey;
68    type StateSignatureKey = SchnorrPubKey;
69}
70
71#[derive(
72    Copy,
73    Clone,
74    Debug,
75    Default,
76    Hash,
77    PartialEq,
78    Eq,
79    PartialOrd,
80    Ord,
81    serde::Serialize,
82    serde::Deserialize,
83)]
84/// filler struct to implement node type and allow us
85/// to select our traits
86pub struct TestTypesRandomizedLeader;
87impl NodeType for TestTypesRandomizedLeader {
88    const UPGRADE_CONSTANTS: UpgradeConstants = TEST_UPGRADE_CONSTANTS;
89
90    type View = ViewNumber;
91    type Epoch = EpochNumber;
92    type BlockHeader = TestBlockHeader;
93    type BlockPayload = TestBlockPayload;
94    type SignatureKey = BLSPubKey;
95    type Transaction = TestTransaction;
96    type ValidatedState = TestValidatedState;
97    type InstanceState = TestInstanceState;
98    type Membership =
99        StrictMembership<TestTypesRandomizedLeader, RandomizedStakeTable<BLSPubKey, SchnorrPubKey>>;
100    type BuilderSignatureKey = BuilderKey;
101    type StateSignatureKey = SchnorrPubKey;
102}
103
104#[derive(Debug, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
105pub struct TestTypesEpochCatchupTypes<StakeTable: TestStakeTable<BLSPubKey, SchnorrPubKey>> {
106    _pd: PhantomData<StakeTable>,
107}
108
109impl<StakeTable: TestStakeTable<BLSPubKey, SchnorrPubKey>> Default
110    for TestTypesEpochCatchupTypes<StakeTable>
111{
112    fn default() -> Self {
113        Self { _pd: PhantomData }
114    }
115}
116
117impl<StakeTable: TestStakeTable<BLSPubKey, SchnorrPubKey>> Hash
118    for TestTypesEpochCatchupTypes<StakeTable>
119{
120    fn hash<H: Hasher>(&self, state: &mut H) {
121        self._pd.hash(state);
122    }
123}
124
125impl<StakeTable: TestStakeTable<BLSPubKey, SchnorrPubKey>> PartialEq
126    for TestTypesEpochCatchupTypes<StakeTable>
127{
128    fn eq(&self, _other: &Self) -> bool {
129        true
130    }
131}
132
133impl<StakeTable: TestStakeTable<BLSPubKey, SchnorrPubKey>> Eq
134    for TestTypesEpochCatchupTypes<StakeTable>
135{
136}
137
138impl<StakeTable: TestStakeTable<BLSPubKey, SchnorrPubKey>> Copy
139    for TestTypesEpochCatchupTypes<StakeTable>
140{
141}
142
143impl<StakeTable: TestStakeTable<BLSPubKey, SchnorrPubKey>> Clone
144    for TestTypesEpochCatchupTypes<StakeTable>
145{
146    fn clone(&self) -> Self {
147        *self
148    }
149}
150
151impl<StakeTable: TestStakeTable<BLSPubKey, SchnorrPubKey> + 'static> NodeType
152    for TestTypesEpochCatchupTypes<StakeTable>
153{
154    const UPGRADE_CONSTANTS: UpgradeConstants = TEST_UPGRADE_CONSTANTS;
155
156    type View = ViewNumber;
157    type Epoch = EpochNumber;
158    type BlockHeader = TestBlockHeader;
159    type BlockPayload = TestBlockPayload;
160    type SignatureKey = BLSPubKey;
161    type Transaction = TestTransaction;
162    type ValidatedState = TestValidatedState;
163    type InstanceState = TestInstanceState;
164    type Membership = StrictMembership<TestTypesEpochCatchupTypes<StakeTable>, StakeTable>;
165    type BuilderSignatureKey = BuilderKey;
166    type StateSignatureKey = SchnorrPubKey;
167}
168
169#[derive(
170    Copy,
171    Clone,
172    Debug,
173    Default,
174    Hash,
175    PartialEq,
176    Eq,
177    PartialOrd,
178    Ord,
179    serde::Serialize,
180    serde::Deserialize,
181)]
182/// filler struct to implement node type and allow us
183/// to select our traits
184pub struct TestTypesRandomizedCommitteeMembers<
185    QuorumConfig: QuorumFilterConfig,
186    DaConfig: QuorumFilterConfig,
187> {
188    _pd: PhantomData<QuorumConfig>,
189    _dd: PhantomData<DaConfig>,
190}
191
192impl<QuorumConfig: QuorumFilterConfig, DaConfig: QuorumFilterConfig> NodeType
193    for TestTypesRandomizedCommitteeMembers<QuorumConfig, DaConfig>
194{
195    const UPGRADE_CONSTANTS: UpgradeConstants = TEST_UPGRADE_CONSTANTS;
196
197    type View = ViewNumber;
198    type Epoch = EpochNumber;
199    type BlockHeader = TestBlockHeader;
200    type BlockPayload = TestBlockPayload;
201    type SignatureKey = BLSPubKey;
202    type Transaction = TestTransaction;
203    type ValidatedState = TestValidatedState;
204    type InstanceState = TestInstanceState;
205    type Membership = StrictMembership<
206        TestTypesRandomizedCommitteeMembers<QuorumConfig, DaConfig>,
207        RandomizedCommitteeMembers<BLSPubKey, SchnorrPubKey, QuorumConfig, DaConfig>,
208    >;
209    type BuilderSignatureKey = BuilderKey;
210    type StateSignatureKey = SchnorrPubKey;
211}
212
213#[derive(
214    Copy,
215    Clone,
216    Debug,
217    Default,
218    Hash,
219    PartialEq,
220    Eq,
221    PartialOrd,
222    Ord,
223    serde::Serialize,
224    serde::Deserialize,
225)]
226/// filler struct to implement node type and allow us
227/// to select our traits
228pub struct TestConsecutiveLeaderTypes;
229impl NodeType for TestConsecutiveLeaderTypes {
230    const UPGRADE_CONSTANTS: UpgradeConstants = TEST_UPGRADE_CONSTANTS;
231
232    type View = ViewNumber;
233    type Epoch = EpochNumber;
234    type BlockHeader = TestBlockHeader;
235    type BlockPayload = TestBlockPayload;
236    type SignatureKey = BLSPubKey;
237    type Transaction = TestTransaction;
238    type ValidatedState = TestValidatedState;
239    type InstanceState = TestInstanceState;
240    type Membership = StrictMembership<
241        TestConsecutiveLeaderTypes,
242        StaticStakeTableLeaderForTwoViews<BLSPubKey, SchnorrPubKey>,
243    >;
244    type BuilderSignatureKey = BuilderKey;
245    type StateSignatureKey = SchnorrPubKey;
246}
247
248#[derive(
249    Copy,
250    Clone,
251    Debug,
252    Default,
253    Hash,
254    PartialEq,
255    Eq,
256    PartialOrd,
257    Ord,
258    serde::Serialize,
259    serde::Deserialize,
260)]
261/// filler struct to implement node type and allow us
262/// to select our traits
263pub struct TestTwoStakeTablesTypes;
264impl NodeType for TestTwoStakeTablesTypes {
265    const UPGRADE_CONSTANTS: UpgradeConstants = TEST_UPGRADE_CONSTANTS;
266
267    type View = ViewNumber;
268    type Epoch = EpochNumber;
269    type BlockHeader = TestBlockHeader;
270    type BlockPayload = TestBlockPayload;
271    type SignatureKey = BLSPubKey;
272    type Transaction = TestTransaction;
273    type ValidatedState = TestValidatedState;
274    type InstanceState = TestInstanceState;
275    type Membership =
276        StrictMembership<TestTwoStakeTablesTypes, TwoStakeTables<BLSPubKey, SchnorrPubKey>>;
277    type BuilderSignatureKey = BuilderKey;
278    type StateSignatureKey = SchnorrPubKey;
279}
280
281/// The Push CDN implementation
282#[derive(Clone, Debug, Deserialize, Serialize, Hash, Eq, PartialEq)]
283pub struct PushCdnImpl;
284
285/// Memory network implementation
286#[derive(Clone, Debug, Deserialize, Serialize, Hash, Eq, PartialEq)]
287pub struct MemoryImpl;
288
289/// Libp2p network implementation
290#[derive(Clone, Debug, Deserialize, Serialize, Hash, Eq, PartialEq)]
291pub struct Libp2pImpl;
292
293/// Cliquenet network implementation
294#[derive(Clone, Debug, Deserialize, Serialize, Hash, Eq, PartialEq)]
295pub struct CliquenetImpl;
296
297/// Web server network implementation
298#[derive(Clone, Debug, Deserialize, Serialize, Hash, Eq, PartialEq)]
299pub struct WebImpl;
300
301/// Combined Network implementation (libp2p + web server)
302#[derive(Clone, Debug, Deserialize, Serialize, Hash, Eq, PartialEq)]
303pub struct CombinedImpl;
304
305impl<TYPES: NodeType> NodeImplementation<TYPES> for PushCdnImpl {
306    type Network = PushCdnNetwork<TYPES::SignatureKey>;
307    type Storage = TestStorage<TYPES>;
308}
309
310impl<TYPES: NodeType> NodeImplementation<TYPES> for MemoryImpl {
311    type Network = MemoryNetwork<TYPES::SignatureKey>;
312    type Storage = TestStorage<TYPES>;
313}
314
315impl<TYPES: NodeType> NodeImplementation<TYPES> for CombinedImpl {
316    type Network = CombinedNetworks<TYPES>;
317    type Storage = TestStorage<TYPES>;
318}
319
320impl<TYPES: NodeType> NodeImplementation<TYPES> for Libp2pImpl {
321    type Network = Libp2pNetwork<TYPES>;
322    type Storage = TestStorage<TYPES>;
323}
324
325impl<TYPES: NodeType> NodeImplementation<TYPES> for CliquenetImpl {
326    type Network = Cliquenet<TYPES>;
327    type Storage = TestStorage<TYPES>;
328}
329
330#[derive(Clone, Debug, Copy)]
331pub struct TestVersions {}
332
333impl Versions for TestVersions {
334    type Base = StaticVersion<0, 1>;
335    type Upgrade = StaticVersion<0, 2>;
336    const UPGRADE_HASH: [u8; 32] = [
337        1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
338        0, 0,
339    ];
340
341    type Epochs = StaticVersion<0, 4>;
342    type DrbAndHeaderUpgrade = StaticVersion<0, 5>;
343    type Vid2Upgrade = StaticVersion<0, 6>;
344}
345
346#[derive(Clone, Debug, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
347pub struct EpochsTestVersions {}
348
349impl Versions for EpochsTestVersions {
350    type Base = StaticVersion<0, 3>;
351    type Upgrade = StaticVersion<0, 3>;
352    const UPGRADE_HASH: [u8; 32] = [
353        1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
354        0, 0,
355    ];
356
357    type Epochs = StaticVersion<0, 3>;
358    type DrbAndHeaderUpgrade = StaticVersion<0, 5>;
359    type Vid2Upgrade = StaticVersion<0, 6>;
360}
361
362#[derive(Clone, Debug, Copy)]
363pub struct EpochUpgradeTestVersions {}
364
365impl Versions for EpochUpgradeTestVersions {
366    type Base = StaticVersion<0, 3>;
367    type Upgrade = StaticVersion<0, 4>;
368    const UPGRADE_HASH: [u8; 32] = [
369        1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
370        0, 0,
371    ];
372
373    type Epochs = StaticVersion<0, 4>;
374    type DrbAndHeaderUpgrade = StaticVersion<0, 5>;
375    type Vid2Upgrade = StaticVersion<0, 6>;
376}
377
378#[derive(Clone, Debug, Copy)]
379pub struct DaCommitteeTestVersions {}
380
381impl Versions for DaCommitteeTestVersions {
382    type Base = StaticVersion<0, 4>;
383    type Upgrade = StaticVersion<0, 4>;
384    const UPGRADE_HASH: [u8; 32] = [
385        1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
386        0, 0,
387    ];
388
389    type Epochs = StaticVersion<0, 1>;
390    type DrbAndHeaderUpgrade = StaticVersion<0, 1>;
391    // TODO(Chengyu): tweak this version
392    type Vid2Upgrade = StaticVersion<0, 6>;
393}
394
395#[derive(Clone, Debug, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
396pub struct Vid2TestVersions {}
397
398impl Versions for Vid2TestVersions {
399    type Base = StaticVersion<0, 6>;
400    type Upgrade = StaticVersion<0, 6>;
401    const UPGRADE_HASH: [u8; 32] = [
402        1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
403        0, 0,
404    ];
405
406    type Epochs = StaticVersion<0, 3>;
407    type DrbAndHeaderUpgrade = StaticVersion<0, 5>;
408    type Vid2Upgrade = StaticVersion<0, 6>;
409}
410
411#[derive(Clone, Debug, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
412pub struct Vid2UpgradeTestVersions {}
413
414impl Versions for Vid2UpgradeTestVersions {
415    type Base = StaticVersion<0, 5>;
416    type Upgrade = StaticVersion<0, 6>;
417    const UPGRADE_HASH: [u8; 32] = [
418        1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
419        0, 0,
420    ];
421
422    type Epochs = StaticVersion<0, 3>;
423    type DrbAndHeaderUpgrade = StaticVersion<0, 5>;
424    type Vid2Upgrade = StaticVersion<0, 6>;
425}
426
427#[cfg(test)]
428mod tests {
429    use committable::{Commitment, Committable};
430    use hotshot_types::{
431        impl_has_epoch,
432        message::UpgradeLock,
433        simple_vote::{HasEpoch, VersionedVoteData},
434        traits::node_implementation::ConsensusTime,
435        utils::{genesis_epoch_from_version, option_epoch_from_block_number},
436    };
437    use serde::{Deserialize, Serialize};
438
439    use crate::node_types::{EpochsTestVersions, NodeType, TestTypes, TestVersions};
440    #[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Hash, Eq)]
441    /// Dummy data used for test
442    struct TestData<TYPES: NodeType> {
443        data: u64,
444        epoch: Option<TYPES::Epoch>,
445    }
446
447    impl<TYPES: NodeType> Committable for TestData<TYPES> {
448        fn commit(&self) -> Commitment<Self> {
449            committable::RawCommitmentBuilder::new("Test data")
450                .u64(self.data)
451                .finalize()
452        }
453    }
454
455    impl_has_epoch!(TestData<TYPES>);
456
457    #[tokio::test(flavor = "multi_thread")]
458    /// Test that the view number affects the commitment post-marketplace
459    async fn test_versioned_commitment_includes_view() {
460        let upgrade_lock = UpgradeLock::new();
461
462        let data = TestData {
463            data: 10,
464            epoch: None,
465        };
466
467        let view_0 = <TestTypes as NodeType>::View::new(0);
468        let view_1 = <TestTypes as NodeType>::View::new(1);
469
470        let versioned_data_0 =
471            VersionedVoteData::<TestTypes, TestData<TestTypes>, TestVersions>::new(
472                data,
473                view_0,
474                &upgrade_lock,
475            )
476            .await
477            .unwrap();
478        let versioned_data_1 =
479            VersionedVoteData::<TestTypes, TestData<TestTypes>, TestVersions>::new(
480                data,
481                view_1,
482                &upgrade_lock,
483            )
484            .await
485            .unwrap();
486
487        let versioned_data_commitment_0: [u8; 32] = versioned_data_0.commit().into();
488        let versioned_data_commitment_1: [u8; 32] = versioned_data_1.commit().into();
489
490        assert!(
491            versioned_data_commitment_0 != versioned_data_commitment_1,
492            "left: {versioned_data_commitment_0:?}, right: {versioned_data_commitment_1:?}"
493        );
494    }
495
496    #[test]
497    fn test_option_epoch_from_block_number() {
498        // block 0 is always epoch 0
499        let epoch = option_epoch_from_block_number::<TestTypes>(true, 1, 10);
500        assert_eq!(Some(<TestTypes as NodeType>::Epoch::new(1)), epoch);
501
502        let epoch = option_epoch_from_block_number::<TestTypes>(true, 1, 10);
503        assert_eq!(Some(<TestTypes as NodeType>::Epoch::new(1)), epoch);
504
505        let epoch = option_epoch_from_block_number::<TestTypes>(true, 10, 10);
506        assert_eq!(Some(<TestTypes as NodeType>::Epoch::new(1)), epoch);
507
508        let epoch = option_epoch_from_block_number::<TestTypes>(true, 11, 10);
509        assert_eq!(Some(<TestTypes as NodeType>::Epoch::new(2)), epoch);
510
511        let epoch = option_epoch_from_block_number::<TestTypes>(true, 20, 10);
512        assert_eq!(Some(<TestTypes as NodeType>::Epoch::new(2)), epoch);
513
514        let epoch = option_epoch_from_block_number::<TestTypes>(true, 21, 10);
515        assert_eq!(Some(<TestTypes as NodeType>::Epoch::new(3)), epoch);
516
517        let epoch = option_epoch_from_block_number::<TestTypes>(true, 21, 0);
518        assert_eq!(None, epoch);
519
520        let epoch = option_epoch_from_block_number::<TestTypes>(false, 21, 10);
521        assert_eq!(None, epoch);
522
523        let epoch = option_epoch_from_block_number::<TestTypes>(false, 21, 0);
524        assert_eq!(None, epoch);
525    }
526
527    #[test]
528    fn test_genesis_epoch_from_version() {
529        let epoch = genesis_epoch_from_version::<TestVersions, TestTypes>();
530        assert_eq!(None, epoch);
531
532        let epoch = genesis_epoch_from_version::<EpochsTestVersions, TestTypes>();
533        assert_eq!(Some(<TestTypes as NodeType>::Epoch::new(1)), epoch);
534    }
535}