1use 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 #[serde(default = "default_listen_address")]
17 pub listen_address: SocketAddr,
18 #[serde(skip_serializing_if = "Option::is_none")]
21 pub external_address: Option<Multiaddr>,
22 #[serde(skip_serializing_if = "Vec::is_empty", default)]
25 pub seed_peers: Vec<SeedPeer>,
26 #[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 #[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 #[serde(skip_serializing_if = "Vec::is_empty", default)]
114 pub pinned_checkpoints: Vec<(CheckpointSequenceNumber, CheckpointDigest)>,
115
116 #[serde(skip_serializing_if = "Option::is_none")]
120 pub interval_period_ms: Option<u64>,
121
122 #[serde(skip_serializing_if = "Option::is_none")]
126 pub mailbox_capacity: Option<usize>,
127
128 #[serde(skip_serializing_if = "Option::is_none")]
132 pub synced_checkpoint_broadcast_channel_capacity: Option<usize>,
133
134 #[serde(skip_serializing_if = "Option::is_none")]
138 pub checkpoint_header_download_concurrency: Option<usize>,
139
140 #[serde(skip_serializing_if = "Option::is_none")]
144 pub checkpoint_content_download_concurrency: Option<usize>,
145
146 #[serde(skip_serializing_if = "Option::is_none")]
152 pub checkpoint_content_download_tx_concurrency: Option<u64>,
153
154 #[serde(skip_serializing_if = "Option::is_none")]
158 pub timeout_ms: Option<u64>,
159
160 #[serde(skip_serializing_if = "Option::is_none")]
164 pub checkpoint_content_timeout_ms: Option<u64>,
165
166 #[serde(skip_serializing_if = "Option::is_none")]
170 pub push_checkpoint_summary_rate_limit: Option<NonZeroU32>,
171
172 #[serde(skip_serializing_if = "Option::is_none")]
176 pub get_checkpoint_summary_rate_limit: Option<NonZeroU32>,
177
178 #[serde(skip_serializing_if = "Option::is_none")]
182 pub get_checkpoint_contents_rate_limit: Option<NonZeroU32>,
183
184 #[serde(skip_serializing_if = "Option::is_none")]
188 pub get_checkpoint_contents_inflight_limit: Option<usize>,
189
190 #[serde(skip_serializing_if = "Option::is_none")]
195 pub get_checkpoint_contents_per_checkpoint_limit: Option<usize>,
196
197 #[serde(skip_serializing_if = "Option::is_none")]
200 pub wait_interval_when_no_peer_to_sync_content_ms: Option<u64>,
201
202 #[serde(skip_serializing_if = "Option::is_none")]
206 pub use_get_checkpoint_contents_v2: Option<bool>,
207
208 #[serde(skip_serializing_if = "Option::is_none")]
213 pub max_checkpoint_lookahead: Option<u64>,
214
215 #[serde(skip_serializing_if = "Option::is_none")]
219 pub max_checkpoint_sync_batch_size: Option<u64>,
220
221 #[serde(skip_serializing_if = "Option::is_none")]
226 pub max_checkpoint_summary_size: Option<usize>,
227
228 #[serde(skip_serializing_if = "Option::is_none")]
232 pub checkpoint_content_timeout_min_ms: Option<u64>,
233
234 #[serde(skip_serializing_if = "Option::is_none")]
238 pub checkpoint_content_timeout_max_ms: Option<u64>,
239
240 #[serde(skip_serializing_if = "Option::is_none")]
244 pub peer_scoring_window_ms: Option<u64>,
245
246 #[serde(skip_serializing_if = "Option::is_none")]
250 pub exploration_probability: Option<f64>,
251
252 #[serde(skip_serializing_if = "Option::is_none")]
257 pub peer_failure_rate: Option<f64>,
258
259 #[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; 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; 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; 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#[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 #[serde(skip_serializing_if = "Option::is_none")]
468 pub interval_period_ms: Option<u64>,
469
470 #[serde(skip_serializing_if = "Option::is_none")]
474 pub target_concurrent_connections: Option<usize>,
475
476 #[serde(skip_serializing_if = "Option::is_none")]
483 pub peers_to_query: Option<usize>,
484
485 #[serde(skip_serializing_if = "Option::is_none")]
489 pub get_known_peers_rate_limit: Option<NonZeroU32>,
490
491 #[serde(skip_serializing_if = "Option::is_none")]
493 pub access_type: Option<AccessType>,
494
495 #[serde(skip_serializing_if = "Vec::is_empty", default)]
503 pub allowlisted_peers: Vec<AllowlistedPeer>,
504
505 #[serde(skip_serializing_if = "Option::is_none")]
509 pub mailbox_capacity: Option<usize>,
510
511 #[serde(skip_serializing_if = "Option::is_none")]
515 pub use_get_known_peers_v3: Option<bool>,
516
517 #[serde(skip_serializing_if = "Option::is_none")]
522 pub peer_addr_store_path: Option<PathBuf>,
523
524 #[serde(skip_serializing_if = "Option::is_none")]
529 pub peer_failure_cooldown_ms: Option<u64>,
530
531 #[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; 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 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; 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 #[serde(skip_serializing_if = "Option::is_none")]
592 pub max_partial_sigs_rounds_ahead: Option<u64>,
593
594 #[serde(skip_serializing_if = "Option::is_none")]
598 pub max_partial_sigs_concurrent_sends: Option<usize>,
599
600 #[serde(skip_serializing_if = "Option::is_none")]
604 pub partial_signature_retry_interval_ms: Option<u64>,
605
606 #[serde(skip_serializing_if = "Option::is_none")]
611 pub mailbox_capacity: Option<usize>,
612
613 #[serde(skip_serializing_if = "Option::is_none")]
617 pub send_partial_signatures_inflight_limit: Option<usize>,
618
619 #[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; 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}