cumulus_client_bootnodes/
task.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Cumulus.
3// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
4
5// Cumulus is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9
10// Cumulus is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13// GNU General Public License for more details.
14
15// You should have received a copy of the GNU General Public License
16// along with Cumulus.  If not, see <http://www.gnu.org/licenses/>.
17
18//! Parachain bootnodes advertisement and discovery service.
19
20use crate::{
21	advertisement::{BootnodeAdvertisement, BootnodeAdvertisementParams},
22	config::paranode_protocol_name,
23	discovery::{BootnodeDiscovery, BootnodeDiscoveryParams},
24};
25use cumulus_primitives_core::{relay_chain::BlockId, ParaId};
26use cumulus_relay_chain_interface::RelayChainInterface;
27use log::{debug, error};
28use num_traits::Zero;
29use sc_network::{request_responses::IncomingRequest, service::traits::NetworkService, Multiaddr};
30use sc_service::TaskManager;
31use std::sync::Arc;
32
33/// Log target for this crate.
34const LOG_TARGET: &str = "bootnodes";
35
36/// Bootnode advertisement task params.
37pub struct StartBootnodeTasksParams<'a> {
38	/// Enable embedded DHT bootnode.
39	pub embedded_dht_bootnode: bool,
40	/// Enable DHT bootnode discovery.
41	pub dht_bootnode_discovery: bool,
42	/// Parachain ID.
43	pub para_id: ParaId,
44	/// Task manager.
45	pub task_manager: &'a mut TaskManager,
46	/// Relay chain interface.
47	pub relay_chain_interface: Arc<dyn RelayChainInterface>,
48	/// Relay chain fork ID.
49	pub relay_chain_fork_id: Option<String>,
50	/// Relay chain network service.
51	pub relay_chain_network: Arc<dyn NetworkService>,
52	/// `/paranode` protocol request receiver.
53	pub request_receiver: async_channel::Receiver<IncomingRequest>,
54	/// Parachain node network service.
55	pub parachain_network: Arc<dyn NetworkService>,
56	/// Whether to advertise non-global IP addresses.
57	pub advertise_non_global_ips: bool,
58	/// Parachain genesis hash.
59	pub parachain_genesis_hash: Vec<u8>,
60	/// Parachain fork ID.
61	pub parachain_fork_id: Option<String>,
62	/// Parachain public addresses provided by the operator.
63	pub parachain_public_addresses: Vec<Multiaddr>,
64}
65
66async fn bootnode_advertisement(
67	para_id: ParaId,
68	relay_chain_interface: Arc<dyn RelayChainInterface>,
69	relay_chain_network: Arc<dyn NetworkService>,
70	request_receiver: async_channel::Receiver<IncomingRequest>,
71	parachain_network: Arc<dyn NetworkService>,
72	advertise_non_global_ips: bool,
73	parachain_genesis_hash: Vec<u8>,
74	parachain_fork_id: Option<String>,
75	public_addresses: Vec<Multiaddr>,
76) {
77	let bootnode_advertisement = BootnodeAdvertisement::new(BootnodeAdvertisementParams {
78		para_id,
79		relay_chain_interface,
80		relay_chain_network,
81		request_receiver,
82		parachain_network,
83		advertise_non_global_ips,
84		parachain_genesis_hash,
85		parachain_fork_id,
86		public_addresses,
87	});
88
89	if let Err(e) = bootnode_advertisement.run().await {
90		error!(target: LOG_TARGET, "Bootnode advertisement terminated with error: {e}");
91	}
92}
93
94async fn bootnode_discovery(
95	para_id: ParaId,
96	parachain_network: Arc<dyn NetworkService>,
97	parachain_genesis_hash: Vec<u8>,
98	parachain_fork_id: Option<String>,
99	relay_chain_interface: Arc<dyn RelayChainInterface>,
100	relay_chain_fork_id: Option<String>,
101	relay_chain_network: Arc<dyn NetworkService>,
102) {
103	let relay_chain_genesis_hash =
104		match relay_chain_interface.header(BlockId::Number(Zero::zero())).await {
105			Ok(Some(header)) => header.hash().as_bytes().to_vec(),
106			Ok(None) => {
107				error!(
108					target: LOG_TARGET,
109					"Bootnode discovery: relay chain genesis hash does not exist",
110				);
111				// Make essential task fail.
112				return;
113			},
114			Err(e) => {
115				error!(
116					target: LOG_TARGET,
117					"Bootnode discovery: failed to obtain relay chain genesis hash: {e}",
118				);
119				// Make essential task fail.
120				return;
121			},
122		};
123
124	let paranode_protocol_name =
125		paranode_protocol_name(relay_chain_genesis_hash, relay_chain_fork_id.as_deref());
126
127	let bootnode_discovery = BootnodeDiscovery::new(BootnodeDiscoveryParams {
128		para_id,
129		parachain_network,
130		parachain_genesis_hash,
131		parachain_fork_id,
132		relay_chain_interface,
133		relay_chain_network,
134		paranode_protocol_name,
135	});
136
137	match bootnode_discovery.run().await {
138		// Do not terminate the essentil task if bootnode discovery succeeded.
139		Ok(()) => std::future::pending().await,
140		Err(e) => error!(target: LOG_TARGET, "Bootnode discovery terminated with error: {e}"),
141	}
142}
143
144/// Start parachain bootnode advertisement and discovery tasks.
145pub fn start_bootnode_tasks(
146	StartBootnodeTasksParams {
147		embedded_dht_bootnode,
148		dht_bootnode_discovery,
149		para_id,
150		task_manager,
151		relay_chain_interface,
152		relay_chain_fork_id,
153		relay_chain_network,
154		request_receiver,
155		parachain_network,
156		advertise_non_global_ips,
157		parachain_genesis_hash,
158		parachain_fork_id,
159		parachain_public_addresses,
160	}: StartBootnodeTasksParams,
161) {
162	debug!(
163		target: LOG_TARGET,
164		"Embedded DHT bootnode enabled: {embedded_dht_bootnode}; \
165		 DHT bootnode discovery enabled: {dht_bootnode_discovery}",
166	);
167
168	if embedded_dht_bootnode {
169		task_manager.spawn_essential_handle().spawn(
170			"cumulus-dht-bootnode-advertisement",
171			None,
172			bootnode_advertisement(
173				para_id,
174				relay_chain_interface.clone(),
175				relay_chain_network.clone(),
176				request_receiver,
177				parachain_network.clone(),
178				advertise_non_global_ips,
179				parachain_genesis_hash.clone(),
180				parachain_fork_id.clone(),
181				parachain_public_addresses,
182			),
183		);
184	}
185
186	if dht_bootnode_discovery {
187		task_manager.spawn_essential_handle().spawn(
188			"cumulus-dht-bootnode-discovery",
189			None,
190			bootnode_discovery(
191				para_id,
192				parachain_network,
193				parachain_genesis_hash,
194				parachain_fork_id,
195				relay_chain_interface,
196				relay_chain_fork_id,
197				relay_chain_network,
198			),
199		);
200	}
201}