cuprated/config/p2p.rs
1use std::{
2 cmp::min,
3 net::{Ipv4Addr, Ipv6Addr, SocketAddr},
4 path::Path,
5 time::Duration,
6};
7
8use serde::{Deserialize, Serialize};
9
10use cuprate_helper::{cast::u64_to_usize, fs::address_book_path, network::Network};
11use cuprate_p2p::config::TransportConfig;
12use cuprate_p2p_core::{
13 transports::{Tcp, TcpServerConfig},
14 ClearNet, NetworkZone,
15};
16use cuprate_wire::OnionAddr;
17
18use super::{default::DefaultOrCustom, macros::config_struct};
19use crate::p2p::ProxySettings;
20
21config_struct! {
22 /// P2P config.
23 #[derive(Debug, Default, Deserialize, Serialize, PartialEq)]
24 #[serde(deny_unknown_fields, default)]
25 pub struct P2PConfig {
26 #[child = true]
27 /// The clear-net P2P config.
28 pub clear_net: ClearNetConfig,
29
30 #[child = true]
31 /// The tor-net P2P config.
32 pub tor_net: TorNetConfig,
33
34 #[child = true]
35 /// Block downloader config.
36 ///
37 /// The block downloader handles downloading old blocks from peers when we are behind.
38 pub block_downloader: BlockDownloaderConfig,
39 }
40}
41
42config_struct! {
43 #[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)]
44 #[serde(deny_unknown_fields, default)]
45 pub struct BlockDownloaderConfig {
46 #[comment_out = true]
47 /// The size in bytes of the buffer between the block downloader
48 /// and the place which is consuming the downloaded blocks (`cuprated`).
49 ///
50 /// This value is an absolute maximum,
51 /// once this is reached the block downloader will pause.
52 ///
53 /// Type | Number
54 /// Valid values | >= 0
55 /// Examples | 1_000_000_000, 5_500_000_000, 500_000_000
56 pub buffer_bytes: DefaultOrCustom<usize>,
57
58 #[comment_out = true]
59 /// The size of the in progress queue (in bytes)
60 /// at which cuprated stops requesting more blocks.
61 ///
62 /// The value is _NOT_ an absolute maximum,
63 /// the in-progress queue could get much larger.
64 /// This value is only the value cuprated stops requesting more blocks,
65 /// if cuprated still has requests in progress,
66 /// it will still accept the response and add the blocks to the queue.
67 ///
68 /// Type | Number
69 /// Valid values | >= 0
70 /// Examples | 500_000_000, 1_000_000_000,
71 pub in_progress_queue_bytes: DefaultOrCustom<usize>,
72
73 #[inline = true]
74 /// The duration between checking the client pool for free peers.
75 ///
76 /// Type | Duration
77 /// Examples | { secs = 30, nanos = 0 }, { secs = 35, nano = 123 }
78 pub check_client_pool_interval: Duration,
79
80 #[comment_out = true]
81 /// The target size of a single batch of blocks (in bytes).
82 ///
83 /// This value must be below 100_000,000,
84 /// it is not recommended to set it above 30_000_000.
85 ///
86 /// Type | Number
87 /// Valid values | 0..100_000,000
88 pub target_batch_bytes: usize,
89 }
90}
91
92impl BlockDownloaderConfig {
93 /// Constructs the config given to the p2p crate.
94 pub fn construct_inner(
95 &self,
96 total_memory: u64,
97 ) -> cuprate_p2p::block_downloader::BlockDownloaderConfig {
98 let buffer_mem = u64_to_usize(min(total_memory / 5, 1024 * 1024 * 1024));
99
100 cuprate_p2p::block_downloader::BlockDownloaderConfig {
101 buffer_bytes: *self.buffer_bytes.value(&buffer_mem),
102 in_progress_queue_bytes: *self.in_progress_queue_bytes.value(&(buffer_mem / 2)),
103 check_client_pool_interval: self.check_client_pool_interval,
104 target_batch_bytes: self.target_batch_bytes,
105 initial_batch_len: 1,
106 }
107 }
108}
109
110impl Default for BlockDownloaderConfig {
111 fn default() -> Self {
112 Self {
113 buffer_bytes: DefaultOrCustom::Default,
114 in_progress_queue_bytes: DefaultOrCustom::Default,
115 check_client_pool_interval: Duration::from_secs(30),
116 target_batch_bytes: 15_000_000,
117 }
118 }
119}
120
121config_struct! {
122 Shared {
123 #[comment_out = true]
124 /// The number of outbound connections to make and try keep.
125 ///
126 /// It's recommended to keep this value above 12.
127 ///
128 /// Type | Number
129 /// Valid values | >= 0
130 /// Examples | 12, 32, 64, 100, 500
131 pub outbound_connections: usize,
132
133 #[comment_out = true]
134 /// The amount of extra connections to make if cuprated is under load.
135 ///
136 /// Type | Number
137 /// Valid values | >= 0
138 /// Examples | 0, 12, 32, 64, 100, 500
139 pub extra_outbound_connections: usize,
140
141 #[comment_out = true]
142 /// The maximum amount of inbound connections to allow.
143 ///
144 /// Type | Number
145 /// Valid values | >= 0
146 /// Examples | 0, 12, 32, 64, 100, 500
147 pub max_inbound_connections: usize,
148
149 #[comment_out = true]
150 /// The percent of connections that should be
151 /// to peers that haven't connected to before.
152 ///
153 /// 0.0 is 0%.
154 /// 1.0 is 100%.
155 ///
156 /// Type | Floating point number
157 /// Valid values | 0.0..1.0
158 /// Examples | 0.0, 0.5, 0.123, 0.999, 1.0
159 pub gray_peers_percent: f64,
160
161 /// The port bind to this network zone.
162 ///
163 /// This port will be bind to if the incoming P2P
164 /// server for this zone has been enabled.
165 ///
166 /// Type | Number or "Default"
167 /// Valid values | 0..65534, "Default"
168 /// Examples | 18080, 9999, 5432
169 pub p2p_port: DefaultOrCustom<u16>,
170
171 #[child = true]
172 /// The address book config.
173 pub address_book_config: AddressBookConfig,
174 }
175
176 /// The config values for P2P clear-net.
177 #[derive(Debug, Deserialize, Serialize, PartialEq)]
178 #[serde(deny_unknown_fields, default)]
179 pub struct ClearNetConfig {
180
181 /// Enable IPv4 inbound server.
182 ///
183 /// The inbound server will listen on port `p2p.clear_net.p2p_port`.
184 /// Setting this to `false` will disable incoming IPv4 P2P connections.
185 ///
186 /// Type | boolean
187 /// Valid values | false, true
188 /// Examples | false
189 pub enable_inbound: bool,
190
191 /// The IPv4 address to bind and listen for connections on.
192 ///
193 /// Type | IPv4 address
194 /// Examples | "0.0.0.0", "192.168.1.50"
195 pub listen_on: Ipv4Addr,
196
197 /// Enable IPv6 inbound server.
198 ///
199 /// The inbound server will listen on port `p2p.clear_net.p2p_port`.
200 /// Setting this to `false` will disable incoming IPv6 P2P connections.
201 ///
202 /// Type | boolean
203 /// Valid values | false, true
204 /// Examples | false
205 pub enable_inbound_v6: bool,
206
207 /// The IPv6 address to bind and listen for connections on.
208 ///
209 /// Type | IPv6 address
210 /// Examples | "::", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
211 pub listen_on_v6: Ipv6Addr,
212
213 #[comment_out = true]
214 /// The proxy to use for outgoing P2P connections
215 ///
216 /// Setting this to "Tor" will anonymise clearnet connections through Tor.
217 ///
218 /// Setting this to "" (an empty string) will disable the proxy.
219 ///
220 /// Enabling this setting will disable inbound connections.
221 ///
222 /// Type | String
223 /// Valid values | "Tor", "socks5://ip:port", "socks5://user:pass@ip:port"
224 /// Examples | "Tor", "socks5://127.0.0.1:9050"
225 pub proxy: ProxySettings,
226
227 #[comment_out = true]
228 /// Extra seed nodes to connect to on startup, in addition to the
229 /// network's built-in seeds. Given as "ip:port" socket addresses.
230 ///
231 /// FakeChain/regtest ships no built-in seeds, so a private or isolated
232 /// network relies entirely on this list to bootstrap.
233 ///
234 /// Type | Array of socket addresses
235 /// Examples | "1.2.3.4:18080", "5.6.7.8:18080"
236 pub seed_nodes: Vec<SocketAddr>,
237 }
238
239 /// The config values for P2P tor.
240 #[derive(Debug, Deserialize, Serialize, PartialEq)]
241 #[serde(deny_unknown_fields, default)]
242 pub struct TorNetConfig {
243
244 #[comment_out = true]
245 /// Enable the Tor P2P network.
246 ///
247 /// Type | boolean
248 /// Valid values | false, true
249 /// Examples | false
250 pub enabled: bool,
251
252 #[comment_out = true]
253 /// Enable Tor inbound onion server.
254 ///
255 /// In Arti mode, setting this to `true` will enable Arti's onion service for accepting inbound
256 /// Tor P2P connections. The keypair and therefore onion address is generated randomly on first run.
257 ///
258 /// In Daemon mode, setting this to `true` will enable a TCP server listening for inbound connections
259 /// from your Tor daemon. Refer to the `tor.anonymous_inbound` and `tor.listening_addr` field for onion address
260 /// and listening configuration.
261 ///
262 /// The server will listen on port `p2p.tor_net.p2p_port`
263 ///
264 /// Type | boolean
265 /// Valid values | false, true
266 /// Examples | false
267 pub inbound_onion: bool,
268
269 #[comment_out = true]
270 /// Extra Tor seed nodes to connect to on startup, in addition to the
271 /// built-in seeds. Given as onion addresses.
272 ///
273 /// Type | Array of onion addresses
274 /// Examples | "zbjkbsxc5munw3qusl7j2hpcmikhqocdf4pqhnhtpzw5nt5jrmofptid.onion:18083"
275 pub seed_nodes: Vec<OnionAddr>,
276 }
277}
278
279/// Gets the port to listen on for p2p connections.
280pub const fn p2p_port(setting: DefaultOrCustom<u16>, network: Network) -> u16 {
281 match setting {
282 DefaultOrCustom::Default => match network {
283 Network::Mainnet | Network::FakeChain => 18080,
284 Network::Stagenet => 38080,
285 Network::Testnet => 28080,
286 },
287 DefaultOrCustom::Custom(port) => port,
288 }
289}
290
291impl ClearNetConfig {
292 /// Gets the transport config for [`ClearNet`] over [`Tcp`].
293 pub fn tcp_transport_config(&self, network: Network) -> TransportConfig<ClearNet, Tcp> {
294 let server_config = if self.enable_inbound {
295 let mut sc = TcpServerConfig::default();
296 sc.ipv4 = Some(self.listen_on);
297 sc.ipv6 = self.enable_inbound_v6.then_some(self.listen_on_v6);
298 sc.port = p2p_port(self.p2p_port, network);
299 Some(sc)
300 } else {
301 None
302 };
303
304 TransportConfig {
305 client_config: (),
306 server_config,
307 }
308 }
309}
310
311impl Default for ClearNetConfig {
312 fn default() -> Self {
313 Self {
314 p2p_port: DefaultOrCustom::Default,
315 enable_inbound: true,
316 listen_on: Ipv4Addr::UNSPECIFIED,
317 enable_inbound_v6: false,
318 listen_on_v6: Ipv6Addr::UNSPECIFIED,
319 proxy: ProxySettings::Disabled,
320 seed_nodes: Vec::new(),
321 outbound_connections: 32,
322 extra_outbound_connections: 8,
323 max_inbound_connections: 128,
324 gray_peers_percent: 0.3,
325 address_book_config: AddressBookConfig::default(),
326 }
327 }
328}
329
330impl Default for TorNetConfig {
331 fn default() -> Self {
332 Self {
333 enabled: false,
334 inbound_onion: false,
335 seed_nodes: Vec::new(),
336 p2p_port: DefaultOrCustom::Default,
337 outbound_connections: 12,
338 extra_outbound_connections: 2,
339 max_inbound_connections: 128,
340 gray_peers_percent: 0.3,
341 address_book_config: AddressBookConfig::default(),
342 }
343 }
344}
345
346config_struct! {
347 /// The addressbook config exposed to users.
348 #[derive(Debug, Deserialize, Serialize, Eq, PartialEq)]
349 #[serde(deny_unknown_fields, default)]
350 pub struct AddressBookConfig {
351 /// The size of the white peer list.
352 ///
353 /// The white list holds peers that have been connected to before.
354 ///
355 /// Type | Number
356 /// Valid values | >= 0
357 /// Examples | 1000, 500, 241
358 pub max_white_list_length: usize,
359
360 /// The size of the gray peer list.
361 ///
362 /// The gray peer list holds peers that have been
363 /// told about but not connected to cuprated.
364 ///
365 /// Type | Number
366 /// Valid values | >= 0
367 /// Examples | 1000, 500, 241
368 pub max_gray_list_length: usize,
369
370 #[inline = true]
371 /// The time period between address book saves.
372 ///
373 /// Type | Duration
374 /// Examples | { secs = 90, nanos = 0 }, { secs = 100, nano = 123 }
375 pub peer_save_period: Duration,
376 }
377}
378
379impl Default for AddressBookConfig {
380 fn default() -> Self {
381 Self {
382 max_white_list_length: 1_000,
383 max_gray_list_length: 5_000,
384 peer_save_period: Duration::from_secs(90),
385 }
386 }
387}
388
389impl AddressBookConfig {
390 /// Returns the [`cuprate_address_book::AddressBookConfig`].
391 pub fn address_book_config<Z: NetworkZone>(
392 &self,
393 cache_dir: &Path,
394 network: Network,
395 our_own_address: Option<Z::Addr>,
396 ) -> cuprate_address_book::AddressBookConfig<Z> {
397 cuprate_address_book::AddressBookConfig {
398 max_white_list_length: self.max_white_list_length,
399 max_gray_list_length: self.max_gray_list_length,
400 peer_store_directory: address_book_path(cache_dir, network),
401 peer_save_period: self.peer_save_period,
402 our_own_address,
403 }
404 }
405}
406
407/// Seed nodes for [`ClearNet`].
408pub(crate) fn clear_net_seed_nodes(network: Network) -> Vec<SocketAddr> {
409 let seeds = match network {
410 Network::FakeChain => [].as_slice(),
411 Network::Mainnet => [
412 "176.9.0.187:18080",
413 "88.198.163.90:18080",
414 "66.85.74.134:18080",
415 "51.79.173.165:18080",
416 "192.99.8.110:18080",
417 "37.187.74.171:18080",
418 "77.172.183.193:18080",
419 ]
420 .as_slice(),
421 Network::Stagenet => [
422 "176.9.0.187:38080",
423 "51.79.173.165:38080",
424 "192.99.8.110:38080",
425 "37.187.74.171:38080",
426 "77.172.183.193:38080",
427 ]
428 .as_slice(),
429 Network::Testnet => [
430 "176.9.0.187:28080",
431 "51.79.173.165:28080",
432 "192.99.8.110:28080",
433 "37.187.74.171:28080",
434 "77.172.183.193:28080",
435 ]
436 .as_slice(),
437 };
438
439 seeds
440 .iter()
441 .map(|s| s.parse())
442 .collect::<Result<_, _>>()
443 .unwrap()
444}
445
446/// Seed nodes for `Tor`.
447pub(crate) fn tor_net_seed_nodes(network: Network) -> Vec<OnionAddr> {
448 let seeds = match network {
449 Network::Mainnet => [
450 "zbjkbsxc5munw3qusl7j2hpcmikhqocdf4pqhnhtpzw5nt5jrmofptid.onion:18083",
451 "lykcas4tus7mkm4bhsgqe4drtd4awi7gja24goscc47xfgzj54yofyqd.onion:18083",
452 "plowsof3t5hogddwabaeiyrno25efmzfxyro2vligremt7sxpsclfaid.onion:18083",
453 "plowsoffjexmxalw73tkjmf422gq6575fc7vicuu4javzn2ynnte6tyd.onion:18083",
454 "plowsofe6cleftfmk2raiw5h2x66atrik3nja4bfd3zrfa2hdlgworad.onion:18083",
455 "aclc4e2jhhtr44guufbnwk5bzwhaecinax4yip4wr4tjn27sjsfg6zqd.onion:18083",
456 ]
457 .as_slice(),
458 Network::FakeChain | Network::Stagenet | Network::Testnet => [].as_slice(),
459 };
460
461 seeds
462 .iter()
463 .map(|s| s.parse())
464 .collect::<Result<_, _>>()
465 .unwrap()
466}