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