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