espresso_types/v0/
config.rs

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