diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 639b8b3d4dcf..890cf5199169 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -18,6 +18,7 @@ path = "src/main.rs" async-trait = "0.1.79" clap = { version = "4.5.3", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.12" } +color-print = "0.3.4" futures = "0.3.28" hex-literal = "0.4.1" log = { workspace = true, default-features = true } @@ -111,7 +112,6 @@ cumulus-client-service = { path = "../client/service" } cumulus-primitives-aura = { path = "../primitives/aura" } cumulus-primitives-core = { path = "../primitives/core" } cumulus-relay-chain-interface = { path = "../client/relay-chain-interface" } -color-print = "0.3.4" [build-dependencies] substrate-build-script-utils = { path = "../../substrate/utils/build-script-utils" } diff --git a/cumulus/polkadot-parachain/src/cli.rs b/cumulus/polkadot-parachain/src/cli.rs index f7d2fd0f0be3..fa4b4da1ba9c 100644 --- a/cumulus/polkadot-parachain/src/cli.rs +++ b/cumulus/polkadot-parachain/src/cli.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . +use clap::{CommandFactory, FromArgMatches}; use std::path::PathBuf; /// Sub-commands supported by the collator. @@ -108,18 +109,19 @@ pub struct RelayChainCli { } impl RelayChainCli { - /// Parse the relay chain CLI parameters using the para chain `Configuration`. + /// Parse the relay chain CLI parameters using the parachain `Configuration`. pub fn new<'a>( para_config: &sc_service::Configuration, relay_chain_args: impl Iterator, ) -> Self { + let polkadot_cmd = polkadot_cli::RunCmd::command().no_binary_name(true); + let matches = polkadot_cmd.get_matches_from(relay_chain_args); + let base = FromArgMatches::from_arg_matches(&matches).unwrap_or_else(|e| e.exit()); + let extension = crate::chain_spec::Extensions::try_get(&*para_config.chain_spec); let chain_id = extension.map(|e| e.relay_chain.clone()); + let base_path = para_config.base_path.path().join("polkadot"); - Self { - base_path: Some(base_path), - chain_id, - base: clap::Parser::parse_from(relay_chain_args), - } + Self { base, chain_id, base_path: Some(base_path) } } } diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index 653ea3281f0f..6b3f4b4cd0a7 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -530,13 +530,9 @@ pub fn run() -> Result<()> { }), Some(Subcommand::PurgeChain(cmd)) => { let runner = cli.create_runner(cmd)?; + let polkadot_cli = RelayChainCli::new(runner.config(), cli.relaychain_args.iter()); runner.sync_run(|config| { - let polkadot_cli = RelayChainCli::new( - &config, - [RelayChainCli::executable_name()].iter().chain(cli.relaychain_args.iter()), - ); - let polkadot_config = SubstrateCli::create_configuration( &polkadot_cli, &polkadot_cli, @@ -603,6 +599,7 @@ pub fn run() -> Result<()> { Some(Subcommand::Key(cmd)) => Ok(cmd.run(&cli)?), None => { let runner = cli.create_runner(&cli.run.normalize())?; + let polkadot_cli = RelayChainCli::new(runner.config(), cli.relaychain_args.iter()); let collator_options = cli.run.collator_options(); runner.run_node_until_exit(|config| async move { @@ -648,11 +645,6 @@ pub fn run() -> Result<()> { .map(|e| e.para_id) .ok_or("Could not find parachain extension in chain-spec.")?; - let polkadot_cli = RelayChainCli::new( - &config, - [RelayChainCli::executable_name()].iter().chain(cli.relaychain_args.iter()), - ); - let id = ParaId::from(para_id); let parachain_account = @@ -667,7 +659,7 @@ pub fn run() -> Result<()> { info!("Parachain Account: {}", parachain_account); info!("Is collating: {}", if config.role.is_authority() { "yes" } else { "no" }); - match polkadot_config.network.network_backend { + match config.network.network_backend { sc_network::config::NetworkBackendType::Libp2p => start_node::>( config, diff --git a/cumulus/polkadot-parachain/src/common/aura.rs b/cumulus/polkadot-parachain/src/common/aura.rs new file mode 100644 index 000000000000..9f72d847926f --- /dev/null +++ b/cumulus/polkadot-parachain/src/common/aura.rs @@ -0,0 +1,68 @@ +// 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 codec::Codec; +use cumulus_primitives_aura::AuraUnincludedSegmentApi; +use cumulus_primitives_core::BlockT; +use sp_consensus_aura::AuraApi; +use sp_runtime::app_crypto::{AppCrypto, AppPair, AppSignature, Pair}; + +/// Convenience trait for defining the basic bounds of an `AuraId`. +pub trait AuraIdT: AppCrypto + Codec + Send { + /// Extra bounds for the `Pair`. + type BoundedPair: AppPair + AppCrypto; + + /// Extra bounds for the `Signature`. + type BoundedSignature: AppSignature + + TryFrom> + + std::hash::Hash + + sp_runtime::traits::Member + + Codec; +} + +impl AuraIdT for T +where + T: AppCrypto + Codec + Send + Sync, + <::Pair as AppCrypto>::Signature: + TryFrom> + std::hash::Hash + sp_runtime::traits::Member + Codec, +{ + type BoundedPair = ::Pair; + type BoundedSignature = <::Pair as AppCrypto>::Signature; +} + +/// Convenience trait for defining the basic bounds of a parachain runtime that supports +/// the Aura consensus. +pub trait AuraRuntimeApi: + sp_api::ApiExt + + AuraApi::Public> + + AuraUnincludedSegmentApi + + Sized +{ + /// Check if the runtime has the Aura API. + fn has_aura_api(&self, at: Block::Hash) -> bool { + self.has_api::::Public>>(at) + .unwrap_or(false) + } +} + +impl AuraRuntimeApi for T where + T: sp_api::ApiExt + + AuraApi::Public> + + AuraUnincludedSegmentApi +{ +} diff --git a/cumulus/polkadot-parachain/src/common/mod.rs b/cumulus/polkadot-parachain/src/common/mod.rs new file mode 100644 index 000000000000..5adbb4137cd3 --- /dev/null +++ b/cumulus/polkadot-parachain/src/common/mod.rs @@ -0,0 +1,67 @@ +// 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 . + +//! Cumulus parachain collator primitives. + +#![warn(missing_docs)] + +pub mod aura; + +use cumulus_primitives_core::CollectCollationInfo; +use sp_api::{ApiExt, CallApiAt, ConstructRuntimeApi, Metadata}; +use sp_block_builder::BlockBuilder; +use sp_runtime::traits::Block as BlockT; +use sp_session::SessionKeys; +use sp_transaction_pool::runtime_api::TaggedTransactionQueue; + +/// Convenience trait that defines the basic bounds for the `RuntimeApi` of a parachain node. +pub trait NodeRuntimeApi: + ApiExt + + Metadata + + SessionKeys + + BlockBuilder + + TaggedTransactionQueue + + CollectCollationInfo + + Sized +{ +} + +impl NodeRuntimeApi for T where + T: ApiExt + + Metadata + + SessionKeys + + BlockBuilder + + TaggedTransactionQueue + + CollectCollationInfo +{ +} + +/// Convenience trait that defines the basic bounds for the `ConstructRuntimeApi` of a parachain +/// node. +pub trait ConstructNodeRuntimeApi>: + ConstructRuntimeApi + Send + Sync + 'static +{ + /// Basic bounds for the `RuntimeApi` of a parachain node. + type BoundedRuntimeApi: NodeRuntimeApi; +} + +impl> ConstructNodeRuntimeApi for T +where + T: ConstructRuntimeApi + Send + Sync + 'static, + T::RuntimeApi: NodeRuntimeApi, +{ + type BoundedRuntimeApi = T::RuntimeApi; +} diff --git a/cumulus/polkadot-parachain/src/fake_runtime_api/asset_hub_polkadot_aura.rs b/cumulus/polkadot-parachain/src/fake_runtime_api/asset_hub_polkadot_aura.rs index 82c02943c5fc..0b79d338c168 100644 --- a/cumulus/polkadot-parachain/src/fake_runtime_api/asset_hub_polkadot_aura.rs +++ b/cumulus/polkadot-parachain/src/fake_runtime_api/asset_hub_polkadot_aura.rs @@ -105,12 +105,6 @@ sp_api::impl_runtime_apis! { } } - impl sp_offchain::OffchainWorkerApi for Runtime { - fn offchain_worker(_: &::Header) { - unimplemented!() - } - } - impl sp_session::SessionKeys for Runtime { fn generate_session_keys(_: Option>) -> Vec { unimplemented!() diff --git a/cumulus/polkadot-parachain/src/fake_runtime_api/aura.rs b/cumulus/polkadot-parachain/src/fake_runtime_api/aura.rs index 6b718e912164..823eb9ab584a 100644 --- a/cumulus/polkadot-parachain/src/fake_runtime_api/aura.rs +++ b/cumulus/polkadot-parachain/src/fake_runtime_api/aura.rs @@ -105,12 +105,6 @@ sp_api::impl_runtime_apis! { } } - impl sp_offchain::OffchainWorkerApi for Runtime { - fn offchain_worker(_: &::Header) { - unimplemented!() - } - } - impl sp_session::SessionKeys for Runtime { fn generate_session_keys(_: Option>) -> Vec { unimplemented!() diff --git a/cumulus/polkadot-parachain/src/main.rs b/cumulus/polkadot-parachain/src/main.rs index 0757bea84aae..2bf659228bc6 100644 --- a/cumulus/polkadot-parachain/src/main.rs +++ b/cumulus/polkadot-parachain/src/main.rs @@ -22,6 +22,7 @@ mod chain_spec; mod cli; mod command; +mod common; mod fake_runtime_api; mod rpc; mod service; diff --git a/cumulus/polkadot-parachain/src/service.rs b/cumulus/polkadot-parachain/src/service.rs index 19ad75e384ce..9cd3a0037223 100644 --- a/cumulus/polkadot-parachain/src/service.rs +++ b/cumulus/polkadot-parachain/src/service.rs @@ -14,13 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use codec::{Codec, Decode}; +use codec::Decode; use cumulus_client_cli::CollatorOptions; use cumulus_client_collator::service::CollatorService; use cumulus_client_consensus_aura::collators::lookahead::{self as aura, Params as AuraParams}; -use cumulus_client_consensus_common::{ - ParachainBlockImport as TParachainBlockImport, ParachainCandidate, ParachainConsensus, -}; +use cumulus_client_consensus_common::ParachainBlockImport as TParachainBlockImport; use cumulus_client_consensus_proposer::Proposer; #[allow(deprecated)] use cumulus_client_service::old_consensus; @@ -28,22 +26,26 @@ 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::{Hash as PHash, PersistedValidationData, ValidationCode}, - ParaId, -}; +use cumulus_primitives_core::{relay_chain::ValidationCode, ParaId}; use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface}; use sc_rpc::DenyUnsafe; -use sp_core::Pair; use jsonrpsee::RpcModule; -use crate::{fake_runtime_api::aura::RuntimeApi as FakeRuntimeApi, rpc}; -pub use parachains_common::{AccountId, AuraId, Balance, Block, Hash, Header, Nonce}; +use crate::{ + common::{ + aura::{AuraIdT, AuraRuntimeApi}, + ConstructNodeRuntimeApi, + }, + fake_runtime_api::aura::RuntimeApi as FakeRuntimeApi, + rpc, +}; +pub use parachains_common::{AccountId, AuraId, Balance, Block, Hash, Nonce}; use cumulus_client_consensus_relay_chain::Verifier as RelayChainVerifier; -use futures::{lock::Mutex, prelude::*}; +use futures::prelude::*; use prometheus_endpoint::Registry; +use sc_client_api::Backend as ClientApiBackend; use sc_consensus::{ import_queue::{BasicQueue, Verifier as VerifierT}, BlockImportParams, ImportQueue, @@ -53,8 +55,8 @@ use sc_network::{config::FullNetworkConfiguration, service::traits::NetworkBacke use sc_network_sync::SyncingService; use sc_service::{Configuration, PartialComponents, TFullBackend, TFullClient, TaskManager}; use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle}; -use sp_api::{ApiExt, ConstructRuntimeApi, ProvideRuntimeApi}; -use sp_consensus_aura::AuraApi; +use sp_api::{ConstructRuntimeApi, ProvideRuntimeApi}; +use sp_blockchain::HeaderBackend; use sp_core::traits::SpawnEssentialNamed; use sp_keystore::KeystorePtr; use sp_runtime::{ @@ -100,13 +102,7 @@ pub fn new_partial( build_import_queue: BIQ, ) -> Result, sc_service::Error> where - RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, - RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi - + sp_block_builder::BlockBuilder, + RuntimeApi: ConstructNodeRuntimeApi>, BIQ: FnOnce( Arc>, ParachainBlockImport, @@ -200,16 +196,7 @@ async fn start_node_impl( hwbench: Option, ) -> sc_service::error::Result<(TaskManager, Arc>)> where - RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, - RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi - + sp_block_builder::BlockBuilder - + cumulus_primitives_core::CollectCollationInfo - + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi - + substrate_frame_rpc_system::AccountNonceApi, + RuntimeApi: ConstructNodeRuntimeApi>, RB: Fn( DenyUnsafe, Arc>, @@ -529,61 +516,6 @@ impl BuildOnAccess { } } -/// Special [`ParachainConsensus`] implementation that waits for the upgrade from -/// shell to a parachain runtime that implements Aura. -struct WaitForAuraConsensus { - client: Arc, - aura_consensus: Arc>>>>, - relay_chain_consensus: Arc>>>, - _phantom: PhantomData, -} - -impl Clone for WaitForAuraConsensus { - fn clone(&self) -> Self { - Self { - client: self.client.clone(), - aura_consensus: self.aura_consensus.clone(), - relay_chain_consensus: self.relay_chain_consensus.clone(), - _phantom: PhantomData, - } - } -} - -#[async_trait::async_trait] -impl ParachainConsensus for WaitForAuraConsensus -where - Client: sp_api::ProvideRuntimeApi + Send + Sync, - Client::Api: AuraApi, - AuraId: Send + Codec + Sync, -{ - async fn produce_candidate( - &mut self, - parent: &Header, - relay_parent: PHash, - validation_data: &PersistedValidationData, - ) -> Option> { - if self - .client - .runtime_api() - .has_api::>(parent.hash()) - .unwrap_or(false) - { - self.aura_consensus - .lock() - .await - .get_mut() - .produce_candidate(parent, relay_parent, validation_data) - .await - } else { - self.relay_chain_consensus - .lock() - .await - .produce_candidate(parent, relay_parent, validation_data) - .await - } - } -} - struct Verifier { client: Arc, aura_verifier: BuildOnAccess>>, @@ -592,22 +524,16 @@ struct Verifier { } #[async_trait::async_trait] -impl VerifierT for Verifier +impl VerifierT for Verifier where Client: sp_api::ProvideRuntimeApi + Send + Sync, - Client::Api: AuraApi, - AuraId: Send + Sync + Codec, + Client::Api: AuraRuntimeApi, { async fn verify( &mut self, block_import: BlockImportParams, ) -> Result, String> { - if self - .client - .runtime_api() - .has_api::>(*block_import.header.parent_hash()) - .unwrap_or(false) - { + if self.client.runtime_api().has_aura_api(*block_import.header.parent_hash()) { self.aura_verifier.get_mut().verify(block_import).await } else { self.relay_chain_verifier.verify(block_import).await @@ -617,7 +543,7 @@ where /// Build the import queue for parachain runtimes that started with relay chain consensus and /// switched to aura. -pub fn build_relay_to_aura_import_queue( +pub fn build_relay_to_aura_import_queue( client: Arc>, block_import: ParachainBlockImport, config: &Configuration, @@ -625,16 +551,8 @@ pub fn build_relay_to_aura_import_queue( task_manager: &TaskManager, ) -> Result, sc_service::Error> where - RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, - RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi - + sp_block_builder::BlockBuilder - + sp_consensus_aura::AuraApi::Pair as Pair>::Public>, - <::Pair as Pair>::Signature: - TryFrom> + std::hash::Hash + sp_runtime::traits::Member + Codec, + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi, { let verifier_client = client.clone(); @@ -714,11 +632,7 @@ pub async fn start_generic_aura_lookahead_node> /// /// Uses the lookahead collator to support async backing. #[sc_tracing::logging::prefix_logs_with("Parachain")] -pub async fn start_asset_hub_lookahead_node< - RuntimeApi, - AuraId: AppCrypto + Send + Codec + Sync, - Net, ->( +pub async fn start_asset_hub_lookahead_node( parachain_config: Configuration, polkadot_config: Configuration, collator_options: CollatorOptions, @@ -726,20 +640,10 @@ pub async fn start_asset_hub_lookahead_node< hwbench: Option, ) -> sc_service::error::Result<(TaskManager, Arc>)> where - RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, - RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi - + sp_block_builder::BlockBuilder - + cumulus_primitives_core::CollectCollationInfo - + sp_consensus_aura::AuraApi::Pair as Pair>::Public> + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi - + substrate_frame_rpc_system::AccountNonceApi - + cumulus_primitives_aura::AuraUnincludedSegmentApi, - <::Pair as Pair>::Signature: - TryFrom> + std::hash::Hash + sp_runtime::traits::Member + Codec, + + substrate_frame_rpc_system::AccountNonceApi, Net: NetworkBackend, { start_node_impl::( @@ -807,11 +711,7 @@ where // Check if we have upgraded to an Aura compatible runtime and transition if // necessary. - if client - .runtime_api() - .has_api::>(last_head_hash) - .unwrap_or(false) - { + if client.runtime_api().has_aura_api(last_head_hash) { // Respond to this request before transitioning to Aura. request.complete(None); break @@ -930,14 +830,14 @@ fn start_relay_chain_consensus( } /// Start consensus using the lookahead aura collator. -fn start_lookahead_aura_consensus( - client: Arc>, - block_import: ParachainBlockImport, +fn start_lookahead_aura_consensus( + client: Arc>, + block_import: ParachainBlockImport, prometheus_registry: Option<&Registry>, telemetry: Option, task_manager: &TaskManager, relay_chain_interface: Arc, - transaction_pool: Arc>>, + transaction_pool: Arc>>, sync_oracle: Arc>, keystore: KeystorePtr, relay_chain_slot_duration: Duration, @@ -946,7 +846,16 @@ fn start_lookahead_aura_consensus( overseer_handle: OverseerHandle, announce_block: Arc>) + Send + Sync>, backend: Arc, -) -> Result<(), sc_service::Error> { +) -> Result<(), sc_service::Error> +where + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi, +{ + let info = backend.blockchain().info(); + if !client.runtime_api().has_aura_api(info.finalized_hash) { + return Err(sc_service::error::Error::Other("Missing aura runtime APIs".to_string())); + } + let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( task_manager.spawn_handle(), client.clone(), diff --git a/substrate/client/service/src/config.rs b/substrate/client/service/src/config.rs index 187e18aa3cac..e4788f1f3376 100644 --- a/substrate/client/service/src/config.rs +++ b/substrate/client/service/src/config.rs @@ -280,7 +280,7 @@ impl Default for RpcMethods { static mut BASE_PATH_TEMP: Option = None; /// The base path that is used for everything that needs to be written on disk to run a node. -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct BasePath { path: PathBuf, }