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}