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