hotshot_types/traits/
node_implementation.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//! Composite trait for node behavior
8//!
9//! This module defines the [`NodeImplementation`] trait, which is a composite trait used for
10//! describing the overall behavior of a node, as a composition of implementations of the node trait.
11
12use std::{
13    fmt::{Debug, Display},
14    hash::Hash,
15    ops::{self, Deref, Sub},
16    sync::Arc,
17    time::Duration,
18};
19
20use async_trait::async_trait;
21use committable::Committable;
22use serde::{Deserialize, Serialize};
23use vbs::version::StaticVersionType;
24
25use super::{
26    block_contents::{BlockHeader, TestableBlock, Transaction},
27    network::{
28        AsyncGenerator, ConnectedNetwork, NetworkReliability, TestableNetworkingImplementation,
29    },
30    signature_key::{
31        BuilderSignatureKey, LCV1StateSignatureKey, LCV2StateSignatureKey, LCV3StateSignatureKey,
32        StateSignatureKey,
33    },
34    states::TestableState,
35    storage::Storage,
36    ValidatedState,
37};
38use crate::{
39    constants::DEFAULT_UPGRADE_CONSTANTS,
40    data::{Leaf2, TestableLeaf},
41    traits::{
42        election::Membership, signature_key::SignatureKey, states::InstanceState, BlockPayload,
43    },
44    upgrade_config::UpgradeConstants,
45};
46
47/// Node implementation aggregate trait
48///
49/// This trait exists to collect multiple behavior implementations into one type, to allow
50/// `HotShot` to avoid annoying numbers of type arguments and type patching.
51///
52/// It is recommended you implement this trait on a zero sized type, as `HotShot`does not actually
53/// store or keep a reference to any value implementing this trait.
54pub trait NodeImplementation<TYPES: NodeType>:
55    Send + Sync + Clone + Eq + Hash + 'static + Serialize + for<'de> Deserialize<'de>
56{
57    /// The underlying network type
58    type Network: ConnectedNetwork<TYPES::SignatureKey>;
59
60    /// Storage for DA layer interactions
61    type Storage: Storage<TYPES>;
62}
63
64/// extra functions required on a node implementation to be usable by hotshot-testing
65#[allow(clippy::type_complexity)]
66#[async_trait]
67pub trait TestableNodeImplementation<TYPES: NodeType>: NodeImplementation<TYPES> {
68    /// Creates random transaction if possible
69    /// otherwise panics
70    /// `padding` is the bytes of padding to add to the transaction
71    fn state_create_random_transaction(
72        state: Option<&TYPES::ValidatedState>,
73        rng: &mut dyn rand::RngCore,
74        padding: u64,
75    ) -> <TYPES::BlockPayload as BlockPayload<TYPES>>::Transaction;
76
77    /// Creates random transaction if possible
78    /// otherwise panics
79    /// `padding` is the bytes of padding to add to the transaction
80    fn leaf_create_random_transaction(
81        leaf: &Leaf2<TYPES>,
82        rng: &mut dyn rand::RngCore,
83        padding: u64,
84    ) -> <TYPES::BlockPayload as BlockPayload<TYPES>>::Transaction;
85
86    /// generate a genesis block
87    fn block_genesis() -> TYPES::BlockPayload;
88
89    /// the number of transactions in a block
90    fn txn_count(block: &TYPES::BlockPayload) -> u64;
91
92    /// Generate the communication channels for testing
93    fn gen_networks(
94        expected_node_count: usize,
95        num_bootstrap: usize,
96        da_committee_size: usize,
97        reliability_config: Option<Box<dyn NetworkReliability>>,
98        secondary_network_delay: Duration,
99    ) -> AsyncGenerator<Arc<Self::Network>>;
100}
101
102#[async_trait]
103impl<TYPES: NodeType, I: NodeImplementation<TYPES>> TestableNodeImplementation<TYPES> for I
104where
105    TYPES::ValidatedState: TestableState<TYPES>,
106    TYPES::BlockPayload: TestableBlock<TYPES>,
107    I::Network: TestableNetworkingImplementation<TYPES>,
108{
109    fn state_create_random_transaction(
110        state: Option<&TYPES::ValidatedState>,
111        rng: &mut dyn rand::RngCore,
112        padding: u64,
113    ) -> <TYPES::BlockPayload as BlockPayload<TYPES>>::Transaction {
114        <TYPES::ValidatedState as TestableState<TYPES>>::create_random_transaction(
115            state, rng, padding,
116        )
117    }
118
119    fn leaf_create_random_transaction(
120        leaf: &Leaf2<TYPES>,
121        rng: &mut dyn rand::RngCore,
122        padding: u64,
123    ) -> <TYPES::BlockPayload as BlockPayload<TYPES>>::Transaction {
124        Leaf2::create_random_transaction(leaf, rng, padding)
125    }
126
127    fn block_genesis() -> TYPES::BlockPayload {
128        <TYPES::BlockPayload as TestableBlock<TYPES>>::genesis()
129    }
130
131    fn txn_count(block: &TYPES::BlockPayload) -> u64 {
132        <TYPES::BlockPayload as TestableBlock<TYPES>>::txn_count(block)
133    }
134
135    fn gen_networks(
136        expected_node_count: usize,
137        num_bootstrap: usize,
138        da_committee_size: usize,
139        reliability_config: Option<Box<dyn NetworkReliability>>,
140        secondary_network_delay: Duration,
141    ) -> AsyncGenerator<Arc<Self::Network>> {
142        <I::Network as TestableNetworkingImplementation<TYPES>>::generator(
143            expected_node_count,
144            num_bootstrap,
145            0,
146            da_committee_size,
147            reliability_config.clone(),
148            secondary_network_delay,
149        )
150    }
151}
152
153/// Trait for time compatibility needed for reward collection
154pub trait ConsensusTime:
155    PartialOrd
156    + Ord
157    + Send
158    + Sync
159    + Debug
160    + Clone
161    + Copy
162    + Hash
163    + Deref<Target = u64>
164    + serde::Serialize
165    + for<'de> serde::Deserialize<'de>
166    + ops::AddAssign<u64>
167    + ops::Add<u64, Output = Self>
168    + Sub<u64, Output = Self>
169    + 'static
170    + Committable
171{
172    /// Create a new instance of this time unit at time number 0
173    #[must_use]
174    fn genesis() -> Self {
175        Self::new(0)
176    }
177
178    /// Create a new instance of this time unit
179    fn new(val: u64) -> Self;
180
181    /// Get the u64 format of time
182    fn u64(&self) -> u64;
183}
184
185/// Trait with all the type definitions that are used in the current hotshot setup.
186pub trait NodeType:
187    Clone
188    + Copy
189    + Debug
190    + Hash
191    + PartialEq
192    + Eq
193    + Default
194    + serde::Serialize
195    + for<'de> Deserialize<'de>
196    + Send
197    + Sync
198    + 'static
199{
200    /// Constants used to construct upgrade proposals
201    const UPGRADE_CONSTANTS: UpgradeConstants = DEFAULT_UPGRADE_CONSTANTS;
202    /// The time type that this hotshot setup is using.
203    ///
204    /// This should be the same `Time` that `ValidatedState::Time` is using.
205    type View: ConsensusTime + Display;
206    /// Same as above but for epoch.
207    type Epoch: ConsensusTime + Display;
208    /// The block header type that this hotshot setup is using.
209    type BlockHeader: BlockHeader<Self>;
210    /// The block type that this hotshot setup is using.
211    ///
212    /// This should be the same block that `ValidatedState::BlockPayload` is using.
213    type BlockPayload: BlockPayload<
214        Self,
215        Instance = Self::InstanceState,
216        Transaction = Self::Transaction,
217        ValidatedState = Self::ValidatedState,
218    >;
219    /// The signature key that this hotshot setup is using.
220    type SignatureKey: SignatureKey;
221    /// The transaction type that this hotshot setup is using.
222    ///
223    /// This should be equal to `BlockPayload::Transaction`
224    type Transaction: Transaction;
225
226    /// The instance-level state type that this hotshot setup is using.
227    type InstanceState: InstanceState;
228
229    /// The validated state type that this hotshot setup is using.
230    type ValidatedState: ValidatedState<Self, Instance = Self::InstanceState, Time = Self::View>;
231
232    /// Membership used for this implementation
233    type Membership: Membership<Self>;
234
235    /// The type builder uses to sign its messages
236    type BuilderSignatureKey: BuilderSignatureKey;
237
238    /// The type replica uses to sign the light client state
239    type StateSignatureKey: StateSignatureKey
240        + LCV1StateSignatureKey
241        + LCV2StateSignatureKey
242        + LCV3StateSignatureKey;
243}
244
245/// Version information for HotShot
246pub trait Versions: Clone + Copy + Debug + Send + Sync + 'static {
247    /// The base version of HotShot this node is instantiated with.
248    type Base: StaticVersionType;
249
250    /// The version of HotShot this node may be upgraded to. Set equal to `Base` to disable upgrades.
251    type Upgrade: StaticVersionType;
252
253    /// The hash for the upgrade.
254    const UPGRADE_HASH: [u8; 32];
255
256    /// The version at which to switch over to epochs logic
257    type Epochs: StaticVersionType;
258
259    /// The version at which to use the upgraded DRB difficulty
260    type DrbAndHeaderUpgrade: StaticVersionType;
261}