1use crate::{
20 arg_enums::{NetworkBackendType, SyncMode},
21 params::node_key_params::NodeKeyParams,
22};
23use clap::Args;
24use sc_network::{
25 config::{
26 NetworkConfiguration, NodeKeyConfig, NonReservedPeerMode, SetConfig, TransportConfig,
27 DEFAULT_IDLE_CONNECTION_TIMEOUT, DEFAULT_LIGHT_REQUEST_EXECUTION_TIMEOUT,
28 },
29 multiaddr::Protocol,
30};
31use sc_service::{
32 config::{Multiaddr, MultiaddrWithPeerId},
33 ChainSpec, ChainType,
34};
35use std::{borrow::Cow, num::NonZeroUsize, path::PathBuf, time::Duration};
36
37#[derive(Debug, Clone, Args)]
39pub struct NetworkParams {
40 #[arg(long, value_name = "ADDR", num_args = 1..)]
42 pub bootnodes: Vec<MultiaddrWithPeerId>,
43
44 #[arg(long, value_name = "ADDR", num_args = 1..)]
46 pub reserved_nodes: Vec<MultiaddrWithPeerId>,
47
48 #[arg(long)]
56 pub reserved_only: bool,
57
58 #[arg(long, value_name = "PUBLIC_ADDR", num_args = 1..)]
70 pub public_addr: Vec<Multiaddr>,
71
72 #[arg(long, value_name = "LISTEN_ADDR", num_args = 1..)]
87 pub listen_addr: Vec<Multiaddr>,
88
89 #[arg(long)]
95 pub force_enable_webrtc: bool,
96
97 #[arg(long, value_name = "PORT", conflicts_with_all = &[ "listen_addr" ])]
99 pub port: Option<u16>,
100
101 #[arg(long, alias = "no-private-ipv4", conflicts_with_all = &["allow_private_ip"])]
110 pub no_private_ip: bool,
111
112 #[arg(long, alias = "allow-private-ipv4", conflicts_with_all = &["no_private_ip"])]
120 pub allow_private_ip: bool,
121
122 #[arg(long, value_name = "COUNT", default_value_t = 8)]
124 pub out_peers: u32,
125
126 #[arg(long, value_name = "COUNT", default_value_t = 32)]
128 pub in_peers: u32,
129
130 #[arg(long, value_name = "COUNT", default_value_t = 500)]
132 pub in_peers_light: u32,
133
134 #[arg(long)]
139 pub no_mdns: bool,
140
141 #[arg(long, value_name = "COUNT", default_value_t = 5)]
146 pub max_parallel_downloads: u32,
147
148 #[allow(missing_docs)]
149 #[clap(flatten)]
150 pub node_key_params: NodeKeyParams,
151
152 #[arg(long)]
157 pub discover_local: bool,
158
159 #[arg(long)]
166 pub kademlia_disjoint_query_paths: bool,
167
168 #[arg(long, default_value = "20")]
175 pub kademlia_replication_factor: NonZeroUsize,
176
177 #[arg(long)]
179 pub ipfs_server: bool,
180
181 #[arg(long, value_name = "ADDR", num_args = 1.., requires = "ipfs_server")]
183 pub ipfs_bootnodes: Vec<MultiaddrWithPeerId>,
184
185 #[arg(
194 long,
195 value_name = "MILLISECONDS",
196 default_value_t = DEFAULT_LIGHT_REQUEST_EXECUTION_TIMEOUT.as_millis() as u64
197 )]
198 pub light_request_execution_timeout_ms: u64,
199
200 #[arg(
202 long,
203 value_enum,
204 value_name = "SYNC_MODE",
205 default_value_t = SyncMode::Full,
206 ignore_case = true,
207 verbatim_doc_comment
208 )]
209 pub sync: SyncMode,
210
211 #[arg(long, value_name = "COUNT", default_value_t = 64)]
216 pub max_blocks_per_request: u32,
217
218 #[arg(
227 long,
228 value_enum,
229 value_name = "NETWORK_BACKEND",
230 default_value_t = NetworkBackendType::Litep2p,
231 ignore_case = true,
232 verbatim_doc_comment
233 )]
234 pub network_backend: NetworkBackendType,
235}
236
237impl NetworkParams {
238 pub fn network_config(
240 &self,
241 chain_spec: &Box<dyn ChainSpec>,
242 is_dev: bool,
243 is_validator: bool,
244 net_config_path: Option<PathBuf>,
245 client_id: &str,
246 node_name: &str,
247 node_key: NodeKeyConfig,
248 default_listen_port: u16,
249 ) -> NetworkConfiguration {
250 let port = self.port.unwrap_or(default_listen_port);
251
252 if self.force_enable_webrtc && !matches!(self.network_backend, NetworkBackendType::Litep2p)
253 {
254 log::warn!(
255 "`--force-enable-webrtc` has no effect: WebRTC is only supported by the litep2p \
256 network backend",
257 );
258 }
259
260 let listen_addresses = if self.listen_addr.is_empty() {
261 let mut listen_addresses = if is_validator || is_dev {
262 vec![
263 Multiaddr::empty()
264 .with(Protocol::Ip6([0, 0, 0, 0, 0, 0, 0, 0].into()))
265 .with(Protocol::Tcp(port)),
266 Multiaddr::empty()
267 .with(Protocol::Ip4([0, 0, 0, 0].into()))
268 .with(Protocol::Tcp(port)),
269 ]
270 } else {
271 vec![
272 Multiaddr::empty()
273 .with(Protocol::Ip6([0, 0, 0, 0, 0, 0, 0, 0].into()))
274 .with(Protocol::Tcp(port))
275 .with(Protocol::Ws(Cow::Borrowed("/"))),
276 Multiaddr::empty()
277 .with(Protocol::Ip4([0, 0, 0, 0].into()))
278 .with(Protocol::Tcp(port))
279 .with(Protocol::Ws(Cow::Borrowed("/"))),
280 ]
281 };
282
283 if matches!(self.network_backend, NetworkBackendType::Litep2p) &&
284 (self.force_enable_webrtc || !is_validator)
285 {
286 listen_addresses.extend([
287 Multiaddr::empty()
288 .with(Protocol::Ip6([0, 0, 0, 0, 0, 0, 0, 0].into()))
289 .with(Protocol::Udp(port))
290 .with(Protocol::WebRTCDirect),
291 Multiaddr::empty()
292 .with(Protocol::Ip4([0, 0, 0, 0].into()))
293 .with(Protocol::Udp(port))
294 .with(Protocol::WebRTCDirect),
295 ]);
296 }
297
298 listen_addresses
299 } else {
300 self.listen_addr.clone()
301 };
302
303 let public_addresses = self.public_addr.clone();
304
305 let mut boot_nodes = chain_spec.boot_nodes().to_vec();
306 boot_nodes.extend(self.bootnodes.clone());
307
308 let chain_type = chain_spec.chain_type();
309 let allow_non_globals_in_dht =
312 self.discover_local ||
313 is_dev || matches!(chain_type, ChainType::Local | ChainType::Development);
314
315 let allow_private_ip = match (self.allow_private_ip, self.no_private_ip) {
316 (true, true) => unreachable!("`*_private_ip` flags are mutually exclusive; qed"),
317 (true, false) => true,
318 (false, true) => false,
319 (false, false) => {
320 is_dev || matches!(chain_type, ChainType::Local | ChainType::Development)
321 },
322 };
323
324 NetworkConfiguration {
325 boot_nodes,
326 net_config_path,
327 default_peers_set: SetConfig {
328 in_peers: self.in_peers + self.in_peers_light,
329 out_peers: self.out_peers,
330 reserved_nodes: self.reserved_nodes.clone(),
331 non_reserved_mode: if self.reserved_only {
332 NonReservedPeerMode::Deny
333 } else {
334 NonReservedPeerMode::Accept
335 },
336 },
337 default_peers_set_num_full: self.in_peers + self.out_peers,
338 listen_addresses,
339 public_addresses,
340 node_key,
341 node_name: node_name.to_string(),
342 client_version: client_id.to_string(),
343 transport: TransportConfig::Normal {
344 enable_mdns: !is_dev && !self.no_mdns,
345 allow_private_ip,
346 },
347 idle_connection_timeout: DEFAULT_IDLE_CONNECTION_TIMEOUT,
348 max_parallel_downloads: self.max_parallel_downloads,
349 max_blocks_per_request: self.max_blocks_per_request,
350 min_peers_to_start_warp_sync: None,
351 enable_dht_random_walk: !self.reserved_only,
352 allow_non_globals_in_dht,
353 kademlia_disjoint_query_paths: self.kademlia_disjoint_query_paths,
354 kademlia_replication_factor: self.kademlia_replication_factor,
355 ipfs_server: self.ipfs_server,
356 ipfs_bootnodes: self.ipfs_bootnodes.clone(),
357 light_request_execution_timeout: match self.light_request_execution_timeout_ms {
358 0 => None,
359 ms => Some(Duration::from_millis(ms)),
360 },
361 sync_mode: self.sync.into(),
362 network_backend: self.network_backend.into(),
363 }
364 }
365}
366
367#[cfg(test)]
368mod tests {
369 use super::*;
370 use clap::Parser;
371
372 #[derive(Parser)]
373 struct Cli {
374 #[clap(flatten)]
375 network_params: NetworkParams,
376 }
377
378 #[test]
379 fn reserved_nodes_multiple_values_and_occurrences() {
380 let params = Cli::try_parse_from([
381 "",
382 "--reserved-nodes",
383 "/ip4/0.0.0.0/tcp/501/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS",
384 "/ip4/0.0.0.0/tcp/502/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS",
385 "--reserved-nodes",
386 "/ip4/0.0.0.0/tcp/503/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS",
387 ])
388 .expect("Parses network params");
389
390 let expected = vec![
391 MultiaddrWithPeerId::try_from(
392 "/ip4/0.0.0.0/tcp/501/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS"
393 .to_string(),
394 )
395 .unwrap(),
396 MultiaddrWithPeerId::try_from(
397 "/ip4/0.0.0.0/tcp/502/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS"
398 .to_string(),
399 )
400 .unwrap(),
401 MultiaddrWithPeerId::try_from(
402 "/ip4/0.0.0.0/tcp/503/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS"
403 .to_string(),
404 )
405 .unwrap(),
406 ];
407
408 assert_eq!(expected, params.network_params.reserved_nodes);
409 }
410
411 #[test]
412 fn sync_ignores_case() {
413 let params = Cli::try_parse_from(["", "--sync", "wArP"]).expect("Parses network params");
414
415 assert_eq!(SyncMode::Warp, params.network_params.sync);
416 }
417}