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 = "Option::is_none")]
27 pub anemo_config: Option<anemo::Config>,
28 #[serde(skip_serializing_if = "Option::is_none")]
29 pub state_sync: Option<StateSyncConfig>,
30 #[serde(skip_serializing_if = "Option::is_none")]
31 pub discovery: Option<DiscoveryConfig>,
32 #[serde(skip_serializing_if = "Option::is_none")]
33 pub randomness: Option<RandomnessConfig>,
34 #[serde(skip_serializing_if = "Option::is_none")]
39 pub excessive_message_size: Option<usize>,
40}
41
42fn default_listen_address() -> SocketAddr {
43 "0.0.0.0:8084".parse().unwrap()
44}
45
46impl Default for P2pConfig {
47 fn default() -> Self {
48 Self {
49 listen_address: default_listen_address(),
50 external_address: Default::default(),
51 seed_peers: Default::default(),
52 anemo_config: Default::default(),
53 state_sync: None,
54 discovery: None,
55 randomness: None,
56 excessive_message_size: None,
57 }
58 }
59}
60
61impl P2pConfig {
62 pub fn excessive_message_size(&self) -> usize {
63 const EXCESSIVE_MESSAGE_SIZE: usize = 32 << 20;
64
65 self.excessive_message_size
66 .unwrap_or(EXCESSIVE_MESSAGE_SIZE)
67 }
68
69 pub fn set_discovery_config(mut self, discovery_config: DiscoveryConfig) -> Self {
70 self.discovery = Some(discovery_config);
71 self
72 }
73}
74
75#[derive(Clone, Debug, Deserialize, Serialize)]
76#[serde(rename_all = "kebab-case")]
77pub struct SeedPeer {
78 #[serde(skip_serializing_if = "Option::is_none")]
79 pub peer_id: Option<anemo::PeerId>,
80 pub address: Multiaddr,
81}
82
83#[derive(Clone, Debug, Deserialize, Serialize)]
84#[serde(rename_all = "kebab-case")]
85pub struct AllowlistedPeer {
86 pub peer_id: anemo::PeerId,
87 #[serde(skip_serializing_if = "Option::is_none")]
88 pub address: Option<Multiaddr>,
89}
90
91#[derive(Clone, Debug, Default, Deserialize, Serialize)]
92#[serde(rename_all = "kebab-case")]
93pub struct StateSyncConfig {
94 #[serde(skip_serializing_if = "Vec::is_empty", default)]
103 pub pinned_checkpoints: Vec<(CheckpointSequenceNumber, CheckpointDigest)>,
104
105 #[serde(skip_serializing_if = "Option::is_none")]
109 pub interval_period_ms: Option<u64>,
110
111 #[serde(skip_serializing_if = "Option::is_none")]
115 pub mailbox_capacity: Option<usize>,
116
117 #[serde(skip_serializing_if = "Option::is_none")]
121 pub synced_checkpoint_broadcast_channel_capacity: Option<usize>,
122
123 #[serde(skip_serializing_if = "Option::is_none")]
127 pub checkpoint_header_download_concurrency: Option<usize>,
128
129 #[serde(skip_serializing_if = "Option::is_none")]
133 pub checkpoint_content_download_concurrency: Option<usize>,
134
135 #[serde(skip_serializing_if = "Option::is_none")]
141 pub checkpoint_content_download_tx_concurrency: Option<u64>,
142
143 #[serde(skip_serializing_if = "Option::is_none")]
147 pub timeout_ms: Option<u64>,
148
149 #[serde(skip_serializing_if = "Option::is_none")]
153 pub checkpoint_content_timeout_ms: Option<u64>,
154
155 #[serde(skip_serializing_if = "Option::is_none")]
159 pub push_checkpoint_summary_rate_limit: Option<NonZeroU32>,
160
161 #[serde(skip_serializing_if = "Option::is_none")]
165 pub get_checkpoint_summary_rate_limit: Option<NonZeroU32>,
166
167 #[serde(skip_serializing_if = "Option::is_none")]
171 pub get_checkpoint_contents_rate_limit: Option<NonZeroU32>,
172
173 #[serde(skip_serializing_if = "Option::is_none")]
177 pub get_checkpoint_contents_inflight_limit: Option<usize>,
178
179 #[serde(skip_serializing_if = "Option::is_none")]
184 pub get_checkpoint_contents_per_checkpoint_limit: Option<usize>,
185
186 #[serde(skip_serializing_if = "Option::is_none")]
189 pub wait_interval_when_no_peer_to_sync_content_ms: Option<u64>,
190
191 #[serde(skip_serializing_if = "Option::is_none")]
195 pub use_get_checkpoint_contents_v2: Option<bool>,
196
197 #[serde(skip_serializing_if = "Option::is_none")]
202 pub max_checkpoint_lookahead: Option<u64>,
203
204 #[serde(skip_serializing_if = "Option::is_none")]
208 pub max_checkpoint_sync_batch_size: Option<u64>,
209
210 #[serde(skip_serializing_if = "Option::is_none")]
215 pub max_checkpoint_summary_size: Option<usize>,
216}
217
218impl StateSyncConfig {
219 pub fn interval_period(&self) -> Duration {
220 const INTERVAL_PERIOD_MS: u64 = 5_000; Duration::from_millis(self.interval_period_ms.unwrap_or(INTERVAL_PERIOD_MS))
223 }
224
225 pub fn mailbox_capacity(&self) -> usize {
226 const MAILBOX_CAPACITY: usize = 1_024;
227
228 self.mailbox_capacity.unwrap_or(MAILBOX_CAPACITY)
229 }
230
231 pub fn synced_checkpoint_broadcast_channel_capacity(&self) -> usize {
232 const SYNCED_CHECKPOINT_BROADCAST_CHANNEL_CAPACITY: usize = 1_024;
233
234 self.synced_checkpoint_broadcast_channel_capacity
235 .unwrap_or(SYNCED_CHECKPOINT_BROADCAST_CHANNEL_CAPACITY)
236 }
237
238 pub fn checkpoint_header_download_concurrency(&self) -> usize {
239 const CHECKPOINT_HEADER_DOWNLOAD_CONCURRENCY: usize = 400;
240
241 self.checkpoint_header_download_concurrency
242 .unwrap_or(CHECKPOINT_HEADER_DOWNLOAD_CONCURRENCY)
243 }
244
245 pub fn checkpoint_content_download_concurrency(&self) -> usize {
246 const CHECKPOINT_CONTENT_DOWNLOAD_CONCURRENCY: usize = 400;
247
248 self.checkpoint_content_download_concurrency
249 .unwrap_or(CHECKPOINT_CONTENT_DOWNLOAD_CONCURRENCY)
250 }
251
252 pub fn checkpoint_content_download_tx_concurrency(&self) -> u64 {
253 const CHECKPOINT_CONTENT_DOWNLOAD_TX_CONCURRENCY: u64 = 50_000;
254
255 self.checkpoint_content_download_tx_concurrency
256 .unwrap_or(CHECKPOINT_CONTENT_DOWNLOAD_TX_CONCURRENCY)
257 }
258
259 pub fn timeout(&self) -> Duration {
260 const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
261
262 self.timeout_ms
263 .map(Duration::from_millis)
264 .unwrap_or(DEFAULT_TIMEOUT)
265 }
266
267 pub fn checkpoint_content_timeout(&self) -> Duration {
268 const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60);
269
270 self.checkpoint_content_timeout_ms
271 .map(Duration::from_millis)
272 .unwrap_or(DEFAULT_TIMEOUT)
273 }
274
275 pub fn wait_interval_when_no_peer_to_sync_content(&self) -> Duration {
276 self.wait_interval_when_no_peer_to_sync_content_ms
277 .map(Duration::from_millis)
278 .unwrap_or(self.default_wait_interval_when_no_peer_to_sync_content())
279 }
280
281 fn default_wait_interval_when_no_peer_to_sync_content(&self) -> Duration {
282 if cfg!(msim) {
283 Duration::from_secs(5)
284 } else {
285 Duration::from_secs(10)
286 }
287 }
288
289 pub fn use_get_checkpoint_contents_v2(&self) -> bool {
290 const DEFAULT_USE_GET_CHECKPOINT_CONTENTS_V2: bool = false;
291
292 self.use_get_checkpoint_contents_v2
293 .unwrap_or(DEFAULT_USE_GET_CHECKPOINT_CONTENTS_V2)
294 }
295
296 pub fn max_checkpoint_lookahead(&self) -> u64 {
297 const DEFAULT_MAX_CHECKPOINT_LOOKAHEAD: u64 = 1_000;
298
299 self.max_checkpoint_lookahead
300 .unwrap_or(DEFAULT_MAX_CHECKPOINT_LOOKAHEAD)
301 }
302
303 pub fn max_checkpoint_sync_batch_size(&self) -> u64 {
304 const DEFAULT_MAX_CHECKPOINT_SYNC_BATCH_SIZE: u64 = 400;
305
306 self.max_checkpoint_sync_batch_size
307 .unwrap_or(DEFAULT_MAX_CHECKPOINT_SYNC_BATCH_SIZE)
308 }
309
310 pub fn max_checkpoint_summary_size(&self) -> usize {
311 const DEFAULT_MAX_CHECKPOINT_SUMMARY_SIZE: usize = 256 * 1024; self.max_checkpoint_summary_size
314 .unwrap_or(DEFAULT_MAX_CHECKPOINT_SUMMARY_SIZE)
315 }
316
317 pub fn randomized_for_testing() -> Self {
319 use rand::Rng;
320 let mut rng = rand::thread_rng();
321 let config = Self {
322 mailbox_capacity: Some(rng.gen_range(16..=2048)),
323 synced_checkpoint_broadcast_channel_capacity: Some(rng.gen_range(16..=2048)),
324 checkpoint_header_download_concurrency: Some(rng.gen_range(10..=500)),
325 checkpoint_content_download_concurrency: Some(rng.gen_range(10..=500)),
326 max_checkpoint_lookahead: Some(rng.gen_range(100..=2000)),
327 max_checkpoint_sync_batch_size: Some(rng.gen_range(100..=500)),
329 max_checkpoint_summary_size: Some(rng.gen_range(64 * 1024..=512 * 1024)),
330 ..Default::default()
331 };
332 tracing::info!(
333 mailbox_capacity = config.mailbox_capacity.unwrap(),
334 broadcast_capacity = config.synced_checkpoint_broadcast_channel_capacity.unwrap(),
335 header_concurrency = config.checkpoint_header_download_concurrency.unwrap(),
336 content_concurrency = config.checkpoint_content_download_concurrency.unwrap(),
337 lookahead = config.max_checkpoint_lookahead.unwrap(),
338 batch_size = config.max_checkpoint_sync_batch_size.unwrap(),
339 summary_size = config.max_checkpoint_summary_size.unwrap(),
340 "StateSyncConfig::randomized_for_testing"
341 );
342 config
343 }
344}
345
346#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
356pub enum AccessType {
357 Public,
358 Private,
359}
360
361#[derive(Clone, Debug, Default, Deserialize, Serialize)]
362#[serde(rename_all = "kebab-case")]
363pub struct DiscoveryConfig {
364 #[serde(skip_serializing_if = "Option::is_none")]
368 pub interval_period_ms: Option<u64>,
369
370 #[serde(skip_serializing_if = "Option::is_none")]
374 pub target_concurrent_connections: Option<usize>,
375
376 #[serde(skip_serializing_if = "Option::is_none")]
383 pub peers_to_query: Option<usize>,
384
385 #[serde(skip_serializing_if = "Option::is_none")]
389 pub get_known_peers_rate_limit: Option<NonZeroU32>,
390
391 #[serde(skip_serializing_if = "Option::is_none")]
393 pub access_type: Option<AccessType>,
394
395 #[serde(skip_serializing_if = "Vec::is_empty", default)]
403 pub allowlisted_peers: Vec<AllowlistedPeer>,
404}
405
406impl DiscoveryConfig {
407 pub fn interval_period(&self) -> Duration {
408 const INTERVAL_PERIOD_MS: u64 = 5_000; Duration::from_millis(self.interval_period_ms.unwrap_or(INTERVAL_PERIOD_MS))
411 }
412
413 pub fn target_concurrent_connections(&self) -> usize {
414 const TARGET_CONCURRENT_CONNECTIONS: usize = 4;
415
416 self.target_concurrent_connections
417 .unwrap_or(TARGET_CONCURRENT_CONNECTIONS)
418 }
419
420 pub fn peers_to_query(&self) -> usize {
421 const PEERS_TO_QUERY: usize = 1;
422
423 self.peers_to_query.unwrap_or(PEERS_TO_QUERY)
424 }
425
426 pub fn access_type(&self) -> AccessType {
427 self.access_type.unwrap_or(AccessType::Public)
429 }
430}
431
432#[derive(Clone, Debug, Default, Deserialize, Serialize)]
433#[serde(rename_all = "kebab-case")]
434pub struct RandomnessConfig {
435 #[serde(skip_serializing_if = "Option::is_none")]
440 pub max_partial_sigs_rounds_ahead: Option<u64>,
441
442 #[serde(skip_serializing_if = "Option::is_none")]
446 pub max_partial_sigs_concurrent_sends: Option<usize>,
447
448 #[serde(skip_serializing_if = "Option::is_none")]
452 pub partial_signature_retry_interval_ms: Option<u64>,
453
454 #[serde(skip_serializing_if = "Option::is_none")]
459 pub mailbox_capacity: Option<usize>,
460
461 #[serde(skip_serializing_if = "Option::is_none")]
465 pub send_partial_signatures_inflight_limit: Option<usize>,
466
467 #[serde(skip_serializing_if = "Option::is_none")]
471 pub max_ignored_peer_weight_factor: Option<f64>,
472}
473
474impl RandomnessConfig {
475 pub fn max_partial_sigs_rounds_ahead(&self) -> u64 {
476 const MAX_PARTIAL_SIGS_ROUNDS_AHEAD: u64 = 50;
477
478 self.max_partial_sigs_rounds_ahead
479 .unwrap_or(MAX_PARTIAL_SIGS_ROUNDS_AHEAD)
480 }
481
482 pub fn max_partial_sigs_concurrent_sends(&self) -> usize {
483 const MAX_PARTIAL_SIGS_CONCURRENT_SENDS: usize = 20;
484
485 self.max_partial_sigs_concurrent_sends
486 .unwrap_or(MAX_PARTIAL_SIGS_CONCURRENT_SENDS)
487 }
488 pub fn partial_signature_retry_interval(&self) -> Duration {
489 const PARTIAL_SIGNATURE_RETRY_INTERVAL: u64 = 5_000; Duration::from_millis(
492 self.partial_signature_retry_interval_ms
493 .unwrap_or(PARTIAL_SIGNATURE_RETRY_INTERVAL),
494 )
495 }
496
497 pub fn mailbox_capacity(&self) -> usize {
498 const MAILBOX_CAPACITY: usize = 1_000_000;
499
500 self.mailbox_capacity.unwrap_or(MAILBOX_CAPACITY)
501 }
502
503 pub fn send_partial_signatures_inflight_limit(&self) -> usize {
504 const SEND_PARTIAL_SIGNATURES_INFLIGHT_LIMIT: usize = 20;
505
506 self.send_partial_signatures_inflight_limit
507 .unwrap_or(SEND_PARTIAL_SIGNATURES_INFLIGHT_LIMIT)
508 }
509
510 pub fn max_ignored_peer_weight_factor(&self) -> f64 {
511 const MAX_IGNORED_PEER_WEIGHT_FACTOR: f64 = 0.2;
512
513 self.max_ignored_peer_weight_factor
514 .unwrap_or(MAX_IGNORED_PEER_WEIGHT_FACTOR)
515 }
516}