commonware_p2p/authenticated/lookup/config.rs
1use commonware_cryptography::Signer;
2use commonware_runtime::Quota;
3use commonware_utils::NZU32;
4use std::{net::SocketAddr, num::NonZeroU32, time::Duration};
5
6/// Configuration for the peer-to-peer instance.
7///
8/// # Warning
9/// It is recommended to synchronize this configuration across peers in the network (with the
10/// exception of `crypto`, `listen`, `allow_private_ips`, and `mailbox_size`).
11/// If this is not synchronized, connections could be unnecessarily dropped, messages could be parsed incorrectly,
12/// and/or peers will rate limit each other during normal operation.
13#[derive(Clone)]
14pub struct Config<C: Signer> {
15 /// Cryptographic primitives.
16 pub crypto: C,
17
18 /// Prefix for all signed messages to avoid replay attacks.
19 pub namespace: Vec<u8>,
20
21 /// Address to listen on.
22 pub listen: SocketAddr,
23
24 /// Whether or not to allow connections with private IP addresses.
25 pub allow_private_ips: bool,
26
27 /// Whether or not to allow DNS-based ingress addresses.
28 ///
29 /// When dialing a DNS-based address, the hostname is resolved and a random IP
30 /// is selected from the results (shuffled for each dial attempt).
31 pub allow_dns: bool,
32
33 /// Whether or not to skip IP verification for incoming connections
34 /// (allows known peers to connect from unknown IPs).
35 pub bypass_ip_check: bool,
36
37 /// Maximum size allowed for messages over any connection.
38 ///
39 /// The actual size of the network message will be higher due to overhead from the protocol;
40 /// this may include additional metadata, data from the codec, and/or cryptographic signatures.
41 pub max_message_size: u32,
42
43 /// Message backlog allowed for internal actors.
44 ///
45 /// When there are more messages in the mailbox than this value, any actor
46 /// sending a message will be blocked until the mailbox is processed.
47 pub mailbox_size: usize,
48
49 /// Time into the future that a timestamp can be and still be considered valid.
50 pub synchrony_bound: Duration,
51
52 /// Duration after which a handshake message is considered stale.
53 pub max_handshake_age: Duration,
54
55 /// Timeout for the handshake process.
56 ///
57 /// This is often set to some value less than the connection read timeout to prevent
58 /// unauthenticated peers from holding open connection.
59 pub handshake_timeout: Duration,
60
61 /// Quota for connection attempts per peer (incoming or outgoing).
62 pub allowed_connection_rate_per_peer: Quota,
63
64 /// Maximum number of concurrent handshake attempts allowed.
65 pub max_concurrent_handshakes: NonZeroU32,
66
67 /// Quota for handshake attempts originating from a single IP address.
68 ///
69 /// To cap the number of handshakes concurrently attempted for a single
70 /// IP, set this to [Config::handshake_timeout].
71 pub allowed_handshake_rate_per_ip: Quota,
72
73 /// Quota for handshake attempts originating from a single IP subnet.
74 pub allowed_handshake_rate_per_subnet: Quota,
75
76 /// Frequency at which we send ping messages to peers.
77 ///
78 /// This also determines the rate limit for incoming ping messages (one per half this
79 /// frequency to account for jitter).
80 pub ping_frequency: Duration,
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 /// Number of peer sets to track.
91 ///
92 /// We will attempt to maintain connections to peers stored
93 /// across all peer sets, not just the most recent. This allows
94 /// us to continue serving requests to peers that have recently
95 /// been evicted and/or to communicate with peers in a future
96 /// set (if we, for example, are trying to do a reshare of a threshold
97 /// key).
98 pub tracked_peer_sets: usize,
99
100 /// Duration after which a blocked peer is allowed to reconnect.
101 pub block_duration: Duration,
102}
103
104impl<C: Signer> Config<C> {
105 /// Generates a configuration with reasonable defaults for usage in production.
106 pub fn recommended(
107 crypto: C,
108 namespace: &[u8],
109 listen: SocketAddr,
110 max_message_size: u32,
111 ) -> Self {
112 Self {
113 crypto,
114 namespace: namespace.to_vec(),
115 listen,
116
117 allow_private_ips: false,
118 allow_dns: true,
119 bypass_ip_check: false,
120 max_message_size,
121 mailbox_size: 1_000,
122 synchrony_bound: Duration::from_secs(5),
123 max_handshake_age: Duration::from_secs(10),
124 handshake_timeout: Duration::from_secs(5),
125 allowed_connection_rate_per_peer: Quota::per_minute(NZU32!(1)),
126 max_concurrent_handshakes: NZU32!(512),
127 allowed_handshake_rate_per_ip: Quota::with_period(Duration::from_secs(5)).unwrap(), // 1 concurrent handshake per IP
128 allowed_handshake_rate_per_subnet: Quota::per_second(NZU32!(64)),
129 ping_frequency: Duration::from_secs(50),
130 dial_frequency: Duration::from_secs(1),
131 query_frequency: Duration::from_secs(60),
132 tracked_peer_sets: 4,
133 block_duration: Duration::from_hours(4),
134 }
135 }
136
137 /// Generates a configuration that minimizes peer discovery latency. This
138 /// can be useful when running local demos.
139 ///
140 /// # Warning
141 ///
142 /// It is not recommended to use this configuration in production.
143 pub fn local(crypto: C, namespace: &[u8], listen: SocketAddr, max_message_size: u32) -> Self {
144 Self {
145 crypto,
146 namespace: namespace.to_vec(),
147 listen,
148
149 allow_private_ips: true,
150 allow_dns: true,
151 bypass_ip_check: false,
152 max_message_size,
153 mailbox_size: 1_000,
154 synchrony_bound: Duration::from_secs(5),
155 max_handshake_age: Duration::from_secs(10),
156 handshake_timeout: Duration::from_secs(5),
157 allowed_connection_rate_per_peer: Quota::per_second(NZU32!(1)),
158 max_concurrent_handshakes: NZU32!(1_024),
159 allowed_handshake_rate_per_ip: Quota::per_second(NZU32!(16)), // 80 concurrent handshakes per IP
160 allowed_handshake_rate_per_subnet: Quota::per_second(NZU32!(128)),
161 ping_frequency: Duration::from_secs(5),
162 dial_frequency: Duration::from_millis(500),
163 query_frequency: Duration::from_secs(30),
164 tracked_peer_sets: 4,
165 block_duration: Duration::from_hours(1),
166 }
167 }
168
169 #[cfg(test)]
170 pub fn test(crypto: C, listen: SocketAddr, max_message_size: u32) -> Self {
171 Self {
172 crypto,
173 namespace: b"test_namespace".to_vec(),
174 listen,
175
176 allow_private_ips: true,
177 allow_dns: true,
178 bypass_ip_check: false,
179 max_message_size,
180 mailbox_size: 1_000,
181 synchrony_bound: Duration::from_secs(5),
182 max_handshake_age: Duration::from_secs(10),
183 handshake_timeout: Duration::from_secs(5),
184 allowed_connection_rate_per_peer: Quota::per_second(NZU32!(4)),
185 max_concurrent_handshakes: NZU32!(1_024),
186 allowed_handshake_rate_per_ip: Quota::per_second(NZU32!(128)), // 640 concurrent handshakes per IP
187 allowed_handshake_rate_per_subnet: Quota::per_second(NZU32!(256)),
188 ping_frequency: Duration::from_secs(1),
189 dial_frequency: Duration::from_millis(200),
190 query_frequency: Duration::from_secs(5),
191 tracked_peer_sets: 4,
192 block_duration: Duration::from_mins(1),
193 }
194 }
195}