Skip to main content

iota_config/
p2p.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::{net::SocketAddr, num::NonZeroU32, time::Duration};
6
7use iota_sdk_types::CheckpointDigest;
8use iota_types::{messages_checkpoint::CheckpointSequenceNumber, multiaddr::Multiaddr};
9use serde::{Deserialize, Serialize};
10
11#[derive(Clone, Debug, Deserialize, Serialize)]
12#[serde(rename_all = "kebab-case")]
13pub struct P2pConfig {
14    /// The address that the p2p network will bind on.
15    #[serde(default = "default_listen_address")]
16    pub listen_address: SocketAddr,
17    /// The external address other nodes can use to reach this node.
18    /// This will be shared with other peers through the discovery service
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub external_address: Option<Multiaddr>,
21    /// SeedPeers are preferred and the node will always try to ensure a
22    /// connection is established with these nodes.
23    #[serde(skip_serializing_if = "Vec::is_empty", default)]
24    pub seed_peers: Vec<SeedPeer>,
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub anemo_config: Option<anemo::Config>,
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub state_sync: Option<StateSyncConfig>,
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub discovery: Option<DiscoveryConfig>,
31    #[serde(skip_serializing_if = "Option::is_none")]
32    pub randomness: Option<RandomnessConfig>,
33    /// Size in bytes above which network messages are considered excessively
34    /// large. Excessively large messages will still be handled, but logged
35    /// and reported in metrics for debugging.
36    ///
37    /// If unspecified, this will default to 8 MiB.
38    #[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    /// List of "known-good" checkpoints that state sync will be forced to use.
95    /// State sync will skip verification of pinned checkpoints, and reject
96    /// checkpoints with digests that don't match pinned values for a given
97    /// sequence number.
98    ///
99    /// This can be used:
100    /// - in case of a fork, to prevent the node from syncing to the wrong
101    ///   chain.
102    /// - in case of a network stall, to force the node to proceed with a
103    ///   manually-injected checkpoint.
104    #[serde(skip_serializing_if = "Vec::is_empty", default)]
105    pub pinned_checkpoints: Vec<(CheckpointSequenceNumber, CheckpointDigest)>,
106
107    /// Query peers for their latest checkpoint every interval period.
108    ///
109    /// If unspecified, this will default to `5,000` milliseconds.
110    #[serde(skip_serializing_if = "Option::is_none")]
111    pub interval_period_ms: Option<u64>,
112
113    /// Size of the StateSync actor's mailbox.
114    ///
115    /// If unspecified, this will default to `1,024`.
116    #[serde(skip_serializing_if = "Option::is_none")]
117    pub mailbox_capacity: Option<usize>,
118
119    /// Size of the broadcast channel use for notifying other systems of newly
120    /// sync'ed checkpoints.
121    ///
122    /// If unspecified, this will default to `1,024`.
123    #[serde(skip_serializing_if = "Option::is_none")]
124    pub synced_checkpoint_broadcast_channel_capacity: Option<usize>,
125
126    /// Set the upper bound on the number of checkpoint headers to be downloaded
127    /// concurrently.
128    ///
129    /// If unspecified, this will default to `400`.
130    #[serde(skip_serializing_if = "Option::is_none")]
131    pub checkpoint_header_download_concurrency: Option<usize>,
132
133    /// Set the upper bound on the number of checkpoint contents to be
134    /// downloaded concurrently.
135    ///
136    /// If unspecified, this will default to `400`.
137    #[serde(skip_serializing_if = "Option::is_none")]
138    pub checkpoint_content_download_concurrency: Option<usize>,
139
140    /// Set the upper bound on the number of individual transactions contained
141    /// in checkpoint contents to be downloaded concurrently. If both this
142    /// value and `checkpoint_content_download_concurrency` are set, the
143    /// lower of the two will apply.
144    ///
145    /// If unspecified, this will default to `50,000`.
146    #[serde(skip_serializing_if = "Option::is_none")]
147    pub checkpoint_content_download_tx_concurrency: Option<u64>,
148
149    /// Set the timeout that should be used when sending most state-sync RPC
150    /// requests.
151    ///
152    /// If unspecified, this will default to `10,000` milliseconds.
153    #[serde(skip_serializing_if = "Option::is_none")]
154    pub timeout_ms: Option<u64>,
155
156    /// Set the timeout that should be used when sending RPC requests to sync
157    /// checkpoint contents.
158    ///
159    /// If unspecified, this will default to `10,000` milliseconds.
160    #[serde(skip_serializing_if = "Option::is_none")]
161    pub checkpoint_content_timeout_ms: Option<u64>,
162
163    /// Per-peer rate-limit (in requests/sec) for the PushCheckpointSummary RPC.
164    ///
165    /// If unspecified, this will default to no limit.
166    #[serde(skip_serializing_if = "Option::is_none")]
167    pub push_checkpoint_summary_rate_limit: Option<NonZeroU32>,
168
169    /// Per-peer rate-limit (in requests/sec) for the GetCheckpointSummary RPC.
170    ///
171    /// If unspecified, this will default to no limit.
172    #[serde(skip_serializing_if = "Option::is_none")]
173    pub get_checkpoint_summary_rate_limit: Option<NonZeroU32>,
174
175    /// Per-peer rate-limit (in requests/sec) for the GetCheckpointContents RPC.
176    ///
177    /// If unspecified, this will default to no limit.
178    #[serde(skip_serializing_if = "Option::is_none")]
179    pub get_checkpoint_contents_rate_limit: Option<NonZeroU32>,
180
181    /// Per-peer inflight limit for the GetCheckpointContents RPC.
182    ///
183    /// If unspecified, this will default to no limit.
184    #[serde(skip_serializing_if = "Option::is_none")]
185    pub get_checkpoint_contents_inflight_limit: Option<usize>,
186
187    /// Per-checkpoint inflight limit for the GetCheckpointContents RPC. This is
188    /// enforced globally across all peers.
189    ///
190    /// If unspecified, this will default to no limit.
191    #[serde(skip_serializing_if = "Option::is_none")]
192    pub get_checkpoint_contents_per_checkpoint_limit: Option<usize>,
193
194    /// The amount of time to wait before retry if there are no peers to sync
195    /// content from. If unspecified, this will set to default value
196    #[serde(skip_serializing_if = "Option::is_none")]
197    pub wait_interval_when_no_peer_to_sync_content_ms: Option<u64>,
198}
199
200impl StateSyncConfig {
201    pub fn interval_period(&self) -> Duration {
202        const INTERVAL_PERIOD_MS: u64 = 5_000; // 5 seconds
203
204        Duration::from_millis(self.interval_period_ms.unwrap_or(INTERVAL_PERIOD_MS))
205    }
206
207    pub fn mailbox_capacity(&self) -> usize {
208        const MAILBOX_CAPACITY: usize = 1_024;
209
210        self.mailbox_capacity.unwrap_or(MAILBOX_CAPACITY)
211    }
212
213    pub fn synced_checkpoint_broadcast_channel_capacity(&self) -> usize {
214        const SYNCED_CHECKPOINT_BROADCAST_CHANNEL_CAPACITY: usize = 1_024;
215
216        self.synced_checkpoint_broadcast_channel_capacity
217            .unwrap_or(SYNCED_CHECKPOINT_BROADCAST_CHANNEL_CAPACITY)
218    }
219
220    pub fn checkpoint_header_download_concurrency(&self) -> usize {
221        const CHECKPOINT_HEADER_DOWNLOAD_CONCURRENCY: usize = 400;
222
223        self.checkpoint_header_download_concurrency
224            .unwrap_or(CHECKPOINT_HEADER_DOWNLOAD_CONCURRENCY)
225    }
226
227    pub fn checkpoint_content_download_concurrency(&self) -> usize {
228        const CHECKPOINT_CONTENT_DOWNLOAD_CONCURRENCY: usize = 400;
229
230        self.checkpoint_content_download_concurrency
231            .unwrap_or(CHECKPOINT_CONTENT_DOWNLOAD_CONCURRENCY)
232    }
233
234    pub fn checkpoint_content_download_tx_concurrency(&self) -> u64 {
235        const CHECKPOINT_CONTENT_DOWNLOAD_TX_CONCURRENCY: u64 = 50_000;
236
237        self.checkpoint_content_download_tx_concurrency
238            .unwrap_or(CHECKPOINT_CONTENT_DOWNLOAD_TX_CONCURRENCY)
239    }
240
241    pub fn timeout(&self) -> Duration {
242        const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
243
244        self.timeout_ms
245            .map(Duration::from_millis)
246            .unwrap_or(DEFAULT_TIMEOUT)
247    }
248
249    pub fn checkpoint_content_timeout(&self) -> Duration {
250        const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60);
251
252        self.checkpoint_content_timeout_ms
253            .map(Duration::from_millis)
254            .unwrap_or(DEFAULT_TIMEOUT)
255    }
256
257    pub fn wait_interval_when_no_peer_to_sync_content(&self) -> Duration {
258        self.wait_interval_when_no_peer_to_sync_content_ms
259            .map(Duration::from_millis)
260            .unwrap_or(self.default_wait_interval_when_no_peer_to_sync_content())
261    }
262
263    fn default_wait_interval_when_no_peer_to_sync_content(&self) -> Duration {
264        if cfg!(msim) {
265            Duration::from_secs(5)
266        } else {
267            Duration::from_secs(10)
268        }
269    }
270
271    pub fn randomized_for_testing() -> Self {
272        use rand::Rng;
273        let mut rng = rand::thread_rng();
274        let config = Self {
275            mailbox_capacity: Some(rng.gen_range(16..=2048)),
276            synced_checkpoint_broadcast_channel_capacity: Some(rng.gen_range(16..=2048)),
277            checkpoint_header_download_concurrency: Some(rng.gen_range(10..=500)),
278            checkpoint_content_download_concurrency: Some(rng.gen_range(10..=500)),
279            ..Default::default()
280        };
281        tracing::info!(
282            mailbox_capacity = config.mailbox_capacity.unwrap(),
283            broadcast_capacity = config.synced_checkpoint_broadcast_channel_capacity.unwrap(),
284            header_concurrency = config.checkpoint_header_download_concurrency.unwrap(),
285            content_concurrency = config.checkpoint_content_download_concurrency.unwrap(),
286            "StateSyncConfig::randomized_for_testing"
287        );
288        config
289    }
290}
291
292/// Access Type of a node.
293/// AccessType info is shared in the discovery process.
294/// * If the node marks itself as Public, other nodes may try to connect to it.
295/// * If the node marks itself as Private, only nodes that have it in their
296///   `allowlisted_peers` or `seed_peers` will try to connect to it.
297/// * If not set, defaults to Public.
298///
299/// AccessType is useful when a network of nodes want to stay private. To
300/// achieve this, mark every node in this network as `Private` and
301/// allowlist/seed them to each other.
302#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
303pub enum AccessType {
304    Public,
305    Private,
306}
307
308#[derive(Clone, Debug, Default, Deserialize, Serialize)]
309#[serde(rename_all = "kebab-case")]
310pub struct DiscoveryConfig {
311    /// Query peers for their latest checkpoint every interval period.
312    ///
313    /// If unspecified, this will default to `5,000` milliseconds.
314    #[serde(skip_serializing_if = "Option::is_none")]
315    pub interval_period_ms: Option<u64>,
316
317    /// Target number of concurrent connections to establish.
318    ///
319    /// If unspecified, this will default to `4`.
320    #[serde(skip_serializing_if = "Option::is_none")]
321    pub target_concurrent_connections: Option<usize>,
322
323    /// Number of peers to query each interval.
324    ///
325    /// Sets the number of peers, to be randomly selected, that are queried for
326    /// their known peers each interval.
327    ///
328    /// If unspecified, this will default to `1`.
329    #[serde(skip_serializing_if = "Option::is_none")]
330    pub peers_to_query: Option<usize>,
331
332    /// Timeout for individual peer query requests in discovery protocol.
333    ///
334    /// If unspecified, this will default to `1` second.
335    #[serde(skip_serializing_if = "Option::is_none")]
336    pub peer_query_timeout_sec: Option<u64>,
337
338    /// Per-peer rate-limit (in requests/sec) for the GetKnownPeers RPC.
339    ///
340    /// If unspecified, this will default to no limit.
341    #[serde(skip_serializing_if = "Option::is_none")]
342    pub get_known_peers_rate_limit: Option<NonZeroU32>,
343
344    /// See docstring for `AccessType`.
345    #[serde(skip_serializing_if = "Option::is_none")]
346    pub access_type: Option<AccessType>,
347
348    /// Like `seed_peers` in `P2pConfig`, allowlisted peers will always be
349    /// allowed to establish connection with this node regardless of the
350    /// concurrency limit. Unlike `seed_peers`, a node does not reach out to
351    /// `allowlisted_peers` preferentially. It is also used to determine if
352    /// a peer is accessible when its AccessType is Private. For example, a
353    /// node will ignore a peer with Private AccessType if the peer is not in
354    /// its `allowlisted_peers`. Namely, the node will not try to establish
355    /// connections to this peer, nor advertise this peer's info to other
356    /// peers in the network.
357    #[serde(skip_serializing_if = "Vec::is_empty", default)]
358    pub allowlisted_peers: Vec<AllowlistedPeer>,
359
360    /// Maximum number of concurrent address verification attempts.
361    /// This prevents overwhelming the network when verifying many peers at
362    /// once.
363    ///
364    /// If unspecified, this will default to `10`.
365    #[serde(skip_serializing_if = "Option::is_none")]
366    pub max_concurrent_address_verifications: Option<usize>,
367
368    /// Timeout for individual address verification attempts.
369    ///
370    /// If unspecified, this will default to `3` seconds.
371    #[serde(skip_serializing_if = "Option::is_none")]
372    pub address_verification_timeout_sec: Option<u64>,
373
374    /// Total timeout for all address verification attempts to prevent DoS
375    /// attacks.
376    ///
377    /// If unspecified, this will default to `8` seconds.
378    #[serde(skip_serializing_if = "Option::is_none")]
379    pub address_verification_total_timeout_sec: Option<u64>,
380
381    /// Cooldown period in seconds for peers whose address verification failed.
382    /// During this period, new peer info from the same peer will be ignored.
383    /// Set to 0 to disable the cooldown feature entirely.
384    ///
385    /// If unspecified, this will default to `600` seconds (10 minutes).
386    #[serde(skip_serializing_if = "Option::is_none")]
387    pub address_verification_failure_cooldown_sec: Option<u64>,
388
389    /// Interval for cleaning up old entries from the verification failure
390    /// cooldown list.
391    ///
392    /// If unspecified, this will default to `300` seconds (5 minutes).
393    #[serde(skip_serializing_if = "Option::is_none")]
394    pub cooldown_cleanup_interval_sec: Option<u64>,
395
396    /// Whether to allow private IP and local DNS addresses (e.g., 192.168.0.1,
397    /// localhost, .local) when verifying peer addresses.
398    #[serde(skip_serializing_if = "Option::is_none")]
399    pub allow_private_addresses: Option<bool>,
400}
401
402impl DiscoveryConfig {
403    pub fn interval_period(&self) -> Duration {
404        const INTERVAL_PERIOD_MS: u64 = 10_000; // 10 seconds
405
406        Duration::from_millis(self.interval_period_ms.unwrap_or(INTERVAL_PERIOD_MS))
407    }
408
409    pub fn target_concurrent_connections(&self) -> usize {
410        const TARGET_CONCURRENT_CONNECTIONS: usize = 4;
411
412        self.target_concurrent_connections
413            .unwrap_or(TARGET_CONCURRENT_CONNECTIONS)
414    }
415
416    pub fn peers_to_query(&self) -> usize {
417        const PEERS_TO_QUERY: usize = 1;
418
419        self.peers_to_query.unwrap_or(PEERS_TO_QUERY)
420    }
421
422    pub fn peer_query_timeout(&self) -> Duration {
423        const PEER_QUERY_TIMEOUT_SEC: u64 = 1;
424
425        Duration::from_secs(
426            self.peer_query_timeout_sec
427                .unwrap_or(PEER_QUERY_TIMEOUT_SEC),
428        )
429    }
430
431    pub fn access_type(&self) -> AccessType {
432        // defaults None to Public
433        self.access_type.unwrap_or(AccessType::Public)
434    }
435
436    pub fn max_concurrent_address_verifications(&self) -> usize {
437        const MAX_CONCURRENT_ADDRESS_VERIFICATIONS: usize = 10;
438
439        self.max_concurrent_address_verifications
440            .unwrap_or(MAX_CONCURRENT_ADDRESS_VERIFICATIONS)
441    }
442
443    pub fn address_verification_timeout(&self) -> Duration {
444        const ADDRESS_VERIFICATION_TIMEOUT_SEC: u64 = 3;
445
446        Duration::from_secs(
447            self.address_verification_timeout_sec
448                .unwrap_or(ADDRESS_VERIFICATION_TIMEOUT_SEC),
449        )
450    }
451
452    pub fn address_verification_total_timeout(&self) -> Duration {
453        const ADDRESS_VERIFICATION_TOTAL_TIMEOUT_SEC: u64 = 8;
454
455        Duration::from_secs(
456            self.address_verification_total_timeout_sec
457                .unwrap_or(ADDRESS_VERIFICATION_TOTAL_TIMEOUT_SEC),
458        )
459    }
460
461    pub fn address_verification_failure_cooldown(&self) -> Duration {
462        const ADDRESS_VERIFICATION_FAILURE_COOLDOWN_SEC: u64 = 600; // 10 minutes
463
464        Duration::from_secs(
465            self.address_verification_failure_cooldown_sec
466                .unwrap_or(ADDRESS_VERIFICATION_FAILURE_COOLDOWN_SEC),
467        )
468    }
469
470    pub fn cooldown_cleanup_interval(&self) -> Duration {
471        const COOLDOWN_CLEANUP_INTERVAL_SEC: u64 = 300; // 5 minutes
472
473        Duration::from_secs(
474            self.cooldown_cleanup_interval_sec
475                .unwrap_or(COOLDOWN_CLEANUP_INTERVAL_SEC),
476        )
477    }
478
479    /// Returns true if address verification cooldown is enabled (cooldown > 0)
480    pub fn is_address_verification_cooldown_enabled(&self) -> bool {
481        self.address_verification_failure_cooldown_sec
482            .unwrap_or(600)
483            > 0
484    }
485
486    /// Whether to allow private IP and local DNS addresses (e.g., 192.168.0.1,
487    /// localhost, .local) when verifying peer addresses.
488    pub fn allow_private_addresses(&self) -> bool {
489        self.allow_private_addresses.unwrap_or(false)
490    }
491}
492
493#[derive(Clone, Debug, Default, Deserialize, Serialize)]
494#[serde(rename_all = "kebab-case")]
495pub struct RandomnessConfig {
496    /// Maximum number of rounds ahead of our most recent completed round for
497    /// which we should accept partial signatures from other validators.
498    ///
499    /// If unspecified, this will default to 50.
500    #[serde(skip_serializing_if = "Option::is_none")]
501    pub max_partial_sigs_rounds_ahead: Option<u64>,
502
503    /// Maximum number of rounds for which partial signatures should be
504    /// concurrently sent.
505    ///
506    /// If unspecified, this will default to 20.
507    #[serde(skip_serializing_if = "Option::is_none")]
508    pub max_partial_sigs_concurrent_sends: Option<usize>,
509
510    /// Interval at which to retry sending partial signatures until the round is
511    /// complete.
512    ///
513    /// If unspecified, this will default to `5,000` milliseconds.
514    #[serde(skip_serializing_if = "Option::is_none")]
515    pub partial_signature_retry_interval_ms: Option<u64>,
516
517    /// Size of the Randomness actor's mailbox. This should be set large enough
518    /// to never overflow unless a bug is encountered.
519    ///
520    /// If unspecified, this will default to `1,000,000`.
521    #[serde(skip_serializing_if = "Option::is_none")]
522    pub mailbox_capacity: Option<usize>,
523
524    /// Per-peer inflight limit for the SendPartialSignatures RPC.
525    ///
526    /// If unspecified, this will default to 20.
527    #[serde(skip_serializing_if = "Option::is_none")]
528    pub send_partial_signatures_inflight_limit: Option<usize>,
529
530    /// Maximum proportion of total peer weight to ignore in case of byzantine
531    /// behavior.
532    ///
533    /// If unspecified, this will default to 0.2.
534    #[serde(skip_serializing_if = "Option::is_none")]
535    pub max_ignored_peer_weight_factor: Option<f64>,
536}
537
538impl RandomnessConfig {
539    pub fn max_partial_sigs_rounds_ahead(&self) -> u64 {
540        const MAX_PARTIAL_SIGS_ROUNDS_AHEAD: u64 = 50;
541
542        self.max_partial_sigs_rounds_ahead
543            .unwrap_or(MAX_PARTIAL_SIGS_ROUNDS_AHEAD)
544    }
545
546    pub fn max_partial_sigs_concurrent_sends(&self) -> usize {
547        const MAX_PARTIAL_SIGS_CONCURRENT_SENDS: usize = 20;
548
549        self.max_partial_sigs_concurrent_sends
550            .unwrap_or(MAX_PARTIAL_SIGS_CONCURRENT_SENDS)
551    }
552    pub fn partial_signature_retry_interval(&self) -> Duration {
553        const PARTIAL_SIGNATURE_RETRY_INTERVAL: u64 = 5_000; // 5 seconds
554
555        Duration::from_millis(
556            self.partial_signature_retry_interval_ms
557                .unwrap_or(PARTIAL_SIGNATURE_RETRY_INTERVAL),
558        )
559    }
560
561    pub fn mailbox_capacity(&self) -> usize {
562        const MAILBOX_CAPACITY: usize = 1_000_000;
563
564        self.mailbox_capacity.unwrap_or(MAILBOX_CAPACITY)
565    }
566
567    pub fn send_partial_signatures_inflight_limit(&self) -> usize {
568        const SEND_PARTIAL_SIGNATURES_INFLIGHT_LIMIT: usize = 20;
569
570        self.send_partial_signatures_inflight_limit
571            .unwrap_or(SEND_PARTIAL_SIGNATURES_INFLIGHT_LIMIT)
572    }
573
574    pub fn max_ignored_peer_weight_factor(&self) -> f64 {
575        const MAX_IGNORED_PEER_WEIGHT_FACTOR: f64 = 0.2;
576
577        self.max_ignored_peer_weight_factor
578            .unwrap_or(MAX_IGNORED_PEER_WEIGHT_FACTOR)
579    }
580}