referrerpolicy=no-referrer-when-downgrade

staging_node_cli/
service.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#![warn(unused_extern_crates)]
20
21//! Service implementation. Specialized wrapper over substrate service.
22
23use polkadot_sdk::{
24	sc_consensus_beefy as beefy, sc_consensus_grandpa as grandpa,
25	sp_consensus_babe::inherents::BabeCreateInherentDataProviders,
26	sp_consensus_beefy as beefy_primitives, *,
27};
28
29use crate::Cli;
30use codec::Encode;
31use frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE;
32use frame_system_rpc_runtime_api::AccountNonceApi;
33use futures::prelude::*;
34use kitchensink_runtime::RuntimeApi;
35use node_primitives::Block;
36use sc_client_api::{Backend, BlockBackend};
37use sc_consensus_babe::{self, SlotProportion};
38use sc_network::{
39	event::Event, service::traits::NetworkService, NetworkBackend, NetworkEventStream,
40};
41use sc_network_sync::{strategy::warp::WarpSyncConfig, SyncingService};
42use sc_service::{config::Configuration, error::Error as ServiceError, RpcHandlers, TaskManager};
43use sc_statement_store::Store as StatementStore;
44use sc_telemetry::{Telemetry, TelemetryWorker};
45use sc_transaction_pool::TransactionPoolHandle;
46use sc_transaction_pool_api::OffchainTransactionPoolFactory;
47use sp_api::ProvideRuntimeApi;
48use sp_core::crypto::Pair;
49use sp_runtime::{generic, traits::Block as BlockT, SaturatedConversion};
50use std::{path::Path, sync::Arc};
51
52/// Host functions required for kitchensink runtime and Substrate node.
53#[cfg(not(feature = "runtime-benchmarks"))]
54pub type HostFunctions =
55	(sp_io::SubstrateHostFunctions, sp_statement_store::runtime_api::HostFunctions);
56
57/// Host functions required for kitchensink runtime and Substrate node.
58#[cfg(feature = "runtime-benchmarks")]
59pub type HostFunctions = (
60	sp_io::SubstrateHostFunctions,
61	sp_statement_store::runtime_api::HostFunctions,
62	frame_benchmarking::benchmarking::HostFunctions,
63);
64
65/// A specialized `WasmExecutor` intended to use across substrate node. It provides all required
66/// HostFunctions.
67pub type RuntimeExecutor = sc_executor::WasmExecutor<HostFunctions>;
68
69/// The full client type definition.
70pub type FullClient = sc_service::TFullClient<Block, RuntimeApi, RuntimeExecutor>;
71type FullBackend = sc_service::TFullBackend<Block>;
72type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;
73type FullGrandpaBlockImport =
74	grandpa::GrandpaBlockImport<FullBackend, Block, FullClient, FullSelectChain>;
75type FullBeefyBlockImport<InnerBlockImport> = beefy::import::BeefyBlockImport<
76	Block,
77	FullBackend,
78	FullClient,
79	InnerBlockImport,
80	beefy_primitives::ecdsa_crypto::AuthorityId,
81>;
82
83/// The transaction pool type definition.
84pub type TransactionPool = sc_transaction_pool::TransactionPoolHandle<Block, FullClient>;
85
86/// The minimum period of blocks on which justifications will be
87/// imported and generated.
88const GRANDPA_JUSTIFICATION_PERIOD: u32 = 512;
89
90/// Fetch the nonce of the given `account` from the chain state.
91///
92/// Note: Should only be used for tests.
93pub fn fetch_nonce(client: &FullClient, account: sp_core::sr25519::Pair) -> u32 {
94	let best_hash = client.chain_info().best_hash;
95	client
96		.runtime_api()
97		.account_nonce(best_hash, account.public().into())
98		.expect("Fetching account nonce works; qed")
99}
100
101/// Create a transaction using the given `call`.
102///
103/// The transaction will be signed by `sender`. If `nonce` is `None` it will be fetched from the
104/// state of the best block.
105///
106/// Note: Should only be used for tests.
107pub fn create_extrinsic(
108	client: &FullClient,
109	sender: sp_core::sr25519::Pair,
110	function: impl Into<kitchensink_runtime::RuntimeCall>,
111	nonce: Option<u32>,
112) -> kitchensink_runtime::UncheckedExtrinsic {
113	let function = function.into();
114	let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed");
115	let best_hash = client.chain_info().best_hash;
116	let best_block = client.chain_info().best_number;
117	let nonce = nonce.unwrap_or_else(|| fetch_nonce(client, sender.clone()));
118
119	let period = kitchensink_runtime::BlockHashCount::get()
120		.checked_next_power_of_two()
121		.map(|c| c / 2)
122		.unwrap_or(2) as u64;
123	let tip = 0;
124	let tx_ext: kitchensink_runtime::TxExtension =
125		(
126			frame_system::AuthorizeCall::<kitchensink_runtime::Runtime>::new(),
127			frame_system::CheckNonZeroSender::<kitchensink_runtime::Runtime>::new(),
128			frame_system::CheckSpecVersion::<kitchensink_runtime::Runtime>::new(),
129			frame_system::CheckTxVersion::<kitchensink_runtime::Runtime>::new(),
130			frame_system::CheckGenesis::<kitchensink_runtime::Runtime>::new(),
131			frame_system::CheckEra::<kitchensink_runtime::Runtime>::from(generic::Era::mortal(
132				period,
133				best_block.saturated_into(),
134			)),
135			frame_system::CheckNonce::<kitchensink_runtime::Runtime>::from(nonce),
136			frame_system::CheckWeight::<kitchensink_runtime::Runtime>::new(),
137			pallet_skip_feeless_payment::SkipCheckIfFeeless::from(
138				pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::<
139					kitchensink_runtime::Runtime,
140				>::from(tip, None),
141			),
142			frame_metadata_hash_extension::CheckMetadataHash::new(false),
143			frame_system::WeightReclaim::<kitchensink_runtime::Runtime>::new(),
144		);
145
146	let raw_payload = kitchensink_runtime::SignedPayload::from_raw(
147		function.clone(),
148		tx_ext.clone(),
149		(
150			(),
151			(),
152			kitchensink_runtime::VERSION.spec_version,
153			kitchensink_runtime::VERSION.transaction_version,
154			genesis_hash,
155			best_hash,
156			(),
157			(),
158			(),
159			None,
160			(),
161		),
162	);
163	let signature = raw_payload.using_encoded(|e| sender.sign(e));
164
165	generic::UncheckedExtrinsic::new_signed(
166		function,
167		sp_runtime::AccountId32::from(sender.public()).into(),
168		kitchensink_runtime::Signature::Sr25519(signature),
169		tx_ext,
170	)
171	.into()
172}
173
174/// Creates a new partial node.
175pub fn new_partial(
176	config: &Configuration,
177	mixnet_config: Option<&sc_mixnet::Config>,
178) -> Result<
179	sc_service::PartialComponents<
180		FullClient,
181		FullBackend,
182		FullSelectChain,
183		sc_consensus::DefaultImportQueue<Block>,
184		sc_transaction_pool::TransactionPoolHandle<Block, FullClient>,
185		(
186			impl Fn(
187				sc_rpc::SubscriptionTaskExecutor,
188			) -> Result<jsonrpsee::RpcModule<()>, sc_service::Error>,
189			(
190				sc_consensus_babe::BabeBlockImport<
191					Block,
192					FullClient,
193					FullBeefyBlockImport<FullGrandpaBlockImport>,
194					BabeCreateInherentDataProviders<Block>,
195					FullSelectChain,
196				>,
197				grandpa::LinkHalf<Block, FullClient, FullSelectChain>,
198				sc_consensus_babe::BabeLink<Block>,
199				beefy::BeefyVoterLinks<Block, beefy_primitives::ecdsa_crypto::AuthorityId>,
200			),
201			grandpa::SharedVoterState,
202			Option<Telemetry>,
203			Arc<StatementStore>,
204			Option<sc_mixnet::ApiBackend>,
205		),
206	>,
207	ServiceError,
208> {
209	let telemetry = config
210		.telemetry_endpoints
211		.clone()
212		.filter(|x| !x.is_empty())
213		.map(|endpoints| -> Result<_, sc_telemetry::Error> {
214			let worker = TelemetryWorker::new(16)?;
215			let telemetry = worker.handle().new_telemetry(endpoints);
216			Ok((worker, telemetry))
217		})
218		.transpose()?;
219
220	let executor = sc_service::new_wasm_executor(&config.executor);
221
222	let (client, backend, keystore_container, task_manager) =
223		sc_service::new_full_parts::<Block, RuntimeApi, _>(
224			config,
225			telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
226			executor,
227		)?;
228	let client = Arc::new(client);
229
230	let telemetry = telemetry.map(|(worker, telemetry)| {
231		task_manager.spawn_handle().spawn("telemetry", None, worker.run());
232		telemetry
233	});
234
235	let select_chain = sc_consensus::LongestChain::new(backend.clone());
236
237	let transaction_pool = Arc::from(
238		sc_transaction_pool::Builder::new(
239			task_manager.spawn_essential_handle(),
240			client.clone(),
241			config.role.is_authority().into(),
242		)
243		.with_options(config.transaction_pool.clone())
244		.with_prometheus(config.prometheus_registry())
245		.build(),
246	);
247
248	let (grandpa_block_import, grandpa_link) = grandpa::block_import(
249		client.clone(),
250		GRANDPA_JUSTIFICATION_PERIOD,
251		&(client.clone() as Arc<_>),
252		select_chain.clone(),
253		telemetry.as_ref().map(|x| x.handle()),
254	)?;
255	let justification_import = grandpa_block_import.clone();
256
257	let (beefy_block_import, beefy_voter_links, beefy_rpc_links) =
258		beefy::beefy_block_import_and_links(
259			grandpa_block_import,
260			backend.clone(),
261			client.clone(),
262			config.prometheus_registry().cloned(),
263		);
264
265	let babe_config = sc_consensus_babe::configuration(&*client)?;
266	let slot_duration = babe_config.slot_duration();
267	let (block_import, babe_link) = sc_consensus_babe::block_import(
268		babe_config,
269		beefy_block_import,
270		client.clone(),
271		Arc::new(move |_, _| async move {
272			let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
273			let slot =
274			sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
275				*timestamp,
276				slot_duration,
277			);
278			Ok((slot, timestamp))
279		}) as BabeCreateInherentDataProviders<Block>,
280		select_chain.clone(),
281		OffchainTransactionPoolFactory::new(transaction_pool.clone()),
282	)?;
283
284	let (import_queue, babe_worker_handle) =
285		sc_consensus_babe::import_queue(sc_consensus_babe::ImportQueueParams {
286			link: babe_link.clone(),
287			block_import: block_import.clone(),
288			justification_import: Some(Box::new(justification_import)),
289			client: client.clone(),
290			slot_duration,
291			spawner: &task_manager.spawn_essential_handle(),
292			registry: config.prometheus_registry(),
293			telemetry: telemetry.as_ref().map(|x| x.handle()),
294		})?;
295
296	let import_setup = (block_import, grandpa_link, babe_link, beefy_voter_links);
297
298	let statement_store = sc_statement_store::Store::new_shared(
299		&config.data_path,
300		Default::default(),
301		client.clone(),
302		keystore_container.local_keystore(),
303		config.prometheus_registry(),
304		&task_manager.spawn_handle(),
305	)
306	.map_err(|e| ServiceError::Other(format!("Statement store error: {:?}", e)))?;
307
308	let (mixnet_api, mixnet_api_backend) = mixnet_config.map(sc_mixnet::Api::new).unzip();
309
310	let (rpc_extensions_builder, rpc_setup) = {
311		let (_, grandpa_link, _, _) = &import_setup;
312
313		let justification_stream = grandpa_link.justification_stream();
314		let shared_authority_set = grandpa_link.shared_authority_set().clone();
315		let shared_voter_state = grandpa::SharedVoterState::empty();
316		let shared_voter_state2 = shared_voter_state.clone();
317
318		let finality_proof_provider = grandpa::FinalityProofProvider::new_for_service(
319			backend.clone(),
320			Some(shared_authority_set.clone()),
321		);
322
323		let client = client.clone();
324		let pool = transaction_pool.clone();
325		let select_chain = select_chain.clone();
326		let keystore = keystore_container.keystore();
327		let chain_spec = config.chain_spec.cloned_box();
328
329		let rpc_backend = backend.clone();
330		let rpc_statement_store = statement_store.clone();
331		let rpc_extensions_builder =
332			move |subscription_executor: node_rpc::SubscriptionTaskExecutor| {
333				let deps = node_rpc::FullDeps {
334					client: client.clone(),
335					pool: pool.clone(),
336					select_chain: select_chain.clone(),
337					chain_spec: chain_spec.cloned_box(),
338					babe: node_rpc::BabeDeps {
339						keystore: keystore.clone(),
340						babe_worker_handle: babe_worker_handle.clone(),
341					},
342					grandpa: node_rpc::GrandpaDeps {
343						shared_voter_state: shared_voter_state.clone(),
344						shared_authority_set: shared_authority_set.clone(),
345						justification_stream: justification_stream.clone(),
346						subscription_executor: subscription_executor.clone(),
347						finality_provider: finality_proof_provider.clone(),
348					},
349					beefy: node_rpc::BeefyDeps::<beefy_primitives::ecdsa_crypto::AuthorityId> {
350						beefy_finality_proof_stream: beefy_rpc_links
351							.from_voter_justif_stream
352							.clone(),
353						beefy_best_block_stream: beefy_rpc_links
354							.from_voter_best_beefy_stream
355							.clone(),
356						subscription_executor,
357					},
358					statement_store: rpc_statement_store.clone(),
359					backend: rpc_backend.clone(),
360					mixnet_api: mixnet_api.as_ref().cloned(),
361				};
362
363				node_rpc::create_full(deps).map_err(Into::into)
364			};
365
366		(rpc_extensions_builder, shared_voter_state2)
367	};
368
369	Ok(sc_service::PartialComponents {
370		client,
371		backend,
372		task_manager,
373		keystore_container,
374		select_chain,
375		import_queue,
376		transaction_pool,
377		other: (
378			rpc_extensions_builder,
379			import_setup,
380			rpc_setup,
381			telemetry,
382			statement_store,
383			mixnet_api_backend,
384		),
385	})
386}
387
388/// Result of [`new_full_base`].
389pub struct NewFullBase {
390	/// The task manager of the node.
391	pub task_manager: TaskManager,
392	/// The client instance of the node.
393	pub client: Arc<FullClient>,
394	/// The networking service of the node.
395	pub network: Arc<dyn NetworkService>,
396	/// The syncing service of the node.
397	pub sync: Arc<SyncingService<Block>>,
398	/// The transaction pool of the node.
399	pub transaction_pool: Arc<TransactionPoolHandle<Block, FullClient>>,
400	/// The rpc handlers of the node.
401	pub rpc_handlers: RpcHandlers,
402}
403
404/// Creates a full service from the configuration.
405pub fn new_full_base<N: NetworkBackend<Block, <Block as BlockT>::Hash>>(
406	config: Configuration,
407	mixnet_config: Option<sc_mixnet::Config>,
408	disable_hardware_benchmarks: bool,
409	with_startup_data: impl FnOnce(
410		&sc_consensus_babe::BabeBlockImport<
411			Block,
412			FullClient,
413			FullBeefyBlockImport<FullGrandpaBlockImport>,
414			BabeCreateInherentDataProviders<Block>,
415			FullSelectChain,
416		>,
417		&sc_consensus_babe::BabeLink<Block>,
418	),
419) -> Result<NewFullBase, ServiceError> {
420	let is_offchain_indexing_enabled = config.offchain_worker.indexing_enabled;
421	let role = config.role;
422	let force_authoring = config.force_authoring;
423	let backoff_authoring_blocks =
424		Some(sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging::default());
425	let name = config.network.node_name.clone();
426	let enable_grandpa = !config.disable_grandpa;
427	let prometheus_registry = config.prometheus_registry().cloned();
428	let enable_offchain_worker = config.offchain_worker.enabled;
429
430	let hwbench = (!disable_hardware_benchmarks)
431		.then(|| {
432			config.database.path().map(|database_path| {
433				let _ = std::fs::create_dir_all(&database_path);
434				sc_sysinfo::gather_hwbench(Some(database_path), &SUBSTRATE_REFERENCE_HARDWARE)
435			})
436		})
437		.flatten();
438
439	let sc_service::PartialComponents {
440		client,
441		backend,
442		mut task_manager,
443		import_queue,
444		keystore_container,
445		select_chain,
446		transaction_pool,
447		other:
448			(rpc_builder, import_setup, rpc_setup, mut telemetry, statement_store, mixnet_api_backend),
449	} = new_partial(&config, mixnet_config.as_ref())?;
450
451	let metrics = N::register_notification_metrics(
452		config.prometheus_config.as_ref().map(|cfg| &cfg.registry),
453	);
454	let shared_voter_state = rpc_setup;
455	let auth_disc_publish_non_global_ips = config.network.allow_non_globals_in_dht;
456	let auth_disc_public_addresses = config.network.public_addresses.clone();
457
458	let mut net_config = sc_network::config::FullNetworkConfiguration::<_, _, N>::new(
459		&config.network,
460		config.prometheus_config.as_ref().map(|cfg| cfg.registry.clone()),
461	);
462
463	let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed");
464	let peer_store_handle = net_config.peer_store_handle();
465
466	let grandpa_protocol_name = grandpa::protocol_standard_name(&genesis_hash, &config.chain_spec);
467	let (grandpa_protocol_config, grandpa_notification_service) =
468		grandpa::grandpa_peers_set_config::<_, N>(
469			grandpa_protocol_name.clone(),
470			metrics.clone(),
471			Arc::clone(&peer_store_handle),
472		);
473	net_config.add_notification_protocol(grandpa_protocol_config);
474
475	let beefy_gossip_proto_name =
476		beefy::gossip_protocol_name(&genesis_hash, config.chain_spec.fork_id());
477	// `beefy_on_demand_justifications_handler` is given to `beefy-gadget` task to be run,
478	// while `beefy_req_resp_cfg` is added to `config.network.request_response_protocols`.
479	let (beefy_on_demand_justifications_handler, beefy_req_resp_cfg) =
480		beefy::communication::request_response::BeefyJustifsRequestHandler::new::<_, N>(
481			&genesis_hash,
482			config.chain_spec.fork_id(),
483			client.clone(),
484			prometheus_registry.clone(),
485		);
486
487	let (beefy_notification_config, beefy_notification_service) =
488		beefy::communication::beefy_peers_set_config::<_, N>(
489			beefy_gossip_proto_name.clone(),
490			metrics.clone(),
491			Arc::clone(&peer_store_handle),
492		);
493
494	net_config.add_notification_protocol(beefy_notification_config);
495	net_config.add_request_response_protocol(beefy_req_resp_cfg);
496
497	let (statement_handler_proto, statement_config) =
498		sc_network_statement::StatementHandlerPrototype::new::<_, _, N>(
499			genesis_hash,
500			config.chain_spec.fork_id(),
501			metrics.clone(),
502			Arc::clone(&peer_store_handle),
503		);
504	net_config.add_notification_protocol(statement_config);
505
506	let mixnet_protocol_name =
507		sc_mixnet::protocol_name(genesis_hash.as_ref(), config.chain_spec.fork_id());
508	let mixnet_notification_service = mixnet_config.as_ref().map(|mixnet_config| {
509		let (config, notification_service) = sc_mixnet::peers_set_config::<_, N>(
510			mixnet_protocol_name.clone(),
511			mixnet_config,
512			metrics.clone(),
513			Arc::clone(&peer_store_handle),
514		);
515		net_config.add_notification_protocol(config);
516		notification_service
517	});
518
519	let warp_sync = Arc::new(grandpa::warp_proof::NetworkProvider::new(
520		backend.clone(),
521		import_setup.1.shared_authority_set().clone(),
522		Vec::default(),
523	));
524
525	let (network, system_rpc_tx, tx_handler_controller, sync_service) =
526		sc_service::build_network(sc_service::BuildNetworkParams {
527			config: &config,
528			net_config,
529			client: client.clone(),
530			transaction_pool: transaction_pool.clone(),
531			spawn_handle: task_manager.spawn_handle(),
532			import_queue,
533			block_announce_validator_builder: None,
534			warp_sync_config: Some(WarpSyncConfig::WithProvider(warp_sync)),
535			block_relay: None,
536			metrics,
537		})?;
538
539	if let Some(mixnet_config) = mixnet_config {
540		let mixnet = sc_mixnet::run(
541			mixnet_config,
542			mixnet_api_backend.expect("Mixnet API backend created if mixnet enabled"),
543			client.clone(),
544			sync_service.clone(),
545			network.clone(),
546			mixnet_protocol_name,
547			transaction_pool.clone(),
548			Some(keystore_container.keystore()),
549			mixnet_notification_service
550				.expect("`NotificationService` exists since mixnet was enabled; qed"),
551		);
552		task_manager.spawn_handle().spawn("mixnet", None, mixnet);
553	}
554
555	let net_config_path = config.network.net_config_path.clone();
556	let rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
557		config,
558		backend: backend.clone(),
559		client: client.clone(),
560		keystore: keystore_container.keystore(),
561		network: network.clone(),
562		rpc_builder: Box::new(rpc_builder),
563		transaction_pool: transaction_pool.clone(),
564		task_manager: &mut task_manager,
565		system_rpc_tx,
566		tx_handler_controller,
567		sync_service: sync_service.clone(),
568		telemetry: telemetry.as_mut(),
569	})?;
570
571	if let Some(hwbench) = hwbench {
572		sc_sysinfo::print_hwbench(&hwbench);
573		match SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench, false) {
574			Err(err) if role.is_authority() => {
575				log::warn!(
576					"⚠️  The hardware does not meet the minimal requirements {} for role 'Authority'.",
577					err
578				);
579			},
580			_ => {},
581		}
582
583		if let Some(ref mut telemetry) = telemetry {
584			let telemetry_handle = telemetry.handle();
585			task_manager.spawn_handle().spawn(
586				"telemetry_hwbench",
587				None,
588				sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench),
589			);
590		}
591	}
592
593	let (block_import, grandpa_link, babe_link, beefy_links) = import_setup;
594
595	(with_startup_data)(&block_import, &babe_link);
596
597	if let sc_service::config::Role::Authority { .. } = &role {
598		let proposer = sc_basic_authorship::ProposerFactory::new(
599			task_manager.spawn_handle(),
600			client.clone(),
601			transaction_pool.clone(),
602			prometheus_registry.as_ref(),
603			telemetry.as_ref().map(|x| x.handle()),
604		);
605
606		let client_clone = client.clone();
607		let slot_duration = babe_link.config().slot_duration();
608		let babe_config = sc_consensus_babe::BabeParams {
609			keystore: keystore_container.keystore(),
610			client: client.clone(),
611			select_chain,
612			env: proposer,
613			block_import,
614			sync_oracle: sync_service.clone(),
615			justification_sync_link: sync_service.clone(),
616			create_inherent_data_providers: move |parent, ()| {
617				let client_clone = client_clone.clone();
618				async move {
619					let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
620
621					let slot =
622						sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
623							*timestamp,
624							slot_duration,
625						);
626
627					let storage_proof =
628						sp_transaction_storage_proof::registration::new_data_provider(
629							&*client_clone,
630							&parent,
631						)?;
632
633					Ok((slot, timestamp, storage_proof))
634				}
635			},
636			force_authoring,
637			backoff_authoring_blocks,
638			babe_link,
639			block_proposal_slot_portion: SlotProportion::new(0.5),
640			max_block_proposal_slot_portion: None,
641			telemetry: telemetry.as_ref().map(|x| x.handle()),
642		};
643
644		let babe = sc_consensus_babe::start_babe(babe_config)?;
645		task_manager.spawn_essential_handle().spawn_blocking(
646			"babe-proposer",
647			Some("block-authoring"),
648			babe,
649		);
650	}
651
652	// Spawn authority discovery module.
653	if role.is_authority() {
654		let authority_discovery_role =
655			sc_authority_discovery::Role::PublishAndDiscover(keystore_container.keystore());
656		let dht_event_stream =
657			network.event_stream("authority-discovery").filter_map(|e| async move {
658				match e {
659					Event::Dht(e) => Some(e),
660					_ => None,
661				}
662			});
663		let (authority_discovery_worker, _service) =
664			sc_authority_discovery::new_worker_and_service_with_config(
665				sc_authority_discovery::WorkerConfig {
666					publish_non_global_ips: auth_disc_publish_non_global_ips,
667					public_addresses: auth_disc_public_addresses,
668					persisted_cache_directory: net_config_path,
669					..Default::default()
670				},
671				client.clone(),
672				Arc::new(network.clone()),
673				Box::pin(dht_event_stream),
674				authority_discovery_role,
675				prometheus_registry.clone(),
676				task_manager.spawn_handle(),
677			);
678
679		task_manager.spawn_handle().spawn(
680			"authority-discovery-worker",
681			Some("networking"),
682			authority_discovery_worker.run(),
683		);
684	}
685
686	// if the node isn't actively participating in consensus then it doesn't
687	// need a keystore, regardless of which protocol we use below.
688	let keystore = if role.is_authority() { Some(keystore_container.keystore()) } else { None };
689
690	// beefy is enabled if its notification service exists
691	let network_params = beefy::BeefyNetworkParams {
692		network: Arc::new(network.clone()),
693		sync: sync_service.clone(),
694		gossip_protocol_name: beefy_gossip_proto_name,
695		justifications_protocol_name: beefy_on_demand_justifications_handler.protocol_name(),
696		notification_service: beefy_notification_service,
697		_phantom: core::marker::PhantomData::<Block>,
698	};
699	let beefy_params = beefy::BeefyParams {
700		client: client.clone(),
701		backend: backend.clone(),
702		payload_provider: sp_consensus_beefy::mmr::MmrRootProvider::new(client.clone()),
703		runtime: client.clone(),
704		key_store: keystore.clone(),
705		network_params,
706		min_block_delta: 8,
707		prometheus_registry: prometheus_registry.clone(),
708		links: beefy_links,
709		on_demand_justifications_handler: beefy_on_demand_justifications_handler,
710		is_authority: role.is_authority(),
711	};
712
713	let beefy_gadget = beefy::start_beefy_gadget::<_, _, _, _, _, _, _, _>(beefy_params);
714	// BEEFY is part of consensus, if it fails we'll bring the node down with it to make sure it
715	// is noticed.
716	task_manager
717		.spawn_essential_handle()
718		.spawn_blocking("beefy-gadget", None, beefy_gadget);
719	// When offchain indexing is enabled, MMR gadget should also run.
720	if is_offchain_indexing_enabled {
721		task_manager.spawn_essential_handle().spawn_blocking(
722			"mmr-gadget",
723			None,
724			mmr_gadget::MmrGadget::start(
725				client.clone(),
726				backend.clone(),
727				sp_mmr_primitives::INDEXING_PREFIX.to_vec(),
728			),
729		);
730	}
731
732	let grandpa_config = grandpa::Config {
733		// FIXME #1578 make this available through chainspec
734		gossip_duration: std::time::Duration::from_millis(333),
735		justification_generation_period: GRANDPA_JUSTIFICATION_PERIOD,
736		name: Some(name),
737		observer_enabled: false,
738		keystore,
739		local_role: role,
740		telemetry: telemetry.as_ref().map(|x| x.handle()),
741		protocol_name: grandpa_protocol_name,
742	};
743
744	if enable_grandpa {
745		// start the full GRANDPA voter
746		// NOTE: non-authorities could run the GRANDPA observer protocol, but at
747		// this point the full voter should provide better guarantees of block
748		// and vote data availability than the observer. The observer has not
749		// been tested extensively yet and having most nodes in a network run it
750		// could lead to finality stalls.
751		let grandpa_params = grandpa::GrandpaParams {
752			config: grandpa_config,
753			link: grandpa_link,
754			network: network.clone(),
755			sync: Arc::new(sync_service.clone()),
756			notification_service: grandpa_notification_service,
757			telemetry: telemetry.as_ref().map(|x| x.handle()),
758			voting_rule: grandpa::VotingRulesBuilder::default().build(),
759			prometheus_registry: prometheus_registry.clone(),
760			shared_voter_state,
761			offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(transaction_pool.clone()),
762		};
763
764		// the GRANDPA voter task is considered infallible, i.e.
765		// if it fails we take down the service with it.
766		task_manager.spawn_essential_handle().spawn_blocking(
767			"grandpa-voter",
768			None,
769			grandpa::run_grandpa_voter(grandpa_params)?,
770		);
771	}
772
773	// Spawn statement protocol worker
774	let statement_protocol_executor = {
775		let spawn_handle = task_manager.spawn_handle();
776		Box::new(move |fut| {
777			spawn_handle.spawn("network-statement-validator", Some("networking"), fut);
778		})
779	};
780	let statement_handler = statement_handler_proto.build(
781		network.clone(),
782		sync_service.clone(),
783		statement_store.clone(),
784		prometheus_registry.as_ref(),
785		statement_protocol_executor,
786	)?;
787	task_manager.spawn_handle().spawn(
788		"network-statement-handler",
789		Some("networking"),
790		statement_handler.run(),
791	);
792
793	if enable_offchain_worker {
794		let offchain_workers =
795			sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions {
796				runtime_api_provider: client.clone(),
797				keystore: Some(keystore_container.keystore()),
798				offchain_db: backend.offchain_storage(),
799				transaction_pool: Some(OffchainTransactionPoolFactory::new(
800					transaction_pool.clone(),
801				)),
802				network_provider: Arc::new(network.clone()),
803				is_validator: role.is_authority(),
804				enable_http_requests: true,
805				custom_extensions: move |_| {
806					vec![Box::new(statement_store.clone().as_statement_store_ext()) as Box<_>]
807				},
808			})?;
809		task_manager.spawn_handle().spawn(
810			"offchain-workers-runner",
811			"offchain-work",
812			offchain_workers.run(client.clone(), task_manager.spawn_handle()).boxed(),
813		);
814	}
815
816	Ok(NewFullBase {
817		task_manager,
818		client,
819		network,
820		sync: sync_service,
821		transaction_pool,
822		rpc_handlers,
823	})
824}
825
826/// Builds a new service for a full client.
827pub fn new_full(config: Configuration, cli: Cli) -> Result<TaskManager, ServiceError> {
828	let mixnet_config = cli.mixnet_params.config(config.role.is_authority());
829	let database_path = config.database.path().map(Path::to_path_buf);
830
831	let task_manager = match config.network.network_backend {
832		sc_network::config::NetworkBackendType::Libp2p => {
833			let task_manager = new_full_base::<sc_network::NetworkWorker<_, _>>(
834				config,
835				mixnet_config,
836				cli.no_hardware_benchmarks,
837				|_, _| (),
838			)
839			.map(|NewFullBase { task_manager, .. }| task_manager)?;
840			task_manager
841		},
842		sc_network::config::NetworkBackendType::Litep2p => {
843			let task_manager = new_full_base::<sc_network::Litep2pNetworkBackend>(
844				config,
845				mixnet_config,
846				cli.no_hardware_benchmarks,
847				|_, _| (),
848			)
849			.map(|NewFullBase { task_manager, .. }| task_manager)?;
850			task_manager
851		},
852	};
853
854	if let Some(database_path) = database_path {
855		sc_storage_monitor::StorageMonitorService::try_spawn(
856			cli.storage_monitor,
857			database_path,
858			&task_manager.spawn_essential_handle(),
859		)
860		.map_err(|e| ServiceError::Application(e.into()))?;
861	}
862
863	Ok(task_manager)
864}
865
866#[cfg(test)]
867mod tests {
868	use crate::service::{new_full_base, NewFullBase};
869	use codec::Encode;
870	use kitchensink_runtime::{
871		constants::{currency::CENTS, time::SLOT_DURATION},
872		Address, BalancesCall, RuntimeCall, TxExtension,
873	};
874	use node_primitives::{Block, DigestItem, Signature};
875	use polkadot_sdk::{sc_transaction_pool_api::MaintainedTransactionPool, *};
876	use sc_client_api::BlockBackend;
877	use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy};
878	use sc_consensus_babe::{BabeIntermediate, CompatibleDigestItem, INTERMEDIATE_KEY};
879	use sc_consensus_epochs::descendent_query;
880	use sc_keystore::LocalKeystore;
881	use sc_service_test::TestNetNode;
882	use sc_transaction_pool_api::ChainEvent;
883	use sp_consensus::{BlockOrigin, Environment, Proposer};
884	use sp_core::crypto::Pair;
885	use sp_inherents::InherentDataProvider;
886	use sp_keyring::Sr25519Keyring;
887	use sp_keystore::KeystorePtr;
888	use sp_runtime::{
889		generic::{self, Digest, Era, SignedPayload},
890		key_types::BABE,
891		traits::{Block as BlockT, Header as HeaderT, IdentifyAccount, Verify},
892		RuntimeAppPublic,
893	};
894	use sp_timestamp;
895	use std::sync::Arc;
896
897	type AccountPublic = <Signature as Verify>::Signer;
898
899	#[test]
900	// It is "ignored", but the node-cli ignored tests are running on the CI.
901	// This can be run locally with `cargo test --release -p node-cli test_sync -- --ignored`.
902	#[ignore]
903	fn test_sync() {
904		sp_tracing::try_init_simple();
905
906		let keystore_path = tempfile::tempdir().expect("Creates keystore path");
907		let keystore: KeystorePtr = LocalKeystore::open(keystore_path.path(), None)
908			.expect("Creates keystore")
909			.into();
910		let alice: sp_consensus_babe::AuthorityId = keystore
911			.sr25519_generate_new(BABE, Some("//Alice"))
912			.expect("Creates authority pair")
913			.into();
914
915		let chain_spec = crate::chain_spec::tests::integration_test_config_with_single_authority();
916
917		// For the block factory
918		let mut slot = 1u64;
919
920		// For the extrinsics factory
921		let bob = Arc::new(Sr25519Keyring::Bob.pair());
922		let charlie = Arc::new(Sr25519Keyring::Charlie.pair());
923		let mut index = 0;
924
925		sc_service_test::sync(
926			chain_spec,
927			|config| {
928				let mut setup_handles = None;
929				let NewFullBase { task_manager, client, network, sync, transaction_pool, .. } =
930					new_full_base::<sc_network::NetworkWorker<_, _>>(
931						config,
932						None,
933						false,
934						|block_import: &sc_consensus_babe::BabeBlockImport<Block, _, _, _, _>,
935						 babe_link: &sc_consensus_babe::BabeLink<Block>| {
936							setup_handles = Some((block_import.clone(), babe_link.clone()));
937						},
938					)?;
939
940				let node = sc_service_test::TestNetComponents::new(
941					task_manager,
942					client,
943					network,
944					sync,
945					transaction_pool,
946				);
947				Ok((node, setup_handles.unwrap()))
948			},
949			|service, &mut (ref mut block_import, ref babe_link)| {
950				let parent_hash = service.client().chain_info().best_hash;
951				let parent_header = service.client().header(parent_hash).unwrap().unwrap();
952				let parent_number = *parent_header.number();
953
954				futures::executor::block_on(service.transaction_pool().maintain(
955					ChainEvent::NewBestBlock { hash: parent_header.hash(), tree_route: None },
956				));
957
958				let mut proposer_factory = sc_basic_authorship::ProposerFactory::new(
959					service.spawn_handle(),
960					service.client(),
961					service.transaction_pool(),
962					None,
963					None,
964				);
965
966				let mut digest = Digest::default();
967
968				// even though there's only one authority some slots might be empty,
969				// so we must keep trying the next slots until we can claim one.
970				let (babe_pre_digest, epoch_descriptor) = loop {
971					let epoch_descriptor = babe_link
972						.epoch_changes()
973						.shared_data()
974						.epoch_descriptor_for_child_of(
975							descendent_query(&*service.client()),
976							&parent_hash,
977							parent_number,
978							slot.into(),
979						)
980						.unwrap()
981						.unwrap();
982
983					let epoch = babe_link
984						.epoch_changes()
985						.shared_data()
986						.epoch_data(&epoch_descriptor, |slot| {
987							sc_consensus_babe::Epoch::genesis(babe_link.config(), slot)
988						})
989						.unwrap();
990
991					if let Some(babe_pre_digest) =
992						sc_consensus_babe::authorship::claim_slot(slot.into(), &epoch, &keystore)
993							.map(|(digest, _)| digest)
994					{
995						break (babe_pre_digest, epoch_descriptor);
996					}
997
998					slot += 1;
999				};
1000
1001				let inherent_data = futures::executor::block_on(
1002					(
1003						sp_timestamp::InherentDataProvider::new(
1004							std::time::Duration::from_millis(SLOT_DURATION * slot).into(),
1005						),
1006						sp_consensus_babe::inherents::InherentDataProvider::new(slot.into()),
1007					)
1008						.create_inherent_data(),
1009				)
1010				.expect("Creates inherent data");
1011
1012				digest.push(<DigestItem as CompatibleDigestItem>::babe_pre_digest(babe_pre_digest));
1013
1014				let new_block = futures::executor::block_on(async move {
1015					let proposer = proposer_factory.init(&parent_header).await.unwrap();
1016					Proposer::propose(
1017						proposer,
1018						inherent_data,
1019						digest,
1020						std::time::Duration::from_secs(1),
1021						None,
1022					)
1023					.await
1024				})
1025				.expect("Error making test block")
1026				.block;
1027
1028				let (new_header, new_body) = new_block.deconstruct();
1029				let pre_hash = new_header.hash();
1030				// sign the pre-sealed hash of the block and then
1031				// add it to a digest item.
1032				let to_sign = pre_hash.encode();
1033				let signature = keystore
1034					.sr25519_sign(sp_consensus_babe::AuthorityId::ID, alice.as_ref(), &to_sign)
1035					.unwrap()
1036					.unwrap();
1037				let item = <DigestItem as CompatibleDigestItem>::babe_seal(signature.into());
1038				slot += 1;
1039
1040				let mut params = BlockImportParams::new(BlockOrigin::File, new_header);
1041				params.post_digests.push(item);
1042				params.body = Some(new_body);
1043				params.insert_intermediate(
1044					INTERMEDIATE_KEY,
1045					BabeIntermediate::<Block> { epoch_descriptor },
1046				);
1047				params.fork_choice = Some(ForkChoiceStrategy::LongestChain);
1048
1049				futures::executor::block_on(block_import.import_block(params))
1050					.expect("error importing test block");
1051			},
1052			|service, _| {
1053				let amount = 5 * CENTS;
1054				let to: Address = AccountPublic::from(bob.public()).into_account().into();
1055				let from: Address = AccountPublic::from(charlie.public()).into_account().into();
1056				let genesis_hash = service.client().block_hash(0).unwrap().unwrap();
1057				let best_hash = service.client().chain_info().best_hash;
1058				let (spec_version, transaction_version) = {
1059					let version = service.client().runtime_version_at(best_hash).unwrap();
1060					(version.spec_version, version.transaction_version)
1061				};
1062				let signer = charlie.clone();
1063
1064				let function = RuntimeCall::Balances(BalancesCall::transfer_allow_death {
1065					dest: to.into(),
1066					value: amount,
1067				});
1068
1069				let authorize_call = frame_system::AuthorizeCall::new();
1070				let check_non_zero_sender = frame_system::CheckNonZeroSender::new();
1071				let check_spec_version = frame_system::CheckSpecVersion::new();
1072				let check_tx_version = frame_system::CheckTxVersion::new();
1073				let check_genesis = frame_system::CheckGenesis::new();
1074				let check_era = frame_system::CheckEra::from(Era::Immortal);
1075				let check_nonce = frame_system::CheckNonce::from(index);
1076				let check_weight = frame_system::CheckWeight::new();
1077				let tx_payment = pallet_skip_feeless_payment::SkipCheckIfFeeless::from(
1078					pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::from(0, None),
1079				);
1080				let weight_reclaim = frame_system::WeightReclaim::new();
1081				let metadata_hash = frame_metadata_hash_extension::CheckMetadataHash::new(false);
1082				let tx_ext: TxExtension = (
1083					authorize_call,
1084					check_non_zero_sender,
1085					check_spec_version,
1086					check_tx_version,
1087					check_genesis,
1088					check_era,
1089					check_nonce,
1090					check_weight,
1091					tx_payment,
1092					metadata_hash,
1093					weight_reclaim,
1094				);
1095				let raw_payload = SignedPayload::from_raw(
1096					function,
1097					tx_ext,
1098					(
1099						(),
1100						(),
1101						spec_version,
1102						transaction_version,
1103						genesis_hash,
1104						genesis_hash,
1105						(),
1106						(),
1107						(),
1108						None,
1109						(),
1110					),
1111				);
1112				let signature = raw_payload.using_encoded(|payload| signer.sign(payload));
1113				let (function, tx_ext, _) = raw_payload.deconstruct();
1114				index += 1;
1115				let utx: kitchensink_runtime::UncheckedExtrinsic =
1116					generic::UncheckedExtrinsic::new_signed(
1117						function,
1118						from.into(),
1119						signature.into(),
1120						tx_ext,
1121					)
1122					.into();
1123
1124				utx.into()
1125			},
1126		);
1127	}
1128
1129	#[test]
1130	#[ignore]
1131	fn test_consensus() {
1132		sp_tracing::try_init_simple();
1133
1134		sc_service_test::consensus(
1135			crate::chain_spec::tests::integration_test_config_with_two_authorities(),
1136			|config| {
1137				let NewFullBase { task_manager, client, network, sync, transaction_pool, .. } =
1138					new_full_base::<sc_network::NetworkWorker<_, _>>(
1139						config,
1140						None,
1141						false,
1142						|_, _| (),
1143					)?;
1144				Ok(sc_service_test::TestNetComponents::new(
1145					task_manager,
1146					client,
1147					network,
1148					sync,
1149					transaction_pool,
1150				))
1151			},
1152			vec!["//Alice".into(), "//Bob".into()],
1153		)
1154	}
1155}