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