diff --git a/cumulus/polkadot-omni-node/lib/src/cli.rs b/cumulus/polkadot-omni-node/lib/src/cli.rs index af9f6c00dd7d8..4ec678f5739cd 100644 --- a/cumulus/polkadot-omni-node/lib/src/cli.rs +++ b/cumulus/polkadot-omni-node/lib/src/cli.rs @@ -16,6 +16,9 @@ //! CLI options of the omni-node. See [`Command`]. +/// Default block time for dev mode when using `--dev` flag. +const DEFAULT_DEV_BLOCK_TIME_MS: u64 = 3000; + use crate::{ chain_spec::DiskChainSpecLoader, common::{ @@ -163,9 +166,19 @@ pub struct Cli { /// /// The `--dev` flag sets the `dev_block_time` to a default value of 3000ms unless explicitly /// provided. - #[arg(long)] + #[arg(long, conflicts_with = "instant_seal")] pub dev_block_time: Option, + /// Start a dev node with instant seal. + /// + /// This is a dev option that enables instant sealing, meaning blocks are produced + /// immediately when transactions are received, rather than at fixed intervals. + /// Using this option won't result in starting or connecting to a parachain network. + /// The resulting node will work on its own, running the wasm blob and producing blocks + /// instantly upon receiving transactions. + #[arg(long, conflicts_with = "dev_block_time")] + pub instant_seal: bool, + /// DEPRECATED: This feature has been stabilized, pLease use `--authoring slot-based` instead. /// /// Use slot-based collator which can handle elastic scaling. @@ -209,6 +222,16 @@ pub struct Cli { pub(crate) _phantom: PhantomData, } +/// Development sealing mode. +#[derive(Debug, Clone, Copy)] +pub(crate) enum DevSealMode { + /// Produces blocks immediately upon receiving transactions. + InstantSeal, + /// Produces blocks at fixed time intervals. + /// The u64 parameter represents the block time in milliseconds. + ManualSeal(u64), +} + /// Collator implementation to use. #[derive(PartialEq, Debug, ValueEnum, Clone, Copy)] pub enum AuthoringPolicy { @@ -242,6 +265,19 @@ impl Cli { enable_statement_store: self.enable_statement_store, } } + + /// Returns the dev seal mode if the node is in dev mode. + pub(crate) fn dev_mode(&self) -> Option { + if self.instant_seal { + Some(DevSealMode::InstantSeal) + } else if let Some(dev_block_time) = self.dev_block_time { + Some(DevSealMode::ManualSeal(dev_block_time)) + } else if self.run.base.is_dev().unwrap_or(false) { + Some(DevSealMode::ManualSeal(DEFAULT_DEV_BLOCK_TIME_MS)) + } else { + None + } + } } impl SubstrateCli for Cli { diff --git a/cumulus/polkadot-omni-node/lib/src/command.rs b/cumulus/polkadot-omni-node/lib/src/command.rs index 22b27cd601543..4ac7f6ef82bab 100644 --- a/cumulus/polkadot-omni-node/lib/src/command.rs +++ b/cumulus/polkadot-omni-node/lib/src/command.rs @@ -35,12 +35,10 @@ use clap::{CommandFactory, FromArgMatches}; use cumulus_client_service::storage_proof_size::HostFunctions as ReclaimHostFunctions; use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; use log::info; -use sc_cli::{CliConfiguration, Result, SubstrateCli}; +use sc_cli::{Result, SubstrateCli}; #[cfg(feature = "runtime-benchmarks")] use sp_runtime::traits::HashingFor; -const DEFAULT_DEV_BLOCK_TIME_MS: u64 = 3000; - /// Structure that can be used in order to provide customizers for different functionalities of the /// node binary that is being built using this library. pub struct RunConfig { @@ -303,17 +301,8 @@ where let node_spec = new_node_spec(&config, &cmd_config.runtime_resolver, &cli.node_extra_args())?; - if cli.run.base.is_dev()? { - let dev_block_time = cli.dev_block_time.unwrap_or(DEFAULT_DEV_BLOCK_TIME_MS); - return node_spec - .start_manual_seal_node(config, dev_block_time) - .map_err(Into::into); - } - - if let Some(dev_block_time) = cli.dev_block_time { - return node_spec - .start_manual_seal_node(config, dev_block_time) - .map_err(Into::into); + if let Some(dev_mode) = cli.dev_mode() { + return node_spec.start_dev_node(config, dev_mode).map_err(Into::into); } // If Statemint (Statemine, Westmint, Rockmine) DB exists and we're using the diff --git a/cumulus/polkadot-omni-node/lib/src/common/spec.rs b/cumulus/polkadot-omni-node/lib/src/common/spec.rs index 686e2cc4e1669..3e1f69e94c5a7 100644 --- a/cumulus/polkadot-omni-node/lib/src/common/spec.rs +++ b/cumulus/polkadot-omni-node/lib/src/common/spec.rs @@ -16,6 +16,7 @@ use crate::{ chain_spec::Extensions, + cli::DevSealMode, common::{ command::NodeCommandRunner, rpc::BuildRpcExtensions, @@ -300,11 +301,11 @@ pub(crate) trait NodeSpec: BaseNodeSpec { const SYBIL_RESISTANCE: CollatorSybilResistance; - fn start_manual_seal_node( + fn start_dev_node( _config: Configuration, - _block_time: u64, + _mode: DevSealMode, ) -> sc_service::error::Result { - Err(sc_service::Error::Other("Manual seal not supported for this node type".into())) + Err(sc_service::Error::Other("Dev not supported for this node type".into())) } /// Start a node with the given parachain spec. @@ -557,11 +558,11 @@ pub(crate) trait NodeSpec: BaseNodeSpec { } pub(crate) trait DynNodeSpec: NodeCommandRunner { - /// Start node with manual-seal consensus. - fn start_manual_seal_node( + /// Start node with manual or instant seal consensus. + fn start_dev_node( self: Box, config: Configuration, - block_time: u64, + mode: DevSealMode, ) -> sc_service::error::Result; /// Start the node. @@ -579,12 +580,12 @@ impl DynNodeSpec for T where T: NodeSpec + NodeCommandRunner, { - fn start_manual_seal_node( + fn start_dev_node( self: Box, config: Configuration, - block_time: u64, + mode: DevSealMode, ) -> sc_service::error::Result { - ::start_manual_seal_node(config, block_time) + ::start_dev_node(config, mode) } fn start_node( diff --git a/cumulus/polkadot-omni-node/lib/src/nodes/aura.rs b/cumulus/polkadot-omni-node/lib/src/nodes/aura.rs index ec4eb36689dcc..2a7ef5cf537e2 100644 --- a/cumulus/polkadot-omni-node/lib/src/nodes/aura.rs +++ b/cumulus/polkadot-omni-node/lib/src/nodes/aura.rs @@ -15,7 +15,7 @@ // limitations under the License. use crate::{ - cli::AuthoringPolicy, + cli::{AuthoringPolicy, DevSealMode}, common::{ aura::{AuraIdT, AuraRuntimeApi}, rpc::{BuildParachainRpcExtensions, BuildRpcExtensions}, @@ -211,9 +211,9 @@ where type StartConsensus = StartConsensus; const SYBIL_RESISTANCE: CollatorSybilResistance = CollatorSybilResistance::Resistant; - fn start_manual_seal_node( + fn start_dev_node( mut config: Configuration, - block_time: u64, + mode: DevSealMode, ) -> sc_service::error::Result { let PartialComponents { client, @@ -277,24 +277,6 @@ where None, ); - let (manual_seal_sink, manual_seal_stream) = futures::channel::mpsc::channel(1024); - let mut manual_seal_sink_clone = manual_seal_sink.clone(); - task_manager - .spawn_essential_handle() - .spawn("block_authoring", None, async move { - loop { - futures_timer::Delay::new(std::time::Duration::from_millis(block_time)).await; - manual_seal_sink_clone - .try_send(sc_consensus_manual_seal::EngineCommand::SealNewBlock { - create_empty: true, - finalize: true, - parent_hash: None, - sender: None, - }) - .unwrap(); - } - }); - // Note: Changing slot durations are currently not supported let slot_duration = sc_consensus_aura::slot_duration(&*client) .expect("slot_duration is always present; qed."); @@ -305,29 +287,67 @@ where let para_id = Self::parachain_id(&client, &config).ok_or("Failed to retrieve the parachain id")?; - let create_inherent_data_providers = Self::create_manual_seal_inherent_data_providers( - client.clone(), - para_id, - slot_duration, - ); - - let params = sc_consensus_manual_seal::ManualSealParams { - block_import: client.clone(), - env: proposer, - client: client.clone(), - pool: transaction_pool.clone(), - select_chain: LongestChain::new(backend.clone()), - commands_stream: Box::pin(manual_seal_stream), - consensus_data_provider: Some(Box::new(aura_digest_provider)), - create_inherent_data_providers, - }; - - let authorship_future = sc_consensus_manual_seal::run_manual_seal(params); - task_manager.spawn_essential_handle().spawn_blocking( - "manual-seal", - None, - authorship_future, - ); + let create_inherent_data_providers = + Self::create_dev_node_inherent_data_providers(client.clone(), para_id, slot_duration); + + match mode { + DevSealMode::InstantSeal => { + let params = sc_consensus_manual_seal::InstantSealParams { + block_import: client.clone(), + env: proposer, + client: client.clone(), + pool: transaction_pool.clone(), + select_chain: LongestChain::new(backend.clone()), + consensus_data_provider: Some(Box::new(aura_digest_provider)), + create_inherent_data_providers, + }; + + let authorship_future = sc_consensus_manual_seal::run_instant_seal(params); + task_manager.spawn_essential_handle().spawn_blocking( + "instant-seal", + None, + authorship_future, + ); + }, + DevSealMode::ManualSeal(block_time) => { + let (manual_seal_sink, manual_seal_stream) = futures::channel::mpsc::channel(1024); + let mut manual_seal_sink_clone = manual_seal_sink.clone(); + task_manager + .spawn_essential_handle() + .spawn("block_authoring", None, async move { + loop { + futures_timer::Delay::new(std::time::Duration::from_millis(block_time)) + .await; + manual_seal_sink_clone + .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: client.clone(), + pool: transaction_pool.clone(), + select_chain: LongestChain::new(backend.clone()), + commands_stream: Box::pin(manual_seal_stream), + consensus_data_provider: Some(Box::new(aura_digest_provider)), + create_inherent_data_providers, + }; + + let authorship_future = sc_consensus_manual_seal::run_manual_seal(params); + task_manager.spawn_essential_handle().spawn_blocking( + "manual-seal", + None, + authorship_future, + ); + }, + } let rpc_extensions_builder = { let client = client.clone(); @@ -373,11 +393,11 @@ where RuntimeApi::RuntimeApi: AuraRuntimeApi, AuraId: AuraIdT + Sync, { - /// Creates the inherent data providers for manual seal consensus. + /// Creates the inherent data providers for manual and instant seal consensus. /// /// This function sets up the timestamp and parachain validation data providers - /// required for manual seal block production in a parachain environment. - fn create_manual_seal_inherent_data_providers( + /// required for dev seal block production in a parachain environment. + fn create_dev_node_inherent_data_providers( client: Arc>, para_id: ParaId, slot_duration: sp_consensus_aura::SlotDuration, diff --git a/prdoc/pr_10008.prdoc b/prdoc/pr_10008.prdoc new file mode 100644 index 0000000000000..d9da04a4c5693 --- /dev/null +++ b/prdoc/pr_10008.prdoc @@ -0,0 +1,12 @@ +title: Add instant seal to omni-node +doc: +- audience: Runtime Dev + description: |- + Adds a new `--instant-seal` CLI flag to enable instant seal mode in omni-node. When this flag + is passed, blocks are produced immediately upon receiving transactions, rather than at fixed + intervals. This flag cannot be used together with `--dev-block-time`. + + fixes https://github.com/paritytech/polkadot-sdk/issues/9996 +crates: +- name: polkadot-omni-node-lib + bump: patch