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