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}