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::{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/// Web server network implementation
294#[derive(Clone, Debug, Deserialize, Serialize, Hash, Eq, PartialEq)]
295pub struct WebImpl;
296
297/// Combined Network implementation (libp2p + web server)
298#[derive(Clone, Debug, Deserialize, Serialize, Hash, Eq, PartialEq)]
299pub struct CombinedImpl;
300
301impl<TYPES: NodeType> NodeImplementation<TYPES> for PushCdnImpl {
302    type Network = PushCdnNetwork<TYPES::SignatureKey>;
303    type Storage = TestStorage<TYPES>;
304}
305
306impl<TYPES: NodeType> NodeImplementation<TYPES> for MemoryImpl {
307    type Network = MemoryNetwork<TYPES::SignatureKey>;
308    type Storage = TestStorage<TYPES>;
309}
310
311impl<TYPES: NodeType> NodeImplementation<TYPES> for CombinedImpl {
312    type Network = CombinedNetworks<TYPES>;
313    type Storage = TestStorage<TYPES>;
314}
315
316impl<TYPES: NodeType> NodeImplementation<TYPES> for Libp2pImpl {
317    type Network = Libp2pNetwork<TYPES>;
318    type Storage = TestStorage<TYPES>;
319}
320
321#[derive(Clone, Debug, Copy)]
322pub struct TestVersions {}
323
324impl Versions for TestVersions {
325    type Base = StaticVersion<0, 1>;
326    type Upgrade = StaticVersion<0, 2>;
327    const UPGRADE_HASH: [u8; 32] = [
328        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,
329        0, 0,
330    ];
331
332    type Epochs = StaticVersion<0, 4>;
333    type DrbAndHeaderUpgrade = StaticVersion<0, 5>;
334}
335
336#[derive(Clone, Debug, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
337pub struct EpochsTestVersions {}
338
339impl Versions for EpochsTestVersions {
340    type Base = StaticVersion<0, 3>;
341    type Upgrade = StaticVersion<0, 3>;
342    const UPGRADE_HASH: [u8; 32] = [
343        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,
344        0, 0,
345    ];
346
347    type Epochs = StaticVersion<0, 3>;
348    type DrbAndHeaderUpgrade = StaticVersion<0, 5>;
349}
350
351#[derive(Clone, Debug, Copy)]
352pub struct EpochUpgradeTestVersions {}
353
354impl Versions for EpochUpgradeTestVersions {
355    type Base = StaticVersion<0, 3>;
356    type Upgrade = StaticVersion<0, 4>;
357    const UPGRADE_HASH: [u8; 32] = [
358        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,
359        0, 0,
360    ];
361
362    type Epochs = StaticVersion<0, 4>;
363    type DrbAndHeaderUpgrade = StaticVersion<0, 5>;
364}
365
366#[derive(Clone, Debug, Copy)]
367pub struct DaCommitteeTestVersions {}
368
369impl Versions for DaCommitteeTestVersions {
370    type Base = StaticVersion<0, 4>;
371    type Upgrade = StaticVersion<0, 4>;
372    const UPGRADE_HASH: [u8; 32] = [
373        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,
374        0, 0,
375    ];
376
377    type Epochs = StaticVersion<0, 1>;
378    type DrbAndHeaderUpgrade = StaticVersion<0, 1>;
379}
380
381#[cfg(test)]
382mod tests {
383    use committable::{Commitment, Committable};
384    use hotshot_types::{
385        impl_has_epoch,
386        message::UpgradeLock,
387        simple_vote::{HasEpoch, VersionedVoteData},
388        traits::node_implementation::ConsensusTime,
389        utils::{genesis_epoch_from_version, option_epoch_from_block_number},
390    };
391    use serde::{Deserialize, Serialize};
392
393    use crate::node_types::{EpochsTestVersions, NodeType, TestTypes, TestVersions};
394    #[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Hash, Eq)]
395    /// Dummy data used for test
396    struct TestData<TYPES: NodeType> {
397        data: u64,
398        epoch: Option<TYPES::Epoch>,
399    }
400
401    impl<TYPES: NodeType> Committable for TestData<TYPES> {
402        fn commit(&self) -> Commitment<Self> {
403            committable::RawCommitmentBuilder::new("Test data")
404                .u64(self.data)
405                .finalize()
406        }
407    }
408
409    impl_has_epoch!(TestData<TYPES>);
410
411    #[tokio::test(flavor = "multi_thread")]
412    /// Test that the view number affects the commitment post-marketplace
413    async fn test_versioned_commitment_includes_view() {
414        let upgrade_lock = UpgradeLock::new();
415
416        let data = TestData {
417            data: 10,
418            epoch: None,
419        };
420
421        let view_0 = <TestTypes as NodeType>::View::new(0);
422        let view_1 = <TestTypes as NodeType>::View::new(1);
423
424        let versioned_data_0 =
425            VersionedVoteData::<TestTypes, TestData<TestTypes>, TestVersions>::new(
426                data,
427                view_0,
428                &upgrade_lock,
429            )
430            .await
431            .unwrap();
432        let versioned_data_1 =
433            VersionedVoteData::<TestTypes, TestData<TestTypes>, TestVersions>::new(
434                data,
435                view_1,
436                &upgrade_lock,
437            )
438            .await
439            .unwrap();
440
441        let versioned_data_commitment_0: [u8; 32] = versioned_data_0.commit().into();
442        let versioned_data_commitment_1: [u8; 32] = versioned_data_1.commit().into();
443
444        assert!(
445            versioned_data_commitment_0 != versioned_data_commitment_1,
446            "left: {versioned_data_commitment_0:?}, right: {versioned_data_commitment_1:?}"
447        );
448    }
449
450    #[test]
451    fn test_option_epoch_from_block_number() {
452        // block 0 is always epoch 0
453        let epoch = option_epoch_from_block_number::<TestTypes>(true, 1, 10);
454        assert_eq!(Some(<TestTypes as NodeType>::Epoch::new(1)), epoch);
455
456        let epoch = option_epoch_from_block_number::<TestTypes>(true, 1, 10);
457        assert_eq!(Some(<TestTypes as NodeType>::Epoch::new(1)), epoch);
458
459        let epoch = option_epoch_from_block_number::<TestTypes>(true, 10, 10);
460        assert_eq!(Some(<TestTypes as NodeType>::Epoch::new(1)), epoch);
461
462        let epoch = option_epoch_from_block_number::<TestTypes>(true, 11, 10);
463        assert_eq!(Some(<TestTypes as NodeType>::Epoch::new(2)), epoch);
464
465        let epoch = option_epoch_from_block_number::<TestTypes>(true, 20, 10);
466        assert_eq!(Some(<TestTypes as NodeType>::Epoch::new(2)), epoch);
467
468        let epoch = option_epoch_from_block_number::<TestTypes>(true, 21, 10);
469        assert_eq!(Some(<TestTypes as NodeType>::Epoch::new(3)), epoch);
470
471        let epoch = option_epoch_from_block_number::<TestTypes>(true, 21, 0);
472        assert_eq!(None, epoch);
473
474        let epoch = option_epoch_from_block_number::<TestTypes>(false, 21, 10);
475        assert_eq!(None, epoch);
476
477        let epoch = option_epoch_from_block_number::<TestTypes>(false, 21, 0);
478        assert_eq!(None, epoch);
479    }
480
481    #[test]
482    fn test_genesis_epoch_from_version() {
483        let epoch = genesis_epoch_from_version::<TestVersions, TestTypes>();
484        assert_eq!(None, epoch);
485
486        let epoch = genesis_epoch_from_version::<EpochsTestVersions, TestTypes>();
487        assert_eq!(Some(<TestTypes as NodeType>::Epoch::new(1)), epoch);
488    }
489}