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
198impl StateSyncConfig {
199 pub fn interval_period(&self) -> Duration {
200 const INTERVAL_PERIOD_MS: u64 = 5_000; Duration::from_millis(self.interval_period_ms.unwrap_or(INTERVAL_PERIOD_MS))
203 }
204
205 pub fn mailbox_capacity(&self) -> usize {
206 const MAILBOX_CAPACITY: usize = 1_024;
207
208 self.mailbox_capacity.unwrap_or(MAILBOX_CAPACITY)
209 }
210
211 pub fn synced_checkpoint_broadcast_channel_capacity(&self) -> usize {
212 const SYNCED_CHECKPOINT_BROADCAST_CHANNEL_CAPACITY: usize = 1_024;
213
214 self.synced_checkpoint_broadcast_channel_capacity
215 .unwrap_or(SYNCED_CHECKPOINT_BROADCAST_CHANNEL_CAPACITY)
216 }
217
218 pub fn checkpoint_header_download_concurrency(&self) -> usize {
219 const CHECKPOINT_HEADER_DOWNLOAD_CONCURRENCY: usize = 400;
220
221 self.checkpoint_header_download_concurrency
222 .unwrap_or(CHECKPOINT_HEADER_DOWNLOAD_CONCURRENCY)
223 }
224
225 pub fn checkpoint_content_download_concurrency(&self) -> usize {
226 const CHECKPOINT_CONTENT_DOWNLOAD_CONCURRENCY: usize = 400;
227
228 self.checkpoint_content_download_concurrency
229 .unwrap_or(CHECKPOINT_CONTENT_DOWNLOAD_CONCURRENCY)
230 }
231
232 pub fn checkpoint_content_download_tx_concurrency(&self) -> u64 {
233 const CHECKPOINT_CONTENT_DOWNLOAD_TX_CONCURRENCY: u64 = 50_000;
234
235 self.checkpoint_content_download_tx_concurrency
236 .unwrap_or(CHECKPOINT_CONTENT_DOWNLOAD_TX_CONCURRENCY)
237 }
238
239 pub fn timeout(&self) -> Duration {
240 const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
241
242 self.timeout_ms
243 .map(Duration::from_millis)
244 .unwrap_or(DEFAULT_TIMEOUT)
245 }
246
247 pub fn checkpoint_content_timeout(&self) -> Duration {
248 const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60);
249
250 self.checkpoint_content_timeout_ms
251 .map(Duration::from_millis)
252 .unwrap_or(DEFAULT_TIMEOUT)
253 }
254
255 pub fn wait_interval_when_no_peer_to_sync_content(&self) -> Duration {
256 self.wait_interval_when_no_peer_to_sync_content_ms
257 .map(Duration::from_millis)
258 .unwrap_or(self.default_wait_interval_when_no_peer_to_sync_content())
259 }
260
261 fn default_wait_interval_when_no_peer_to_sync_content(&self) -> Duration {
262 if cfg!(msim) {
263 Duration::from_secs(5)
264 } else {
265 Duration::from_secs(10)
266 }
267 }
268
269 pub fn use_get_checkpoint_contents_v2(&self) -> bool {
270 const DEFAULT_USE_GET_CHECKPOINT_CONTENTS_V2: bool = false;
271
272 self.use_get_checkpoint_contents_v2
273 .unwrap_or(DEFAULT_USE_GET_CHECKPOINT_CONTENTS_V2)
274 }
275}
276
277#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
287pub enum AccessType {
288 Public,
289 Private,
290}
291
292#[derive(Clone, Debug, Default, Deserialize, Serialize)]
293#[serde(rename_all = "kebab-case")]
294pub struct DiscoveryConfig {
295 #[serde(skip_serializing_if = "Option::is_none")]
299 pub interval_period_ms: Option<u64>,
300
301 #[serde(skip_serializing_if = "Option::is_none")]
305 pub target_concurrent_connections: Option<usize>,
306
307 #[serde(skip_serializing_if = "Option::is_none")]
314 pub peers_to_query: Option<usize>,
315
316 #[serde(skip_serializing_if = "Option::is_none")]
320 pub get_known_peers_rate_limit: Option<NonZeroU32>,
321
322 #[serde(skip_serializing_if = "Option::is_none")]
324 pub access_type: Option<AccessType>,
325
326 #[serde(skip_serializing_if = "Vec::is_empty", default)]
334 pub allowlisted_peers: Vec<AllowlistedPeer>,
335}
336
337impl DiscoveryConfig {
338 pub fn interval_period(&self) -> Duration {
339 const INTERVAL_PERIOD_MS: u64 = 5_000; Duration::from_millis(self.interval_period_ms.unwrap_or(INTERVAL_PERIOD_MS))
342 }
343
344 pub fn target_concurrent_connections(&self) -> usize {
345 const TARGET_CONCURRENT_CONNECTIONS: usize = 4;
346
347 self.target_concurrent_connections
348 .unwrap_or(TARGET_CONCURRENT_CONNECTIONS)
349 }
350
351 pub fn peers_to_query(&self) -> usize {
352 const PEERS_TO_QUERY: usize = 1;
353
354 self.peers_to_query.unwrap_or(PEERS_TO_QUERY)
355 }
356
357 pub fn access_type(&self) -> AccessType {
358 self.access_type.unwrap_or(AccessType::Public)
360 }
361}
362
363#[derive(Clone, Debug, Default, Deserialize, Serialize)]
364#[serde(rename_all = "kebab-case")]
365pub struct RandomnessConfig {
366 #[serde(skip_serializing_if = "Option::is_none")]
371 pub max_partial_sigs_rounds_ahead: Option<u64>,
372
373 #[serde(skip_serializing_if = "Option::is_none")]
377 pub max_partial_sigs_concurrent_sends: Option<usize>,
378
379 #[serde(skip_serializing_if = "Option::is_none")]
383 pub partial_signature_retry_interval_ms: Option<u64>,
384
385 #[serde(skip_serializing_if = "Option::is_none")]
390 pub mailbox_capacity: Option<usize>,
391
392 #[serde(skip_serializing_if = "Option::is_none")]
396 pub send_partial_signatures_inflight_limit: Option<usize>,
397
398 #[serde(skip_serializing_if = "Option::is_none")]
402 pub max_ignored_peer_weight_factor: Option<f64>,
403}
404
405impl RandomnessConfig {
406 pub fn max_partial_sigs_rounds_ahead(&self) -> u64 {
407 const MAX_PARTIAL_SIGS_ROUNDS_AHEAD: u64 = 50;
408
409 self.max_partial_sigs_rounds_ahead
410 .unwrap_or(MAX_PARTIAL_SIGS_ROUNDS_AHEAD)
411 }
412
413 pub fn max_partial_sigs_concurrent_sends(&self) -> usize {
414 const MAX_PARTIAL_SIGS_CONCURRENT_SENDS: usize = 20;
415
416 self.max_partial_sigs_concurrent_sends
417 .unwrap_or(MAX_PARTIAL_SIGS_CONCURRENT_SENDS)
418 }
419 pub fn partial_signature_retry_interval(&self) -> Duration {
420 const PARTIAL_SIGNATURE_RETRY_INTERVAL: u64 = 5_000; Duration::from_millis(
423 self.partial_signature_retry_interval_ms
424 .unwrap_or(PARTIAL_SIGNATURE_RETRY_INTERVAL),
425 )
426 }
427
428 pub fn mailbox_capacity(&self) -> usize {
429 const MAILBOX_CAPACITY: usize = 1_000_000;
430
431 self.mailbox_capacity.unwrap_or(MAILBOX_CAPACITY)
432 }
433
434 pub fn send_partial_signatures_inflight_limit(&self) -> usize {
435 const SEND_PARTIAL_SIGNATURES_INFLIGHT_LIMIT: usize = 20;
436
437 self.send_partial_signatures_inflight_limit
438 .unwrap_or(SEND_PARTIAL_SIGNATURES_INFLIGHT_LIMIT)
439 }
440
441 pub fn max_ignored_peer_weight_factor(&self) -> f64 {
442 const MAX_IGNORED_PEER_WEIGHT_FACTOR: f64 = 0.2;
443
444 self.max_ignored_peer_weight_factor
445 .unwrap_or(MAX_IGNORED_PEER_WEIGHT_FACTOR)
446 }
447}