cuprated/config/
p2p.rs

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