123456789use std::sync::Arc;10use std::sync::Mutex;11use std::collections::BTreeMap;12use std::time::Duration;13use fc_rpc_core::types::FeeHistoryCache;14use futures::StreamExt;1516use unique_rpc::overrides_handle;1718use unique_runtime::RuntimeApi;192021use cumulus_client_consensus_aura::{AuraConsensus, BuildAuraConsensusParams, SlotProportion};22use cumulus_client_consensus_common::ParachainConsensus;23use cumulus_client_service::{24 prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams,25};26use cumulus_client_network::BlockAnnounceValidator;27use cumulus_primitives_core::ParaId;28use cumulus_relay_chain_interface::RelayChainInterface;29use cumulus_relay_chain_local::build_relay_chain_interface;303132use sc_client_api::ExecutorProvider;33use sc_executor::NativeElseWasmExecutor;34use sc_executor::NativeExecutionDispatch;35use sc_network::NetworkService;36use sc_service::{BasePath, Configuration, PartialComponents, Role, TaskManager};37use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle};38use sp_consensus::SlotData;39use sp_keystore::SyncCryptoStorePtr;40use sp_runtime::traits::BlakeTwo256;41use substrate_prometheus_endpoint::Registry;42use sc_client_api::BlockchainEvents;434445use fc_rpc_core::types::FilterPool;46use fc_mapping_sync::{MappingSyncWorker, SyncStrategy};474849type BlockNumber = u32;50type Header = sp_runtime::generic::Header<BlockNumber, sp_runtime::traits::BlakeTwo256>;51pub type Block = sp_runtime::generic::Block<Header, sp_runtime::OpaqueExtrinsic>;52type Hash = sp_core::H256;535455pub struct ParachainRuntimeExecutor;5657impl NativeExecutionDispatch for ParachainRuntimeExecutor {58 type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;5960 fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {61 unique_runtime::api::dispatch(method, data)62 }6364 fn native_version() -> sc_executor::NativeVersion {65 unique_runtime::native_version()66 }67}6869pub fn open_frontier_backend(config: &Configuration) -> Result<Arc<fc_db::Backend<Block>>, String> {70 let config_dir = config71 .base_path72 .as_ref()73 .map(|base_path| base_path.config_dir(config.chain_spec.id()))74 .unwrap_or_else(|| {75 BasePath::from_project("", "", "unique").config_dir(config.chain_spec.id())76 });77 let database_dir = config_dir.join("frontier").join("db");7879 Ok(Arc::new(fc_db::Backend::<Block>::new(80 &fc_db::DatabaseSettings {81 source: fc_db::DatabaseSettingsSrc::RocksDb {82 path: database_dir,83 cache_size: 0,84 },85 },86 )?))87}8889type ExecutorDispatch = ParachainRuntimeExecutor;9091type FullClient =92 sc_service::TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<ExecutorDispatch>>;93type FullBackend = sc_service::TFullBackend<Block>;94type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;9596979899100#[allow(clippy::type_complexity)]101pub fn new_partial<BIQ>(102 config: &Configuration,103 build_import_queue: BIQ,104) -> Result<105 PartialComponents<106 FullClient,107 FullBackend,108 FullSelectChain,109 sc_consensus::DefaultImportQueue<Block, FullClient>,110 sc_transaction_pool::FullPool<Block, FullClient>,111 (112 Option<Telemetry>,113 Option<FilterPool>,114 Arc<fc_db::Backend<Block>>,115 Option<TelemetryWorkerHandle>,116 FeeHistoryCache,117 ),118 >,119 sc_service::Error,120>121where122 sc_client_api::StateBackendFor<FullBackend, Block>: sp_api::StateBackend<BlakeTwo256>,123 ExecutorDispatch: NativeExecutionDispatch + 'static,124 BIQ: FnOnce(125 Arc<FullClient>,126 &Configuration,127 Option<TelemetryHandle>,128 &TaskManager,129 ) -> Result<sc_consensus::DefaultImportQueue<Block, FullClient>, sc_service::Error>,130{131 let _telemetry = config132 .telemetry_endpoints133 .clone()134 .filter(|x| !x.is_empty())135 .map(|endpoints| -> Result<_, sc_telemetry::Error> {136 let worker = TelemetryWorker::new(16)?;137 let telemetry = worker.handle().new_telemetry(endpoints);138 Ok((worker, telemetry))139 })140 .transpose()?;141142 let telemetry = config143 .telemetry_endpoints144 .clone()145 .filter(|x| !x.is_empty())146 .map(|endpoints| -> Result<_, sc_telemetry::Error> {147 let worker = TelemetryWorker::new(16)?;148 let telemetry = worker.handle().new_telemetry(endpoints);149 Ok((worker, telemetry))150 })151 .transpose()?;152153 let executor = NativeElseWasmExecutor::<ExecutorDispatch>::new(154 config.wasm_method,155 config.default_heap_pages,156 config.max_runtime_instances,157 config.runtime_cache_size,158 );159160 let (client, backend, keystore_container, task_manager) =161 sc_service::new_full_parts::<Block, RuntimeApi, _>(162 config,163 telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),164 executor,165 )?;166 let client = Arc::new(client);167168 let telemetry_worker_handle = telemetry.as_ref().map(|(worker, _)| worker.handle());169170 let telemetry = telemetry.map(|(worker, telemetry)| {171 task_manager172 .spawn_handle()173 .spawn("telemetry", None, worker.run());174 telemetry175 });176177 let select_chain = sc_consensus::LongestChain::new(backend.clone());178179 let transaction_pool = sc_transaction_pool::BasicPool::new_full(180 config.transaction_pool.clone(),181 config.role.is_authority().into(),182 config.prometheus_registry(),183 task_manager.spawn_essential_handle(),184 client.clone(),185 );186187 let filter_pool: Option<FilterPool> = Some(Arc::new(Mutex::new(BTreeMap::new())));188189 let frontier_backend = open_frontier_backend(config)?;190191 let import_queue = build_import_queue(192 client.clone(),193 config,194 telemetry.as_ref().map(|telemetry| telemetry.handle()),195 &task_manager,196 )?;197 let fee_history_cache: FeeHistoryCache = Arc::new(Mutex::new(BTreeMap::new()));198199 let params = PartialComponents {200 backend,201 client,202 import_queue,203 keystore_container,204 task_manager,205 transaction_pool,206 select_chain,207 other: (208 telemetry,209 filter_pool,210 frontier_backend,211 telemetry_worker_handle,212 fee_history_cache,213 ),214 };215216 Ok(params)217}218219220221222#[sc_tracing::logging::prefix_logs_with("Parachain")]223async fn start_node_impl<BIQ, BIC>(224 parachain_config: Configuration,225 polkadot_config: Configuration,226 id: ParaId,227 build_import_queue: BIQ,228 build_consensus: BIC,229) -> sc_service::error::Result<(TaskManager, Arc<FullClient>)>230where231 sc_client_api::StateBackendFor<FullBackend, Block>: sp_api::StateBackend<BlakeTwo256>,232 ExecutorDispatch: NativeExecutionDispatch + 'static,233 BIQ: FnOnce(234 Arc<FullClient>,235 &Configuration,236 Option<TelemetryHandle>,237 &TaskManager,238 ) -> Result<sc_consensus::DefaultImportQueue<Block, FullClient>, sc_service::Error>,239 BIC: FnOnce(240 Arc<FullClient>,241 Option<&Registry>,242 Option<TelemetryHandle>,243 &TaskManager,244 Arc<dyn RelayChainInterface>,245 Arc<sc_transaction_pool::FullPool<Block, FullClient>>,246 Arc<NetworkService<Block, Hash>>,247 SyncCryptoStorePtr,248 bool,249 ) -> Result<Box<dyn ParachainConsensus<Block>>, sc_service::Error>,250{251 if matches!(parachain_config.role, Role::Light) {252 return Err("Light client not supported!".into());253 }254255 let parachain_config = prepare_node_config(parachain_config);256257 let params = new_partial::<BIQ>(¶chain_config, build_import_queue)?;258 let (mut telemetry, filter_pool, frontier_backend, telemetry_worker_handle, fee_history_cache) =259 params.other;260 let mut task_manager = params.task_manager;261262 let (relay_chain_interface, collator_key) =263 build_relay_chain_interface(polkadot_config, telemetry_worker_handle, &mut task_manager)264 .map_err(|e| match e {265 polkadot_service::Error::Sub(x) => x,266 s => format!("{}", s).into(),267 })?;268 let block_announce_validator = BlockAnnounceValidator::new(relay_chain_interface.clone(), id);269270 let client = params.client.clone();271 let backend = params.backend.clone();272273 let force_authoring = parachain_config.force_authoring;274 let validator = parachain_config.role.is_authority();275 let prometheus_registry = parachain_config.prometheus_registry().cloned();276 let transaction_pool = params.transaction_pool.clone();277 let import_queue = cumulus_client_service::SharedImportQueue::new(params.import_queue);278279 let (network, system_rpc_tx, start_network) =280 sc_service::build_network(sc_service::BuildNetworkParams {281 config: ¶chain_config,282 client: client.clone(),283 transaction_pool: transaction_pool.clone(),284 spawn_handle: task_manager.spawn_handle(),285 import_queue: import_queue.clone(),286 block_announce_validator_builder: Some(Box::new(|_| {287 Box::new(block_announce_validator)288 })),289 warp_sync: None,290 })?;291292 let subscription_executor = sc_rpc::SubscriptionTaskExecutor::new(task_manager.spawn_handle());293 let rpc_client = client.clone();294 let rpc_pool = transaction_pool.clone();295 let select_chain = params.select_chain.clone();296 let is_authority = parachain_config.role.clone().is_authority();297 let rpc_network = network.clone();298299 let rpc_frontier_backend = frontier_backend.clone();300301 let block_data_cache = Arc::new(fc_rpc::EthBlockDataCache::new(302 task_manager.spawn_handle(),303 overrides_handle(client.clone()),304 50,305 50,306 ));307308 let rpc_extensions_builder = Box::new(move |deny_unsafe, _| {309 let full_deps = unique_rpc::FullDeps {310 backend: rpc_frontier_backend.clone(),311 deny_unsafe,312 client: rpc_client.clone(),313 pool: rpc_pool.clone(),314 graph: rpc_pool.pool().clone(),315 316 enable_dev_signer: false,317 filter_pool: filter_pool.clone(),318 network: rpc_network.clone(),319 select_chain: select_chain.clone(),320 is_authority,321 322 max_past_logs: 10000,323 block_data_cache: block_data_cache.clone(),324 fee_history_cache: fee_history_cache.clone(),325 326 fee_history_limit: 2048,327 };328329 Ok(unique_rpc::create_full::<_, _, _, _, RuntimeApi, _>(330 full_deps,331 subscription_executor.clone(),332 ))333 });334335 task_manager.spawn_essential_handle().spawn(336 "frontier-mapping-sync-worker",337 None,338 MappingSyncWorker::new(339 client.import_notification_stream(),340 Duration::new(6, 0),341 client.clone(),342 backend.clone(),343 frontier_backend.clone(),344 SyncStrategy::Normal,345 )346 .for_each(|()| futures::future::ready(())),347 );348349 sc_service::spawn_tasks(sc_service::SpawnTasksParams {350 rpc_extensions_builder,351 client: client.clone(),352 transaction_pool: transaction_pool.clone(),353 task_manager: &mut task_manager,354 config: parachain_config,355 keystore: params.keystore_container.sync_keystore(),356 backend: backend.clone(),357 network: network.clone(),358 system_rpc_tx,359 telemetry: telemetry.as_mut(),360 })?;361362 let announce_block = {363 let network = network.clone();364 Arc::new(move |hash, data| network.announce_block(hash, data))365 };366367 let relay_chain_slot_duration = Duration::from_secs(6);368369 if validator {370 let parachain_consensus = build_consensus(371 client.clone(),372 prometheus_registry.as_ref(),373 telemetry.as_ref().map(|t| t.handle()),374 &task_manager,375 relay_chain_interface.clone(),376 transaction_pool,377 network,378 params.keystore_container.sync_keystore(),379 force_authoring,380 )?;381382 let spawner = task_manager.spawn_handle();383384 let params = StartCollatorParams {385 para_id: id,386 block_status: client.clone(),387 announce_block,388 client: client.clone(),389 task_manager: &mut task_manager,390 spawner,391 parachain_consensus,392 import_queue,393 collator_key,394 relay_chain_interface,395 relay_chain_slot_duration,396 };397398 start_collator(params).await?;399 } else {400 let params = StartFullNodeParams {401 client: client.clone(),402 announce_block,403 task_manager: &mut task_manager,404 para_id: id,405 import_queue,406 relay_chain_interface,407 relay_chain_slot_duration,408 };409410 start_full_node(params)?;411 }412413 start_network.start_network();414415 Ok((task_manager, client))416}417418419pub fn parachain_build_import_queue(420 client: Arc<FullClient>,421 config: &Configuration,422 telemetry: Option<TelemetryHandle>,423 task_manager: &TaskManager,424) -> Result<sc_consensus::DefaultImportQueue<Block, FullClient>, sc_service::Error> {425 let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?;426427 cumulus_client_consensus_aura::import_queue::<428 sp_consensus_aura::sr25519::AuthorityPair,429 _,430 _,431 _,432 _,433 _,434 _,435 >(cumulus_client_consensus_aura::ImportQueueParams {436 block_import: client.clone(),437 client: client.clone(),438 create_inherent_data_providers: move |_, _| async move {439 let time = sp_timestamp::InherentDataProvider::from_system_time();440441 let slot =442 sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(443 *time,444 slot_duration.slot_duration(),445 );446447 Ok((time, slot))448 },449 registry: config.prometheus_registry(),450 can_author_with: sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()),451 spawner: &task_manager.spawn_essential_handle(),452 telemetry,453 })454 .map_err(Into::into)455}456457458pub async fn start_node(459 parachain_config: Configuration,460 polkadot_config: Configuration,461 id: ParaId,462) -> sc_service::error::Result<(TaskManager, Arc<FullClient>)> {463 start_node_impl::<_, _>(464 parachain_config,465 polkadot_config,466 id,467 parachain_build_import_queue,468 |client,469 prometheus_registry,470 telemetry,471 task_manager,472 relay_chain_interface,473 transaction_pool,474 sync_oracle,475 keystore,476 force_authoring| {477 let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?;478479 let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording(480 task_manager.spawn_handle(),481 client.clone(),482 transaction_pool,483 prometheus_registry,484 telemetry.clone(),485 );486487 Ok(AuraConsensus::build::<488 sp_consensus_aura::sr25519::AuthorityPair,489 _,490 _,491 _,492 _,493 _,494 _,495 >(BuildAuraConsensusParams {496 proposer_factory,497 create_inherent_data_providers: move |_, (relay_parent, validation_data)| {498 let relay_chain_interface = relay_chain_interface.clone();499 async move {500 let parachain_inherent =501 cumulus_primitives_parachain_inherent::ParachainInherentData::create_at(502 relay_parent,503 &relay_chain_interface,504 &validation_data,505 id,506 ).await;507508 let time = sp_timestamp::InherentDataProvider::from_system_time();509510 let slot =511 sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(512 *time,513 slot_duration.slot_duration(),514 );515516 let parachain_inherent = parachain_inherent.ok_or_else(|| {517 Box::<dyn std::error::Error + Send + Sync>::from(518 "Failed to create parachain inherent",519 )520 })?;521 Ok((time, slot, parachain_inherent))522 }523 },524 block_import: client.clone(),525 para_client: client,526 backoff_authoring_blocks: Option::<()>::None,527 sync_oracle,528 keystore,529 force_authoring,530 slot_duration,531 532 block_proposal_slot_portion: SlotProportion::new(1f32 / 24f32),533 telemetry,534 max_block_proposal_slot_portion: None,535 }))536 },537 )538 .await539}