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