Skip to main content

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