referrerpolicy=no-referrer-when-downgrade

sc_service/
builder.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
19use crate::{
20	build_network_future, build_system_rpc_future,
21	client::{Client, ClientConfig},
22	config::{Configuration, ExecutorConfiguration, KeystoreConfig, Multiaddr, PrometheusConfig},
23	error::Error,
24	metrics::MetricsService,
25	start_rpc_servers, BuildGenesisBlock, GenesisBlockBuilder, RpcHandlers,
26	SpawnEssentialTaskHandle, SpawnTaskHandle, TaskManager, TransactionPoolAdapter,
27};
28use futures::{select, FutureExt, StreamExt};
29use jsonrpsee::RpcModule;
30use log::{debug, error, info};
31use prometheus_endpoint::Registry;
32use sc_chain_spec::{get_extension, ChainSpec};
33use sc_client_api::{
34	execution_extensions::ExecutionExtensions, proof_provider::ProofProvider, BadBlocks,
35	BlockBackend, BlockchainEvents, ExecutorProvider, ForkBlocks, KeysIter, StorageProvider,
36	TrieCacheContext, UsageProvider,
37};
38use sc_client_db::{Backend, BlocksPruning, DatabaseSettings, PruningMode};
39use sc_consensus::import_queue::{ImportQueue, ImportQueueService};
40use sc_executor::{
41	sp_wasm_interface::HostFunctions, HeapAllocStrategy, RuntimeVersionOf, WasmExecutor,
42	DEFAULT_HEAP_ALLOC_STRATEGY,
43};
44use sc_keystore::LocalKeystore;
45use sc_network::{
46	config::{FullNetworkConfiguration, IpfsConfig, ProtocolId, SyncMode},
47	multiaddr::Protocol,
48	service::{
49		traits::{PeerStore, RequestResponseConfig},
50		NotificationMetrics,
51	},
52	IpfsIndexedTransactions, NetworkBackend, NetworkStateInfo,
53};
54use sc_network_common::role::{Role, Roles};
55use sc_network_light::light_client_requests::handler::LightClientRequestHandler;
56use sc_network_sync::{
57	block_relay_protocol::{BlockDownloader, BlockRelayParams},
58	block_request_handler::BlockRequestHandler,
59	engine::SyncingEngine,
60	service::network::{NetworkServiceHandle, NetworkServiceProvider},
61	state_request_handler::StateRequestHandler,
62	strategy::{
63		chain_sync::{GapSyncBodyPolicy, GapSyncBodyPolicyProvider},
64		polkadot::{PolkadotSyncingStrategy, PolkadotSyncingStrategyConfig},
65		SyncingStrategy,
66	},
67	warp_request_handler::RequestHandler as WarpSyncRequestHandler,
68	SyncingService, WarpSyncConfig,
69};
70use sc_rpc::{
71	author::AuthorApiServer,
72	chain::ChainApiServer,
73	offchain::OffchainApiServer,
74	state::{ChildStateApiServer, StateApiServer},
75	system::SystemApiServer,
76	DenyUnsafe, SubscriptionTaskExecutor,
77};
78use sc_rpc_spec_v2::{
79	archive::ArchiveApiServer,
80	bitswap::BitswapApiServer,
81	chain_head::ChainHeadApiServer,
82	chain_spec::ChainSpecApiServer,
83	transaction::{TransactionApiServer, TransactionBroadcastApiServer},
84};
85use sc_telemetry::{telemetry, ConnectionMessage, Telemetry, TelemetryHandle, SUBSTRATE_INFO};
86use sc_tracing::block::TracingExecuteBlock;
87use sc_transaction_pool_api::{MaintainedTransactionPool, TransactionPool};
88use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedSender};
89use sp_api::{CallApiAt, ProvideRuntimeApi};
90use sp_blockchain::{HeaderBackend, HeaderMetadata};
91use sp_consensus::block_validation::{
92	BlockAnnounceValidator, Chain, DefaultBlockAnnounceValidator,
93};
94use sp_core::traits::{CodeExecutor, SpawnNamed};
95use sp_keystore::KeystorePtr;
96use sp_runtime::traits::{Block as BlockT, NumberFor, Zero};
97use sp_storage::{ChildInfo, ChildType, PrefixedStorageKey};
98use std::{
99	str::FromStr,
100	sync::Arc,
101	time::{Duration, SystemTime},
102};
103
104/// Cap the maximum number of blocks advertized to IPFS to two weeks at 6-second block time.
105/// Block pruning depth will be used if it is shorter.
106const IPFS_MAX_BLOCKS: u32 = 201600;
107
108/// Full client type.
109pub type TFullClient<TBl, TRtApi, TExec> =
110	Client<TFullBackend<TBl>, TFullCallExecutor<TBl, TExec>, TBl, TRtApi>;
111
112/// Full client backend type.
113pub type TFullBackend<TBl> = Backend<TBl>;
114
115/// Full client call executor type.
116pub type TFullCallExecutor<TBl, TExec> = crate::client::LocalCallExecutor<TBl, Backend<TBl>, TExec>;
117
118type TFullParts<TBl, TRtApi, TExec> =
119	(TFullClient<TBl, TRtApi, TExec>, Arc<TFullBackend<TBl>>, KeystoreContainer, TaskManager);
120
121/// Construct a local keystore shareable container
122pub struct KeystoreContainer(Arc<LocalKeystore>);
123
124impl KeystoreContainer {
125	/// Construct KeystoreContainer
126	pub fn new(config: &KeystoreConfig) -> Result<Self, Error> {
127		let keystore = Arc::new(match config {
128			KeystoreConfig::Path { path, password } => {
129				LocalKeystore::open(path.clone(), password.clone())?
130			},
131			KeystoreConfig::InMemory => LocalKeystore::in_memory(),
132		});
133
134		Ok(Self(keystore))
135	}
136
137	/// Returns a shared reference to a dynamic `Keystore` trait implementation.
138	pub fn keystore(&self) -> KeystorePtr {
139		self.0.clone()
140	}
141
142	/// Returns a shared reference to the local keystore .
143	pub fn local_keystore(&self) -> Arc<LocalKeystore> {
144		self.0.clone()
145	}
146}
147
148/// Creates a new full client for the given config.
149pub fn new_full_client<TBl, TRtApi, TExec>(
150	config: &Configuration,
151	telemetry: Option<TelemetryHandle>,
152	executor: TExec,
153	pruning_filters: Vec<Arc<dyn sc_client_db::PruningFilter>>,
154) -> Result<TFullClient<TBl, TRtApi, TExec>, Error>
155where
156	TBl: BlockT,
157	TExec: CodeExecutor + RuntimeVersionOf + Clone,
158{
159	new_full_parts(config, telemetry, executor, pruning_filters).map(|parts| parts.0)
160}
161
162/// Create the initial parts of a full node with the default genesis block builder.
163///
164/// The `pruning_filters` parameter allows configuring which blocks should be preserved
165/// during pruning.
166pub fn new_full_parts_record_import<TBl, TRtApi, TExec>(
167	config: &Configuration,
168	telemetry: Option<TelemetryHandle>,
169	executor: TExec,
170	enable_import_proof_recording: bool,
171	pruning_filters: Vec<Arc<dyn sc_client_db::PruningFilter>>,
172) -> Result<TFullParts<TBl, TRtApi, TExec>, Error>
173where
174	TBl: BlockT,
175	TExec: CodeExecutor + RuntimeVersionOf + Clone,
176{
177	let mut db_config = config.db_config();
178	db_config.pruning_filters = pruning_filters;
179	let backend = new_db_backend(db_config)?;
180
181	let genesis_block_builder = GenesisBlockBuilder::new(
182		config.chain_spec.as_storage_builder(),
183		!config.no_genesis(),
184		backend.clone(),
185		executor.clone(),
186	)?;
187
188	new_full_parts_with_genesis_builder(
189		config,
190		telemetry,
191		executor,
192		backend,
193		genesis_block_builder,
194		enable_import_proof_recording,
195	)
196}
197
198/// Create the initial parts of a full node with the default genesis block builder.
199///
200/// The `pruning_filters` parameter allows configuring which blocks should be preserved
201/// during pruning.
202pub fn new_full_parts<TBl, TRtApi, TExec>(
203	config: &Configuration,
204	telemetry: Option<TelemetryHandle>,
205	executor: TExec,
206	pruning_filters: Vec<Arc<dyn sc_client_db::PruningFilter>>,
207) -> Result<TFullParts<TBl, TRtApi, TExec>, Error>
208where
209	TBl: BlockT,
210	TExec: CodeExecutor + RuntimeVersionOf + Clone,
211{
212	new_full_parts_record_import(config, telemetry, executor, false, pruning_filters)
213}
214
215/// Create the initial parts of a full node.
216pub fn new_full_parts_with_genesis_builder<TBl, TRtApi, TExec, TBuildGenesisBlock>(
217	config: &Configuration,
218	telemetry: Option<TelemetryHandle>,
219	executor: TExec,
220	backend: Arc<TFullBackend<TBl>>,
221	genesis_block_builder: TBuildGenesisBlock,
222	enable_import_proof_recording: bool,
223) -> Result<TFullParts<TBl, TRtApi, TExec>, Error>
224where
225	TBl: BlockT,
226	TExec: CodeExecutor + RuntimeVersionOf + Clone,
227	TBuildGenesisBlock: BuildGenesisBlock<
228		TBl,
229		BlockImportOperation = <Backend<TBl> as sc_client_api::backend::Backend<TBl>>::BlockImportOperation
230	>,
231{
232	let keystore_container = KeystoreContainer::new(&config.keystore)?;
233
234	let task_manager = {
235		let registry = config.prometheus_config.as_ref().map(|cfg| &cfg.registry);
236		TaskManager::new(config.tokio_handle.clone(), registry)?
237	};
238
239	let chain_spec = &config.chain_spec;
240	let fork_blocks = get_extension::<ForkBlocks<TBl>>(chain_spec.extensions())
241		.cloned()
242		.unwrap_or_default();
243
244	let bad_blocks = get_extension::<BadBlocks<TBl>>(chain_spec.extensions())
245		.cloned()
246		.unwrap_or_default();
247
248	let client = {
249		let extensions = ExecutionExtensions::new(None, Arc::new(executor.clone()));
250
251		let wasm_runtime_substitutes = config
252			.chain_spec
253			.code_substitutes()
254			.into_iter()
255			.map(|(n, c)| {
256				let number = NumberFor::<TBl>::from_str(&n).map_err(|_| {
257					Error::Application(Box::from(format!(
258						"Failed to parse `{}` as block number for code substitutes. \
259						 In an old version the key for code substitute was a block hash. \
260						 Please update the chain spec to a version that is compatible with your node.",
261						n
262					)))
263				})?;
264				Ok((number, c))
265			})
266			.collect::<Result<std::collections::HashMap<_, _>, Error>>()?;
267
268		let client = new_client(
269			backend.clone(),
270			executor,
271			genesis_block_builder,
272			fork_blocks,
273			bad_blocks,
274			extensions,
275			Box::new(task_manager.spawn_handle()),
276			config.prometheus_config.as_ref().map(|config| config.registry.clone()),
277			telemetry,
278			ClientConfig {
279				offchain_worker_enabled: config.offchain_worker.enabled,
280				offchain_indexing_api: config.offchain_worker.indexing_enabled,
281				wasm_runtime_overrides: config.wasm_runtime_overrides.clone(),
282				no_genesis: config.no_genesis(),
283				wasm_runtime_substitutes,
284				enable_import_proof_recording,
285			},
286		)?;
287
288		if let Some(warm_up_strategy) = config.warm_up_trie_cache {
289			let storage_root = client.usage_info().chain.best_hash;
290			let backend_clone = backend.clone();
291
292			if warm_up_strategy.is_blocking() {
293				// We use the blocking strategy for testing purposes.
294				// So better to error out if it fails.
295				warm_up_trie_cache(backend_clone, storage_root)?;
296			} else {
297				task_manager.spawn_handle().spawn_blocking(
298					"warm-up-trie-cache",
299					None,
300					async move {
301						if let Err(e) = warm_up_trie_cache(backend_clone, storage_root) {
302							error!("Failed to warm up trie cache: {e}");
303						}
304					},
305				);
306			}
307		}
308
309		client
310	};
311
312	Ok((client, backend, keystore_container, task_manager))
313}
314
315fn child_info(key: Vec<u8>) -> Option<ChildInfo> {
316	let prefixed_key = PrefixedStorageKey::new(key);
317	ChildType::from_prefixed_key(&prefixed_key).and_then(|(child_type, storage_key)| {
318		(child_type == ChildType::ParentKeyId).then(|| ChildInfo::new_default(storage_key))
319	})
320}
321
322fn warm_up_trie_cache<TBl: BlockT>(
323	backend: Arc<TFullBackend<TBl>>,
324	storage_root: TBl::Hash,
325) -> Result<(), Error> {
326	use sc_client_api::backend::Backend;
327	use sp_state_machine::Backend as StateBackend;
328
329	let untrusted_state = || backend.state_at(storage_root, TrieCacheContext::Untrusted);
330	let trusted_state = || backend.state_at(storage_root, TrieCacheContext::Trusted);
331
332	debug!("Populating trie cache started",);
333	let start_time = std::time::Instant::now();
334	let mut keys_count = 0;
335	let mut child_keys_count = 0;
336	for key in KeysIter::<_, TBl>::new(untrusted_state()?, None, None)? {
337		if keys_count != 0 && keys_count % 100_000 == 0 {
338			debug!("{} keys and {} child keys have been warmed", keys_count, child_keys_count);
339		}
340		match child_info(key.0.clone()) {
341			Some(info) => {
342				for child_key in
343					KeysIter::<_, TBl>::new_child(untrusted_state()?, info.clone(), None, None)?
344				{
345					if trusted_state()?
346						.child_storage(&info, &child_key.0)
347						.unwrap_or_default()
348						.is_none()
349					{
350						debug!("Child storage value unexpectedly empty: {child_key:?}");
351					}
352					child_keys_count += 1;
353				}
354			},
355			None => {
356				if trusted_state()?.storage(&key.0).unwrap_or_default().is_none() {
357					debug!("Storage value unexpectedly empty: {key:?}");
358				}
359				keys_count += 1;
360			},
361		}
362	}
363	debug!(
364		"Trie cache populated with {keys_count} keys and {child_keys_count} child keys in {} s",
365		start_time.elapsed().as_secs_f32()
366	);
367
368	Ok(())
369}
370
371/// Creates a [`WasmExecutor`] according to [`ExecutorConfiguration`].
372pub fn new_wasm_executor<H: HostFunctions>(config: &ExecutorConfiguration) -> WasmExecutor<H> {
373	let strategy = config
374		.default_heap_pages
375		.map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |p| HeapAllocStrategy::Static { extra_pages: p as _ });
376	WasmExecutor::<H>::builder()
377		.with_execution_method(config.wasm_method)
378		.with_onchain_heap_alloc_strategy(strategy)
379		.with_offchain_heap_alloc_strategy(strategy)
380		.with_max_runtime_instances(config.max_runtime_instances)
381		.with_runtime_cache_size(config.runtime_cache_size)
382		.build()
383}
384
385/// Create an instance of the default DB-backend.
386///
387/// Pruning filters can be configured via `settings.pruning_filters`.
388/// If any filter returns `true` for a block's justifications, the block will not be pruned.
389pub fn new_db_backend<Block>(
390	settings: DatabaseSettings,
391) -> Result<Arc<Backend<Block>>, sp_blockchain::Error>
392where
393	Block: BlockT,
394{
395	const CANONICALIZATION_DELAY: u64 = 4096;
396
397	Ok(Arc::new(Backend::new(settings, CANONICALIZATION_DELAY)?))
398}
399
400/// Create an instance of client backed by given backend.
401pub fn new_client<E, Block, RA, G>(
402	backend: Arc<Backend<Block>>,
403	executor: E,
404	genesis_block_builder: G,
405	fork_blocks: ForkBlocks<Block>,
406	bad_blocks: BadBlocks<Block>,
407	execution_extensions: ExecutionExtensions<Block>,
408	spawn_handle: Box<dyn SpawnNamed>,
409	prometheus_registry: Option<Registry>,
410	telemetry: Option<TelemetryHandle>,
411	config: ClientConfig<Block>,
412) -> Result<
413	Client<
414		Backend<Block>,
415		crate::client::LocalCallExecutor<Block, Backend<Block>, E>,
416		Block,
417		RA,
418	>,
419	sp_blockchain::Error,
420>
421where
422	Block: BlockT,
423	E: CodeExecutor + RuntimeVersionOf,
424	G: BuildGenesisBlock<
425		Block,
426		BlockImportOperation = <Backend<Block> as sc_client_api::backend::Backend<Block>>::BlockImportOperation
427	>,
428{
429	let executor = crate::client::LocalCallExecutor::new(
430		backend.clone(),
431		executor,
432		config.clone(),
433		execution_extensions,
434	)?;
435
436	Client::new(
437		backend,
438		executor,
439		spawn_handle,
440		genesis_block_builder,
441		fork_blocks,
442		bad_blocks,
443		prometheus_registry,
444		telemetry,
445		config,
446	)
447}
448
449/// The client capabilities every service entry point relies on.
450///
451/// It is blanket implemented, so every full client qualifies. Having it as a single bound keeps
452/// the client bounds readable at [`build_network`], [`build_network_advanced`], [`spawn_tasks`]
453/// and [`gen_rpc_module`], each of which adds only the few capabilities it genuinely needs on top.
454pub trait ClientForService<Block: BlockT>:
455	ProvideRuntimeApi<Block>
456	+ HeaderMetadata<Block, Error = sp_blockchain::Error>
457	+ HeaderBackend<Block>
458	+ BlockBackend<Block>
459	+ ProofProvider<Block>
460	+ BlockchainEvents<Block>
461	+ 'static
462{
463}
464
465impl<Block: BlockT, T> ClientForService<Block> for T where
466	T: ProvideRuntimeApi<Block>
467		+ HeaderMetadata<Block, Error = sp_blockchain::Error>
468		+ HeaderBackend<Block>
469		+ BlockBackend<Block>
470		+ ProofProvider<Block>
471		+ BlockchainEvents<Block>
472		+ 'static
473{
474}
475
476/// Parameters to pass into [`spawn_tasks`].
477pub struct SpawnTasksParams<'a, TBl: BlockT, TCl, TExPool: ?Sized, TRpc, Backend> {
478	/// The service configuration.
479	pub config: Configuration,
480	/// A shared client returned by `new_full_parts`.
481	pub client: Arc<TCl>,
482	/// A shared backend returned by `new_full_parts`.
483	pub backend: Arc<Backend>,
484	/// A task manager returned by `new_full_parts`.
485	pub task_manager: &'a mut TaskManager,
486	/// A shared keystore returned by `new_full_parts`.
487	pub keystore: KeystorePtr,
488	/// A shared transaction pool.
489	pub transaction_pool: Arc<TExPool>,
490	/// Builds additional [`RpcModule`]s that should be added to the server
491	pub rpc_builder: Box<dyn Fn(SubscriptionTaskExecutor) -> Result<RpcModule<TRpc>, Error>>,
492	/// A shared network instance.
493	pub network: Arc<dyn sc_network::service::traits::NetworkService>,
494	/// A Sender for RPC requests.
495	pub system_rpc_tx: TracingUnboundedSender<sc_rpc::system::Request<TBl>>,
496	/// Controller for transactions handlers
497	pub tx_handler_controller:
498		sc_network_transactions::TransactionsHandlerController<<TBl as BlockT>::Hash>,
499	/// Syncing service.
500	pub sync_service: Arc<SyncingService<TBl>>,
501	/// Telemetry instance for this node.
502	pub telemetry: Option<&'a mut Telemetry>,
503	/// Optional [`TracingExecuteBlock`] handle.
504	///
505	/// Will be used by the `trace_block` RPC to execute the actual block.
506	pub tracing_execute_block: Option<Arc<dyn TracingExecuteBlock<TBl>>>,
507}
508
509/// Spawn the tasks that are required to run a node.
510pub fn spawn_tasks<TBl, TBackend, TExPool, TRpc, TCl>(
511	SpawnTasksParams {
512		mut config,
513		task_manager,
514		client,
515		backend,
516		keystore,
517		transaction_pool,
518		rpc_builder,
519		network,
520		system_rpc_tx,
521		tx_handler_controller,
522		sync_service,
523		telemetry,
524		tracing_execute_block: execute_block,
525	}: SpawnTasksParams<TBl, TCl, TExPool, TRpc, TBackend>,
526) -> Result<RpcHandlers, Error>
527where
528	TCl: ClientForService<TBl>
529		+ Chain<TBl>
530		+ ExecutorProvider<TBl>
531		+ UsageProvider<TBl>
532		+ StorageProvider<TBl, TBackend>
533		+ CallApiAt<TBl>,
534	<TCl as ProvideRuntimeApi<TBl>>::Api:
535		sp_api::Metadata<TBl> + sp_session::SessionKeys<TBl> + sp_api::ApiExt<TBl>,
536	TBl: BlockT,
537	TBl::Hash: Unpin,
538	TBl::Header: Unpin,
539	TBackend: 'static + sc_client_api::backend::Backend<TBl> + Send,
540	TExPool:
541		MaintainedTransactionPool<Block = TBl, Hash = <TBl as BlockT>::Hash> + ?Sized + 'static,
542{
543	let chain_info = client.usage_info().chain;
544
545	sp_session::generate_initial_session_keys(
546		client.clone(),
547		chain_info.best_hash,
548		config.dev_key_seed.clone().map(|s| vec![s]).unwrap_or_default(),
549		keystore.clone(),
550	)
551	.map_err(|e| Error::Application(Box::new(e)))?;
552
553	let sysinfo = sc_sysinfo::gather_sysinfo();
554	sc_sysinfo::print_sysinfo(&sysinfo);
555
556	let telemetry = telemetry
557		.map(|telemetry| {
558			init_telemetry(
559				config.network.node_name.clone(),
560				config.impl_name.clone(),
561				config.impl_version.clone(),
562				config.chain_spec.name().to_string(),
563				config.role.is_authority(),
564				network.clone(),
565				client.clone(),
566				telemetry,
567				Some(sysinfo),
568			)
569		})
570		.transpose()?;
571
572	info!("📦 Highest known block at #{}", chain_info.best_number);
573
574	let spawn_handle = task_manager.spawn_handle();
575
576	// Inform the tx pool about imported and finalized blocks.
577	spawn_handle.spawn(
578		"txpool-notifications",
579		Some("transaction-pool"),
580		sc_transaction_pool::notification_future(
581			client.clone(),
582			transaction_pool.clone(),
583			config.transaction_pool.use_all_block_notifications(),
584		),
585	);
586
587	spawn_handle.spawn(
588		"on-transaction-imported",
589		Some("transaction-pool"),
590		propagate_transaction_notifications(
591			transaction_pool.clone(),
592			tx_handler_controller,
593			telemetry.clone(),
594		),
595	);
596
597	// Prometheus metrics.
598	let metrics_service =
599		if let Some(PrometheusConfig { port, registry }) = config.prometheus_config.clone() {
600			// Set static metrics.
601			let metrics = MetricsService::with_prometheus(
602				telemetry,
603				&registry,
604				config.role,
605				&config.network.node_name,
606				&config.impl_version,
607			)?;
608			spawn_handle.spawn(
609				"prometheus-endpoint",
610				None,
611				prometheus_endpoint::init_prometheus(port, registry).map(drop),
612			);
613
614			metrics
615		} else {
616			MetricsService::new(telemetry)
617		};
618
619	// Periodically updated metrics and telemetry updates.
620	spawn_handle.spawn(
621		"telemetry-periodic-send",
622		None,
623		metrics_service.run(
624			client.clone(),
625			transaction_pool.clone(),
626			network.clone(),
627			sync_service.clone(),
628		),
629	);
630
631	let rpc_id_provider = config.rpc.id_provider.take();
632
633	// jsonrpsee RPC
634	// RPC-V2 specific metrics need to be registered before the RPC server is started,
635	// since we might have two instances running (one for the in-memory RPC and one for the network
636	// RPC).
637	let rpc_v2_metrics = config
638		.prometheus_registry()
639		.map(|registry| sc_rpc_spec_v2::transaction::TransactionMetrics::new(registry))
640		.transpose()?;
641
642	// Create dedicated RPC runtime with limited blocking threads.
643	// This isolates RPC blocking operations from the rest of the node.
644	let rpc_runtime = sc_rpc_server::create_rpc_runtime(config.rpc.max_connections)
645		.map_err(|e| Error::Application(Box::new(e)))?;
646
647	// Create spawn handle for RPC tasks
648	let rpc_spawn_handle: Arc<dyn sp_core::traits::SpawnNamed> =
649		Arc::new(sc_rpc_server::RpcSpawnHandle::new(rpc_runtime.handle().clone()));
650
651	// Factory that creates RPC module
652	let gen_rpc_module = || {
653		gen_rpc_module(GenRpcModuleParams {
654			spawn_handle: rpc_spawn_handle.clone(),
655			client: client.clone(),
656			transaction_pool: transaction_pool.clone(),
657			keystore: keystore.clone(),
658			system_rpc_tx: system_rpc_tx.clone(),
659			impl_name: config.impl_name.clone(),
660			impl_version: config.impl_version.clone(),
661			chain_spec: config.chain_spec.as_ref(),
662			state_pruning: &config.state_pruning,
663			blocks_pruning: config.blocks_pruning,
664			backend: backend.clone(),
665			rpc_builder: &*rpc_builder,
666			metrics: rpc_v2_metrics.clone(),
667			sync_oracle: sync_service.clone(),
668			tracing_execute_block: execute_block.clone(),
669		})
670	};
671
672	// Generate the RPC module for the server
673	let rpc_api = gen_rpc_module()?;
674
675	let rpc_server_handle = start_rpc_servers(
676		&config.rpc,
677		config.prometheus_registry(),
678		&config.tokio_handle,
679		rpc_api,
680		rpc_runtime,
681		rpc_id_provider,
682	)?;
683
684	let listen_addrs = rpc_server_handle
685		.listen_addrs()
686		.into_iter()
687		.map(|socket_addr| {
688			let mut multiaddr: Multiaddr = socket_addr.ip().into();
689			multiaddr.push(Protocol::Tcp(socket_addr.port()));
690			multiaddr
691		})
692		.collect();
693
694	// In-memory RPC uses the same dedicated RPC runtime
695	let in_memory_rpc = {
696		let mut module = gen_rpc_module()?;
697		module.extensions_mut().insert(DenyUnsafe::No);
698		module
699	};
700
701	let in_memory_rpc_handle = RpcHandlers::new(Arc::new(in_memory_rpc), listen_addrs);
702
703	// Spawn informant task
704	spawn_handle.spawn(
705		"informant",
706		None,
707		sc_informant::build(client.clone(), network, sync_service.clone()),
708	);
709
710	task_manager.keep_alive((config.base_path, rpc_server_handle));
711
712	Ok(in_memory_rpc_handle)
713}
714
715/// Returns a future that forwards imported transactions to the transaction networking protocol.
716pub async fn propagate_transaction_notifications<Block, ExPool>(
717	transaction_pool: Arc<ExPool>,
718	tx_handler_controller: sc_network_transactions::TransactionsHandlerController<
719		<Block as BlockT>::Hash,
720	>,
721	telemetry: Option<TelemetryHandle>,
722) where
723	Block: BlockT,
724	ExPool: MaintainedTransactionPool<Block = Block, Hash = <Block as BlockT>::Hash> + ?Sized,
725{
726	const TELEMETRY_INTERVAL: Duration = Duration::from_secs(1);
727
728	// transaction notifications
729	let mut notifications = transaction_pool.import_notification_stream().fuse();
730	let mut timer = futures_timer::Delay::new(TELEMETRY_INTERVAL).fuse();
731	let mut tx_imported = false;
732
733	loop {
734		select! {
735			notification = notifications.next() => {
736				let Some(hash) = notification else { return };
737
738				tx_handler_controller.propagate_transaction(hash);
739
740				tx_imported = true;
741			},
742			_ = timer => {
743				timer = futures_timer::Delay::new(TELEMETRY_INTERVAL).fuse();
744
745				if !tx_imported {
746					continue;
747				}
748
749				tx_imported = false;
750				let status = transaction_pool.status();
751
752				telemetry!(
753					telemetry;
754					SUBSTRATE_INFO;
755					"txpool.import";
756					"ready" => status.ready,
757					"future" => status.future,
758				);
759			}
760		}
761	}
762}
763
764/// Initialize telemetry with provided configuration and return telemetry handle
765pub fn init_telemetry<Block, Client, Network>(
766	name: String,
767	implementation: String,
768	version: String,
769	chain: String,
770	authority: bool,
771	network: Network,
772	client: Arc<Client>,
773	telemetry: &mut Telemetry,
774	sysinfo: Option<sc_telemetry::SysInfo>,
775) -> sc_telemetry::Result<TelemetryHandle>
776where
777	Block: BlockT,
778	Client: BlockBackend<Block>,
779	Network: NetworkStateInfo,
780{
781	let genesis_hash = client.block_hash(Zero::zero()).ok().flatten().unwrap_or_default();
782	let connection_message = ConnectionMessage {
783		name,
784		implementation,
785		version,
786		target_os: sc_sysinfo::TARGET_OS.into(),
787		target_arch: sc_sysinfo::TARGET_ARCH.into(),
788		target_env: sc_sysinfo::TARGET_ENV.into(),
789		config: String::new(),
790		chain,
791		genesis_hash: format!("{:?}", genesis_hash),
792		authority,
793		startup_time: SystemTime::UNIX_EPOCH
794			.elapsed()
795			.map(|dur| dur.as_millis())
796			.unwrap_or(0)
797			.to_string(),
798		network_id: network.local_peer_id().to_base58(),
799		sysinfo,
800	};
801
802	telemetry.start_telemetry(connection_message)?;
803
804	Ok(telemetry.handle())
805}
806
807/// Parameters for [`gen_rpc_module`].
808pub struct GenRpcModuleParams<'a, TBl: BlockT, TBackend, TCl, TRpc, TExPool: ?Sized> {
809	/// The handle to spawn tasks on the RPC runtime.
810	pub spawn_handle: Arc<dyn sp_core::traits::SpawnNamed>,
811	/// Access to the client.
812	pub client: Arc<TCl>,
813	/// The transaction pool.
814	pub transaction_pool: Arc<TExPool>,
815	/// Keystore handle.
816	pub keystore: KeystorePtr,
817	/// Sender for system requests.
818	pub system_rpc_tx: TracingUnboundedSender<sc_rpc::system::Request<TBl>>,
819	/// Implementation name of this node.
820	pub impl_name: String,
821	/// Implementation version of this node.
822	pub impl_version: String,
823	/// The chain spec.
824	pub chain_spec: &'a dyn ChainSpec,
825	/// Enabled pruning mode for this node.
826	pub state_pruning: &'a Option<PruningMode>,
827	/// Enabled blocks pruning mode.
828	pub blocks_pruning: BlocksPruning,
829	/// Backend of the node.
830	pub backend: Arc<TBackend>,
831	/// RPC builder.
832	pub rpc_builder: &'a dyn Fn(SubscriptionTaskExecutor) -> Result<RpcModule<TRpc>, Error>,
833	/// Transaction metrics handle.
834	pub metrics: Option<sc_rpc_spec_v2::transaction::TransactionMetrics>,
835	/// Sync oracle for determining sync status.
836	pub sync_oracle: Arc<dyn sp_consensus::SyncOracle + Send + Sync>,
837	/// Optional [`TracingExecuteBlock`] handle.
838	///
839	/// Will be used by the `trace_block` RPC to execute the actual block.
840	pub tracing_execute_block: Option<Arc<dyn TracingExecuteBlock<TBl>>>,
841}
842
843/// Generate RPC module using provided configuration
844pub fn gen_rpc_module<TBl, TBackend, TCl, TRpc, TExPool>(
845	GenRpcModuleParams {
846		spawn_handle,
847		client,
848		transaction_pool,
849		keystore,
850		system_rpc_tx,
851		impl_name,
852		impl_version,
853		chain_spec,
854		state_pruning,
855		blocks_pruning,
856		backend,
857		rpc_builder,
858		metrics,
859		sync_oracle,
860		tracing_execute_block: execute_block,
861	}: GenRpcModuleParams<TBl, TBackend, TCl, TRpc, TExPool>,
862) -> Result<RpcModule<()>, Error>
863where
864	TBl: BlockT,
865	TCl: ClientForService<TBl>
866		+ ExecutorProvider<TBl>
867		+ CallApiAt<TBl>
868		+ StorageProvider<TBl, TBackend>,
869	TBackend: sc_client_api::backend::Backend<TBl> + 'static,
870	<TCl as ProvideRuntimeApi<TBl>>::Api: sp_session::SessionKeys<TBl> + sp_api::Metadata<TBl>,
871	TBl::Hash: Unpin,
872	TBl::Header: Unpin,
873	TExPool:
874		MaintainedTransactionPool<Block = TBl, Hash = <TBl as BlockT>::Hash> + ?Sized + 'static,
875{
876	let system_info = sc_rpc::system::SystemInfo {
877		chain_name: chain_spec.name().into(),
878		impl_name,
879		impl_version,
880		properties: chain_spec.properties(),
881		chain_type: chain_spec.chain_type(),
882	};
883
884	let mut rpc_api = RpcModule::new(());
885	let task_executor = spawn_handle;
886
887	let (chain, state, child_state) = {
888		let chain = sc_rpc::chain::new_full(client.clone(), task_executor.clone()).into_rpc();
889		let (state, child_state) =
890			sc_rpc::state::new_full(client.clone(), task_executor.clone(), execute_block);
891		let state = state.into_rpc();
892		let child_state = child_state.into_rpc();
893
894		(chain, state, child_state)
895	};
896
897	const MAX_TRANSACTION_PER_CONNECTION: usize = 16;
898
899	let transaction_broadcast_rpc_v2 = sc_rpc_spec_v2::transaction::TransactionBroadcast::new(
900		client.clone(),
901		transaction_pool.clone(),
902		task_executor.clone(),
903		MAX_TRANSACTION_PER_CONNECTION,
904	)
905	.into_rpc();
906
907	let transaction_v2 = sc_rpc_spec_v2::transaction::Transaction::new(
908		client.clone(),
909		transaction_pool.clone(),
910		task_executor.clone(),
911		metrics,
912	)
913	.into_rpc();
914
915	let chain_head_v2 = sc_rpc_spec_v2::chain_head::ChainHead::new(
916		client.clone(),
917		backend.clone(),
918		task_executor.clone(),
919		// Defaults to sensible limits for the `ChainHead`.
920		sc_rpc_spec_v2::chain_head::ChainHeadConfig::default(),
921	)
922	.into_rpc();
923
924	// Part of the RPC v2 spec.
925	// An archive node that can respond to the `archive` RPC-v2 queries is a node with:
926	// - state pruning in archive mode: The storage of blocks is kept around
927	// - block pruning in archive mode: The block's body is kept around
928	let is_archive_node = state_pruning.as_ref().map(|sp| sp.is_archive()).unwrap_or(false) &&
929		blocks_pruning.is_archive();
930	let genesis_hash = client.hash(Zero::zero()).ok().flatten().expect("Genesis block exists; qed");
931	if is_archive_node {
932		let archive_v2 = sc_rpc_spec_v2::archive::Archive::new(
933			client.clone(),
934			backend.clone(),
935			genesis_hash,
936			task_executor.clone(),
937		)
938		.into_rpc();
939		rpc_api.merge(archive_v2).map_err(|e| Error::Application(e.into()))?;
940	}
941
942	// ChainSpec RPC-v2.
943	let chain_spec_v2 = sc_rpc_spec_v2::chain_spec::ChainSpec::new(
944		chain_spec.name().into(),
945		genesis_hash,
946		chain_spec.properties(),
947	)
948	.into_rpc();
949
950	// Bitswap RPC-v2 (`bitswap_unstable_*`; `bitswap_v1_get` is registered as an alias of
951	// `bitswap_unstable_get` during the migration). Do not confuse with the Bitswap network
952	// protocol itself, which is the IPFS-style block-exchange wire format these methods may
953	// dispatch to.
954	let bitswap_v2 =
955		sc_rpc_spec_v2::bitswap::Bitswap::new(client.clone(), sync_oracle, task_executor.clone())
956			.into_rpc();
957
958	let author = sc_rpc::author::Author::new(
959		client.clone(),
960		transaction_pool,
961		keystore,
962		task_executor.clone(),
963	)
964	.into_rpc();
965
966	let system = sc_rpc::system::System::new(system_info, system_rpc_tx).into_rpc();
967
968	if let Some(storage) = backend.offchain_storage() {
969		let offchain = sc_rpc::offchain::Offchain::new(storage).into_rpc();
970
971		rpc_api.merge(offchain).map_err(|e| Error::Application(e.into()))?;
972	}
973
974	// Part of the RPC v2 spec.
975	rpc_api.merge(transaction_v2).map_err(|e| Error::Application(e.into()))?;
976	rpc_api
977		.merge(transaction_broadcast_rpc_v2)
978		.map_err(|e| Error::Application(e.into()))?;
979	rpc_api.merge(chain_head_v2).map_err(|e| Error::Application(e.into()))?;
980	rpc_api.merge(chain_spec_v2).map_err(|e| Error::Application(e.into()))?;
981	rpc_api.merge(bitswap_v2).map_err(|e| Error::Application(e.into()))?;
982
983	// Part of the old RPC spec.
984	rpc_api.merge(chain).map_err(|e| Error::Application(e.into()))?;
985	rpc_api.merge(author).map_err(|e| Error::Application(e.into()))?;
986	rpc_api.merge(system).map_err(|e| Error::Application(e.into()))?;
987	rpc_api.merge(state).map_err(|e| Error::Application(e.into()))?;
988	rpc_api.merge(child_state).map_err(|e| Error::Application(e.into()))?;
989	// Additional [`RpcModule`]s defined in the node to fit the specific blockchain
990	let extra_rpcs = rpc_builder(task_executor.clone())?;
991	rpc_api.merge(extra_rpcs).map_err(|e| Error::Application(e.into()))?;
992
993	Ok(rpc_api)
994}
995
996/// Parameters to pass into [`build_network`].
997pub struct BuildNetworkParams<'a, Block, Net, TxPool: ?Sized, IQ, Client>
998where
999	Block: BlockT,
1000	Net: NetworkBackend<Block, <Block as BlockT>::Hash>,
1001{
1002	/// The service configuration.
1003	pub config: &'a Configuration,
1004	/// Full network configuration.
1005	pub net_config: FullNetworkConfiguration<Block, <Block as BlockT>::Hash, Net>,
1006	/// A shared client returned by `new_full_parts`.
1007	pub client: Arc<Client>,
1008	/// A shared transaction pool.
1009	pub transaction_pool: Arc<TxPool>,
1010	/// A handle for spawning tasks.
1011	pub spawn_handle: SpawnTaskHandle,
1012	/// A handle for spawning essential tasks.
1013	pub spawn_essential_handle: SpawnEssentialTaskHandle,
1014	/// An import queue.
1015	pub import_queue: IQ,
1016	/// A block announce validator builder.
1017	pub block_announce_validator_builder: Option<
1018		Box<dyn FnOnce(Arc<Client>) -> Box<dyn BlockAnnounceValidator<Block> + Send> + Send>,
1019	>,
1020	/// Optional warp sync config.
1021	pub warp_sync_config: Option<WarpSyncConfig<Block>>,
1022	/// User specified block relay params. If not specified, the default
1023	/// block request handler will be used.
1024	pub block_relay: Option<BlockRelayParams<Block, Net>>,
1025	/// Metrics.
1026	pub metrics: NotificationMetrics,
1027	/// Which block bodies gap sync downloads after warp sync. `None` derives the
1028	/// default from the block pruning configuration, see
1029	/// [`default_gap_sync_body_policy`].
1030	pub gap_sync_body_policy: Option<GapSyncBodyPolicyProvider>,
1031}
1032
1033/// Build the network service, the network status sinks and an RPC sender.
1034pub fn build_network<Block, Net, TxPool, IQ, Client>(
1035	params: BuildNetworkParams<Block, Net, TxPool, IQ, Client>,
1036) -> Result<
1037	(
1038		Arc<dyn sc_network::service::traits::NetworkService>,
1039		TracingUnboundedSender<sc_rpc::system::Request<Block>>,
1040		sc_network_transactions::TransactionsHandlerController<<Block as BlockT>::Hash>,
1041		Arc<SyncingService<Block>>,
1042		Option<sc_network_bitswap::BitswapHandle>,
1043	),
1044	Error,
1045>
1046where
1047	Block: BlockT,
1048	Client: ClientForService<Block> + Chain<Block>,
1049	TxPool: TransactionPool<Block = Block, Hash = <Block as BlockT>::Hash> + ?Sized + 'static,
1050	IQ: ImportQueue<Block> + 'static,
1051	Net: NetworkBackend<Block, <Block as BlockT>::Hash>,
1052{
1053	let BuildNetworkParams {
1054		config,
1055		mut net_config,
1056		client,
1057		transaction_pool,
1058		spawn_handle,
1059		spawn_essential_handle,
1060		import_queue,
1061		block_announce_validator_builder,
1062		warp_sync_config,
1063		block_relay,
1064		metrics,
1065		gap_sync_body_policy,
1066	} = params;
1067
1068	let block_announce_validator = if let Some(f) = block_announce_validator_builder {
1069		f(client.clone())
1070	} else {
1071		Box::new(DefaultBlockAnnounceValidator)
1072	};
1073
1074	let network_service_provider = NetworkServiceProvider::new();
1075	let protocol_id = config.protocol_id();
1076	let fork_id = config.chain_spec.fork_id();
1077	let metrics_registry = config.prometheus_config.as_ref().map(|config| &config.registry);
1078
1079	let block_downloader = match block_relay {
1080		Some(params) => {
1081			let BlockRelayParams { mut server, downloader, request_response_config } = params;
1082
1083			net_config.add_request_response_protocol(request_response_config);
1084
1085			spawn_handle.spawn("block-request-handler", Some("networking"), async move {
1086				server.run().await;
1087			});
1088
1089			downloader
1090		},
1091		None => build_default_block_downloader(
1092			&protocol_id,
1093			fork_id,
1094			&mut net_config,
1095			network_service_provider.handle(),
1096			Arc::clone(&client),
1097			config.network.default_peers_set.in_peers as usize +
1098				config.network.default_peers_set.out_peers as usize,
1099			&spawn_handle,
1100		),
1101	};
1102
1103	let gap_sync_body_policy =
1104		gap_sync_body_policy.unwrap_or_else(|| default_gap_sync_body_policy(config.blocks_pruning));
1105	let syncing_strategy = build_polkadot_syncing_strategy(
1106		protocol_id.clone(),
1107		fork_id,
1108		&mut net_config,
1109		warp_sync_config,
1110		block_downloader,
1111		client.clone(),
1112		&spawn_handle,
1113		metrics_registry,
1114		gap_sync_body_policy,
1115	)?;
1116
1117	let (syncing_engine, sync_service, block_announce_config) = SyncingEngine::new(
1118		Roles::from(&config.role),
1119		Arc::clone(&client),
1120		metrics_registry,
1121		metrics.clone(),
1122		&net_config,
1123		protocol_id.clone(),
1124		fork_id,
1125		block_announce_validator,
1126		syncing_strategy,
1127		network_service_provider.handle(),
1128		import_queue.service(),
1129		net_config.peer_store_handle(),
1130	)?;
1131
1132	// The syncing engine is spawned as an essential task: a node that can no longer
1133	// sync is better shut down than kept running.
1134	spawn_essential_handle.spawn_blocking("syncing", None, syncing_engine.run());
1135
1136	build_network_advanced(BuildNetworkAdvancedParams {
1137		role: config.role,
1138		protocol_id,
1139		fork_id,
1140		announce_block: config.announce_block,
1141		net_config,
1142		client,
1143		transaction_pool,
1144		spawn_handle,
1145		spawn_essential_handle,
1146		import_queue,
1147		sync_service,
1148		block_announce_config,
1149		network_service_provider,
1150		metrics_registry,
1151		metrics,
1152		blocks_pruning: config.blocks_pruning,
1153	})
1154}
1155
1156/// Parameters to pass into [`build_network_advanced`].
1157pub struct BuildNetworkAdvancedParams<'a, Block, Net, TxPool: ?Sized, IQ, Client>
1158where
1159	Block: BlockT,
1160	Net: NetworkBackend<Block, <Block as BlockT>::Hash>,
1161{
1162	/// Role of the local node.
1163	pub role: Role,
1164	/// Protocol name prefix.
1165	pub protocol_id: ProtocolId,
1166	/// Fork ID.
1167	pub fork_id: Option<&'a str>,
1168	/// Announce block automatically after they have been imported.
1169	pub announce_block: bool,
1170	/// Full network configuration.
1171	pub net_config: FullNetworkConfiguration<Block, <Block as BlockT>::Hash, Net>,
1172	/// A shared client returned by `new_full_parts`.
1173	pub client: Arc<Client>,
1174	/// A shared transaction pool.
1175	pub transaction_pool: Arc<TxPool>,
1176	/// A handle for spawning tasks.
1177	pub spawn_handle: SpawnTaskHandle,
1178	/// A handle for spawning essential tasks.
1179	pub spawn_essential_handle: SpawnEssentialTaskHandle,
1180	/// An import queue.
1181	pub import_queue: IQ,
1182	/// Syncing service to communicate with syncing engine.
1183	pub sync_service: SyncingService<Block>,
1184	/// Block announce config.
1185	pub block_announce_config: Net::NotificationProtocolConfig,
1186	/// Network service provider to drive with network internally.
1187	pub network_service_provider: NetworkServiceProvider,
1188	/// Prometheus metrics registry.
1189	pub metrics_registry: Option<&'a Registry>,
1190	/// Metrics.
1191	pub metrics: NotificationMetrics,
1192	/// Block pruning configuration.
1193	pub blocks_pruning: BlocksPruning,
1194}
1195
1196/// Builds the lower-level network service.
1197///
1198/// The final tuple element contains the Bitswap handle when IPFS is enabled.
1199pub fn build_network_advanced<Block, Net, TxPool, IQ, Client>(
1200	params: BuildNetworkAdvancedParams<Block, Net, TxPool, IQ, Client>,
1201) -> Result<
1202	(
1203		Arc<dyn sc_network::service::traits::NetworkService>,
1204		TracingUnboundedSender<sc_rpc::system::Request<Block>>,
1205		sc_network_transactions::TransactionsHandlerController<<Block as BlockT>::Hash>,
1206		Arc<SyncingService<Block>>,
1207		Option<sc_network_bitswap::BitswapHandle>,
1208	),
1209	Error,
1210>
1211where
1212	Block: BlockT,
1213	Client: ClientForService<Block> + Chain<Block>,
1214	TxPool: TransactionPool<Block = Block, Hash = <Block as BlockT>::Hash> + ?Sized + 'static,
1215	IQ: ImportQueue<Block> + 'static,
1216	Net: NetworkBackend<Block, <Block as BlockT>::Hash>,
1217{
1218	let BuildNetworkAdvancedParams {
1219		role,
1220		protocol_id,
1221		fork_id,
1222		announce_block,
1223		mut net_config,
1224		client,
1225		transaction_pool,
1226		spawn_handle,
1227		spawn_essential_handle,
1228		import_queue,
1229		sync_service,
1230		block_announce_config,
1231		network_service_provider,
1232		metrics_registry,
1233		metrics,
1234		blocks_pruning,
1235	} = params;
1236
1237	let genesis_hash = client.info().genesis_hash;
1238	let sync_service = Arc::new(sync_service);
1239
1240	let light_client_request_protocol_config = {
1241		// Allow both outgoing and incoming requests.
1242		let (handler, protocol_config) = LightClientRequestHandler::new::<Net>(
1243			&protocol_id,
1244			fork_id,
1245			client.clone(),
1246			net_config.network_config.light_request_execution_timeout,
1247			net_config.network_config.light_request_call_workers,
1248			metrics_registry,
1249		);
1250		spawn_handle.spawn(
1251			"light-client-request-handler",
1252			Some("networking"),
1253			handler.run(spawn_handle.clone()),
1254		);
1255		protocol_config
1256	};
1257
1258	// install request handlers to `FullNetworkConfiguration`
1259	net_config.add_request_response_protocol(light_client_request_protocol_config);
1260
1261	let (ipfs_config, bitswap) = if net_config.network_config.ipfs_server {
1262		if !Net::SUPPORTS_IPFS {
1263			return Err(Error::Other(
1264				"the selected network backend does not support Bitswap; \
1265					 set --network-backend litep2p or disable --ipfs-server"
1266					.into(),
1267			));
1268		}
1269
1270		let ipfs_num_blocks = match blocks_pruning {
1271			BlocksPruning::KeepAll | BlocksPruning::KeepFinalized => IPFS_MAX_BLOCKS,
1272			BlocksPruning::Some(num) => std::cmp::min(num, IPFS_MAX_BLOCKS),
1273		};
1274
1275		let (ipfs_config, litep2p_bitswap_handle) = IpfsConfig::new(
1276			Box::new(IpfsIndexedTransactions::new(client.clone(), ipfs_num_blocks)),
1277			net_config.network_config.ipfs_bootnodes.clone(),
1278		);
1279
1280		let (handler, handle) = sc_network_bitswap::start::<Block, _>(
1281			client.clone(),
1282			&*sync_service,
1283			litep2p_bitswap_handle,
1284			metrics_registry,
1285		);
1286
1287		(Some(ipfs_config), Some((handler, handle)))
1288	} else {
1289		(None, None)
1290	};
1291
1292	// Create transactions protocol and add it to the list of supported protocols of
1293	let (transactions_handler_proto, transactions_config) =
1294		sc_network_transactions::TransactionsHandlerPrototype::new::<_, Block, Net>(
1295			protocol_id.clone(),
1296			genesis_hash,
1297			fork_id,
1298			metrics.clone(),
1299			net_config.peer_store_handle(),
1300		);
1301	net_config.add_notification_protocol(transactions_config);
1302
1303	// Start task for `PeerStore`
1304	let peer_store = net_config.take_peer_store();
1305	spawn_handle.spawn("peer-store", Some("networking"), peer_store.run());
1306
1307	let network_params = sc_network::config::Params::<Block, <Block as BlockT>::Hash, Net> {
1308		role,
1309		executor: {
1310			let spawn_handle = Clone::clone(&spawn_handle);
1311			Box::new(move |fut| {
1312				spawn_handle.spawn("libp2p-node", Some("networking"), fut);
1313			})
1314		},
1315		network_config: net_config,
1316		genesis_hash,
1317		protocol_id,
1318		fork_id: fork_id.map(ToOwned::to_owned),
1319		metrics_registry: metrics_registry.cloned(),
1320		block_announce_config,
1321		ipfs_config,
1322		notification_metrics: metrics,
1323	};
1324
1325	let has_bootnodes = !network_params.network_config.network_config.boot_nodes.is_empty();
1326	let network_mut = Net::new(network_params)?;
1327	let network = network_mut.network_service().clone();
1328
1329	// Essential: on storage chains block import depends on the bitswap actor, so its
1330	// death must shut the node down instead of stalling sync silently.
1331	let bitswap_handle = bitswap.map(|(handler, handle)| {
1332		spawn_essential_handle.spawn("bitswap-service", Some("networking"), handler);
1333		handle
1334	});
1335
1336	let (tx_handler, tx_handler_controller) = transactions_handler_proto.build(
1337		network.clone(),
1338		sync_service.clone(),
1339		Arc::new(TransactionPoolAdapter { pool: transaction_pool, client: client.clone() }),
1340		metrics_registry,
1341	)?;
1342	spawn_handle.spawn_blocking(
1343		"network-transactions-handler",
1344		Some("networking"),
1345		tx_handler.run(),
1346	);
1347
1348	spawn_handle.spawn_blocking(
1349		"chain-sync-network-service-provider",
1350		Some("networking"),
1351		network_service_provider.run(Arc::new(network.clone())),
1352	);
1353	spawn_handle.spawn("import-queue", None, {
1354		let sync_service = sync_service.clone();
1355
1356		async move { import_queue.run(sync_service.as_ref()).await }
1357	});
1358
1359	let (system_rpc_tx, system_rpc_rx) = tracing_unbounded("mpsc_system_rpc", 10_000);
1360	spawn_handle.spawn(
1361		"system-rpc-handler",
1362		Some("networking"),
1363		build_system_rpc_future::<_, _, <Block as BlockT>::Hash>(
1364			role,
1365			network_mut.network_service(),
1366			sync_service.clone(),
1367			client.clone(),
1368			system_rpc_rx,
1369			has_bootnodes,
1370		),
1371	);
1372
1373	let future = build_network_future::<_, _, <Block as BlockT>::Hash, _>(
1374		network_mut,
1375		client,
1376		sync_service.clone(),
1377		announce_block,
1378	);
1379
1380	// The network worker is responsible for gathering all network messages and processing
1381	// them. This is quite a heavy task, and at the time of the writing of this comment it
1382	// frequently happens that this future takes several seconds or in some situations
1383	// even more than a minute until it has processed its entire queue. This is clearly an
1384	// issue, and ideally we would like to fix the network future to take as little time as
1385	// possible, but we also take the extra harm-prevention measure to execute the networking
1386	// future using `spawn_blocking`.
1387	//
1388	// The network worker is spawned as an essential task, meaning if it exits unexpectedly
1389	// the service will shut down.
1390	spawn_essential_handle.spawn_blocking("network-worker", Some("networking"), future);
1391
1392	Ok((network, system_rpc_tx, tx_handler_controller, sync_service.clone(), bitswap_handle))
1393}
1394
1395/// Configuration for [`build_default_syncing_engine`].
1396pub struct DefaultSyncingEngineConfig<'a, Block, Client, Net>
1397where
1398	Block: BlockT,
1399	Net: NetworkBackend<Block, <Block as BlockT>::Hash>,
1400{
1401	/// Role of the local node.
1402	pub role: Role,
1403	/// Protocol name prefix.
1404	pub protocol_id: ProtocolId,
1405	/// Fork ID.
1406	pub fork_id: Option<&'a str>,
1407	/// Full network configuration.
1408	pub net_config: &'a mut FullNetworkConfiguration<Block, <Block as BlockT>::Hash, Net>,
1409	/// Validator for incoming block announcements.
1410	pub block_announce_validator: Box<dyn BlockAnnounceValidator<Block> + Send>,
1411	/// Handle to communicate with `NetworkService`.
1412	pub network_service_handle: NetworkServiceHandle,
1413	/// Warp sync configuration (when used).
1414	pub warp_sync_config: Option<WarpSyncConfig<Block>>,
1415	/// A shared client returned by `new_full_parts`.
1416	pub client: Arc<Client>,
1417	/// Blocks import queue API.
1418	pub import_queue_service: Box<dyn ImportQueueService<Block>>,
1419	/// Expected max total number of peer connections (in + out).
1420	pub num_peers_hint: usize,
1421	/// A handle for spawning tasks.
1422	pub spawn_handle: &'a SpawnTaskHandle,
1423	/// A handle for spawning essential tasks. Used for the syncing engine itself.
1424	pub spawn_essential_handle: &'a SpawnEssentialTaskHandle,
1425	/// Prometheus metrics registry.
1426	pub metrics_registry: Option<&'a Registry>,
1427	/// Metrics.
1428	pub metrics: NotificationMetrics,
1429	/// Resolves the gap sync body policy when a `ChainSync` instance is created. Use
1430	/// [`default_gap_sync_body_policy`] unless the node opts into storage-chain body
1431	/// recovery.
1432	pub gap_sync_body_policy: GapSyncBodyPolicyProvider,
1433}
1434
1435/// Build default syncing engine using [`build_default_block_downloader`] and
1436/// [`build_polkadot_syncing_strategy`] internally.
1437pub fn build_default_syncing_engine<Block, Client, Net>(
1438	config: DefaultSyncingEngineConfig<Block, Client, Net>,
1439) -> Result<(SyncingService<Block>, Net::NotificationProtocolConfig), Error>
1440where
1441	Block: BlockT,
1442	Client: HeaderBackend<Block>
1443		+ BlockBackend<Block>
1444		+ HeaderMetadata<Block, Error = sp_blockchain::Error>
1445		+ ProofProvider<Block>
1446		+ Send
1447		+ Sync
1448		+ 'static,
1449	Net: NetworkBackend<Block, <Block as BlockT>::Hash>,
1450{
1451	let DefaultSyncingEngineConfig {
1452		role,
1453		protocol_id,
1454		fork_id,
1455		net_config,
1456		block_announce_validator,
1457		network_service_handle,
1458		warp_sync_config,
1459		client,
1460		import_queue_service,
1461		num_peers_hint,
1462		spawn_handle,
1463		spawn_essential_handle,
1464		metrics_registry,
1465		metrics,
1466		gap_sync_body_policy,
1467	} = config;
1468
1469	let block_downloader = build_default_block_downloader(
1470		&protocol_id,
1471		fork_id,
1472		net_config,
1473		network_service_handle.clone(),
1474		client.clone(),
1475		num_peers_hint,
1476		spawn_handle,
1477	);
1478	let syncing_strategy = build_polkadot_syncing_strategy(
1479		protocol_id.clone(),
1480		fork_id,
1481		net_config,
1482		warp_sync_config,
1483		block_downloader,
1484		client.clone(),
1485		spawn_handle,
1486		metrics_registry,
1487		gap_sync_body_policy,
1488	)?;
1489
1490	let (syncing_engine, sync_service, block_announce_config) = SyncingEngine::new(
1491		Roles::from(&role),
1492		client,
1493		metrics_registry,
1494		metrics,
1495		&net_config,
1496		protocol_id,
1497		fork_id,
1498		block_announce_validator,
1499		syncing_strategy,
1500		network_service_handle,
1501		import_queue_service,
1502		net_config.peer_store_handle(),
1503	)?;
1504
1505	// The syncing engine is spawned as an essential task: a node that can no longer
1506	// sync is better shut down than kept running.
1507	spawn_essential_handle.spawn_blocking("syncing", None, syncing_engine.run());
1508
1509	Ok((sync_service, block_announce_config))
1510}
1511
1512/// Build default block downloader
1513pub fn build_default_block_downloader<Block, Client, Net>(
1514	protocol_id: &ProtocolId,
1515	fork_id: Option<&str>,
1516	net_config: &mut FullNetworkConfiguration<Block, <Block as BlockT>::Hash, Net>,
1517	network_service_handle: NetworkServiceHandle,
1518	client: Arc<Client>,
1519	num_peers_hint: usize,
1520	spawn_handle: &SpawnTaskHandle,
1521) -> Arc<dyn BlockDownloader<Block>>
1522where
1523	Block: BlockT,
1524	Client: HeaderBackend<Block> + BlockBackend<Block> + Send + Sync + 'static,
1525	Net: NetworkBackend<Block, <Block as BlockT>::Hash>,
1526{
1527	// Custom protocol was not specified, use the default block handler.
1528	// Allow both outgoing and incoming requests.
1529	let BlockRelayParams { mut server, downloader, request_response_config } =
1530		BlockRequestHandler::new::<Net>(
1531			network_service_handle,
1532			&protocol_id,
1533			fork_id,
1534			client.clone(),
1535			num_peers_hint,
1536		);
1537
1538	spawn_handle.spawn("block-request-handler", Some("networking"), async move {
1539		server.run().await;
1540	});
1541
1542	net_config.add_request_response_protocol(request_response_config);
1543
1544	downloader
1545}
1546
1547/// The default gap sync body policy provider, derived from the block pruning
1548/// configuration: archive nodes backfill the whole gap with bodies, pruned nodes
1549/// headers and justifications only.
1550///
1551/// Storage-chain nodes install their own provider instead, via
1552/// [`BuildNetworkParams::gap_sync_body_policy`].
1553pub fn default_gap_sync_body_policy(blocks_pruning: BlocksPruning) -> GapSyncBodyPolicyProvider {
1554	Arc::new(move || {
1555		Ok(blocks_pruning
1556			.is_archive()
1557			.then_some(GapSyncBodyPolicy::All)
1558			.unwrap_or(GapSyncBodyPolicy::HeadersOnly))
1559	})
1560}
1561
1562/// Build standard polkadot syncing strategy
1563pub fn build_polkadot_syncing_strategy<Block, Client, Net>(
1564	protocol_id: ProtocolId,
1565	fork_id: Option<&str>,
1566	net_config: &mut FullNetworkConfiguration<Block, <Block as BlockT>::Hash, Net>,
1567	warp_sync_config: Option<WarpSyncConfig<Block>>,
1568	block_downloader: Arc<dyn BlockDownloader<Block>>,
1569	client: Arc<Client>,
1570	spawn_handle: &SpawnTaskHandle,
1571	metrics_registry: Option<&Registry>,
1572	gap_sync_body_policy: GapSyncBodyPolicyProvider,
1573) -> Result<Box<dyn SyncingStrategy<Block>>, Error>
1574where
1575	Block: BlockT,
1576	Client: HeaderBackend<Block>
1577		+ BlockBackend<Block>
1578		+ HeaderMetadata<Block, Error = sp_blockchain::Error>
1579		+ ProofProvider<Block>
1580		+ Send
1581		+ Sync
1582		+ 'static,
1583	Net: NetworkBackend<Block, <Block as BlockT>::Hash>,
1584{
1585	if warp_sync_config.is_none() && net_config.network_config.sync_mode.is_warp() {
1586		return Err("Warp sync enabled, but no warp sync provider configured.".into());
1587	}
1588
1589	if client.requires_full_sync() {
1590		match net_config.network_config.sync_mode {
1591			SyncMode::LightState { .. } => {
1592				return Err("Fast sync doesn't work for archive nodes".into())
1593			},
1594			SyncMode::Warp => return Err("Warp sync doesn't work for archive nodes".into()),
1595			SyncMode::Full => {},
1596		}
1597	}
1598
1599	let genesis_hash = client.info().genesis_hash;
1600
1601	let (state_request_protocol_config, state_request_protocol_name) = {
1602		let num_peer_hint = net_config.network_config.default_peers_set_num_full as usize +
1603			net_config.network_config.default_peers_set.reserved_nodes.len();
1604		// Allow both outgoing and incoming requests.
1605		let (handler, protocol_config) =
1606			StateRequestHandler::new::<Net>(&protocol_id, fork_id, client.clone(), num_peer_hint);
1607		let config_name = protocol_config.protocol_name().clone();
1608
1609		spawn_handle.spawn("state-request-handler", Some("networking"), handler.run());
1610		(protocol_config, config_name)
1611	};
1612	net_config.add_request_response_protocol(state_request_protocol_config);
1613
1614	let (warp_sync_protocol_config, warp_sync_protocol_name) = match warp_sync_config.as_ref() {
1615		Some(WarpSyncConfig::WithProvider(warp_with_provider)) => {
1616			// Allow both outgoing and incoming requests.
1617			let (handler, protocol_config) = WarpSyncRequestHandler::new::<_, Net>(
1618				protocol_id,
1619				genesis_hash,
1620				fork_id,
1621				warp_with_provider.clone(),
1622			);
1623			let config_name = protocol_config.protocol_name().clone();
1624
1625			spawn_handle.spawn("warp-sync-request-handler", Some("networking"), handler.run());
1626			(Some(protocol_config), Some(config_name))
1627		},
1628		_ => (None, None),
1629	};
1630	if let Some(config) = warp_sync_protocol_config {
1631		net_config.add_request_response_protocol(config);
1632	}
1633
1634	let syncing_config = PolkadotSyncingStrategyConfig {
1635		mode: net_config.network_config.sync_mode,
1636		max_parallel_downloads: net_config.network_config.max_parallel_downloads,
1637		max_blocks_per_request: net_config.network_config.max_blocks_per_request,
1638		min_peers_to_start_warp_sync: net_config.network_config.min_peers_to_start_warp_sync,
1639		metrics_registry: metrics_registry.cloned(),
1640		state_request_protocol_name,
1641		block_downloader,
1642		gap_sync_body_policy,
1643	};
1644	Ok(Box::new(PolkadotSyncingStrategy::new(
1645		syncing_config,
1646		client,
1647		warp_sync_config,
1648		warp_sync_protocol_name,
1649	)?))
1650}