diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 828c830948a13..ced3e33eaabaa 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -235,15 +235,6 @@ check-web-wasm: - time cargo build --manifest-path=bin/node/cli/Cargo.toml --no-default-features --features "browser" --target=wasm32-unknown-unknown - sccache -s -node-exits: - stage: test - <<: *docker-env - except: - - /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - script: - - ./.maintain/check_for_exit.sh - - test-full-crypto-feature: stage: test <<: *docker-env diff --git a/.maintain/check_for_exit.sh b/.maintain/check_for_exit.sh deleted file mode 100755 index edc2130e57113..0000000000000 --- a/.maintain/check_for_exit.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -# Script that checks that a node exits after `SIGINT` was send. - -set -e - -cargo build -./target/debug/substrate --dev & -PID=$! - -# Let the chain running for 60 seconds -sleep 60 - -# Send `SIGINT` and give the process 30 seconds to end -kill -INT $PID -timeout 30 tail --pid=$PID -f /dev/null diff --git a/Cargo.lock b/Cargo.lock index f521817b2cab6..3f94778b8430c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -150,6 +150,19 @@ dependencies = [ "syn", ] +[[package]] +name = "assert_cmd" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6283bac8dd7226470d491bc4737816fea4ca1fba7a2847f2e9097fd6bfb4624c" +dependencies = [ + "doc-comment", + "escargot", + "predicates", + "predicates-core", + "predicates-tree", +] + [[package]] name = "assert_matches" version = "1.3.0" @@ -1227,6 +1240,18 @@ dependencies = [ "libc", ] +[[package]] +name = "escargot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74cf96bec282dcdb07099f7e31d9fed323bca9435a09aba7b6d99b7617bca96d" +dependencies = [ + "lazy_static", + "log 0.4.8", + "serde", + "serde_json", +] + [[package]] name = "evm" version = "0.14.2" @@ -3318,10 +3343,24 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "nix" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", + "void", +] + [[package]] name = "node-cli" version = "2.0.0" dependencies = [ + "assert_cmd", "browser-utils", "frame-support", "frame-system", @@ -3329,6 +3368,7 @@ dependencies = [ "hex-literal", "jsonrpc-core", "log 0.4.8", + "nix", "node-executor", "node-primitives", "node-rpc", @@ -4816,6 +4856,32 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +[[package]] +name = "predicates" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9bfe52247e5cc9b2f943682a85a5549fb9662245caf094504e69a2f03fe64d4" +dependencies = [ + "difference", + "predicates-core", +] + +[[package]] +name = "predicates-core" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06075c3a3e92559ff8929e7a280684489ea27fe44805174c3ebd9328dcb37178" + +[[package]] +name = "predicates-tree" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e63c4859013b38a76eca2414c64911fba30def9e3202ac461a2d22831220124" +dependencies = [ + "predicates-core", + "treeline", +] + [[package]] name = "pretty_assertions" version = "0.6.1" @@ -8118,6 +8184,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" +[[package]] +name = "treeline" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41" + [[package]] name = "trie-bench" version = "0.19.0" @@ -8204,7 +8276,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bfd5b7557925ce778ff9b9ef90e3ade34c524b5ff10e239c69a42d546d2af56" dependencies = [ - "rand 0.3.23", + "rand 0.7.3", ] [[package]] diff --git a/bin/node-template/node/src/command.rs b/bin/node-template/node/src/command.rs index 86058929b0871..585b8e1ca8eb9 100644 --- a/bin/node-template/node/src/command.rs +++ b/bin/node-template/node/src/command.rs @@ -25,8 +25,7 @@ pub fn run(version: VersionInfo) -> error::Result<()> { let opt = sc_cli::from_args::(&version); - let mut config = sc_service::Configuration::default(); - config.impl_name = "node-template"; + let config = sc_service::Configuration::new(&version); match opt.subcommand { Some(subcommand) => sc_cli::run_subcommand( diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index ef6e90f91a943..cf666ffdc518e 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -95,6 +95,8 @@ sc-consensus-babe = { version = "0.8", features = ["test-helpers"], path = "../. sc-service-test = { version = "2.0.0", path = "../../../client/service/test" } futures = "0.3.1" tempfile = "3.1.0" +assert_cmd = "0.12" +nix = "0.17" [build-dependencies] build-script-utils = { version = "2.0.0", package = "substrate-build-script-utils", path = "../../../utils/build-script-utils" } diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index 7a22710ec1699..eb18d6d8b33d1 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -28,8 +28,7 @@ where let args: Vec<_> = args.collect(); let opt = sc_cli::from_iter::(args.clone(), &version); - let mut config = sc_service::Configuration::default(); - config.impl_name = "substrate-node"; + let mut config = sc_service::Configuration::new(&version); match opt.subcommand { None => sc_cli::run( @@ -41,8 +40,8 @@ where &version, ), Some(Subcommand::Factory(cli_args)) => { - sc_cli::init(&mut config, load_spec, &cli_args.shared_params, &version)?; - + sc_cli::init(&cli_args.shared_params, &version)?; + sc_cli::load_spec(&mut config, &cli_args.shared_params, load_spec)?; sc_cli::fill_import_params( &mut config, &cli_args.import_params, diff --git a/bin/node/cli/tests/running_the_node_and_interrupt.rs b/bin/node/cli/tests/running_the_node_and_interrupt.rs new file mode 100644 index 0000000000000..6b0d6963966d3 --- /dev/null +++ b/bin/node/cli/tests/running_the_node_and_interrupt.rs @@ -0,0 +1,58 @@ +// Copyright 2020 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +use assert_cmd::cargo::cargo_bin; +use std::convert::TryInto; +use std::process::{Child, Command, ExitStatus}; +use std::thread::sleep; +use std::time::Duration; + +#[test] +#[cfg(unix)] +fn running_the_node_works_and_can_be_interrupted() { + use nix::sys::signal::{kill, Signal::{self, SIGINT, SIGTERM}}; + use nix::unistd::Pid; + + fn wait_for(child: &mut Child, secs: usize) -> Option { + for _ in 0..secs { + match child.try_wait().unwrap() { + Some(status) => return Some(status), + None => sleep(Duration::from_secs(1)), + } + } + eprintln!("Took to long to exit. Killing..."); + let _ = child.kill(); + child.wait().unwrap(); + + None + } + + fn run_command_and_kill(signal: Signal) { + let mut cmd = Command::new(cargo_bin("substrate")).spawn().unwrap(); + sleep(Duration::from_secs(30)); + assert!(cmd.try_wait().unwrap().is_none(), "the process should still be running"); + kill(Pid::from_raw(cmd.id().try_into().unwrap()), signal).unwrap(); + assert_eq!( + wait_for(&mut cmd, 30).map(|x| x.success()), + Some(true), + "the pocess must exit gracefully after signal {}", + signal, + ); + } + + run_command_and_kill(SIGINT); + run_command_and_kill(SIGTERM); +} diff --git a/client/cli/src/lib.rs b/client/cli/src/lib.rs index 785a6fb073bc9..7f726893368a0 100644 --- a/client/cli/src/lib.rs +++ b/client/cli/src/lib.rs @@ -35,6 +35,7 @@ use sc_service::{ RuntimeGenesis, ChainSpecExtension, PruningMode, ChainSpec, AbstractService, Roles as ServiceRoles, }; +pub use sc_service::config::VersionInfo; use sc_network::{ self, multiaddr::Protocol, @@ -74,32 +75,11 @@ const DEFAULT_NETWORK_CONFIG_PATH : &'static str = "network"; /// default sub directory to store database const DEFAULT_DB_CONFIG_PATH : &'static str = "db"; /// default sub directory for the key store -const DEFAULT_KEYSTORE_CONFIG_PATH : &'static str = "keystore"; +const DEFAULT_KEYSTORE_CONFIG_PATH : &'static str = "keystore"; /// The maximum number of characters for a node name. const NODE_NAME_MAX_LENGTH: usize = 32; -/// Executable version. Used to pass version information from the root crate. -#[derive(Clone)] -pub struct VersionInfo { - /// Implementaiton name. - pub name: &'static str, - /// Implementation version. - pub version: &'static str, - /// SCM Commit hash. - pub commit: &'static str, - /// Executable file name. - pub executable_name: &'static str, - /// Executable file description. - pub description: &'static str, - /// Executable file author. - pub author: &'static str, - /// Support URL. - pub support_url: &'static str, - /// Copyright starting year (x-current year) - pub copyright_start_year: i32, -} - fn get_chain_key(cli: &SharedParams) -> String { match cli.chain { Some(ref chain) => chain.clone(), @@ -120,8 +100,12 @@ fn generate_node_name() -> String { result } -/// Load spec give shared params and spec factory. -pub fn load_spec(cli: &SharedParams, factory: F) -> error::Result> where +/// Load spec to `Configuration` from shared params and spec factory. +pub fn load_spec<'a, G, E, F>( + mut config: &'a mut Configuration, + cli: &SharedParams, + factory: F, +) -> error::Result<&'a ChainSpec> where G: RuntimeGenesis, E: ChainSpecExtension, F: FnOnce(&str) -> Result>, String>, @@ -131,7 +115,13 @@ pub fn load_spec(cli: &SharedParams, factory: F) -> error::Result spec, None => ChainSpec::from_json_file(PathBuf::from(chain_key))? }; - Ok(spec) + + config.network.boot_nodes = spec.boot_nodes().to_vec(); + config.telemetry_endpoints = spec.telemetry_endpoints().clone(); + + config.chain_spec = Some(spec); + + Ok(config.chain_spec.as_ref().unwrap()) } fn base_path(cli: &SharedParams, version: &VersionInfo) -> PathBuf { @@ -243,8 +233,8 @@ where SL: AbstractService + Unpin, SF: AbstractService + Unpin, { - init(&mut config, spec_factory, &run_cmd.shared_params, version)?; - + init(&run_cmd.shared_params, version)?; + load_spec(&mut config, &run_cmd.shared_params, spec_factory)?; run_cmd.run(config, new_light, new_full, version) } @@ -266,30 +256,21 @@ where <<::Header as HeaderT>::Number as std::str::FromStr>::Err: std::fmt::Debug, ::Hash: std::str::FromStr, { - init(&mut config, spec_factory, &subcommand.get_shared_params(), version)?; + let shared_params = subcommand.get_shared_params(); + init(shared_params, version)?; + load_spec(&mut config, shared_params, spec_factory)?; subcommand.run(config, builder) } -/// Initialize substrate and its configuration +/// Initialize substrate. This must be done only once. /// /// This method: /// /// 1. set the panic handler /// 2. raise the FD limit /// 3. initialize the logger -/// 4. update the configuration provided with the chain specification, config directory, -/// information (version, commit), database's path, boot nodes and telemetry endpoints -pub fn init( - mut config: &mut Configuration, - spec_factory: F, - shared_params: &SharedParams, - version: &VersionInfo, -) -> error::Result<()> -where - G: RuntimeGenesis, - E: ChainSpecExtension, - F: FnOnce(&str) -> Result>, String>, +pub fn init(shared_params: &SharedParams, version: &VersionInfo) -> error::Result<()> { let full_version = sc_service::config::full_version_from_strs( version.version, @@ -300,21 +281,6 @@ where fdlimit::raise_fd_limit(); init_logger(shared_params.log.as_ref().map(|v| v.as_ref()).unwrap_or("")); - config.chain_spec = Some(load_spec(shared_params, spec_factory)?); - config.config_dir = Some(base_path(shared_params, version)); - config.impl_commit = version.commit; - config.impl_version = version.version; - - config.database = DatabaseConfig::Path { - path: config - .in_chain_config_dir(DEFAULT_DB_CONFIG_PATH) - .expect("We provided a base_path/config_dir."), - cache_size: None, - }; - - config.network.boot_nodes = config.expect_chain_spec().boot_nodes().to_vec(); - config.telemetry_endpoints = config.expect_chain_spec().telemetry_endpoints().clone(); - Ok(()) } @@ -419,8 +385,6 @@ fn fill_network_configuration( ]; } - config.public_addresses = Vec::new(); - config.client_version = client_id; config.node_key = node_key::node_key_config(cli.node_key_params, &config.net_config_path)?; @@ -496,10 +460,8 @@ pub fn fill_import_params( where G: RuntimeGenesis, { - match config.database { - DatabaseConfig::Path { ref mut cache_size, .. } => - *cache_size = Some(cli.database_cache_size), - DatabaseConfig::Custom(_) => {}, + if let Some(DatabaseConfig::Path { ref mut cache_size, .. }) = config.database { + *cache_size = Some(cli.database_cache_size); } config.state_cache_size = cli.state_cache_size; @@ -549,14 +511,30 @@ where Ok(()) } -/// Update and prepare a `Configuration` with command line parameters of `RunCmd` +/// Update and prepare a `Configuration` with command line parameters of `RunCmd` and `VersionInfo` pub fn update_config_for_running_node( mut config: &mut Configuration, cli: RunCmd, + version: &VersionInfo, ) -> error::Result<()> where G: RuntimeGenesis, { + if config.config_dir.is_none() { + config.config_dir = Some(base_path(&cli.shared_params, version)); + } + + if config.database.is_none() { + // NOTE: the loading of the DatabaseConfig is voluntarily delayed to here + // in case config.config_dir has been customized + config.database = Some(DatabaseConfig::Path { + path: config + .in_chain_config_dir(DEFAULT_DB_CONFIG_PATH) + .expect("We provided a base_path/config_dir."), + cache_size: None, + }); + } + fill_config_keystore_password_and_path(&mut config, &cli)?; let keyring = cli.get_keyring(); @@ -580,16 +558,13 @@ where (_, Some(keyring)) => keyring.to_string(), (None, None) => generate_node_name(), }; - match node_key::is_node_name_valid(&config.name) { - Ok(_) => (), - Err(msg) => Err( - error::Error::Input( - format!("Invalid node name '{}'. Reason: {}. If unsure, use none.", - config.name, - msg - ) + if let Err(msg) = node_key::is_node_name_valid(&config.name) { + return Err(error::Error::Input( + format!("Invalid node name '{}'. Reason: {}. If unsure, use none.", + config.name, + msg, ) - )? + )); } // set sentry mode (i.e. act as an authority but **never** actively participate) @@ -625,16 +600,16 @@ where } }); - if config.rpc_http.is_none() { + if config.rpc_http.is_none() || cli.rpc_port.is_some() { let rpc_interface: &str = interface_str(cli.rpc_external, cli.unsafe_rpc_external, cli.validator)?; config.rpc_http = Some(parse_address(&format!("{}:{}", rpc_interface, 9933), cli.rpc_port)?); } - if config.rpc_ws.is_none() { + if config.rpc_ws.is_none() || cli.ws_port.is_some() { let ws_interface: &str = interface_str(cli.ws_external, cli.unsafe_ws_external, cli.validator)?; config.rpc_ws = Some(parse_address(&format!("{}:{}", ws_interface, 9944), cli.ws_port)?); } - if config.grafana_port.is_none() { + if config.grafana_port.is_none() || cli.grafana_port.is_some() { let grafana_interface: &str = if cli.grafana_external { "0.0.0.0" } else { "127.0.0.1" }; config.grafana_port = Some( parse_address(&format!("{}:{}", grafana_interface, 9955), cli.grafana_port)? @@ -781,6 +756,17 @@ fn kill_color(s: &str) -> String { mod tests { use super::*; + 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 keystore_path_is_generated_correctly() { let chain_spec = ChainSpec::from_genesis( @@ -805,6 +791,7 @@ mod tests { update_config_for_running_node( &mut node_config, run_cmds.clone(), + TEST_VERSION_INFO, ).unwrap(); let expected_path = match keystore_path { @@ -815,4 +802,60 @@ mod tests { assert_eq!(expected_path, node_config.keystore.path().unwrap().to_owned()); } } + + #[test] + fn ensure_load_spec_provide_defaults() { + let chain_spec = ChainSpec::from_genesis( + "test", + "test-id", + || (), + vec!["boo".to_string()], + Some(TelemetryEndpoints::new(vec![("foo".to_string(), 42)])), + None, + None, + None::<()>, + ); + + let args: Vec<&str> = vec![]; + let cli = RunCmd::from_iter(args); + + let mut config = Configuration::new(TEST_VERSION_INFO); + load_spec(&mut config, &cli.shared_params, |_| Ok(Some(chain_spec))).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 = ChainSpec::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::new(TEST_VERSION_INFO); + config.chain_spec = Some(chain_spec); + update_config_for_running_node(&mut config, cli, 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()); + } } diff --git a/client/cli/src/params.rs b/client/cli/src/params.rs index eddd8578b3917..3a4aa319c6e8f 100644 --- a/client/cli/src/params.rs +++ b/client/cli/src/params.rs @@ -936,6 +936,7 @@ impl RunCmd { crate::update_config_for_running_node( &mut config, self, + &version, )?; crate::run_node(config, new_light, new_full, &version) @@ -1003,7 +1004,7 @@ impl ExportBlocksCmd { crate::fill_config_keystore_in_memory(&mut config)?; - if let DatabaseConfig::Path { ref path, .. } = &config.database { + if let DatabaseConfig::Path { ref path, .. } = config.expect_database() { info!("DB path: {}", path.display()); } let from = self.from.as_ref().and_then(|f| f.parse().ok()).unwrap_or(1); @@ -1124,7 +1125,7 @@ impl PurgeChainCmd { crate::fill_config_keystore_in_memory(&mut config)?; - let db_path = match config.database { + let db_path = match config.expect_database() { DatabaseConfig::Path { path, .. } => path, _ => { eprintln!("Cannot purge custom database implementation"); diff --git a/client/cli/src/runtime.rs b/client/cli/src/runtime.rs index 3eee94c0495ea..62a2245c9e174 100644 --- a/client/cli/src/runtime.rs +++ b/client/cli/src/runtime.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . +use std::sync::Arc; + use futures::{Future, future, future::FutureExt}; use futures::select; use futures::pin_mut; @@ -91,7 +93,7 @@ where config.task_executor = { let runtime_handle = runtime.handle().clone(); - Some(Box::new(move |fut| { runtime_handle.spawn(fut); })) + Some(Arc::new(move |fut| { runtime_handle.spawn(fut); })) }; let f = future_builder(config)?; @@ -117,7 +119,7 @@ where config.task_executor = { let runtime_handle = runtime.handle().clone(); - Some(Box::new(move |fut| { runtime_handle.spawn(fut); })) + Some(Arc::new(move |fut| { runtime_handle.spawn(fut); })) }; let service = service_builder(config)?; diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 7a6ca8dc791c4..ad1d225134ffd 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -196,7 +196,7 @@ fn new_full_parts( state_cache_child_ratio: config.state_cache_child_ratio.map(|v| (v, 100)), pruning: config.pruning.clone(), - source: match &config.database { + source: match config.expect_database() { DatabaseConfig::Path { path, cache_size } => sc_client_db::DatabaseSettingsSrc::Path { path: path.clone(), @@ -307,7 +307,7 @@ where TGen: RuntimeGenesis, TCSExt: Extension { state_cache_child_ratio: config.state_cache_child_ratio.map(|v| (v, 100)), pruning: config.pruning.clone(), - source: match &config.database { + source: match config.expect_database() { DatabaseConfig::Path { path, cache_size } => sc_client_db::DatabaseSettingsSrc::Path { path: path.clone(), @@ -1187,7 +1187,7 @@ ServiceBuilder< task_executor: if let Some(exec) = config.task_executor { exec } else { - return Err(Error::TasksExecutorRequired); + return Err(Error::TaskExecutorRequired); }, rpc_handlers, _rpc: rpc, diff --git a/client/service/src/config.rs b/client/service/src/config.rs index cb8170f7f4966..f4043d533e190 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -28,6 +28,27 @@ use sp_core::crypto::Protected; use target_info::Target; use sc_telemetry::TelemetryEndpoints; +/// Executable version. Used to pass version information from the root crate. +#[derive(Clone)] +pub struct VersionInfo { + /// Implementation name. + pub name: &'static str, + /// Implementation version. + pub version: &'static str, + /// SCM Commit hash. + pub commit: &'static str, + /// Executable file name. + pub executable_name: &'static str, + /// Executable file description. + pub description: &'static str, + /// Executable file author. + pub author: &'static str, + /// Support URL. + pub support_url: &'static str, + /// Copyright starting year (x-current year) + pub copyright_start_year: i32, +} + /// Service configuration. pub struct Configuration { /// Implementation name @@ -39,7 +60,7 @@ pub struct Configuration { /// Node roles. pub roles: Roles, /// How to spawn background tasks. Mandatory, otherwise creating a `Service` will error. - pub task_executor: Option + Send>>) + Send>>, + pub task_executor: Option + Send>>) + Send + Sync>>, /// Extrinsic pool configuration. pub transaction_pool: TransactionPoolOptions, /// Network configuration. @@ -49,7 +70,7 @@ pub struct Configuration { /// Configuration for the keystore. pub keystore: KeystoreConfig, /// Configuration for the database. - pub database: DatabaseConfig, + pub database: Option, /// Size of internal state cache in Bytes pub state_cache_size: usize, /// Size in percent of cache size dedicated to child tries @@ -147,7 +168,7 @@ pub enum DatabaseConfig { impl Default for Configuration { /// Create a default config fn default() -> Self { - let configuration = Configuration { + Configuration { impl_name: "parity-substrate", impl_version: "0.0.0", impl_commit: "", @@ -159,10 +180,7 @@ impl Default for Configuration { transaction_pool: Default::default(), network: Default::default(), keystore: KeystoreConfig::None, - database: DatabaseConfig::Path { - path: Default::default(), - cache_size: Default::default(), - }, + database: None, state_cache_size: Default::default(), state_cache_child_ratio: Default::default(), pruning: PruningMode::default(), @@ -183,14 +201,21 @@ impl Default for Configuration { dev_key_seed: None, tracing_targets: Default::default(), tracing_receiver: Default::default(), - }; - - configuration + } } - } impl Configuration { + /// Create a default config using `VersionInfo` + pub fn new(version: &VersionInfo) -> Self { + let mut config = Configuration::default(); + config.impl_name = version.name; + config.impl_version = version.version; + config.impl_commit = version.commit; + + config + } + /// Returns full version string of this configuration. pub fn full_version(&self) -> String { full_version_from_strs(self.impl_version, self.impl_commit) @@ -220,6 +245,15 @@ impl Configuration { pub fn expect_chain_spec(&self) -> &ChainSpec { self.chain_spec.as_ref().expect("chain_spec must be specified") } + + /// Return a reference to the `DatabaseConfig` of this `Configuration`. + /// + /// ### Panics + /// + /// This method panic if the `database` is `None` + pub fn expect_database(&self) -> &DatabaseConfig { + self.database.as_ref().expect("database must be specified") + } } /// Returns platform info diff --git a/client/service/src/error.rs b/client/service/src/error.rs index 14b03d7e95de7..059e1c19e490d 100644 --- a/client/service/src/error.rs +++ b/client/service/src/error.rs @@ -42,7 +42,7 @@ pub enum Error { SelectChainRequired, /// Tasks executor is missing. #[display(fmt="Tasks executor hasn't been provided.")] - TasksExecutorRequired, + TaskExecutorRequired, /// Other error. Other(String), } diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index dc158f1300a90..577f36572acbb 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -96,7 +96,7 @@ pub struct Service { /// Receiver for futures that must be spawned as background tasks. to_spawn_rx: mpsc::UnboundedReceiver<(Pin + Send>>, Cow<'static, str>)>, /// How to spawn background tasks. - task_executor: Box + Send>>) + Send>, + task_executor: Arc + Send>>) + Send + Sync>, rpc_handlers: sc_rpc_server::RpcHandler, _rpc: Box, _telemetry: Option, diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index cb458d533fdf1..2976e66a2982f 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -133,7 +133,7 @@ fn node_config ( index: usize, spec: &ChainSpec, role: Roles, - task_executor: Box + Send>>) + Send>, + task_executor: Arc + Send>>) + Send + Sync>, key_seed: Option, base_port: u16, root: &TempDir, @@ -183,10 +183,10 @@ fn node_config ( password: None }, config_dir: Some(root.clone()), - database: DatabaseConfig::Path { + database: Some(DatabaseConfig::Path { path: root.join("db"), cache_size: None - }, + }), state_cache_size: 16777216, state_cache_child_ratio: None, pruning: Default::default(), @@ -256,7 +256,7 @@ impl TestNet where for (key, authority) in authorities { let task_executor = { let executor = executor.clone(); - Box::new(move |fut: Pin + Send>>| executor.spawn(fut.unit_error().compat())) + Arc::new(move |fut: Pin + Send>>| executor.spawn(fut.unit_error().compat())) }; let node_config = node_config( self.nodes, @@ -280,7 +280,7 @@ impl TestNet where for full in full { let task_executor = { let executor = executor.clone(); - Box::new(move |fut: Pin + Send>>| executor.spawn(fut.unit_error().compat())) + Arc::new(move |fut: Pin + Send>>| executor.spawn(fut.unit_error().compat())) }; let node_config = node_config(self.nodes, &self.chain_spec, Roles::FULL, task_executor, None, self.base_port, &temp); let addr = node_config.network.listen_addresses.iter().next().unwrap().clone(); @@ -296,7 +296,7 @@ impl TestNet where for light in light { let task_executor = { let executor = executor.clone(); - Box::new(move |fut: Pin + Send>>| executor.spawn(fut.unit_error().compat())) + Arc::new(move |fut: Pin + Send>>| executor.spawn(fut.unit_error().compat())) }; let node_config = node_config(self.nodes, &self.chain_spec, Roles::LIGHT, task_executor, None, self.base_port, &temp); let addr = node_config.network.listen_addresses.iter().next().unwrap().clone(); diff --git a/utils/browser/src/lib.rs b/utils/browser/src/lib.rs index 4f985871f5a22..d7ffdca1aa389 100644 --- a/utils/browser/src/lib.rs +++ b/utils/browser/src/lib.rs @@ -51,18 +51,18 @@ where allow_private_ipv4: true, enable_mdns: false, }; - config.task_executor = Some(Box::new(move |fut| { + config.task_executor = Some(Arc::new(move |fut| { wasm_bindgen_futures::spawn_local(fut) })); config.telemetry_external_transport = Some(transport); config.roles = Roles::LIGHT; config.name = format!("{} (Browser)", name); - config.database = { + config.database = Some({ info!("Opening Indexed DB database '{}'...", name); let db = kvdb_web::Database::open(name, 10) .await?; DatabaseConfig::Custom(Arc::new(db)) - }; + }); config.keystore = KeystoreConfig::InMemory; Ok(config)