Skip to main content

zebra_network/
constants.rs

1//! Definitions of Zebra network constants, including:
2//! - network protocol versions,
3//! - network protocol user agents,
4//! - peer address limits,
5//! - peer connection limits, and
6//! - peer connection timeouts.
7
8use std::{collections::HashMap, time::Duration};
9
10use lazy_static::lazy_static;
11use regex::Regex;
12
13// TODO: should these constants be split into protocol also?
14use crate::protocol::external::types::*;
15
16use zebra_chain::{
17    parameters::{
18        Network::{self, *},
19        NetworkKind,
20        NetworkUpgrade::*,
21    },
22    serialization::Duration32,
23};
24
25/// A multiplier used to calculate the inbound connection limit for the peer set,
26///
27/// When it starts up, Zebra opens [`crate::Config::peerset_initial_target_size`]
28/// outbound connections.
29///
30/// Then it opens additional outbound connections as needed for network requests,
31/// and accepts inbound connections initiated by other peers.
32///
33/// The inbound and outbound connection limits are calculated from:
34///
35/// The inbound limit is:
36/// `crate::Config::peerset_initial_target_size * INBOUND_PEER_LIMIT_MULTIPLIER`.
37/// (This is similar to `zcashd`'s default inbound limit.)
38///
39/// The outbound limit is:
40/// `crate::Config::peerset_initial_target_size * OUTBOUND_PEER_LIMIT_MULTIPLIER`.
41/// (This is a bit larger than `zcashd`'s default outbound limit.)
42///
43/// # Security
44///
45/// Each connection requires one inbound slot and one outbound slot, on two different peers.
46/// But some peers only make outbound connections, because they are behind a firewall,
47/// or their lister port address is misconfigured.
48///
49/// Zebra allows extra inbound connection slots,
50/// to prevent accidental connection slot exhaustion.
51/// (`zcashd` also allows a large number of extra inbound slots.)
52///
53/// ## Security Tradeoff
54///
55/// Since the inbound peer limit is higher than the outbound peer limit,
56/// Zebra can be connected to a majority of peers
57/// that it has *not* chosen from its [`crate::AddressBook`].
58///
59/// Inbound peer connections are initiated by the remote peer,
60/// so inbound peer selection is not controlled by the local node.
61/// This means that an attacker can easily become a majority of a node's peers.
62///
63/// However, connection exhaustion is a higher priority.
64pub const INBOUND_PEER_LIMIT_MULTIPLIER: usize = 5;
65
66/// A multiplier used to calculate the outbound connection limit for the peer set,
67///
68/// See [`INBOUND_PEER_LIMIT_MULTIPLIER`] for details.
69pub const OUTBOUND_PEER_LIMIT_MULTIPLIER: usize = 3;
70
71/// The default maximum number of peer connections Zebra will keep for a given IP address
72/// before it drops any additional peer connections with that IP.
73///
74/// This will be used as `Config.max_connections_per_ip` if no valid value is provided.
75///
76/// Note: Zebra will currently avoid initiating outbound connections where it
77///       has recently had a successful handshake with any address
78///       on that IP. Zebra will not initiate more than 1 outbound connection
79///       to an IP based on the default configuration, but it will accept more inbound
80///       connections to an IP.
81pub const DEFAULT_MAX_CONNS_PER_IP: usize = 1;
82
83/// The default peerset target size.
84///
85/// This will be used as `Config.peerset_initial_target_size` if no valid value is provided.
86pub const DEFAULT_PEERSET_INITIAL_TARGET_SIZE: usize = 25;
87
88/// The maximum number of peers we will add to the address book after each `getaddr` request.
89pub const PEER_ADDR_RESPONSE_LIMIT: usize =
90    DEFAULT_PEERSET_INITIAL_TARGET_SIZE * OUTBOUND_PEER_LIMIT_MULTIPLIER / 2;
91
92/// The buffer size for the peer set.
93///
94/// This should be greater than 1 to avoid sender contention, but also reasonably
95/// small, to avoid queueing too many in-flight block downloads. (A large queue
96/// of in-flight block downloads can choke a constrained local network
97/// connection, or a small peer set on testnet.)
98///
99/// We assume that Zebra nodes have at least 10 Mbps bandwidth. Therefore, a
100/// maximum-sized block can take up to 2 seconds to download. So the peer set
101/// buffer adds up to 6 seconds worth of blocks to the queue.
102pub const PEERSET_BUFFER_SIZE: usize = 3;
103
104/// The timeout for sending a message to a remote peer,
105/// and receiving a response from a remote peer.
106pub const REQUEST_TIMEOUT: Duration = Duration::from_secs(20);
107
108/// The timeout for connections and handshakes when connecting to new peers.
109///
110/// Outbound TCP connections must complete within this timeout,
111/// then the handshake messages get an additional `HANDSHAKE_TIMEOUT` to complete.
112/// (Inbound TCP accepts can't have a timeout, because they are handled by the OS.)
113///
114/// This timeout should remain small, because it helps stop slow peers getting
115/// into the peer set. This is particularly important for network-constrained
116/// nodes, and on testnet.
117pub const HANDSHAKE_TIMEOUT: Duration = Duration::from_secs(3);
118
119/// The maximum time difference for two address book changes to be considered concurrent.
120///
121/// This prevents simultaneous or nearby important changes or connection progress
122/// being overridden by less important changes.
123///
124/// This timeout should be less than:
125/// - the [peer reconnection delay](MIN_PEER_RECONNECTION_DELAY), and
126/// - the [peer keepalive/heartbeat interval](HEARTBEAT_INTERVAL).
127///
128/// But more than:
129/// - the amount of time between connection events and address book updates,
130///   even under heavy load (in tests, we have observed delays up to 500ms),
131/// - the delay between an outbound connection failing,
132///   and [candidate selection](crate::peer_set::candidate_set) registering the failure, and
133/// - the delay between the application closing a connection,
134///   and any remaining positive changes from the peer.
135pub const CONCURRENT_ADDRESS_CHANGE_PERIOD: Duration = Duration::from_secs(5);
136
137/// We expect to receive a message from a live peer at least once in this time duration.
138///
139/// This is the sum of:
140/// - the interval between connection heartbeats
141/// - the timeout of a possible pending (already-sent) request
142/// - the timeout for a possible queued request
143/// - the timeout for the heartbeat request itself
144///
145/// This avoids explicit synchronization, but relies on the peer
146/// connector actually setting up channels and these heartbeats in a
147/// specific manner that matches up with this math.
148pub const MIN_PEER_RECONNECTION_DELAY: Duration = Duration::from_secs(59 + 20 + 20 + 20);
149
150/// Zebra rotates its peer inventory registry every time this interval elapses.
151///
152/// Available, missing, and failed inventory entries expire after two rotations. Delayed polling
153/// restarts this interval instead of replaying missed rotations.
154pub const INVENTORY_ROTATION_INTERVAL: Duration = Duration::from_secs(53);
155
156/// How long a single-hash [`Request::BlocksByHash`](crate::Request::BlocksByHash) waits for
157/// eligible busy capacity before returning a local refusal.
158///
159/// Sync and gossip downloaders use [`Request::BlockDownload`](crate::Request::BlockDownload)
160/// instead: capacity waits do not consume peer attempts, and the caller bounds the complete
161/// readiness and response operation. The connection's [`REQUEST_TIMEOUT`] starts at wire dispatch.
162pub const INVENTORY_BUSY_PEER_WAIT_TIMEOUT: Duration = Duration::from_millis(1500);
163
164/// How long a find-blocks or find-headers request waits for a busy serving peer before it can
165/// fall back to any ready peer.
166///
167/// This wait starts when the request enters the peer set and counts towards the syncer's
168/// six-second request timeout, leaving time for the fallback peer to respond.
169pub const FIND_BUSY_SERVING_PEER_WAIT_TIMEOUT: Duration = Duration::from_millis(1500);
170
171/// The default peer address crawler interval.
172///
173/// This should be at least [`HANDSHAKE_TIMEOUT`] lower than all other crawler
174/// intervals.
175///
176/// This makes the following sequence of events more likely:
177/// 1. a peer address crawl,
178/// 2. new peer connections,
179/// 3. peer requests from other crawlers.
180///
181/// Using a prime number makes sure that peer address crawls
182/// don't synchronise with other crawls.
183pub const DEFAULT_CRAWL_NEW_PEER_INTERVAL: Duration = Duration::from_secs(61);
184
185/// The peer address disk cache update interval.
186///
187/// This should be longer than [`DEFAULT_CRAWL_NEW_PEER_INTERVAL`],
188/// but shorter than [`MAX_PEER_ACTIVE_FOR_GOSSIP`].
189///
190/// We use a short interval so Zebra instances which are restarted frequently
191/// still have useful caches.
192pub const PEER_DISK_CACHE_UPDATE_INTERVAL: Duration = Duration::from_secs(5 * 60);
193
194/// The maximum number of addresses in the peer disk cache.
195///
196/// This is chosen to be less than the number of active peers,
197/// and approximately the same as the number of seed peers returned by DNS.
198/// It is a tradeoff between fingerprinting attacks, DNS pollution risk, and cache pollution risk.
199pub const MAX_PEER_DISK_CACHE_SIZE: usize = 75;
200
201/// The maximum duration since a peer was last seen to consider it reachable.
202///
203/// This is used to prevent Zebra from gossiping addresses that are likely unreachable. Peers that
204/// have last been seen more than this duration ago will not be gossiped.
205///
206/// This is determined as a tradeoff between network health and network view leakage. From the
207/// [Bitcoin protocol documentation](https://en.bitcoin.it/wiki/Protocol_documentation#getaddr):
208///
209/// "The typical presumption is that a node is likely to be active if it has been sending a message
210/// within the last three hours."
211pub const MAX_PEER_ACTIVE_FOR_GOSSIP: Duration32 = Duration32::from_hours(3);
212
213/// The maximum duration since a peer was last seen to consider reconnecting to it.
214///
215/// Peers that haven't been seen for more than three days and that had its last connection attempt
216/// fail are considered to be offline and Zebra will stop trying to connect to them.
217///
218/// This is to ensure that Zebra can't have a denial-of-service as a consequence of having too many
219/// offline peers that it constantly and uselessly retries to connect to.
220pub const MAX_RECENT_PEER_AGE: Duration32 = Duration32::from_days(3);
221
222/// Regular interval for sending keepalive `Ping` messages to each
223/// connected peer.
224///
225/// Using a prime number makes sure that heartbeats don't synchronise with crawls.
226pub const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(59);
227
228/// The minimum time between outbound peer connections, implemented by
229/// [`next_reconnect_peer`][crate::peer_set::candidate_set::next_reconnect_peer].
230///
231/// ## Security
232///
233/// Zebra resists distributed denial of service attacks by making sure that new outbound peer
234/// connections are only initiated after this minimum time has elapsed.
235///
236/// It also enforces a minimum per-peer reconnection interval, and filters failed outbound peers.
237pub const MIN_OUTBOUND_PEER_CONNECTION_INTERVAL: Duration = Duration::from_millis(100);
238
239/// The minimum time between _successful_ inbound peer connections, implemented by
240/// `peer_set::initialize::accept_inbound_connections`.
241///
242/// To support multiple peers connecting simultaneously, this is less than the
243/// [`HANDSHAKE_TIMEOUT`].
244///
245/// ## Security
246///
247/// Zebra resists distributed denial of service attacks by limiting the inbound connection rate.
248/// After a _successful_ inbound connection, new inbound peer connections are only accepted,
249/// and our side of the handshake initiated, after this minimum time has elapsed.
250///
251/// The inbound interval is much longer than the outbound interval, because Zebra does not
252/// control the selection or reconnections of inbound peers.
253pub const MIN_INBOUND_PEER_CONNECTION_INTERVAL: Duration = Duration::from_secs(1);
254
255/// The minimum time between _failed_ inbound peer connections, implemented by
256/// `peer_set::initialize::accept_inbound_connections`.
257///
258/// This is a tradeoff between:
259/// - the memory, CPU, and network usage of each new connection attempt, and
260/// - denying service to honest peers due to an attack which makes many inbound connections.
261///
262/// Attacks that reach this limit should be managed using a firewall or intrusion prevention system.
263///
264/// ## Security
265///
266/// Zebra resists distributed denial of service attacks by limiting the inbound connection rate.
267/// After a _failed_ inbound connection, new inbound peer connections are only accepted,
268/// and our side of the handshake initiated, after this minimum time has elapsed.
269pub const MIN_INBOUND_PEER_FAILED_CONNECTION_INTERVAL: Duration = Duration::from_millis(10);
270
271/// The minimum time between successive calls to
272/// [`crawl_once`][crate::peer_set::candidate_set::crawl_once].
273///
274/// Using a prime number makes sure that peer address crawls don't synchronise with other crawls.
275///
276/// ## Security
277///
278/// Zebra resists distributed denial of service attacks by making sure that requests for more
279/// peer addresses are sent at least [`MIN_PEER_GET_ADDR_INTERVAL`] apart.
280pub const MIN_PEER_GET_ADDR_INTERVAL: Duration = Duration::from_secs(31);
281
282/// The combined timeout for all the requests in
283/// [`crawl_once`][crate::peer_set::candidate_set::crawl_once].
284///
285/// `zcashd` doesn't respond to most `getaddr` requests,
286/// so this timeout needs to be short.
287pub const PEER_GET_ADDR_TIMEOUT: Duration = Duration::from_secs(8);
288
289/// The number of GetAddr requests sent when crawling for new peers.
290///
291/// # Security
292///
293/// The fanout should be greater than 2, so that Zebra avoids getting a majority
294/// of its initial address book entries from a single peer.
295///
296/// Zebra regularly crawls for new peers, initiating a new crawl every
297/// [`crawl_new_peer_interval`](crate::config::Config.crawl_new_peer_interval).
298///
299/// TODO: Restore the fanout to 3, once fanouts are limited to the number of ready peers (#2214)
300///
301/// In #3110, we changed the fanout to 1, to make sure we actually use cached address responses.
302/// With a fanout of 3, we were dropping a lot of responses, because the overall crawl timed out.
303pub const GET_ADDR_FANOUT: usize = 1;
304
305/// The maximum number of addresses allowed in an `addr` or `addrv2` message.
306///
307/// `addr`:
308/// > The number of IP address entries up to a maximum of 1,000.
309///
310/// <https://developer.bitcoin.org/reference/p2p_networking.html#addr>
311///
312/// `addrv2`:
313/// > One message can contain up to 1,000 addresses.
314/// > Clients MUST reject messages with more addresses.
315///
316/// <https://zips.z.cash/zip-0155#specification>
317pub const MAX_ADDRS_IN_MESSAGE: usize = 1000;
318
319/// The fraction of addresses Zebra sends in response to a `Peers` request.
320///
321/// Each response contains approximately:
322/// `address_book.len() / ADDR_RESPONSE_LIMIT_DENOMINATOR`
323/// addresses, selected at random from the address book.
324///
325/// # Security
326///
327/// This limit makes sure that Zebra does not reveal its entire address book
328/// in a single `Peers` response.
329///
330/// This is temporarily set to 2 (up from 4) to speed up peer discovery, so
331/// nodes can recover more quickly from network fragmentation. This reveals
332/// more of the address book to each requester, see #11103 for the tradeoff
333/// discussion and the follow-up conditions for reverting or replacing this
334/// value.
335pub const ADDR_RESPONSE_LIMIT_DENOMINATOR: usize = 2;
336
337/// The maximum number of addresses Zebra will keep in its address book.
338///
339/// This is a tradeoff between:
340/// - revealing the whole address book in a few requests,
341/// - sending the maximum number of peer addresses, and
342/// - making sure the limit code actually gets run.
343///
344/// This value is deliberately pinned rather than derived from
345/// [`ADDR_RESPONSE_LIMIT_DENOMINATOR`], so the temporary denominator change
346/// above does not shrink the address book (see #11103).
347pub const MAX_ADDRS_IN_ADDRESS_BOOK: usize = MAX_ADDRS_IN_MESSAGE * 5;
348
349/// Truncate timestamps in outbound address messages to this time interval.
350///
351/// ## SECURITY
352///
353/// Timestamp truncation prevents a peer from learning exactly when we received
354/// messages from each of our peers.
355pub const TIMESTAMP_TRUNCATION_SECONDS: u32 = 30 * 60;
356
357/// The Zcash network protocol version implemented by this crate, and advertised
358/// during connection setup.
359///
360/// The current protocol version is checked by our peers. If it is too old,
361/// newer peers will disconnect from us.
362///
363/// The current protocol version typically changes before Mainnet and Testnet
364/// network upgrades.
365///
366/// Advertise NU7 Testnet support; Mainnet's assigned version must wait for its activation schedule.
367/// See [ZIP 204](https://zips.z.cash/zip-0204#assigning-protocol-versions-to-network-upgrades).
368pub const CURRENT_NETWORK_PROTOCOL_VERSION: Version = Version(170_180);
369
370/// The default RTT estimate for peer responses.
371///
372/// We choose a high value for the default RTT, so that new peers must prove they
373/// are fast, before we prefer them to other peers. This is particularly
374/// important on testnet, which has a small number of peers, which are often
375/// slow.
376///
377/// Make the default RTT slightly higher than the request timeout.
378pub const EWMA_DEFAULT_RTT: Duration = Duration::from_secs(REQUEST_TIMEOUT.as_secs() + 1);
379
380/// The decay time for the EWMA response time metric used for load balancing.
381///
382/// This should be much larger than the `SYNC_RESTART_TIMEOUT`, so we choose
383/// better peers when we restart the sync.
384pub const EWMA_DECAY_TIME_NANOS: f64 = 200.0 * NANOS_PER_SECOND;
385
386/// The number of nanoseconds in one second.
387const NANOS_PER_SECOND: f64 = 1_000_000_000.0;
388
389/// The duration it takes for the drop probability of an overloaded connection to
390/// reach [`MIN_OVERLOAD_DROP_PROBABILITY`].
391///
392/// Peer connections that receive multiple overloads have a higher probability of being dropped.
393///
394/// The probability of a connection being dropped gradually decreases during this interval
395/// until it reaches the default drop probability ([`MIN_OVERLOAD_DROP_PROBABILITY`]).
396///
397/// Increasing this number increases the rate at which connections are dropped.
398pub const OVERLOAD_PROTECTION_INTERVAL: Duration = MIN_INBOUND_PEER_CONNECTION_INTERVAL;
399
400/// The minimum probability of dropping a peer connection when it receives an
401/// [`Overloaded`](crate::PeerError::Overloaded) error.
402pub const MIN_OVERLOAD_DROP_PROBABILITY: f32 = 0.05;
403
404/// The maximum probability of dropping a peer connection when it receives an
405/// [`Overloaded`](crate::PeerError::Overloaded) error.
406pub const MAX_OVERLOAD_DROP_PROBABILITY: f32 = 0.5;
407
408/// The minimum interval between logging peer set status updates.
409pub const MIN_PEER_SET_LOG_INTERVAL: Duration = Duration::from_secs(60);
410
411/// The misbehavior score that bans a peer group.
412pub const MAX_PEER_MISBEHAVIOR_SCORE: u32 = 100;
413
414/// The interval between flushes of batched peer misbehaviour updates into the address book.
415///
416/// Misbehaviour updates are batched so peers can't keep the address book mutex locked by
417/// repeatedly sending invalid blocks or transactions.
418#[cfg(not(test))]
419pub const MISBEHAVIOR_FLUSH_INTERVAL: Duration = Duration::from_secs(30);
420
421/// The interval between flushes of batched peer misbehaviour updates into the address book.
422///
423/// Tests use a much shorter interval, so that tests which wait for a misbehaviour update to
424/// turn into a ban don't have to wait for a production flush cycle.
425#[cfg(test)]
426pub const MISBEHAVIOR_FLUSH_INTERVAL: Duration = Duration::from_millis(100);
427
428/// The maximum number of banned IP addresses to be stored in-memory at any time.
429pub const MAX_BANNED_IPS: usize = 20_000;
430
431/// How long a peer group stays banned after reaching
432/// [`MAX_PEER_MISBEHAVIOR_SCORE`].
433///
434/// This matches `zcashd`'s and Bitcoin Core's `DEFAULT_MISBEHAVING_BANTIME`.
435///
436/// # Security
437///
438/// Bans must expire. A ban applies to a whole peer group, and an IPv6 `/64` can
439/// be shared by unrelated nodes at providers that allocate narrower prefixes per
440/// customer, so a permanent ban risks permanently isolating an honest peer.
441/// Expiry also bounds the damage from a misattributed score, at the cost of
442/// letting a genuinely malicious peer retry once the ban lapses — it is banned
443/// again as soon as it misbehaves again.
444pub const BAN_DURATION: Duration = Duration::from_secs(60 * 60 * 24);
445
446lazy_static! {
447    /// The minimum network protocol version accepted by this crate for each network,
448    /// represented as a network upgrade.
449    ///
450    /// The minimum protocol version is used to check the protocol versions of our
451    /// peers during the initial block download. After the initial block download,
452    /// we use the current block height to select the minimum network protocol
453    /// version.
454    ///
455    /// If peer versions are too old, we will disconnect from them.
456    ///
457    /// The minimum network protocol version typically changes after Mainnet and
458    /// Testnet network upgrades.
459    // TODO: Change `Nu6_2` to `Nu7` after NU7 activation.
460    // TODO: Move the value here to a field on `testnet::Parameters` (#8367)
461    pub static ref INITIAL_MIN_NETWORK_PROTOCOL_VERSION: HashMap<NetworkKind, Version> = {
462        let mut hash_map = HashMap::new();
463
464        hash_map.insert(NetworkKind::Mainnet, Version::min_specified_for_upgrade(&Mainnet, Nu6_2));
465        hash_map.insert(NetworkKind::Testnet, Version::min_specified_for_upgrade(&Network::new_default_testnet(), Nu6_2));
466        hash_map.insert(NetworkKind::Regtest, Version::min_specified_for_upgrade(&Network::new_regtest(Default::default()), Nu6_2));
467
468        hash_map
469    };
470
471    /// OS-specific error when the port attempting to be opened is already in use.
472    pub static ref PORT_IN_USE_ERROR: Regex = if cfg!(unix) {
473        #[allow(clippy::trivial_regex)]
474        Regex::new(&regex::escape("already in use"))
475    } else {
476        Regex::new("(access a socket in a way forbidden by its access permissions)|(Only one usage of each socket address)")
477    }.expect("regex is valid");
478}
479
480/// The timeout for DNS lookups.
481///
482/// [6.1.3.3 Efficient Resource Usage] from [RFC 1123: Requirements for Internet Hosts]
483/// suggest no less than 5 seconds for resolving timeout.
484///
485/// [RFC 1123: Requirements for Internet Hosts] <https://tools.ietf.org/rfcmarkup?doc=1123>
486/// [6.1.3.3  Efficient Resource Usage] <https://tools.ietf.org/rfcmarkup?doc=1123#page-77>
487pub const DNS_LOOKUP_TIMEOUT: Duration = Duration::from_secs(5);
488
489#[cfg(test)]
490mod tests {
491    use zebra_chain::parameters::POST_BLOSSOM_POW_TARGET_SPACING;
492
493    use super::*;
494
495    /// This assures that the `Duration` value we are computing for
496    /// [`MIN_PEER_RECONNECTION_DELAY`] actually matches the other const values
497    /// it relies on.
498    #[test]
499    fn ensure_live_peer_duration_value_matches_others() {
500        let _init_guard = zebra_test::init();
501
502        let constructed_live_peer_duration =
503            HEARTBEAT_INTERVAL + REQUEST_TIMEOUT + REQUEST_TIMEOUT + REQUEST_TIMEOUT;
504
505        assert_eq!(MIN_PEER_RECONNECTION_DELAY, constructed_live_peer_duration);
506    }
507
508    /// Make sure that the timeout values are consistent with each other.
509    #[test]
510    fn ensure_timeouts_consistent() {
511        let _init_guard = zebra_test::init();
512
513        assert!(HANDSHAKE_TIMEOUT <= REQUEST_TIMEOUT,
514                "Handshakes are requests, so the handshake timeout can't be longer than the timeout for all requests.");
515        // This check is particularly important on testnet, which has a small
516        // number of peers, which are often slow.
517        assert!(EWMA_DEFAULT_RTT > REQUEST_TIMEOUT,
518                "The default EWMA RTT should be higher than the request timeout, so new peers are required to prove they are fast, before we prefer them to other peers.");
519
520        let request_timeout_nanos = REQUEST_TIMEOUT.as_secs_f64()
521            + f64::from(REQUEST_TIMEOUT.subsec_nanos()) * NANOS_PER_SECOND;
522
523        assert!(EWMA_DECAY_TIME_NANOS > request_timeout_nanos,
524                "The EWMA decay time should be higher than the request timeout, so timed out peers are penalised by the EWMA.");
525
526        assert!(
527            MIN_PEER_RECONNECTION_DELAY.as_secs() as f32
528                / (u32::try_from(MAX_ADDRS_IN_ADDRESS_BOOK).expect("fits in u32")
529                    * MIN_OUTBOUND_PEER_CONNECTION_INTERVAL)
530                    .as_secs() as f32
531                >= 0.2,
532            "some peers should get a connection attempt in each connection interval",
533        );
534
535        assert!(
536            MIN_PEER_RECONNECTION_DELAY.as_secs() as f32
537                / (u32::try_from(MAX_ADDRS_IN_ADDRESS_BOOK).expect("fits in u32")
538                    * MIN_OUTBOUND_PEER_CONNECTION_INTERVAL)
539                    .as_secs() as f32
540                <= 2.0,
541            "each peer should only have a few connection attempts in each connection interval",
542        );
543    }
544
545    /// Make sure that peer age limits are consistent with each other.
546    #[test]
547    fn ensure_peer_age_limits_consistent() {
548        let _init_guard = zebra_test::init();
549
550        assert!(
551            MAX_PEER_ACTIVE_FOR_GOSSIP <= MAX_RECENT_PEER_AGE,
552            "we should only gossip peers we are actually willing to try ourselves"
553        );
554    }
555
556    /// Make sure the address limits are consistent with each other.
557    #[test]
558    #[allow(clippy::assertions_on_constants)]
559    fn ensure_address_limits_consistent() {
560        // Estimated network address book size in November 2023, after the address book limit was increased.
561        // Zebra 1.0.0-beta.2 address book metrics in December 2021 showed 4500 peers.
562        const TYPICAL_MAINNET_ADDRESS_BOOK_SIZE: usize = 5_500;
563
564        let _init_guard = zebra_test::init();
565
566        assert!(
567            MAX_ADDRS_IN_ADDRESS_BOOK >= GET_ADDR_FANOUT * MAX_ADDRS_IN_MESSAGE,
568            "the address book should hold at least a fanout's worth of addresses"
569        );
570
571        assert!(
572            MAX_ADDRS_IN_ADDRESS_BOOK / ADDR_RESPONSE_LIMIT_DENOMINATOR > MAX_ADDRS_IN_MESSAGE,
573            "the address book should hold enough addresses for a full response"
574        );
575
576        assert!(
577            MAX_ADDRS_IN_ADDRESS_BOOK <= TYPICAL_MAINNET_ADDRESS_BOOK_SIZE,
578            "the address book limit should actually be used"
579        );
580    }
581
582    /// Make sure inventory registry rotation is consistent with the target block interval.
583    #[test]
584    fn ensure_inventory_rotation_consistent() {
585        let _init_guard = zebra_test::init();
586
587        assert!(
588            INVENTORY_ROTATION_INTERVAL
589                < Duration::from_secs(POST_BLOSSOM_POW_TARGET_SPACING.into()),
590            "we should expire inventory every time 1-2 new blocks get generated"
591        );
592    }
593}