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