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 the mailbox than this value, any actor
57 /// sending a message will be blocked until the mailbox is processed.
58 pub mailbox_size: usize,
59
60 /// Maximum number of already-queued outbound messages to combine into one connection write.
61 ///
62 /// Set this to `1` to disable batching.
63 pub send_batch_size: NonZeroUsize,
64
65 /// Time into the future that a timestamp can be and still be considered valid.
66 pub synchrony_bound: Duration,
67
68 /// Duration after which a handshake message is considered stale.
69 pub max_handshake_age: Duration,
70
71 /// Timeout for the handshake process.
72 ///
73 /// This is often set to some value less than the connection read timeout to prevent
74 /// unauthenticated peers from holding open connection.
75 pub handshake_timeout: Duration,
76
77 /// Minimum time between connection reservations for a single peer.
78 pub peer_connection_cooldown: Duration,
79
80 /// Maximum number of concurrent handshake attempts allowed.
81 pub max_concurrent_handshakes: NonZeroU32,
82
83 /// Quota for handshake attempts originating from a single IP address.
84 ///
85 /// To cap the number of handshakes concurrently attempted for a single
86 /// IP, set this to [Config::handshake_timeout].
87 pub allowed_handshake_rate_per_ip: Quota,
88
89 /// Quota for handshake attempts originating from a single IP subnet.
90 pub allowed_handshake_rate_per_subnet: Quota,
91
92 /// Average frequency at which we make a single dial attempt across all peers.
93 pub dial_frequency: Duration,
94
95 /// Times that dialing a given peer should fail before asking for updated peer information for
96 /// that peer.
97 pub dial_fail_limit: usize,
98
99 /// Number of peer sets to track.
100 ///
101 /// We will attempt to maintain connections to peers stored
102 /// across all peer sets, not just the most recent. This allows
103 /// us to continue serving requests to peers that have recently
104 /// been evicted and/or to communicate with peers in a future
105 /// set (if we, for example, are trying to do a reshare of a threshold
106 /// key).
107 pub tracked_peer_sets: NonZeroUsize,
108
109 /// Maximum number of peers to track in a single peer set.
110 ///
111 /// This is used to limit the size of the bit vec messages, which will take one bit per peer in
112 /// the set. This number can be set to a reasonably high value that we never expect to reach.
113 pub max_peer_set_size: u64,
114
115 /// Frequency we gossip about known peers.
116 ///
117 /// If there is no other network activity, this message is used as a ping
118 /// and should be sent more often than the read_timeout.
119 ///
120 /// This also determines the rate limit for incoming BitVec and Peers messages
121 /// (one per half this frequency to account for jitter).
122 pub gossip_bit_vec_frequency: Duration,
123
124 /// Maximum number of peers we will send or consider valid when receiving in a single message.
125 ///
126 /// This is used to prevent malicious peers from sending us a large number of peers at one time (each
127 /// of which requires a signature verification).
128 pub peer_gossip_max_count: usize,
129
130 /// Duration after which a blocked peer is allowed to reconnect.
131 pub block_duration: Duration,
132}
133
134impl<C: Signer> Config<C> {
135 /// Generates a configuration with reasonable defaults for usage in production.
136 pub fn recommended(
137 crypto: C,
138 namespace: &[u8],
139 listen: SocketAddr,
140 dialable: impl Into<Ingress>,
141 bootstrappers: Vec<Bootstrapper<C::PublicKey>>,
142 max_message_size: u32,
143 ) -> Self {
144 Self {
145 crypto,
146 namespace: namespace.to_vec(),
147 listen,
148 dialable: dialable.into(),
149 bootstrappers,
150 allow_dns: true,
151
152 allow_private_ips: false,
153 max_message_size,
154 mailbox_size: 1_000,
155 send_batch_size: NZUsize!(8),
156 synchrony_bound: Duration::from_secs(5),
157 max_handshake_age: Duration::from_secs(10),
158 handshake_timeout: Duration::from_secs(5),
159 peer_connection_cooldown: Duration::from_secs(60),
160 max_concurrent_handshakes: NZU32!(512),
161 allowed_handshake_rate_per_ip: Quota::with_period(Duration::from_secs(5)).unwrap(), // 1 concurrent handshake per IP
162 allowed_handshake_rate_per_subnet: Quota::per_second(NZU32!(64)),
163 dial_frequency: Duration::from_secs(1),
164 dial_fail_limit: 2,
165 tracked_peer_sets: NZUsize!(4),
166 max_peer_set_size: 1 << 16, // 2^16
167 gossip_bit_vec_frequency: Duration::from_secs(50),
168 peer_gossip_max_count: 32,
169 block_duration: Duration::from_hours(4),
170 }
171 }
172
173 /// Generates a configuration that minimizes peer discovery latency. This
174 /// can be useful when running local demos.
175 ///
176 /// # Warning
177 ///
178 /// It is not recommended to use this configuration in production.
179 pub fn local(
180 crypto: C,
181 namespace: &[u8],
182 listen: SocketAddr,
183 dialable: impl Into<Ingress>,
184 bootstrappers: Vec<Bootstrapper<C::PublicKey>>,
185 max_message_size: u32,
186 ) -> Self {
187 Self {
188 crypto,
189 namespace: namespace.to_vec(),
190 listen,
191 dialable: dialable.into(),
192 bootstrappers,
193 allow_dns: true,
194
195 allow_private_ips: true,
196 max_message_size,
197 mailbox_size: 1_000,
198 send_batch_size: NZUsize!(8),
199 synchrony_bound: Duration::from_secs(5),
200 max_handshake_age: Duration::from_secs(10),
201 handshake_timeout: Duration::from_secs(5),
202 peer_connection_cooldown: Duration::from_secs(1),
203 max_concurrent_handshakes: NZU32!(1_024),
204 allowed_handshake_rate_per_ip: Quota::per_second(NZU32!(16)), // 80 concurrent handshakes per IP
205 allowed_handshake_rate_per_subnet: Quota::per_second(NZU32!(128)),
206 dial_frequency: Duration::from_millis(500),
207 dial_fail_limit: 1,
208 tracked_peer_sets: NZUsize!(4),
209 max_peer_set_size: 1 << 16, // 2^16
210 gossip_bit_vec_frequency: Duration::from_secs(5),
211 peer_gossip_max_count: 32,
212 block_duration: Duration::from_hours(1),
213 }
214 }
215
216 #[cfg(test)]
217 pub fn test(
218 crypto: C,
219 listen: SocketAddr,
220 bootstrappers: Vec<Bootstrapper<C::PublicKey>>,
221 max_message_size: u32,
222 ) -> Self {
223 Self {
224 crypto,
225 namespace: b"test_namespace".to_vec(),
226 listen,
227 dialable: listen.into(),
228 bootstrappers,
229 allow_dns: true,
230
231 allow_private_ips: true,
232 max_message_size,
233 mailbox_size: 1_000,
234 send_batch_size: NZUsize!(8),
235 synchrony_bound: Duration::from_secs(5),
236 max_handshake_age: Duration::from_secs(10),
237 handshake_timeout: Duration::from_secs(5),
238 peer_connection_cooldown: Duration::from_millis(250),
239 max_concurrent_handshakes: NZU32!(1_024),
240 allowed_handshake_rate_per_ip: Quota::per_second(NZU32!(128)), // 640 concurrent handshakes per IP
241 allowed_handshake_rate_per_subnet: Quota::per_second(NZU32!(256)),
242 dial_frequency: Duration::from_millis(200),
243 dial_fail_limit: 1,
244 tracked_peer_sets: NZUsize!(4),
245 max_peer_set_size: 1 << 8, // 2^8
246 gossip_bit_vec_frequency: Duration::from_secs(1),
247 peer_gossip_max_count: 32,
248 block_duration: Duration::from_mins(1),
249 }
250 }
251}