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