From 43356005b41377323e3ad566e04f8b5d5b2d18ef Mon Sep 17 00:00:00 2001 From: Iulian Barbu <14218860+iulianbarbu@users.noreply.github.com> Date: Wed, 11 Dec 2024 00:33:13 +0200 Subject: [PATCH] BACKPORT-CONFLICT --- cumulus/polkadot-omni-node/README.md | 65 +++ cumulus/polkadot-omni-node/lib/src/cli.rs | 414 ++++++++++++++++++ cumulus/polkadot-omni-node/lib/src/command.rs | 329 ++++++++++++++ prdoc/pr_6646.prdoc | 19 + .../client/cli/src/params/shared_params.rs | 18 +- templates/minimal/README.md | 93 ++++ templates/minimal/zombienet-omni-node.toml | 9 + templates/parachain/README.md | 97 ++++ 8 files changed, 1034 insertions(+), 10 deletions(-) create mode 100644 cumulus/polkadot-omni-node/README.md create mode 100644 cumulus/polkadot-omni-node/lib/src/cli.rs create mode 100644 cumulus/polkadot-omni-node/lib/src/command.rs create mode 100644 prdoc/pr_6646.prdoc create mode 100644 templates/minimal/zombienet-omni-node.toml diff --git a/cumulus/polkadot-omni-node/README.md b/cumulus/polkadot-omni-node/README.md new file mode 100644 index 000000000000..015019961c9f --- /dev/null +++ b/cumulus/polkadot-omni-node/README.md @@ -0,0 +1,65 @@ +# Polkadot Omni Node + +This is a white labeled implementation based on [`polkadot-omni-node-lib`](https://crates.io/crates/polkadot-omni-node-lib). +It can be used to start a parachain node from a provided chain spec file. It is only compatible with runtimes that use block +number `u32` and `Aura` consensus. + +## Installation + +Download & expose it via `PATH`: + +```bash +# Download and set it on PATH. +wget https://github.com/paritytech/polkadot-sdk/releases/download//polkadot-omni-node +chmod +x polkadot-omni-node +export PATH="$PATH:`pwd`" +``` + +Compile & install via `cargo`: + +```bash +# Assuming ~/.cargo/bin is on the PATH +cargo install polkadot-omni-node +``` + +## Usage + +A basic example for an Omni Node run starts from a runtime which implements the [`sp_genesis_builder::GenesisBuilder`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html). +The interface mandates the runtime to expose a [`named-preset`](https://docs.rs/staging-chain-spec-builder/latest/staging_chain_spec_builder/#generate-chain-spec-using-runtime-provided-genesis-config-preset). + +### 1. Install chain-spec-builder + +**Note**: `chain-spec-builder` binary is published on [`crates.io`](https://crates.io) under +[`staging-chain-spec-builder`](https://crates.io/crates/staging-chain-spec-builder) due to a name conflict. +Install it with `cargo` like bellow : + +```bash +cargo install staging-chain-spec-builder +``` + +### 2. Generate a chain spec + +Omni Node expects for the chain spec to contain parachains related fields like `relay_chain` and `para_id`. +These fields can be introduced by running [`staging-chain-spec-builder`](https://crates.io/crates/staging-chain-spec-builder) +with additional flags: + +```bash +chain-spec-builder create --relay-chain --para-id -r named-preset +``` + +### 3. Run Omni Node + +And now with the generated chain spec we can start the node in development mode like so: + +```bash +polkadot-omni-node --dev --chain +``` + +## Useful links + +* [`Omni Node Polkadot SDK Docs`](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/omni_node/index.html) +* [`Chain Spec Genesis Reference Docs`](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/chain_spec_genesis/index.html) +* [`polkadot-parachain-bin`](https://crates.io/crates/polkadot-parachain-bin) +* [`polkadot-sdk-parachain-template`](https://github.com/paritytech/polkadot-sdk-parachain-template) +* [`frame-omni-bencher`](https://crates.io/crates/frame-omni-bencher) +* [`staging-chain-spec-builder`](https://crates.io/crates/staging-chain-spec-builder) diff --git a/cumulus/polkadot-omni-node/lib/src/cli.rs b/cumulus/polkadot-omni-node/lib/src/cli.rs new file mode 100644 index 000000000000..9c4e2561592d --- /dev/null +++ b/cumulus/polkadot-omni-node/lib/src/cli.rs @@ -0,0 +1,414 @@ +// 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 . + +//! CLI options of the omni-node. See [`Command`]. + +use crate::{ + chain_spec::DiskChainSpecLoader, + common::{ + chain_spec::{Extensions, LoadSpec}, + NodeExtraArgs, + }, +}; +use clap::{Command, CommandFactory, FromArgMatches}; +use sc_chain_spec::ChainSpec; +use sc_cli::{ + CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, NetworkParams, + RpcEndpoint, SharedParams, SubstrateCli, +}; +use sc_service::{config::PrometheusConfig, BasePath}; +use std::{fmt::Debug, marker::PhantomData, path::PathBuf}; + +/// Trait that can be used to customize some of the customer-facing info related to the node binary +/// that is being built using this library. +/// +/// The related info is shown to the customer as part of logs or help messages. +/// It does not impact functionality. +pub trait CliConfig { + /// The version of the resulting node binary. + fn impl_version() -> String; + + /// The description of the resulting node binary. + fn description(executable_name: String) -> String { + format!( + "The command-line arguments provided first will be passed to the parachain node, \n\ + and the arguments provided after -- will be passed to the relay chain node. \n\ + \n\ + Example: \n\ + \n\ + {} [parachain-args] -- [relay-chain-args]", + executable_name + ) + } + + /// The author of the resulting node binary. + fn author() -> String; + + /// The support URL for the resulting node binary. + fn support_url() -> String; + + /// The starting copyright year of the resulting node binary. + fn copyright_start_year() -> u16; +} + +/// Sub-commands supported by the collator. +#[derive(Debug, clap::Subcommand)] +pub enum Subcommand { + /// Key management CLI utilities + #[command(subcommand)] + Key(sc_cli::KeySubcommand), + + /// Build a chain specification. + BuildSpec(sc_cli::BuildSpecCmd), + + /// Validate blocks. + CheckBlock(sc_cli::CheckBlockCmd), + + /// Export blocks. + ExportBlocks(sc_cli::ExportBlocksCmd), + + /// Export the state of a given block into a chain spec. + ExportState(sc_cli::ExportStateCmd), + + /// Import blocks. + ImportBlocks(sc_cli::ImportBlocksCmd), + + /// Revert the chain to a previous state. + Revert(sc_cli::RevertCmd), + + /// Remove the whole chain. + PurgeChain(cumulus_client_cli::PurgeChainCmd), + + /// Export the genesis state of the parachain. + #[command(alias = "export-genesis-state")] + ExportGenesisHead(cumulus_client_cli::ExportGenesisHeadCommand), + + /// Export the genesis wasm of the parachain. + ExportGenesisWasm(cumulus_client_cli::ExportGenesisWasmCommand), + + /// Sub-commands concerned with benchmarking. + /// The pallet benchmarking moved to the `pallet` sub-command. + #[command(subcommand)] + Benchmark(frame_benchmarking_cli::BenchmarkCmd), +} + +/// CLI Options shipped with `polkadot-omni-node`. +#[derive(clap::Parser)] +#[command( + propagate_version = true, + args_conflicts_with_subcommands = true, + subcommand_negates_reqs = true +)] +pub struct Cli { + #[arg(skip)] + pub(crate) chain_spec_loader: Option>, + + /// Possible subcommands. See [`Subcommand`]. + #[command(subcommand)] + pub subcommand: Option, + + /// The shared parameters with all cumulus-based parachain nodes. + #[command(flatten)] + pub run: cumulus_client_cli::RunCmd, + + /// Start a dev node that produces a block each `dev_block_time` ms. + /// + /// This is a dev option. It enables a manual sealing, meaning blocks are produced manually + /// rather than being part of an actual network consensus process. Using the 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 artificially producing a block each `dev_block_time` ms, + /// as if it was part of a parachain. + /// + /// The `--dev` flag sets the `dev_block_time` to a default value of 3000ms unless explicitly + /// provided. + #[arg(long)] + pub dev_block_time: Option, + + /// EXPERIMENTAL: Use slot-based collator which can handle elastic scaling. + /// + /// Use with care, this flag is unstable and subject to change. + #[arg(long)] + pub experimental_use_slot_based: bool, + + /// Disable automatic hardware benchmarks. + /// + /// By default these benchmarks are automatically ran at startup and measure + /// the CPU speed, the memory bandwidth and the disk speed. + /// + /// The results are then printed out in the logs, and also sent as part of + /// telemetry, if telemetry is enabled. + #[arg(long)] + pub no_hardware_benchmarks: bool, + + /// Export all `PoVs` build by this collator to the given folder. + /// + /// This is useful for debugging issues that are occurring while validating these `PoVs` on the + /// relay chain. + #[arg(long)] + pub export_pov_to_path: Option, + + /// Relay chain arguments + #[arg(raw = true)] + pub relay_chain_args: Vec, + + #[arg(skip)] + pub(crate) _phantom: PhantomData, +} + +impl Cli { + pub(crate) fn node_extra_args(&self) -> NodeExtraArgs { + NodeExtraArgs { + use_slot_based_consensus: self.experimental_use_slot_based, + export_pov: self.export_pov_to_path.clone(), + } + } +} + +impl SubstrateCli for Cli { + fn impl_name() -> String { + Self::executable_name() + } + + fn impl_version() -> String { + Config::impl_version() + } + + fn description() -> String { + Config::description(Self::executable_name()) + } + + fn author() -> String { + Config::author() + } + + fn support_url() -> String { + Config::support_url() + } + + fn copyright_start_year() -> i32 { + Config::copyright_start_year() as i32 + } + + fn load_spec(&self, id: &str) -> Result, String> { + match &self.chain_spec_loader { + Some(chain_spec_loader) => chain_spec_loader.load_spec(id), + None => DiskChainSpecLoader.load_spec(id), + } + } +} + +/// The relay chain CLI flags. These are passed in after a `--` at the end. +#[derive(Debug)] +pub struct RelayChainCli { + /// The actual relay chain cli object. + pub base: polkadot_cli::RunCmd, + + /// Optional chain id that should be passed to the relay chain. + pub chain_id: Option, + + /// The base path that should be used by the relay chain. + pub base_path: Option, + + _phantom: PhantomData, +} + +impl RelayChainCli { + fn polkadot_cmd() -> Command { + let help_template = color_print::cformat!( + "The arguments that are passed to the relay chain node. \n\ + \n\ + RELAY_CHAIN_ARGS: \n\ + {{options}}", + ); + + polkadot_cli::RunCmd::command() + .no_binary_name(true) + .help_template(help_template) + } + + /// 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 = Self::polkadot_cmd(); + 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 = 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, chain_id, base_path: Some(base_path), _phantom: Default::default() } + } +} + +impl SubstrateCli for RelayChainCli { + fn impl_name() -> String { + Cli::::impl_name() + } + + fn impl_version() -> String { + Cli::::impl_version() + } + + fn description() -> String { + Cli::::description() + } + + fn author() -> String { + Cli::::author() + } + + fn support_url() -> String { + Cli::::support_url() + } + + fn copyright_start_year() -> i32 { + Cli::::copyright_start_year() + } + + fn load_spec(&self, id: &str) -> std::result::Result, String> { + polkadot_cli::Cli::from_iter([Self::executable_name()].iter()).load_spec(id) + } +} + +impl DefaultConfigurationValues for RelayChainCli { + fn p2p_listen_port() -> u16 { + 30334 + } + + fn rpc_listen_port() -> u16 { + 9945 + } + + fn prometheus_listen_port() -> u16 { + 9616 + } +} + +impl CliConfiguration for RelayChainCli { + fn shared_params(&self) -> &SharedParams { + self.base.base.shared_params() + } + + fn import_params(&self) -> Option<&ImportParams> { + self.base.base.import_params() + } + + fn network_params(&self) -> Option<&NetworkParams> { + self.base.base.network_params() + } + + fn keystore_params(&self) -> Option<&KeystoreParams> { + self.base.base.keystore_params() + } + + fn base_path(&self) -> sc_cli::Result> { + Ok(self + .shared_params() + .base_path()? + .or_else(|| self.base_path.clone().map(Into::into))) + } + + fn rpc_addr(&self, default_listen_port: u16) -> sc_cli::Result>> { + self.base.base.rpc_addr(default_listen_port) + } + + fn prometheus_config( + &self, + default_listen_port: u16, + chain_spec: &Box, + ) -> sc_cli::Result> { + self.base.base.prometheus_config(default_listen_port, chain_spec) + } + + fn init( + &self, + _support_url: &String, + _impl_version: &String, + _logger_hook: F, + ) -> sc_cli::Result<()> + where + F: FnOnce(&mut sc_cli::LoggerBuilder), + { + unreachable!("PolkadotCli is never initialized; qed"); + } + + fn chain_id(&self, is_dev: bool) -> sc_cli::Result { + let chain_id = self.base.base.chain_id(is_dev)?; + + Ok(if chain_id.is_empty() { self.chain_id.clone().unwrap_or_default() } else { chain_id }) + } + + fn role(&self, is_dev: bool) -> sc_cli::Result { + self.base.base.role(is_dev) + } + + fn transaction_pool( + &self, + is_dev: bool, + ) -> sc_cli::Result { + self.base.base.transaction_pool(is_dev) + } + + fn trie_cache_maximum_size(&self) -> sc_cli::Result> { + self.base.base.trie_cache_maximum_size() + } + + fn rpc_methods(&self) -> sc_cli::Result { + self.base.base.rpc_methods() + } + + fn rpc_max_connections(&self) -> sc_cli::Result { + self.base.base.rpc_max_connections() + } + + fn rpc_cors(&self, is_dev: bool) -> sc_cli::Result>> { + self.base.base.rpc_cors(is_dev) + } + + fn default_heap_pages(&self) -> sc_cli::Result> { + self.base.base.default_heap_pages() + } + + fn force_authoring(&self) -> sc_cli::Result { + self.base.base.force_authoring() + } + + fn disable_grandpa(&self) -> sc_cli::Result { + self.base.base.disable_grandpa() + } + + fn max_runtime_instances(&self) -> sc_cli::Result> { + self.base.base.max_runtime_instances() + } + + fn announce_block(&self) -> sc_cli::Result { + self.base.base.announce_block() + } + + fn telemetry_endpoints( + &self, + chain_spec: &Box, + ) -> sc_cli::Result> { + self.base.base.telemetry_endpoints(chain_spec) + } + + fn node_name(&self) -> sc_cli::Result { + self.base.base.node_name() + } +} diff --git a/cumulus/polkadot-omni-node/lib/src/command.rs b/cumulus/polkadot-omni-node/lib/src/command.rs new file mode 100644 index 000000000000..fe7f7cac0971 --- /dev/null +++ b/cumulus/polkadot-omni-node/lib/src/command.rs @@ -0,0 +1,329 @@ +// 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::{ + cli::{Cli, RelayChainCli, Subcommand}, + common::{ + chain_spec::{Extensions, LoadSpec}, + runtime::{ + AuraConsensusId, Consensus, Runtime, RuntimeResolver as RuntimeResolverT, + RuntimeResolver, + }, + types::Block, + NodeBlock, NodeExtraArgs, + }, + fake_runtime_api, + nodes::DynNodeSpecExt, + runtime::BlockNumber, +}; +#[cfg(feature = "runtime-benchmarks")] +use cumulus_client_service::storage_proof_size::HostFunctions as ReclaimHostFunctions; +use cumulus_primitives_core::ParaId; +use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; +use log::info; +use sc_cli::{CliConfiguration, Result, SubstrateCli}; +use sp_runtime::traits::AccountIdConversion; +#[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 { + /// A custom chain spec loader. + pub chain_spec_loader: Box, + /// A custom runtime resolver. + pub runtime_resolver: Box, +} + +impl RunConfig { + /// Create a new `RunConfig` + pub fn new( + runtime_resolver: Box, + chain_spec_loader: Box, + ) -> Self { + RunConfig { chain_spec_loader, runtime_resolver } + } +} + +pub fn new_aura_node_spec( + aura_id: AuraConsensusId, + extra_args: &NodeExtraArgs, +) -> Box +where + Block: NodeBlock, +{ + match aura_id { + AuraConsensusId::Sr25519 => crate::nodes::aura::new_aura_node_spec::< + Block, + fake_runtime_api::aura_sr25519::RuntimeApi, + sp_consensus_aura::sr25519::AuthorityId, + >(extra_args), + AuraConsensusId::Ed25519 => crate::nodes::aura::new_aura_node_spec::< + Block, + fake_runtime_api::aura_ed25519::RuntimeApi, + sp_consensus_aura::ed25519::AuthorityId, + >(extra_args), + } +} + +fn new_node_spec( + config: &sc_service::Configuration, + runtime_resolver: &Box, + extra_args: &NodeExtraArgs, +) -> std::result::Result, sc_cli::Error> { + let runtime = runtime_resolver.runtime(config.chain_spec.as_ref())?; + + Ok(match runtime { + Runtime::Omni(block_number, consensus) => match (block_number, consensus) { + (BlockNumber::U32, Consensus::Aura(aura_id)) => + new_aura_node_spec::>(aura_id, extra_args), + (BlockNumber::U64, Consensus::Aura(aura_id)) => + new_aura_node_spec::>(aura_id, extra_args), + }, + }) +} + +/// Parse command line arguments into service configuration. +pub fn run(cmd_config: RunConfig) -> Result<()> { + let mut cli = Cli::::from_args(); + cli.chain_spec_loader = Some(cmd_config.chain_spec_loader); + + match &cli.subcommand { + Some(Subcommand::BuildSpec(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|config| cmd.run(config.chain_spec, config.network)) + }, + Some(Subcommand::CheckBlock(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let node = + new_node_spec(&config, &cmd_config.runtime_resolver, &cli.node_extra_args())?; + node.prepare_check_block_cmd(config, cmd) + }) + }, + Some(Subcommand::ExportBlocks(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let node = + new_node_spec(&config, &cmd_config.runtime_resolver, &cli.node_extra_args())?; + node.prepare_export_blocks_cmd(config, cmd) + }) + }, + Some(Subcommand::ExportState(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let node = + new_node_spec(&config, &cmd_config.runtime_resolver, &cli.node_extra_args())?; + node.prepare_export_state_cmd(config, cmd) + }) + }, + Some(Subcommand::ImportBlocks(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let node = + new_node_spec(&config, &cmd_config.runtime_resolver, &cli.node_extra_args())?; + node.prepare_import_blocks_cmd(config, cmd) + }) + }, + Some(Subcommand::Revert(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let node = + new_node_spec(&config, &cmd_config.runtime_resolver, &cli.node_extra_args())?; + node.prepare_revert_cmd(config, cmd) + }) + }, + Some(Subcommand::PurgeChain(cmd)) => { + let runner = cli.create_runner(cmd)?; + let polkadot_cli = + RelayChainCli::::new(runner.config(), cli.relay_chain_args.iter()); + + runner.sync_run(|config| { + let polkadot_config = SubstrateCli::create_configuration( + &polkadot_cli, + &polkadot_cli, + config.tokio_handle.clone(), + ) + .map_err(|err| format!("Relay chain argument error: {}", err))?; + + cmd.run(config, polkadot_config) + }) + }, + Some(Subcommand::ExportGenesisHead(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|config| { + let node = + new_node_spec(&config, &cmd_config.runtime_resolver, &cli.node_extra_args())?; + node.run_export_genesis_head_cmd(config, cmd) + }) + }, + Some(Subcommand::ExportGenesisWasm(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|_config| { + let spec = cli.load_spec(&cmd.shared_params.chain.clone().unwrap_or_default())?; + cmd.run(&*spec) + }) + }, + Some(Subcommand::Benchmark(cmd)) => { + let runner = cli.create_runner(cmd)?; + + // Switch on the concrete benchmark sub-command- + match cmd { + #[cfg(feature = "runtime-benchmarks")] + BenchmarkCmd::Pallet(cmd) => runner.sync_run(|config| { + cmd.run_with_spec::>, ReclaimHostFunctions>(Some( + config.chain_spec, + )) + }), + BenchmarkCmd::Block(cmd) => runner.sync_run(|config| { + let node = new_node_spec( + &config, + &cmd_config.runtime_resolver, + &cli.node_extra_args(), + )?; + node.run_benchmark_block_cmd(config, cmd) + }), + #[cfg(feature = "runtime-benchmarks")] + BenchmarkCmd::Storage(cmd) => runner.sync_run(|config| { + let node = new_node_spec( + &config, + &cmd_config.runtime_resolver, + &cli.node_extra_args(), + )?; + node.run_benchmark_storage_cmd(config, cmd) + }), + BenchmarkCmd::Machine(cmd) => + runner.sync_run(|config| cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone())), + #[allow(unreachable_patterns)] + _ => Err("Benchmarking sub-command unsupported or compilation feature missing. \ + Make sure to compile with --features=runtime-benchmarks \ + to enable all supported benchmarks." + .into()), + } + }, + 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.relay_chain_args.iter()); + let collator_options = cli.run.collator_options(); + + runner.run_node_until_exit(|config| async move { + let node_spec = + new_node_spec(&config, &cmd_config.runtime_resolver, &cli.node_extra_args())?; + let para_id = ParaId::from( + Extensions::try_get(&*config.chain_spec) + .map(|e| e.para_id) + .ok_or("Could not find parachain extension in chain-spec.")?, + ); + + if cli.run.base.is_dev()? { + // Set default dev block time to 3000ms if not set. + // TODO: take block time from AURA config if set. + let dev_block_time = cli.dev_block_time.unwrap_or(DEFAULT_DEV_BLOCK_TIME_MS); + return node_spec + .start_manual_seal_node(config, para_id, 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, para_id, dev_block_time) + .map_err(Into::into); + } + + // If Statemint (Statemine, Westmint, Rockmine) DB exists and we're using the + // asset-hub chain spec, then rename the base path to the new chain ID. In the case + // that both file paths exist, the node will exit, as the user must decide (by + // deleting one path) the information that they want to use as their DB. + let old_name = match config.chain_spec.id() { + "asset-hub-polkadot" => Some("statemint"), + "asset-hub-kusama" => Some("statemine"), + "asset-hub-westend" => Some("westmint"), + "asset-hub-rococo" => Some("rockmine"), + _ => None, + }; + + if let Some(old_name) = old_name { + let new_path = config.base_path.config_dir(config.chain_spec.id()); + let old_path = config.base_path.config_dir(old_name); + + if old_path.exists() && new_path.exists() { + return Err(format!( + "Found legacy {} path {} and new Asset Hub path {}. \ + Delete one path such that only one exists.", + old_name, + old_path.display(), + new_path.display() + ) + .into()); + } + + if old_path.exists() { + std::fs::rename(old_path.clone(), new_path.clone())?; + info!( + "{} was renamed to Asset Hub. The filepath with associated data on disk \ + has been renamed from {} to {}.", + old_name, + old_path.display(), + new_path.display() + ); + } + } + + let hwbench = (!cli.no_hardware_benchmarks) + .then(|| { + config.database.path().map(|database_path| { + let _ = std::fs::create_dir_all(database_path); + sc_sysinfo::gather_hwbench( + Some(database_path), + &SUBSTRATE_REFERENCE_HARDWARE, + ) + }) + }) + .flatten(); + + let parachain_account = + AccountIdConversion::::into_account_truncating( + ¶_id, + ); + + let tokio_handle = config.tokio_handle.clone(); + let polkadot_config = + SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle) + .map_err(|err| format!("Relay chain argument error: {}", err))?; + + info!("๐Ÿชช Parachain id: {:?}", para_id); + info!("๐Ÿงพ Parachain Account: {}", parachain_account); + info!("โœ๏ธ Is collating: {}", if config.role.is_authority() { "yes" } else { "no" }); + + node_spec + .start_node( + config, + polkadot_config, + collator_options, + para_id, + hwbench, + cli.node_extra_args(), + ) + .await + .map_err(Into::into) + }) + }, + } +} diff --git a/prdoc/pr_6646.prdoc b/prdoc/pr_6646.prdoc new file mode 100644 index 000000000000..4dcda8d41bda --- /dev/null +++ b/prdoc/pr_6646.prdoc @@ -0,0 +1,19 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: OmniNode --dev flag starts node with manual seal + +doc: + - audience: [ Runtime Dev, Node Dev ] + description: | + `polkadot-omni-node` lib supports `--dev` flag now by allowing also to pass over a chain spec, + and starts the node with manual seal. It will seal the node at each `dev_block_time` milliseconds, + which can be set via `--dev-block-time`, and if not set will default to `3000ms`. + +crates: + - name: sc-cli + bump: patch + - name: polkadot-omni-node-lib + bump: patch + - name: polkadot-omni-node + bump: patch diff --git a/substrate/client/cli/src/params/shared_params.rs b/substrate/client/cli/src/params/shared_params.rs index 465372fba17d..e0c52deb44ca 100644 --- a/substrate/client/cli/src/params/shared_params.rs +++ b/substrate/client/cli/src/params/shared_params.rs @@ -33,10 +33,12 @@ pub struct SharedParams { /// Specify the development chain. /// - /// This flag sets `--chain=dev`, `--force-authoring`, `--rpc-cors=all`, - /// `--alice`, and `--tmp` flags, unless explicitly overridden. - /// It also disables local peer discovery (see --no-mdns and --discover-local) - #[arg(long, conflicts_with_all = &["chain"])] + /// This flag sets `--chain=dev`, `--force-authoring`, `--rpc-cors=all`, `--alice`, and `--tmp` + /// flags, unless explicitly overridden. It also disables local peer discovery (see `--no-mdns` + /// and `--discover-local`). With this flag some nodes might start with manual seal, producing + /// blocks at certain events (e.g. `polkadot-omni-node`, which produces blocks at certain + /// intervals dictated by `--dev-block-time`). + #[arg(long)] pub dev: bool, /// Specify custom base path. @@ -109,12 +111,8 @@ impl SharedParams { pub fn chain_id(&self, is_dev: bool) -> String { match self.chain { Some(ref chain) => chain.clone(), - None => - if is_dev { - "dev".into() - } else { - "".into() - }, + None if is_dev => "dev".into(), + _ => "".into(), } } diff --git a/templates/minimal/README.md b/templates/minimal/README.md index 9c9cb40a311a..818aace306c6 100644 --- a/templates/minimal/README.md +++ b/templates/minimal/README.md @@ -45,7 +45,63 @@ packages required to compile this template - please take note of the Rust compil cargo build --package minimal-template-node --release ``` +<<<<<<< HEAD ๐Ÿณ Alternatively, build the docker image: +======= +## Starting a Minimal Template Chain + +### Omni Node + +[Omni Node](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/omni_node/index.html) can +be used to run the minimal template's runtime. `polkadot-omni-node` binary crate usage is described at a high-level +[on crates.io](https://crates.io/crates/polkadot-omni-node). + +#### Install `polkadot-omni-node` + +Please see installation section on [crates.io/omni-node](https://crates.io/crates/polkadot-omni-node). + +#### Build `minimal-template-runtime` + +```sh +cargo build -p minimal-template-runtime --release +``` + +#### Install `staging-chain-spec-builder` + +Please see the installation section at [`crates.io/staging-chain-spec-builder`](https://crates.io/crates/staging-chain-spec-builder). + +#### Use chain-spec-builder to generate the chain_spec.json file + +```sh +chain-spec-builder create --relay-chain "dev" --para-id 1000 --runtime \ + target/release/wbuild/minimal-template-runtime/minimal_template_runtime.wasm named-preset development +``` + +**Note**: the `relay-chain` and `para-id` flags are extra bits of information required to +configure the node for the case of representing a parachain that is connected to a relay chain. +They are not relevant to minimal template business logic, but they are mandatory information for +Omni Node, nonetheless. + +#### Run Omni Node + +Start Omni Node in development mode (sets up block production and finalization based on manual seal, +sealing a new block every 3 seconds), with a minimal template runtime chain spec. + +```sh +polkadot-omni-node --chain --dev +``` + +### Minimal Template Node + +#### Build both node & runtime + +```sh +cargo build --workspace --release +``` + +๐Ÿณ Alternatively, build the docker image which builds all the workspace members, +and has as entry point the node binary: +>>>>>>> 48c28d4c (omni-node: --dev sets manual seal and allows --chain to be set (#6646)) ```sh docker build . -t polkadot-sdk-minimal-template @@ -64,9 +120,46 @@ docker run --rm polkadot-sdk-minimal-template --dev Development chains: +<<<<<<< HEAD * ๐Ÿงน Do not persist the state. * ๐Ÿ’ฐ Are pre-configured with a genesis state that includes several pre-funded development accounts. * ๐Ÿง‘โ€โš–๏ธ One development account (`ALICE`) is used as `sudo` accounts. +======= +#### Install `zombienet` + +We can install `zombienet` as described [here](https://paritytech.github.io/zombienet/install.html#installation), +and `zombienet-omni-node.toml` contains the network specification we want to start. + +#### Update `zombienet-omni-node.toml` with a valid chain spec path + +Before starting the network with zombienet we must update the network specification +with a valid chain spec path. If we need to generate one, we can look up at the previous +section for chain spec creation [here](#use-chain-spec-builder-to-generate-the-chain_specjson-file). + +Then make the changes in the network specification like so: + +```toml +# ... +chain = "dev" +chain_spec_path = "" +default_args = ["--dev"] +# .. +``` + +#### Start the network + +```sh +zombienet --provider native spawn zombienet-omni-node.toml +``` + +### Zombienet with `minimal-template-node` + +For this one we just need to have `zombienet` installed and run: + +```sh +zombienet --provider native spawn zombienet-multi-node.toml +``` +>>>>>>> 48c28d4c (omni-node: --dev sets manual seal and allows --chain to be set (#6646)) ### Connect with the Polkadot-JS Apps Front-End diff --git a/templates/minimal/zombienet-omni-node.toml b/templates/minimal/zombienet-omni-node.toml new file mode 100644 index 000000000000..acd5b121c674 --- /dev/null +++ b/templates/minimal/zombienet-omni-node.toml @@ -0,0 +1,9 @@ +[relaychain] +default_command = "polkadot-omni-node" +chain = "dev" +chain_spec_path = "" +default_args = ["--dev"] + +[[relaychain.nodes]] +name = "alice" +ws_port = 9944 diff --git a/templates/parachain/README.md b/templates/parachain/README.md index 802d8586b39e..85a47eb7d11c 100644 --- a/templates/parachain/README.md +++ b/templates/parachain/README.md @@ -13,7 +13,33 @@ * โซ This template provides a starting point to build a [parachain](https://wiki.polkadot.network/docs/learn-parachains). +<<<<<<< HEAD * โ˜๏ธ It is based on the +======= +- [Intro](#intro) + +- [Template Structure](#template-structure) + +- [Getting Started](#getting-started) + +- [Starting a Development Chain](#starting-a-development-chain) + + - [Omni Node](#omni-node-prerequisites) + - [Zombienet setup with Omni Node](#zombienet-setup-with-omni-node) + - [Parachain Template Node](#parachain-template-node) + - [Connect with the Polkadot-JS Apps Front-End](#connect-with-the-polkadot-js-apps-front-end) + - [Takeaways](#takeaways) + +- [Runtime development](#runtime-development) +- [Contributing](#contributing) +- [Getting Help](#getting-help) + +## Intro + +- โซ This template provides a starting point to build a [parachain](https://wiki.polkadot.network/docs/learn-parachains). + +- โ˜๏ธ It is based on the +>>>>>>> 48c28d4c (omni-node: --dev sets manual seal and allows --chain to be set (#6646)) [Cumulus](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/cumulus/index.html) framework. * ๐Ÿ”ง Its runtime is configured with a single custom pallet as a starting point, and a handful of ready-made pallets @@ -72,7 +98,35 @@ export PATH="./target/release/:$PATH" This way, we can conveniently use them in the following steps. +<<<<<<< HEAD ๐Ÿ‘ฅ The following command starts a local development chain, with a single relay chain node and a single parachain collator: +======= +#### Run Omni Node + +Start Omni Node with the generated chain spec. We'll start it in development mode (without a relay chain config), producing +and finalizing blocks based on manual seal, configured below to seal a block with each second. + +```bash +polkadot-omni-node --chain --dev --dev-block-time 1000 +``` + +However, such a setup is not close to what would run in production, and for that we need to setup a local +relay chain network that will help with the block finalization. In this guide we'll setup a local relay chain +as well. We'll not do it manually, by starting one node at a time, but we'll use [zombienet](https://paritytech.github.io/zombienet/intro.html). + +Follow through the next section for more details on how to do it. + +### Zombienet setup with Omni Node + +Assuming we continue from the last step of the previous section, we have a chain spec and we need to setup a relay chain. +We can install `zombienet` as described [here](https://paritytech.github.io/zombienet/install.html#installation), and +`zombienet-omni-node.toml` contains the network specification we want to start. + +#### Relay chain prerequisites + +Download the `polkadot` (and the accompanying `polkadot-prepare-worker` and `polkadot-execute-worker`) binaries from +[Polkadot SDK releases](https://github.com/paritytech/polkadot-sdk/releases). Then expose them on `PATH` like so: +>>>>>>> 48c28d4c (omni-node: --dev sets manual seal and allows --chain to be set (#6646)) ```sh zombienet --provider native spawn ./zombienet.toml @@ -100,6 +154,49 @@ available on [IPFS](https://dotapps.io/). * ๐Ÿง‘โ€๐Ÿ”ง You can also find the source code and instructions for hosting your own instance in the [`polkadot-js/apps`](https://github.com/polkadot-js/apps) repository. +<<<<<<< HEAD +======= +### Takeaways + +Development parachains: + +- ๐Ÿ”— Connect to relay chains, and we showcased how to connect to a local one. +- ๐Ÿงน Do not persist the state. +- ๐Ÿ’ฐ Are preconfigured with a genesis state that includes several prefunded development accounts. +- ๐Ÿง‘โ€โš–๏ธ Development accounts are used as validators, collators, and `sudo` accounts. + +## Runtime development + +We recommend using [`chopsticks`](https://github.com/AcalaNetwork/chopsticks) when the focus is more on the runtime +development and `OmniNode` is enough as is. + +### Install chopsticks + +To use `chopsticks`, please install the latest version according to the installation [guide](https://github.com/AcalaNetwork/chopsticks?tab=readme-ov-file#install). + +### Build a raw chain spec + +Build the `parachain-template-runtime` as mentioned before in this guide and use `chain-spec-builder` +again but this time by passing `--raw-storage` flag: + +```sh +chain-spec-builder create --raw-storage --relay-chain "rococo-local" --para-id 1000 --runtime \ + target/release/wbuild/parachain-template-runtime/parachain_template_runtime.wasm named-preset development +``` + +### Start `chopsticks` with the chain spec + +```sh +npx @acala-network/chopsticks@latest --chain-spec +``` + +### Alternatives + +`OmniNode` can be still used for runtime development if using the `--dev` flag, while `parachain-template-node` doesn't +support it at this moment. It can still be used to test a runtime in a full setup where it is started alongside a +relay chain network (see [Parachain Template node](#parachain-template-node) setup). + +>>>>>>> 48c28d4c (omni-node: --dev sets manual seal and allows --chain to be set (#6646)) ## Contributing * ๐Ÿ”„ This template is automatically updated after releases in the main [Polkadot SDK monorepo](https://github.com/paritytech/polkadot-sdk).