sui_config/
p2p.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::{net::SocketAddr, num::NonZeroU32, path::PathBuf, time::Duration};
5
6use serde::{Deserialize, Serialize};
7use sui_types::{
8    messages_checkpoint::{CheckpointDigest, CheckpointSequenceNumber},
9    multiaddr::Multiaddr,
10};
11
12#[derive(Clone, Debug, Deserialize, Serialize)]
13#[serde(rename_all = "kebab-case")]
14pub struct P2pConfig {
15    /// The address that the p2p network will bind on.
16    #[serde(default = "default_listen_address")]
17    pub listen_address: SocketAddr,
18    /// The external address other nodes can use to reach this node.
19    /// This will be shared with other peers through the discovery service
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub external_address: Option<Multiaddr>,
22    /// SeedPeers are preferred and the node will always try to ensure a
23    /// connection is established with these nodes.
24    #[serde(skip_serializing_if = "Vec::is_empty", default)]
25    pub seed_peers: Vec<SeedPeer>,
26    /// Manually configured peer addresses. These override addresses loaded from on-chain configs.
27    #[serde(skip_serializing_if = "Vec::is_empty", default)]
28    pub peer_address_overrides: Vec<PeerAddresses>,
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub anemo_config: Option<anemo::Config>,
31    #[serde(skip_serializing_if = "Option::is_none")]
32    pub state_sync: Option<StateSyncConfig>,
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub discovery: Option<DiscoveryConfig>,
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub randomness: Option<RandomnessConfig>,
37    /// Size in bytes above which network messages are considered excessively large. Excessively
38    /// large messages will still be handled, but logged and reported in metrics for debugging.
39    ///
40    /// If unspecified, this will default to 8 MiB.
41    #[serde(skip_serializing_if = "Option::is_none")]
42    pub excessive_message_size: Option<usize>,
43}
44
45fn default_listen_address() -> SocketAddr {
46    "0.0.0.0:8084".parse().unwrap()
47}
48
49impl Default for P2pConfig {
50    fn default() -> Self {
51        Self {
52            listen_address: default_listen_address(),
53            external_address: Default::default(),
54            seed_peers: Default::default(),
55            peer_address_overrides: Default::default(),
56            anemo_config: Default::default(),
57            state_sync: None,
58            discovery: None,
59            randomness: None,
60            excessive_message_size: None,
61        }
62    }
63}
64
65impl P2pConfig {
66    pub fn excessive_message_size(&self) -> usize {
67        const EXCESSIVE_MESSAGE_SIZE: usize = 32 << 20;
68
69        self.excessive_message_size
70            .unwrap_or(EXCESSIVE_MESSAGE_SIZE)
71    }
72
73    pub fn set_discovery_config(mut self, discovery_config: DiscoveryConfig) -> Self {
74        self.discovery = Some(discovery_config);
75        self
76    }
77}
78
79#[derive(Clone, Debug, Deserialize, Serialize)]
80#[serde(rename_all = "kebab-case")]
81pub struct SeedPeer {
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub peer_id: Option<anemo::PeerId>,
84    pub address: Multiaddr,
85}
86
87#[derive(Clone, Debug, Deserialize, Serialize)]
88#[serde(rename_all = "kebab-case")]
89pub struct AllowlistedPeer {
90    pub peer_id: anemo::PeerId,
91    #[serde(skip_serializing_if = "Option::is_none")]
92    pub address: Option<Multiaddr>,
93}
94
95#[derive(Clone, Debug, Deserialize, Serialize)]
96#[serde(rename_all = "kebab-case")]
97pub struct PeerAddresses {
98    pub peer_id: anemo::PeerId,
99    pub addresses: Vec<Multiaddr>,
100}
101
102#[derive(Clone, Debug, Default, Deserialize, Serialize)]
103#[serde(rename_all = "kebab-case")]
104pub struct StateSyncConfig {
105    /// List of "known-good" checkpoints that state sync will be forced to use. State sync will
106    /// skip verification of pinned checkpoints, and reject checkpoints with digests that don't
107    /// match pinned values for a given sequence number.
108    ///
109    /// This can be used:
110    /// - in case of a fork, to prevent the node from syncing to the wrong chain.
111    /// - in case of a network stall, to force the node to proceed with a manually-injected
112    ///   checkpoint.
113    #[serde(skip_serializing_if = "Vec::is_empty", default)]
114    pub pinned_checkpoints: Vec<(CheckpointSequenceNumber, CheckpointDigest)>,
115
116    /// Query peers for their latest checkpoint every interval period.
117    ///
118    /// If unspecified, this will default to `5,000` milliseconds.
119    #[serde(skip_serializing_if = "Option::is_none")]
120    pub interval_period_ms: Option<u64>,
121
122    /// Size of the StateSync actor's mailbox.
123    ///
124    /// If unspecified, this will default to `1,024`.
125    #[serde(skip_serializing_if = "Option::is_none")]
126    pub mailbox_capacity: Option<usize>,
127
128    /// Size of the broadcast channel use for notifying other systems of newly sync'ed checkpoints.
129    ///
130    /// If unspecified, this will default to `1,024`.
131    #[serde(skip_serializing_if = "Option::is_none")]
132    pub synced_checkpoint_broadcast_channel_capacity: Option<usize>,
133
134    /// Set the upper bound on the number of checkpoint headers to be downloaded concurrently.
135    ///
136    /// If unspecified, this will default to `400`.
137    #[serde(skip_serializing_if = "Option::is_none")]
138    pub checkpoint_header_download_concurrency: Option<usize>,
139
140    /// Set the upper bound on the number of checkpoint contents to be downloaded concurrently.
141    ///
142    /// If unspecified, this will default to `400`.
143    #[serde(skip_serializing_if = "Option::is_none")]
144    pub checkpoint_content_download_concurrency: Option<usize>,
145
146    /// Set the upper bound on the number of individual transactions contained in checkpoint
147    /// contents to be downloaded concurrently. If both this value and
148    /// `checkpoint_content_download_concurrency` are set, the lower of the two will apply.
149    ///
150    /// If unspecified, this will default to `50,000`.
151    #[serde(skip_serializing_if = "Option::is_none")]
152    pub checkpoint_content_download_tx_concurrency: Option<u64>,
153
154    /// Set the timeout that should be used when sending most state-sync RPC requests.
155    ///
156    /// If unspecified, this will default to `10,000` milliseconds.
157    #[serde(skip_serializing_if = "Option::is_none")]
158    pub timeout_ms: Option<u64>,
159
160    /// Set the timeout that should be used when sending RPC requests to sync checkpoint contents.
161    ///
162    /// If unspecified, this will default to `10,000` milliseconds.
163    #[serde(skip_serializing_if = "Option::is_none")]
164    pub checkpoint_content_timeout_ms: Option<u64>,
165
166    /// Per-peer rate-limit (in requests/sec) for the PushCheckpointSummary RPC.
167    ///
168    /// If unspecified, this will default to no limit.
169    #[serde(skip_serializing_if = "Option::is_none")]
170    pub push_checkpoint_summary_rate_limit: Option<NonZeroU32>,
171
172    /// Per-peer rate-limit (in requests/sec) for the GetCheckpointSummary RPC.
173    ///
174    /// If unspecified, this will default to no limit.
175    #[serde(skip_serializing_if = "Option::is_none")]
176    pub get_checkpoint_summary_rate_limit: Option<NonZeroU32>,
177
178    /// Per-peer rate-limit (in requests/sec) for the GetCheckpointContents RPC.
179    ///
180    /// If unspecified, this will default to no limit.
181    #[serde(skip_serializing_if = "Option::is_none")]
182    pub get_checkpoint_contents_rate_limit: Option<NonZeroU32>,
183
184    /// Per-peer inflight limit for the GetCheckpointContents RPC.
185    ///
186    /// If unspecified, this will default to no limit.
187    #[serde(skip_serializing_if = "Option::is_none")]
188    pub get_checkpoint_contents_inflight_limit: Option<usize>,
189
190    /// Per-checkpoint inflight limit for the GetCheckpointContents RPC. This is enforced globally
191    /// across all peers.
192    ///
193    /// If unspecified, this will default to no limit.
194    #[serde(skip_serializing_if = "Option::is_none")]
195    pub get_checkpoint_contents_per_checkpoint_limit: Option<usize>,
196
197    /// The amount of time to wait before retry if there are no peers to sync content from.
198    /// If unspecified, this will set to default value
199    #[serde(skip_serializing_if = "Option::is_none")]
200    pub wait_interval_when_no_peer_to_sync_content_ms: Option<u64>,
201
202    /// If true, the v2 version of get_checkpoint_contents will be used.
203    ///
204    /// If unspecified, this will default to true.
205    #[serde(skip_serializing_if = "Option::is_none")]
206    pub use_get_checkpoint_contents_v2: Option<bool>,
207
208    /// Maximum lookahead (in checkpoint sequence numbers) for storing unverified checkpoint
209    /// summaries received via PushCheckpointSummary.
210    ///
211    /// If unspecified, this will default to `1,000`.
212    #[serde(skip_serializing_if = "Option::is_none")]
213    pub max_checkpoint_lookahead: Option<u64>,
214
215    /// Maximum number of checkpoint headers to attempt to sync in a single sync task.
216    ///
217    /// If unspecified, this will default to `400`.
218    #[serde(skip_serializing_if = "Option::is_none")]
219    pub max_checkpoint_sync_batch_size: Option<u64>,
220
221    /// Maximum serialized size in bytes for a CertifiedCheckpointSummary received via
222    /// PushCheckpointSummary.
223    ///
224    /// If unspecified, this will default to `262,144` (256 KiB).
225    #[serde(skip_serializing_if = "Option::is_none")]
226    pub max_checkpoint_summary_size: Option<usize>,
227
228    /// Minimum timeout for checkpoint content downloads (adaptive timeout lower bound).
229    ///
230    /// If unspecified, this will default to `10,000` milliseconds.
231    #[serde(skip_serializing_if = "Option::is_none")]
232    pub checkpoint_content_timeout_min_ms: Option<u64>,
233
234    /// Maximum timeout for checkpoint content downloads (adaptive timeout upper bound).
235    ///
236    /// If unspecified, this will default to `30,000` milliseconds.
237    #[serde(skip_serializing_if = "Option::is_none")]
238    pub checkpoint_content_timeout_max_ms: Option<u64>,
239
240    /// Time window for peer scoring samples.
241    ///
242    /// If unspecified, this will default to `60,000` milliseconds.
243    #[serde(skip_serializing_if = "Option::is_none")]
244    pub peer_scoring_window_ms: Option<u64>,
245
246    /// Probability of selecting an unknown peer to explore its throughput.
247    ///
248    /// If unspecified, this will default to `0.1`.
249    #[serde(skip_serializing_if = "Option::is_none")]
250    pub exploration_probability: Option<f64>,
251
252    /// Failure rate threshold for marking a peer as failing.
253    /// A peer is marked as failing if its failure rate exceeds this threshold.
254    ///
255    /// If unspecified, this will default to `0.3` (30%).
256    #[serde(skip_serializing_if = "Option::is_none")]
257    pub peer_failure_rate: Option<f64>,
258
259    /// Duration in milliseconds that a peer must be continuously failing before it is
260    /// reported to discovery for disconnection. Set to 0 to disable automatic reporting
261    /// of failing peers.
262    ///
263    /// If unspecified, this will default to `30,000` (30 seconds).
264    #[serde(skip_serializing_if = "Option::is_none")]
265    pub peer_disconnect_threshold_ms: Option<u64>,
266}
267
268impl StateSyncConfig {
269    pub fn interval_period(&self) -> Duration {
270        const INTERVAL_PERIOD_MS: u64 = 5_000; // 5 seconds
271
272        Duration::from_millis(self.interval_period_ms.unwrap_or(INTERVAL_PERIOD_MS))
273    }
274
275    pub fn mailbox_capacity(&self) -> usize {
276        const MAILBOX_CAPACITY: usize = 1_024;
277
278        self.mailbox_capacity.unwrap_or(MAILBOX_CAPACITY)
279    }
280
281    pub fn synced_checkpoint_broadcast_channel_capacity(&self) -> usize {
282        const SYNCED_CHECKPOINT_BROADCAST_CHANNEL_CAPACITY: usize = 1_024;
283
284        self.synced_checkpoint_broadcast_channel_capacity
285            .unwrap_or(SYNCED_CHECKPOINT_BROADCAST_CHANNEL_CAPACITY)
286    }
287
288    pub fn checkpoint_header_download_concurrency(&self) -> usize {
289        const CHECKPOINT_HEADER_DOWNLOAD_CONCURRENCY: usize = 400;
290
291        self.checkpoint_header_download_concurrency
292            .unwrap_or(CHECKPOINT_HEADER_DOWNLOAD_CONCURRENCY)
293    }
294
295    pub fn checkpoint_content_download_concurrency(&self) -> usize {
296        const CHECKPOINT_CONTENT_DOWNLOAD_CONCURRENCY: usize = 400;
297
298        self.checkpoint_content_download_concurrency
299            .unwrap_or(CHECKPOINT_CONTENT_DOWNLOAD_CONCURRENCY)
300    }
301
302    pub fn checkpoint_content_download_tx_concurrency(&self) -> u64 {
303        const CHECKPOINT_CONTENT_DOWNLOAD_TX_CONCURRENCY: u64 = 50_000;
304
305        self.checkpoint_content_download_tx_concurrency
306            .unwrap_or(CHECKPOINT_CONTENT_DOWNLOAD_TX_CONCURRENCY)
307    }
308
309    pub fn timeout(&self) -> Duration {
310        const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
311
312        self.timeout_ms
313            .map(Duration::from_millis)
314            .unwrap_or(DEFAULT_TIMEOUT)
315    }
316
317    pub fn checkpoint_content_timeout(&self) -> Duration {
318        const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60);
319
320        self.checkpoint_content_timeout_ms
321            .map(Duration::from_millis)
322            .unwrap_or(DEFAULT_TIMEOUT)
323    }
324
325    pub fn wait_interval_when_no_peer_to_sync_content(&self) -> Duration {
326        self.wait_interval_when_no_peer_to_sync_content_ms
327            .map(Duration::from_millis)
328            .unwrap_or(self.default_wait_interval_when_no_peer_to_sync_content())
329    }
330
331    fn default_wait_interval_when_no_peer_to_sync_content(&self) -> Duration {
332        if cfg!(msim) {
333            Duration::from_secs(5)
334        } else {
335            Duration::from_secs(10)
336        }
337    }
338
339    pub fn use_get_checkpoint_contents_v2(&self) -> bool {
340        const DEFAULT_USE_GET_CHECKPOINT_CONTENTS_V2: bool = true;
341
342        self.use_get_checkpoint_contents_v2
343            .unwrap_or(DEFAULT_USE_GET_CHECKPOINT_CONTENTS_V2)
344    }
345
346    pub fn max_checkpoint_lookahead(&self) -> u64 {
347        const DEFAULT_MAX_CHECKPOINT_LOOKAHEAD: u64 = 1_000;
348
349        self.max_checkpoint_lookahead
350            .unwrap_or(DEFAULT_MAX_CHECKPOINT_LOOKAHEAD)
351    }
352
353    pub fn max_checkpoint_sync_batch_size(&self) -> u64 {
354        const DEFAULT_MAX_CHECKPOINT_SYNC_BATCH_SIZE: u64 = 400;
355
356        self.max_checkpoint_sync_batch_size
357            .unwrap_or(DEFAULT_MAX_CHECKPOINT_SYNC_BATCH_SIZE)
358    }
359
360    pub fn max_checkpoint_summary_size(&self) -> usize {
361        const DEFAULT_MAX_CHECKPOINT_SUMMARY_SIZE: usize = 256 * 1024; // 256 KiB
362
363        self.max_checkpoint_summary_size
364            .unwrap_or(DEFAULT_MAX_CHECKPOINT_SUMMARY_SIZE)
365    }
366
367    pub fn checkpoint_content_timeout_min(&self) -> Duration {
368        const DEFAULT: Duration = Duration::from_secs(5);
369        self.checkpoint_content_timeout_min_ms
370            .map(Duration::from_millis)
371            .unwrap_or(DEFAULT)
372    }
373
374    pub fn checkpoint_content_timeout_max(&self) -> Duration {
375        const DEFAULT: Duration = Duration::from_secs(30);
376        self.checkpoint_content_timeout_max_ms
377            .map(Duration::from_millis)
378            .unwrap_or(DEFAULT)
379    }
380
381    pub fn peer_scoring_window(&self) -> Duration {
382        const DEFAULT: Duration = Duration::from_secs(60);
383        self.peer_scoring_window_ms
384            .map(Duration::from_millis)
385            .unwrap_or(DEFAULT)
386    }
387
388    pub fn exploration_probability(&self) -> f64 {
389        const DEFAULT: f64 = 0.1;
390        let value = self.exploration_probability.unwrap_or(DEFAULT);
391        assert!(
392            (0.0..=1.0).contains(&value),
393            "exploration_probability must be in [0, 1], got {value}"
394        );
395        value
396    }
397
398    pub fn peer_failure_rate(&self) -> f64 {
399        const DEFAULT: f64 = 0.3;
400        let value = self.peer_failure_rate.unwrap_or(DEFAULT);
401        assert!(
402            (0.0..=1.0).contains(&value),
403            "peer_failure_rate must be in [0, 1], got {value}"
404        );
405        value
406    }
407
408    pub fn peer_disconnect_threshold(&self) -> Duration {
409        const DEFAULT_MS: u64 = 30_000; // 30 seconds
410        Duration::from_millis(self.peer_disconnect_threshold_ms.unwrap_or(DEFAULT_MS))
411    }
412
413    pub fn randomized_for_testing() -> Self {
414        use rand::Rng;
415        let mut rng = rand::thread_rng();
416        let config = Self {
417            mailbox_capacity: Some(rng.gen_range(16..=2048)),
418            synced_checkpoint_broadcast_channel_capacity: Some(rng.gen_range(16..=2048)),
419            checkpoint_header_download_concurrency: Some(rng.gen_range(10..=500)),
420            checkpoint_content_download_concurrency: Some(rng.gen_range(10..=500)),
421            max_checkpoint_lookahead: Some(rng.gen_range(100..=2000)),
422            max_checkpoint_sync_batch_size: Some(rng.gen_range(100..=500)),
423            max_checkpoint_summary_size: Some(rng.gen_range(64 * 1024..=512 * 1024)),
424            ..Default::default()
425        };
426        tracing::info!(
427            mailbox_capacity = config.mailbox_capacity.unwrap(),
428            broadcast_capacity = config.synced_checkpoint_broadcast_channel_capacity.unwrap(),
429            header_concurrency = config.checkpoint_header_download_concurrency.unwrap(),
430            content_concurrency = config.checkpoint_content_download_concurrency.unwrap(),
431            lookahead = config.max_checkpoint_lookahead.unwrap(),
432            batch_size = config.max_checkpoint_sync_batch_size.unwrap(),
433            summary_size = config.max_checkpoint_summary_size.unwrap(),
434            "StateSyncConfig::randomized_for_testing"
435        );
436        config
437    }
438}
439
440/// Access Type of a node.
441/// AccessType info is shared in the discovery process.
442/// * If the node marks itself as Public, other nodes may try to connect to it.
443/// * If the node marks itself as Private, only nodes that have it in
444///   their `allowlisted_peers` or `seed_peers` will try to connect to it. The
445///   node's info will not be shared through discovery.
446/// * Trusted is the same as Private, except it allows sharing the node's info
447///   only to other preconfigured peers (i.e. those in `allowlisted_peers` and
448///   `seed_peers`).
449/// * If not set, defaults to Public.
450///
451/// AccessType is useful when a network of nodes want to stay private. To achieve this,
452/// mark every node in this network as `Private` or `Trusted`, and allowlist/seed them
453/// to each other.
454#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
455pub enum AccessType {
456    Public,
457    Private,
458    Trusted,
459}
460
461#[derive(Clone, Debug, Default, Deserialize, Serialize)]
462#[serde(rename_all = "kebab-case")]
463pub struct DiscoveryConfig {
464    /// Query peers for their latest checkpoint every interval period.
465    ///
466    /// If unspecified, this will default to `5,000` milliseconds.
467    #[serde(skip_serializing_if = "Option::is_none")]
468    pub interval_period_ms: Option<u64>,
469
470    /// Target number of concurrent connections to establish.
471    ///
472    /// If unspecified, this will default to `4`.
473    #[serde(skip_serializing_if = "Option::is_none")]
474    pub target_concurrent_connections: Option<usize>,
475
476    /// Number of peers to query each interval.
477    ///
478    /// Sets the number of peers, to be randomly selected, that are queried for their known peers
479    /// each interval.
480    ///
481    /// If unspecified, this will default to `1`.
482    #[serde(skip_serializing_if = "Option::is_none")]
483    pub peers_to_query: Option<usize>,
484
485    /// Per-peer rate-limit (in requests/sec) for the GetKnownPeers RPC.
486    ///
487    /// If unspecified, this will default to no limit.
488    #[serde(skip_serializing_if = "Option::is_none")]
489    pub get_known_peers_rate_limit: Option<NonZeroU32>,
490
491    /// See docstring for `AccessType`.
492    #[serde(skip_serializing_if = "Option::is_none")]
493    pub access_type: Option<AccessType>,
494
495    /// Like `seed_peers` in `P2pConfig`, allowlisted peers will always be allowed to establish
496    /// connection with this node regardless of the concurrency limit.
497    /// Unlike `seed_peers`, a node does not reach out to `allowlisted_peers` preferentially.
498    /// It is also used to determine if a peer is accessible when its AccessType is Private.
499    /// For example, a node will ignore a peer with Private AccessType if the peer is not in
500    /// its `allowlisted_peers`. Namely, the node will not try to establish connections
501    /// to this peer, nor advertise this peer's info to other peers in the network.
502    #[serde(skip_serializing_if = "Vec::is_empty", default)]
503    pub allowlisted_peers: Vec<AllowlistedPeer>,
504
505    /// Size of the Discovery loop's mailbox.
506    ///
507    /// If unspecified, this will default to `1,024`.
508    #[serde(skip_serializing_if = "Option::is_none")]
509    pub mailbox_capacity: Option<usize>,
510
511    /// Use get_known_peers_v3 RPC to fetch peer info.
512    ///
513    /// If unspecified, this will default to `false`.
514    #[serde(skip_serializing_if = "Option::is_none")]
515    pub use_get_known_peers_v3: Option<bool>,
516
517    /// Path to store discovered peer addresses across restarts.
518    ///
519    /// If unspecified, defaults to `<db_path>/discovery_peer_cache.yaml` when
520    /// started via `SuiNode`.
521    #[serde(skip_serializing_if = "Option::is_none")]
522    pub peer_addr_store_path: Option<PathBuf>,
523
524    /// Duration in milliseconds to cooldown a peer after a failure report from state-sync.
525    /// During cooldown, the peer is deprioritized for new connections.
526    ///
527    /// If unspecified, this will default to `3,600,000` (1 hour).
528    #[serde(skip_serializing_if = "Option::is_none")]
529    pub peer_failure_cooldown_ms: Option<u64>,
530
531    /// Minimum number of connected peers below which no failing-peer disconnect will occur.
532    ///
533    /// If unspecified, this will default to `2`.
534    #[serde(skip_serializing_if = "Option::is_none")]
535    pub min_peers_for_disconnect: Option<usize>,
536}
537
538impl DiscoveryConfig {
539    pub fn interval_period(&self) -> Duration {
540        const INTERVAL_PERIOD_MS: u64 = 5_000; // 5 seconds
541
542        Duration::from_millis(self.interval_period_ms.unwrap_or(INTERVAL_PERIOD_MS))
543    }
544
545    pub fn target_concurrent_connections(&self) -> usize {
546        const TARGET_CONCURRENT_CONNECTIONS: usize = 4;
547
548        self.target_concurrent_connections
549            .unwrap_or(TARGET_CONCURRENT_CONNECTIONS)
550    }
551
552    pub fn peers_to_query(&self) -> usize {
553        const PEERS_TO_QUERY: usize = 1;
554
555        self.peers_to_query.unwrap_or(PEERS_TO_QUERY)
556    }
557
558    pub fn access_type(&self) -> AccessType {
559        // defaults None to Public
560        self.access_type.unwrap_or(AccessType::Public)
561    }
562
563    pub fn mailbox_capacity(&self) -> usize {
564        const MAILBOX_CAPACITY: usize = 1_024;
565
566        self.mailbox_capacity.unwrap_or(MAILBOX_CAPACITY)
567    }
568
569    pub fn use_get_known_peers_v3(&self) -> bool {
570        self.use_get_known_peers_v3.unwrap_or(false)
571    }
572
573    pub fn peer_failure_cooldown(&self) -> Duration {
574        const DEFAULT_MS: u64 = 3_600_000; // 1 hour
575        Duration::from_millis(self.peer_failure_cooldown_ms.unwrap_or(DEFAULT_MS))
576    }
577
578    pub fn min_peers_for_disconnect(&self) -> usize {
579        const DEFAULT: usize = 2;
580        self.min_peers_for_disconnect.unwrap_or(DEFAULT)
581    }
582}
583
584#[derive(Clone, Debug, Default, Deserialize, Serialize)]
585#[serde(rename_all = "kebab-case")]
586pub struct RandomnessConfig {
587    /// Maximum number of rounds ahead of our most recent completed round for which we should
588    /// accept partial signatures from other validators.
589    ///
590    /// If unspecified, this will default to 50.
591    #[serde(skip_serializing_if = "Option::is_none")]
592    pub max_partial_sigs_rounds_ahead: Option<u64>,
593
594    /// Maximum number of rounds for which partial signatures should be concurrently sent.
595    ///
596    /// If unspecified, this will default to 20.
597    #[serde(skip_serializing_if = "Option::is_none")]
598    pub max_partial_sigs_concurrent_sends: Option<usize>,
599
600    /// Interval at which to retry sending partial signatures until the round is complete.
601    ///
602    /// If unspecified, this will default to `5,000` milliseconds.
603    #[serde(skip_serializing_if = "Option::is_none")]
604    pub partial_signature_retry_interval_ms: Option<u64>,
605
606    /// Size of the Randomness actor's mailbox. This should be set large enough to never
607    /// overflow unless a bug is encountered.
608    ///
609    /// If unspecified, this will default to `1,000,000`.
610    #[serde(skip_serializing_if = "Option::is_none")]
611    pub mailbox_capacity: Option<usize>,
612
613    /// Per-peer inflight limit for the SendPartialSignatures RPC.
614    ///
615    /// If unspecified, this will default to 20.
616    #[serde(skip_serializing_if = "Option::is_none")]
617    pub send_partial_signatures_inflight_limit: Option<usize>,
618
619    /// Maximum proportion of total peer weight to ignore in case of byzantine behavior.
620    ///
621    /// If unspecified, this will default to 0.2.
622    #[serde(skip_serializing_if = "Option::is_none")]
623    pub max_ignored_peer_weight_factor: Option<f64>,
624}
625
626impl RandomnessConfig {
627    pub fn max_partial_sigs_rounds_ahead(&self) -> u64 {
628        const MAX_PARTIAL_SIGS_ROUNDS_AHEAD: u64 = 50;
629
630        self.max_partial_sigs_rounds_ahead
631            .unwrap_or(MAX_PARTIAL_SIGS_ROUNDS_AHEAD)
632    }
633
634    pub fn max_partial_sigs_concurrent_sends(&self) -> usize {
635        const MAX_PARTIAL_SIGS_CONCURRENT_SENDS: usize = 20;
636
637        self.max_partial_sigs_concurrent_sends
638            .unwrap_or(MAX_PARTIAL_SIGS_CONCURRENT_SENDS)
639    }
640    pub fn partial_signature_retry_interval(&self) -> Duration {
641        const PARTIAL_SIGNATURE_RETRY_INTERVAL: u64 = 5_000; // 5 seconds
642
643        Duration::from_millis(
644            self.partial_signature_retry_interval_ms
645                .unwrap_or(PARTIAL_SIGNATURE_RETRY_INTERVAL),
646        )
647    }
648
649    pub fn mailbox_capacity(&self) -> usize {
650        const MAILBOX_CAPACITY: usize = 1_000_000;
651
652        self.mailbox_capacity.unwrap_or(MAILBOX_CAPACITY)
653    }
654
655    pub fn send_partial_signatures_inflight_limit(&self) -> usize {
656        const SEND_PARTIAL_SIGNATURES_INFLIGHT_LIMIT: usize = 20;
657
658        self.send_partial_signatures_inflight_limit
659            .unwrap_or(SEND_PARTIAL_SIGNATURES_INFLIGHT_LIMIT)
660    }
661
662    pub fn max_ignored_peer_weight_factor(&self) -> f64 {
663        const MAX_IGNORED_PEER_WEIGHT_FACTOR: f64 = 0.2;
664
665        self.max_ignored_peer_weight_factor
666            .unwrap_or(MAX_IGNORED_PEER_WEIGHT_FACTOR)
667    }
668}