1use std::{net::SocketAddr, num::NonZeroU32, 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
260impl StateSyncConfig {
261 pub fn interval_period(&self) -> Duration {
262 const INTERVAL_PERIOD_MS: u64 = 5_000; Duration::from_millis(self.interval_period_ms.unwrap_or(INTERVAL_PERIOD_MS))
265 }
266
267 pub fn mailbox_capacity(&self) -> usize {
268 const MAILBOX_CAPACITY: usize = 1_024;
269
270 self.mailbox_capacity.unwrap_or(MAILBOX_CAPACITY)
271 }
272
273 pub fn synced_checkpoint_broadcast_channel_capacity(&self) -> usize {
274 const SYNCED_CHECKPOINT_BROADCAST_CHANNEL_CAPACITY: usize = 1_024;
275
276 self.synced_checkpoint_broadcast_channel_capacity
277 .unwrap_or(SYNCED_CHECKPOINT_BROADCAST_CHANNEL_CAPACITY)
278 }
279
280 pub fn checkpoint_header_download_concurrency(&self) -> usize {
281 const CHECKPOINT_HEADER_DOWNLOAD_CONCURRENCY: usize = 400;
282
283 self.checkpoint_header_download_concurrency
284 .unwrap_or(CHECKPOINT_HEADER_DOWNLOAD_CONCURRENCY)
285 }
286
287 pub fn checkpoint_content_download_concurrency(&self) -> usize {
288 const CHECKPOINT_CONTENT_DOWNLOAD_CONCURRENCY: usize = 400;
289
290 self.checkpoint_content_download_concurrency
291 .unwrap_or(CHECKPOINT_CONTENT_DOWNLOAD_CONCURRENCY)
292 }
293
294 pub fn checkpoint_content_download_tx_concurrency(&self) -> u64 {
295 const CHECKPOINT_CONTENT_DOWNLOAD_TX_CONCURRENCY: u64 = 50_000;
296
297 self.checkpoint_content_download_tx_concurrency
298 .unwrap_or(CHECKPOINT_CONTENT_DOWNLOAD_TX_CONCURRENCY)
299 }
300
301 pub fn timeout(&self) -> Duration {
302 const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
303
304 self.timeout_ms
305 .map(Duration::from_millis)
306 .unwrap_or(DEFAULT_TIMEOUT)
307 }
308
309 pub fn checkpoint_content_timeout(&self) -> Duration {
310 const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60);
311
312 self.checkpoint_content_timeout_ms
313 .map(Duration::from_millis)
314 .unwrap_or(DEFAULT_TIMEOUT)
315 }
316
317 pub fn wait_interval_when_no_peer_to_sync_content(&self) -> Duration {
318 self.wait_interval_when_no_peer_to_sync_content_ms
319 .map(Duration::from_millis)
320 .unwrap_or(self.default_wait_interval_when_no_peer_to_sync_content())
321 }
322
323 fn default_wait_interval_when_no_peer_to_sync_content(&self) -> Duration {
324 if cfg!(msim) {
325 Duration::from_secs(5)
326 } else {
327 Duration::from_secs(10)
328 }
329 }
330
331 pub fn use_get_checkpoint_contents_v2(&self) -> bool {
332 const DEFAULT_USE_GET_CHECKPOINT_CONTENTS_V2: bool = true;
333
334 self.use_get_checkpoint_contents_v2
335 .unwrap_or(DEFAULT_USE_GET_CHECKPOINT_CONTENTS_V2)
336 }
337
338 pub fn max_checkpoint_lookahead(&self) -> u64 {
339 const DEFAULT_MAX_CHECKPOINT_LOOKAHEAD: u64 = 1_000;
340
341 self.max_checkpoint_lookahead
342 .unwrap_or(DEFAULT_MAX_CHECKPOINT_LOOKAHEAD)
343 }
344
345 pub fn max_checkpoint_sync_batch_size(&self) -> u64 {
346 const DEFAULT_MAX_CHECKPOINT_SYNC_BATCH_SIZE: u64 = 400;
347
348 self.max_checkpoint_sync_batch_size
349 .unwrap_or(DEFAULT_MAX_CHECKPOINT_SYNC_BATCH_SIZE)
350 }
351
352 pub fn max_checkpoint_summary_size(&self) -> usize {
353 const DEFAULT_MAX_CHECKPOINT_SUMMARY_SIZE: usize = 256 * 1024; self.max_checkpoint_summary_size
356 .unwrap_or(DEFAULT_MAX_CHECKPOINT_SUMMARY_SIZE)
357 }
358
359 pub fn checkpoint_content_timeout_min(&self) -> Duration {
360 const DEFAULT: Duration = Duration::from_secs(5);
361 self.checkpoint_content_timeout_min_ms
362 .map(Duration::from_millis)
363 .unwrap_or(DEFAULT)
364 }
365
366 pub fn checkpoint_content_timeout_max(&self) -> Duration {
367 const DEFAULT: Duration = Duration::from_secs(30);
368 self.checkpoint_content_timeout_max_ms
369 .map(Duration::from_millis)
370 .unwrap_or(DEFAULT)
371 }
372
373 pub fn peer_scoring_window(&self) -> Duration {
374 const DEFAULT: Duration = Duration::from_secs(60);
375 self.peer_scoring_window_ms
376 .map(Duration::from_millis)
377 .unwrap_or(DEFAULT)
378 }
379
380 pub fn exploration_probability(&self) -> f64 {
381 const DEFAULT: f64 = 0.1;
382 self.exploration_probability.unwrap_or(DEFAULT)
383 }
384
385 pub fn peer_failure_rate(&self) -> f64 {
386 const DEFAULT: f64 = 0.3;
387 self.peer_failure_rate.unwrap_or(DEFAULT)
388 }
389
390 pub fn randomized_for_testing() -> Self {
391 use rand::Rng;
392 let mut rng = rand::thread_rng();
393 let config = Self {
394 mailbox_capacity: Some(rng.gen_range(16..=2048)),
395 synced_checkpoint_broadcast_channel_capacity: Some(rng.gen_range(16..=2048)),
396 checkpoint_header_download_concurrency: Some(rng.gen_range(10..=500)),
397 checkpoint_content_download_concurrency: Some(rng.gen_range(10..=500)),
398 max_checkpoint_lookahead: Some(rng.gen_range(100..=2000)),
399 max_checkpoint_sync_batch_size: Some(rng.gen_range(100..=500)),
400 max_checkpoint_summary_size: Some(rng.gen_range(64 * 1024..=512 * 1024)),
401 ..Default::default()
402 };
403 tracing::info!(
404 mailbox_capacity = config.mailbox_capacity.unwrap(),
405 broadcast_capacity = config.synced_checkpoint_broadcast_channel_capacity.unwrap(),
406 header_concurrency = config.checkpoint_header_download_concurrency.unwrap(),
407 content_concurrency = config.checkpoint_content_download_concurrency.unwrap(),
408 lookahead = config.max_checkpoint_lookahead.unwrap(),
409 batch_size = config.max_checkpoint_sync_batch_size.unwrap(),
410 summary_size = config.max_checkpoint_summary_size.unwrap(),
411 "StateSyncConfig::randomized_for_testing"
412 );
413 config
414 }
415}
416
417#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
432pub enum AccessType {
433 Public,
434 Private,
435 Trusted,
436}
437
438#[derive(Clone, Debug, Default, Deserialize, Serialize)]
439#[serde(rename_all = "kebab-case")]
440pub struct DiscoveryConfig {
441 #[serde(skip_serializing_if = "Option::is_none")]
445 pub interval_period_ms: Option<u64>,
446
447 #[serde(skip_serializing_if = "Option::is_none")]
451 pub target_concurrent_connections: Option<usize>,
452
453 #[serde(skip_serializing_if = "Option::is_none")]
460 pub peers_to_query: Option<usize>,
461
462 #[serde(skip_serializing_if = "Option::is_none")]
466 pub get_known_peers_rate_limit: Option<NonZeroU32>,
467
468 #[serde(skip_serializing_if = "Option::is_none")]
470 pub access_type: Option<AccessType>,
471
472 #[serde(skip_serializing_if = "Vec::is_empty", default)]
480 pub allowlisted_peers: Vec<AllowlistedPeer>,
481
482 #[serde(skip_serializing_if = "Option::is_none")]
486 pub mailbox_capacity: Option<usize>,
487
488 #[serde(skip_serializing_if = "Option::is_none")]
492 pub use_get_known_peers_v3: Option<bool>,
493}
494
495impl DiscoveryConfig {
496 pub fn interval_period(&self) -> Duration {
497 const INTERVAL_PERIOD_MS: u64 = 5_000; Duration::from_millis(self.interval_period_ms.unwrap_or(INTERVAL_PERIOD_MS))
500 }
501
502 pub fn target_concurrent_connections(&self) -> usize {
503 const TARGET_CONCURRENT_CONNECTIONS: usize = 4;
504
505 self.target_concurrent_connections
506 .unwrap_or(TARGET_CONCURRENT_CONNECTIONS)
507 }
508
509 pub fn peers_to_query(&self) -> usize {
510 const PEERS_TO_QUERY: usize = 1;
511
512 self.peers_to_query.unwrap_or(PEERS_TO_QUERY)
513 }
514
515 pub fn access_type(&self) -> AccessType {
516 self.access_type.unwrap_or(AccessType::Public)
518 }
519
520 pub fn mailbox_capacity(&self) -> usize {
521 const MAILBOX_CAPACITY: usize = 1_024;
522
523 self.mailbox_capacity.unwrap_or(MAILBOX_CAPACITY)
524 }
525
526 pub fn use_get_known_peers_v3(&self) -> bool {
527 self.use_get_known_peers_v3.unwrap_or(false)
528 }
529}
530
531#[derive(Clone, Debug, Default, Deserialize, Serialize)]
532#[serde(rename_all = "kebab-case")]
533pub struct RandomnessConfig {
534 #[serde(skip_serializing_if = "Option::is_none")]
539 pub max_partial_sigs_rounds_ahead: Option<u64>,
540
541 #[serde(skip_serializing_if = "Option::is_none")]
545 pub max_partial_sigs_concurrent_sends: Option<usize>,
546
547 #[serde(skip_serializing_if = "Option::is_none")]
551 pub partial_signature_retry_interval_ms: Option<u64>,
552
553 #[serde(skip_serializing_if = "Option::is_none")]
558 pub mailbox_capacity: Option<usize>,
559
560 #[serde(skip_serializing_if = "Option::is_none")]
564 pub send_partial_signatures_inflight_limit: Option<usize>,
565
566 #[serde(skip_serializing_if = "Option::is_none")]
570 pub max_ignored_peer_weight_factor: Option<f64>,
571}
572
573impl RandomnessConfig {
574 pub fn max_partial_sigs_rounds_ahead(&self) -> u64 {
575 const MAX_PARTIAL_SIGS_ROUNDS_AHEAD: u64 = 50;
576
577 self.max_partial_sigs_rounds_ahead
578 .unwrap_or(MAX_PARTIAL_SIGS_ROUNDS_AHEAD)
579 }
580
581 pub fn max_partial_sigs_concurrent_sends(&self) -> usize {
582 const MAX_PARTIAL_SIGS_CONCURRENT_SENDS: usize = 20;
583
584 self.max_partial_sigs_concurrent_sends
585 .unwrap_or(MAX_PARTIAL_SIGS_CONCURRENT_SENDS)
586 }
587 pub fn partial_signature_retry_interval(&self) -> Duration {
588 const PARTIAL_SIGNATURE_RETRY_INTERVAL: u64 = 5_000; Duration::from_millis(
591 self.partial_signature_retry_interval_ms
592 .unwrap_or(PARTIAL_SIGNATURE_RETRY_INTERVAL),
593 )
594 }
595
596 pub fn mailbox_capacity(&self) -> usize {
597 const MAILBOX_CAPACITY: usize = 1_000_000;
598
599 self.mailbox_capacity.unwrap_or(MAILBOX_CAPACITY)
600 }
601
602 pub fn send_partial_signatures_inflight_limit(&self) -> usize {
603 const SEND_PARTIAL_SIGNATURES_INFLIGHT_LIMIT: usize = 20;
604
605 self.send_partial_signatures_inflight_limit
606 .unwrap_or(SEND_PARTIAL_SIGNATURES_INFLIGHT_LIMIT)
607 }
608
609 pub fn max_ignored_peer_weight_factor(&self) -> f64 {
610 const MAX_IGNORED_PEER_WEIGHT_FACTOR: f64 = 0.2;
611
612 self.max_ignored_peer_weight_factor
613 .unwrap_or(MAX_IGNORED_PEER_WEIGHT_FACTOR)
614 }
615}