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}