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