CLI: refactoring: remove Options from sc_service::Configuration's fields (#5271)

* WIP

Forked at: d6aa8e954c
Parent branch: origin/master

* Rename IntoConfiguration to CliConfiguration

* Renamed into_configuration to create_configuration

* WIP

Forked at: d6aa8e954c
Parent branch: origin/master

* WIP

Forked at: d6aa8e954c
Parent branch: origin/master

* Move keystore params to its own module

* Use in-memory keystore even for build-spec

* Enforce proper value for node name

* dev_key_seed

* Telemetry endpoints

* rustfmt

* Converted all RunCmd

* rustfmt

* Added export-blocks

* Missed something

* Removed config_path in NetworkConfiguration (not used)

* Fixed warnings

* public_addresses is used but never set, keeping it

* Merge Configuration.node and NetworkConfiguration.node_name

...because they are the same thing

* Added: import-blocks

* Adding a proc_macro to help impl SubstrateCli

* WIP

Forked at: d6aa8e954c
Parent branch: origin/master

* WIP

Forked at: d6aa8e954c
Parent branch: origin/master

* WIP

Forked at: d6aa8e954c
Parent branch: origin/master

* Re-export spec_factory from sc_cli

* Re-added all the commands

* Refactored node_key_params

* Fixed previous refucktoring

* Clean-up and removed full_version()

* Renamed get_is_dev to not confuse with Configuration field

* Fixed sc-cli-derive example

* Fixing tests

* Fixing tests and removing some (will re-add later)

* Fixing more tests

* Removes the need of type parameter

* Converting bin/node and simplifying API

* Converting more

* Converting last command

* WIP

Forked at: d6aa8e954c
Parent branch: origin/master

* Fixing tests and added default for WasmExecutionMethod

* Fixing stuff

* Fixed something I broke oops

* Update Cargo.lock

* Moving things around

* Convert everything to Result

* Added new macros to simplify the impl of CliConfiguration

* Added a macro to generate CliConfiguration automatically for subcommands

* Revert... too many macros (this one is not really useful)

This reverts commit 9c516dd38b40fbc420b02c1f8e61d5b2b1a4e434.

* Renamed is_dev to get_is_dev

Good enough for now

* Fixed name roles (this is plural, not singular)

* Clean-up

* Re-export NodeKeyConfig and TelemetryEndpoints from sc_service

* Improve styling/formatting

* Added copyrights

* Added doc and fixed warnings

* Added myself to code owners

* Yes it is needed according to the history

* Revert formatting

* Fixing conflict

* Updated build.rs

* Cargo.lock

* Clean-up

* Update client/cli-derive/Cargo.toml

Co-Authored-By: Seun Lanlege <seunlanlege@gmail.com>

* Fail if using proc_macro and build.rs is not set properly

* Dropped all get_ in front of methods

* Clean-up

* Fixing proc macro missing env var

* Get the configuration inside the Runtime (needed for polkadot)

* Clean-up

* Get is_dev from argument like the others

* Get chain ID instead of chain spec from shared params

* &self is passed to spec_factory/load_spec

* Wrong text

* Fix example

* Officialize macro and made a cool doc

* Renamed spec_factory to load_spec (substrate_cli_configuration)

* Removed not so useful ChainSpec

* Renamed SubstrateCLI to SubstrateCli

* Added changelog for impl_version being full now

* Renamed Runtime to Runner

* Update changelog to show example

* Removed option on database cache size

* WIP

Forked at: d6aa8e954c
Parent branch: origin/master

* Fix on removal of option

* typo

* Clean-up imports

* Added info in Cargo.toml

* typo

* remarks

* Moved function for build.rs to substrate-build-script-utils

* Fixed example & test of cli-derive

* Moved function for build.rs to substrate-build-script-utils

* Renamed substrate_cli_configuration to substrate_cli oops

It implements SubstrateCli not CliConfiguration!

* Added documentation and wrapper macro

* Removed option on database cache size

* Removed option on database cache size

* Clean-up

* Reduce risk of errors due to typos

* Removed option on database cache size

* Added NOTE as suggested

* Added doc as suggested

* Fixed test

* typo

* renamed runtime to runner

* Fixed weird argument

* More commas

* Moved client/cli-derive to client/cli/derive

* Added 7 tests for the macros

* Improve error message

* Upgrade assert_cmd

* Fixing missing stuff

* Fixed unused import

* Improve SubstrateCli doc

* Applied suggestions

* Fix and clean-up imports

* Started replacing macros WIP

* WIP

Forked at: d6aa8e954c
Parent branch: origin/master

* WIP

Forked at: d6aa8e954c
Parent branch: origin/master

* WIP

Forked at: d6aa8e954c
Parent branch: origin/master

* Started removing substrate_cli

* WIP

Forked at: d6aa8e954c
Parent branch: origin/master

* WIP

Forked at: d6aa8e954c
Parent branch: origin/master

* WIP

Forked at: d6aa8e954c
Parent branch: origin/master

* fixed bug introduced while refactoring

* Renamed NetworkConfigurationParams to NetworkParams for consistency sake

* Fixed test

* Update client/cli/src/commands/runcmd.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/cli/src/commands/runcmd.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/cli/src/commands/export_blocks_cmd.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/cli/src/commands/check_block_cmd.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update bin/node/cli/src/command.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update bin/node/cli/src/command.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/cli/src/commands/export_blocks_cmd.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Revert "Update client/cli/src/commands/export_blocks_cmd.rs"

This reverts commit 5906776953392c02beac6bc0bf50f8cbe1a12a01.

* Revert "Update client/cli/src/commands/check_block_cmd.rs"

This reverts commit f705f42b7f3d732be001141afee210fe46a1ef47.

* Revert "Update client/cli/src/commands/export_blocks_cmd.rs"

This reverts commit 8d57c0550164449e6eb2d3bacb04c750c714fcea.

* Revert "Update client/cli/src/commands/runcmd.rs"

This reverts commit 93e74cf5d2e1c0dc49cdff8608d59fc40fc59338.

* Revert "Update client/cli/src/commands/runcmd.rs"

This reverts commit 11d527ba345c0d79f0d3b5b071933d95474d0614.

* Update client/cli/src/commands/export_blocks_cmd.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/cli/src/commands/import_blocks_cmd.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/cli/src/commands/purge_chain_cmd.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Changed ::sc_cli to $crate in the macro

* fixed tests

* fixed conflicts

* Fixing test

* Update client/cli/src/commands/purge_chain_cmd.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/cli/src/params/pruning_params.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Remove comment as suggested

* Apply suggestion

* Update client/cli/src/commands/purge_chain_cmd.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/cli/src/commands/purge_chain_cmd.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/cli/src/commands/purge_chain_cmd.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update utils/frame/benchmarking-cli/src/command.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/cli/src/runner.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/cli/src/runner.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/cli/src/runner.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/cli/src/params/pruning_params.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/cli/src/params/node_key_params.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/cli/src/params/network_params.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/cli/src/lib.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/cli/src/config.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Added doc

* Fixed error introduced after applying suggestion

* Revert "Update client/cli/src/params/pruning_params.rs"

This reverts commit 0574d06a4f1efd86e94c1214420a12e7a4be0099.

* Print error

* Apply suggestions from code review

* Remove useless Results

* Fixed CI failing on polkadot approval

Co-authored-by: Seun Lanlege <seunlanlege@gmail.com>
Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
Cecile Tonglet
2020-04-07 11:38:07 +02:00
committed by GitHub
parent fb9bbf306d
commit 3da069e359
66 changed files with 2916 additions and 2156 deletions
@@ -14,15 +14,14 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use structopt::StructOpt;
use log::info;
use sc_network::config::{build_multiaddr, MultiaddrWithPeerId};
use sc_service::{Configuration, ChainSpec};
use crate::error;
use crate::VersionInfo;
use crate::params::SharedParams;
use crate::params::NodeKeyParams;
use crate::params::SharedParams;
use crate::CliConfiguration;
use log::info;
use sc_network::config::build_multiaddr;
use sc_service::{config::MultiaddrWithPeerId, Configuration};
use structopt::StructOpt;
/// The `build-spec` command used to build a specification.
#[derive(Debug, StructOpt, Clone)]
@@ -49,12 +48,9 @@ pub struct BuildSpecCmd {
impl BuildSpecCmd {
/// Run the build-spec command
pub fn run(
self,
config: Configuration,
) -> error::Result<()> {
pub fn run(&self, config: Configuration) -> error::Result<()> {
info!("Building chain spec");
let mut spec = config.chain_spec.expect("`chain_spec` is set to `Some` in `update_config`");
let mut spec = config.chain_spec;
let raw_output = self.raw;
if spec.boot_nodes().is_empty() && !self.disable_default_bootnode {
@@ -73,25 +69,14 @@ impl BuildSpecCmd {
Ok(())
}
/// Update and prepare a `Configuration` with command line parameters
pub fn update_config<F>(
&self,
mut config: &mut Configuration,
spec_factory: F,
version: &VersionInfo,
) -> error::Result<()> where
F: FnOnce(&str) -> Result<Box<dyn ChainSpec>, String>,
{
self.shared_params.update_config(&mut config, spec_factory, version)?;
let net_config_path = config
.in_chain_config_dir(crate::commands::DEFAULT_NETWORK_CONFIG_PATH)
.expect("We provided a base_path");
self.node_key_params.update_config(&mut config, Some(&net_config_path))?;
Ok(())
}
}
impl CliConfiguration for BuildSpecCmd {
fn shared_params(&self) -> &SharedParams {
&self.shared_params
}
fn node_key_params(&self) -> Option<&NodeKeyParams> {
Some(&self.node_key_params)
}
}
@@ -14,20 +14,16 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use crate::error;
use crate::params::ImportParams;
use crate::params::SharedParams;
use crate::CliConfiguration;
use sc_service::{Configuration, ServiceBuilderCommand};
use sp_runtime::generic::BlockId;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use std::fmt::Debug;
use std::str::FromStr;
use structopt::StructOpt;
use sc_service::{
Configuration, ServiceBuilderCommand, Role, ChainSpec,
};
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use sp_runtime::generic::BlockId;
use crate::error;
use crate::VersionInfo;
use crate::runtime::run_until_exit;
use crate::params::SharedParams;
use crate::params::ImportParams;
/// The `check-block` command used to validate blocks.
#[derive(Debug, StructOpt, Clone)]
@@ -53,8 +49,8 @@ pub struct CheckBlockCmd {
impl CheckBlockCmd {
/// Run the check-block command
pub fn run<B, BC, BB>(
self,
pub async fn run<B, BC, BB>(
&self,
config: Configuration,
builder: B,
) -> error::Result<()>
@@ -65,37 +61,37 @@ impl CheckBlockCmd {
<<<BB as BlockT>::Header as HeaderT>::Number as std::str::FromStr>::Err: std::fmt::Debug,
<BB as BlockT>::Hash: std::str::FromStr,
{
let input = if self.input.starts_with("0x") { &self.input[2..] } else { &self.input[..] };
let input = if self.input.starts_with("0x") {
&self.input[2..]
} else {
&self.input[..]
};
let block_id = match FromStr::from_str(input) {
Ok(hash) => BlockId::hash(hash),
Err(_) => match self.input.parse::<u32>() {
Ok(n) => BlockId::number((n as u32).into()),
Err(_) => return Err(error::Error::Input("Invalid hash or number specified".into())),
}
Err(_) => {
return Err(error::Error::Input(
"Invalid hash or number specified".into(),
))
}
},
};
let start = std::time::Instant::now();
run_until_exit(config, |config| {
Ok(builder(config)?.check_block(block_id))
})?;
builder(config)?.check_block(block_id).await?;
println!("Completed in {} ms.", start.elapsed().as_millis());
Ok(())
}
}
/// Update and prepare a `Configuration` with command line parameters
pub fn update_config<F>(
&self,
mut config: &mut Configuration,
spec_factory: F,
version: &VersionInfo,
) -> error::Result<()> where
F: FnOnce(&str) -> Result<Box<dyn ChainSpec>, String>,
{
self.shared_params.update_config(&mut config, spec_factory, version)?;
self.import_params.update_config(&mut config, &Role::Full, self.shared_params.dev)?;
config.use_in_memory_keystore()?;
impl CliConfiguration for CheckBlockCmd {
fn shared_params(&self) -> &SharedParams {
&self.shared_params
}
Ok(())
fn import_params(&self) -> Option<&ImportParams> {
Some(&self.import_params)
}
}
@@ -14,22 +14,19 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use std::io;
use std::fs;
use std::path::PathBuf;
use std::fmt::Debug;
use crate::error;
use crate::params::{BlockNumber, PruningParams, SharedParams};
use crate::CliConfiguration;
use log::info;
use structopt::StructOpt;
use sc_service::{
Configuration, ServiceBuilderCommand, ChainSpec,
config::DatabaseConfig, Role,
config::DatabaseConfig, Configuration, ServiceBuilderCommand,
};
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use crate::error;
use crate::VersionInfo;
use crate::runtime::run_until_exit;
use crate::params::{SharedParams, BlockNumber, PruningParams};
use std::fmt::Debug;
use std::fs;
use std::io;
use std::path::PathBuf;
use structopt::StructOpt;
/// The `export-blocks` command used to export blocks.
#[derive(Debug, StructOpt, Clone)]
@@ -65,8 +62,8 @@ pub struct ExportBlocksCmd {
impl ExportBlocksCmd {
/// Run the export-blocks command
pub fn run<B, BC, BB>(
self,
pub async fn run<B, BC, BB>(
&self,
config: Configuration,
builder: B,
) -> error::Result<()>
@@ -77,9 +74,10 @@ impl ExportBlocksCmd {
<<<BB as BlockT>::Header as HeaderT>::Number as std::str::FromStr>::Err: std::fmt::Debug,
<BB as BlockT>::Hash: std::str::FromStr,
{
if let DatabaseConfig::Path { ref path, .. } = config.expect_database() {
if let DatabaseConfig::Path { ref path, .. } = &config.database {
info!("DB path: {}", path.display());
}
let from = self.from.as_ref().and_then(|f| f.parse().ok()).unwrap_or(1);
let to = self.to.as_ref().and_then(|t| t.parse().ok());
@@ -90,24 +88,19 @@ impl ExportBlocksCmd {
None => Box::new(io::stdout()),
};
run_until_exit(config, |config| {
Ok(builder(config)?.export_blocks(file, from.into(), to, binary))
})
}
/// Update and prepare a `Configuration` with command line parameters
pub fn update_config<F>(
&self,
mut config: &mut Configuration,
spec_factory: F,
version: &VersionInfo,
) -> error::Result<()> where
F: FnOnce(&str) -> Result<Box<dyn ChainSpec>, String>,
{
self.shared_params.update_config(&mut config, spec_factory, version)?;
self.pruning_params.update_config(&mut config, &Role::Full, true)?;
config.use_in_memory_keystore()?;
Ok(())
builder(config)?
.export_blocks(file, from.into(), to, binary)
.await
.map_err(Into::into)
}
}
impl CliConfiguration for ExportBlocksCmd {
fn shared_params(&self) -> &SharedParams {
&self.shared_params
}
fn pruning_params(&self) -> Option<&PruningParams> {
Some(&self.pruning_params)
}
}
@@ -14,21 +14,17 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use crate::error;
use crate::params::ImportParams;
use crate::params::SharedParams;
use crate::CliConfiguration;
use sc_service::{Configuration, ServiceBuilderCommand};
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use std::fmt::Debug;
use std::io::{Read, Seek, self};
use std::fs;
use std::io::{self, Read, Seek};
use std::path::PathBuf;
use structopt::StructOpt;
use sc_service::{
Configuration, ServiceBuilderCommand, ChainSpec, Role,
};
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use crate::error;
use crate::VersionInfo;
use crate::runtime::run_until_exit;
use crate::params::SharedParams;
use crate::params::ImportParams;
/// The `import-blocks` command used to import blocks.
#[derive(Debug, StructOpt, Clone)]
@@ -59,8 +55,8 @@ impl<T: Read + Seek> ReadPlusSeek for T {}
impl ImportBlocksCmd {
/// Run the import-blocks command
pub fn run<B, BC, BB>(
self,
pub async fn run<B, BC, BB>(
&self,
config: Configuration,
builder: B,
) -> error::Result<()>
@@ -77,27 +73,22 @@ impl ImportBlocksCmd {
let mut buffer = Vec::new();
io::stdin().read_to_end(&mut buffer)?;
Box::new(io::Cursor::new(buffer))
},
}
};
run_until_exit(config, |config| {
Ok(builder(config)?.import_blocks(file, false))
})
}
/// Update and prepare a `Configuration` with command line parameters
pub fn update_config<F>(
&self,
mut config: &mut Configuration,
spec_factory: F,
version: &VersionInfo,
) -> error::Result<()> where
F: FnOnce(&str) -> Result<Box<dyn ChainSpec>, String>,
{
self.shared_params.update_config(&mut config, spec_factory, version)?;
self.import_params.update_config(&mut config, &Role::Full, self.shared_params.dev)?;
config.use_in_memory_keystore()?;
Ok(())
builder(config)?
.import_blocks(file, false)
.await
.map_err(Into::into)
}
}
impl CliConfiguration for ImportBlocksCmd {
fn shared_params(&self) -> &SharedParams {
&self.shared_params
}
fn import_params(&self) -> Option<&ImportParams> {
Some(&self.import_params)
}
}
+330 -92
View File
@@ -14,35 +14,24 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
mod runcmd;
mod export_blocks_cmd;
mod build_spec_cmd;
mod import_blocks_cmd;
mod check_block_cmd;
mod revert_cmd;
mod export_blocks_cmd;
mod import_blocks_cmd;
mod purge_chain_cmd;
mod revert_cmd;
mod runcmd;
pub use crate::commands::build_spec_cmd::BuildSpecCmd;
pub use crate::commands::check_block_cmd::CheckBlockCmd;
pub use crate::commands::export_blocks_cmd::ExportBlocksCmd;
pub use crate::commands::import_blocks_cmd::ImportBlocksCmd;
pub use crate::commands::purge_chain_cmd::PurgeChainCmd;
pub use crate::commands::revert_cmd::RevertCmd;
pub use crate::commands::runcmd::RunCmd;
use std::fmt::Debug;
use structopt::StructOpt;
use sc_service::{ Configuration, ServiceBuilderCommand, ChainSpec };
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use crate::error;
use crate::VersionInfo;
use crate::params::SharedParams;
pub use crate::commands::runcmd::RunCmd;
pub use crate::commands::export_blocks_cmd::ExportBlocksCmd;
pub use crate::commands::build_spec_cmd::BuildSpecCmd;
pub use crate::commands::import_blocks_cmd::ImportBlocksCmd;
pub use crate::commands::check_block_cmd::CheckBlockCmd;
pub use crate::commands::revert_cmd::RevertCmd;
pub use crate::commands::purge_chain_cmd::PurgeChainCmd;
/// default sub directory to store network config
const DEFAULT_NETWORK_CONFIG_PATH : &'static str = "network";
/// All core commands that are provided by default.
///
/// The core commands are split into multiple subcommands and `Run` is the default subcommand. From
@@ -51,89 +40,338 @@ const DEFAULT_NETWORK_CONFIG_PATH : &'static str = "network";
#[derive(Debug, Clone, StructOpt)]
pub enum Subcommand {
/// Build a spec.json file, outputs to stdout.
BuildSpec(build_spec_cmd::BuildSpecCmd),
BuildSpec(BuildSpecCmd),
/// Export blocks to a file.
ExportBlocks(export_blocks_cmd::ExportBlocksCmd),
ExportBlocks(ExportBlocksCmd),
/// Import blocks from file.
ImportBlocks(import_blocks_cmd::ImportBlocksCmd),
ImportBlocks(ImportBlocksCmd),
/// Validate a single block.
CheckBlock(check_block_cmd::CheckBlockCmd),
CheckBlock(CheckBlockCmd),
/// Revert chain to the previous state.
Revert(revert_cmd::RevertCmd),
Revert(RevertCmd),
/// Remove the whole chain data.
PurgeChain(purge_chain_cmd::PurgeChainCmd),
PurgeChain(PurgeChainCmd),
}
impl Subcommand {
/// Get the shared parameters of a `CoreParams` command.
pub fn get_shared_params(&self) -> &SharedParams {
use Subcommand::*;
// TODO: move to config.rs?
/// 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<String> { 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<Option<PathBuf>> {
/// match self {
/// Subcommand::Variant1(cmd) => cmd.base_path(),
/// Subcommand::Variant2(cmd) => cmd.base_path(),
/// }
/// }
///
/// fn is_dev(&self) -> Result<bool> {
/// 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()),*
}
}
match self {
BuildSpec(params) => &params.shared_params,
ExportBlocks(params) => &params.shared_params,
ImportBlocks(params) => &params.shared_params,
CheckBlock(params) => &params.shared_params,
Revert(params) => &params.shared_params,
PurgeChain(params) => &params.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 base_path(&self) -> $crate::Result<::std::option::Option<::std::path::PathBuf>> {
match self {
$($enum::$variant(cmd) => cmd.base_path()),*
}
}
fn is_dev(&self) -> $crate::Result<bool> {
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<dyn ::sc_service::ChainSpec>,
is_dev: bool,
net_config_dir: &::std::path::PathBuf,
client_id: &str,
node_name: &str,
node_key: ::sc_service::config::NodeKeyConfig,
) -> $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
)
),*
}
}
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<usize>> {
match self {
$($enum::$variant(cmd) => cmd.database_cache_size()),*
}
}
fn database_config(
&self,
base_path: &::std::path::PathBuf,
cache_size: usize,
) -> $crate::Result<::sc_service::config::DatabaseConfig> {
match self {
$($enum::$variant(cmd) => cmd.database_config(base_path, cache_size)),*
}
}
fn state_cache_size(&self) -> $crate::Result<usize> {
match self {
$($enum::$variant(cmd) => cmd.state_cache_size()),*
}
}
fn state_cache_child_ratio(&self) -> $crate::Result<::std::option::Option<usize>> {
match self {
$($enum::$variant(cmd) => cmd.state_cache_child_ratio()),*
}
}
fn pruning(&self, is_dev: bool, role: &::sc_service::Role)
-> $crate::Result<::sc_service::config::PruningMode> {
match self {
$($enum::$variant(cmd) => cmd.pruning(is_dev, role)),*
}
}
fn chain_id(&self, is_dev: bool) -> $crate::Result<String> {
match self {
$($enum::$variant(cmd) => cmd.chain_id(is_dev)),*
}
}
fn init<C: $crate::SubstrateCli>(&self) -> $crate::Result<()> {
match self {
$($enum::$variant(cmd) => cmd.init::<C>()),*
}
}
fn node_name(&self) -> $crate::Result<String> {
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)
-> $crate::Result<::sc_service::config::ExecutionStrategies> {
match self {
$($enum::$variant(cmd) => cmd.execution_strategies(is_dev)),*
}
}
fn rpc_http(&self) -> $crate::Result<::std::option::Option<::std::net::SocketAddr>> {
match self {
$($enum::$variant(cmd) => cmd.rpc_http()),*
}
}
fn rpc_ws(&self) -> $crate::Result<::std::option::Option<::std::net::SocketAddr>> {
match self {
$($enum::$variant(cmd) => cmd.rpc_ws()),*
}
}
fn rpc_ws_max_connections(&self) -> $crate::Result<::std::option::Option<usize>> {
match self {
$($enum::$variant(cmd) => cmd.rpc_ws_max_connections()),*
}
}
fn rpc_cors(&self, is_dev: bool)
-> $crate::Result<::std::option::Option<::std::vec::Vec<String>>> {
match self {
$($enum::$variant(cmd) => cmd.rpc_cors(is_dev)),*
}
}
fn prometheus_config(&self)
-> $crate::Result<::std::option::Option<::sc_service::config::PrometheusConfig>> {
match self {
$($enum::$variant(cmd) => cmd.prometheus_config()),*
}
}
fn telemetry_endpoints(
&self,
chain_spec: &Box<dyn ::sc_service::ChainSpec>,
) -> $crate::Result<::std::option::Option<::sc_service::config::TelemetryEndpoints>> {
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<u64>> {
match self {
$($enum::$variant(cmd) => cmd.default_heap_pages()),*
}
}
fn offchain_worker(&self, role: &::sc_service::Role) -> $crate::Result<bool> {
match self {
$($enum::$variant(cmd) => cmd.offchain_worker(role)),*
}
}
fn force_authoring(&self) -> $crate::Result<bool> {
match self {
$($enum::$variant(cmd) => cmd.force_authoring()),*
}
}
fn disable_grandpa(&self) -> $crate::Result<bool> {
match self {
$($enum::$variant(cmd) => cmd.disable_grandpa()),*
}
}
fn dev_key_seed(&self, is_dev: bool) -> $crate::Result<::std::option::Option<String>> {
match self {
$($enum::$variant(cmd) => cmd.dev_key_seed(is_dev)),*
}
}
fn tracing_targets(&self) -> $crate::Result<::std::option::Option<String>> {
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<usize>> {
match self {
$($enum::$variant(cmd) => cmd.max_runtime_instances()),*
}
}
fn log_filters(&self) -> $crate::Result<::std::option::Option<String>> {
match self {
$($enum::$variant(cmd) => cmd.log_filters()),*
}
}
}
}
/// Run any `CoreParams` command.
pub fn run<B, BC, BB>(
self,
config: Configuration,
builder: B,
) -> error::Result<()>
where
B: FnOnce(Configuration) -> Result<BC, sc_service::error::Error>,
BC: ServiceBuilderCommand<Block = BB> + Unpin,
BB: sp_runtime::traits::Block + Debug,
<<<BB as BlockT>::Header as HeaderT>::Number as std::str::FromStr>::Err: std::fmt::Debug,
<BB as BlockT>::Hash: std::str::FromStr,
{
match self {
Subcommand::BuildSpec(cmd) => cmd.run(config),
Subcommand::ExportBlocks(cmd) => cmd.run(config, builder),
Subcommand::ImportBlocks(cmd) => cmd.run(config, builder),
Subcommand::CheckBlock(cmd) => cmd.run(config, builder),
Subcommand::PurgeChain(cmd) => cmd.run(config),
Subcommand::Revert(cmd) => cmd.run(config, builder),
}
}
/// Update and prepare a `Configuration` with command line parameters.
pub fn update_config<F>(
&self,
mut config: &mut Configuration,
spec_factory: F,
version: &VersionInfo,
) -> error::Result<()> where
F: FnOnce(&str) -> Result<Box<dyn ChainSpec>, String>,
{
match self {
Subcommand::BuildSpec(cmd) => cmd.update_config(&mut config, spec_factory, version),
Subcommand::ExportBlocks(cmd) => cmd.update_config(&mut config, spec_factory, version),
Subcommand::ImportBlocks(cmd) => cmd.update_config(&mut config, spec_factory, version),
Subcommand::CheckBlock(cmd) => cmd.update_config(&mut config, spec_factory, version),
Subcommand::PurgeChain(cmd) => cmd.update_config(&mut config, spec_factory, version),
Subcommand::Revert(cmd) => cmd.update_config(&mut config, spec_factory, version),
}
}
/// Initialize substrate. This must be done only once.
///
/// This method:
///
/// 1. Set the panic handler
/// 2. Raise the FD limit
/// 3. Initialize the logger
pub fn init(&self, version: &VersionInfo) -> error::Result<()> {
self.get_shared_params().init(version)
}
}
substrate_cli_subcommands!(
Subcommand => BuildSpec, ExportBlocks, ImportBlocks, CheckBlock, Revert, PurgeChain
);
@@ -14,15 +14,14 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use std::fmt::Debug;
use std::io::{Write, self};
use std::fs;
use structopt::StructOpt;
use sc_service::{ Configuration, ChainSpec, config::{DatabaseConfig} };
use crate::error;
use crate::VersionInfo;
use crate::params::SharedParams;
use crate::CliConfiguration;
use sc_service::{config::DatabaseConfig, Configuration};
use std::fmt::Debug;
use std::fs;
use std::io::{self, Write};
use structopt::StructOpt;
/// The `purge-chain` command used to remove the whole chain.
#[derive(Debug, StructOpt, Clone)]
@@ -38,11 +37,8 @@ pub struct PurgeChainCmd {
impl PurgeChainCmd {
/// Run the purge command
pub fn run(
self,
config: Configuration,
) -> error::Result<()> {
let db_path = match config.expect_database() {
pub fn run(&self, config: Configuration) -> error::Result<()> {
let db_path = match &config.database {
DatabaseConfig::Path { path, .. } => path,
_ => {
eprintln!("Cannot purge custom database implementation");
@@ -76,22 +72,13 @@ impl PurgeChainCmd {
eprintln!("{:?} did not exist.", &db_path);
Ok(())
},
Err(err) => Result::Err(err.into())
Err(err) => Result::Err(err.into()),
}
}
}
/// Update and prepare a `Configuration` with command line parameters
pub fn update_config<F>(
&self,
mut config: &mut Configuration,
spec_factory: F,
version: &VersionInfo,
) -> error::Result<()> where
F: FnOnce(&str) -> Result<Box<dyn ChainSpec>, String>,
{
self.shared_params.update_config(&mut config, spec_factory, version)?;
config.use_in_memory_keystore()?;
Ok(())
impl CliConfiguration for PurgeChainCmd {
fn shared_params(&self) -> &SharedParams {
&self.shared_params
}
}
+13 -26
View File
@@ -14,16 +14,13 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use crate::error;
use crate::params::{BlockNumber, PruningParams, SharedParams};
use crate::CliConfiguration;
use sc_service::{Configuration, ServiceBuilderCommand};
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use std::fmt::Debug;
use structopt::StructOpt;
use sc_service::{
Configuration, ServiceBuilderCommand, ChainSpec, Role,
};
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use crate::error;
use crate::VersionInfo;
use crate::params::{BlockNumber, SharedParams, PruningParams};
/// The `revert` command used revert the chain to a previous state.
#[derive(Debug, StructOpt, Clone)]
@@ -43,11 +40,7 @@ pub struct RevertCmd {
impl RevertCmd {
/// Run the revert command
pub fn run<B, BC, BB>(
self,
config: Configuration,
builder: B,
) -> error::Result<()>
pub fn run<B, BC, BB>(&self, config: Configuration, builder: B) -> error::Result<()>
where
B: FnOnce(Configuration) -> Result<BC, sc_service::error::Error>,
BC: ServiceBuilderCommand<Block = BB> + Unpin,
@@ -60,20 +53,14 @@ impl RevertCmd {
Ok(())
}
}
/// Update and prepare a `Configuration` with command line parameters
pub fn update_config<F>(
&self,
mut config: &mut Configuration,
spec_factory: F,
version: &VersionInfo,
) -> error::Result<()> where
F: FnOnce(&str) -> Result<Box<dyn ChainSpec>, String>,
{
self.shared_params.update_config(&mut config, spec_factory, version)?;
self.pruning_params.update_config(&mut config, &Role::Full, true)?;
config.use_in_memory_keystore()?;
impl CliConfiguration for RevertCmd {
fn shared_params(&self) -> &SharedParams {
&self.shared_params
}
Ok(())
fn pruning_params(&self) -> Option<&PruningParams> {
Some(&self.pruning_params)
}
}
+226 -383
View File
@@ -14,34 +14,21 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use std::path::PathBuf;
use std::net::SocketAddr;
use std::fs;
use std::fmt;
use log::info;
use structopt::{StructOpt, clap::arg_enum};
use names::{Generator, Name};
use crate::error::{Error, Result};
use crate::params::ImportParams;
use crate::params::KeystoreParams;
use crate::params::NetworkParams;
use crate::params::SharedParams;
use crate::params::TransactionPoolParams;
use crate::CliConfiguration;
use regex::Regex;
use chrono::prelude::*;
use sc_service::{
AbstractService, Configuration, ChainSpec, Role,
config::{MultiaddrWithPeerId, KeystoreConfig, PrometheusConfig},
config::{MultiaddrWithPeerId, PrometheusConfig, TransactionPoolOptions},
ChainSpec, Role,
};
use sc_telemetry::TelemetryEndpoints;
use crate::VersionInfo;
use crate::error;
use crate::params::ImportParams;
use crate::params::SharedParams;
use crate::params::NetworkConfigurationParams;
use crate::params::TransactionPoolParams;
use crate::runtime::run_service_until_exit;
/// The maximum number of characters for a node name.
const NODE_NAME_MAX_LENGTH: usize = 32;
/// default sub directory for the key store
const DEFAULT_KEYSTORE_CONFIG_PATH : &'static str = "keystore";
use std::net::SocketAddr;
use structopt::{clap::arg_enum, StructOpt};
arg_enum! {
/// Whether off-chain workers are enabled.
@@ -200,7 +187,7 @@ pub struct RunCmd {
#[allow(missing_docs)]
#[structopt(flatten)]
pub network_config: NetworkConfigurationParams,
pub network_params: NetworkParams,
#[allow(missing_docs)]
#[structopt(flatten)]
@@ -242,38 +229,23 @@ pub struct RunCmd {
#[structopt(long = "force-authoring")]
pub force_authoring: bool,
/// Specify custom keystore path.
#[structopt(long = "keystore-path", value_name = "PATH", parse(from_os_str))]
pub keystore_path: Option<PathBuf>,
/// Use interactive shell for entering the password used by the keystore.
#[structopt(
long = "password-interactive",
conflicts_with_all = &[ "password", "password-filename" ]
)]
pub password_interactive: bool,
/// Password used by the keystore.
#[structopt(
long = "password",
conflicts_with_all = &[ "password-interactive", "password-filename" ]
)]
pub password: Option<String>,
/// File that contains the password used by the keystore.
#[structopt(
long = "password-filename",
value_name = "PATH",
parse(from_os_str),
conflicts_with_all = &[ "password-interactive", "password" ]
)]
pub password_filename: Option<PathBuf>,
#[allow(missing_docs)]
#[structopt(flatten)]
pub keystore_params: KeystoreParams,
/// The size of the instances cache for each runtime.
///
/// The default value is 8 and the values higher than 256 are ignored.
#[structopt(long = "max-runtime-instances", default_value = "8")]
pub max_runtime_instances: usize,
#[structopt(long)]
pub max_runtime_instances: Option<usize>,
/// Specify a list of sentry node public addresses.
#[structopt(
long = "sentry-nodes",
value_name = "ADDR",
conflicts_with_all = &[ "sentry" ]
)]
pub sentry_nodes: Vec<MultiaddrWithPeerId>,
}
impl RunCmd {
@@ -281,219 +253,203 @@ impl RunCmd {
pub fn get_keyring(&self) -> Option<sp_keyring::Sr25519Keyring> {
use sp_keyring::Sr25519Keyring::*;
if self.alice { Some(Alice) }
else if self.bob { Some(Bob) }
else if self.charlie { Some(Charlie) }
else if self.dave { Some(Dave) }
else if self.eve { Some(Eve) }
else if self.ferdie { Some(Ferdie) }
else if self.one { Some(One) }
else if self.two { Some(Two) }
else { None }
}
/// Update and prepare a `Configuration` with command line parameters of `RunCmd` and `VersionInfo`.
pub fn update_config<F>(
&self,
mut config: &mut Configuration,
spec_factory: F,
version: &VersionInfo,
) -> error::Result<()>
where
F: FnOnce(&str) -> Result<Box<dyn ChainSpec>, String>,
{
self.shared_params.update_config(&mut config, spec_factory, version)?;
let password = if self.password_interactive {
#[cfg(not(target_os = "unknown"))]
{
Some(input_keystore_password()?.into())
}
#[cfg(target_os = "unknown")]
None
} else if let Some(ref file) = self.password_filename {
Some(fs::read_to_string(file).map_err(|e| format!("{}", e))?.into())
} else if let Some(ref password) = self.password {
Some(password.clone().into())
if self.alice {
Some(Alice)
} else if self.bob {
Some(Bob)
} else if self.charlie {
Some(Charlie)
} else if self.dave {
Some(Dave)
} else if self.eve {
Some(Eve)
} else if self.ferdie {
Some(Ferdie)
} else if self.one {
Some(One)
} else if self.two {
Some(Two)
} else {
None
};
}
}
}
let path = self.keystore_path.clone().or(
config.in_chain_config_dir(DEFAULT_KEYSTORE_CONFIG_PATH)
);
impl CliConfiguration for RunCmd {
fn shared_params(&self) -> &SharedParams {
&self.shared_params
}
config.keystore = KeystoreConfig::Path {
path: path.ok_or_else(|| "No `base_path` provided to create keystore path!".to_string())?,
password,
};
fn import_params(&self) -> Option<&ImportParams> {
Some(&self.import_params)
}
let keyring = self.get_keyring();
let is_dev = self.shared_params.dev;
let is_light = self.light;
let is_authority = (self.validator || is_dev || keyring.is_some())
&& !is_light;
let role =
if is_light {
sc_service::Role::Light
} else if is_authority {
sc_service::Role::Authority { sentry_nodes: self.network_config.sentry_nodes.clone() }
} else if !self.sentry.is_empty() {
sc_service::Role::Sentry { validators: self.sentry.clone() }
} else {
sc_service::Role::Full
};
fn network_params(&self) -> Option<&NetworkParams> {
Some(&self.network_params)
}
self.import_params.update_config(&mut config, &role, is_dev)?;
fn keystore_params(&self) -> Option<&KeystoreParams> {
Some(&self.keystore_params)
}
config.name = match (self.name.as_ref(), keyring) {
fn node_name(&self) -> Result<String> {
let name: String = match (self.name.as_ref(), self.get_keyring()) {
(Some(name), _) => name.to_string(),
(_, Some(keyring)) => keyring.to_string(),
(None, None) => generate_node_name(),
(None, None) => crate::generate_node_name(),
};
if let Err(msg) = is_node_name_valid(&config.name) {
return Err(error::Error::Input(
format!("Invalid node name '{}'. Reason: {}. If unsure, use none.",
config.name,
msg,
)
));
}
config.offchain_worker = match (&self.offchain_worker, &role) {
(OffchainWorkerEnabled::WhenValidating, sc_service::Role::Authority { .. }) => true,
is_node_name_valid(&name).map_err(|msg| {
Error::Input(format!(
"Invalid node name '{}'. Reason: {}. If unsure, use none.",
name, msg
));
})?;
Ok(name)
}
fn dev_key_seed(&self, is_dev: bool) -> Result<Option<String>> {
Ok(self.get_keyring().map(|a| format!("//{}", a)).or_else(|| {
if is_dev && !self.light {
Some("//Alice".into())
} else {
None
}
}))
}
fn telemetry_endpoints(
&self,
chain_spec: &Box<dyn ChainSpec>,
) -> Result<Option<TelemetryEndpoints>> {
Ok(if self.no_telemetry {
None
} else if !self.telemetry_endpoints.is_empty() {
Some(
TelemetryEndpoints::new(self.telemetry_endpoints.clone())
.map_err(|e| e.to_string())?,
)
} else {
chain_spec.telemetry_endpoints().clone()
})
}
fn role(&self, is_dev: bool) -> Result<Role> {
let keyring = self.get_keyring();
let is_light = self.light;
let is_authority = (self.validator || is_dev || keyring.is_some()) && !is_light;
Ok(if is_light {
sc_service::Role::Light
} else if is_authority {
sc_service::Role::Authority {
sentry_nodes: self.sentry_nodes.clone(),
}
} else if !self.sentry.is_empty() {
sc_service::Role::Sentry {
validators: self.sentry.clone(),
}
} else {
sc_service::Role::Full
})
}
fn force_authoring(&self) -> Result<bool> {
// Imply forced authoring on --dev
Ok(self.shared_params.dev || self.force_authoring)
}
fn prometheus_config(&self) -> Result<Option<PrometheusConfig>> {
if self.no_prometheus {
Ok(None)
} else {
let prometheus_interface: &str = if self.prometheus_external {
"0.0.0.0"
} else {
"127.0.0.1"
};
Ok(Some(PrometheusConfig::new_with_default_registry(
parse_address(
&format!("{}:{}", prometheus_interface, 9615),
self.prometheus_port,
)?,
)))
}
}
fn disable_grandpa(&self) -> Result<bool> {
Ok(self.no_grandpa)
}
fn rpc_ws_max_connections(&self) -> Result<Option<usize>> {
Ok(self.ws_max_connections)
}
fn rpc_cors(&self, is_dev: bool) -> Result<Option<Vec<String>>> {
Ok(self
.rpc_cors
.clone()
.unwrap_or_else(|| {
if is_dev {
log::warn!("Running in --dev mode, RPC CORS has been disabled.");
Cors::All
} else {
Cors::List(vec![
"http://localhost:*".into(),
"http://127.0.0.1:*".into(),
"https://localhost:*".into(),
"https://127.0.0.1:*".into(),
"https://polkadot.js.org".into(),
])
}
})
.into())
}
fn rpc_http(&self) -> Result<Option<SocketAddr>> {
let rpc_interface: &str =
interface_str(self.rpc_external, self.unsafe_rpc_external, self.validator)?;
Ok(Some(parse_address(
&format!("{}:{}", rpc_interface, 9933),
self.rpc_port,
)?))
}
fn rpc_ws(&self) -> Result<Option<SocketAddr>> {
let ws_interface: &str =
interface_str(self.ws_external, self.unsafe_ws_external, self.validator)?;
Ok(Some(parse_address(
&format!("{}:{}", ws_interface, 9944),
self.ws_port,
)?))
}
fn offchain_worker(&self, role: &Role) -> Result<bool> {
Ok(match (&self.offchain_worker, role) {
(OffchainWorkerEnabled::WhenValidating, Role::Authority { .. }) => true,
(OffchainWorkerEnabled::Always, _) => true,
(OffchainWorkerEnabled::Never, _) => false,
(OffchainWorkerEnabled::WhenValidating, _) => false,
};
config.role = role;
config.disable_grandpa = self.no_grandpa;
let client_id = config.client_id();
let network_path = config
.in_chain_config_dir(crate::commands::DEFAULT_NETWORK_CONFIG_PATH)
.expect("We provided a basepath");
self.network_config.update_config(
&mut config,
network_path,
client_id,
is_dev,
)?;
self.pool_config.update_config(&mut config)?;
config.dev_key_seed = keyring
.map(|a| format!("//{}", a)).or_else(|| {
if is_dev && !is_light {
Some("//Alice".into())
} else {
None
}
});
if config.rpc_http.is_none() || self.rpc_port.is_some() {
let rpc_interface: &str = interface_str(self.rpc_external, self.unsafe_rpc_external, self.validator)?;
config.rpc_http = Some(parse_address(&format!("{}:{}", rpc_interface, 9933), self.rpc_port)?);
}
if config.rpc_ws.is_none() || self.ws_port.is_some() {
let ws_interface: &str = interface_str(self.ws_external, self.unsafe_ws_external, self.validator)?;
config.rpc_ws = Some(parse_address(&format!("{}:{}", ws_interface, 9944), self.ws_port)?);
}
config.rpc_ws_max_connections = self.ws_max_connections;
config.rpc_cors = self.rpc_cors.clone().unwrap_or_else(|| if is_dev {
log::warn!("Running in --dev mode, RPC CORS has been disabled.");
Cors::All
} else {
Cors::List(vec![
"http://localhost:*".into(),
"http://127.0.0.1:*".into(),
"https://localhost:*".into(),
"https://127.0.0.1:*".into(),
"https://polkadot.js.org".into(),
])
}).into();
// Override telemetry
if self.no_telemetry {
config.telemetry_endpoints = None;
} else if !self.telemetry_endpoints.is_empty() {
config.telemetry_endpoints = Some(
TelemetryEndpoints::new(self.telemetry_endpoints.clone()).map_err(|e| e.to_string())?
);
}
// Override prometheus
if self.no_prometheus {
config.prometheus_config = None;
} else if config.prometheus_config.is_none() {
let prometheus_interface: &str = if self.prometheus_external { "0.0.0.0" } else { "127.0.0.1" };
config.prometheus_config = Some(PrometheusConfig::new_with_default_registry(
parse_address(&format!("{}:{}", prometheus_interface, 9615), self.prometheus_port)?,
));
}
config.tracing_targets = self.import_params.tracing_targets.clone().into();
config.tracing_receiver = self.import_params.tracing_receiver.clone().into();
// Imply forced authoring on --dev
config.force_authoring = self.shared_params.dev || self.force_authoring;
config.max_runtime_instances = self.max_runtime_instances.min(256);
Ok(())
})
}
/// Run the command that runs the node.
pub fn run<FNL, FNF, SL, SF>(
self,
config: Configuration,
new_light: FNL,
new_full: FNF,
version: &VersionInfo,
) -> error::Result<()>
where
FNL: FnOnce(Configuration) -> Result<SL, sc_service::error::Error>,
FNF: FnOnce(Configuration) -> Result<SF, sc_service::error::Error>,
SL: AbstractService + Unpin,
SF: AbstractService + Unpin,
{
info!("{}", version.name);
info!("✌️ version {}", config.full_version());
info!("❤️ by {}, {}-{}", version.author, version.copyright_start_year, Local::today().year());
info!("📋 Chain specification: {}", config.expect_chain_spec().name());
info!("🏷 Node name: {}", config.name);
info!("👤 Role: {}", config.display_role());
match config.role {
Role::Light => run_service_until_exit(
config,
new_light,
),
_ => run_service_until_exit(
config,
new_full,
),
}
fn transaction_pool(&self) -> Result<TransactionPoolOptions> {
Ok(self.pool_config.transaction_pool())
}
/// Initialize substrate. This must be done only once.
///
/// This method:
///
/// 1. Set the panic handler
/// 2. Raise the FD limit
/// 3. Initialize the logger
pub fn init(&self, version: &VersionInfo) -> error::Result<()> {
self.shared_params.init(version)
fn max_runtime_instances(&self) -> Result<Option<usize>> {
Ok(self.max_runtime_instances.map(|x| x.min(256)))
}
}
/// Check whether a node name is considered as valid.
pub fn is_node_name_valid(_name: &str) -> Result<(), &str> {
pub fn is_node_name_valid(_name: &str) -> std::result::Result<(), &str> {
let name = _name.to_string();
if name.chars().count() >= NODE_NAME_MAX_LENGTH {
if name.chars().count() >= crate::NODE_NAME_MAX_LENGTH {
return Err("Node name too long");
}
@@ -512,32 +468,10 @@ pub fn is_node_name_valid(_name: &str) -> Result<(), &str> {
Ok(())
}
#[cfg(not(target_os = "unknown"))]
fn input_keystore_password() -> Result<String, String> {
rpassword::read_password_from_tty(Some("Keystore password: "))
.map_err(|e| format!("{:?}", e))
}
fn generate_node_name() -> String {
let result = loop {
let node_name = Generator::with_naming(Name::Numbered).next().unwrap();
let count = node_name.chars().count();
if count < NODE_NAME_MAX_LENGTH {
break node_name
}
};
result
}
fn parse_address(
address: &str,
port: Option<u16>,
) -> Result<SocketAddr, String> {
let mut address: SocketAddr = address.parse().map_err(
|_| format!("Invalid address: {}", address)
)?;
fn parse_address(address: &str, port: Option<u16>) -> std::result::Result<SocketAddr, String> {
let mut address: SocketAddr = address
.parse()
.map_err(|_| format!("Invalid address: {}", address))?;
if let Some(port) = port {
address.set_port(port);
}
@@ -549,16 +483,21 @@ fn interface_str(
is_external: bool,
is_unsafe_external: bool,
is_validator: bool,
) -> Result<&'static str, error::Error> {
) -> Result<&'static str> {
if is_external && is_validator {
return Err(error::Error::Input("--rpc-external and --ws-external options shouldn't be \
return Err(Error::Input(
"--rpc-external and --ws-external options shouldn't be \
used if the node is running as a validator. Use `--unsafe-rpc-external` if you understand \
the risks. See the options description for more information.".to_owned()));
the risks. See the options description for more information."
.to_owned(),
));
}
if is_external || is_unsafe_external {
log::warn!("It isn't safe to expose RPC publicly without a proxy server that filters \
available set of RPC methods.");
log::warn!(
"It isn't safe to expose RPC publicly without a proxy server that filters \
available set of RPC methods."
);
Ok("0.0.0.0")
} else {
@@ -574,8 +513,8 @@ enum TelemetryParsingError {
impl std::error::Error for TelemetryParsingError {}
impl fmt::Display for TelemetryParsingError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
impl std::fmt::Display for TelemetryParsingError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &*self {
TelemetryParsingError::MissingVerbosity => write!(f, "Verbosity level missing"),
TelemetryParsingError::VerbosityParsingError(e) => write!(f, "{}", e),
@@ -583,13 +522,15 @@ impl fmt::Display for TelemetryParsingError {
}
}
fn parse_telemetry_endpoints(s: &str) -> Result<(String, u8), TelemetryParsingError> {
fn parse_telemetry_endpoints(s: &str) -> std::result::Result<(String, u8), TelemetryParsingError> {
let pos = s.find(' ');
match pos {
None => Err(TelemetryParsingError::MissingVerbosity),
Some(pos_) => {
let url = s[..pos_].to_string();
let verbosity = s[pos_ + 1..].parse().map_err(TelemetryParsingError::VerbosityParsingError)?;
let verbosity = s[pos_ + 1..]
.parse()
.map_err(TelemetryParsingError::VerbosityParsingError)?;
Ok((url, verbosity))
}
}
@@ -617,7 +558,7 @@ impl From<Cors> for Option<Vec<String>> {
}
/// Parse cors origins.
fn parse_cors(s: &str) -> Result<Cors, Box<dyn std::error::Error>> {
fn parse_cors(s: &str) -> std::result::Result<Cors, Box<dyn std::error::Error>> {
let mut is_all = false;
let mut origins = Vec::new();
for part in s.split(',') {
@@ -625,29 +566,21 @@ fn parse_cors(s: &str) -> Result<Cors, Box<dyn std::error::Error>> {
"all" | "*" => {
is_all = true;
break;
},
}
other => origins.push(other.to_owned()),
}
}
Ok(if is_all { Cors::All } else { Cors::List(origins) })
Ok(if is_all {
Cors::All
} else {
Cors::List(origins)
})
}
#[cfg(test)]
mod tests {
use super::*;
use sc_service::{GenericChainSpec, config::DatabaseConfig};
const TEST_VERSION_INFO: &'static VersionInfo = &VersionInfo {
name: "node-test",
version: "0.1.0",
commit: "some_commit",
executable_name: "node-test",
description: "description",
author: "author",
support_url: "http://example.org",
copyright_start_year: 2020,
};
#[test]
fn tests_node_name_good() {
@@ -663,94 +596,4 @@ mod tests {
assert!(is_node_name_valid("www.visit.me").is_err());
assert!(is_node_name_valid("email@domain").is_err());
}
#[test]
fn keystore_path_is_generated_correctly() {
let chain_spec = GenericChainSpec::from_genesis(
"test",
"test-id",
|| (),
Vec::new(),
None,
None,
None,
None::<()>,
);
for keystore_path in vec![None, Some("/keystore/path")] {
let args: Vec<&str> = vec![];
let mut cli = RunCmd::from_iter(args);
cli.keystore_path = keystore_path.clone().map(PathBuf::from);
let mut config = Configuration::default();
config.config_dir = Some(PathBuf::from("/test/path"));
config.chain_spec = Some(Box::new(chain_spec.clone()));
let chain_spec = chain_spec.clone();
cli.update_config(&mut config, move |_| Ok(Box::new(chain_spec)), TEST_VERSION_INFO).unwrap();
let expected_path = match keystore_path {
Some(path) => PathBuf::from(path),
None => PathBuf::from("/test/path/chains/test-id/keystore"),
};
assert_eq!(expected_path, config.keystore.path().unwrap().to_owned());
}
}
#[test]
fn ensure_load_spec_provide_defaults() {
let chain_spec = GenericChainSpec::from_genesis(
"test",
"test-id",
|| (),
vec!["/ip4/127.0.0.1/tcp/30333/p2p/QmdSHZLmwEL5Axz5JvWNE2mmxU7qyd7xHBFpyUfktgAdg7".parse().unwrap()],
Some(TelemetryEndpoints::new(vec![("wss://foo/bar".to_string(), 42)])
.expect("provided url should be valid")),
None,
None,
None::<()>,
);
let args: Vec<&str> = vec![];
let cli = RunCmd::from_iter(args);
let mut config = Configuration::from_version(TEST_VERSION_INFO);
cli.update_config(&mut config, |_| Ok(Box::new(chain_spec)), TEST_VERSION_INFO).unwrap();
assert!(config.chain_spec.is_some());
assert!(!config.network.boot_nodes.is_empty());
assert!(config.telemetry_endpoints.is_some());
}
#[test]
fn ensure_update_config_for_running_node_provides_defaults() {
let chain_spec = GenericChainSpec::from_genesis(
"test",
"test-id",
|| (),
vec![],
None,
None,
None,
None::<()>,
);
let args: Vec<&str> = vec![];
let cli = RunCmd::from_iter(args);
let mut config = Configuration::from_version(TEST_VERSION_INFO);
cli.init(&TEST_VERSION_INFO).unwrap();
cli.update_config(&mut config, |_| Ok(Box::new(chain_spec)), TEST_VERSION_INFO).unwrap();
assert!(config.config_dir.is_some());
assert!(config.database.is_some());
if let Some(DatabaseConfig::Path { ref cache_size, .. }) = config.database {
assert!(cache_size.is_some());
} else {
panic!("invalid config.database variant");
}
assert!(!config.name.is_empty());
assert!(config.network.config_path.is_some());
assert!(!config.network.listen_addresses.is_empty());
}
}