Skip to main content

commonware_p2p/authenticated/discovery/
config.rs

1use crate::Ingress;
2use commonware_cryptography::Signer;
3use commonware_runtime::Quota;
4use commonware_utils::{NZUsize, NZU32};
5use std::{
6    net::SocketAddr,
7    num::{NonZeroU32, NonZeroUsize},
8    time::Duration,
9};
10
11/// Known peer and its accompanying ingress address that will be dialed on startup.
12pub type Bootstrapper<P> = (P, Ingress);
13
14/// Configuration for the peer-to-peer instance.
15///
16/// # Warning
17/// It is recommended to synchronize this configuration across peers in the network (with the
18/// exception of `crypto`, `listen`, `bootstrappers`, `allow_private_ips`, `mailbox_size`, and
19/// `send_batch_size`).
20/// If this is not synchronized, connections could be unnecessarily dropped, messages could be parsed incorrectly,
21/// and/or peers will rate limit each other during normal operation.
22#[derive(Clone)]
23pub struct Config<C: Signer> {
24    /// Cryptographic primitives.
25    pub crypto: C,
26
27    /// Prefix for all signed messages to avoid replay attacks.
28    pub namespace: Vec<u8>,
29
30    /// Address to listen on.
31    pub listen: SocketAddr,
32
33    /// Dialable ingress address of the peer.
34    pub dialable: Ingress,
35
36    /// Peers dialed on startup.
37    pub bootstrappers: Vec<Bootstrapper<C::PublicKey>>,
38
39    /// Whether or not to allow DNS-based ingress addresses.
40    ///
41    /// When dialing a DNS-based address, the hostname is resolved and a random IP
42    /// is selected from the results (shuffled for each dial attempt).
43    pub allow_dns: bool,
44
45    /// Whether or not to allow connections with private IP addresses.
46    pub allow_private_ips: bool,
47
48    /// Maximum size allowed for messages over any connection.
49    ///
50    /// The actual size of the network message will be higher due to overhead from the protocol;
51    /// this may include additional metadata, data from the codec, and/or cryptographic signatures.
52    pub max_message_size: u32,
53
54    /// Message backlog allowed for internal actors.
55    ///
56    /// When there are more messages in a mailbox than this value, messages may be rejected before
57    /// they are processed. Refer to [`commonware_actor::Feedback`] and/or metrics on
58    /// [`commonware_actor::mailbox`] for a signal this is occurring.
59    pub mailbox_size: NonZeroUsize,
60
61    /// Maximum number of already-queued outbound messages to combine into one connection write.
62    ///
63    /// Set this to `1` to disable batching.
64    pub send_batch_size: NonZeroUsize,
65
66    /// Time into the future that a timestamp can be and still be considered valid.
67    pub synchrony_bound: Duration,
68
69    /// Duration after which a handshake message is considered stale.
70    pub max_handshake_age: Duration,
71
72    /// Timeout for the handshake process.
73    ///
74    /// This is often set to some value less than the connection read timeout to prevent
75    /// unauthenticated peers from holding open connection.
76    pub handshake_timeout: Duration,
77
78    /// Minimum time between connection reservations for a single peer.
79    pub peer_connection_cooldown: Duration,
80
81    /// Maximum number of concurrent handshake attempts allowed.
82    pub max_concurrent_handshakes: NonZeroU32,
83
84    /// Quota for handshake attempts originating from a single IP address.
85    ///
86    /// To cap the number of handshakes concurrently attempted for a single
87    /// IP, set this to [Config::handshake_timeout].
88    pub allowed_handshake_rate_per_ip: Quota,
89
90    /// Quota for handshake attempts originating from a single IP subnet.
91    pub allowed_handshake_rate_per_subnet: Quota,
92
93    /// Average frequency at which we make a single dial attempt across all peers.
94    pub dial_frequency: Duration,
95
96    /// Times that dialing a given peer should fail before asking for updated peer information for
97    /// that peer.
98    pub dial_fail_limit: usize,
99
100    /// Number of peer sets to track.
101    ///
102    /// We will attempt to maintain connections to peers stored
103    /// across all peer sets, not just the most recent. This allows
104    /// us to continue serving requests to peers that have recently
105    /// been evicted and/or to communicate with peers in a future
106    /// set (if we, for example, are trying to do a reshare of a threshold
107    /// key).
108    pub tracked_peer_sets: NonZeroUsize,
109
110    /// Maximum number of peers to track in a single peer set.
111    ///
112    /// This is used to limit the size of the bit vec messages, which will take one bit per peer in
113    /// the set. This number can be set to a reasonably high value that we never expect to reach.
114    pub max_peer_set_size: u64,
115
116    /// Frequency we gossip about known peers.
117    ///
118    /// If there is no other network activity, this message is used as a ping
119    /// and should be sent more often than the read_timeout.
120    ///
121    /// This also determines the rate limit for incoming BitVec and Peers messages
122    /// (one per half this frequency to account for jitter).
123    pub gossip_bit_vec_frequency: Duration,
124
125    /// Maximum number of peers we will send or consider valid when receiving in a single message.
126    ///
127    /// This is used to prevent malicious peers from sending us a large number of peers at one time (each
128    /// of which requires a signature verification).
129    pub peer_gossip_max_count: usize,
130
131    /// Duration after which a blocked peer is allowed to reconnect.
132    pub block_duration: Duration,
133}
134
135impl<C: Signer> Config<C> {
136    /// Generates a configuration with reasonable defaults for usage in production.
137    pub fn recommended(
138        crypto: C,
139        namespace: &[u8],
140        listen: SocketAddr,
141        dialable: impl Into<Ingress>,
142        bootstrappers: Vec<Bootstrapper<C::PublicKey>>,
143        max_message_size: u32,
144    ) -> Self {
145        Self {
146            crypto,
147            namespace: namespace.to_vec(),
148            listen,
149            dialable: dialable.into(),
150            bootstrappers,
151            allow_dns: true,
152
153            allow_private_ips: false,
154            max_message_size,
155            mailbox_size: NZUsize!(1_000),
156            send_batch_size: NZUsize!(8),
157            synchrony_bound: Duration::from_secs(5),
158            max_handshake_age: Duration::from_secs(10),
159            handshake_timeout: Duration::from_secs(5),
160            peer_connection_cooldown: Duration::from_secs(60),
161            max_concurrent_handshakes: NZU32!(512),
162            allowed_handshake_rate_per_ip: Quota::with_period(Duration::from_secs(5)).unwrap(), // 1 concurrent handshake per IP
163            allowed_handshake_rate_per_subnet: Quota::per_second(NZU32!(64)),
164            dial_frequency: Duration::from_secs(1),
165            dial_fail_limit: 2,
166            tracked_peer_sets: NZUsize!(4),
167            max_peer_set_size: 1 << 16, // 2^16
168            gossip_bit_vec_frequency: Duration::from_secs(50),
169            peer_gossip_max_count: 32,
170            block_duration: Duration::from_hours(4),
171        }
172    }
173
174    /// Generates a configuration that minimizes peer discovery latency. This
175    /// can be useful when running local demos.
176    ///
177    /// # Warning
178    ///
179    /// It is not recommended to use this configuration in production.
180    pub fn local(
181        crypto: C,
182        namespace: &[u8],
183        listen: SocketAddr,
184        dialable: impl Into<Ingress>,
185        bootstrappers: Vec<Bootstrapper<C::PublicKey>>,
186        max_message_size: u32,
187    ) -> Self {
188        Self {
189            crypto,
190            namespace: namespace.to_vec(),
191            listen,
192            dialable: dialable.into(),
193            bootstrappers,
194            allow_dns: true,
195
196            allow_private_ips: true,
197            max_message_size,
198            mailbox_size: NZUsize!(1_000),
199            send_batch_size: NZUsize!(8),
200            synchrony_bound: Duration::from_secs(5),
201            max_handshake_age: Duration::from_secs(10),
202            handshake_timeout: Duration::from_secs(5),
203            peer_connection_cooldown: Duration::from_secs(1),
204            max_concurrent_handshakes: NZU32!(1_024),
205            allowed_handshake_rate_per_ip: Quota::per_second(NZU32!(16)), // 80 concurrent handshakes per IP
206            allowed_handshake_rate_per_subnet: Quota::per_second(NZU32!(128)),
207            dial_frequency: Duration::from_millis(500),
208            dial_fail_limit: 1,
209            tracked_peer_sets: NZUsize!(4),
210            max_peer_set_size: 1 << 16, // 2^16
211            gossip_bit_vec_frequency: Duration::from_secs(5),
212            peer_gossip_max_count: 32,
213            block_duration: Duration::from_hours(1),
214        }
215    }
216
217    #[cfg(test)]
218    pub fn test(
219        crypto: C,
220        listen: SocketAddr,
221        bootstrappers: Vec<Bootstrapper<C::PublicKey>>,
222        max_message_size: u32,
223    ) -> Self {
224        Self {
225            crypto,
226            namespace: b"test_namespace".to_vec(),
227            listen,
228            dialable: listen.into(),
229            bootstrappers,
230            allow_dns: true,
231
232            allow_private_ips: true,
233            max_message_size,
234            mailbox_size: NZUsize!(1_000),
235            send_batch_size: NZUsize!(8),
236            synchrony_bound: Duration::from_secs(5),
237            max_handshake_age: Duration::from_secs(10),
238            handshake_timeout: Duration::from_secs(5),
239            peer_connection_cooldown: Duration::from_millis(250),
240            max_concurrent_handshakes: NZU32!(1_024),
241            allowed_handshake_rate_per_ip: Quota::per_second(NZU32!(128)), // 640 concurrent handshakes per IP
242            allowed_handshake_rate_per_subnet: Quota::per_second(NZU32!(256)),
243            dial_frequency: Duration::from_millis(200),
244            dial_fail_limit: 1,
245            tracked_peer_sets: NZUsize!(4),
246            max_peer_set_size: 1 << 8, // 2^8
247            gossip_bit_vec_frequency: Duration::from_secs(1),
248            peer_gossip_max_count: 32,
249            block_duration: Duration::from_mins(1),
250        }
251    }
252}