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(long, value_name = "ADDR", num_args = 1.., requires = "ipfs_server")]
158 pub ipfs_bootnodes: Vec<MultiaddrWithPeerId>,
159
160 #[arg(
162 long,
163 value_enum,
164 value_name = "SYNC_MODE",
165 default_value_t = SyncMode::Full,
166 ignore_case = true,
167 verbatim_doc_comment
168 )]
169 pub sync: SyncMode,
170
171 #[arg(long, value_name = "COUNT", default_value_t = 64)]
176 pub max_blocks_per_request: u32,
177
178 #[arg(
187 long,
188 value_enum,
189 value_name = "NETWORK_BACKEND",
190 default_value_t = NetworkBackendType::Litep2p,
191 ignore_case = true,
192 verbatim_doc_comment
193 )]
194 pub network_backend: NetworkBackendType,
195}
196
197impl NetworkParams {
198 pub fn network_config(
200 &self,
201 chain_spec: &Box<dyn ChainSpec>,
202 is_dev: bool,
203 is_validator: bool,
204 net_config_path: Option<PathBuf>,
205 client_id: &str,
206 node_name: &str,
207 node_key: NodeKeyConfig,
208 default_listen_port: u16,
209 ) -> NetworkConfiguration {
210 let port = self.port.unwrap_or(default_listen_port);
211
212 let listen_addresses = if self.listen_addr.is_empty() {
213 if is_validator || is_dev {
214 vec![
215 Multiaddr::empty()
216 .with(Protocol::Ip6([0, 0, 0, 0, 0, 0, 0, 0].into()))
217 .with(Protocol::Tcp(port)),
218 Multiaddr::empty()
219 .with(Protocol::Ip4([0, 0, 0, 0].into()))
220 .with(Protocol::Tcp(port)),
221 ]
222 } else {
223 vec![
224 Multiaddr::empty()
225 .with(Protocol::Ip6([0, 0, 0, 0, 0, 0, 0, 0].into()))
226 .with(Protocol::Tcp(port))
227 .with(Protocol::Ws(Cow::Borrowed("/"))),
228 Multiaddr::empty()
229 .with(Protocol::Ip4([0, 0, 0, 0].into()))
230 .with(Protocol::Tcp(port))
231 .with(Protocol::Ws(Cow::Borrowed("/"))),
232 ]
233 }
234 } else {
235 self.listen_addr.clone()
236 };
237
238 let public_addresses = self.public_addr.clone();
239
240 let mut boot_nodes = chain_spec.boot_nodes().to_vec();
241 boot_nodes.extend(self.bootnodes.clone());
242
243 let chain_type = chain_spec.chain_type();
244 let allow_non_globals_in_dht =
247 self.discover_local ||
248 is_dev || matches!(chain_type, ChainType::Local | ChainType::Development);
249
250 let allow_private_ip = match (self.allow_private_ip, self.no_private_ip) {
251 (true, true) => unreachable!("`*_private_ip` flags are mutually exclusive; qed"),
252 (true, false) => true,
253 (false, true) => false,
254 (false, false) => {
255 is_dev || matches!(chain_type, ChainType::Local | ChainType::Development)
256 },
257 };
258
259 NetworkConfiguration {
260 boot_nodes,
261 net_config_path,
262 default_peers_set: SetConfig {
263 in_peers: self.in_peers + self.in_peers_light,
264 out_peers: self.out_peers,
265 reserved_nodes: self.reserved_nodes.clone(),
266 non_reserved_mode: if self.reserved_only {
267 NonReservedPeerMode::Deny
268 } else {
269 NonReservedPeerMode::Accept
270 },
271 },
272 default_peers_set_num_full: self.in_peers + self.out_peers,
273 listen_addresses,
274 public_addresses,
275 node_key,
276 node_name: node_name.to_string(),
277 client_version: client_id.to_string(),
278 transport: TransportConfig::Normal {
279 enable_mdns: !is_dev && !self.no_mdns,
280 allow_private_ip,
281 },
282 idle_connection_timeout: DEFAULT_IDLE_CONNECTION_TIMEOUT,
283 max_parallel_downloads: self.max_parallel_downloads,
284 max_blocks_per_request: self.max_blocks_per_request,
285 min_peers_to_start_warp_sync: None,
286 enable_dht_random_walk: !self.reserved_only,
287 allow_non_globals_in_dht,
288 kademlia_disjoint_query_paths: self.kademlia_disjoint_query_paths,
289 kademlia_replication_factor: self.kademlia_replication_factor,
290 ipfs_server: self.ipfs_server,
291 ipfs_bootnodes: self.ipfs_bootnodes.clone(),
292 sync_mode: self.sync.into(),
293 network_backend: self.network_backend.into(),
294 }
295 }
296}
297
298#[cfg(test)]
299mod tests {
300 use super::*;
301 use clap::Parser;
302
303 #[derive(Parser)]
304 struct Cli {
305 #[clap(flatten)]
306 network_params: NetworkParams,
307 }
308
309 #[test]
310 fn reserved_nodes_multiple_values_and_occurrences() {
311 let params = Cli::try_parse_from([
312 "",
313 "--reserved-nodes",
314 "/ip4/0.0.0.0/tcp/501/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS",
315 "/ip4/0.0.0.0/tcp/502/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS",
316 "--reserved-nodes",
317 "/ip4/0.0.0.0/tcp/503/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS",
318 ])
319 .expect("Parses network params");
320
321 let expected = vec![
322 MultiaddrWithPeerId::try_from(
323 "/ip4/0.0.0.0/tcp/501/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS"
324 .to_string(),
325 )
326 .unwrap(),
327 MultiaddrWithPeerId::try_from(
328 "/ip4/0.0.0.0/tcp/502/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS"
329 .to_string(),
330 )
331 .unwrap(),
332 MultiaddrWithPeerId::try_from(
333 "/ip4/0.0.0.0/tcp/503/p2p/12D3KooWEBo1HUPQJwiBmM5kSeg4XgiVxEArArQdDarYEsGxMfbS"
334 .to_string(),
335 )
336 .unwrap(),
337 ];
338
339 assert_eq!(expected, params.network_params.reserved_nodes);
340 }
341
342 #[test]
343 fn sync_ignores_case() {
344 let params = Cli::try_parse_from(["", "--sync", "wArP"]).expect("Parses network params");
345
346 assert_eq!(SyncMode::Warp, params.network_params.sync);
347 }
348}