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