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