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,
28 },
29 multiaddr::Protocol,
30};
31use sc_service::{
32 config::{Multiaddr, MultiaddrWithPeerId},
33 ChainSpec, ChainType,
34};
35use std::{borrow::Cow, num::NonZeroUsize, path::PathBuf};
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..)]
62 pub public_addr: Vec<Multiaddr>,
63
64 #[arg(long, value_name = "LISTEN_ADDR", num_args = 1..)]
75 pub listen_addr: Vec<Multiaddr>,
76
77 #[arg(long)]
82 pub experimental_webrtc: bool,
83
84 #[arg(long, value_name = "PORT", conflicts_with_all = &[ "listen_addr" ])]
86 pub port: Option<u16>,
87
88 #[arg(long, alias = "no-private-ipv4", conflicts_with_all = &["allow_private_ip"])]
97 pub no_private_ip: bool,
98
99 #[arg(long, alias = "allow-private-ipv4", conflicts_with_all = &["no_private_ip"])]
107 pub allow_private_ip: bool,
108
109 #[arg(long, value_name = "COUNT", default_value_t = 8)]
111 pub out_peers: u32,
112
113 #[arg(long, value_name = "COUNT", default_value_t = 32)]
115 pub in_peers: u32,
116
117 #[arg(long, value_name = "COUNT", default_value_t = 100)]
119 pub in_peers_light: u32,
120
121 #[arg(long)]
126 pub no_mdns: bool,
127
128 #[arg(long, value_name = "COUNT", default_value_t = 5)]
133 pub max_parallel_downloads: u32,
134
135 #[allow(missing_docs)]
136 #[clap(flatten)]
137 pub node_key_params: NodeKeyParams,
138
139 #[arg(long)]
144 pub discover_local: bool,
145
146 #[arg(long)]
153 pub kademlia_disjoint_query_paths: bool,
154
155 #[arg(long, default_value = "20")]
162 pub kademlia_replication_factor: NonZeroUsize,
163
164 #[arg(long)]
166 pub ipfs_server: bool,
167
168 #[arg(long, value_name = "ADDR", num_args = 1.., requires = "ipfs_server")]
170 pub ipfs_bootnodes: Vec<MultiaddrWithPeerId>,
171
172 #[arg(
174 long,
175 value_enum,
176 value_name = "SYNC_MODE",
177 default_value_t = SyncMode::Full,
178 ignore_case = true,
179 verbatim_doc_comment
180 )]
181 pub sync: SyncMode,
182
183 #[arg(long, value_name = "COUNT", default_value_t = 64)]
188 pub max_blocks_per_request: u32,
189
190 #[arg(
199 long,
200 value_enum,
201 value_name = "NETWORK_BACKEND",
202 default_value_t = NetworkBackendType::Litep2p,
203 ignore_case = true,
204 verbatim_doc_comment
205 )]
206 pub network_backend: NetworkBackendType,
207}
208
209impl NetworkParams {
210 pub fn network_config(
212 &self,
213 chain_spec: &Box<dyn ChainSpec>,
214 is_dev: bool,
215 is_validator: bool,
216 net_config_path: Option<PathBuf>,
217 client_id: &str,
218 node_name: &str,
219 node_key: NodeKeyConfig,
220 default_listen_port: u16,
221 ) -> NetworkConfiguration {
222 let port = self.port.unwrap_or(default_listen_port);
223
224 let listen_addresses = if self.listen_addr.is_empty() {
225 if is_validator || is_dev {
226 vec![
227 Multiaddr::empty()
228 .with(Protocol::Ip6([0, 0, 0, 0, 0, 0, 0, 0].into()))
229 .with(Protocol::Tcp(port)),
230 Multiaddr::empty()
231 .with(Protocol::Ip4([0, 0, 0, 0].into()))
232 .with(Protocol::Tcp(port)),
233 ]
234 } else {
235 vec![
236 Multiaddr::empty()
237 .with(Protocol::Ip6([0, 0, 0, 0, 0, 0, 0, 0].into()))
238 .with(Protocol::Tcp(port))
239 .with(Protocol::Ws(Cow::Borrowed("/"))),
240 Multiaddr::empty()
241 .with(Protocol::Ip4([0, 0, 0, 0].into()))
242 .with(Protocol::Tcp(port))
243 .with(Protocol::Ws(Cow::Borrowed("/"))),
244 ]
245 }
246 } else {
247 self.listen_addr.clone()
248 };
249
250 let public_addresses = self.public_addr.clone();
251
252 let mut boot_nodes = chain_spec.boot_nodes().to_vec();
253 boot_nodes.extend(self.bootnodes.clone());
254
255 let chain_type = chain_spec.chain_type();
256 let allow_non_globals_in_dht =
259 self.discover_local ||
260 is_dev || matches!(chain_type, ChainType::Local | ChainType::Development);
261
262 let allow_private_ip = match (self.allow_private_ip, self.no_private_ip) {
263 (true, true) => unreachable!("`*_private_ip` flags are mutually exclusive; qed"),
264 (true, false) => true,
265 (false, true) => false,
266 (false, false) => {
267 is_dev || matches!(chain_type, ChainType::Local | ChainType::Development)
268 },
269 };
270
271 NetworkConfiguration {
272 boot_nodes,
273 net_config_path,
274 default_peers_set: SetConfig {
275 in_peers: self.in_peers + self.in_peers_light,
276 out_peers: self.out_peers,
277 reserved_nodes: self.reserved_nodes.clone(),
278 non_reserved_mode: if self.reserved_only {
279 NonReservedPeerMode::Deny
280 } else {
281 NonReservedPeerMode::Accept
282 },
283 },
284 default_peers_set_num_full: self.in_peers + self.out_peers,
285 listen_addresses,
286 experimental_webrtc: self.experimental_webrtc,
287 public_addresses,
288 node_key,
289 node_name: node_name.to_string(),
290 client_version: client_id.to_string(),
291 transport: TransportConfig::Normal {
292 enable_mdns: !is_dev && !self.no_mdns,
293 allow_private_ip,
294 },
295 idle_connection_timeout: DEFAULT_IDLE_CONNECTION_TIMEOUT,
296 max_parallel_downloads: self.max_parallel_downloads,
297 max_blocks_per_request: self.max_blocks_per_request,
298 min_peers_to_start_warp_sync: None,
299 enable_dht_random_walk: !self.reserved_only,
300 allow_non_globals_in_dht,
301 kademlia_disjoint_query_paths: self.kademlia_disjoint_query_paths,
302 kademlia_replication_factor: self.kademlia_replication_factor,
303 ipfs_server: self.ipfs_server,
304 ipfs_bootnodes: self.ipfs_bootnodes.clone(),
305 sync_mode: self.sync.into(),
306 network_backend: self.network_backend.into(),
307 }
308 }
309}
310
311#[cfg(test)]
312mod tests {
313 use super::*;
314 use clap::Parser;
315
316 #[derive(Parser)]
317 struct Cli {
318 #[clap(flatten)]
319 network_params: NetworkParams,
320 }
321
322 #[test]
323 fn reserved_nodes_multiple_values_and_occurrences() {
324 let params = Cli::try_parse_from([
325 "",
326 "--reserved-nodes",
327 "/ip4/0.0.0.0/tcp/501/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS",
328 "/ip4/0.0.0.0/tcp/502/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS",
329 "--reserved-nodes",
330 "/ip4/0.0.0.0/tcp/503/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS",
331 ])
332 .expect("Parses network params");
333
334 let expected = vec![
335 MultiaddrWithPeerId::try_from(
336 "/ip4/0.0.0.0/tcp/501/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS"
337 .to_string(),
338 )
339 .unwrap(),
340 MultiaddrWithPeerId::try_from(
341 "/ip4/0.0.0.0/tcp/502/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS"
342 .to_string(),
343 )
344 .unwrap(),
345 MultiaddrWithPeerId::try_from(
346 "/ip4/0.0.0.0/tcp/503/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS"
347 .to_string(),
348 )
349 .unwrap(),
350 ];
351
352 assert_eq!(expected, params.network_params.reserved_nodes);
353 }
354
355 #[test]
356 fn sync_ignores_case() {
357 let params = Cli::try_parse_from(["", "--sync", "wArP"]).expect("Parses network params");
358
359 assert_eq!(SyncMode::Warp, params.network_params.sync);
360 }
361}