1use std::{
6 net::SocketAddr,
7 num::{NonZeroU32, NonZeroU64},
8 time::Duration,
9};
10
11use iota_multiaddr::Multiaddr;
12use iota_sdk_types::CheckpointDigest;
13use iota_types::messages_checkpoint::CheckpointSequenceNumber;
14use serde::{Deserialize, Serialize};
15
16#[derive(Clone, Debug, Deserialize, Serialize)]
17#[serde(rename_all = "kebab-case")]
18pub struct P2pConfig {
19 #[serde(default = "default_listen_address")]
21 pub listen_address: SocketAddr,
22 #[serde(skip_serializing_if = "Option::is_none")]
25 pub external_address: Option<Multiaddr>,
26 #[serde(skip_serializing_if = "Vec::is_empty", default)]
29 pub seed_peers: Vec<SeedPeer>,
30 #[serde(skip_serializing_if = "Option::is_none")]
31 pub anemo_config: Option<anemo::Config>,
32 #[serde(skip_serializing_if = "Option::is_none")]
33 pub state_sync: Option<StateSyncConfig>,
34 #[serde(skip_serializing_if = "Option::is_none")]
35 pub discovery: Option<DiscoveryConfig>,
36 #[serde(skip_serializing_if = "Option::is_none")]
37 pub randomness: Option<RandomnessConfig>,
38 #[serde(skip_serializing_if = "Option::is_none")]
44 pub excessive_message_size: Option<usize>,
45}
46
47fn default_listen_address() -> SocketAddr {
48 "0.0.0.0:8084".parse().unwrap()
49}
50
51impl Default for P2pConfig {
52 fn default() -> Self {
53 Self {
54 listen_address: default_listen_address(),
55 external_address: Default::default(),
56 seed_peers: Default::default(),
57 anemo_config: Default::default(),
58 state_sync: None,
59 discovery: None,
60 randomness: None,
61 excessive_message_size: None,
62 }
63 }
64}
65
66impl P2pConfig {
67 pub fn excessive_message_size(&self) -> usize {
68 const EXCESSIVE_MESSAGE_SIZE: usize = 32 << 20;
69
70 self.excessive_message_size
71 .unwrap_or(EXCESSIVE_MESSAGE_SIZE)
72 }
73
74 pub fn set_discovery_config(mut self, discovery_config: DiscoveryConfig) -> Self {
75 self.discovery = Some(discovery_config);
76 self
77 }
78}
79
80#[derive(Clone, Debug, Deserialize, Serialize)]
81#[serde(rename_all = "kebab-case")]
82pub struct SeedPeer {
83 #[serde(skip_serializing_if = "Option::is_none")]
84 pub peer_id: Option<anemo::PeerId>,
85 pub address: Multiaddr,
86}
87
88#[derive(Clone, Debug, Deserialize, Serialize)]
89#[serde(rename_all = "kebab-case")]
90pub struct AllowlistedPeer {
91 pub peer_id: anemo::PeerId,
92 #[serde(skip_serializing_if = "Option::is_none")]
93 pub address: Option<Multiaddr>,
94}
95
96#[derive(Clone, Debug, Default, Deserialize, Serialize)]
97#[serde(rename_all = "kebab-case")]
98pub struct StateSyncConfig {
99 #[serde(skip_serializing_if = "Vec::is_empty", default)]
109 pub pinned_checkpoints: Vec<(CheckpointSequenceNumber, CheckpointDigest)>,
110
111 #[serde(skip_serializing_if = "Option::is_none")]
115 pub interval_period_ms: Option<u64>,
116
117 #[serde(skip_serializing_if = "Option::is_none")]
121 pub mailbox_capacity: Option<usize>,
122
123 #[serde(skip_serializing_if = "Option::is_none")]
128 pub synced_checkpoint_broadcast_channel_capacity: Option<usize>,
129
130 #[serde(skip_serializing_if = "Option::is_none")]
135 pub checkpoint_header_download_concurrency: Option<usize>,
136
137 #[serde(skip_serializing_if = "Option::is_none")]
142 pub checkpoint_content_download_concurrency: Option<usize>,
143
144 #[serde(skip_serializing_if = "Option::is_none")]
151 pub checkpoint_content_download_tx_concurrency: Option<u64>,
152
153 #[serde(skip_serializing_if = "Option::is_none")]
158 pub timeout_ms: Option<u64>,
159
160 #[serde(skip_serializing_if = "Option::is_none")]
165 pub checkpoint_content_timeout_ms: Option<u64>,
166
167 #[serde(skip_serializing_if = "Option::is_none")]
171 pub push_checkpoint_summary_rate_limit: Option<NonZeroU32>,
172
173 #[serde(skip_serializing_if = "Option::is_none")]
177 pub get_checkpoint_summary_rate_limit: Option<NonZeroU32>,
178
179 #[serde(skip_serializing_if = "Option::is_none")]
183 pub get_checkpoint_contents_rate_limit: Option<NonZeroU32>,
184
185 #[serde(skip_serializing_if = "Option::is_none")]
189 pub get_checkpoint_contents_inflight_limit: Option<usize>,
190
191 #[serde(skip_serializing_if = "Option::is_none")]
196 pub get_checkpoint_contents_per_checkpoint_limit: Option<usize>,
197
198 #[serde(skip_serializing_if = "Option::is_none")]
201 pub wait_interval_when_no_peer_to_sync_content_ms: Option<u64>,
202
203 #[serde(skip_serializing_if = "Option::is_none")]
212 pub max_checkpoints_ahead_of_execution: Option<NonZeroU64>,
213}
214
215impl StateSyncConfig {
216 pub fn interval_period(&self) -> Duration {
217 const INTERVAL_PERIOD_MS: u64 = 5_000; Duration::from_millis(self.interval_period_ms.unwrap_or(INTERVAL_PERIOD_MS))
220 }
221
222 pub fn mailbox_capacity(&self) -> usize {
223 const MAILBOX_CAPACITY: usize = 1_024;
224
225 self.mailbox_capacity.unwrap_or(MAILBOX_CAPACITY)
226 }
227
228 pub fn synced_checkpoint_broadcast_channel_capacity(&self) -> usize {
229 const SYNCED_CHECKPOINT_BROADCAST_CHANNEL_CAPACITY: usize = 1_024;
230
231 self.synced_checkpoint_broadcast_channel_capacity
232 .unwrap_or(SYNCED_CHECKPOINT_BROADCAST_CHANNEL_CAPACITY)
233 }
234
235 pub fn checkpoint_header_download_concurrency(&self) -> usize {
236 const CHECKPOINT_HEADER_DOWNLOAD_CONCURRENCY: usize = 400;
237
238 self.checkpoint_header_download_concurrency
239 .unwrap_or(CHECKPOINT_HEADER_DOWNLOAD_CONCURRENCY)
240 }
241
242 pub fn checkpoint_content_download_concurrency(&self) -> usize {
243 const CHECKPOINT_CONTENT_DOWNLOAD_CONCURRENCY: usize = 400;
244
245 self.checkpoint_content_download_concurrency
246 .unwrap_or(CHECKPOINT_CONTENT_DOWNLOAD_CONCURRENCY)
247 }
248
249 pub fn checkpoint_content_download_tx_concurrency(&self) -> u64 {
250 const CHECKPOINT_CONTENT_DOWNLOAD_TX_CONCURRENCY: u64 = 50_000;
251
252 self.checkpoint_content_download_tx_concurrency
253 .unwrap_or(CHECKPOINT_CONTENT_DOWNLOAD_TX_CONCURRENCY)
254 }
255
256 pub fn timeout(&self) -> Duration {
257 const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
258
259 self.timeout_ms
260 .map(Duration::from_millis)
261 .unwrap_or(DEFAULT_TIMEOUT)
262 }
263
264 pub fn checkpoint_content_timeout(&self) -> Duration {
265 const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60);
266
267 self.checkpoint_content_timeout_ms
268 .map(Duration::from_millis)
269 .unwrap_or(DEFAULT_TIMEOUT)
270 }
271
272 pub fn max_checkpoints_ahead_of_execution(&self) -> u64 {
273 const MAX_CHECKPOINTS_AHEAD_OF_EXECUTION: u64 = 100_000;
274
275 self.max_checkpoints_ahead_of_execution
276 .map(NonZeroU64::get)
277 .unwrap_or(MAX_CHECKPOINTS_AHEAD_OF_EXECUTION)
278 }
279
280 pub fn wait_interval_when_no_peer_to_sync_content(&self) -> Duration {
281 self.wait_interval_when_no_peer_to_sync_content_ms
282 .map(Duration::from_millis)
283 .unwrap_or(self.default_wait_interval_when_no_peer_to_sync_content())
284 }
285
286 fn default_wait_interval_when_no_peer_to_sync_content(&self) -> Duration {
287 if cfg!(msim) {
288 Duration::from_secs(5)
289 } else {
290 Duration::from_secs(10)
291 }
292 }
293
294 pub fn randomized_for_testing() -> Self {
295 use rand::RngExt;
296 let mut rng = rand::rng();
297 let config = Self {
298 mailbox_capacity: Some(rng.random_range(16..=2048)),
299 synced_checkpoint_broadcast_channel_capacity: Some(rng.random_range(16..=2048)),
300 checkpoint_header_download_concurrency: Some(rng.random_range(10..=500)),
301 checkpoint_content_download_concurrency: Some(rng.random_range(10..=500)),
302 ..Default::default()
303 };
304 tracing::info!(
305 mailbox_capacity = config.mailbox_capacity.unwrap(),
306 broadcast_capacity = config.synced_checkpoint_broadcast_channel_capacity.unwrap(),
307 header_concurrency = config.checkpoint_header_download_concurrency.unwrap(),
308 content_concurrency = config.checkpoint_content_download_concurrency.unwrap(),
309 "StateSyncConfig::randomized_for_testing"
310 );
311 config
312 }
313}
314
315#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
326pub enum AccessType {
327 Public,
328 Private,
329}
330
331#[derive(Clone, Debug, Default, Deserialize, Serialize)]
332#[serde(rename_all = "kebab-case")]
333pub struct DiscoveryConfig {
334 #[serde(skip_serializing_if = "Option::is_none")]
338 pub interval_period_ms: Option<u64>,
339
340 #[serde(skip_serializing_if = "Option::is_none")]
344 pub target_concurrent_connections: Option<usize>,
345
346 #[serde(skip_serializing_if = "Option::is_none")]
353 pub peers_to_query: Option<usize>,
354
355 #[serde(skip_serializing_if = "Option::is_none")]
359 pub peer_query_timeout_sec: Option<u64>,
360
361 #[serde(skip_serializing_if = "Option::is_none")]
365 pub get_known_peers_rate_limit: Option<NonZeroU32>,
366
367 #[serde(skip_serializing_if = "Option::is_none")]
369 pub access_type: Option<AccessType>,
370
371 #[serde(skip_serializing_if = "Vec::is_empty", default)]
381 pub allowlisted_peers: Vec<AllowlistedPeer>,
382
383 #[serde(skip_serializing_if = "Option::is_none")]
389 pub max_concurrent_address_verifications: Option<usize>,
390
391 #[serde(skip_serializing_if = "Option::is_none")]
395 pub address_verification_timeout_sec: Option<u64>,
396
397 #[serde(skip_serializing_if = "Option::is_none")]
402 pub address_verification_total_timeout_sec: Option<u64>,
403
404 #[serde(skip_serializing_if = "Option::is_none")]
410 pub address_verification_failure_cooldown_sec: Option<u64>,
411
412 #[serde(skip_serializing_if = "Option::is_none")]
417 pub cooldown_cleanup_interval_sec: Option<u64>,
418
419 #[serde(skip_serializing_if = "Option::is_none")]
422 pub allow_private_addresses: Option<bool>,
423}
424
425impl DiscoveryConfig {
426 pub fn interval_period(&self) -> Duration {
427 const INTERVAL_PERIOD_MS: u64 = 10_000; Duration::from_millis(self.interval_period_ms.unwrap_or(INTERVAL_PERIOD_MS))
430 }
431
432 pub fn target_concurrent_connections(&self) -> usize {
433 const TARGET_CONCURRENT_CONNECTIONS: usize = 4;
434
435 self.target_concurrent_connections
436 .unwrap_or(TARGET_CONCURRENT_CONNECTIONS)
437 }
438
439 pub fn peers_to_query(&self) -> usize {
440 const PEERS_TO_QUERY: usize = 1;
441
442 self.peers_to_query.unwrap_or(PEERS_TO_QUERY)
443 }
444
445 pub fn peer_query_timeout(&self) -> Duration {
446 const PEER_QUERY_TIMEOUT_SEC: u64 = 1;
447
448 Duration::from_secs(
449 self.peer_query_timeout_sec
450 .unwrap_or(PEER_QUERY_TIMEOUT_SEC),
451 )
452 }
453
454 pub fn access_type(&self) -> AccessType {
455 self.access_type.unwrap_or(AccessType::Public)
457 }
458
459 pub fn max_concurrent_address_verifications(&self) -> usize {
460 const MAX_CONCURRENT_ADDRESS_VERIFICATIONS: usize = 10;
461
462 self.max_concurrent_address_verifications
463 .unwrap_or(MAX_CONCURRENT_ADDRESS_VERIFICATIONS)
464 }
465
466 pub fn address_verification_timeout(&self) -> Duration {
467 const ADDRESS_VERIFICATION_TIMEOUT_SEC: u64 = 3;
468
469 Duration::from_secs(
470 self.address_verification_timeout_sec
471 .unwrap_or(ADDRESS_VERIFICATION_TIMEOUT_SEC),
472 )
473 }
474
475 pub fn address_verification_total_timeout(&self) -> Duration {
476 const ADDRESS_VERIFICATION_TOTAL_TIMEOUT_SEC: u64 = 8;
477
478 Duration::from_secs(
479 self.address_verification_total_timeout_sec
480 .unwrap_or(ADDRESS_VERIFICATION_TOTAL_TIMEOUT_SEC),
481 )
482 }
483
484 pub fn address_verification_failure_cooldown(&self) -> Duration {
485 const ADDRESS_VERIFICATION_FAILURE_COOLDOWN_SEC: u64 = 600; Duration::from_secs(
488 self.address_verification_failure_cooldown_sec
489 .unwrap_or(ADDRESS_VERIFICATION_FAILURE_COOLDOWN_SEC),
490 )
491 }
492
493 pub fn cooldown_cleanup_interval(&self) -> Duration {
494 const COOLDOWN_CLEANUP_INTERVAL_SEC: u64 = 300; Duration::from_secs(
497 self.cooldown_cleanup_interval_sec
498 .unwrap_or(COOLDOWN_CLEANUP_INTERVAL_SEC),
499 )
500 }
501
502 pub fn is_address_verification_cooldown_enabled(&self) -> bool {
504 self.address_verification_failure_cooldown_sec
505 .unwrap_or(600)
506 > 0
507 }
508
509 pub fn allow_private_addresses(&self) -> bool {
512 self.allow_private_addresses.unwrap_or(false)
513 }
514}
515
516#[derive(Clone, Debug, Default, Deserialize, Serialize)]
517#[serde(rename_all = "kebab-case")]
518pub struct RandomnessConfig {
519 #[serde(skip_serializing_if = "Option::is_none")]
524 pub max_partial_sigs_rounds_ahead: Option<u64>,
525
526 #[serde(skip_serializing_if = "Option::is_none")]
531 pub max_partial_sigs_concurrent_sends: Option<usize>,
532
533 #[serde(skip_serializing_if = "Option::is_none")]
538 pub partial_signature_retry_interval_ms: Option<u64>,
539
540 #[serde(skip_serializing_if = "Option::is_none")]
545 pub mailbox_capacity: Option<usize>,
546
547 #[serde(skip_serializing_if = "Option::is_none")]
551 pub send_partial_signatures_inflight_limit: Option<usize>,
552
553 #[serde(skip_serializing_if = "Option::is_none")]
558 pub max_ignored_peer_weight_factor: Option<f64>,
559}
560
561impl RandomnessConfig {
562 pub fn max_partial_sigs_rounds_ahead(&self) -> u64 {
563 const MAX_PARTIAL_SIGS_ROUNDS_AHEAD: u64 = 50;
564
565 self.max_partial_sigs_rounds_ahead
566 .unwrap_or(MAX_PARTIAL_SIGS_ROUNDS_AHEAD)
567 }
568
569 pub fn max_partial_sigs_concurrent_sends(&self) -> usize {
570 const MAX_PARTIAL_SIGS_CONCURRENT_SENDS: usize = 20;
571
572 self.max_partial_sigs_concurrent_sends
573 .unwrap_or(MAX_PARTIAL_SIGS_CONCURRENT_SENDS)
574 }
575 pub fn partial_signature_retry_interval(&self) -> Duration {
576 const PARTIAL_SIGNATURE_RETRY_INTERVAL: u64 = 5_000; Duration::from_millis(
579 self.partial_signature_retry_interval_ms
580 .unwrap_or(PARTIAL_SIGNATURE_RETRY_INTERVAL),
581 )
582 }
583
584 pub fn mailbox_capacity(&self) -> usize {
585 const MAILBOX_CAPACITY: usize = 1_000_000;
586
587 self.mailbox_capacity.unwrap_or(MAILBOX_CAPACITY)
588 }
589
590 pub fn send_partial_signatures_inflight_limit(&self) -> usize {
591 const SEND_PARTIAL_SIGNATURES_INFLIGHT_LIMIT: usize = 20;
592
593 self.send_partial_signatures_inflight_limit
594 .unwrap_or(SEND_PARTIAL_SIGNATURES_INFLIGHT_LIMIT)
595 }
596
597 pub fn max_ignored_peer_weight_factor(&self) -> f64 {
598 const MAX_IGNORED_PEER_WEIGHT_FACTOR: f64 = 0.2;
599
600 self.max_ignored_peer_weight_factor
601 .unwrap_or(MAX_IGNORED_PEER_WEIGHT_FACTOR)
602 }
603}