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..)]
70 pub listen_addr: Vec<Multiaddr>,
71
72 #[arg(long, value_name = "PORT", conflicts_with_all = &[ "listen_addr" ])]
74 pub port: Option<u16>,
75
76 #[arg(long, alias = "no-private-ipv4", conflicts_with_all = &["allow_private_ip"])]
85 pub no_private_ip: bool,
86
87 #[arg(long, alias = "allow-private-ipv4", conflicts_with_all = &["no_private_ip"])]
95 pub allow_private_ip: bool,
96
97 #[arg(long, value_name = "COUNT", default_value_t = 8)]
99 pub out_peers: u32,
100
101 #[arg(long, value_name = "COUNT", default_value_t = 32)]
103 pub in_peers: u32,
104
105 #[arg(long, value_name = "COUNT", default_value_t = 100)]
107 pub in_peers_light: u32,
108
109 #[arg(long)]
114 pub no_mdns: bool,
115
116 #[arg(long, value_name = "COUNT", default_value_t = 5)]
121 pub max_parallel_downloads: u32,
122
123 #[allow(missing_docs)]
124 #[clap(flatten)]
125 pub node_key_params: NodeKeyParams,
126
127 #[arg(long)]
132 pub discover_local: bool,
133
134 #[arg(long)]
141 pub kademlia_disjoint_query_paths: bool,
142
143 #[arg(long, default_value = "20")]
150 pub kademlia_replication_factor: NonZeroUsize,
151
152 #[arg(long)]
154 pub ipfs_server: bool,
155
156 #[arg(
158 long,
159 value_enum,
160 value_name = "SYNC_MODE",
161 default_value_t = SyncMode::Full,
162 ignore_case = true,
163 verbatim_doc_comment
164 )]
165 pub sync: SyncMode,
166
167 #[arg(long, value_name = "COUNT", default_value_t = 64)]
172 pub max_blocks_per_request: u32,
173
174 #[arg(
183 long,
184 value_enum,
185 value_name = "NETWORK_BACKEND",
186 default_value_t = NetworkBackendType::Litep2p,
187 ignore_case = true,
188 verbatim_doc_comment
189 )]
190 pub network_backend: NetworkBackendType,
191}
192
193impl NetworkParams {
194 pub fn network_config(
196 &self,
197 chain_spec: &Box<dyn ChainSpec>,
198 is_dev: bool,
199 is_validator: bool,
200 net_config_path: Option<PathBuf>,
201 client_id: &str,
202 node_name: &str,
203 node_key: NodeKeyConfig,
204 default_listen_port: u16,
205 ) -> NetworkConfiguration {
206 let port = self.port.unwrap_or(default_listen_port);
207
208 let listen_addresses = if self.listen_addr.is_empty() {
209 if is_validator || is_dev {
210 vec![
211 Multiaddr::empty()
212 .with(Protocol::Ip6([0, 0, 0, 0, 0, 0, 0, 0].into()))
213 .with(Protocol::Tcp(port)),
214 Multiaddr::empty()
215 .with(Protocol::Ip4([0, 0, 0, 0].into()))
216 .with(Protocol::Tcp(port)),
217 ]
218 } else {
219 vec![
220 Multiaddr::empty()
221 .with(Protocol::Ip6([0, 0, 0, 0, 0, 0, 0, 0].into()))
222 .with(Protocol::Tcp(port))
223 .with(Protocol::Ws(Cow::Borrowed("/"))),
224 Multiaddr::empty()
225 .with(Protocol::Ip4([0, 0, 0, 0].into()))
226 .with(Protocol::Tcp(port))
227 .with(Protocol::Ws(Cow::Borrowed("/"))),
228 ]
229 }
230 } else {
231 self.listen_addr.clone()
232 };
233
234 let public_addresses = self.public_addr.clone();
235
236 let mut boot_nodes = chain_spec.boot_nodes().to_vec();
237 boot_nodes.extend(self.bootnodes.clone());
238
239 let chain_type = chain_spec.chain_type();
240 let allow_non_globals_in_dht =
243 self.discover_local ||
244 is_dev || matches!(chain_type, ChainType::Local | ChainType::Development);
245
246 let allow_private_ip = match (self.allow_private_ip, self.no_private_ip) {
247 (true, true) => unreachable!("`*_private_ip` flags are mutually exclusive; qed"),
248 (true, false) => true,
249 (false, true) => false,
250 (false, false) => {
251 is_dev || matches!(chain_type, ChainType::Local | ChainType::Development)
252 },
253 };
254
255 NetworkConfiguration {
256 boot_nodes,
257 net_config_path,
258 default_peers_set: SetConfig {
259 in_peers: self.in_peers + self.in_peers_light,
260 out_peers: self.out_peers,
261 reserved_nodes: self.reserved_nodes.clone(),
262 non_reserved_mode: if self.reserved_only {
263 NonReservedPeerMode::Deny
264 } else {
265 NonReservedPeerMode::Accept
266 },
267 },
268 default_peers_set_num_full: self.in_peers + self.out_peers,
269 listen_addresses,
270 public_addresses,
271 node_key,
272 node_name: node_name.to_string(),
273 client_version: client_id.to_string(),
274 transport: TransportConfig::Normal {
275 enable_mdns: !is_dev && !self.no_mdns,
276 allow_private_ip,
277 },
278 idle_connection_timeout: DEFAULT_IDLE_CONNECTION_TIMEOUT,
279 max_parallel_downloads: self.max_parallel_downloads,
280 max_blocks_per_request: self.max_blocks_per_request,
281 min_peers_to_start_warp_sync: None,
282 enable_dht_random_walk: !self.reserved_only,
283 allow_non_globals_in_dht,
284 kademlia_disjoint_query_paths: self.kademlia_disjoint_query_paths,
285 kademlia_replication_factor: self.kademlia_replication_factor,
286 ipfs_server: self.ipfs_server,
287 sync_mode: self.sync.into(),
288 network_backend: self.network_backend.into(),
289 }
290 }
291}
292
293#[cfg(test)]
294mod tests {
295 use super::*;
296 use clap::Parser;
297
298 #[derive(Parser)]
299 struct Cli {
300 #[clap(flatten)]
301 network_params: NetworkParams,
302 }
303
304 #[test]
305 fn reserved_nodes_multiple_values_and_occurrences() {
306 let params = Cli::try_parse_from([
307 "",
308 "--reserved-nodes",
309 "/ip4/0.0.0.0/tcp/501/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS",
310 "/ip4/0.0.0.0/tcp/502/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS",
311 "--reserved-nodes",
312 "/ip4/0.0.0.0/tcp/503/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS",
313 ])
314 .expect("Parses network params");
315
316 let expected = vec![
317 MultiaddrWithPeerId::try_from(
318 "/ip4/0.0.0.0/tcp/501/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS"
319 .to_string(),
320 )
321 .unwrap(),
322 MultiaddrWithPeerId::try_from(
323 "/ip4/0.0.0.0/tcp/502/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS"
324 .to_string(),
325 )
326 .unwrap(),
327 MultiaddrWithPeerId::try_from(
328 "/ip4/0.0.0.0/tcp/503/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS"
329 .to_string(),
330 )
331 .unwrap(),
332 ];
333
334 assert_eq!(expected, params.network_params.reserved_nodes);
335 }
336
337 #[test]
338 fn sync_ignores_case() {
339 let params = Cli::try_parse_from(["", "--sync", "wArP"]).expect("Parses network params");
340
341 assert_eq!(SyncMode::Warp, params.network_params.sync);
342 }
343}