git.delta.rocks / unique-network / refs/commits / 6bb4298375fb

difftreelog

source

node/cli/src/service.rs36.7 KiBsourcehistory
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617// std18use std::{19	collections::BTreeMap,20	marker::PhantomData,21	pin::Pin,22	sync::{Arc, Mutex},23	time::Duration,24};2526use cumulus_client_cli::CollatorOptions;27use cumulus_client_collator::service::CollatorService;28#[cfg(not(feature = "lookahead"))]29use cumulus_client_consensus_aura::collators::basic::{30	run as run_aura, Params as BuildAuraConsensusParams,31};32#[cfg(feature = "lookahead")]33use cumulus_client_consensus_aura::collators::lookahead::{34	run as run_aura, Params as BuildAuraConsensusParams,35};36use cumulus_client_consensus_common::ParachainBlockImport as TParachainBlockImport;37use cumulus_client_consensus_proposer::Proposer;38use cumulus_client_network::RequireSecondedInBlockAnnounce;39use cumulus_client_service::{40	build_relay_chain_interface, prepare_node_config, start_relay_chain_tasks, DARecoveryProfile,41	StartRelayChainTasksParams,42};43use cumulus_primitives_core::ParaId;44use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface};45use fc_mapping_sync::{kv::MappingSyncWorker, EthereumBlockNotificationSinks, SyncStrategy};46use fc_rpc::{47	frontier_backend_client::SystemAccountId32StorageOverride, EthBlockDataCacheTask, EthConfig,48	EthTask, OverrideHandle, RuntimeApiStorageOverride, SchemaV1Override, SchemaV2Override,49	SchemaV3Override, StorageOverride,50};51use fc_rpc_core::types::{FeeHistoryCache, FilterPool};52use fp_rpc::EthereumRuntimeRPCApi;53use fp_storage::EthereumStorageSchema;54use futures::{55	stream::select,56	task::{Context, Poll},57	Stream, StreamExt,58};59use jsonrpsee::RpcModule;60use polkadot_service::CollatorPair;61use sc_client_api::{AuxStore, Backend, BlockOf, BlockchainEvents, StorageProvider};62use sc_consensus::ImportQueue;63use sc_executor::{NativeElseWasmExecutor, NativeExecutionDispatch};64use sc_network::NetworkBlock;65use sc_network_sync::SyncingService;66use sc_rpc::SubscriptionTaskExecutor;67use sc_service::{Configuration, PartialComponents, TaskManager};68use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle};69use serde::{Deserialize, Serialize};70use sp_api::{ProvideRuntimeApi, StateBackend};71use sp_block_builder::BlockBuilder;72use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata};73use sp_consensus_aura::sr25519::AuthorityPair as AuraAuthorityPair;74use sp_keystore::KeystorePtr;75use sp_runtime::traits::BlakeTwo256;76use substrate_prometheus_endpoint::Registry;77use tokio::time::Interval;78use up_common::types::{opaque::*, Nonce};7980use crate::{81	chain_spec::RuntimeIdentification,82	rpc::{create_eth, create_full, EthDeps, FullDeps},83};8485/// Unique native executor instance.86#[cfg(feature = "unique-runtime")]87pub struct UniqueRuntimeExecutor;8889#[cfg(feature = "quartz-runtime")]90/// Quartz native executor instance.91pub struct QuartzRuntimeExecutor;9293/// Opal native executor instance.94pub struct OpalRuntimeExecutor;9596#[cfg(feature = "unique-runtime")]97impl NativeExecutionDispatch for UniqueRuntimeExecutor {98	/// Only enable the benchmarking host functions when we actually want to benchmark.99	#[cfg(feature = "runtime-benchmarks")]100	type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;101	/// Otherwise we only use the default Substrate host functions.102	#[cfg(not(feature = "runtime-benchmarks"))]103	type ExtendHostFunctions = ();104105	fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {106		unique_runtime::api::dispatch(method, data)107	}108109	fn native_version() -> sc_executor::NativeVersion {110		unique_runtime::native_version()111	}112}113114#[cfg(feature = "quartz-runtime")]115impl NativeExecutionDispatch for QuartzRuntimeExecutor {116	/// Only enable the benchmarking host functions when we actually want to benchmark.117	#[cfg(feature = "runtime-benchmarks")]118	type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;119	/// Otherwise we only use the default Substrate host functions.120	#[cfg(not(feature = "runtime-benchmarks"))]121	type ExtendHostFunctions = ();122123	fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {124		quartz_runtime::api::dispatch(method, data)125	}126127	fn native_version() -> sc_executor::NativeVersion {128		quartz_runtime::native_version()129	}130}131132impl NativeExecutionDispatch for OpalRuntimeExecutor {133	/// Only enable the benchmarking host functions when we actually want to benchmark.134	#[cfg(feature = "runtime-benchmarks")]135	type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;136	/// Otherwise we only use the default Substrate host functions.137	#[cfg(not(feature = "runtime-benchmarks"))]138	type ExtendHostFunctions = ();139140	fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {141		opal_runtime::api::dispatch(method, data)142	}143144	fn native_version() -> sc_executor::NativeVersion {145		opal_runtime::native_version()146	}147}148149pub struct AutosealInterval {150	interval: Interval,151}152153impl AutosealInterval {154	pub fn new(config: &Configuration, interval: u64) -> Self {155		let _tokio_runtime = config.tokio_handle.enter();156		let interval = tokio::time::interval(Duration::from_millis(interval));157158		Self { interval }159	}160}161162impl Stream for AutosealInterval {163	type Item = tokio::time::Instant;164165	fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {166		self.interval.poll_tick(cx).map(Some)167	}168}169170pub fn open_frontier_backend<C: HeaderBackend<Block>>(171	client: Arc<C>,172	config: &Configuration,173) -> Result<Arc<fc_db::kv::Backend<Block>>, String> {174	let config_dir = config.base_path.config_dir(config.chain_spec.id());175	let database_dir = config_dir.join("frontier").join("db");176177	Ok(Arc::new(fc_db::kv::Backend::<Block>::new(178		client,179		&fc_db::kv::DatabaseSettings {180			source: fc_db::DatabaseSource::RocksDb {181				path: database_dir,182				cache_size: 0,183			},184		},185	)?))186}187188type FullClient<RuntimeApi, ExecutorDispatch> =189	sc_service::TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<ExecutorDispatch>>;190type FullBackend = sc_service::TFullBackend<Block>;191type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;192type ParachainBlockImport<RuntimeApi, ExecutorDispatch> =193	TParachainBlockImport<Block, Arc<FullClient<RuntimeApi, ExecutorDispatch>>, FullBackend>;194195/// Generate a supertrait based on bounds, and blanket impl for it.196macro_rules! ez_bounds {197	($vis:vis trait $name:ident$(<$($gen:ident $(: $($(+)? $bound:path)*)?),* $(,)?>)? $(:)? $($(+)? $super:path)* {}) => {198		$vis trait $name $(<$($gen $(: $($bound+)*)?,)*>)?: $($super +)* {}199		impl<T, $($($gen $(: $($bound+)*)?,)*)?> $name$(<$($gen,)*>)? for T200		where T: $($super +)* {}201	}202}203ez_bounds!(204	pub trait RuntimeApiDep<Runtime: RuntimeInstance>:205		sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>206		+ sp_consensus_aura::AuraApi<Block, AuraId>207		+ fp_rpc::EthereumRuntimeRPCApi<Block>208		+ sp_session::SessionKeys<Block>209		+ sp_block_builder::BlockBuilder<Block>210		+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>211		+ sp_api::ApiExt<Block>212		+ up_rpc::UniqueApi<Block, Runtime::CrossAccountId, AccountId>213		+ app_promotion_rpc::AppPromotionApi<Block, BlockNumber, Runtime::CrossAccountId, AccountId>214		+ up_pov_estimate_rpc::PovEstimateApi<Block>215		+ substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Nonce>216		+ sp_api::Metadata<Block>217		+ sp_offchain::OffchainWorkerApi<Block>218		+ cumulus_primitives_core::CollectCollationInfo<Block>219		// Deprecated, not used.220		+ fp_rpc::ConvertTransactionRuntimeApi<Block>221	{222	}223);224#[cfg(not(feature = "lookahead"))]225ez_bounds!(226	pub trait LookaheadApiDep {}227);228#[cfg(feature = "lookahead")]229ez_bounds!(230	pub trait LookaheadApiDep: cumulus_primitives_aura::AuraUnincludedSegmentApi<Block> {}231);232233/// Starts a `ServiceBuilder` for a full service.234///235/// Use this macro if you don't actually need the full service, but just the builder in order to236/// be able to perform chain operations.237#[allow(clippy::type_complexity)]238pub fn new_partial<Runtime, RuntimeApi, ExecutorDispatch, BIQ>(239	config: &Configuration,240	build_import_queue: BIQ,241) -> Result<242	PartialComponents<243		FullClient<RuntimeApi, ExecutorDispatch>,244		FullBackend,245		FullSelectChain,246		sc_consensus::DefaultImportQueue<Block>,247		sc_transaction_pool::FullPool<Block, FullClient<RuntimeApi, ExecutorDispatch>>,248		OtherPartial,249	>,250	sc_service::Error,251>252where253	sc_client_api::StateBackendFor<FullBackend, Block>: sp_api::StateBackend<BlakeTwo256>,254	RuntimeApi: sp_api::ConstructRuntimeApi<Block, FullClient<RuntimeApi, ExecutorDispatch>>255		+ Send256		+ Sync257		+ 'static,258	RuntimeApi::RuntimeApi: RuntimeApiDep<Runtime> + 'static,259	Runtime: RuntimeInstance,260	ExecutorDispatch: NativeExecutionDispatch + 'static,261	BIQ: FnOnce(262		Arc<FullClient<RuntimeApi, ExecutorDispatch>>,263		Arc<FullBackend>,264		&Configuration,265		Option<TelemetryHandle>,266		&TaskManager,267	) -> Result<sc_consensus::DefaultImportQueue<Block>, sc_service::Error>,268{269	let telemetry = config270		.telemetry_endpoints271		.clone()272		.filter(|x| !x.is_empty())273		.map(|endpoints| -> Result<_, sc_telemetry::Error> {274			let worker = TelemetryWorker::new(16)?;275			let telemetry = worker.handle().new_telemetry(endpoints);276			Ok((worker, telemetry))277		})278		.transpose()?;279280	let executor = sc_service::new_native_or_wasm_executor(config);281282	let (client, backend, keystore_container, task_manager) =283		sc_service::new_full_parts::<Block, RuntimeApi, _>(284			config,285			telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),286			executor,287		)?;288	let client = Arc::new(client);289290	let telemetry_worker_handle = telemetry.as_ref().map(|(worker, _)| worker.handle());291292	let telemetry = telemetry.map(|(worker, telemetry)| {293		task_manager294			.spawn_handle()295			.spawn("telemetry", None, worker.run());296		telemetry297	});298299	let select_chain = sc_consensus::LongestChain::new(backend.clone());300301	let transaction_pool = sc_transaction_pool::BasicPool::new_full(302		config.transaction_pool.clone(),303		config.role.is_authority().into(),304		config.prometheus_registry(),305		task_manager.spawn_essential_handle(),306		client.clone(),307	);308309	let eth_filter_pool: Option<FilterPool> = Some(Arc::new(Mutex::new(BTreeMap::new())));310311	let eth_backend = open_frontier_backend(client.clone(), config)?;312313	let import_queue = build_import_queue(314		client.clone(),315		backend.clone(),316		config,317		telemetry.as_ref().map(|telemetry| telemetry.handle()),318		&task_manager,319	)?;320321	let params = PartialComponents {322		backend,323		client,324		import_queue,325		keystore_container,326		task_manager,327		transaction_pool,328		select_chain,329		other: OtherPartial {330			telemetry,331			eth_filter_pool,332			eth_backend,333			telemetry_worker_handle,334		},335	};336337	Ok(params)338}339340macro_rules! clone {341    ($($i:ident),* $(,)?) => {342		$(343			let $i = $i.clone();344		)*345    };346}347348/// Start a node with the given parachain `Configuration` and relay chain `Configuration`.349///350/// This is the actual implementation that is abstract over the executor and the runtime api.351#[sc_tracing::logging::prefix_logs_with("Parachain")]352pub async fn start_node<Runtime, RuntimeApi, ExecutorDispatch>(353	parachain_config: Configuration,354	polkadot_config: Configuration,355	collator_options: CollatorOptions,356	para_id: ParaId,357	hwbench: Option<sc_sysinfo::HwBench>,358) -> sc_service::error::Result<(TaskManager, Arc<FullClient<RuntimeApi, ExecutorDispatch>>)>359where360	sc_client_api::StateBackendFor<FullBackend, Block>: sp_api::StateBackend<BlakeTwo256>,361	Runtime: RuntimeInstance + Send + Sync + 'static,362	<Runtime as RuntimeInstance>::CrossAccountId: Serialize,363	for<'de> <Runtime as RuntimeInstance>::CrossAccountId: Deserialize<'de>,364	RuntimeApi: sp_api::ConstructRuntimeApi<Block, FullClient<RuntimeApi, ExecutorDispatch>>365		+ Send366		+ Sync367		+ 'static,368	RuntimeApi::RuntimeApi: RuntimeApiDep<Runtime> + 'static,369	RuntimeApi::RuntimeApi: LookaheadApiDep,370	Runtime: RuntimeInstance,371	ExecutorDispatch: NativeExecutionDispatch + 'static,372{373	let parachain_config = prepare_node_config(parachain_config);374375	let params = new_partial::<Runtime, RuntimeApi, ExecutorDispatch, _>(376		&parachain_config,377		parachain_build_import_queue,378	)?;379	let OtherPartial {380		mut telemetry,381		telemetry_worker_handle,382		eth_filter_pool,383		eth_backend,384	} = params.other;385	let net_config = sc_network::config::FullNetworkConfiguration::new(&parachain_config.network);386387	let client = params.client.clone();388	let backend = params.backend.clone();389	let mut task_manager = params.task_manager;390391	let (relay_chain_interface, collator_key) = build_relay_chain_interface(392		polkadot_config,393		&parachain_config,394		telemetry_worker_handle,395		&mut task_manager,396		collator_options.clone(),397		hwbench.clone(),398	)399	.await400	.map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?;401402	let block_announce_validator =403		RequireSecondedInBlockAnnounce::new(relay_chain_interface.clone(), para_id);404405	let validator = parachain_config.role.is_authority();406	let prometheus_registry = parachain_config.prometheus_registry().cloned();407	let transaction_pool = params.transaction_pool.clone();408	let import_queue_service = params.import_queue.service();409410	let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) =411		sc_service::build_network(sc_service::BuildNetworkParams {412			config: &parachain_config,413			net_config,414			client: client.clone(),415			transaction_pool: transaction_pool.clone(),416			spawn_handle: task_manager.spawn_handle(),417			import_queue: params.import_queue,418			block_announce_validator_builder: Some(Box::new(|_| {419				Box::new(block_announce_validator)420			})),421			warp_sync_params: None,422		})?;423424	let select_chain = params.select_chain.clone();425426	let runtime_id = parachain_config.chain_spec.runtime_id();427428	// Frontier429	let fee_history_cache: FeeHistoryCache = Arc::new(Mutex::new(BTreeMap::new()));430	let fee_history_limit = 2048;431432	let eth_pubsub_notification_sinks: Arc<433		EthereumBlockNotificationSinks<fc_mapping_sync::EthereumBlockNotification<Block>>,434	> = Default::default();435436	let overrides = overrides_handle(client.clone());437	let eth_block_data_cache = spawn_frontier_tasks(438		FrontierTaskParams {439			client: client.clone(),440			substrate_backend: backend.clone(),441			eth_filter_pool: eth_filter_pool.clone(),442			eth_backend: eth_backend.clone(),443			fee_history_limit,444			fee_history_cache: fee_history_cache.clone(),445			task_manager: &task_manager,446			prometheus_registry: prometheus_registry.clone(),447			overrides: overrides.clone(),448			sync_strategy: SyncStrategy::Parachain,449		},450		sync_service.clone(),451		eth_pubsub_notification_sinks.clone(),452	);453454	// Rpc455	let rpc_builder = Box::new({456		clone!(457			client,458			backend,459			eth_backend,460			eth_pubsub_notification_sinks,461			fee_history_cache,462			eth_block_data_cache,463			overrides,464			transaction_pool,465			network,466			sync_service,467		);468		move |deny_unsafe, subscription_task_executor: SubscriptionTaskExecutor| {469			clone!(470				backend,471				eth_block_data_cache,472				client,473				eth_backend,474				eth_filter_pool,475				eth_pubsub_notification_sinks,476				fee_history_cache,477				eth_block_data_cache,478				network,479				runtime_id,480				transaction_pool,481				select_chain,482				overrides,483			);484485			#[cfg(not(feature = "pov-estimate"))]486			let _ = backend;487488			let mut rpc_handle = RpcModule::new(());489490			let full_deps = FullDeps {491				client: client.clone(),492				runtime_id,493494				#[cfg(feature = "pov-estimate")]495				exec_params: uc_rpc::pov_estimate::ExecutorParams {496					wasm_method: parachain_config.wasm_method,497					default_heap_pages: parachain_config.default_heap_pages,498					max_runtime_instances: parachain_config.max_runtime_instances,499					runtime_cache_size: parachain_config.runtime_cache_size,500				},501502				#[cfg(feature = "pov-estimate")]503				backend,504505				deny_unsafe,506				pool: transaction_pool.clone(),507				select_chain,508			};509510			create_full::<_, _, _, Runtime, _>(&mut rpc_handle, full_deps)?;511512			let eth_deps = EthDeps {513				client,514				graph: transaction_pool.pool().clone(),515				pool: transaction_pool,516				is_authority: validator,517				network,518				eth_backend,519				// TODO: Unhardcode520				max_past_logs: 10000,521				fee_history_limit,522				fee_history_cache,523				eth_block_data_cache,524				// TODO: Unhardcode525				enable_dev_signer: false,526				eth_filter_pool,527				eth_pubsub_notification_sinks,528				overrides,529				sync: sync_service.clone(),530				pending_create_inherent_data_providers: |_, ()| async move { Ok(()) },531			};532533			create_eth::<534				_,535				_,536				_,537				_,538				_,539				_,540				DefaultEthConfig<FullClient<RuntimeApi, ExecutorDispatch>>,541			>(542				&mut rpc_handle,543				eth_deps,544				subscription_task_executor.clone(),545			)?;546547			Ok(rpc_handle)548		}549	});550551	sc_service::spawn_tasks(sc_service::SpawnTasksParams {552		rpc_builder,553		client: client.clone(),554		transaction_pool: transaction_pool.clone(),555		task_manager: &mut task_manager,556		config: parachain_config,557		keystore: params.keystore_container.keystore(),558		backend: backend.clone(),559		network,560		sync_service: sync_service.clone(),561		system_rpc_tx,562		telemetry: telemetry.as_mut(),563		tx_handler_controller,564	})?;565566	if let Some(hwbench) = hwbench {567		sc_sysinfo::print_hwbench(&hwbench);568569		if let Some(ref mut telemetry) = telemetry {570			let telemetry_handle = telemetry.handle();571			task_manager.spawn_handle().spawn(572				"telemetry_hwbench",573				None,574				sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench),575			);576		}577	}578579	let announce_block = {580		let sync_service = sync_service.clone();581		Arc::new(Box::new(move |hash, data| {582			sync_service.announce_block(hash, data)583		}))584	};585586	let relay_chain_slot_duration = Duration::from_secs(6);587588	let overseer_handle = relay_chain_interface589		.overseer_handle()590		.map_err(|e| sc_service::Error::Application(Box::new(e)))?;591592	start_relay_chain_tasks(StartRelayChainTasksParams {593		client: client.clone(),594		announce_block: announce_block.clone(),595		para_id,596		relay_chain_interface: relay_chain_interface.clone(),597		task_manager: &mut task_manager,598		da_recovery_profile: if validator {599			DARecoveryProfile::Collator600		} else {601			DARecoveryProfile::FullNode602		},603		import_queue: import_queue_service,604		relay_chain_slot_duration,605		recovery_handle: Box::new(overseer_handle.clone()),606		sync_service: sync_service.clone(),607	})?;608609	if validator {610		start_consensus(611			client.clone(),612			transaction_pool,613			StartConsensusParameters {614				backend: backend.clone(),615				prometheus_registry: prometheus_registry.as_ref(),616				telemetry: telemetry.as_ref().map(|t| t.handle()),617				task_manager: &task_manager,618				relay_chain_interface: relay_chain_interface.clone(),619				sync_oracle: sync_service,620				keystore: params.keystore_container.keystore(),621				overseer_handle,622				relay_chain_slot_duration,623				para_id,624				collator_key: collator_key.expect("cli args do not allow this"),625				announce_block,626			},627		)?;628	}629630	start_network.start_network();631632	Ok((task_manager, client))633}634635/// Build the import queue for the the parachain runtime.636pub fn parachain_build_import_queue<Runtime, RuntimeApi, ExecutorDispatch>(637	client: Arc<FullClient<RuntimeApi, ExecutorDispatch>>,638	backend: Arc<FullBackend>,639	config: &Configuration,640	telemetry: Option<TelemetryHandle>,641	task_manager: &TaskManager,642) -> Result<sc_consensus::DefaultImportQueue<Block>, sc_service::Error>643where644	RuntimeApi: sp_api::ConstructRuntimeApi<Block, FullClient<RuntimeApi, ExecutorDispatch>>645		+ Send646		+ Sync647		+ 'static,648	RuntimeApi::RuntimeApi: RuntimeApiDep<Runtime> + 'static,649	Runtime: RuntimeInstance,650	ExecutorDispatch: NativeExecutionDispatch + 'static,651{652	let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?;653654	let block_import = ParachainBlockImport::new(client.clone(), backend);655656	cumulus_client_consensus_aura::import_queue::<657		sp_consensus_aura::sr25519::AuthorityPair,658		_,659		_,660		_,661		_,662		_,663	>(cumulus_client_consensus_aura::ImportQueueParams {664		block_import,665		client,666		create_inherent_data_providers: move |_, _| async move {667			let time = sp_timestamp::InherentDataProvider::from_system_time();668669			let slot =670				sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(671					*time,672					slot_duration,673				);674675			Ok((slot, time))676		},677		registry: config.prometheus_registry(),678		spawner: &task_manager.spawn_essential_handle(),679		telemetry,680	})681	.map_err(Into::into)682}683684pub struct StartConsensusParameters<'a> {685	backend: Arc<FullBackend>,686	prometheus_registry: Option<&'a Registry>,687	telemetry: Option<TelemetryHandle>,688	task_manager: &'a TaskManager,689	relay_chain_interface: Arc<dyn RelayChainInterface>,690	sync_oracle: Arc<SyncingService<Block>>,691	keystore: KeystorePtr,692	overseer_handle: OverseerHandle,693	relay_chain_slot_duration: Duration,694	para_id: ParaId,695	collator_key: CollatorPair,696	announce_block: Arc<dyn Fn(Hash, Option<Vec<u8>>) + Send + Sync>,697}698699// Clones ignored for optional lookahead collator700#[allow(clippy::redundant_clone)]701pub fn start_consensus<ExecutorDispatch, RuntimeApi, Runtime>(702	client: Arc<FullClient<RuntimeApi, ExecutorDispatch>>,703	transaction_pool: Arc<704		sc_transaction_pool::FullPool<Block, FullClient<RuntimeApi, ExecutorDispatch>>,705	>,706	parameters: StartConsensusParameters<'_>,707) -> Result<(), sc_service::Error>708where709	ExecutorDispatch: NativeExecutionDispatch + 'static,710	RuntimeApi: sp_api::ConstructRuntimeApi<Block, FullClient<RuntimeApi, ExecutorDispatch>>711		+ Send712		+ Sync713		+ 'static,714	RuntimeApi::RuntimeApi: RuntimeApiDep<Runtime> + 'static,715	RuntimeApi::RuntimeApi: LookaheadApiDep,716	Runtime: RuntimeInstance,717{718	let StartConsensusParameters {719		backend,720		prometheus_registry,721		telemetry,722		task_manager,723		relay_chain_interface,724		sync_oracle,725		keystore,726		overseer_handle,727		relay_chain_slot_duration,728		para_id,729		collator_key,730		announce_block,731	} = parameters;732	let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?;733734	let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording(735		task_manager.spawn_handle(),736		client.clone(),737		transaction_pool,738		prometheus_registry,739		telemetry,740	);741	let proposer = Proposer::new(proposer_factory);742743	let collator_service = CollatorService::new(744		client.clone(),745		Arc::new(task_manager.spawn_handle()),746		announce_block,747		client.clone(),748	);749750	let block_import = ParachainBlockImport::new(client.clone(), backend.clone());751752	let params = BuildAuraConsensusParams {753		create_inherent_data_providers: move |_, ()| async move { Ok(()) },754		block_import,755		para_client: client.clone(),756		#[cfg(feature = "lookahead")]757		para_backend: backend,758		para_id,759		relay_client: relay_chain_interface,760		sync_oracle,761		keystore,762		slot_duration,763		proposer,764		collator_service,765		// With async-baking, we allowed to be both slower (longer authoring) and faster (multiple para blocks per relay block)766		#[cfg(not(feature = "lookahead"))]767		authoring_duration: Duration::from_millis(500),768		#[cfg(feature = "lookahead")]769		authoring_duration: Duration::from_millis(1500),770		overseer_handle,771		#[cfg(feature = "lookahead")]772		code_hash_provider: move |block_hash| {773			client774				.code_at(block_hash)775				.ok()776				.map(cumulus_primitives_core::relay_chain::ValidationCode)777				.map(|c| c.hash())778		},779		collator_key,780		relay_chain_slot_duration,781	};782783	task_manager.spawn_essential_handle().spawn(784		"aura",785		None,786		#[cfg(not(feature = "lookahead"))]787		run_aura::<_, AuraAuthorityPair, _, _, _, _, _, _, _>(params),788		#[cfg(feature = "lookahead")]789		run_aura::<_, AuraAuthorityPair, _, _, _, _, _, _, _, _, _>(params),790	);791	Ok(())792}793794fn dev_build_import_queue<RuntimeApi, ExecutorDispatch>(795	client: Arc<FullClient<RuntimeApi, ExecutorDispatch>>,796	_: Arc<FullBackend>,797	config: &Configuration,798	_: Option<TelemetryHandle>,799	task_manager: &TaskManager,800) -> Result<sc_consensus::DefaultImportQueue<Block>, sc_service::Error>801where802	RuntimeApi: sp_api::ConstructRuntimeApi<Block, FullClient<RuntimeApi, ExecutorDispatch>>803		+ Send804		+ Sync805		+ 'static,806	RuntimeApi::RuntimeApi:807		sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> + sp_api::ApiExt<Block>,808	ExecutorDispatch: NativeExecutionDispatch + 'static,809{810	Ok(sc_consensus_manual_seal::import_queue(811		Box::new(client),812		&task_manager.spawn_essential_handle(),813		config.prometheus_registry(),814	))815}816817pub struct OtherPartial {818	pub telemetry: Option<Telemetry>,819	pub telemetry_worker_handle: Option<TelemetryWorkerHandle>,820	pub eth_filter_pool: Option<FilterPool>,821	pub eth_backend: Arc<fc_db::kv::Backend<Block>>,822}823824struct DefaultEthConfig<C>(PhantomData<C>);825impl<C> EthConfig<Block, C> for DefaultEthConfig<C>826where827	C: StorageProvider<Block, FullBackend> + Sync + Send + 'static,828{829	type EstimateGasAdapter = ();830	type RuntimeStorageOverride = SystemAccountId32StorageOverride<Block, C, FullBackend>;831}832833/// Builds a new development service. This service uses instant seal, and mocks834/// the parachain inherent835pub fn start_dev_node<Runtime, RuntimeApi, ExecutorDispatch>(836	config: Configuration,837	autoseal_interval: u64,838	autoseal_finalize_delay: Option<u64>,839	disable_autoseal_on_tx: bool,840) -> sc_service::error::Result<TaskManager>841where842	Runtime: RuntimeInstance + Send + Sync + 'static,843	<Runtime as RuntimeInstance>::CrossAccountId: Serialize,844	for<'de> <Runtime as RuntimeInstance>::CrossAccountId: Deserialize<'de>,845	RuntimeApi: sp_api::ConstructRuntimeApi<Block, FullClient<RuntimeApi, ExecutorDispatch>>846		+ Send847		+ Sync848		+ 'static,849	RuntimeApi::RuntimeApi: RuntimeApiDep<Runtime> + 'static,850	ExecutorDispatch: NativeExecutionDispatch + 'static,851{852	use fc_consensus::FrontierBlockImport;853	use sc_consensus_manual_seal::{854		run_delayed_finalize, run_manual_seal, DelayedFinalizeParams, EngineCommand,855		ManualSealParams,856	};857858	let sc_service::PartialComponents {859		client,860		backend,861		mut task_manager,862		import_queue,863		keystore_container,864		select_chain: maybe_select_chain,865		transaction_pool,866		other:867			OtherPartial {868				telemetry,869				eth_filter_pool,870				eth_backend,871				telemetry_worker_handle: _,872			},873	} = new_partial::<Runtime, RuntimeApi, ExecutorDispatch, _>(874		&config,875		dev_build_import_queue::<RuntimeApi, ExecutorDispatch>,876	)?;877	let net_config = sc_network::config::FullNetworkConfiguration::new(&config.network);878	let prometheus_registry = config.prometheus_registry().cloned();879880	let (network, system_rpc_tx, tx_handler_controller, network_starter, sync_service) =881		sc_service::build_network(sc_service::BuildNetworkParams {882			config: &config,883			net_config,884			client: client.clone(),885			transaction_pool: transaction_pool.clone(),886			spawn_handle: task_manager.spawn_handle(),887			import_queue,888			block_announce_validator_builder: None,889			warp_sync_params: None,890		})?;891892	let collator = config.role.is_authority();893894	let select_chain = maybe_select_chain;895896	if collator {897		let block_import = FrontierBlockImport::new(client.clone(), client.clone());898899		let env = sc_basic_authorship::ProposerFactory::new(900			task_manager.spawn_handle(),901			client.clone(),902			transaction_pool.clone(),903			prometheus_registry.as_ref(),904			telemetry.as_ref().map(|x| x.handle()),905		);906907		let transactions_commands_stream: Box<908			dyn Stream<Item = EngineCommand<Hash>> + Send + Sync + Unpin,909		> = Box::new(910			transaction_pool911				.pool()912				.validated_pool()913				.import_notification_stream()914				.filter(move |_| futures::future::ready(!disable_autoseal_on_tx))915				.map(|_| EngineCommand::SealNewBlock {916					create_empty: true,917					finalize: false,918					parent_hash: None,919					sender: None,920				}),921		);922923		let autoseal_interval = Box::pin(AutosealInterval::new(&config, autoseal_interval));924925		let idle_commands_stream: Box<926			dyn Stream<Item = EngineCommand<Hash>> + Send + Sync + Unpin,927		> = Box::new(autoseal_interval.map(|_| EngineCommand::SealNewBlock {928			create_empty: true,929			finalize: false,930			parent_hash: None,931			sender: None,932		}));933934		let commands_stream = select(transactions_commands_stream, idle_commands_stream);935936		let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?;937		let client_set_aside_for_cidp = client.clone();938939		if let Some(delay_sec) = autoseal_finalize_delay {940			let spawn_handle = task_manager.spawn_handle();941942			task_manager.spawn_essential_handle().spawn_blocking(943				"finalization_task",944				Some("block-authoring"),945				run_delayed_finalize(DelayedFinalizeParams {946					client: client.clone(),947					delay_sec,948					spawn_handle,949				}),950			);951		}952953		task_manager.spawn_essential_handle().spawn_blocking(954			"authorship_task",955			Some("block-authoring"),956			run_manual_seal(ManualSealParams {957				block_import,958				env,959				client: client.clone(),960				pool: transaction_pool.clone(),961				commands_stream,962				select_chain: select_chain.clone(),963				consensus_data_provider: None,964				create_inherent_data_providers: move |block: Hash, ()| {965					let current_para_block = client_set_aside_for_cidp966						.number(block)967						.expect("Header lookup should succeed")968						.expect("Header passed in as parent should be present in backend.");969970					let client_for_xcm = client_set_aside_for_cidp.clone();971					async move {972						let time = sp_timestamp::InherentDataProvider::from_system_time();973974						let mocked_parachain = cumulus_primitives_parachain_inherent::MockValidationDataInherentDataProvider {975							current_para_block,976							relay_offset: 1000,977							relay_blocks_per_para_block: 2,978							para_blocks_per_relay_epoch: 0,979							xcm_config: cumulus_primitives_parachain_inherent::MockXcmConfig::new(980								&*client_for_xcm,981								block,982								Default::default(),983								Default::default(),984							),985							relay_randomness_config: (),986							raw_downward_messages: vec![],987							raw_horizontal_messages: vec![],988						};989990						let slot =991						sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(992							*time,993							slot_duration,994						);995996						Ok((time, slot, mocked_parachain))997					}998				},999			}),1000		);1001	}10021003	#[cfg(feature = "pov-estimate")]1004	let rpc_backend = backend.clone();10051006	let runtime_id = config.chain_spec.runtime_id();10071008	// Frontier1009	let fee_history_cache: FeeHistoryCache = Arc::new(Mutex::new(BTreeMap::new()));1010	let fee_history_limit = 2048;10111012	let eth_pubsub_notification_sinks: Arc<1013		EthereumBlockNotificationSinks<fc_mapping_sync::EthereumBlockNotification<Block>>,1014	> = Default::default();10151016	let overrides = overrides_handle(client.clone());1017	let eth_block_data_cache = spawn_frontier_tasks(1018		FrontierTaskParams {1019			client: client.clone(),1020			substrate_backend: backend.clone(),1021			eth_filter_pool: eth_filter_pool.clone(),1022			eth_backend: eth_backend.clone(),1023			fee_history_limit,1024			fee_history_cache: fee_history_cache.clone(),1025			task_manager: &task_manager,1026			prometheus_registry,1027			overrides: overrides.clone(),1028			sync_strategy: SyncStrategy::Normal,1029		},1030		sync_service.clone(),1031		eth_pubsub_notification_sinks.clone(),1032	);10331034	// Rpc1035	let rpc_builder = Box::new({1036		clone!(1037			client,1038			backend,1039			eth_backend,1040			eth_pubsub_notification_sinks,1041			fee_history_cache,1042			eth_block_data_cache,1043			overrides,1044			transaction_pool,1045			network,1046			sync_service,1047		);1048		move |deny_unsafe, subscription_task_executor: SubscriptionTaskExecutor| {1049			clone!(1050				backend,1051				eth_block_data_cache,1052				client,1053				eth_backend,1054				eth_filter_pool,1055				eth_pubsub_notification_sinks,1056				fee_history_cache,1057				eth_block_data_cache,1058				network,1059				runtime_id,1060				transaction_pool,1061				select_chain,1062				overrides,1063			);10641065			#[cfg(not(feature = "pov-estimate"))]1066			let _ = backend;10671068			let mut rpc_module = RpcModule::new(());10691070			let full_deps = FullDeps {1071				runtime_id,10721073				#[cfg(feature = "pov-estimate")]1074				exec_params: uc_rpc::pov_estimate::ExecutorParams {1075					wasm_method: config.wasm_method,1076					default_heap_pages: config.default_heap_pages,1077					max_runtime_instances: config.max_runtime_instances,1078					runtime_cache_size: config.runtime_cache_size,1079				},10801081				#[cfg(feature = "pov-estimate")]1082				backend,1083				// eth_backend,1084				deny_unsafe,1085				client: client.clone(),1086				pool: transaction_pool.clone(),1087				select_chain,1088			};10891090			create_full::<_, _, _, Runtime, _>(&mut rpc_module, full_deps)?;10911092			let eth_deps = EthDeps {1093				client,1094				graph: transaction_pool.pool().clone(),1095				pool: transaction_pool,1096				is_authority: true,1097				network,1098				eth_backend,1099				// TODO: Unhardcode1100				max_past_logs: 10000,1101				fee_history_limit,1102				fee_history_cache,1103				eth_block_data_cache,1104				// TODO: Unhardcode1105				enable_dev_signer: false,1106				eth_filter_pool,1107				eth_pubsub_notification_sinks,1108				overrides,1109				sync: sync_service.clone(),1110				// We don't have any inherents except parachain built-ins, which we can't even extract from inside `run_aura`.1111				pending_create_inherent_data_providers: |_, ()| async move { Ok(()) },1112			};11131114			create_eth::<1115				_,1116				_,1117				_,1118				_,1119				_,1120				_,1121				DefaultEthConfig<FullClient<RuntimeApi, ExecutorDispatch>>,1122			>(1123				&mut rpc_module,1124				eth_deps,1125				subscription_task_executor.clone(),1126			)?;11271128			Ok(rpc_module)1129		}1130	});11311132	sc_service::spawn_tasks(sc_service::SpawnTasksParams {1133		network,1134		sync_service,1135		client,1136		keystore: keystore_container.keystore(),1137		task_manager: &mut task_manager,1138		transaction_pool,1139		rpc_builder,1140		backend,1141		system_rpc_tx,1142		config,1143		telemetry: None,1144		tx_handler_controller,1145	})?;11461147	network_starter.start_network();1148	Ok(task_manager)1149}11501151fn overrides_handle<C, BE>(client: Arc<C>) -> Arc<OverrideHandle<Block>>1152where1153	C: ProvideRuntimeApi<Block> + StorageProvider<Block, BE> + AuxStore,1154	C: HeaderBackend<Block> + HeaderMetadata<Block, Error = BlockChainError>,1155	C: Send + Sync + 'static,1156	C::Api: fp_rpc::EthereumRuntimeRPCApi<Block>,1157	BE: Backend<Block> + 'static,1158	BE::State: StateBackend<BlakeTwo256>,1159{1160	let mut overrides_map = BTreeMap::new();1161	overrides_map.insert(1162		EthereumStorageSchema::V1,1163		Box::new(SchemaV1Override::new(client.clone())) as Box<dyn StorageOverride<_> + 'static>,1164	);1165	overrides_map.insert(1166		EthereumStorageSchema::V2,1167		Box::new(SchemaV2Override::new(client.clone())) as Box<dyn StorageOverride<_> + 'static>,1168	);1169	overrides_map.insert(1170		EthereumStorageSchema::V3,1171		Box::new(SchemaV3Override::new(client.clone())) as Box<dyn StorageOverride<_> + 'static>,1172	);11731174	Arc::new(OverrideHandle {1175		schemas: overrides_map,1176		fallback: Box::new(RuntimeApiStorageOverride::new(client)),1177	})1178}11791180pub struct FrontierTaskParams<'a, C, B> {1181	pub task_manager: &'a TaskManager,1182	pub client: Arc<C>,1183	pub substrate_backend: Arc<B>,1184	pub eth_backend: Arc<fc_db::kv::Backend<Block>>,1185	pub eth_filter_pool: Option<FilterPool>,1186	pub overrides: Arc<OverrideHandle<Block>>,1187	pub fee_history_limit: u64,1188	pub fee_history_cache: FeeHistoryCache,1189	pub sync_strategy: SyncStrategy,1190	pub prometheus_registry: Option<Registry>,1191}11921193pub fn spawn_frontier_tasks<C, B>(1194	params: FrontierTaskParams<C, B>,1195	sync: Arc<SyncingService<Block>>,1196	pubsub_notification_sinks: Arc<1197		EthereumBlockNotificationSinks<fc_mapping_sync::EthereumBlockNotification<Block>>,1198	>,1199) -> Arc<EthBlockDataCacheTask<Block>>1200where1201	C: ProvideRuntimeApi<Block> + BlockOf,1202	C: HeaderBackend<Block> + HeaderMetadata<Block, Error = BlockChainError> + 'static,1203	C: BlockchainEvents<Block> + StorageProvider<Block, B>,1204	C: Send + Sync + 'static,1205	C::Api: EthereumRuntimeRPCApi<Block>,1206	C::Api: BlockBuilder<Block>,1207	B: Backend<Block> + 'static,1208	B::State: StateBackend<BlakeTwo256>,1209{1210	let FrontierTaskParams {1211		task_manager,1212		client,1213		substrate_backend,1214		eth_backend,1215		eth_filter_pool,1216		overrides,1217		fee_history_limit,1218		fee_history_cache,1219		sync_strategy,1220		prometheus_registry,1221	} = params;1222	// Frontier offchain DB task. Essential.1223	// Maps emulated ethereum data to substrate native data.1224	params.task_manager.spawn_essential_handle().spawn(1225		"frontier-mapping-sync-worker",1226		Some("frontier"),1227		MappingSyncWorker::new(1228			client.import_notification_stream(),1229			Duration::new(6, 0),1230			client.clone(),1231			substrate_backend,1232			overrides.clone(),1233			eth_backend,1234			3,1235			0,1236			sync_strategy,1237			sync,1238			pubsub_notification_sinks,1239		)1240		.for_each(|()| futures::future::ready(())),1241	);12421243	// Frontier `EthFilterApi` maintenance.1244	// Manages the pool of user-created Filters.1245	if let Some(eth_filter_pool) = eth_filter_pool {1246		// Each filter is allowed to stay in the pool for 100 blocks.1247		const FILTER_RETAIN_THRESHOLD: u64 = 100;1248		params.task_manager.spawn_essential_handle().spawn(1249			"frontier-filter-pool",1250			Some("frontier"),1251			EthTask::filter_pool_task(client.clone(), eth_filter_pool, FILTER_RETAIN_THRESHOLD),1252		);1253	}12541255	// Spawn Frontier FeeHistory cache maintenance task.1256	params.task_manager.spawn_essential_handle().spawn(1257		"frontier-fee-history",1258		Some("frontier"),1259		EthTask::fee_history_task(1260			client,1261			overrides.clone(),1262			fee_history_cache,1263			fee_history_limit,1264		),1265	);12661267	Arc::new(EthBlockDataCacheTask::new(1268		task_manager.spawn_handle(),1269		overrides,1270		50,1271		50,1272		prometheus_registry,1273	))1274}