diff --git a/bin/node-template/node/src/cli.rs b/bin/node-template/node/src/cli.rs index 46ab9bc3dafac..f3667fa79d19e 100644 --- a/bin/node-template/node/src/cli.rs +++ b/bin/node-template/node/src/cli.rs @@ -1,5 +1,5 @@ use structopt::StructOpt; -use sc_cli::{RunCmd, Subcommand}; +use sc_cli::RunCmd; #[derive(Debug, StructOpt)] pub struct Cli { @@ -9,3 +9,27 @@ pub struct Cli { #[structopt(flatten)] pub run: RunCmd, } + +#[derive(Debug, StructOpt)] +pub enum Subcommand { + /// 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), + + /// Remove the whole chain. + PurgeChain(sc_cli::PurgeChainCmd), + + /// Revert the chain to a previous state. + Revert(sc_cli::RevertCmd), +} diff --git a/bin/node-template/node/src/command.rs b/bin/node-template/node/src/command.rs index 9cd2248d6547a..98c56e948300e 100644 --- a/bin/node-template/node/src/command.rs +++ b/bin/node-template/node/src/command.rs @@ -16,7 +16,7 @@ // limitations under the License. use crate::chain_spec; -use crate::cli::Cli; +use crate::cli::{Cli, Subcommand}; use crate::service; use sc_cli::{SubstrateCli, RuntimeVersion, Role, ChainSpec}; use sc_service::PartialComponents; @@ -66,15 +66,55 @@ impl SubstrateCli for Cli { pub fn run() -> sc_cli::Result<()> { let cli = Cli::from_args(); - match cli.subcommand { - Some(ref subcommand) => { - let runner = cli.create_runner(subcommand)?; - runner.run_subcommand(subcommand, |config| { - let PartialComponents { client, backend, task_manager, import_queue, .. } + 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 PartialComponents { client, task_manager, import_queue, ..} = new_partial(&config)?; - Ok((client, backend, import_queue, task_manager)) + Ok((cmd.run(client, import_queue), task_manager)) }) - } + }, + Some(Subcommand::ExportBlocks(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { client, task_manager, ..} + = new_partial(&config)?; + Ok((cmd.run(client, config.database), task_manager)) + }) + }, + Some(Subcommand::ExportState(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { client, task_manager, ..} + = new_partial(&config)?; + Ok((cmd.run(client, config.chain_spec), task_manager)) + }) + }, + Some(Subcommand::ImportBlocks(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { client, task_manager, import_queue, ..} + = new_partial(&config)?; + Ok((cmd.run(client, import_queue), task_manager)) + }) + }, + Some(Subcommand::PurgeChain(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|config| cmd.run(config.database)) + }, + Some(Subcommand::Revert(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { client, task_manager, backend, ..} + = new_partial(&config)?; + Ok((cmd.run(client, backend), task_manager)) + }) + }, None => { let runner = cli.create_runner(&cli.run)?; runner.run_node_until_exit(|config| match config.role { diff --git a/bin/node/cli/src/cli.rs b/bin/node/cli/src/cli.rs index 42a13fcb39070..2130ff1e4b106 100644 --- a/bin/node/cli/src/cli.rs +++ b/bin/node/cli/src/cli.rs @@ -33,10 +33,6 @@ pub struct Cli { /// Possible subcommands of the main binary. #[derive(Debug, StructOpt)] pub enum Subcommand { - /// A set of base subcommands handled by `sc_cli`. - #[structopt(flatten)] - Base(sc_cli::Subcommand), - /// Key management cli utilities Key(KeySubcommand), @@ -59,4 +55,25 @@ pub enum Subcommand { /// Sign a message, with a given (secret) key. Sign(SignCmd), + + /// 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), + + /// Remove the whole chain. + PurgeChain(sc_cli::PurgeChainCmd), + + /// Revert the chain to a previous state. + Revert(sc_cli::RevertCmd), } diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index 10e9413702b81..a715b2ecaa091 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -97,13 +97,53 @@ pub fn run() -> Result<()> { Some(Subcommand::Sign(cmd)) => cmd.run(), Some(Subcommand::Verify(cmd)) => cmd.run(), Some(Subcommand::Vanity(cmd)) => cmd.run(), - Some(Subcommand::Base(subcommand)) => { - let runner = cli.create_runner(subcommand)?; - runner.run_subcommand(subcommand, |config| { - let PartialComponents { client, backend, task_manager, import_queue, ..} + 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 PartialComponents { client, task_manager, import_queue, ..} = new_partial(&config)?; - Ok((client, backend, import_queue, task_manager)) + Ok((cmd.run(client, import_queue), task_manager)) }) - } + }, + Some(Subcommand::ExportBlocks(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { client, task_manager, ..} + = new_partial(&config)?; + Ok((cmd.run(client, config.database), task_manager)) + }) + }, + Some(Subcommand::ExportState(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { client, task_manager, ..} + = new_partial(&config)?; + Ok((cmd.run(client, config.chain_spec), task_manager)) + }) + }, + Some(Subcommand::ImportBlocks(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { client, task_manager, import_queue, ..} + = new_partial(&config)?; + Ok((cmd.run(client, import_queue), task_manager)) + }) + }, + Some(Subcommand::PurgeChain(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|config| cmd.run(config.database)) + }, + Some(Subcommand::Revert(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { client, task_manager, backend, ..} + = new_partial(&config)?; + Ok((cmd.run(client, backend), task_manager)) + }) + }, } } diff --git a/client/cli/src/commands/mod.rs b/client/cli/src/commands/mod.rs index 108c38b19db30..7b740d1003238 100644 --- a/client/cli/src/commands/mod.rs +++ b/client/cli/src/commands/mod.rs @@ -34,9 +34,6 @@ mod inspect; mod key; pub mod utils; -use std::fmt::Debug; -use structopt::StructOpt; - pub use self::{ build_spec_cmd::BuildSpecCmd, check_block_cmd::CheckBlockCmd, @@ -56,403 +53,3 @@ pub use self::{ revert_cmd::RevertCmd, run_cmd::RunCmd, }; - -/// All core commands that are provided by default. -/// -/// The core commands are split into multiple subcommands and `Run` is the default subcommand. From -/// the CLI user perspective, it is not visible that `Run` is a subcommand. So, all parameters of -/// `Run` are exported as main executable parameters. -#[derive(Debug, StructOpt)] -pub enum Subcommand { - /// Build a spec.json file, outputs to stdout. - BuildSpec(BuildSpecCmd), - - /// Export blocks to a file. - ExportBlocks(ExportBlocksCmd), - - /// Import blocks from file. - ImportBlocks(ImportBlocksCmd), - - /// Validate a single block. - CheckBlock(CheckBlockCmd), - - /// Export state as raw chain spec. - ExportState(ExportStateCmd), - - /// Revert chain to the previous state. - Revert(RevertCmd), - - /// Remove the whole chain data. - PurgeChain(PurgeChainCmd), -} - -/// Macro that helps implement CliConfiguration on an enum of subcommand automatically -/// -/// # Example -/// -/// ``` -/// # #[macro_use] extern crate sc_cli; -/// -/// # struct EmptyVariant {} -/// -/// # impl sc_cli::CliConfiguration for EmptyVariant { -/// # fn shared_params(&self) -> &sc_cli::SharedParams { unimplemented!() } -/// # fn chain_id(&self, _: bool) -> sc_cli::Result { Ok("test-chain-id".to_string()) } -/// # } -/// -/// # fn main() { -/// enum Subcommand { -/// Variant1(EmptyVariant), -/// Variant2(EmptyVariant), -/// } -/// -/// substrate_cli_subcommands!( -/// Subcommand => Variant1, Variant2 -/// ); -/// -/// # use sc_cli::CliConfiguration; -/// # assert_eq!(Subcommand::Variant1(EmptyVariant {}).chain_id(false).unwrap(), "test-chain-id"); -/// -/// # } -/// ``` -/// -/// Which will expand to: -/// -/// ```ignore -/// impl CliConfiguration for Subcommand { -/// fn base_path(&self) -> Result> { -/// match self { -/// Subcommand::Variant1(cmd) => cmd.base_path(), -/// Subcommand::Variant2(cmd) => cmd.base_path(), -/// } -/// } -/// -/// fn is_dev(&self) -> Result { -/// match self { -/// Subcommand::Variant1(cmd) => cmd.is_dev(), -/// Subcommand::Variant2(cmd) => cmd.is_dev(), -/// } -/// } -/// -/// // ... -/// } -/// ``` -#[macro_export] -macro_rules! substrate_cli_subcommands { - ($enum:ident => $($variant:ident),*) => { - impl $crate::CliConfiguration for $enum { - fn shared_params(&self) -> &$crate::SharedParams { - match self { - $($enum::$variant(cmd) => cmd.shared_params()),* - } - } - - fn import_params(&self) -> Option<&$crate::ImportParams> { - match self { - $($enum::$variant(cmd) => cmd.import_params()),* - } - } - - fn pruning_params(&self) -> Option<&$crate::PruningParams> { - match self { - $($enum::$variant(cmd) => cmd.pruning_params()),* - } - } - - fn keystore_params(&self) -> Option<&$crate::KeystoreParams> { - match self { - $($enum::$variant(cmd) => cmd.keystore_params()),* - } - } - - fn network_params(&self) -> Option<&$crate::NetworkParams> { - match self { - $($enum::$variant(cmd) => cmd.network_params()),* - } - } - - fn offchain_worker_params(&self) -> Option<&$crate::OffchainWorkerParams> { - match self { - $($enum::$variant(cmd) => cmd.offchain_worker_params()),* - } - } - - fn database_params(&self) -> Option<&$crate::DatabaseParams> { - match self { - $($enum::$variant(cmd) => cmd.database_params()),* - } - } - - fn base_path(&self) -> $crate::Result<::std::option::Option> { - match self { - $($enum::$variant(cmd) => cmd.base_path()),* - } - } - - fn is_dev(&self) -> $crate::Result { - match self { - $($enum::$variant(cmd) => cmd.is_dev()),* - } - } - - fn role(&self, is_dev: bool) -> $crate::Result<::sc_service::Role> { - match self { - $($enum::$variant(cmd) => cmd.role(is_dev)),* - } - } - - fn transaction_pool(&self) - -> $crate::Result<::sc_service::config::TransactionPoolOptions> { - match self { - $($enum::$variant(cmd) => cmd.transaction_pool()),* - } - } - - fn network_config( - &self, - chain_spec: &std::boxed::Box, - is_dev: bool, - net_config_dir: std::path::PathBuf, - client_id: &str, - node_name: &str, - node_key: sc_service::config::NodeKeyConfig, - default_listen_port: u16, - ) -> $crate::Result<::sc_service::config::NetworkConfiguration> { - match self { - $( - $enum::$variant(cmd) => cmd.network_config( - chain_spec, - is_dev, - net_config_dir, - client_id, - node_name, - node_key, - default_listen_port, - ) - ),* - } - } - - fn keystore_config(&self, base_path: &::std::path::PathBuf) - -> $crate::Result<::sc_service::config::KeystoreConfig> { - match self { - $($enum::$variant(cmd) => cmd.keystore_config(base_path)),* - } - } - - fn database_cache_size(&self) -> $crate::Result<::std::option::Option> { - match self { - $($enum::$variant(cmd) => cmd.database_cache_size()),* - } - } - - fn database_config( - &self, - base_path: &::std::path::PathBuf, - cache_size: usize, - database: $crate::Database, - ) -> $crate::Result<::sc_service::config::DatabaseConfig> { - match self { - $($enum::$variant(cmd) => cmd.database_config(base_path, cache_size, database)),* - } - } - - fn database(&self) -> $crate::Result<::std::option::Option<$crate::Database>> { - match self { - $($enum::$variant(cmd) => cmd.database()),* - } - } - - fn state_cache_size(&self) -> $crate::Result { - match self { - $($enum::$variant(cmd) => cmd.state_cache_size()),* - } - } - - fn state_cache_child_ratio(&self) -> $crate::Result<::std::option::Option> { - match self { - $($enum::$variant(cmd) => cmd.state_cache_child_ratio()),* - } - } - - fn pruning(&self, unsafe_pruning: bool, role: &::sc_service::Role) - -> $crate::Result<::sc_service::config::PruningMode> { - match self { - $($enum::$variant(cmd) => cmd.pruning(unsafe_pruning, role)),* - } - } - - fn chain_id(&self, is_dev: bool) -> $crate::Result { - match self { - $($enum::$variant(cmd) => cmd.chain_id(is_dev)),* - } - } - - fn init(&self) -> $crate::Result<()> { - match self { - $($enum::$variant(cmd) => cmd.init::()),* - } - } - - fn node_name(&self) -> $crate::Result { - match self { - $($enum::$variant(cmd) => cmd.node_name()),* - } - } - - fn wasm_method(&self) -> $crate::Result<::sc_service::config::WasmExecutionMethod> { - match self { - $($enum::$variant(cmd) => cmd.wasm_method()),* - } - } - - fn execution_strategies(&self, is_dev: bool, is_validator: bool) - -> $crate::Result<::sc_client_api::execution_extensions::ExecutionStrategies> { - match self { - $($enum::$variant(cmd) => cmd.execution_strategies(is_dev, is_validator)),* - } - } - - fn rpc_ipc(&self) -> $crate::Result<::std::option::Option<::std::string::String>> { - match self { - $($enum::$variant(cmd) => cmd.rpc_ipc()),* - } - } - - fn rpc_http( - &self, - default_listen_port: u16, - ) -> $crate::Result> { - match self { - $($enum::$variant(cmd) => cmd.rpc_http(default_listen_port)),* - } - } - - fn rpc_ws( - &self, - default_listen_port: u16, - ) -> $crate::Result> { - match self { - $($enum::$variant(cmd) => cmd.rpc_ws(default_listen_port)),* - } - } - - fn rpc_methods(&self) -> $crate::Result { - match self { - $($enum::$variant(cmd) => cmd.rpc_methods()),* - } - } - - fn rpc_ws_max_connections(&self) -> $crate::Result<::std::option::Option> { - match self { - $($enum::$variant(cmd) => cmd.rpc_ws_max_connections()),* - } - } - - fn rpc_cors(&self, is_dev: bool) - -> $crate::Result>> { - match self { - $($enum::$variant(cmd) => cmd.rpc_cors(is_dev)),* - } - } - - fn prometheus_config(&self, default_listen_port: u16) - -> $crate::Result> { - match self { - $($enum::$variant(cmd) => cmd.prometheus_config(default_listen_port)),* - } - } - - fn telemetry_endpoints( - &self, - chain_spec: &Box, - ) -> $crate::Result> { - match self { - $($enum::$variant(cmd) => cmd.telemetry_endpoints(chain_spec)),* - } - } - - fn telemetry_external_transport(&self) - -> $crate::Result<::std::option::Option<::sc_service::config::ExtTransport>> { - match self { - $($enum::$variant(cmd) => cmd.telemetry_external_transport()),* - } - } - - fn default_heap_pages(&self) -> $crate::Result<::std::option::Option> { - match self { - $($enum::$variant(cmd) => cmd.default_heap_pages()),* - } - } - - fn offchain_worker( - &self, - role: &::sc_service::Role, - ) -> $crate::Result<::sc_service::config::OffchainWorkerConfig> { - match self { - $($enum::$variant(cmd) => cmd.offchain_worker(role)),* - } - } - - fn force_authoring(&self) -> $crate::Result { - match self { - $($enum::$variant(cmd) => cmd.force_authoring()),* - } - } - - fn disable_grandpa(&self) -> $crate::Result { - match self { - $($enum::$variant(cmd) => cmd.disable_grandpa()),* - } - } - - fn dev_key_seed(&self, is_dev: bool) -> $crate::Result<::std::option::Option> { - match self { - $($enum::$variant(cmd) => cmd.dev_key_seed(is_dev)),* - } - } - - fn tracing_targets(&self) -> $crate::Result<::std::option::Option> { - match self { - $($enum::$variant(cmd) => cmd.tracing_targets()),* - } - } - - fn tracing_receiver(&self) -> $crate::Result<::sc_service::TracingReceiver> { - match self { - $($enum::$variant(cmd) => cmd.tracing_receiver()),* - } - } - - fn node_key(&self, net_config_dir: &::std::path::PathBuf) - -> $crate::Result<::sc_service::config::NodeKeyConfig> { - match self { - $($enum::$variant(cmd) => cmd.node_key(net_config_dir)),* - } - } - - fn max_runtime_instances(&self) -> $crate::Result<::std::option::Option> { - match self { - $($enum::$variant(cmd) => cmd.max_runtime_instances()),* - } - } - - fn log_filters(&self) -> $crate::Result { - match self { - $($enum::$variant(cmd) => cmd.log_filters()),* - } - } - } - } -} - -substrate_cli_subcommands!( - Subcommand => - BuildSpec, - ExportBlocks, - ExportState, - ImportBlocks, - CheckBlock, - Revert, - PurgeChain -); diff --git a/client/cli/src/runner.rs b/client/cli/src/runner.rs index f2558b1bb6070..64bd88d63130b 100644 --- a/client/cli/src/runner.rs +++ b/client/cli/src/runner.rs @@ -18,7 +18,6 @@ use crate::CliConfiguration; use crate::Result; -use crate::Subcommand; use crate::SubstrateCli; use chrono::prelude::*; use futures::pin_mut; @@ -26,10 +25,8 @@ use futures::select; use futures::{future, future::FutureExt, Future}; use log::info; use sc_service::{Configuration, TaskType, TaskManager}; -use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use sp_utils::metrics::{TOKIO_THREADS_ALIVE, TOKIO_THREADS_TOTAL}; -use std::{fmt::Debug, marker::PhantomData, str::FromStr, sync::Arc}; -use sc_client_api::{UsageProvider, BlockBackend, StorageProvider}; +use std::marker::PhantomData; #[cfg(target_family = "unix")] async fn main(func: F) -> std::result::Result<(), Box> @@ -173,52 +170,6 @@ impl Runner { info!("⛓ Native runtime: {}", C::native_runtime_version(&self.config.chain_spec)); } - /// A helper function that runs a future with tokio and stops if the process receives the signal - /// `SIGTERM` or `SIGINT`. - pub fn run_subcommand(self, subcommand: &Subcommand, builder: BU) - -> Result<()> - where - BU: FnOnce(Configuration) - -> sc_service::error::Result<(Arc, Arc, IQ, TaskManager)>, - B: BlockT + for<'de> serde::Deserialize<'de>, - BA: sc_client_api::backend::Backend + 'static, - IQ: sc_service::ImportQueue + 'static, - ::Hash: FromStr, - <::Hash as FromStr>::Err: Debug, - <<::Header as HeaderT>::Number as FromStr>::Err: Debug, - CL: UsageProvider + BlockBackend + StorageProvider + Send + Sync + - 'static, - { - let chain_spec = self.config.chain_spec.cloned_box(); - let network_config = self.config.network.clone(); - let db_config = self.config.database.clone(); - - match subcommand { - Subcommand::BuildSpec(cmd) => cmd.run(chain_spec, network_config), - Subcommand::ExportBlocks(cmd) => { - let (client, _, _, task_manager) = builder(self.config)?; - run_until_exit(self.tokio_runtime, cmd.run(client, db_config), task_manager) - } - Subcommand::ImportBlocks(cmd) => { - let (client, _, import_queue, task_manager) = builder(self.config)?; - run_until_exit(self.tokio_runtime, cmd.run(client, import_queue), task_manager) - } - Subcommand::CheckBlock(cmd) => { - let (client, _, import_queue, task_manager) = builder(self.config)?; - run_until_exit(self.tokio_runtime, cmd.run(client, import_queue), task_manager) - } - Subcommand::Revert(cmd) => { - let (client, backend, _, task_manager) = builder(self.config)?; - run_until_exit(self.tokio_runtime, cmd.run(client, backend), task_manager) - }, - Subcommand::PurgeChain(cmd) => cmd.run(db_config), - Subcommand::ExportState(cmd) => { - let (client, _, _, task_manager) = builder(self.config)?; - run_until_exit(self.tokio_runtime, cmd.run(client, chain_spec), task_manager) - }, - } - } - /// A helper function that runs a node with tokio and stops if the process receives the signal /// `SIGTERM` or `SIGINT`. pub fn run_node_until_exit(