iota_config/
p2p.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::{net::SocketAddr, num::NonZeroU32, time::Duration};
6
7use iota_types::{
8    messages_checkpoint::{CheckpointDigest, CheckpointSequenceNumber},
9    multiaddr::Multiaddr,
10};
11use serde::{Deserialize, Serialize};
12
13#[derive(Clone, Debug, Deserialize, Serialize)]
14#[serde(rename_all = "kebab-case")]
15pub struct P2pConfig {
16    /// The address that the p2p network will bind on.
17    #[serde(default = "default_listen_address")]
18    pub listen_address: SocketAddr,
19    /// The external address other nodes can use to reach this node.
20    /// This will be shared with other peers through the discovery service
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub external_address: Option<Multiaddr>,
23    /// SeedPeers are preferred and the node will always try to ensure a
24    /// connection is established with these nodes.
25    #[serde(skip_serializing_if = "Vec::is_empty", default)]
26    pub seed_peers: Vec<SeedPeer>,
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub anemo_config: Option<anemo::Config>,
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub state_sync: Option<StateSyncConfig>,
31    #[serde(skip_serializing_if = "Option::is_none")]
32    pub discovery: Option<DiscoveryConfig>,
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub randomness: Option<RandomnessConfig>,
35    /// Size in bytes above which network messages are considered excessively
36    /// large. Excessively large messages will still be handled, but logged
37    /// and reported in metrics for debugging.
38    ///
39    /// If unspecified, this will default to 8 MiB.
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub excessive_message_size: Option<usize>,
42}
43
44fn default_listen_address() -> SocketAddr {
45    "0.0.0.0:8084".parse().unwrap()
46}
47
48impl Default for P2pConfig {
49    fn default() -> Self {
50        Self {
51            listen_address: default_listen_address(),
52            external_address: Default::default(),
53            seed_peers: Default::default(),
54            anemo_config: Default::default(),
55            state_sync: None,
56            discovery: None,
57            randomness: None,
58            excessive_message_size: None,
59        }
60    }
61}
62
63impl P2pConfig {
64    pub fn excessive_message_size(&self) -> usize {
65        const EXCESSIVE_MESSAGE_SIZE: usize = 32 << 20;
66
67        self.excessive_message_size
68            .unwrap_or(EXCESSIVE_MESSAGE_SIZE)
69    }
70
71    pub fn set_discovery_config(mut self, discovery_config: DiscoveryConfig) -> Self {
72        self.discovery = Some(discovery_config);
73        self
74    }
75}
76
77#[derive(Clone, Debug, Deserialize, Serialize)]
78#[serde(rename_all = "kebab-case")]
79pub struct SeedPeer {
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub peer_id: Option<anemo::PeerId>,
82    pub address: Multiaddr,
83}
84
85#[derive(Clone, Debug, Deserialize, Serialize)]
86#[serde(rename_all = "kebab-case")]
87pub struct AllowlistedPeer {
88    pub peer_id: anemo::PeerId,
89    #[serde(skip_serializing_if = "Option::is_none")]
90    pub address: Option<Multiaddr>,
91}
92
93#[derive(Clone, Debug, Default, Deserialize, Serialize)]
94#[serde(rename_all = "kebab-case")]
95pub struct StateSyncConfig {
96    /// List of "known-good" checkpoints that state sync will be forced to use.
97    /// State sync will skip verification of pinned checkpoints, and reject
98    /// checkpoints with digests that don't match pinned values for a given
99    /// sequence number.
100    ///
101    /// This can be used:
102    /// - in case of a fork, to prevent the node from syncing to the wrong
103    ///   chain.
104    /// - in case of a network stall, to force the node to proceed with a
105    ///   manually-injected checkpoint.
106    #[serde(skip_serializing_if = "Vec::is_empty", default)]
107    pub pinned_checkpoints: Vec<(CheckpointSequenceNumber, CheckpointDigest)>,
108
109    /// Query peers for their latest checkpoint every interval period.
110    ///
111    /// If unspecified, this will default to `5,000` milliseconds.
112    #[serde(skip_serializing_if = "Option::is_none")]
113    pub interval_period_ms: Option<u64>,
114
115    /// Size of the StateSync actor's mailbox.
116    ///
117    /// If unspecified, this will default to `1,024`.
118    #[serde(skip_serializing_if = "Option::is_none")]
119    pub mailbox_capacity: Option<usize>,
120
121    /// Size of the broadcast channel use for notifying other systems of newly
122    /// sync'ed checkpoints.
123    ///
124    /// If unspecified, this will default to `1,024`.
125    #[serde(skip_serializing_if = "Option::is_none")]
126    pub synced_checkpoint_broadcast_channel_capacity: Option<usize>,
127
128    /// Set the upper bound on the number of checkpoint headers to be downloaded
129    /// concurrently.
130    ///
131    /// If unspecified, this will default to `400`.
132    #[serde(skip_serializing_if = "Option::is_none")]
133    pub checkpoint_header_download_concurrency: Option<usize>,
134
135    /// Set the upper bound on the number of checkpoint contents to be
136    /// downloaded concurrently.
137    ///
138    /// If unspecified, this will default to `400`.
139    #[serde(skip_serializing_if = "Option::is_none")]
140    pub checkpoint_content_download_concurrency: Option<usize>,
141
142    /// Set the upper bound on the number of individual transactions contained
143    /// in checkpoint contents to be downloaded concurrently. If both this
144    /// value and `checkpoint_content_download_concurrency` are set, the
145    /// lower of the two will apply.
146    ///
147    /// If unspecified, this will default to `50,000`.
148    #[serde(skip_serializing_if = "Option::is_none")]
149    pub checkpoint_content_download_tx_concurrency: Option<u64>,
150
151    /// Set the timeout that should be used when sending most state-sync RPC
152    /// requests.
153    ///
154    /// If unspecified, this will default to `10,000` milliseconds.
155    #[serde(skip_serializing_if = "Option::is_none")]
156    pub timeout_ms: Option<u64>,
157
158    /// Set the timeout that should be used when sending RPC requests to sync
159    /// checkpoint contents.
160    ///
161    /// If unspecified, this will default to `10,000` milliseconds.
162    #[serde(skip_serializing_if = "Option::is_none")]
163    pub checkpoint_content_timeout_ms: Option<u64>,
164
165    /// Per-peer rate-limit (in requests/sec) for the PushCheckpointSummary RPC.
166    ///
167    /// If unspecified, this will default to no limit.
168    #[serde(skip_serializing_if = "Option::is_none")]
169    pub push_checkpoint_summary_rate_limit: Option<NonZeroU32>,
170
171    /// Per-peer rate-limit (in requests/sec) for the GetCheckpointSummary RPC.
172    ///
173    /// If unspecified, this will default to no limit.
174    #[serde(skip_serializing_if = "Option::is_none")]
175    pub get_checkpoint_summary_rate_limit: Option<NonZeroU32>,
176
177    /// Per-peer rate-limit (in requests/sec) for the GetCheckpointContents RPC.
178    ///
179    /// If unspecified, this will default to no limit.
180    #[serde(skip_serializing_if = "Option::is_none")]
181    pub get_checkpoint_contents_rate_limit: Option<NonZeroU32>,
182
183    /// Per-peer inflight limit for the GetCheckpointContents RPC.
184    ///
185    /// If unspecified, this will default to no limit.
186    #[serde(skip_serializing_if = "Option::is_none")]
187    pub get_checkpoint_contents_inflight_limit: Option<usize>,
188
189    /// Per-checkpoint inflight limit for the GetCheckpointContents RPC. This is
190    /// enforced globally across all peers.
191    ///
192    /// If unspecified, this will default to no limit.
193    #[serde(skip_serializing_if = "Option::is_none")]
194    pub get_checkpoint_contents_per_checkpoint_limit: Option<usize>,
195
196    /// The amount of time to wait before retry if there are no peers to sync
197    /// content from. If unspecified, this will set to default value
198    #[serde(skip_serializing_if = "Option::is_none")]
199    pub wait_interval_when_no_peer_to_sync_content_ms: Option<u64>,
200}
201
202impl StateSyncConfig {
203    pub fn interval_period(&self) -> Duration {
204        const INTERVAL_PERIOD_MS: u64 = 5_000; // 5 seconds
205
206        Duration::from_millis(self.interval_period_ms.unwrap_or(INTERVAL_PERIOD_MS))
207    }
208
209    pub fn mailbox_capacity(&self) -> usize {
210        const MAILBOX_CAPACITY: usize = 1_024;
211
212        self.mailbox_capacity.unwrap_or(MAILBOX_CAPACITY)
213    }
214
215    pub fn synced_checkpoint_broadcast_channel_capacity(&self) -> usize {
216        const SYNCED_CHECKPOINT_BROADCAST_CHANNEL_CAPACITY: usize = 1_024;
217
218        self.synced_checkpoint_broadcast_channel_capacity
219            .unwrap_or(SYNCED_CHECKPOINT_BROADCAST_CHANNEL_CAPACITY)
220    }
221
222    pub fn checkpoint_header_download_concurrency(&self) -> usize {
223        const CHECKPOINT_HEADER_DOWNLOAD_CONCURRENCY: usize = 400;
224
225        self.checkpoint_header_download_concurrency
226            .unwrap_or(CHECKPOINT_HEADER_DOWNLOAD_CONCURRENCY)
227    }
228
229    pub fn checkpoint_content_download_concurrency(&self) -> usize {
230        const CHECKPOINT_CONTENT_DOWNLOAD_CONCURRENCY: usize = 400;
231
232        self.checkpoint_content_download_concurrency
233            .unwrap_or(CHECKPOINT_CONTENT_DOWNLOAD_CONCURRENCY)
234    }
235
236    pub fn checkpoint_content_download_tx_concurrency(&self) -> u64 {
237        const CHECKPOINT_CONTENT_DOWNLOAD_TX_CONCURRENCY: u64 = 50_000;
238
239        self.checkpoint_content_download_tx_concurrency
240            .unwrap_or(CHECKPOINT_CONTENT_DOWNLOAD_TX_CONCURRENCY)
241    }
242
243    pub fn timeout(&self) -> Duration {
244        const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
245
246        self.timeout_ms
247            .map(Duration::from_millis)
248            .unwrap_or(DEFAULT_TIMEOUT)
249    }
250
251    pub fn checkpoint_content_timeout(&self) -> Duration {
252        const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60);
253
254        self.checkpoint_content_timeout_ms
255            .map(Duration::from_millis)
256            .unwrap_or(DEFAULT_TIMEOUT)
257    }
258
259    pub fn wait_interval_when_no_peer_to_sync_content(&self) -> Duration {
260        self.wait_interval_when_no_peer_to_sync_content_ms
261            .map(Duration::from_millis)
262            .unwrap_or(self.default_wait_interval_when_no_peer_to_sync_content())
263    }
264
265    fn default_wait_interval_when_no_peer_to_sync_content(&self) -> Duration {
266        if cfg!(msim) {
267            Duration::from_secs(5)
268        } else {
269            Duration::from_secs(10)
270        }
271    }
272}
273
274/// Access Type of a node.
275/// AccessType info is shared in the discovery process.
276/// * If the node marks itself as Public, other nodes may try to connect to it.
277/// * If the node marks itself as Private, only nodes that have it in their
278///   `allowlisted_peers` or `seed_peers` will try to connect to it.
279/// * If not set, defaults to Public.
280///
281/// AccessType is useful when a network of nodes want to stay private. To
282/// achieve this, mark every node in this network as `Private` and
283/// allowlist/seed them to each other.
284#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
285pub enum AccessType {
286    Public,
287    Private,
288}
289
290#[derive(Clone, Debug, Default, Deserialize, Serialize)]
291#[serde(rename_all = "kebab-case")]
292pub struct DiscoveryConfig {
293    /// Query peers for their latest checkpoint every interval period.
294    ///
295    /// If unspecified, this will default to `5,000` milliseconds.
296    #[serde(skip_serializing_if = "Option::is_none")]
297    pub interval_period_ms: Option<u64>,
298
299    /// Target number of concurrent connections to establish.
300    ///
301    /// If unspecified, this will default to `4`.
302    #[serde(skip_serializing_if = "Option::is_none")]
303    pub target_concurrent_connections: Option<usize>,
304
305    /// Number of peers to query each interval.
306    ///
307    /// Sets the number of peers, to be randomly selected, that are queried for
308    /// their known peers each interval.
309    ///
310    /// If unspecified, this will default to `1`.
311    #[serde(skip_serializing_if = "Option::is_none")]
312    pub peers_to_query: Option<usize>,
313
314    /// Timeout for individual peer query requests in discovery protocol.
315    ///
316    /// If unspecified, this will default to `1` second.
317    #[serde(skip_serializing_if = "Option::is_none")]
318    pub peer_query_timeout_sec: Option<u64>,
319
320    /// Per-peer rate-limit (in requests/sec) for the GetKnownPeers RPC.
321    ///
322    /// If unspecified, this will default to no limit.
323    #[serde(skip_serializing_if = "Option::is_none")]
324    pub get_known_peers_rate_limit: Option<NonZeroU32>,
325
326    /// See docstring for `AccessType`.
327    #[serde(skip_serializing_if = "Option::is_none")]
328    pub access_type: Option<AccessType>,
329
330    /// Like `seed_peers` in `P2pConfig`, allowlisted peers will always be
331    /// allowed to establish connection with this node regardless of the
332    /// concurrency limit. Unlike `seed_peers`, a node does not reach out to
333    /// `allowlisted_peers` preferentially. It is also used to determine if
334    /// a peer is accessible when its AccessType is Private. For example, a
335    /// node will ignore a peer with Private AccessType if the peer is not in
336    /// its `allowlisted_peers`. Namely, the node will not try to establish
337    /// connections to this peer, nor advertise this peer's info to other
338    /// peers in the network.
339    #[serde(skip_serializing_if = "Vec::is_empty", default)]
340    pub allowlisted_peers: Vec<AllowlistedPeer>,
341
342    /// Maximum number of concurrent address verification attempts.
343    /// This prevents overwhelming the network when verifying many peers at
344    /// once.
345    ///
346    /// If unspecified, this will default to `10`.
347    #[serde(skip_serializing_if = "Option::is_none")]
348    pub max_concurrent_address_verifications: Option<usize>,
349
350    /// Timeout for individual address verification attempts.
351    ///
352    /// If unspecified, this will default to `3` seconds.
353    #[serde(skip_serializing_if = "Option::is_none")]
354    pub address_verification_timeout_sec: Option<u64>,
355
356    /// Total timeout for all address verification attempts to prevent DoS
357    /// attacks.
358    ///
359    /// If unspecified, this will default to `8` seconds.
360    #[serde(skip_serializing_if = "Option::is_none")]
361    pub address_verification_total_timeout_sec: Option<u64>,
362
363    /// Cooldown period in seconds for peers whose address verification failed.
364    /// During this period, new peer info from the same peer will be ignored.
365    /// Set to 0 to disable the cooldown feature entirely.
366    ///
367    /// If unspecified, this will default to `600` seconds (10 minutes).
368    #[serde(skip_serializing_if = "Option::is_none")]
369    pub address_verification_failure_cooldown_sec: Option<u64>,
370
371    /// Interval for cleaning up old entries from the verification failure
372    /// cooldown list.
373    ///
374    /// If unspecified, this will default to `300` seconds (5 minutes).
375    #[serde(skip_serializing_if = "Option::is_none")]
376    pub cooldown_cleanup_interval_sec: Option<u64>,
377
378    /// Whether to allow private IP and local DNS addresses (e.g., 192.168.0.1,
379    /// localhost, .local) when verifying peer addresses.
380    #[serde(skip_serializing_if = "Option::is_none")]
381    pub allow_private_addresses: Option<bool>,
382}
383
384impl DiscoveryConfig {
385    pub fn interval_period(&self) -> Duration {
386        const INTERVAL_PERIOD_MS: u64 = 10_000; // 10 seconds
387
388        Duration::from_millis(self.interval_period_ms.unwrap_or(INTERVAL_PERIOD_MS))
389    }
390
391    pub fn target_concurrent_connections(&self) -> usize {
392        const TARGET_CONCURRENT_CONNECTIONS: usize = 4;
393
394        self.target_concurrent_connections
395            .unwrap_or(TARGET_CONCURRENT_CONNECTIONS)
396    }
397
398    pub fn peers_to_query(&self) -> usize {
399        const PEERS_TO_QUERY: usize = 1;
400
401        self.peers_to_query.unwrap_or(PEERS_TO_QUERY)
402    }
403
404    pub fn peer_query_timeout(&self) -> Duration {
405        const PEER_QUERY_TIMEOUT_SEC: u64 = 1;
406
407        Duration::from_secs(
408            self.peer_query_timeout_sec
409                .unwrap_or(PEER_QUERY_TIMEOUT_SEC),
410        )
411    }
412
413    pub fn access_type(&self) -> AccessType {
414        // defaults None to Public
415        self.access_type.unwrap_or(AccessType::Public)
416    }
417
418    pub fn max_concurrent_address_verifications(&self) -> usize {
419        const MAX_CONCURRENT_ADDRESS_VERIFICATIONS: usize = 10;
420
421        self.max_concurrent_address_verifications
422            .unwrap_or(MAX_CONCURRENT_ADDRESS_VERIFICATIONS)
423    }
424
425    pub fn address_verification_timeout(&self) -> Duration {
426        const ADDRESS_VERIFICATION_TIMEOUT_SEC: u64 = 3;
427
428        Duration::from_secs(
429            self.address_verification_timeout_sec
430                .unwrap_or(ADDRESS_VERIFICATION_TIMEOUT_SEC),
431        )
432    }
433
434    pub fn address_verification_total_timeout(&self) -> Duration {
435        const ADDRESS_VERIFICATION_TOTAL_TIMEOUT_SEC: u64 = 8;
436
437        Duration::from_secs(
438            self.address_verification_total_timeout_sec
439                .unwrap_or(ADDRESS_VERIFICATION_TOTAL_TIMEOUT_SEC),
440        )
441    }
442
443    pub fn address_verification_failure_cooldown(&self) -> Duration {
444        const ADDRESS_VERIFICATION_FAILURE_COOLDOWN_SEC: u64 = 600; // 10 minutes
445
446        Duration::from_secs(
447            self.address_verification_failure_cooldown_sec
448                .unwrap_or(ADDRESS_VERIFICATION_FAILURE_COOLDOWN_SEC),
449        )
450    }
451
452    pub fn cooldown_cleanup_interval(&self) -> Duration {
453        const COOLDOWN_CLEANUP_INTERVAL_SEC: u64 = 300; // 5 minutes
454
455        Duration::from_secs(
456            self.cooldown_cleanup_interval_sec
457                .unwrap_or(COOLDOWN_CLEANUP_INTERVAL_SEC),
458        )
459    }
460
461    /// Returns true if address verification cooldown is enabled (cooldown > 0)
462    pub fn is_address_verification_cooldown_enabled(&self) -> bool {
463        self.address_verification_failure_cooldown_sec
464            .unwrap_or(600)
465            > 0
466    }
467
468    /// Whether to allow private IP and local DNS addresses (e.g., 192.168.0.1,
469    /// localhost, .local) when verifying peer addresses.
470    pub fn allow_private_addresses(&self) -> bool {
471        self.allow_private_addresses.unwrap_or(false)
472    }
473}
474
475#[derive(Clone, Debug, Default, Deserialize, Serialize)]
476#[serde(rename_all = "kebab-case")]
477pub struct RandomnessConfig {
478    /// Maximum number of rounds ahead of our most recent completed round for
479    /// which we should accept partial signatures from other validators.
480    ///
481    /// If unspecified, this will default to 50.
482    #[serde(skip_serializing_if = "Option::is_none")]
483    pub max_partial_sigs_rounds_ahead: Option<u64>,
484
485    /// Maximum number of rounds for which partial signatures should be
486    /// concurrently sent.
487    ///
488    /// If unspecified, this will default to 20.
489    #[serde(skip_serializing_if = "Option::is_none")]
490    pub max_partial_sigs_concurrent_sends: Option<usize>,
491
492    /// Interval at which to retry sending partial signatures until the round is
493    /// complete.
494    ///
495    /// If unspecified, this will default to `5,000` milliseconds.
496    #[serde(skip_serializing_if = "Option::is_none")]
497    pub partial_signature_retry_interval_ms: Option<u64>,
498
499    /// Size of the Randomness actor's mailbox. This should be set large enough
500    /// to never overflow unless a bug is encountered.
501    ///
502    /// If unspecified, this will default to `1,000,000`.
503    #[serde(skip_serializing_if = "Option::is_none")]
504    pub mailbox_capacity: Option<usize>,
505
506    /// Per-peer inflight limit for the SendPartialSignatures RPC.
507    ///
508    /// If unspecified, this will default to 20.
509    #[serde(skip_serializing_if = "Option::is_none")]
510    pub send_partial_signatures_inflight_limit: Option<usize>,
511
512    /// Maximum proportion of total peer weight to ignore in case of byzantine
513    /// behavior.
514    ///
515    /// If unspecified, this will default to 0.2.
516    #[serde(skip_serializing_if = "Option::is_none")]
517    pub max_ignored_peer_weight_factor: Option<f64>,
518}
519
520impl RandomnessConfig {
521    pub fn max_partial_sigs_rounds_ahead(&self) -> u64 {
522        const MAX_PARTIAL_SIGS_ROUNDS_AHEAD: u64 = 50;
523
524        self.max_partial_sigs_rounds_ahead
525            .unwrap_or(MAX_PARTIAL_SIGS_ROUNDS_AHEAD)
526    }
527
528    pub fn max_partial_sigs_concurrent_sends(&self) -> usize {
529        const MAX_PARTIAL_SIGS_CONCURRENT_SENDS: usize = 20;
530
531        self.max_partial_sigs_concurrent_sends
532            .unwrap_or(MAX_PARTIAL_SIGS_CONCURRENT_SENDS)
533    }
534    pub fn partial_signature_retry_interval(&self) -> Duration {
535        const PARTIAL_SIGNATURE_RETRY_INTERVAL: u64 = 5_000; // 5 seconds
536
537        Duration::from_millis(
538            self.partial_signature_retry_interval_ms
539                .unwrap_or(PARTIAL_SIGNATURE_RETRY_INTERVAL),
540        )
541    }
542
543    pub fn mailbox_capacity(&self) -> usize {
544        const MAILBOX_CAPACITY: usize = 1_000_000;
545
546        self.mailbox_capacity.unwrap_or(MAILBOX_CAPACITY)
547    }
548
549    pub fn send_partial_signatures_inflight_limit(&self) -> usize {
550        const SEND_PARTIAL_SIGNATURES_INFLIGHT_LIMIT: usize = 20;
551
552        self.send_partial_signatures_inflight_limit
553            .unwrap_or(SEND_PARTIAL_SIGNATURES_INFLIGHT_LIMIT)
554    }
555
556    pub fn max_ignored_peer_weight_factor(&self) -> f64 {
557        const MAX_IGNORED_PEER_WEIGHT_FACTOR: f64 = 0.2;
558
559        self.max_ignored_peer_weight_factor
560            .unwrap_or(MAX_IGNORED_PEER_WEIGHT_FACTOR)
561    }
562}