cuprated/config/
p2p.rs

1use std::{
2    marker::PhantomData,
3    net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
4    path::Path,
5    time::Duration,
6};
7
8use serde::{Deserialize, Serialize};
9
10use cuprate_helper::{fs::address_book_path, network::Network};
11use cuprate_p2p::config::TransportConfig;
12use cuprate_p2p_core::{
13    transports::{Tcp, TcpServerConfig},
14    ClearNet, NetworkZone, Transport,
15};
16use cuprate_wire::OnionAddr;
17
18use super::macros::config_struct;
19
20config_struct! {
21    /// P2P config.
22    #[derive(Debug, Default, Deserialize, Serialize, PartialEq)]
23    #[serde(deny_unknown_fields, default)]
24    pub struct P2PConfig {
25        #[child = true]
26        /// The clear-net P2P config.
27        pub clear_net: ClearNetConfig,
28
29        #[child = true]
30        /// Block downloader config.
31        ///
32        /// The block downloader handles downloading old blocks from peers when we are behind.
33        pub block_downloader: BlockDownloaderConfig,
34    }
35}
36
37config_struct! {
38    #[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)]
39    #[serde(deny_unknown_fields, default)]
40    pub struct BlockDownloaderConfig {
41        #[comment_out = true]
42        /// The size in bytes of the buffer between the block downloader
43        /// and the place which is consuming the downloaded blocks (`cuprated`).
44        ///
45        /// This value is an absolute maximum,
46        /// once this is reached the block downloader will pause.
47        ///
48        /// Type         | Number
49        /// Valid values | >= 0
50        /// Examples     | 1_000_000_000, 5_500_000_000, 500_000_000
51        pub buffer_bytes: usize,
52
53        #[comment_out = true]
54        /// The size of the in progress queue (in bytes)
55        /// at which cuprated stops requesting more blocks.
56        ///
57        /// The value is _NOT_ an absolute maximum,
58        /// the in-progress queue could get much larger.
59        /// This value is only the value cuprated stops requesting more blocks,
60        /// if cuprated still has requests in progress,
61        /// it will still accept the response and add the blocks to the queue.
62        ///
63        /// Type         | Number
64        /// Valid values | >= 0
65        /// Examples     | 500_000_000, 1_000_000_000,
66        pub in_progress_queue_bytes: usize,
67
68        #[inline = true]
69        /// The duration between checking the client pool for free peers.
70        ///
71        /// Type     | Duration
72        /// Examples | { secs = 30, nanos = 0 }, { secs = 35, nano = 123 }
73        pub check_client_pool_interval: Duration,
74
75        #[comment_out = true]
76        /// The target size of a single batch of blocks (in bytes).
77        ///
78        /// This value must be below 100_000,000,
79        /// it is not recommended to set it above 30_000_000.
80        ///
81        /// Type         | Number
82        /// Valid values | 0..100_000,000
83        pub target_batch_bytes: usize,
84    }
85}
86
87impl From<BlockDownloaderConfig> for cuprate_p2p::block_downloader::BlockDownloaderConfig {
88    fn from(value: BlockDownloaderConfig) -> Self {
89        Self {
90            buffer_bytes: value.buffer_bytes,
91            in_progress_queue_bytes: value.in_progress_queue_bytes,
92            check_client_pool_interval: value.check_client_pool_interval,
93            target_batch_bytes: value.target_batch_bytes,
94            initial_batch_len: 1,
95        }
96    }
97}
98
99impl Default for BlockDownloaderConfig {
100    fn default() -> Self {
101        Self {
102            buffer_bytes: 1_000_000_000,
103            in_progress_queue_bytes: 500_000_000,
104            check_client_pool_interval: Duration::from_secs(30),
105            target_batch_bytes: 15_000_000,
106        }
107    }
108}
109
110config_struct! {
111    Shared {
112        #[comment_out = true]
113        /// The number of outbound connections to make and try keep.
114        ///
115        /// It's recommended to keep this value above 12.
116        ///
117        /// Type         | Number
118        /// Valid values | >= 0
119        /// Examples     | 12, 32, 64, 100, 500
120        pub outbound_connections: usize,
121
122        #[comment_out = true]
123        /// The amount of extra connections to make if cuprated is under load.
124        ///
125        /// Type         | Number
126        /// Valid values | >= 0
127        /// Examples     | 0, 12, 32, 64, 100, 500
128        pub extra_outbound_connections: usize,
129
130        #[comment_out = true]
131        /// The maximum amount of inbound connections to allow.
132        ///
133        /// Type         | Number
134        /// Valid values | >= 0
135        /// Examples     | 0, 12, 32, 64, 100, 500
136        pub max_inbound_connections: usize,
137
138        #[comment_out = true]
139        /// The percent of connections that should be
140        /// to peers that haven't connected to before.
141        ///
142        /// 0.0 is 0%.
143        /// 1.0 is 100%.
144        ///
145        /// Type         | Floating point number
146        /// Valid values | 0.0..1.0
147        /// Examples     | 0.0, 0.5, 0.123, 0.999, 1.0
148        pub gray_peers_percent: f64,
149
150        /// The port to use to accept incoming IPv4 P2P connections.
151        ///
152        /// Setting this to 0 will disable incoming P2P connections.
153        ///
154        /// Type         | Number
155        /// Valid values | 0..65534
156        /// Examples     | 18080, 9999, 5432
157        pub p2p_port: u16,
158
159        #[child = true]
160        /// The address book config.
161        pub address_book_config: AddressBookConfig,
162    }
163
164    /// The config values for P2P clear-net.
165    #[derive(Debug, Deserialize, Serialize, PartialEq)]
166    #[serde(deny_unknown_fields, default)]
167    pub struct ClearNetConfig {
168        /// The IPv4 address to bind and listen for connections on.
169        ///
170        /// Type     | IPv4 address
171        /// Examples | "0.0.0.0", "192.168.1.50"
172        pub listen_on: Ipv4Addr,
173
174        /// Enable IPv6 inbound server.
175        ///
176        /// Setting this to `false` will disable incoming IPv6 P2P connections.
177        ///
178        /// Type         | boolean
179        /// Valid values | false, true
180        /// Examples     | false
181        pub enable_inbound_v6: bool,
182
183        /// The IPv6 address to bind and listen for connections on.
184        ///
185        /// Type     | IPv6 address
186        /// Examples | "::", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
187        pub listen_on_v6: Ipv6Addr,
188    }
189}
190
191impl Default for ClearNetConfig {
192    fn default() -> Self {
193        Self {
194            listen_on: Ipv4Addr::UNSPECIFIED,
195            enable_inbound_v6: false,
196            listen_on_v6: Ipv6Addr::UNSPECIFIED,
197            outbound_connections: 32,
198            extra_outbound_connections: 8,
199            max_inbound_connections: 128,
200            gray_peers_percent: 0.7,
201            p2p_port: 18080,
202            address_book_config: AddressBookConfig::default(),
203        }
204    }
205}
206
207impl From<&ClearNetConfig> for TransportConfig<ClearNet, Tcp> {
208    fn from(value: &ClearNetConfig) -> Self {
209        let server_config = if value.p2p_port != 0 {
210            let mut sc = TcpServerConfig::default();
211            sc.ipv4 = Some(value.listen_on);
212            sc.ipv6 = value.enable_inbound_v6.then_some(value.listen_on_v6);
213            sc.port = value.p2p_port;
214            Some(sc)
215        } else {
216            None
217        };
218
219        Self {
220            client_config: (),
221            server_config,
222        }
223    }
224}
225
226config_struct! {
227    /// The addressbook config exposed to users.
228    #[derive(Debug, Deserialize, Serialize, Eq, PartialEq)]
229    #[serde(deny_unknown_fields, default)]
230    pub struct AddressBookConfig {
231        /// The size of the white peer list.
232        ///
233        /// The white list holds peers that have been connected to before.
234        ///
235        /// Type         | Number
236        /// Valid values | >= 0
237        /// Examples     | 1000, 500, 241
238        pub max_white_list_length: usize,
239
240        /// The size of the gray peer list.
241        ///
242        /// The gray peer list holds peers that have been
243        /// told about but not connected to cuprated.
244        ///
245        /// Type         | Number
246        /// Valid values | >= 0
247        /// Examples     | 1000, 500, 241
248        pub max_gray_list_length: usize,
249
250        #[inline = true]
251        /// The time period between address book saves.
252        ///
253        /// Type     | Duration
254        /// Examples | { secs = 90, nanos = 0 }, { secs = 100, nano = 123 }
255        pub peer_save_period: Duration,
256    }
257}
258
259impl Default for AddressBookConfig {
260    fn default() -> Self {
261        Self {
262            max_white_list_length: 1_000,
263            max_gray_list_length: 5_000,
264            peer_save_period: Duration::from_secs(90),
265        }
266    }
267}
268
269impl AddressBookConfig {
270    /// Returns the [`cuprate_address_book::AddressBookConfig`].
271    pub fn address_book_config<Z: NetworkZone>(
272        &self,
273        cache_dir: &Path,
274        network: Network,
275        our_own_address: Option<Z::Addr>,
276    ) -> cuprate_address_book::AddressBookConfig<Z> {
277        cuprate_address_book::AddressBookConfig {
278            max_white_list_length: self.max_white_list_length,
279            max_gray_list_length: self.max_gray_list_length,
280            peer_store_directory: address_book_path(cache_dir, network),
281            peer_save_period: self.peer_save_period,
282            our_own_address,
283        }
284    }
285}
286
287/// Seed nodes for [`ClearNet`].
288pub fn clear_net_seed_nodes(network: Network) -> Vec<SocketAddr> {
289    let seeds = match network {
290        Network::Mainnet => [
291            "176.9.0.187:18080",
292            "88.198.163.90:18080",
293            "66.85.74.134:18080",
294            "51.79.173.165:18080",
295            "192.99.8.110:18080",
296            "37.187.74.171:18080",
297            "77.172.183.193:18080",
298        ]
299        .as_slice(),
300        Network::Stagenet => [
301            "176.9.0.187:38080",
302            "51.79.173.165:38080",
303            "192.99.8.110:38080",
304            "37.187.74.171:38080",
305            "77.172.183.193:38080",
306        ]
307        .as_slice(),
308        Network::Testnet => [
309            "176.9.0.187:28080",
310            "51.79.173.165:28080",
311            "192.99.8.110:28080",
312            "37.187.74.171:28080",
313            "77.172.183.193:28080",
314        ]
315        .as_slice(),
316    };
317
318    seeds
319        .iter()
320        .map(|s| s.parse())
321        .collect::<Result<_, _>>()
322        .unwrap()
323}
324
325/// Seed nodes for `Tor`.
326pub fn tor_net_seed_nodes(network: Network) -> Vec<OnionAddr> {
327    let seeds = match network {
328        Network::Mainnet => [
329            "zbjkbsxc5munw3qusl7j2hpcmikhqocdf4pqhnhtpzw5nt5jrmofptid.onion:18083",
330            "qz43zul2x56jexzoqgkx2trzwcfnr6l3hbtfcfx54g4r3eahy3bssjyd.onion:18083",
331            "plowsof3t5hogddwabaeiyrno25efmzfxyro2vligremt7sxpsclfaid.onion:18083",
332            "plowsoffjexmxalw73tkjmf422gq6575fc7vicuu4javzn2ynnte6tyd.onion:18083",
333            "plowsofe6cleftfmk2raiw5h2x66atrik3nja4bfd3zrfa2hdlgworad.onion:18083",
334            "aclc4e2jhhtr44guufbnwk5bzwhaecinax4yip4wr4tjn27sjsfg6zqd.onion:18083",
335        ]
336        .as_slice(),
337        Network::Stagenet | Network::Testnet => [].as_slice(),
338    };
339
340    seeds
341        .iter()
342        .map(|s| s.parse())
343        .collect::<Result<_, _>>()
344        .unwrap()
345}