diff --git a/Cargo.lock b/Cargo.lock index 9972285780f3..ee21b8fe38d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13760,6 +13760,7 @@ dependencies = [ "frame-system-rpc-runtime-api", "frame-try-runtime", "futures", + "futures-timer", "glutton-westend-runtime", "hex-literal", "jsonrpsee", @@ -13781,10 +13782,13 @@ dependencies = [ "sc-chain-spec", "sc-cli", "sc-client-api", + "sc-client-db", "sc-consensus", + "sc-consensus-manual-seal", "sc-executor", "sc-network", "sc-network-sync", + "sc-offchain", "sc-rpc", "sc-service", "sc-sysinfo", diff --git a/cumulus/client/consensus/relay-chain/src/import_queue.rs b/cumulus/client/consensus/relay-chain/src/import_queue.rs index 1d6f039da4c1..9ead404925b0 100644 --- a/cumulus/client/consensus/relay-chain/src/import_queue.rs +++ b/cumulus/client/consensus/relay-chain/src/import_queue.rs @@ -16,16 +16,13 @@ use std::{marker::PhantomData, sync::Arc}; -use cumulus_client_consensus_common::ParachainBlockImportMarker; - use sc_consensus::{ import_queue::{BasicQueue, Verifier as VerifierT}, - BlockImport, BlockImportParams, + BlockImportParams, BoxBlockImport, }; use sp_api::ProvideRuntimeApi; use sp_block_builder::BlockBuilder as BlockBuilderApi; use sp_blockchain::Result as ClientResult; -use sp_consensus::error::Error as ConsensusError; use sp_inherents::{CreateInherentDataProviders, InherentDataProvider}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; @@ -109,24 +106,19 @@ where } /// Start an import queue for a Cumulus collator that does not uses any special authoring logic. -pub fn import_queue( +pub fn import_queue( client: Arc, - block_import: I, + block_import: BoxBlockImport, create_inherent_data_providers: CIDP, spawner: &impl sp_core::traits::SpawnEssentialNamed, registry: Option<&prometheus_endpoint::Registry>, ) -> ClientResult> where - I: BlockImport - + ParachainBlockImportMarker - + Send - + Sync - + 'static, Client: ProvideRuntimeApi + Send + Sync + 'static, >::Api: BlockBuilderApi, CIDP: CreateInherentDataProviders + 'static, { let verifier = Verifier::new(client, create_inherent_data_providers); - Ok(BasicQueue::new(verifier, Box::new(block_import), None, spawner, registry)) + Ok(BasicQueue::new(verifier, block_import, None, spawner, registry)) } diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 7085211dad26..1a54f3f34b6f 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -57,10 +57,12 @@ sp-core = { workspace = true, default-features = true } sp-session = { workspace = true, default-features = true } frame-try-runtime = { optional = true, workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } +sc-consensus-manual-seal = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } frame-support = { workspace = true, default-features = true } sc-cli = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } +sc-client-db = { workspace = true, default-features = true } sc-executor = { workspace = true, default-features = true } sc-service = { workspace = true, default-features = true } sc-telemetry = { workspace = true, default-features = true } @@ -78,6 +80,7 @@ sc-chain-spec = { workspace = true, default-features = true } sc-rpc = { workspace = true, default-features = true } sp-version = { workspace = true, default-features = true } sc-tracing = { workspace = true, default-features = true } +sc-offchain = { workspace = true, default-features = true } sp-offchain = { workspace = true, default-features = true } frame-system-rpc-runtime-api = { workspace = true, default-features = true } pallet-transaction-payment = { workspace = true, default-features = true } @@ -112,6 +115,7 @@ cumulus-client-service = { workspace = true, default-features = true } cumulus-primitives-aura = { workspace = true, default-features = true } cumulus-primitives-core = { workspace = true, default-features = true } cumulus-relay-chain-interface = { workspace = true, default-features = true } +futures-timer = "3.0.3" [build-dependencies] substrate-build-script-utils = { workspace = true, default-features = true } @@ -147,6 +151,7 @@ runtime-benchmarks = [ "polkadot-primitives/runtime-benchmarks", "polkadot-service/runtime-benchmarks", "rococo-parachain-runtime/runtime-benchmarks", + "sc-client-db/runtime-benchmarks", "sc-service/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index fcf6c06f4222..523a0d00cc53 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -20,12 +20,15 @@ use crate::{ chain_spec, chain_spec::GenericChainSpec, cli::{Cli, RelayChainCli, Subcommand}, - common::NodeExtraArgs, + common::{ + parachain::{aura::new_aura_node_spec, DynParachainNodeSpec}, + NodeExtraArgs, + }, fake_runtime_api::{ asset_hub_polkadot_aura::RuntimeApi as AssetHubPolkadotRuntimeApi, aura::RuntimeApi as AuraRuntimeApi, }, - service::{new_aura_node_spec, DynNodeSpec, ShellNode}, + service::ShellNode, }; #[cfg(feature = "runtime-benchmarks")] use cumulus_client_service::storage_proof_size::HostFunctions as ReclaimHostFunctions; @@ -389,7 +392,7 @@ impl SubstrateCli for RelayChainCli { fn new_node_spec( config: &sc_service::Configuration, extra_args: NodeExtraArgs, -) -> std::result::Result, sc_cli::Error> { +) -> std::result::Result, sc_cli::Error> { Ok(match config.chain_spec.runtime()? { Runtime::AssetHubPolkadot => new_aura_node_spec::(extra_args), diff --git a/cumulus/polkadot-parachain/src/common/command.rs b/cumulus/polkadot-parachain/src/common/command.rs new file mode 100644 index 000000000000..cf77ef804b4a --- /dev/null +++ b/cumulus/polkadot-parachain/src/common/command.rs @@ -0,0 +1,163 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +use crate::common::{NodeSpec, NodeSpecProvider}; +use cumulus_client_cli::ExportGenesisHeadCommand; +use frame_benchmarking_cli::BlockCmd; +#[cfg(any(feature = "runtime-benchmarks"))] +use frame_benchmarking_cli::StorageCmd; +use sc_cli::{CheckBlockCmd, ExportBlocksCmd, ExportStateCmd, ImportBlocksCmd, RevertCmd}; +use sc_service::{Configuration, TaskManager}; +use sp_runtime::traits::NumberFor; +use std::{fmt::Debug, future::Future, pin::Pin, str::FromStr}; + +type SyncCmdResult = sc_cli::Result<()>; + +type AsyncCmdResult<'a> = + sc_cli::Result<(Pin + 'a>>, TaskManager)>; + +pub trait NodeCommandRunner { + fn prepare_check_block_cmd( + self: Box, + config: Configuration, + cmd: &CheckBlockCmd, + ) -> AsyncCmdResult<'_>; + + fn prepare_export_blocks_cmd( + self: Box, + config: Configuration, + cmd: &ExportBlocksCmd, + ) -> AsyncCmdResult<'_>; + + fn prepare_export_state_cmd( + self: Box, + config: Configuration, + cmd: &ExportStateCmd, + ) -> AsyncCmdResult<'_>; + + fn prepare_import_blocks_cmd( + self: Box, + config: Configuration, + cmd: &ImportBlocksCmd, + ) -> AsyncCmdResult<'_>; + + fn prepare_revert_cmd( + self: Box, + config: Configuration, + cmd: &RevertCmd, + ) -> AsyncCmdResult<'_>; + + fn run_export_genesis_head_cmd( + self: Box, + config: Configuration, + cmd: &ExportGenesisHeadCommand, + ) -> SyncCmdResult; + + fn run_benchmark_block_cmd( + self: Box, + config: Configuration, + cmd: &BlockCmd, + ) -> SyncCmdResult; + + #[cfg(any(feature = "runtime-benchmarks"))] + fn run_benchmark_storage_cmd( + self: Box, + config: Configuration, + cmd: &StorageCmd, + ) -> SyncCmdResult; +} + +impl NodeCommandRunner for T +where + T: NodeSpecProvider, + ::Block> as FromStr>::Err: Debug, +{ + fn prepare_check_block_cmd( + self: Box, + config: Configuration, + cmd: &CheckBlockCmd, + ) -> AsyncCmdResult<'_> { + let partial = T::NodeSpec::new_partial(&config).map_err(sc_cli::Error::Service)?; + Ok((Box::pin(cmd.run(partial.client, partial.import_queue)), partial.task_manager)) + } + + fn prepare_export_blocks_cmd( + self: Box, + config: Configuration, + cmd: &ExportBlocksCmd, + ) -> AsyncCmdResult<'_> { + let partial = T::NodeSpec::new_partial(&config).map_err(sc_cli::Error::Service)?; + Ok((Box::pin(cmd.run(partial.client, config.database)), partial.task_manager)) + } + + fn prepare_export_state_cmd( + self: Box, + config: Configuration, + cmd: &ExportStateCmd, + ) -> AsyncCmdResult<'_> { + let partial = T::NodeSpec::new_partial(&config).map_err(sc_cli::Error::Service)?; + Ok((Box::pin(cmd.run(partial.client, config.chain_spec)), partial.task_manager)) + } + + fn prepare_import_blocks_cmd( + self: Box, + config: Configuration, + cmd: &ImportBlocksCmd, + ) -> AsyncCmdResult<'_> { + let partial = T::NodeSpec::new_partial(&config).map_err(sc_cli::Error::Service)?; + Ok((Box::pin(cmd.run(partial.client, partial.import_queue)), partial.task_manager)) + } + + fn prepare_revert_cmd( + self: Box, + config: Configuration, + cmd: &RevertCmd, + ) -> AsyncCmdResult<'_> { + let partial = T::NodeSpec::new_partial(&config).map_err(sc_cli::Error::Service)?; + Ok((Box::pin(cmd.run(partial.client, partial.backend, None)), partial.task_manager)) + } + + fn run_export_genesis_head_cmd( + self: Box, + config: Configuration, + cmd: &ExportGenesisHeadCommand, + ) -> SyncCmdResult { + let partial = T::NodeSpec::new_partial(&config).map_err(sc_cli::Error::Service)?; + cmd.run(partial.client) + } + + fn run_benchmark_block_cmd( + self: Box, + config: Configuration, + cmd: &BlockCmd, + ) -> SyncCmdResult { + let partial = T::NodeSpec::new_partial(&config).map_err(sc_cli::Error::Service)?; + cmd.run(partial.client) + } + + #[cfg(any(feature = "runtime-benchmarks"))] + fn run_benchmark_storage_cmd( + self: Box, + config: Configuration, + cmd: &StorageCmd, + ) -> SyncCmdResult { + let partial = T::NodeSpec::new_partial(&config).map_err(sc_cli::Error::Service)?; + let db = partial.backend.expose_db(); + let storage = partial.backend.expose_storage(); + + cmd.run(config, partial.client, db, storage) + } +} diff --git a/cumulus/polkadot-parachain/src/common/mod.rs b/cumulus/polkadot-parachain/src/common/mod.rs index 9f5febafe304..892526665fa9 100644 --- a/cumulus/polkadot-parachain/src/common/mod.rs +++ b/cumulus/polkadot-parachain/src/common/mod.rs @@ -19,13 +19,61 @@ #![warn(missing_docs)] pub mod aura; +pub mod command; +pub mod parachain; +mod solochain; use cumulus_primitives_core::CollectCollationInfo; -use sp_api::{ApiExt, CallApiAt, ConstructRuntimeApi, Metadata}; +use sc_client_api::{BlockBackend, UsageProvider}; +use sc_client_db::{Backend, DbHash}; +use sc_consensus::DefaultImportQueue; +use sc_executor::{HostFunctions, WasmExecutor}; +use sc_rpc::DenyUnsafe; +pub use sc_service::{error::Result as ServiceResult, Error as ServiceError}; +use sc_service::{Configuration, PartialComponents, TFullClient, TaskManager}; +use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle}; +use sc_transaction_pool::FullPool; +use sp_api::{ApiExt, CallApiAt, ConstructRuntimeApi, Metadata, ProvideRuntimeApi}; use sp_block_builder::BlockBuilder; -use sp_runtime::traits::Block as BlockT; +use sp_blockchain::{HeaderBackend, HeaderMetadata}; +use sp_runtime::{ + traits::{Block as BlockT, BlockIdTo}, + OpaqueExtrinsic, +}; use sp_session::SessionKeys; use sp_transaction_pool::runtime_api::TaggedTransactionQueue; +use std::sync::Arc; + +pub(crate) type NodeBackend = Backend; + +pub(crate) type FullNodeClient = TFullClient< + ::Block, + ::RuntimeApi, + WasmExecutor<::HostFunctions>, +>; + +/// Assembly of PartialComponents (enough to run chain ops subcommands) +pub(crate) type NodeService = +PartialComponents< + FullNodeClient, + Backend<::Block>, + <::BuildSelectChain as BuildSelectChain< + ::Block, + >>::SelectChain, + DefaultImportQueue<::Block>, + FullPool<::Block, FullNodeClient>, + ( + <::BuildImportQueue as BuildImportQueue< + ::Block, + FullNodeClient, + >>::BlockImport, + Option, + Option, + ), +>; + +/// A type representing all RPC extensions. +pub(crate) type RpcModule = jsonrpsee::RpcModule<()>; /// Convenience trait that defines the basic bounds for the `RuntimeApi` of a parachain node. pub trait NodeRuntimeApi: @@ -66,7 +114,129 @@ where type BoundedRuntimeApi = T::RuntimeApi; } +pub trait NodeClient: + ProvideRuntimeApi + + BlockBackend + + BlockIdTo + + HeaderBackend + + HeaderMetadata + + UsageProvider +{ + type BoundedRuntimeApi: NodeRuntimeApi; +} + +impl NodeClient for T +where + T: ProvideRuntimeApi + + BlockBackend + + BlockIdTo + + HeaderBackend + + HeaderMetadata + + UsageProvider, + T::Api: NodeRuntimeApi, +{ + type BoundedRuntimeApi = T::Api; +} + /// Extra args that are passed when creating a new node spec. pub struct NodeExtraArgs { pub use_slot_based_consensus: bool, } + +pub(crate) trait BuildImportQueue { + type BlockImport; + + fn build_import_queue( + client: Arc, + backend: Arc>, + config: &Configuration, + telemetry_handle: Option, + task_manager: &TaskManager, + ) -> ServiceResult<(Self::BlockImport, DefaultImportQueue)>; +} + +pub(crate) trait BuildSelectChain { + type SelectChain; + + fn build_select_chain(backend: Arc>) -> Self::SelectChain; +} + +pub(crate) trait BuildRpcExtensions + 'static, Backend> { + fn build_rpc_extensions( + deny_unsafe: DenyUnsafe, + client: Arc, + backend: Arc, + pool: Arc>, + ) -> ServiceResult; +} + +pub(crate) trait NodeSpec { + type Block: BlockT + + for<'de> serde::Deserialize<'de>; + type RuntimeApi: ConstructNodeRuntimeApi>; + type HostFunctions: HostFunctions; + + type BuildImportQueue: BuildImportQueue>; + type BuildSelectChain: BuildSelectChain; + + fn new_partial(config: &Configuration) -> ServiceResult> { + let telemetry = config + .telemetry_endpoints + .clone() + .filter(|x| !x.is_empty()) + .map(|endpoints| -> Result<_, sc_telemetry::Error> { + let worker = TelemetryWorker::new(16)?; + let telemetry = worker.handle().new_telemetry(endpoints); + Ok((worker, telemetry)) + }) + .transpose()?; + + let executor = sc_service::new_wasm_executor(config); + + let (client, backend, keystore_container, task_manager) = + sc_service::new_full_parts_record_import::( + config, + telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), + executor, + true, + )?; + let client = Arc::new(client); + + let telemetry_worker_handle = telemetry.as_ref().map(|(worker, _)| worker.handle()); + let telemetry = telemetry.map(|(worker, telemetry)| { + task_manager.spawn_handle().spawn("telemetry", None, worker.run()); + telemetry + }); + + let transaction_pool = sc_transaction_pool::BasicPool::new_full( + config.transaction_pool.clone(), + config.role.is_authority().into(), + config.prometheus_registry(), + task_manager.spawn_essential_handle(), + client.clone(), + ); + + let (block_import, import_queue) = Self::BuildImportQueue::build_import_queue( + client.clone(), + backend.clone(), + config, + telemetry.as_ref().map(|telemetry| telemetry.handle()), + &task_manager, + )?; + + Ok(PartialComponents { + client, + backend: backend.clone(), + task_manager, + keystore_container, + select_chain: Self::BuildSelectChain::build_select_chain(backend), + import_queue, + transaction_pool, + other: (block_import, telemetry, telemetry_worker_handle), + }) + } +} + +pub(crate) trait NodeSpecProvider { + type NodeSpec: NodeSpec; +} diff --git a/cumulus/polkadot-parachain/src/common/parachain/aura.rs b/cumulus/polkadot-parachain/src/common/parachain/aura.rs new file mode 100644 index 000000000000..e5edff74accb --- /dev/null +++ b/cumulus/polkadot-parachain/src/common/parachain/aura.rs @@ -0,0 +1,380 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +//! Aura-related primitives for cumulus parachain collators. + +use crate::common::{ + aura::{AuraIdT, AuraRuntimeApi}, + parachain::{ + rpc::BuildParachainRpcExtensions, Block, DynParachainNodeSpec, ParachainBackend, + ParachainBlockImport, ParachainClient, ParachainNodeSpec, StartConsensus, + }, + BuildImportQueue, ConstructNodeRuntimeApi, NodeExtraArgs, +}; +use cumulus_client_collator::service::CollatorService; +use cumulus_client_consensus_aura::collators::{ + lookahead::{self as aura, Params as AuraParams}, + slot_based::{self as slot_based, Params as SlotBasedParams}, +}; +use cumulus_client_consensus_proposer::Proposer; +use cumulus_client_consensus_relay_chain::Verifier as RelayChainVerifier; +use cumulus_client_service::CollatorSybilResistance; +use cumulus_primitives_core::{relay_chain::ValidationCode, ParaId}; +use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface}; +use frame_support::DefaultNoBound; +use futures::prelude::*; +use parachains_common::{AccountId, Balance, Hash, Nonce}; +use polkadot_primitives::CollatorPair; +use prometheus_endpoint::Registry; +use sc_client_api::BlockchainEvents; +use sc_consensus::{ + import_queue::{BasicQueue, Verifier as VerifierT}, + BlockImportParams, DefaultImportQueue, +}; +use sc_service::{Configuration, Error, TaskManager}; +use sc_telemetry::TelemetryHandle; +use sc_transaction_pool::FullPool; +use sp_api::ProvideRuntimeApi; +use sp_keystore::KeystorePtr; +use sp_runtime::{app_crypto::AppCrypto, traits::Header}; +use std::{marker::PhantomData, sync::Arc, time::Duration}; + +struct Verifier { + client: Arc, + aura_verifier: Box>, + relay_chain_verifier: Box>, + _phantom: PhantomData, +} + +#[async_trait::async_trait] +impl VerifierT for Verifier +where + Client: ProvideRuntimeApi + Send + Sync, + Client::Api: AuraRuntimeApi, + AuraId: AuraIdT + Sync, +{ + async fn verify( + &self, + block_import: BlockImportParams, + ) -> Result, String> { + if self.client.runtime_api().has_aura_api(*block_import.header.parent_hash()) { + self.aura_verifier.verify(block_import).await + } else { + self.relay_chain_verifier.verify(block_import).await + } + } +} + +/// Build the import queue for parachain runtimes that started with relay chain consensus and +/// switched to aura. +pub(crate) struct BuildRelayToAuraImportQueue( + PhantomData<(RuntimeApi, AuraId)>, +); + +impl BuildImportQueue> + for BuildRelayToAuraImportQueue +where + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi, + AuraId: AuraIdT + Sync, +{ + type BlockImport = ParachainBlockImport; + + fn build_import_queue( + client: Arc>, + backend: Arc, + config: &Configuration, + telemetry_handle: Option, + task_manager: &TaskManager, + ) -> sc_service::error::Result<(Self::BlockImport, DefaultImportQueue)> { + let block_import = ParachainBlockImport::new(client.clone(), backend); + let verifier_client = client.clone(); + + let aura_verifier = + cumulus_client_consensus_aura::build_verifier::<::Pair, _, _, _>( + cumulus_client_consensus_aura::BuildVerifierParams { + client: verifier_client.clone(), + create_inherent_data_providers: move |parent_hash, _| { + let cidp_client = verifier_client.clone(); + async move { + let slot_duration = cumulus_client_consensus_aura::slot_duration_at( + &*cidp_client, + parent_hash, + )?; + let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = + sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( + *timestamp, + slot_duration, + ); + + Ok((slot, timestamp)) + } + }, + telemetry: telemetry_handle, + }, + ); + + let relay_chain_verifier = + Box::new(RelayChainVerifier::new(client.clone(), |_, _| async { Ok(()) })); + + let verifier = Verifier { + client, + relay_chain_verifier, + aura_verifier: Box::new(aura_verifier), + _phantom: PhantomData, + }; + + let registry = config.prometheus_registry(); + let spawner = task_manager.spawn_essential_handle(); + + Ok(( + block_import.clone(), + BasicQueue::new(verifier, Box::new(block_import), None, &spawner, registry), + )) + } +} + +/// Wait for the Aura runtime API to appear on chain. +/// This is useful for chains that started out without Aura. Components that +/// are depending on Aura functionality will wait until Aura appears in the runtime. +async fn wait_for_aura(client: Arc>) +where + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi, + AuraId: AuraIdT + Sync, +{ + let finalized_hash = client.chain_info().finalized_hash; + if client.runtime_api().has_aura_api(finalized_hash) { + return; + }; + + let mut stream = client.finality_notification_stream(); + while let Some(notification) = stream.next().await { + if client.runtime_api().has_aura_api(notification.hash) { + return; + } + } +} + +/// Start consensus using the lookahead aura collator. +pub(crate) struct StartLookaheadAuraConsensus( + PhantomData<(RuntimeApi, AuraId)>, +); + +impl StartConsensus + for StartLookaheadAuraConsensus +where + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi, + AuraId: AuraIdT + Sync, +{ + fn start_consensus( + client: Arc>, + backend: Arc, + block_import: ParachainBlockImport, + prometheus_registry: Option<&Registry>, + telemetry: Option, + task_manager: &TaskManager, + relay_chain_interface: Arc, + transaction_pool: Arc>>, + keystore: KeystorePtr, + relay_chain_slot_duration: Duration, + para_id: ParaId, + collator_key: CollatorPair, + overseer_handle: OverseerHandle, + announce_block: Arc>) + Send + Sync>, + ) -> Result<(), Error> { + let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( + task_manager.spawn_handle(), + client.clone(), + transaction_pool, + prometheus_registry, + telemetry.clone(), + ); + + let collator_service = CollatorService::new( + client.clone(), + Arc::new(task_manager.spawn_handle()), + announce_block, + client.clone(), + ); + + let params = AuraParams { + create_inherent_data_providers: move |_, ()| async move { Ok(()) }, + block_import, + para_client: client.clone(), + para_backend: backend, + relay_client: relay_chain_interface, + code_hash_provider: { + let client = client.clone(); + move |block_hash| { + client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) + } + }, + keystore, + collator_key, + para_id, + overseer_handle, + relay_chain_slot_duration, + proposer: Proposer::new(proposer_factory), + collator_service, + authoring_duration: Duration::from_millis(1500), + reinitialize: false, + }; + + let fut = async move { + wait_for_aura(client).await; + aura::run::::Pair, _, _, _, _, _, _, _, _>(params).await; + }; + task_manager.spawn_essential_handle().spawn("aura", None, fut); + + Ok(()) + } +} + +/// Start consensus using the lookahead aura collator. +pub(crate) struct StartSlotBasedAuraConsensus( + PhantomData<(RuntimeApi, AuraId)>, +); + +impl StartConsensus + for StartSlotBasedAuraConsensus +where + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi, + AuraId: AuraIdT + Sync, +{ + fn start_consensus( + client: Arc>, + backend: Arc, + block_import: ParachainBlockImport, + prometheus_registry: Option<&Registry>, + telemetry: Option, + task_manager: &TaskManager, + relay_chain_interface: Arc, + transaction_pool: Arc>>, + keystore: KeystorePtr, + relay_chain_slot_duration: Duration, + para_id: ParaId, + collator_key: CollatorPair, + _overseer_handle: OverseerHandle, + announce_block: Arc>) + Send + Sync>, + ) -> Result<(), Error> { + let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( + task_manager.spawn_handle(), + client.clone(), + transaction_pool, + prometheus_registry, + telemetry.clone(), + ); + + let proposer = Proposer::new(proposer_factory); + let collator_service = CollatorService::new( + client.clone(), + Arc::new(task_manager.spawn_handle()), + announce_block, + client.clone(), + ); + + let client_for_aura = client.clone(); + let params = SlotBasedParams { + create_inherent_data_providers: move |_, ()| async move { Ok(()) }, + block_import, + para_client: client.clone(), + para_backend: backend.clone(), + relay_client: relay_chain_interface, + code_hash_provider: move |block_hash| { + client_for_aura.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) + }, + keystore, + collator_key, + para_id, + relay_chain_slot_duration, + proposer, + collator_service, + authoring_duration: Duration::from_millis(2000), + reinitialize: false, + slot_drift: Duration::from_secs(1), + }; + + let (collation_future, block_builder_future) = + slot_based::run::::Pair, _, _, _, _, _, _, _, _>(params); + + task_manager.spawn_essential_handle().spawn( + "collation-task", + Some("parachain-block-authoring"), + collation_future, + ); + task_manager.spawn_essential_handle().spawn( + "block-builder-task", + Some("parachain-block-authoring"), + block_builder_future, + ); + Ok(()) + } +} + +/// Uses the lookahead collator to support async backing. +/// +/// Start an aura powered parachain node. Some system chains use this. +#[derive(DefaultNoBound)] +pub(crate) struct AuraNode( + pub PhantomData<(RuntimeApi, AuraId, StartConsensus)>, +); + +impl ParachainNodeSpec + for AuraNode +where + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi + + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + + substrate_frame_rpc_system::AccountNonceApi, + AuraId: AuraIdT + Sync, + StartConsensus: self::StartConsensus + 'static, +{ + type RuntimeApi = RuntimeApi; + type BuildImportQueue = BuildRelayToAuraImportQueue; + type BuildRpcExtensions = BuildParachainRpcExtensions; + type StartConsensus = StartConsensus; + const SYBIL_RESISTANCE: CollatorSybilResistance = CollatorSybilResistance::Resistant; +} + +pub fn new_aura_node_spec( + extra_args: NodeExtraArgs, +) -> Box +where + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi + + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + + substrate_frame_rpc_system::AccountNonceApi, + AuraId: AuraIdT + Sync, +{ + if extra_args.use_slot_based_consensus { + Box::new(AuraNode::< + RuntimeApi, + AuraId, + StartSlotBasedAuraConsensus, + >::default()) + } else { + Box::new(AuraNode::< + RuntimeApi, + AuraId, + StartLookaheadAuraConsensus, + >::default()) + } +} diff --git a/cumulus/polkadot-parachain/src/common/parachain/mod.rs b/cumulus/polkadot-parachain/src/common/parachain/mod.rs new file mode 100644 index 000000000000..e4358cb35102 --- /dev/null +++ b/cumulus/polkadot-parachain/src/common/parachain/mod.rs @@ -0,0 +1,350 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +use crate::common::{ + command::NodeCommandRunner, BuildImportQueue as BuildImportQueueT, BuildRpcExtensions, + BuildSelectChain, ConstructNodeRuntimeApi, NodeBackend, NodeSpec, NodeSpecProvider, +}; +use cumulus_client_cli::CollatorOptions; +use cumulus_client_consensus_common::ParachainBlockImport as TParachainBlockImport; +use cumulus_client_service::{ + build_network, build_relay_chain_interface, prepare_node_config, start_relay_chain_tasks, + BuildNetworkParams, CollatorSybilResistance, DARecoveryProfile, StartRelayChainTasksParams, +}; +use cumulus_primitives_core::ParaId; +use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface}; +use frame_support::DefaultNoBound; +use futures::prelude::*; +use parachains_common::{Block, Hash}; +use polkadot_primitives::CollatorPair; +use prometheus_endpoint::Registry; +use sc_consensus::ImportQueue; +use sc_executor::WasmExecutor; +use sc_network::{config::FullNetworkConfiguration, service::traits::NetworkBackend, NetworkBlock}; +use sc_service::{Configuration, TFullBackend, TFullClient, TaskManager}; +use sc_sysinfo::HwBench; +use sc_telemetry::TelemetryHandle; +use sc_transaction_pool::FullPool; +use sp_keystore::KeystorePtr; +use std::{marker::PhantomData, pin::Pin, sync::Arc, time::Duration}; + +pub mod aura; +pub mod rpc; + +#[cfg(not(feature = "runtime-benchmarks"))] +pub type HostFunctions = cumulus_client_service::ParachainHostFunctions; + +#[cfg(feature = "runtime-benchmarks")] +pub(crate) type HostFunctions = ( + cumulus_client_service::ParachainHostFunctions, + frame_benchmarking::benchmarking::HostFunctions, +); + +pub(crate) type ParachainClient = + TFullClient>; + +pub(crate) type ParachainBackend = TFullBackend; + +pub(crate) type ParachainBlockImport = + TParachainBlockImport>, ParachainBackend>; + +/// Checks that the hardware meets the requirements and print a warning otherwise. +fn warn_if_slow_hardware(hwbench: &sc_sysinfo::HwBench) { + // Polkadot para-chains should generally use these requirements to ensure that the relay-chain + // will not take longer than expected to import its blocks. + if let Err(err) = frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE.check_hardware(hwbench) { + log::warn!( + "⚠️ The hardware does not meet the minimal requirements {} for role 'Authority' find out more at:\n\ + https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware", + err + ); + } +} + +pub(crate) struct BuildParachainSelectChain; + +impl BuildSelectChain for BuildParachainSelectChain { + type SelectChain = (); + + fn build_select_chain(_backend: Arc>) -> Self::SelectChain { + () + } +} + +#[derive(DefaultNoBound)] +pub(crate) struct ParachainNode( + PhantomData<(RuntimeApi, BuildImportQueue)>, +); + +impl NodeSpec for ParachainNode +where + RuntimeApi: ConstructNodeRuntimeApi>, + BuildImportQueue: BuildImportQueueT>, +{ + type Block = Block; + type RuntimeApi = RuntimeApi; + type HostFunctions = HostFunctions; + type BuildImportQueue = BuildImportQueue; + type BuildSelectChain = BuildParachainSelectChain; +} + +pub(crate) trait StartConsensus +where + RuntimeApi: ConstructNodeRuntimeApi>, +{ + fn start_consensus( + client: Arc>, + backend: Arc, + block_import: ParachainBlockImport, + prometheus_registry: Option<&Registry>, + telemetry: Option, + task_manager: &TaskManager, + relay_chain_interface: Arc, + transaction_pool: Arc>>, + keystore: KeystorePtr, + relay_chain_slot_duration: Duration, + para_id: ParaId, + collator_key: CollatorPair, + overseer_handle: OverseerHandle, + announce_block: Arc>) + Send + Sync>, + ) -> Result<(), sc_service::Error>; +} + +pub(crate) trait ParachainNodeSpec { + type RuntimeApi: ConstructNodeRuntimeApi>; + + type BuildImportQueue: BuildImportQueueT< + Block, + ParachainClient, + BlockImport = ParachainBlockImport, + >; + + type BuildRpcExtensions: BuildRpcExtensions< + Block, + ParachainClient, + ParachainBackend, + >; + + type StartConsensus: StartConsensus; + + const SYBIL_RESISTANCE: CollatorSybilResistance; + + /// Start a node with the given parachain spec. + /// + /// This is the actual implementation that is abstract over the executor and the runtime api. + fn start_node( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, + ) -> Pin>>> + where + Net: NetworkBackend, + { + Box::pin(async move { + let parachain_config = prepare_node_config(parachain_config); + + let params = ParachainNode::::new_partial( + ¶chain_config, + )?; + let (block_import, mut telemetry, telemetry_worker_handle) = params.other; + + let client = params.client.clone(); + let backend = params.backend.clone(); + + let mut task_manager = params.task_manager; + let (relay_chain_interface, collator_key) = build_relay_chain_interface( + polkadot_config, + ¶chain_config, + telemetry_worker_handle, + &mut task_manager, + collator_options.clone(), + hwbench.clone(), + ) + .await + .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; + + let validator = parachain_config.role.is_authority(); + let prometheus_registry = parachain_config.prometheus_registry().cloned(); + let transaction_pool = params.transaction_pool.clone(); + let import_queue_service = params.import_queue.service(); + let net_config = FullNetworkConfiguration::<_, _, Net>::new(¶chain_config.network); + + let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = + build_network(BuildNetworkParams { + parachain_config: ¶chain_config, + net_config, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + para_id, + spawn_handle: task_manager.spawn_handle(), + relay_chain_interface: relay_chain_interface.clone(), + import_queue: params.import_queue, + sybil_resistance_level: Self::SYBIL_RESISTANCE, + }) + .await?; + + let rpc_builder = { + let client = client.clone(); + let transaction_pool = transaction_pool.clone(); + let backend = backend.clone(); + + Box::new(move |deny_unsafe, _| { + Self::BuildRpcExtensions::build_rpc_extensions( + deny_unsafe, + client.clone(), + backend.clone(), + transaction_pool.clone(), + ) + }) + }; + + sc_service::spawn_tasks(sc_service::SpawnTasksParams { + config: parachain_config, + client: client.clone(), + backend: backend.clone(), + task_manager: &mut task_manager, + keystore: params.keystore_container.keystore(), + transaction_pool: transaction_pool.clone(), + rpc_builder, + network: network.clone(), + system_rpc_tx, + tx_handler_controller, + sync_service: sync_service.clone(), + telemetry: telemetry.as_mut(), + })?; + + if let Some(hwbench) = hwbench { + sc_sysinfo::print_hwbench(&hwbench); + if validator { + warn_if_slow_hardware(&hwbench); + } + + if let Some(ref mut telemetry) = telemetry { + let telemetry_handle = telemetry.handle(); + task_manager.spawn_handle().spawn( + "telemetry_hwbench", + None, + sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench), + ); + } + } + + let announce_block = { + let sync_service = sync_service.clone(); + Arc::new(move |hash, data| sync_service.announce_block(hash, data)) + }; + + let relay_chain_slot_duration = Duration::from_secs(6); + + let overseer_handle = relay_chain_interface + .overseer_handle() + .map_err(|e| sc_service::Error::Application(Box::new(e)))?; + + start_relay_chain_tasks(StartRelayChainTasksParams { + client: client.clone(), + announce_block: announce_block.clone(), + para_id, + relay_chain_interface: relay_chain_interface.clone(), + task_manager: &mut task_manager, + da_recovery_profile: if validator { + DARecoveryProfile::Collator + } else { + DARecoveryProfile::FullNode + }, + import_queue: import_queue_service, + relay_chain_slot_duration, + recovery_handle: Box::new(overseer_handle.clone()), + sync_service, + })?; + + if validator { + Self::StartConsensus::start_consensus( + client.clone(), + backend.clone(), + block_import, + prometheus_registry.as_ref(), + telemetry.as_ref().map(|t| t.handle()), + &task_manager, + relay_chain_interface.clone(), + transaction_pool, + params.keystore_container.keystore(), + relay_chain_slot_duration, + para_id, + collator_key.expect("Command line arguments do not allow this. qed"), + overseer_handle, + announce_block, + )?; + } + + start_network.start_network(); + + Ok(task_manager) + }) + } +} + +impl NodeSpecProvider for T +where + T: ParachainNodeSpec, +{ + type NodeSpec = ParachainNode; +} + +pub(crate) trait DynParachainNodeSpec: NodeCommandRunner { + fn start_node( + self: Box, + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, + ) -> Pin>>>; +} + +impl DynParachainNodeSpec for T +where + T: NodeCommandRunner + ParachainNodeSpec, +{ + fn start_node( + self: Box, + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, + ) -> Pin>>> { + match parachain_config.network.network_backend { + sc_network::config::NetworkBackendType::Libp2p => + ::start_node::>( + parachain_config, + polkadot_config, + collator_options, + para_id, + hwbench, + ), + sc_network::config::NetworkBackendType::Litep2p => + ::start_node::( + parachain_config, + polkadot_config, + collator_options, + para_id, + hwbench, + ), + } + } +} diff --git a/cumulus/polkadot-parachain/src/rpc.rs b/cumulus/polkadot-parachain/src/common/parachain/rpc.rs similarity index 63% rename from cumulus/polkadot-parachain/src/rpc.rs rename to cumulus/polkadot-parachain/src/common/parachain/rpc.rs index 283a73d931d7..67f4229a61a2 100644 --- a/cumulus/polkadot-parachain/src/rpc.rs +++ b/cumulus/polkadot-parachain/src/common/parachain/rpc.rs @@ -18,9 +18,9 @@ #![warn(missing_docs)] -use crate::{ - common::ConstructNodeRuntimeApi, - service::{ParachainBackend, ParachainClient}, +use crate::common::{ + parachain::{ParachainBackend, ParachainClient}, + BuildRpcExtensions, ConstructNodeRuntimeApi, RpcModule, }; use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; use parachains_common::{AccountId, Balance, Block, Nonce}; @@ -28,53 +28,34 @@ use sc_rpc::{ dev::{Dev, DevApiServer}, DenyUnsafe, }; +use sc_transaction_pool::FullPool; use std::{marker::PhantomData, sync::Arc}; use substrate_frame_rpc_system::{System, SystemApiServer}; use substrate_state_trie_migration_rpc::{StateMigration, StateMigrationApiServer}; -/// A type representing all RPC extensions. -pub type RpcExtension = jsonrpsee::RpcModule<()>; - -pub(crate) trait BuildRpcExtensions { - fn build_rpc_extensions( - deny_unsafe: DenyUnsafe, - client: Arc, - backend: Arc, - pool: Arc, - ) -> sc_service::error::Result; -} - pub(crate) struct BuildEmptyRpcExtensions(PhantomData); -impl - BuildRpcExtensions< - ParachainClient, - ParachainBackend, - sc_transaction_pool::FullPool>, - > for BuildEmptyRpcExtensions +impl BuildRpcExtensions, ParachainBackend> + for BuildEmptyRpcExtensions where - RuntimeApi: ConstructNodeRuntimeApi> + Send + Sync + 'static, + RuntimeApi: ConstructNodeRuntimeApi>, { fn build_rpc_extensions( _deny_unsafe: DenyUnsafe, _client: Arc>, _backend: Arc, - _pool: Arc>>, - ) -> sc_service::error::Result { - Ok(RpcExtension::new(())) + _pool: Arc>>, + ) -> sc_service::error::Result { + Ok(RpcModule::new(())) } } pub(crate) struct BuildParachainRpcExtensions(PhantomData); -impl - BuildRpcExtensions< - ParachainClient, - ParachainBackend, - sc_transaction_pool::FullPool>, - > for BuildParachainRpcExtensions +impl BuildRpcExtensions, ParachainBackend> + for BuildParachainRpcExtensions where - RuntimeApi: ConstructNodeRuntimeApi> + Send + Sync + 'static, + RuntimeApi: ConstructNodeRuntimeApi>, RuntimeApi::RuntimeApi: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + substrate_frame_rpc_system::AccountNonceApi, { @@ -82,10 +63,10 @@ where deny_unsafe: DenyUnsafe, client: Arc>, backend: Arc, - pool: Arc>>, - ) -> sc_service::error::Result { - let build = || -> Result> { - let mut module = RpcExtension::new(()); + pool: Arc>>, + ) -> sc_service::error::Result { + let build = || -> Result> { + let mut module = RpcModule::new(()); module.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?; module.merge(TransactionPayment::new(client.clone()).into_rpc())?; diff --git a/cumulus/polkadot-parachain/src/common/solochain.rs b/cumulus/polkadot-parachain/src/common/solochain.rs new file mode 100644 index 000000000000..0ebcbe01fefe --- /dev/null +++ b/cumulus/polkadot-parachain/src/common/solochain.rs @@ -0,0 +1,263 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +use crate::common::{ + BuildImportQueue, BuildSelectChain, ConstructNodeRuntimeApi, NodeBackend, NodeSpec, + NodeSpecProvider, RpcModule, ServiceError, ServiceResult, +}; +use futures::FutureExt; +use sc_client_api::Backend; +use sc_consensus::{DefaultImportQueue, LongestChain}; +use sc_executor::WasmExecutor; +use sc_network::NetworkBackend; +use sc_service::{Configuration, PartialComponents, TFullClient, TaskManager}; +use sc_telemetry::TelemetryHandle; +use sc_transaction_pool_api::OffchainTransactionPoolFactory; +use sp_core::crypto::AccountId32; +use sp_runtime::{generic, traits, traits::Block as BlockT, OpaqueExtrinsic}; +use std::{marker::PhantomData, sync::Arc}; +use substrate_frame_rpc_system::{System, SystemApiServer}; + +type BlockNumber = u32; +type AccountId = AccountId32; +type Nonce = u32; + +/// Opaque block header type. +type Header = generic::Header; +/// Opaque block type. +type Block = generic::Block; + +#[cfg(feature = "runtime-benchmarks")] +type HostFunctions = + (sp_io::SubstrateHostFunctions, frame_benchmarking::benchmarking::HostFunctions); + +#[cfg(not(feature = "runtime-benchmarks"))] +type HostFunctions = sp_io::SubstrateHostFunctions; + +type SolochainClient = TFullClient>; + +pub struct BuildManualSealImportQueue(PhantomData); + +impl BuildImportQueue> + for BuildManualSealImportQueue +where + RuntimeApi: ConstructNodeRuntimeApi>, +{ + type BlockImport = (); + + fn build_import_queue( + client: Arc>, + _backend: Arc>, + config: &Configuration, + _telemetry_handle: Option, + task_manager: &TaskManager, + ) -> ServiceResult<(Self::BlockImport, DefaultImportQueue)> { + Ok(( + (), + sc_consensus_manual_seal::import_queue( + Box::new(client), + &task_manager.spawn_essential_handle(), + config.prometheus_registry(), + ), + )) + } +} + +pub struct BuildSelectLongestChain; + +impl BuildSelectChain for BuildSelectLongestChain { + type SelectChain = LongestChain, Block>; + + fn build_select_chain(backend: Arc>) -> Self::SelectChain { + LongestChain::new(backend.clone()) + } +} + +pub struct SolochainNode(PhantomData); + +impl NodeSpec for SolochainNode +where + RuntimeApi: ConstructNodeRuntimeApi>, +{ + type Block = Block; + type RuntimeApi = RuntimeApi; + type HostFunctions = HostFunctions; + type BuildImportQueue = BuildManualSealImportQueue; + type BuildSelectChain = BuildSelectLongestChain; +} + +impl SolochainNode +where + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: substrate_frame_rpc_system::AccountNonceApi + + sc_offchain::OffchainWorkerApi, +{ + fn do_start_node( + config: Configuration, + block_time: u64, + ) -> Result + where + Net: NetworkBackend::Hash>, + { + let PartialComponents { + client, + backend, + mut task_manager, + import_queue, + keystore_container, + select_chain, + transaction_pool, + other: (_, mut telemetry, _), + } = Self::new_partial(&config)?; + + let net_config = sc_network::config::FullNetworkConfiguration::< + Block, + ::Hash, + Net, + >::new(&config.network); + let metrics = Net::register_notification_metrics( + config.prometheus_config.as_ref().map(|cfg| &cfg.registry), + ); + + let (network, system_rpc_tx, tx_handler_controller, network_starter, sync_service) = + sc_service::build_network(sc_service::BuildNetworkParams { + config: &config, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + spawn_handle: task_manager.spawn_handle(), + import_queue, + net_config, + block_announce_validator_builder: None, + warp_sync_params: None, + block_relay: None, + metrics, + })?; + + if config.offchain_worker.enabled { + task_manager.spawn_handle().spawn( + "offchain-workers-runner", + "offchain-worker", + sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions { + runtime_api_provider: client.clone(), + is_validator: config.role.is_authority(), + keystore: Some(keystore_container.keystore()), + offchain_db: backend.offchain_storage(), + transaction_pool: Some(OffchainTransactionPoolFactory::new( + transaction_pool.clone(), + )), + network_provider: Arc::new(network.clone()), + enable_http_requests: true, + custom_extensions: |_| vec![], + }) + .run(client.clone(), task_manager.spawn_handle()) + .boxed(), + ); + } + + let rpc_extensions_builder = { + let client = client.clone(); + let pool = transaction_pool.clone(); + + Box::new(move |deny_unsafe, _| { + let mut module = RpcModule::new(()); + module + .merge(System::new(client.clone(), pool.clone(), deny_unsafe).into_rpc()) + .map_err(|e| ServiceError::Application(e.into()))?; + Ok(module) + }) + }; + + let prometheus_registry = config.prometheus_registry().cloned(); + + sc_service::spawn_tasks(sc_service::SpawnTasksParams { + config, + client: client.clone(), + backend, + task_manager: &mut task_manager, + keystore: keystore_container.keystore(), + transaction_pool: transaction_pool.clone(), + rpc_builder: rpc_extensions_builder, + network, + system_rpc_tx, + tx_handler_controller, + sync_service, + telemetry: telemetry.as_mut(), + })?; + + let proposer = sc_basic_authorship::ProposerFactory::new( + task_manager.spawn_handle(), + client.clone(), + transaction_pool.clone(), + prometheus_registry.as_ref(), + telemetry.as_ref().map(|x| x.handle()), + ); + + // Start ManualSeal consensus + let (mut sink, commands_stream) = futures::channel::mpsc::channel(1024); + task_manager.spawn_handle().spawn("block_authoring", None, async move { + loop { + futures_timer::Delay::new(std::time::Duration::from_millis(block_time)).await; + sink.try_send(sc_consensus_manual_seal::EngineCommand::SealNewBlock { + create_empty: true, + finalize: true, + parent_hash: None, + sender: None, + }) + .unwrap(); + } + }); + + let params = sc_consensus_manual_seal::ManualSealParams { + block_import: client.clone(), + env: proposer, + client, + pool: transaction_pool, + select_chain, + commands_stream: Box::pin(commands_stream), + consensus_data_provider: None, + create_inherent_data_providers: move |_, ()| async move { + Ok(sp_timestamp::InherentDataProvider::from_system_time()) + }, + }; + let authorship_future = sc_consensus_manual_seal::run_manual_seal(params); + + task_manager.spawn_essential_handle().spawn_blocking( + "manual-seal", + None, + authorship_future, + ); + + network_starter.start_network(); + Ok(task_manager) + } + + #[allow(dead_code)] + pub fn start_node(config: Configuration, block_time: u64) -> Result { + match config.network.network_backend { + sc_network::config::NetworkBackendType::Libp2p => + Self::do_start_node::>(config, block_time), + sc_network::config::NetworkBackendType::Litep2p => + Self::do_start_node::(config, block_time), + } + } +} + +impl NodeSpecProvider for SolochainNode +where + RuntimeApi: ConstructNodeRuntimeApi>, +{ + type NodeSpec = Self; +} diff --git a/cumulus/polkadot-parachain/src/main.rs b/cumulus/polkadot-parachain/src/main.rs index cbb76fa214cb..5fde1d002188 100644 --- a/cumulus/polkadot-parachain/src/main.rs +++ b/cumulus/polkadot-parachain/src/main.rs @@ -47,7 +47,6 @@ mod cli; mod command; mod common; mod fake_runtime_api; -mod rpc; mod service; fn main() -> sc_cli::Result<()> { diff --git a/cumulus/polkadot-parachain/src/service.rs b/cumulus/polkadot-parachain/src/service.rs index f5f6189d1f0d..3f456ea7b4c5 100644 --- a/cumulus/polkadot-parachain/src/service.rs +++ b/cumulus/polkadot-parachain/src/service.rs @@ -14,532 +14,58 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use cumulus_client_cli::{CollatorOptions, ExportGenesisHeadCommand}; -use cumulus_client_collator::service::CollatorService; -use cumulus_client_consensus_aura::collators::{ - lookahead::{self as aura, Params as AuraParams}, - slot_based::{self as slot_based, Params as SlotBasedParams}, -}; -use cumulus_client_consensus_common::ParachainBlockImport as TParachainBlockImport; -use cumulus_client_consensus_proposer::Proposer; -use cumulus_client_consensus_relay_chain::Verifier as RelayChainVerifier; -#[allow(deprecated)] -use cumulus_client_service::old_consensus; -use cumulus_client_service::{ - build_network, build_relay_chain_interface, prepare_node_config, start_relay_chain_tasks, - BuildNetworkParams, CollatorSybilResistance, DARecoveryProfile, StartRelayChainTasksParams, -}; -use cumulus_primitives_core::{relay_chain::ValidationCode, ParaId}; -use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface}; - use crate::{ common::{ - aura::{AuraIdT, AuraRuntimeApi}, - ConstructNodeRuntimeApi, NodeExtraArgs, + parachain::{ + rpc::BuildEmptyRpcExtensions, ParachainBackend, ParachainBlockImport, ParachainClient, + ParachainNodeSpec, StartConsensus, + }, + BuildImportQueue, }, fake_runtime_api::aura::RuntimeApi as FakeRuntimeApi, - rpc::BuildRpcExtensions, }; -pub use parachains_common::{AccountId, Balance, Block, Hash, Nonce}; - -use crate::rpc::{BuildEmptyRpcExtensions, BuildParachainRpcExtensions}; -use frame_benchmarking_cli::BlockCmd; -#[cfg(any(feature = "runtime-benchmarks"))] -use frame_benchmarking_cli::StorageCmd; -use futures::prelude::*; +#[allow(deprecated)] +use cumulus_client_service::old_consensus; +use cumulus_client_service::CollatorSybilResistance; +use cumulus_primitives_core::ParaId; +use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface}; +pub use parachains_common::{Block, Hash}; use polkadot_primitives::CollatorPair; use prometheus_endpoint::Registry; -use sc_cli::{CheckBlockCmd, ExportBlocksCmd, ExportStateCmd, ImportBlocksCmd, RevertCmd}; -use sc_client_api::BlockchainEvents; -use sc_consensus::{ - import_queue::{BasicQueue, Verifier as VerifierT}, - BlockImportParams, DefaultImportQueue, ImportQueue, -}; -use sc_executor::{HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY}; -use sc_network::{config::FullNetworkConfiguration, service::traits::NetworkBackend, NetworkBlock}; -use sc_service::{Configuration, Error, PartialComponents, TFullBackend, TFullClient, TaskManager}; -use sc_sysinfo::HwBench; -use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle}; +use sc_consensus::DefaultImportQueue; +use sc_service::{Configuration, Error, TaskManager}; +use sc_telemetry::TelemetryHandle; use sc_transaction_pool::FullPool; -use sp_api::ProvideRuntimeApi; use sp_keystore::KeystorePtr; -use sp_runtime::{app_crypto::AppCrypto, traits::Header as HeaderT}; -use std::{marker::PhantomData, pin::Pin, sync::Arc, time::Duration}; - -#[cfg(not(feature = "runtime-benchmarks"))] -type HostFunctions = cumulus_client_service::ParachainHostFunctions; - -#[cfg(feature = "runtime-benchmarks")] -type HostFunctions = ( - cumulus_client_service::ParachainHostFunctions, - frame_benchmarking::benchmarking::HostFunctions, -); - -pub type ParachainClient = TFullClient>; - -pub type ParachainBackend = TFullBackend; - -type ParachainBlockImport = - TParachainBlockImport>, ParachainBackend>; - -/// Assembly of PartialComponents (enough to run chain ops subcommands) -pub type Service = PartialComponents< - ParachainClient, - ParachainBackend, - (), - sc_consensus::DefaultImportQueue, - sc_transaction_pool::FullPool>, - (ParachainBlockImport, Option, Option), ->; - -pub(crate) trait BuildImportQueue { - fn build_import_queue( - client: Arc>, - block_import: ParachainBlockImport, - config: &Configuration, - telemetry_handle: Option, - task_manager: &TaskManager, - ) -> sc_service::error::Result>; -} - -pub(crate) trait StartConsensus -where - RuntimeApi: ConstructNodeRuntimeApi>, -{ - fn start_consensus( - client: Arc>, - block_import: ParachainBlockImport, - prometheus_registry: Option<&Registry>, - telemetry: Option, - task_manager: &TaskManager, - relay_chain_interface: Arc, - transaction_pool: Arc>>, - keystore: KeystorePtr, - relay_chain_slot_duration: Duration, - para_id: ParaId, - collator_key: CollatorPair, - overseer_handle: OverseerHandle, - announce_block: Arc>) + Send + Sync>, - backend: Arc, - ) -> Result<(), sc_service::Error>; -} - -pub(crate) trait NodeSpec { - type RuntimeApi: ConstructNodeRuntimeApi>; - - type BuildImportQueue: BuildImportQueue + 'static; - - type BuildRpcExtensions: BuildRpcExtensions< - ParachainClient, - ParachainBackend, - sc_transaction_pool::FullPool>, - > + 'static; - - type StartConsensus: StartConsensus + 'static; - - const SYBIL_RESISTANCE: CollatorSybilResistance; - - /// Starts a `ServiceBuilder` for a full service. - /// - /// Use this macro if you don't actually need the full service, but just the builder in order to - /// be able to perform chain operations. - fn new_partial(config: &Configuration) -> sc_service::error::Result> { - let telemetry = config - .telemetry_endpoints - .clone() - .filter(|x| !x.is_empty()) - .map(|endpoints| -> Result<_, sc_telemetry::Error> { - let worker = TelemetryWorker::new(16)?; - let telemetry = worker.handle().new_telemetry(endpoints); - Ok((worker, telemetry)) - }) - .transpose()?; - - let heap_pages = config.default_heap_pages.map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| { - HeapAllocStrategy::Static { extra_pages: h as _ } - }); - - let executor = sc_executor::WasmExecutor::::builder() - .with_execution_method(config.wasm_method) - .with_max_runtime_instances(config.max_runtime_instances) - .with_runtime_cache_size(config.runtime_cache_size) - .with_onchain_heap_alloc_strategy(heap_pages) - .with_offchain_heap_alloc_strategy(heap_pages) - .build(); - - let (client, backend, keystore_container, task_manager) = - sc_service::new_full_parts_record_import::( - config, - telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), - executor, - true, - )?; - let client = Arc::new(client); - - let telemetry_worker_handle = telemetry.as_ref().map(|(worker, _)| worker.handle()); - - let telemetry = telemetry.map(|(worker, telemetry)| { - task_manager.spawn_handle().spawn("telemetry", None, worker.run()); - telemetry - }); - - let transaction_pool = sc_transaction_pool::BasicPool::new_full( - config.transaction_pool.clone(), - config.role.is_authority().into(), - config.prometheus_registry(), - task_manager.spawn_essential_handle(), - client.clone(), - ); - - let block_import = ParachainBlockImport::new(client.clone(), backend.clone()); - - let import_queue = Self::BuildImportQueue::build_import_queue( - client.clone(), - block_import.clone(), - config, - telemetry.as_ref().map(|telemetry| telemetry.handle()), - &task_manager, - )?; - - Ok(PartialComponents { - backend, - client, - import_queue, - keystore_container, - task_manager, - transaction_pool, - select_chain: (), - other: (block_import, telemetry, telemetry_worker_handle), - }) - } - - /// Start a node with the given parachain spec. - /// - /// This is the actual implementation that is abstract over the executor and the runtime api. - fn start_node( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, - ) -> Pin>>> - where - Net: NetworkBackend, - { - Box::pin(async move { - let parachain_config = prepare_node_config(parachain_config); - - let params = Self::new_partial(¶chain_config)?; - let (block_import, mut telemetry, telemetry_worker_handle) = params.other; - - let client = params.client.clone(); - let backend = params.backend.clone(); - - let mut task_manager = params.task_manager; - let (relay_chain_interface, collator_key) = build_relay_chain_interface( - polkadot_config, - ¶chain_config, - telemetry_worker_handle, - &mut task_manager, - collator_options.clone(), - hwbench.clone(), - ) - .await - .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; - - let validator = parachain_config.role.is_authority(); - let prometheus_registry = parachain_config.prometheus_registry().cloned(); - let transaction_pool = params.transaction_pool.clone(); - let import_queue_service = params.import_queue.service(); - let net_config = FullNetworkConfiguration::<_, _, Net>::new(¶chain_config.network); - - let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = - build_network(BuildNetworkParams { - parachain_config: ¶chain_config, - net_config, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - para_id, - spawn_handle: task_manager.spawn_handle(), - relay_chain_interface: relay_chain_interface.clone(), - import_queue: params.import_queue, - sybil_resistance_level: Self::SYBIL_RESISTANCE, - }) - .await?; - - let rpc_builder = { - let client = client.clone(); - let transaction_pool = transaction_pool.clone(); - let backend_for_rpc = backend.clone(); - - Box::new(move |deny_unsafe, _| { - Self::BuildRpcExtensions::build_rpc_extensions( - deny_unsafe, - client.clone(), - backend_for_rpc.clone(), - transaction_pool.clone(), - ) - }) - }; - - sc_service::spawn_tasks(sc_service::SpawnTasksParams { - rpc_builder, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - task_manager: &mut task_manager, - config: parachain_config, - keystore: params.keystore_container.keystore(), - backend: backend.clone(), - network: network.clone(), - sync_service: sync_service.clone(), - system_rpc_tx, - tx_handler_controller, - telemetry: telemetry.as_mut(), - })?; - - if let Some(hwbench) = hwbench { - sc_sysinfo::print_hwbench(&hwbench); - if validator { - warn_if_slow_hardware(&hwbench); - } - - if let Some(ref mut telemetry) = telemetry { - let telemetry_handle = telemetry.handle(); - task_manager.spawn_handle().spawn( - "telemetry_hwbench", - None, - sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench), - ); - } - } - - let announce_block = { - let sync_service = sync_service.clone(); - Arc::new(move |hash, data| sync_service.announce_block(hash, data)) - }; - - let relay_chain_slot_duration = Duration::from_secs(6); - - let overseer_handle = relay_chain_interface - .overseer_handle() - .map_err(|e| sc_service::Error::Application(Box::new(e)))?; - - start_relay_chain_tasks(StartRelayChainTasksParams { - client: client.clone(), - announce_block: announce_block.clone(), - para_id, - relay_chain_interface: relay_chain_interface.clone(), - task_manager: &mut task_manager, - da_recovery_profile: if validator { - DARecoveryProfile::Collator - } else { - DARecoveryProfile::FullNode - }, - import_queue: import_queue_service, - relay_chain_slot_duration, - recovery_handle: Box::new(overseer_handle.clone()), - sync_service, - })?; - - if validator { - Self::StartConsensus::start_consensus( - client.clone(), - block_import, - prometheus_registry.as_ref(), - telemetry.as_ref().map(|t| t.handle()), - &task_manager, - relay_chain_interface.clone(), - transaction_pool, - params.keystore_container.keystore(), - relay_chain_slot_duration, - para_id, - collator_key.expect("Command line arguments do not allow this. qed"), - overseer_handle, - announce_block, - backend.clone(), - )?; - } - - start_network.start_network(); - - Ok(task_manager) - }) - } -} +use std::{marker::PhantomData, sync::Arc, time::Duration}; /// Build the import queue for the shell runtime. pub(crate) struct BuildShellImportQueue(PhantomData); -impl BuildImportQueue for BuildShellImportQueue { - fn build_import_queue( - client: Arc>, - block_import: ParachainBlockImport, - config: &Configuration, - _telemetry_handle: Option, - task_manager: &TaskManager, - ) -> sc_service::error::Result> { - cumulus_client_consensus_relay_chain::import_queue( - client, - block_import, - |_, _| async { Ok(()) }, - &task_manager.spawn_essential_handle(), - config.prometheus_registry(), - ) - .map_err(Into::into) - } -} - -pub(crate) struct ShellNode; - -impl NodeSpec for ShellNode { - type RuntimeApi = FakeRuntimeApi; - type BuildImportQueue = BuildShellImportQueue; - type BuildRpcExtensions = BuildEmptyRpcExtensions; - type StartConsensus = StartRelayChainConsensus; - - const SYBIL_RESISTANCE: CollatorSybilResistance = CollatorSybilResistance::Unresistant; -} - -struct Verifier { - client: Arc, - aura_verifier: Box>, - relay_chain_verifier: Box>, - _phantom: PhantomData, -} - -#[async_trait::async_trait] -impl VerifierT for Verifier -where - Client: ProvideRuntimeApi + Send + Sync, - Client::Api: AuraRuntimeApi, - AuraId: AuraIdT + Sync, +impl BuildImportQueue> + for BuildShellImportQueue { - async fn verify( - &self, - block_import: BlockImportParams, - ) -> Result, String> { - if self.client.runtime_api().has_aura_api(*block_import.header.parent_hash()) { - self.aura_verifier.verify(block_import).await - } else { - self.relay_chain_verifier.verify(block_import).await - } - } -} - -/// Build the import queue for parachain runtimes that started with relay chain consensus and -/// switched to aura. -pub(crate) struct BuildRelayToAuraImportQueue( - PhantomData<(RuntimeApi, AuraId)>, -); + type BlockImport = ParachainBlockImport; -impl BuildImportQueue - for BuildRelayToAuraImportQueue -where - RuntimeApi: ConstructNodeRuntimeApi>, - RuntimeApi::RuntimeApi: AuraRuntimeApi, - AuraId: AuraIdT + Sync, -{ fn build_import_queue( - client: Arc>, - block_import: ParachainBlockImport, + client: Arc>, + backend: Arc, config: &Configuration, - telemetry_handle: Option, + _telemetry_handle: Option, task_manager: &TaskManager, - ) -> sc_service::error::Result> { - let verifier_client = client.clone(); - - let aura_verifier = - cumulus_client_consensus_aura::build_verifier::<::Pair, _, _, _>( - cumulus_client_consensus_aura::BuildVerifierParams { - client: verifier_client.clone(), - create_inherent_data_providers: move |parent_hash, _| { - let cidp_client = verifier_client.clone(); - async move { - let slot_duration = cumulus_client_consensus_aura::slot_duration_at( - &*cidp_client, - parent_hash, - )?; - let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); - - let slot = - sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( - *timestamp, - slot_duration, - ); - - Ok((slot, timestamp)) - } - }, - telemetry: telemetry_handle, - }, - ); - - let relay_chain_verifier = - Box::new(RelayChainVerifier::new(client.clone(), |_, _| async { Ok(()) })); - - let verifier = Verifier { - client, - relay_chain_verifier, - aura_verifier: Box::new(aura_verifier), - _phantom: PhantomData, - }; - - let registry = config.prometheus_registry(); - let spawner = task_manager.spawn_essential_handle(); - - Ok(BasicQueue::new(verifier, Box::new(block_import), None, &spawner, registry)) - } -} - -/// Uses the lookahead collator to support async backing. -/// -/// Start an aura powered parachain node. Some system chains use this. -pub(crate) struct AuraNode( - pub PhantomData<(RuntimeApi, AuraId, StartConsensus)>, -); - -impl Default for AuraNode { - fn default() -> Self { - Self(Default::default()) - } -} - -impl NodeSpec for AuraNode -where - RuntimeApi: ConstructNodeRuntimeApi>, - RuntimeApi::RuntimeApi: AuraRuntimeApi - + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi - + substrate_frame_rpc_system::AccountNonceApi, - AuraId: AuraIdT + Sync, - StartConsensus: self::StartConsensus + 'static, -{ - type RuntimeApi = RuntimeApi; - type BuildImportQueue = BuildRelayToAuraImportQueue; - type BuildRpcExtensions = BuildParachainRpcExtensions; - type StartConsensus = StartConsensus; - const SYBIL_RESISTANCE: CollatorSybilResistance = CollatorSybilResistance::Resistant; -} - -pub fn new_aura_node_spec(extra_args: NodeExtraArgs) -> Box -where - RuntimeApi: ConstructNodeRuntimeApi>, - RuntimeApi::RuntimeApi: AuraRuntimeApi - + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi - + substrate_frame_rpc_system::AccountNonceApi, - AuraId: AuraIdT + Sync, -{ - if extra_args.use_slot_based_consensus { - Box::new(AuraNode::< - RuntimeApi, - AuraId, - StartSlotBasedAuraConsensus, - >::default()) - } else { - Box::new(AuraNode::< - RuntimeApi, - AuraId, - StartLookaheadAuraConsensus, - >::default()) + ) -> sc_service::error::Result<(Self::BlockImport, DefaultImportQueue)> { + let block_import = ParachainBlockImport::new(client.clone(), backend); + Ok(( + block_import.clone(), + cumulus_client_consensus_relay_chain::import_queue( + client, + Box::new(block_import), + |_, _| async { Ok(()) }, + &task_manager.spawn_essential_handle(), + config.prometheus_registry(), + ) + .map_err(Into::::into)?, + )) } } @@ -550,6 +76,7 @@ pub(crate) struct StartRelayChainConsensus; impl StartConsensus for StartRelayChainConsensus { fn start_consensus( client: Arc>, + _backend: Arc, block_import: ParachainBlockImport, prometheus_registry: Option<&Registry>, telemetry: Option, @@ -562,7 +89,6 @@ impl StartConsensus for StartRelayChainConsensus { collator_key: CollatorPair, overseer_handle: OverseerHandle, announce_block: Arc>) + Send + Sync>, - _backend: Arc, ) -> Result<(), Error> { let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( task_manager.spawn_handle(), @@ -618,369 +144,13 @@ impl StartConsensus for StartRelayChainConsensus { } } -/// Start consensus using the lookahead aura collator. -pub(crate) struct StartSlotBasedAuraConsensus( - PhantomData<(RuntimeApi, AuraId)>, -); - -impl StartConsensus - for StartSlotBasedAuraConsensus -where - RuntimeApi: ConstructNodeRuntimeApi>, - RuntimeApi::RuntimeApi: AuraRuntimeApi, - AuraId: AuraIdT + Sync, -{ - fn start_consensus( - client: Arc>, - block_import: ParachainBlockImport, - prometheus_registry: Option<&Registry>, - telemetry: Option, - task_manager: &TaskManager, - relay_chain_interface: Arc, - transaction_pool: Arc>>, - keystore: KeystorePtr, - relay_chain_slot_duration: Duration, - para_id: ParaId, - collator_key: CollatorPair, - _overseer_handle: OverseerHandle, - announce_block: Arc>) + Send + Sync>, - backend: Arc, - ) -> Result<(), Error> { - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - task_manager.spawn_handle(), - client.clone(), - transaction_pool, - prometheus_registry, - telemetry.clone(), - ); - - let proposer = Proposer::new(proposer_factory); - let collator_service = CollatorService::new( - client.clone(), - Arc::new(task_manager.spawn_handle()), - announce_block, - client.clone(), - ); - - let client_for_aura = client.clone(); - let params = SlotBasedParams { - create_inherent_data_providers: move |_, ()| async move { Ok(()) }, - block_import, - para_client: client.clone(), - para_backend: backend.clone(), - relay_client: relay_chain_interface, - code_hash_provider: move |block_hash| { - client_for_aura.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) - }, - keystore, - collator_key, - para_id, - relay_chain_slot_duration, - proposer, - collator_service, - authoring_duration: Duration::from_millis(2000), - reinitialize: false, - slot_drift: Duration::from_secs(1), - }; - - let (collation_future, block_builder_future) = - slot_based::run::::Pair, _, _, _, _, _, _, _, _>(params); - - task_manager.spawn_essential_handle().spawn( - "collation-task", - Some("parachain-block-authoring"), - collation_future, - ); - task_manager.spawn_essential_handle().spawn( - "block-builder-task", - Some("parachain-block-authoring"), - block_builder_future, - ); - Ok(()) - } -} - -/// Wait for the Aura runtime API to appear on chain. -/// This is useful for chains that started out without Aura. Components that -/// are depending on Aura functionality will wait until Aura appears in the runtime. -async fn wait_for_aura(client: Arc>) -where - RuntimeApi: ConstructNodeRuntimeApi>, - RuntimeApi::RuntimeApi: AuraRuntimeApi, - AuraId: AuraIdT + Sync, -{ - let finalized_hash = client.chain_info().finalized_hash; - if client.runtime_api().has_aura_api(finalized_hash) { - return; - }; - - let mut stream = client.finality_notification_stream(); - while let Some(notification) = stream.next().await { - if client.runtime_api().has_aura_api(notification.hash) { - return; - } - } -} - -/// Start consensus using the lookahead aura collator. -pub(crate) struct StartLookaheadAuraConsensus( - PhantomData<(RuntimeApi, AuraId)>, -); - -impl StartConsensus - for StartLookaheadAuraConsensus -where - RuntimeApi: ConstructNodeRuntimeApi>, - RuntimeApi::RuntimeApi: AuraRuntimeApi, - AuraId: AuraIdT + Sync, -{ - fn start_consensus( - client: Arc>, - block_import: ParachainBlockImport, - prometheus_registry: Option<&Registry>, - telemetry: Option, - task_manager: &TaskManager, - relay_chain_interface: Arc, - transaction_pool: Arc>>, - keystore: KeystorePtr, - relay_chain_slot_duration: Duration, - para_id: ParaId, - collator_key: CollatorPair, - overseer_handle: OverseerHandle, - announce_block: Arc>) + Send + Sync>, - backend: Arc, - ) -> Result<(), Error> { - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - task_manager.spawn_handle(), - client.clone(), - transaction_pool, - prometheus_registry, - telemetry.clone(), - ); - - let collator_service = CollatorService::new( - client.clone(), - Arc::new(task_manager.spawn_handle()), - announce_block, - client.clone(), - ); - - let params = AuraParams { - create_inherent_data_providers: move |_, ()| async move { Ok(()) }, - block_import, - para_client: client.clone(), - para_backend: backend, - relay_client: relay_chain_interface, - code_hash_provider: { - let client = client.clone(); - move |block_hash| { - client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) - } - }, - keystore, - collator_key, - para_id, - overseer_handle, - relay_chain_slot_duration, - proposer: Proposer::new(proposer_factory), - collator_service, - authoring_duration: Duration::from_millis(1500), - reinitialize: false, - }; - - let fut = async move { - wait_for_aura(client).await; - aura::run::::Pair, _, _, _, _, _, _, _, _>(params).await; - }; - task_manager.spawn_essential_handle().spawn("aura", None, fut); - - Ok(()) - } -} - -/// Checks that the hardware meets the requirements and print a warning otherwise. -fn warn_if_slow_hardware(hwbench: &sc_sysinfo::HwBench) { - // Polkadot para-chains should generally use these requirements to ensure that the relay-chain - // will not take longer than expected to import its blocks. - if let Err(err) = frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE.check_hardware(hwbench) { - log::warn!( - "⚠️ The hardware does not meet the minimal requirements {} for role 'Authority' find out more at:\n\ - https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware", - err - ); - } -} - -type SyncCmdResult = sc_cli::Result<()>; - -type AsyncCmdResult<'a> = - sc_cli::Result<(Pin + 'a>>, TaskManager)>; - -pub(crate) trait DynNodeSpec { - fn prepare_check_block_cmd( - self: Box, - config: Configuration, - cmd: &CheckBlockCmd, - ) -> AsyncCmdResult<'_>; - - fn prepare_export_blocks_cmd( - self: Box, - config: Configuration, - cmd: &ExportBlocksCmd, - ) -> AsyncCmdResult<'_>; - - fn prepare_export_state_cmd( - self: Box, - config: Configuration, - cmd: &ExportStateCmd, - ) -> AsyncCmdResult<'_>; - - fn prepare_import_blocks_cmd( - self: Box, - config: Configuration, - cmd: &ImportBlocksCmd, - ) -> AsyncCmdResult<'_>; - - fn prepare_revert_cmd( - self: Box, - config: Configuration, - cmd: &RevertCmd, - ) -> AsyncCmdResult<'_>; - - fn run_export_genesis_head_cmd( - self: Box, - config: Configuration, - cmd: &ExportGenesisHeadCommand, - ) -> SyncCmdResult; - - fn run_benchmark_block_cmd( - self: Box, - config: Configuration, - cmd: &BlockCmd, - ) -> SyncCmdResult; - - #[cfg(any(feature = "runtime-benchmarks"))] - fn run_benchmark_storage_cmd( - self: Box, - config: Configuration, - cmd: &StorageCmd, - ) -> SyncCmdResult; - - fn start_node( - self: Box, - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, - ) -> Pin>>>; -} - -impl DynNodeSpec for T -where - T: NodeSpec, -{ - fn prepare_check_block_cmd( - self: Box, - config: Configuration, - cmd: &CheckBlockCmd, - ) -> AsyncCmdResult<'_> { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - Ok((Box::pin(cmd.run(partial.client, partial.import_queue)), partial.task_manager)) - } - - fn prepare_export_blocks_cmd( - self: Box, - config: Configuration, - cmd: &ExportBlocksCmd, - ) -> AsyncCmdResult<'_> { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - Ok((Box::pin(cmd.run(partial.client, config.database)), partial.task_manager)) - } - - fn prepare_export_state_cmd( - self: Box, - config: Configuration, - cmd: &ExportStateCmd, - ) -> AsyncCmdResult<'_> { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - Ok((Box::pin(cmd.run(partial.client, config.chain_spec)), partial.task_manager)) - } - - fn prepare_import_blocks_cmd( - self: Box, - config: Configuration, - cmd: &ImportBlocksCmd, - ) -> AsyncCmdResult<'_> { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - Ok((Box::pin(cmd.run(partial.client, partial.import_queue)), partial.task_manager)) - } - - fn prepare_revert_cmd( - self: Box, - config: Configuration, - cmd: &RevertCmd, - ) -> AsyncCmdResult<'_> { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - Ok((Box::pin(cmd.run(partial.client, partial.backend, None)), partial.task_manager)) - } - - fn run_export_genesis_head_cmd( - self: Box, - config: Configuration, - cmd: &ExportGenesisHeadCommand, - ) -> SyncCmdResult { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - cmd.run(partial.client) - } - - fn run_benchmark_block_cmd( - self: Box, - config: Configuration, - cmd: &BlockCmd, - ) -> SyncCmdResult { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - cmd.run(partial.client) - } - - #[cfg(any(feature = "runtime-benchmarks"))] - fn run_benchmark_storage_cmd( - self: Box, - config: Configuration, - cmd: &StorageCmd, - ) -> SyncCmdResult { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - let db = partial.backend.expose_db(); - let storage = partial.backend.expose_storage(); +pub(crate) struct ShellNode; - cmd.run(config, partial.client, db, storage) - } +impl ParachainNodeSpec for ShellNode { + type RuntimeApi = FakeRuntimeApi; + type BuildImportQueue = BuildShellImportQueue; + type BuildRpcExtensions = BuildEmptyRpcExtensions; + type StartConsensus = StartRelayChainConsensus; - fn start_node( - self: Box, - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, - ) -> Pin>>> { - match parachain_config.network.network_backend { - sc_network::config::NetworkBackendType::Libp2p => - ::start_node::>( - parachain_config, - polkadot_config, - collator_options, - para_id, - hwbench, - ), - sc_network::config::NetworkBackendType::Litep2p => - ::start_node::( - parachain_config, - polkadot_config, - collator_options, - para_id, - hwbench, - ), - } - } + const SYBIL_RESISTANCE: CollatorSybilResistance = CollatorSybilResistance::Unresistant; } diff --git a/substrate/client/cli/src/params/mod.rs b/substrate/client/cli/src/params/mod.rs index f07223ec6a73..36173ecbce66 100644 --- a/substrate/client/cli/src/params/mod.rs +++ b/substrate/client/cli/src/params/mod.rs @@ -116,7 +116,6 @@ impl BlockNumberOrHash { pub fn parse(&self) -> Result, String> where ::Err: std::fmt::Debug, - NumberFor: FromStr, as FromStr>::Err: std::fmt::Debug, { if self.0.starts_with("0x") { diff --git a/templates/minimal/node/Cargo.toml b/templates/minimal/node/Cargo.toml index 70b24c19f8e7..84cba4b583d7 100644 --- a/templates/minimal/node/Cargo.toml +++ b/templates/minimal/node/Cargo.toml @@ -13,6 +13,7 @@ build = "build.rs" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] + [dependencies] docify = { workspace = true } clap = { features = ["derive"], workspace = true } diff --git a/templates/minimal/node/src/service.rs b/templates/minimal/node/src/service.rs index 71b1ef65b6ca..00c6d1bd5b79 100644 --- a/templates/minimal/node/src/service.rs +++ b/templates/minimal/node/src/service.rs @@ -98,9 +98,9 @@ pub fn new_partial(config: &Configuration) -> Result { client, backend, task_manager, - import_queue, keystore_container, select_chain, + import_queue, transaction_pool, other: (telemetry), }) diff --git a/templates/parachain/node/src/service.rs b/templates/parachain/node/src/service.rs index 3e7d4de10553..d7f234f33625 100644 --- a/templates/parachain/node/src/service.rs +++ b/templates/parachain/node/src/service.rs @@ -282,7 +282,7 @@ pub async fn start_parachain_node( task_manager.spawn_handle().spawn( "offchain-workers-runner", - "offchain-work", + "offchain-worker", sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions { runtime_api_provider: client.clone(), keystore: Some(params.keystore_container.keystore()),