hotshot_types/
lib.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//! Types and Traits for the `HotShot` consensus module
8use std::{fmt::Debug, future::Future, num::NonZeroUsize, pin::Pin, time::Duration};
9
10use alloy::primitives::U256;
11use bincode::Options;
12use displaydoc::Display;
13use stake_table::HSStakeTable;
14use tracing::error;
15use traits::{
16    node_implementation::NodeType,
17    signature_key::{SignatureKey, StateSignatureKey},
18};
19use url::Url;
20use vec1::Vec1;
21
22use crate::utils::bincode_opts;
23pub mod bundle;
24pub mod consensus;
25pub mod constants;
26pub mod data;
27/// Holds the types and functions for DRB computation.
28pub mod drb;
29/// Epoch Membership wrappers
30pub mod epoch_membership;
31pub mod error;
32pub mod event;
33/// Holds the configuration file specification for a HotShot node.
34pub mod hotshot_config_file;
35pub mod light_client;
36pub mod message;
37
38/// Holds the network configuration specification for HotShot nodes.
39pub mod network;
40pub mod qc;
41pub mod request_response;
42pub mod signature_key;
43pub mod simple_certificate;
44pub mod simple_vote;
45pub mod stake_table;
46pub mod traits;
47
48pub mod storage_metrics;
49/// Holds the upgrade configuration specification for HotShot nodes.
50pub mod upgrade_config;
51pub mod utils;
52pub mod vid;
53pub mod vote;
54
55/// Pinned future that is Send and Sync
56pub type BoxSyncFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + Sync + 'a>>;
57
58/// yoinked from futures crate
59pub fn assert_future<T, F>(future: F) -> F
60where
61    F: Future<Output = T>,
62{
63    future
64}
65/// yoinked from futures crate, adds sync bound that we need
66pub fn boxed_sync<'a, F>(fut: F) -> BoxSyncFuture<'a, F::Output>
67where
68    F: Future + Sized + Send + Sync + 'a,
69{
70    assert_future::<F::Output, _>(Box::pin(fut))
71}
72
73#[derive(Clone, Debug, Display)]
74/// config for validator, including public key, private key, stake value
75pub struct ValidatorConfig<TYPES: NodeType> {
76    /// The validator's public key and stake value
77    pub public_key: TYPES::SignatureKey,
78    /// The validator's private key, should be in the mempool, not public
79    pub private_key: <TYPES::SignatureKey as SignatureKey>::PrivateKey,
80    /// The validator's stake
81    pub stake_value: U256,
82    /// the validator's key pairs for state verification
83    pub state_public_key: TYPES::StateSignatureKey,
84    /// the validator's key pairs for state verification
85    pub state_private_key: <TYPES::StateSignatureKey as StateSignatureKey>::StatePrivateKey,
86    /// Whether or not this validator is DA
87    pub is_da: bool,
88}
89
90impl<TYPES: NodeType> ValidatorConfig<TYPES> {
91    /// generate validator config from input seed, index, stake value, and whether it's DA
92    #[must_use]
93    pub fn generated_from_seed_indexed(
94        seed: [u8; 32],
95        index: u64,
96        stake_value: U256,
97        is_da: bool,
98    ) -> Self {
99        let (public_key, private_key) =
100            TYPES::SignatureKey::generated_from_seed_indexed(seed, index);
101        let (state_public_key, state_private_key) =
102            TYPES::StateSignatureKey::generated_from_seed_indexed(seed, index);
103        Self {
104            public_key,
105            private_key,
106            stake_value,
107            state_public_key,
108            state_private_key,
109            is_da,
110        }
111    }
112
113    /// get the public config of the validator
114    pub fn public_config(&self) -> PeerConfig<TYPES> {
115        PeerConfig {
116            stake_table_entry: self.public_key.stake_table_entry(self.stake_value),
117            state_ver_key: self.state_public_key.clone(),
118        }
119    }
120}
121
122impl<TYPES: NodeType> Default for ValidatorConfig<TYPES> {
123    fn default() -> Self {
124        Self::generated_from_seed_indexed([0u8; 32], 0, U256::from(1), true)
125    }
126}
127
128#[derive(serde::Serialize, serde::Deserialize, Clone, Display, PartialEq, Eq, Hash)]
129#[serde(bound(deserialize = ""))]
130/// structure of peers' config, including public key, stake value, and state key.
131pub struct PeerConfig<TYPES: NodeType> {
132    ////The peer's public key and stake value. The key is the BLS Public Key used to
133    /// verify Stake Holder in the application layer.
134    pub stake_table_entry: <TYPES::SignatureKey as SignatureKey>::StakeTableEntry,
135    //// The peer's state public key. This is the Schnorr Public Key used to
136    /// verify HotShot state in the state-prover.
137    pub state_ver_key: TYPES::StateSignatureKey,
138}
139
140impl<TYPES: NodeType> PeerConfig<TYPES> {
141    /// Serialize a peer's config to bytes
142    pub fn to_bytes(config: &Self) -> Vec<u8> {
143        let x = bincode_opts().serialize(config);
144        match x {
145            Ok(x) => x,
146            Err(e) => {
147                error!(?e, "Failed to serialize public key");
148                vec![]
149            },
150        }
151    }
152
153    /// Deserialize a peer's config from bytes
154    /// # Errors
155    /// Will return `None` if deserialization fails
156    pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
157        let x: Result<PeerConfig<TYPES>, _> = bincode_opts().deserialize(bytes);
158        match x {
159            Ok(pub_key) => Some(pub_key),
160            Err(e) => {
161                error!(?e, "Failed to deserialize public key");
162                None
163            },
164        }
165    }
166}
167
168impl<TYPES: NodeType> Default for PeerConfig<TYPES> {
169    fn default() -> Self {
170        let default_validator_config = ValidatorConfig::<TYPES>::default();
171        default_validator_config.public_config()
172    }
173}
174
175impl<TYPES: NodeType> Debug for PeerConfig<TYPES> {
176    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177        f.debug_struct("PeerConfig")
178            .field("stake_table_entry", &self.stake_table_entry)
179            .field("state_ver_key", &format_args!("{}", self.state_ver_key))
180            .finish()
181    }
182}
183
184/// Holds configuration for a `HotShot`
185#[derive(Clone, derive_more::Debug, serde::Serialize, serde::Deserialize)]
186#[serde(bound(deserialize = ""))]
187pub struct HotShotConfig<TYPES: NodeType> {
188    /// The proportion of nodes required before the orchestrator issues the ready signal,
189    /// expressed as (numerator, denominator)
190    pub start_threshold: (u64, u64),
191    /// Total number of nodes in the network
192    // Earlier it was total_nodes
193    pub num_nodes_with_stake: NonZeroUsize,
194    /// List of known node's public keys and stake value for certificate aggregation, serving as public parameter
195    pub known_nodes_with_stake: Vec<PeerConfig<TYPES>>,
196    /// All public keys known to be DA nodes
197    pub known_da_nodes: Vec<PeerConfig<TYPES>>,
198    /// List of DA committee (staking)nodes for static DA committee
199    pub da_staked_committee_size: usize,
200    /// Number of fixed leaders for GPU VID, normally it will be 0, it's only used when running GPU VID
201    pub fixed_leader_for_gpuvid: usize,
202    /// Base duration for next-view timeout, in milliseconds
203    pub next_view_timeout: u64,
204    /// Duration of view sync round timeouts
205    pub view_sync_timeout: Duration,
206    /// Number of network bootstrap nodes
207    pub num_bootstrap: usize,
208    /// The maximum amount of time a leader can wait to get a block from a builder
209    pub builder_timeout: Duration,
210    /// time to wait until we request data associated with a proposal
211    pub data_request_delay: Duration,
212    /// Builder API base URL
213    pub builder_urls: Vec1<Url>,
214    /// View to start proposing an upgrade
215    pub start_proposing_view: u64,
216    /// View to stop proposing an upgrade. To prevent proposing an upgrade, set stop_proposing_view <= start_proposing_view.
217    pub stop_proposing_view: u64,
218    /// View to start voting on an upgrade
219    pub start_voting_view: u64,
220    /// View to stop voting on an upgrade. To prevent voting on an upgrade, set stop_voting_view <= start_voting_view.
221    pub stop_voting_view: u64,
222    /// Unix time in seconds at which we start proposing an upgrade
223    pub start_proposing_time: u64,
224    /// Unix time in seconds at which we stop proposing an upgrade. To prevent proposing an upgrade, set stop_proposing_time <= start_proposing_time.
225    pub stop_proposing_time: u64,
226    /// Unix time in seconds at which we start voting on an upgrade
227    pub start_voting_time: u64,
228    /// Unix time in seconds at which we stop voting on an upgrade. To prevent voting on an upgrade, set stop_voting_time <= start_voting_time.
229    pub stop_voting_time: u64,
230    /// Number of blocks in an epoch, zero means there are no epochs
231    pub epoch_height: u64,
232    /// Epoch start block   
233    #[serde(default = "default_epoch_start_block")]
234    pub epoch_start_block: u64,
235    /// Stake table capacity for light client use
236    #[serde(default = "default_stake_table_capacity")]
237    pub stake_table_capacity: usize,
238    /// number of iterations in the DRB calculation
239    pub drb_difficulty: u64,
240    /// number of iterations in the DRB calculation
241    pub drb_upgrade_difficulty: u64,
242}
243
244fn default_epoch_start_block() -> u64 {
245    1
246}
247
248fn default_stake_table_capacity() -> usize {
249    crate::light_client::DEFAULT_STAKE_TABLE_CAPACITY
250}
251
252impl<TYPES: NodeType> HotShotConfig<TYPES> {
253    /// Update a hotshot config to have a view-based upgrade.
254    pub fn set_view_upgrade(&mut self, view: u64) {
255        self.start_proposing_view = view;
256        self.stop_proposing_view = view + 1;
257        self.start_voting_view = view.saturating_sub(1);
258        self.stop_voting_view = view + 10;
259        self.start_proposing_time = 0;
260        self.stop_proposing_time = u64::MAX;
261        self.start_voting_time = 0;
262        self.stop_voting_time = u64::MAX;
263    }
264
265    /// Return the `known_nodes_with_stake` as a `HSStakeTable`
266    pub fn hotshot_stake_table(&self) -> HSStakeTable<TYPES> {
267        self.known_nodes_with_stake.clone().into()
268    }
269}