espresso_types/v0/
config.rs

1use std::{num::NonZeroUsize, time::Duration};
2
3use hotshot_types::{
4    network::{
5        BuilderType, CombinedNetworkConfig, Libp2pConfig, NetworkConfig, RandomBuilderConfig,
6    },
7    HotShotConfig, PeerConfig, ValidatorConfig,
8};
9use serde::{Deserialize, Serialize};
10use tide_disco::Url;
11use vec1::Vec1;
12
13use crate::{PubKey, SeqTypes};
14
15/// This struct defines the public Hotshot validator configuration.
16/// Private key and state key pairs are excluded for security reasons.
17#[derive(Clone, Debug, Deserialize, Serialize)]
18pub struct PublicValidatorConfig {
19    public_key: PubKey,
20    stake_value: u64,
21    is_da: bool,
22    private_key: String,
23    state_public_key: String,
24    state_key_pair: String,
25}
26
27impl From<ValidatorConfig<SeqTypes>> for PublicValidatorConfig {
28    fn from(v: ValidatorConfig<SeqTypes>) -> Self {
29        let ValidatorConfig::<SeqTypes> {
30            public_key,
31            private_key: _,
32            stake_value,
33            state_public_key,
34            state_private_key: _,
35            is_da,
36        } = v;
37
38        Self {
39            public_key,
40            stake_value: stake_value.to::<u64>(),
41            is_da,
42            state_public_key: state_public_key.to_string(),
43            private_key: "*****".into(),
44            state_key_pair: "*****".into(),
45        }
46    }
47}
48
49/// This struct defines the public Hotshot configuration parameters.
50/// Our config module features a GET endpoint accessible via the route `/hotshot` to display the hotshot config parameters.
51/// Hotshot config has sensitive information like private keys and such fields are excluded from this struct.
52#[derive(Clone, Debug, Deserialize, Serialize)]
53pub struct PublicHotShotConfig {
54    start_threshold: (u64, u64),
55    num_nodes_with_stake: NonZeroUsize,
56    known_nodes_with_stake: Vec<PeerConfig<SeqTypes>>,
57    known_da_nodes: Vec<PeerConfig<SeqTypes>>,
58    da_staked_committee_size: usize,
59    fixed_leader_for_gpuvid: usize,
60    next_view_timeout: u64,
61    view_sync_timeout: Duration,
62    num_bootstrap: usize,
63    builder_timeout: Duration,
64    data_request_delay: Duration,
65    builder_urls: Vec1<Url>,
66    start_proposing_view: u64,
67    stop_proposing_view: u64,
68    start_voting_view: u64,
69    stop_voting_view: u64,
70    start_proposing_time: u64,
71    stop_proposing_time: u64,
72    start_voting_time: u64,
73    stop_voting_time: u64,
74    epoch_height: u64,
75    epoch_start_block: u64,
76    #[serde(default = "default_stake_table_capacity")]
77    stake_table_capacity: usize,
78    #[serde(default = "default_drb_difficulty")]
79    drb_difficulty: u64,
80    #[serde(default = "default_drb_upgrade_difficulty")]
81    drb_upgrade_difficulty: u64,
82}
83
84fn default_stake_table_capacity() -> usize {
85    hotshot_types::light_client::DEFAULT_STAKE_TABLE_CAPACITY
86}
87
88/// Default DRB difficulty, set to 0 (intended to be overwritten)
89fn default_drb_difficulty() -> u64 {
90    0
91}
92
93/// Default DRB upgrade difficulty, set to 0 (intended to be overwritten)
94fn default_drb_upgrade_difficulty() -> u64 {
95    0
96}
97
98impl From<HotShotConfig<SeqTypes>> for PublicHotShotConfig {
99    fn from(v: HotShotConfig<SeqTypes>) -> Self {
100        // Destructure all fields from HotShotConfig to return an error
101        // if new fields are added to HotShotConfig. This makes sure that we handle
102        // all fields appropriately and do not miss any updates.
103        let HotShotConfig::<SeqTypes> {
104            start_threshold,
105            num_nodes_with_stake,
106            known_nodes_with_stake,
107            known_da_nodes,
108            da_staked_committee_size,
109            fixed_leader_for_gpuvid,
110            next_view_timeout,
111            view_sync_timeout,
112            num_bootstrap,
113            builder_timeout,
114            data_request_delay,
115            builder_urls,
116            start_proposing_view,
117            stop_proposing_view,
118            start_voting_view,
119            stop_voting_view,
120            start_proposing_time,
121            stop_proposing_time,
122            start_voting_time,
123            stop_voting_time,
124            epoch_height,
125            epoch_start_block,
126            stake_table_capacity,
127            drb_difficulty,
128            drb_upgrade_difficulty,
129        } = v;
130
131        Self {
132            start_threshold,
133            num_nodes_with_stake,
134            known_nodes_with_stake,
135            known_da_nodes,
136            da_staked_committee_size,
137            fixed_leader_for_gpuvid,
138            next_view_timeout,
139            view_sync_timeout,
140            num_bootstrap,
141            builder_timeout,
142            data_request_delay,
143            builder_urls,
144            start_proposing_view,
145            stop_proposing_view,
146            start_voting_view,
147            stop_voting_view,
148            start_proposing_time,
149            stop_proposing_time,
150            start_voting_time,
151            stop_voting_time,
152            epoch_height,
153            epoch_start_block,
154            stake_table_capacity,
155            drb_difficulty,
156            drb_upgrade_difficulty,
157        }
158    }
159}
160
161impl PublicHotShotConfig {
162    pub fn into_hotshot_config(self) -> HotShotConfig<SeqTypes> {
163        HotShotConfig {
164            start_threshold: self.start_threshold,
165            num_nodes_with_stake: self.num_nodes_with_stake,
166            known_nodes_with_stake: self.known_nodes_with_stake,
167            known_da_nodes: self.known_da_nodes,
168            da_staked_committee_size: self.da_staked_committee_size,
169            fixed_leader_for_gpuvid: self.fixed_leader_for_gpuvid,
170            next_view_timeout: self.next_view_timeout,
171            view_sync_timeout: self.view_sync_timeout,
172            num_bootstrap: self.num_bootstrap,
173            builder_timeout: self.builder_timeout,
174            data_request_delay: self.data_request_delay,
175            builder_urls: self.builder_urls,
176            start_proposing_view: self.start_proposing_view,
177            stop_proposing_view: self.stop_proposing_view,
178            start_voting_view: self.start_voting_view,
179            stop_voting_view: self.stop_voting_view,
180            start_proposing_time: self.start_proposing_time,
181            stop_proposing_time: self.stop_proposing_time,
182            start_voting_time: self.start_voting_time,
183            stop_voting_time: self.stop_voting_time,
184            epoch_height: self.epoch_height,
185            epoch_start_block: self.epoch_start_block,
186            stake_table_capacity: self.stake_table_capacity,
187            drb_difficulty: self.drb_difficulty,
188            drb_upgrade_difficulty: self.drb_upgrade_difficulty,
189        }
190    }
191
192    pub fn known_nodes_with_stake(&self) -> Vec<PeerConfig<SeqTypes>> {
193        self.known_nodes_with_stake.clone()
194    }
195
196    pub fn known_da_nodes(&self) -> Vec<PeerConfig<SeqTypes>> {
197        self.known_da_nodes.clone()
198    }
199    pub fn blocks_per_epoch(&self) -> u64 {
200        self.epoch_height
201    }
202    pub fn epoch_start_block(&self) -> u64 {
203        self.epoch_start_block
204    }
205}
206
207#[derive(Clone, Debug, Deserialize, Serialize)]
208pub struct PublicNetworkConfig {
209    rounds: usize,
210    indexed_da: bool,
211    transactions_per_round: usize,
212    manual_start_password: Option<String>,
213    num_bootrap: usize,
214    next_view_timeout: u64,
215    view_sync_timeout: Duration,
216    builder_timeout: Duration,
217    data_request_delay: Duration,
218    node_index: u64,
219    seed: [u8; 32],
220    transaction_size: usize,
221    key_type_name: String,
222    libp2p_config: Option<Libp2pConfig>,
223    config: PublicHotShotConfig,
224    cdn_marshal_address: Option<String>,
225    combined_network_config: Option<CombinedNetworkConfig>,
226    commit_sha: String,
227    builder: BuilderType,
228    random_builder: Option<RandomBuilderConfig>,
229}
230
231impl From<NetworkConfig<SeqTypes>> for PublicNetworkConfig {
232    fn from(cfg: NetworkConfig<SeqTypes>) -> Self {
233        Self {
234            rounds: cfg.rounds,
235            indexed_da: cfg.indexed_da,
236            transactions_per_round: cfg.transactions_per_round,
237            manual_start_password: Some("*****".into()),
238            num_bootrap: cfg.num_bootrap,
239            next_view_timeout: cfg.next_view_timeout,
240            view_sync_timeout: cfg.view_sync_timeout,
241            builder_timeout: cfg.builder_timeout,
242            data_request_delay: cfg.data_request_delay,
243            node_index: cfg.node_index,
244            seed: cfg.seed,
245            transaction_size: cfg.transaction_size,
246            key_type_name: cfg.key_type_name,
247            libp2p_config: cfg.libp2p_config,
248            config: cfg.config.into(),
249            cdn_marshal_address: cfg.cdn_marshal_address,
250            combined_network_config: cfg.combined_network_config,
251            commit_sha: cfg.commit_sha,
252            builder: cfg.builder,
253            random_builder: cfg.random_builder,
254        }
255    }
256}
257
258impl PublicNetworkConfig {
259    pub fn into_network_config(
260        self,
261        my_own_validator_config: ValidatorConfig<SeqTypes>,
262    ) -> anyhow::Result<NetworkConfig<SeqTypes>> {
263        let node_index = self
264            .config
265            .known_nodes_with_stake
266            .iter()
267            .position(|peer| peer.stake_table_entry.stake_key == my_own_validator_config.public_key)
268            .unwrap_or(0) as u64;
269
270        Ok(NetworkConfig {
271            rounds: self.rounds,
272            indexed_da: self.indexed_da,
273            transactions_per_round: self.transactions_per_round,
274            manual_start_password: self.manual_start_password,
275            num_bootrap: self.num_bootrap,
276            next_view_timeout: self.next_view_timeout,
277            view_sync_timeout: self.view_sync_timeout,
278            builder_timeout: self.builder_timeout,
279            data_request_delay: self.data_request_delay,
280            node_index,
281            seed: self.seed,
282            transaction_size: self.transaction_size,
283            key_type_name: self.key_type_name,
284            libp2p_config: self.libp2p_config,
285            config: self.config.into_hotshot_config(),
286            cdn_marshal_address: self.cdn_marshal_address,
287            combined_network_config: self.combined_network_config,
288            commit_sha: self.commit_sha,
289            builder: self.builder,
290            random_builder: self.random_builder,
291            public_keys: Vec::new(),
292        })
293    }
294
295    pub fn hotshot_config(&self) -> PublicHotShotConfig {
296        self.config.clone()
297    }
298}
299
300#[cfg(test)]
301mod tests {
302    use super::PublicNetworkConfig;
303
304    #[test]
305    fn test_deserialize_from_old_config() {
306        // pulled from decaf node
307        let json_str = r#"
308        {
309  "rounds": 100,
310  "indexed_da": false,
311  "transactions_per_round": 10,
312  "manual_start_password": "*****",
313  "num_bootrap": 5,
314  "next_view_timeout": 10,
315  "view_sync_timeout": {
316    "secs": 2,
317    "nanos": 0
318  },
319  "builder_timeout": {
320    "secs": 10,
321    "nanos": 0
322  },
323  "data_request_delay": {
324    "secs": 2,
325    "nanos": 500000000
326  },
327  "node_index": 1,
328  "seed": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
329  "transaction_size": 100,
330  "key_type_name": "jf_signature::bls_over_bn254::VerKey",
331  "libp2p_config": {
332    "bootstrap_nodes": []
333  },
334  "config": {
335    "start_threshold": [100, 100],
336    "num_nodes_with_stake": 100,
337    "known_nodes_with_stake": [],
338    "known_da_nodes": [],
339    "da_staked_committee_size": 100,
340    "fixed_leader_for_gpuvid": 1,
341    "next_view_timeout": 12000,
342    "view_sync_timeout": {
343      "secs": 1,
344      "nanos": 0
345    },
346    "num_bootstrap": 5,
347    "builder_timeout": {
348      "secs": 8,
349      "nanos": 0
350    },
351    "data_request_delay": {
352      "secs": 5,
353      "nanos": 0
354    },
355    "builder_urls": [
356      "https://builder.decaf.testnet.espresso.network/"
357    ],
358    "start_proposing_view": 0,
359    "stop_proposing_view": 0,
360    "start_voting_view": 0,
361    "stop_voting_view": 0,
362    "start_proposing_time": 0,
363    "stop_proposing_time": 0,
364    "start_voting_time": 0,
365    "stop_voting_time": 0,
366    "epoch_height": 3000,
367    "epoch_start_block": 3160636
368  },
369  "cdn_marshal_address": null,
370  "combined_network_config": null,
371  "commit_sha": "",
372  "builder": "Simple",
373  "random_builder": null
374}
375        "#;
376        let _public_config: PublicNetworkConfig = serde_json::from_str(json_str).unwrap();
377    }
378}