referrerpolicy=no-referrer-when-downgrade

sc_network/
config.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! Configuration of the networking layer.
20//!
21//! The [`Params`] struct is the struct that must be passed in order to initialize the networking.
22//! See the documentation of [`Params`].
23
24pub use crate::{
25	discovery::DEFAULT_KADEMLIA_REPLICATION_FACTOR,
26	peer_store::PeerStoreProvider,
27	protocol::{notification_service, NotificationsSink, ProtocolHandlePair},
28	request_responses::{
29		IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig,
30	},
31	service::{
32		metrics::NotificationMetrics,
33		traits::{NotificationConfig, NotificationService, PeerStore},
34	},
35	types::ProtocolName,
36};
37
38pub use sc_network_types::{build_multiaddr, ed25519};
39use sc_network_types::{
40	multiaddr::{self, Multiaddr},
41	PeerId,
42};
43
44use crate::service::{ensure_addresses_consistent_with_transport, traits::NetworkBackend};
45use codec::Encode;
46use prometheus_endpoint::Registry;
47use zeroize::Zeroize;
48
49pub use sc_network_common::{
50	role::{Role, Roles},
51	sync::SyncMode,
52	ExHashT,
53};
54
55use sp_runtime::traits::Block as BlockT;
56
57use std::{
58	error::Error,
59	fmt, fs,
60	future::Future,
61	io::{self, Write},
62	iter,
63	net::Ipv4Addr,
64	num::NonZeroUsize,
65	path::{Path, PathBuf},
66	pin::Pin,
67	str::{self, FromStr},
68	sync::Arc,
69	time::Duration,
70};
71
72/// Default timeout for idle connections of 10 seconds is good enough for most networks.
73/// It doesn't make sense to expose it as a CLI parameter on individual nodes, but customizations
74/// are possible in custom nodes through [`NetworkConfiguration`].
75pub const DEFAULT_IDLE_CONNECTION_TIMEOUT: Duration = Duration::from_secs(10);
76
77/// Maximum number of locally kept Kademlia provider keys.
78///
79/// 10000 keys is enough for a testnet with fast runtime (1-minute epoch) and 13 parachains.
80pub const KADEMLIA_MAX_PROVIDER_KEYS: usize = 10000;
81
82/// Time to keep Kademlia content provider records.
83///
84/// 10 h is enough time to keep the parachain bootnode record for two 4-hour epochs.
85pub const KADEMLIA_PROVIDER_RECORD_TTL: Duration = Duration::from_secs(10 * 3600);
86
87/// Interval of republishing Kademlia provider records.
88///
89/// 3.5 h means we refresh next epoch provider record 30 minutes before next 4-hour epoch comes.
90pub const KADEMLIA_PROVIDER_REPUBLISH_INTERVAL: Duration = Duration::from_secs(12600);
91
92/// Protocol name prefix, transmitted on the wire for legacy protocol names.
93/// I.e., `dot` in `/dot/sync/2`. Should be unique for each chain. Always UTF-8.
94/// Deprecated in favour of genesis hash & fork ID based protocol names.
95#[derive(Clone, PartialEq, Eq, Hash)]
96pub struct ProtocolId(smallvec::SmallVec<[u8; 6]>);
97
98impl<'a> From<&'a str> for ProtocolId {
99	fn from(bytes: &'a str) -> ProtocolId {
100		Self(bytes.as_bytes().into())
101	}
102}
103
104impl AsRef<str> for ProtocolId {
105	fn as_ref(&self) -> &str {
106		str::from_utf8(&self.0[..])
107			.expect("the only way to build a ProtocolId is through a UTF-8 String; qed")
108	}
109}
110
111impl fmt::Debug for ProtocolId {
112	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
113		fmt::Debug::fmt(self.as_ref(), f)
114	}
115}
116
117/// Parses a string address and splits it into Multiaddress and PeerId, if
118/// valid.
119///
120/// # Example
121///
122/// ```
123/// # use sc_network_types::{multiaddr::Multiaddr, PeerId};
124/// use sc_network::config::parse_str_addr;
125/// let (peer_id, addr) = parse_str_addr(
126/// 	"/ip4/198.51.100.19/tcp/30333/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV"
127/// ).unwrap();
128/// assert_eq!(peer_id, "QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV".parse::<PeerId>().unwrap().into());
129/// assert_eq!(addr, "/ip4/198.51.100.19/tcp/30333".parse::<Multiaddr>().unwrap());
130/// ```
131pub fn parse_str_addr(addr_str: &str) -> Result<(PeerId, Multiaddr), ParseErr> {
132	let addr: Multiaddr = addr_str.parse()?;
133	parse_addr(addr)
134}
135
136/// Splits a Multiaddress into a Multiaddress and PeerId.
137pub fn parse_addr(mut addr: Multiaddr) -> Result<(PeerId, Multiaddr), ParseErr> {
138	let multihash = match addr.pop() {
139		Some(multiaddr::Protocol::P2p(multihash)) => multihash,
140		_ => return Err(ParseErr::PeerIdMissing),
141	};
142	let peer_id = PeerId::from_multihash(multihash).map_err(|_| ParseErr::InvalidPeerId)?;
143
144	Ok((peer_id, addr))
145}
146
147/// Address of a node, including its identity.
148///
149/// This struct represents a decoded version of a multiaddress that ends with `/p2p/<peerid>`.
150///
151/// # Example
152///
153/// ```
154/// # use sc_network_types::{multiaddr::Multiaddr, PeerId};
155/// use sc_network::config::MultiaddrWithPeerId;
156/// let addr: MultiaddrWithPeerId =
157/// 	"/ip4/198.51.100.19/tcp/30333/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV".parse().unwrap();
158/// assert_eq!(addr.peer_id.to_base58(), "QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV");
159/// assert_eq!(addr.multiaddr.to_string(), "/ip4/198.51.100.19/tcp/30333");
160/// ```
161#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq)]
162#[serde(try_from = "String", into = "String")]
163pub struct MultiaddrWithPeerId {
164	/// Address of the node.
165	pub multiaddr: Multiaddr,
166	/// Its identity.
167	pub peer_id: PeerId,
168}
169
170impl MultiaddrWithPeerId {
171	/// Concatenates the multiaddress and peer ID into one multiaddress containing both.
172	pub fn concat(&self) -> Multiaddr {
173		let proto = multiaddr::Protocol::P2p(From::from(self.peer_id));
174		self.multiaddr.clone().with(proto)
175	}
176}
177
178impl fmt::Display for MultiaddrWithPeerId {
179	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
180		fmt::Display::fmt(&self.concat(), f)
181	}
182}
183
184impl FromStr for MultiaddrWithPeerId {
185	type Err = ParseErr;
186
187	fn from_str(s: &str) -> Result<Self, Self::Err> {
188		let (peer_id, multiaddr) = parse_str_addr(s)?;
189		Ok(Self { peer_id, multiaddr })
190	}
191}
192
193impl From<MultiaddrWithPeerId> for String {
194	fn from(ma: MultiaddrWithPeerId) -> String {
195		format!("{}", ma)
196	}
197}
198
199impl TryFrom<String> for MultiaddrWithPeerId {
200	type Error = ParseErr;
201	fn try_from(string: String) -> Result<Self, Self::Error> {
202		string.parse()
203	}
204}
205
206/// Error that can be generated by `parse_str_addr`.
207#[derive(Debug)]
208pub enum ParseErr {
209	/// Error while parsing the multiaddress.
210	MultiaddrParse(multiaddr::ParseError),
211	/// Multihash of the peer ID is invalid.
212	InvalidPeerId,
213	/// The peer ID is missing from the address.
214	PeerIdMissing,
215}
216
217impl fmt::Display for ParseErr {
218	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
219		match self {
220			Self::MultiaddrParse(err) => write!(f, "{}", err),
221			Self::InvalidPeerId => write!(f, "Peer id at the end of the address is invalid"),
222			Self::PeerIdMissing => write!(f, "Peer id is missing from the address"),
223		}
224	}
225}
226
227impl std::error::Error for ParseErr {
228	fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
229		match self {
230			Self::MultiaddrParse(err) => Some(err),
231			Self::InvalidPeerId => None,
232			Self::PeerIdMissing => None,
233		}
234	}
235}
236
237impl From<multiaddr::ParseError> for ParseErr {
238	fn from(err: multiaddr::ParseError) -> ParseErr {
239		Self::MultiaddrParse(err)
240	}
241}
242
243/// Custom handshake for the notification protocol
244#[derive(Debug, Clone)]
245pub struct NotificationHandshake(Vec<u8>);
246
247impl NotificationHandshake {
248	/// Create new `NotificationHandshake` from an object that implements `Encode`
249	pub fn new<H: Encode>(handshake: H) -> Self {
250		Self(handshake.encode())
251	}
252
253	/// Create new `NotificationHandshake` from raw bytes
254	pub fn from_bytes(bytes: Vec<u8>) -> Self {
255		Self(bytes)
256	}
257}
258
259impl std::ops::Deref for NotificationHandshake {
260	type Target = Vec<u8>;
261
262	fn deref(&self) -> &Self::Target {
263		&self.0
264	}
265}
266
267/// Configuration for the transport layer.
268#[derive(Clone, Debug)]
269pub enum TransportConfig {
270	/// Normal transport mode.
271	Normal {
272		/// If true, the network will use mDNS to discover other libp2p nodes on the local network
273		/// and connect to them if they support the same chain.
274		enable_mdns: bool,
275
276		/// If true, allow connecting to private IPv4/IPv6 addresses (as defined in
277		/// [RFC1918](https://tools.ietf.org/html/rfc1918)). Irrelevant for addresses that have
278		/// been passed in `::sc_network::config::NetworkConfiguration::boot_nodes`.
279		allow_private_ip: bool,
280	},
281
282	/// Only allow connections within the same process.
283	/// Only addresses of the form `/memory/...` will be supported.
284	MemoryOnly,
285}
286
287/// The policy for connections to non-reserved peers.
288#[derive(Clone, Debug, PartialEq, Eq)]
289pub enum NonReservedPeerMode {
290	/// Accept them. This is the default.
291	Accept,
292	/// Deny them.
293	Deny,
294}
295
296impl NonReservedPeerMode {
297	/// Attempt to parse the peer mode from a string.
298	pub fn parse(s: &str) -> Option<Self> {
299		match s {
300			"accept" => Some(Self::Accept),
301			"deny" => Some(Self::Deny),
302			_ => None,
303		}
304	}
305
306	/// If we are in "reserved-only" peer mode.
307	pub fn is_reserved_only(&self) -> bool {
308		matches!(self, NonReservedPeerMode::Deny)
309	}
310}
311
312/// The configuration of a node's secret key, describing the type of key
313/// and how it is obtained. A node's identity keypair is the result of
314/// the evaluation of the node key configuration.
315#[derive(Clone, Debug)]
316pub enum NodeKeyConfig {
317	/// A Ed25519 secret key configuration.
318	Ed25519(Secret<ed25519::SecretKey>),
319}
320
321impl Default for NodeKeyConfig {
322	fn default() -> NodeKeyConfig {
323		Self::Ed25519(Secret::New)
324	}
325}
326
327/// The options for obtaining a Ed25519 secret key.
328pub type Ed25519Secret = Secret<ed25519::SecretKey>;
329
330/// The configuration options for obtaining a secret key `K`.
331#[derive(Clone)]
332pub enum Secret<K> {
333	/// Use the given secret key `K`.
334	Input(K),
335	/// Read the secret key from a file. If the file does not exist,
336	/// it is created with a newly generated secret key `K`. The format
337	/// of the file is determined by `K`:
338	///
339	///   * `ed25519::SecretKey`: An unencoded 32 bytes Ed25519 secret key.
340	File(PathBuf),
341	/// Always generate a new secret key `K`.
342	New,
343}
344
345impl<K> fmt::Debug for Secret<K> {
346	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
347		match self {
348			Self::Input(_) => f.debug_tuple("Secret::Input").finish(),
349			Self::File(path) => f.debug_tuple("Secret::File").field(path).finish(),
350			Self::New => f.debug_tuple("Secret::New").finish(),
351		}
352	}
353}
354
355impl NodeKeyConfig {
356	/// Evaluate a `NodeKeyConfig` to obtain an identity `Keypair`:
357	///
358	///  * If the secret is configured as input, the corresponding keypair is returned.
359	///
360	///  * If the secret is configured as a file, it is read from that file, if it exists. Otherwise
361	///    a new secret is generated and stored. In either case, the keypair obtained from the
362	///    secret is returned.
363	///
364	///  * If the secret is configured to be new, it is generated and the corresponding keypair is
365	///    returned.
366	pub fn into_keypair(self) -> io::Result<ed25519::Keypair> {
367		use NodeKeyConfig::*;
368		match self {
369			Ed25519(Secret::New) => Ok(ed25519::Keypair::generate()),
370
371			Ed25519(Secret::Input(k)) => Ok(ed25519::Keypair::from(k).into()),
372
373			Ed25519(Secret::File(f)) => get_secret(
374				f,
375				|mut b| match String::from_utf8(b.to_vec()).ok().and_then(|s| {
376					if s.len() == 64 {
377						array_bytes::hex2bytes(&s).ok()
378					} else {
379						None
380					}
381				}) {
382					Some(s) => ed25519::SecretKey::try_from_bytes(s),
383					_ => ed25519::SecretKey::try_from_bytes(&mut b),
384				},
385				ed25519::SecretKey::generate,
386				|b| b.as_ref().to_vec(),
387			)
388			.map(ed25519::Keypair::from),
389		}
390	}
391}
392
393/// Load a secret key from a file, if it exists, or generate a
394/// new secret key and write it to that file. In either case,
395/// the secret key is returned.
396fn get_secret<P, F, G, E, W, K>(file: P, parse: F, generate: G, serialize: W) -> io::Result<K>
397where
398	P: AsRef<Path>,
399	F: for<'r> FnOnce(&'r mut [u8]) -> Result<K, E>,
400	G: FnOnce() -> K,
401	E: Error + Send + Sync + 'static,
402	W: Fn(&K) -> Vec<u8>,
403{
404	std::fs::read(&file)
405		.and_then(|mut sk_bytes| {
406			parse(&mut sk_bytes).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
407		})
408		.or_else(|e| {
409			if e.kind() == io::ErrorKind::NotFound {
410				file.as_ref().parent().map_or(Ok(()), fs::create_dir_all)?;
411				let sk = generate();
412				let mut sk_vec = serialize(&sk);
413				write_secret_file(file, &sk_vec)?;
414				sk_vec.zeroize();
415				Ok(sk)
416			} else {
417				Err(e)
418			}
419		})
420}
421
422/// Write secret bytes to a file.
423fn write_secret_file<P>(path: P, sk_bytes: &[u8]) -> io::Result<()>
424where
425	P: AsRef<Path>,
426{
427	let mut file = open_secret_file(&path)?;
428	file.write_all(sk_bytes)
429}
430
431/// Opens a file containing a secret key in write mode.
432#[cfg(unix)]
433fn open_secret_file<P>(path: P) -> io::Result<fs::File>
434where
435	P: AsRef<Path>,
436{
437	use std::os::unix::fs::OpenOptionsExt;
438	fs::OpenOptions::new().write(true).create_new(true).mode(0o600).open(path)
439}
440
441/// Opens a file containing a secret key in write mode.
442#[cfg(not(unix))]
443fn open_secret_file<P>(path: P) -> Result<fs::File, io::Error>
444where
445	P: AsRef<Path>,
446{
447	fs::OpenOptions::new().write(true).create_new(true).open(path)
448}
449
450/// Configuration for a set of nodes.
451#[derive(Clone, Debug)]
452pub struct SetConfig {
453	/// Maximum allowed number of incoming substreams related to this set.
454	pub in_peers: u32,
455
456	/// Number of outgoing substreams related to this set that we're trying to maintain.
457	pub out_peers: u32,
458
459	/// List of reserved node addresses.
460	pub reserved_nodes: Vec<MultiaddrWithPeerId>,
461
462	/// Whether nodes that aren't in [`SetConfig::reserved_nodes`] are accepted or automatically
463	/// refused.
464	pub non_reserved_mode: NonReservedPeerMode,
465}
466
467impl Default for SetConfig {
468	fn default() -> Self {
469		Self {
470			in_peers: 25,
471			out_peers: 75,
472			reserved_nodes: Vec::new(),
473			non_reserved_mode: NonReservedPeerMode::Accept,
474		}
475	}
476}
477
478/// Extension to [`SetConfig`] for sets that aren't the default set.
479///
480/// > **Note**: As new fields might be added in the future, please consider using the `new` method
481/// >			and modifiers instead of creating this struct manually.
482#[derive(Debug)]
483pub struct NonDefaultSetConfig {
484	/// Name of the notifications protocols of this set. A substream on this set will be
485	/// considered established once this protocol is open.
486	///
487	/// > **Note**: This field isn't present for the default set, as this is handled internally
488	/// > by the networking code.
489	protocol_name: ProtocolName,
490
491	/// If the remote reports that it doesn't support the protocol indicated in the
492	/// `notifications_protocol` field, then each of these fallback names will be tried one by
493	/// one.
494	///
495	/// If a fallback is used, it will be reported in
496	/// `sc_network::protocol::event::Event::NotificationStreamOpened::negotiated_fallback`
497	fallback_names: Vec<ProtocolName>,
498
499	/// Handshake of the protocol
500	///
501	/// NOTE: Currently custom handshakes are not fully supported. See issue #5685 for more
502	/// details. This field is temporarily used to allow moving the hardcoded block announcement
503	/// protocol out of `protocol.rs`.
504	handshake: Option<NotificationHandshake>,
505
506	/// Maximum allowed size of single notifications.
507	max_notification_size: u64,
508
509	/// Base configuration.
510	set_config: SetConfig,
511
512	/// Notification handle.
513	///
514	/// Notification handle is created during `NonDefaultSetConfig` creation and its other half,
515	/// `Box<dyn NotificationService>` is given to the protocol created the config and
516	/// `ProtocolHandle` is given to `Notifications` when it initializes itself. This handle allows
517	/// `Notifications ` to communicate with the protocol directly without relaying events through
518	/// `sc-network.`
519	protocol_handle_pair: ProtocolHandlePair,
520}
521
522impl NonDefaultSetConfig {
523	/// Creates a new [`NonDefaultSetConfig`]. Zero slots and accepts only reserved nodes.
524	/// Also returns an object which allows the protocol to communicate with `Notifications`.
525	pub fn new(
526		protocol_name: ProtocolName,
527		fallback_names: Vec<ProtocolName>,
528		max_notification_size: u64,
529		handshake: Option<NotificationHandshake>,
530		set_config: SetConfig,
531	) -> (Self, Box<dyn NotificationService>) {
532		let (protocol_handle_pair, notification_service) =
533			notification_service(protocol_name.clone());
534		(
535			Self {
536				protocol_name,
537				max_notification_size,
538				fallback_names,
539				handshake,
540				set_config,
541				protocol_handle_pair,
542			},
543			notification_service,
544		)
545	}
546
547	/// Get reference to protocol name.
548	pub fn protocol_name(&self) -> &ProtocolName {
549		&self.protocol_name
550	}
551
552	/// Get reference to fallback protocol names.
553	pub fn fallback_names(&self) -> impl Iterator<Item = &ProtocolName> {
554		self.fallback_names.iter()
555	}
556
557	/// Get reference to handshake.
558	pub fn handshake(&self) -> &Option<NotificationHandshake> {
559		&self.handshake
560	}
561
562	/// Get maximum notification size.
563	pub fn max_notification_size(&self) -> u64 {
564		self.max_notification_size
565	}
566
567	/// Get reference to `SetConfig`.
568	pub fn set_config(&self) -> &SetConfig {
569		&self.set_config
570	}
571
572	/// Take `ProtocolHandlePair` from `NonDefaultSetConfig`
573	pub fn take_protocol_handle(self) -> ProtocolHandlePair {
574		self.protocol_handle_pair
575	}
576
577	/// Modifies the configuration to allow non-reserved nodes.
578	pub fn allow_non_reserved(&mut self, in_peers: u32, out_peers: u32) {
579		self.set_config.in_peers = in_peers;
580		self.set_config.out_peers = out_peers;
581		self.set_config.non_reserved_mode = NonReservedPeerMode::Accept;
582	}
583
584	/// Add a node to the list of reserved nodes.
585	pub fn add_reserved(&mut self, peer: MultiaddrWithPeerId) {
586		self.set_config.reserved_nodes.push(peer);
587	}
588
589	/// Add a list of protocol names used for backward compatibility.
590	///
591	/// See the explanations in [`NonDefaultSetConfig::fallback_names`].
592	pub fn add_fallback_names(&mut self, fallback_names: Vec<ProtocolName>) {
593		self.fallback_names.extend(fallback_names);
594	}
595}
596
597impl NotificationConfig for NonDefaultSetConfig {
598	fn set_config(&self) -> &SetConfig {
599		&self.set_config
600	}
601
602	/// Get reference to protocol name.
603	fn protocol_name(&self) -> &ProtocolName {
604		&self.protocol_name
605	}
606}
607
608/// Network service configuration.
609#[derive(Clone, Debug)]
610pub struct NetworkConfiguration {
611	/// Directory path to store network-specific configuration. None means nothing will be saved.
612	pub net_config_path: Option<PathBuf>,
613
614	/// Multiaddresses to listen for incoming connections.
615	pub listen_addresses: Vec<Multiaddr>,
616
617	/// Multiaddresses to advertise. Detected automatically if empty.
618	pub public_addresses: Vec<Multiaddr>,
619
620	/// List of initial node addresses
621	pub boot_nodes: Vec<MultiaddrWithPeerId>,
622
623	/// The node key configuration, which determines the node's network identity keypair.
624	pub node_key: NodeKeyConfig,
625
626	/// Configuration for the default set of nodes used for block syncing and transactions.
627	pub default_peers_set: SetConfig,
628
629	/// Number of substreams to reserve for full nodes for block syncing and transactions.
630	/// Any other slot will be dedicated to light nodes.
631	///
632	/// This value is implicitly capped to `default_set.out_peers + default_set.in_peers`.
633	pub default_peers_set_num_full: u32,
634
635	/// Client identifier. Sent over the wire for debugging purposes.
636	pub client_version: String,
637
638	/// Name of the node. Sent over the wire for debugging purposes.
639	pub node_name: String,
640
641	/// Configuration for the transport layer.
642	pub transport: TransportConfig,
643
644	/// Idle connection timeout.
645	///
646	/// Set by default to [`DEFAULT_IDLE_CONNECTION_TIMEOUT`].
647	pub idle_connection_timeout: Duration,
648
649	/// Maximum number of peers to ask the same blocks in parallel.
650	pub max_parallel_downloads: u32,
651
652	/// Maximum number of blocks per request.
653	pub max_blocks_per_request: u32,
654
655	/// Number of peers that need to be connected before warp sync is started.
656	pub min_peers_to_start_warp_sync: Option<usize>,
657
658	/// Initial syncing mode.
659	pub sync_mode: SyncMode,
660
661	/// True if Kademlia random discovery should be enabled.
662	///
663	/// If true, the node will automatically randomly walk the DHT in order to find new peers.
664	pub enable_dht_random_walk: bool,
665
666	/// Should we insert non-global addresses into the DHT?
667	pub allow_non_globals_in_dht: bool,
668
669	/// Require iterative Kademlia DHT queries to use disjoint paths for increased resiliency in
670	/// the presence of potentially adversarial nodes.
671	pub kademlia_disjoint_query_paths: bool,
672
673	/// Kademlia replication factor determines to how many closest peers a record is replicated to.
674	///
675	/// Discovery mechanism requires successful replication to all
676	/// `kademlia_replication_factor` peers to consider record successfully put.
677	pub kademlia_replication_factor: NonZeroUsize,
678
679	/// Enable serving block data over IPFS bitswap.
680	pub ipfs_server: bool,
681
682	/// Networking backend used for P2P communication.
683	pub network_backend: NetworkBackendType,
684}
685
686impl NetworkConfiguration {
687	/// Create new default configuration
688	pub fn new<SN: Into<String>, SV: Into<String>>(
689		node_name: SN,
690		client_version: SV,
691		node_key: NodeKeyConfig,
692		net_config_path: Option<PathBuf>,
693	) -> Self {
694		let default_peers_set = SetConfig::default();
695		Self {
696			net_config_path,
697			listen_addresses: Vec::new(),
698			public_addresses: Vec::new(),
699			boot_nodes: Vec::new(),
700			node_key,
701			default_peers_set_num_full: default_peers_set.in_peers + default_peers_set.out_peers,
702			default_peers_set,
703			client_version: client_version.into(),
704			node_name: node_name.into(),
705			transport: TransportConfig::Normal { enable_mdns: false, allow_private_ip: true },
706			idle_connection_timeout: DEFAULT_IDLE_CONNECTION_TIMEOUT,
707			max_parallel_downloads: 5,
708			max_blocks_per_request: 64,
709			min_peers_to_start_warp_sync: None,
710			sync_mode: SyncMode::Full,
711			enable_dht_random_walk: true,
712			allow_non_globals_in_dht: false,
713			kademlia_disjoint_query_paths: false,
714			kademlia_replication_factor: NonZeroUsize::new(DEFAULT_KADEMLIA_REPLICATION_FACTOR)
715				.expect("value is a constant; constant is non-zero; qed."),
716			ipfs_server: false,
717			network_backend: NetworkBackendType::Litep2p,
718		}
719	}
720
721	/// Create new default configuration for localhost-only connection with random port (useful for
722	/// testing)
723	pub fn new_local() -> NetworkConfiguration {
724		let mut config =
725			NetworkConfiguration::new("test-node", "test-client", Default::default(), None);
726
727		config.listen_addresses =
728			vec![iter::once(multiaddr::Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1)))
729				.chain(iter::once(multiaddr::Protocol::Tcp(0)))
730				.collect()];
731
732		config.allow_non_globals_in_dht = true;
733		config
734	}
735
736	/// Create new default configuration for localhost-only connection with random port (useful for
737	/// testing)
738	pub fn new_memory() -> NetworkConfiguration {
739		let mut config =
740			NetworkConfiguration::new("test-node", "test-client", Default::default(), None);
741
742		config.listen_addresses =
743			vec![iter::once(multiaddr::Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1)))
744				.chain(iter::once(multiaddr::Protocol::Tcp(0)))
745				.collect()];
746
747		config.allow_non_globals_in_dht = true;
748		config
749	}
750}
751
752/// Network initialization parameters.
753pub struct Params<Block: BlockT, H: ExHashT, N: NetworkBackend<Block, H>> {
754	/// Assigned role for our node (full, light, ...).
755	pub role: Role,
756
757	/// How to spawn background tasks.
758	pub executor: Box<dyn Fn(Pin<Box<dyn Future<Output = ()> + Send>>) + Send + Sync>,
759
760	/// Network layer configuration.
761	pub network_config: FullNetworkConfiguration<Block, H, N>,
762
763	/// Legacy name of the protocol to use on the wire. Should be different for each chain.
764	pub protocol_id: ProtocolId,
765
766	/// Genesis hash of the chain
767	pub genesis_hash: Block::Hash,
768
769	/// Fork ID to distinguish protocols of different hard forks. Part of the standard protocol
770	/// name on the wire.
771	pub fork_id: Option<String>,
772
773	/// Registry for recording prometheus metrics to.
774	pub metrics_registry: Option<Registry>,
775
776	/// Block announce protocol configuration
777	pub block_announce_config: N::NotificationProtocolConfig,
778
779	/// Bitswap configuration, if the server has been enabled.
780	pub bitswap_config: Option<N::BitswapConfig>,
781
782	/// Notification metrics.
783	pub notification_metrics: NotificationMetrics,
784}
785
786/// Full network configuration.
787pub struct FullNetworkConfiguration<B: BlockT + 'static, H: ExHashT, N: NetworkBackend<B, H>> {
788	/// Installed notification protocols.
789	pub(crate) notification_protocols: Vec<N::NotificationProtocolConfig>,
790
791	/// List of request-response protocols that the node supports.
792	pub(crate) request_response_protocols: Vec<N::RequestResponseProtocolConfig>,
793
794	/// Network configuration.
795	pub network_config: NetworkConfiguration,
796
797	/// [`PeerStore`](crate::peer_store::PeerStore),
798	peer_store: Option<N::PeerStore>,
799
800	/// Handle to [`PeerStore`](crate::peer_store::PeerStore).
801	peer_store_handle: Arc<dyn PeerStoreProvider>,
802
803	/// Registry for recording prometheus metrics to.
804	pub metrics_registry: Option<Registry>,
805}
806
807impl<B: BlockT + 'static, H: ExHashT, N: NetworkBackend<B, H>> FullNetworkConfiguration<B, H, N> {
808	/// Create new [`FullNetworkConfiguration`].
809	pub fn new(network_config: &NetworkConfiguration, metrics_registry: Option<Registry>) -> Self {
810		let bootnodes = network_config.boot_nodes.iter().map(|bootnode| bootnode.peer_id).collect();
811		let peer_store = N::peer_store(bootnodes, metrics_registry.clone());
812		let peer_store_handle = peer_store.handle();
813
814		Self {
815			peer_store: Some(peer_store),
816			peer_store_handle,
817			notification_protocols: Vec::new(),
818			request_response_protocols: Vec::new(),
819			network_config: network_config.clone(),
820			metrics_registry,
821		}
822	}
823
824	/// Add a notification protocol.
825	pub fn add_notification_protocol(&mut self, config: N::NotificationProtocolConfig) {
826		self.notification_protocols.push(config);
827	}
828
829	/// Get reference to installed notification protocols.
830	pub fn notification_protocols(&self) -> &Vec<N::NotificationProtocolConfig> {
831		&self.notification_protocols
832	}
833
834	/// Add a request-response protocol.
835	pub fn add_request_response_protocol(&mut self, config: N::RequestResponseProtocolConfig) {
836		self.request_response_protocols.push(config);
837	}
838
839	/// Get handle to [`PeerStore`].
840	pub fn peer_store_handle(&self) -> Arc<dyn PeerStoreProvider> {
841		Arc::clone(&self.peer_store_handle)
842	}
843
844	/// Take [`PeerStore`].
845	///
846	/// `PeerStore` is created when `FullNetworkConfig` is initialized so that `PeerStoreHandle`s
847	/// can be passed onto notification protocols. `PeerStore` itself should be started only once
848	/// and since technically it's not a libp2p task, it should be started with `SpawnHandle` in
849	/// `builder.rs` instead of using the libp2p/litep2p executor in the networking backend. This
850	/// function consumes `PeerStore` and starts its event loop in the appropriate place.
851	pub fn take_peer_store(&mut self) -> N::PeerStore {
852		self.peer_store
853			.take()
854			.expect("`PeerStore` can only be taken once when it's started; qed")
855	}
856
857	/// Verify addresses are consistent with enabled transports.
858	pub fn sanity_check_addresses(&self) -> Result<(), crate::error::Error> {
859		ensure_addresses_consistent_with_transport(
860			self.network_config.listen_addresses.iter(),
861			&self.network_config.transport,
862		)?;
863		ensure_addresses_consistent_with_transport(
864			self.network_config.boot_nodes.iter().map(|x| &x.multiaddr),
865			&self.network_config.transport,
866		)?;
867		ensure_addresses_consistent_with_transport(
868			self.network_config
869				.default_peers_set
870				.reserved_nodes
871				.iter()
872				.map(|x| &x.multiaddr),
873			&self.network_config.transport,
874		)?;
875
876		for notification_protocol in &self.notification_protocols {
877			ensure_addresses_consistent_with_transport(
878				notification_protocol.set_config().reserved_nodes.iter().map(|x| &x.multiaddr),
879				&self.network_config.transport,
880			)?;
881		}
882		ensure_addresses_consistent_with_transport(
883			self.network_config.public_addresses.iter(),
884			&self.network_config.transport,
885		)?;
886
887		Ok(())
888	}
889
890	/// Check for duplicate bootnodes.
891	pub fn sanity_check_bootnodes(&self) -> Result<(), crate::error::Error> {
892		self.network_config.boot_nodes.iter().try_for_each(|bootnode| {
893			if let Some(other) = self
894				.network_config
895				.boot_nodes
896				.iter()
897				.filter(|o| o.multiaddr == bootnode.multiaddr)
898				.find(|o| o.peer_id != bootnode.peer_id)
899			{
900				Err(crate::error::Error::DuplicateBootnode {
901					address: bootnode.multiaddr.clone().into(),
902					first_id: bootnode.peer_id.into(),
903					second_id: other.peer_id.into(),
904				})
905			} else {
906				Ok(())
907			}
908		})
909	}
910
911	/// Collect all reserved nodes and bootnodes addresses.
912	pub fn known_addresses(&self) -> Vec<(PeerId, Multiaddr)> {
913		let mut addresses: Vec<_> = self
914			.network_config
915			.default_peers_set
916			.reserved_nodes
917			.iter()
918			.map(|reserved| (reserved.peer_id, reserved.multiaddr.clone()))
919			.chain(self.notification_protocols.iter().flat_map(|protocol| {
920				protocol
921					.set_config()
922					.reserved_nodes
923					.iter()
924					.map(|reserved| (reserved.peer_id, reserved.multiaddr.clone()))
925			}))
926			.chain(
927				self.network_config
928					.boot_nodes
929					.iter()
930					.map(|bootnode| (bootnode.peer_id, bootnode.multiaddr.clone())),
931			)
932			.collect();
933
934		// Remove possible duplicates.
935		addresses.sort();
936		addresses.dedup();
937
938		addresses
939	}
940}
941
942/// Network backend type.
943#[derive(Debug, Clone, Default, Copy)]
944pub enum NetworkBackendType {
945	/// Use litep2p for P2P networking.
946	///
947	/// This is the preferred option for Substrate-based chains.
948	#[default]
949	Litep2p,
950
951	/// Use libp2p for P2P networking.
952	///
953	/// The libp2p is still used for compatibility reasons until the
954	/// ecosystem switches entirely to litep2p. The backend will enter
955	/// a "best-effort" maintenance mode, where only critical issues will
956	/// get fixed. If you are unsure, please use `NetworkBackendType::Litep2p`.
957	Libp2p,
958}
959
960#[cfg(test)]
961mod tests {
962	use super::*;
963	use tempfile::TempDir;
964
965	fn tempdir_with_prefix(prefix: &str) -> TempDir {
966		tempfile::Builder::new().prefix(prefix).tempdir().unwrap()
967	}
968
969	fn secret_bytes(kp: ed25519::Keypair) -> Vec<u8> {
970		kp.secret().to_bytes().into()
971	}
972
973	#[test]
974	fn test_secret_file() {
975		let tmp = tempdir_with_prefix("x");
976		std::fs::remove_dir(tmp.path()).unwrap(); // should be recreated
977		let file = tmp.path().join("x").to_path_buf();
978		let kp1 = NodeKeyConfig::Ed25519(Secret::File(file.clone())).into_keypair().unwrap();
979		let kp2 = NodeKeyConfig::Ed25519(Secret::File(file.clone())).into_keypair().unwrap();
980		assert!(file.is_file() && secret_bytes(kp1) == secret_bytes(kp2))
981	}
982
983	#[test]
984	fn test_secret_input() {
985		let sk = ed25519::SecretKey::generate();
986		let kp1 = NodeKeyConfig::Ed25519(Secret::Input(sk.clone())).into_keypair().unwrap();
987		let kp2 = NodeKeyConfig::Ed25519(Secret::Input(sk)).into_keypair().unwrap();
988		assert!(secret_bytes(kp1) == secret_bytes(kp2));
989	}
990
991	#[test]
992	fn test_secret_new() {
993		let kp1 = NodeKeyConfig::Ed25519(Secret::New).into_keypair().unwrap();
994		let kp2 = NodeKeyConfig::Ed25519(Secret::New).into_keypair().unwrap();
995		assert!(secret_bytes(kp1) != secret_bytes(kp2));
996	}
997}