Unverified Commit bee86bba authored by Cecile Tonglet's avatar Cecile Tonglet Committed by GitHub
Browse files

Update cli to new sc-cli API (#935)

* Initial commit

Forked at: 77de8b91
Parent branch: origin/master

* Switch substrate to branch cecton-the-revenge-of-the-cli

* Adapting code

* Update Cargo.lock

* Adapting code

* Adapt more code

* Implement force_kusama parameter

* Revert dependency update

* Adapt code to use ref to SubstrateCli object

* Updated to latest version

* Updated with latest changes

* Bump spec vesion

* Fixed tests

* WIP

Forked at: 77de8b91
Parent branch: origin/master

* More fixes

* Cargo.lock

* Updated code

* Fixed and adapt

* Fixed dependency issue with wasm

* Adapted code

* Revert branch change

* Cargo.lock

* Cargo.lock

* Adapt code

* Clean-up

* More clean-up

* Cargo.lock
parent cda8004c
Pipeline #86844 passed with stages
in 28 minutes and 15 seconds
This diff is collapsed.
......@@ -6,7 +6,6 @@ path = "src/main.rs"
name = "polkadot"
version = "0.7.29-pre1"
authors = ["Parity Technologies <admin@parity.io>"]
build = "build.rs"
edition = "2018"
[dependencies]
......@@ -15,9 +14,6 @@ futures = "0.3.4"
service = { package = "polkadot-service", path = "service" }
parity-util-mem = { version = "*", default-features = false, features = ["jemalloc-global"] }
[build-dependencies]
vergen = "3.0.4"
[dev-dependencies]
assert_cmd = "0.12"
nix = "0.17"
......
......@@ -2,7 +2,7 @@
name = "polkadot-cli"
version = "0.7.29-pre1"
authors = ["Parity Technologies <admin@parity.io>"]
description = "Polkadot node implementation in Rust."
description = "Polkadot Relay-chain Client Node"
edition = "2018"
[package.metadata.wasm-pack.profile.release]
......@@ -29,11 +29,15 @@ service = { package = "polkadot-service", path = "../service", default-features
tokio = { version = "0.2.13", features = ["rt-threaded"], optional = true }
frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
sc-service = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
wasm-bindgen = { version = "0.2.57", optional = true }
wasm-bindgen-futures = { version = "0.4.7", optional = true }
browser-utils = { package = "substrate-browser-utils", git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
[build-dependencies]
substrate-build-script-utils = { git = "https://github.com/paritytech/substrate", branch = "master" }
[features]
default = [ "wasmtime", "rocksdb", "cli" ]
wasmtime = [ "sc-cli/wasmtime" ]
......@@ -41,6 +45,7 @@ rocksdb = [ "service/rocksdb" ]
cli = [
"tokio",
"sc-cli",
"sc-service",
"frame-benchmarking-cli",
"service/full-node",
]
......
......@@ -14,13 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
extern crate vergen;
use vergen::{ConstantsFlags, generate_cargo_keys};
const ERROR_MSG: &'static str = "Failed to generate metadata files";
fn main() {
generate_cargo_keys(ConstantsFlags::all()).expect(ERROR_MSG);
println!("cargo:rerun-if-changed=.git/HEAD");
substrate_build_script_utils::generate_cargo_keys();
}
......@@ -39,10 +39,10 @@ async fn start_inner(chain_spec: String, log_level: String) -> Result<Client, Bo
let config = browser_configuration(chain_spec).await?;
info!("Polkadot browser node");
info!(" version {}", config.full_version());
info!(" version {}", config.impl_version);
info!(" by Parity Technologies, 2017-2020");
info!("📋 Chain specification: {}", config.expect_chain_spec().name());
info!("🏷 Node name: {}", config.name);
info!("📋 Chain specification: {}", config.chain_spec.name());
info!("🏷 Node name: {}", config.network.node_name);
info!("👤 Role: {}", config.display_role());
// Create the service. This is the most heavy initialization step.
......
// Copyright 2017-2020 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot 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.
// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Predefined chains.
use service;
/// The chain specification (this should eventually be replaced by a more general JSON-based chain
/// specification).
#[derive(Clone, Debug)]
pub enum ChainSpec {
/// Whatever the current polkadot runtime is, with just Alice as an auth.
PolkadotDevelopment,
/// Whatever the current pokadot runtime is, with simple Alice/Bob auths.
PolkadotLocalTestnet,
/// The Kusama network.
Kusama,
/// Whatever the current kusama runtime is, with just Alice as an auth.
KusamaDevelopment,
/// The Westend network,
Westend,
/// Whatever the current polkadot runtime is with the "global testnet" defaults.
PolkadotStagingTestnet,
/// Whatever the current kusama runtime is with the "global testnet" defaults.
KusamaStagingTestnet,
/// Whatever the current kusama runtime is, with simple Alice/Bob auths.
KusamaLocalTestnet,
}
impl Default for ChainSpec {
fn default() -> Self {
ChainSpec::Kusama
}
}
/// Get a chain config from a spec setting.
impl ChainSpec {
pub(crate) fn load(self) -> Result<Box<dyn service::ChainSpec>, String> {
Ok(match self {
ChainSpec::PolkadotDevelopment => Box::new(service::chain_spec::polkadot_development_config()),
ChainSpec::PolkadotLocalTestnet => Box::new(service::chain_spec::polkadot_local_testnet_config()),
ChainSpec::PolkadotStagingTestnet => Box::new(service::chain_spec::polkadot_staging_testnet_config()),
ChainSpec::KusamaDevelopment =>Box::new(service::chain_spec::kusama_development_config()),
ChainSpec::KusamaLocalTestnet => Box::new(service::chain_spec::kusama_local_testnet_config()),
ChainSpec::KusamaStagingTestnet => Box::new(service::chain_spec::kusama_staging_testnet_config()),
ChainSpec::Westend => Box::new(service::chain_spec::westend_config()?),
ChainSpec::Kusama => Box::new(service::chain_spec::kusama_config()?),
})
}
pub(crate) fn from(s: &str) -> Option<Self> {
match s {
"polkadot-dev" | "dev" => Some(ChainSpec::PolkadotDevelopment),
"polkadot-local" => Some(ChainSpec::PolkadotLocalTestnet),
"polkadot-staging" => Some(ChainSpec::PolkadotStagingTestnet),
"kusama-dev" => Some(ChainSpec::KusamaDevelopment),
"kusama-local" => Some(ChainSpec::KusamaLocalTestnet),
"kusama-staging" => Some(ChainSpec::KusamaStagingTestnet),
"kusama" => Some(ChainSpec::Kusama),
"westend" => Some(ChainSpec::Westend),
"" => Some(ChainSpec::default()),
_ => None,
}
}
}
/// Load the `ChainSpec` for the given `id`.
/// `force_kusama` treats chain specs coming from a file as kusama specs.
pub fn load_spec(id: &str, force_kusama: bool) -> Result<Box<dyn service::ChainSpec>, String> {
Ok(match ChainSpec::from(id) {
Some(spec) => spec.load()?,
None if force_kusama => Box::new(service::KusamaChainSpec::from_json_file(std::path::PathBuf::from(id))?),
None => Box::new(service::PolkadotChainSpec::from_json_file(std::path::PathBuf::from(id))?),
})
}
......@@ -54,23 +54,6 @@ pub struct RunCmd {
/// Force using Kusama native runtime.
#[structopt(long = "force-kusama")]
pub force_kusama: bool,
}
#[allow(missing_docs)]
#[derive(Debug, StructOpt, Clone)]
#[structopt(settings = &[
structopt::clap::AppSettings::GlobalVersion,
structopt::clap::AppSettings::ArgsNegateSubcommands,
structopt::clap::AppSettings::SubcommandsNegateReqs,
])]
pub struct Cli {
#[allow(missing_docs)]
#[structopt(subcommand)]
pub subcommand: Option<Subcommand>,
#[allow(missing_docs)]
#[structopt(flatten)]
pub run: RunCmd,
#[allow(missing_docs)]
#[structopt(long = "enable-authority-discovery")]
......@@ -85,3 +68,15 @@ pub struct Cli {
#[structopt(long = "grandpa-pause", number_of_values(2))]
pub grandpa_pause: Vec<u32>,
}
#[allow(missing_docs)]
#[derive(Debug, StructOpt, Clone)]
pub struct Cli {
#[allow(missing_docs)]
#[structopt(subcommand)]
pub subcommand: Option<Subcommand>,
#[allow(missing_docs)]
#[structopt(flatten)]
pub run: RunCmd,
}
......@@ -18,44 +18,58 @@ use log::info;
use sp_runtime::traits::BlakeTwo256;
use service::{IsKusama, Block, self, RuntimeApiCollection, TFullClient};
use sp_api::ConstructRuntimeApi;
use sc_cli::{SubstrateCli, Result};
use sc_executor::NativeExecutionDispatch;
use crate::chain_spec::load_spec;
use crate::cli::{Cli, Subcommand};
use sc_cli::VersionInfo;
impl SubstrateCli for Cli {
fn impl_name() -> &'static str { "parity-polkadot" }
fn impl_version() -> &'static str { env!("SUBSTRATE_CLI_IMPL_VERSION") }
fn description() -> &'static str { env!("CARGO_PKG_DESCRIPTION") }
fn author() -> &'static str { env!("CARGO_PKG_AUTHORS") }
fn support_url() -> &'static str { "https://github.com/paritytech/polkadot/issues/new" }
fn copyright_start_year() -> i32 { 2017 }
fn executable_name() -> &'static str { "polkadot" }
fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
Ok(match id {
"polkadot-dev" | "dev" => Box::new(service::chain_spec::polkadot_development_config()),
"polkadot-local" => Box::new(service::chain_spec::polkadot_local_testnet_config()),
"polkadot-staging" => Box::new(service::chain_spec::polkadot_staging_testnet_config()),
"kusama-dev" => Box::new(service::chain_spec::kusama_development_config()),
"kusama-local" => Box::new(service::chain_spec::kusama_local_testnet_config()),
"kusama-staging" => Box::new(service::chain_spec::kusama_staging_testnet_config()),
"westend" => Box::new(service::chain_spec::westend_config()?),
"kusama" | "" => Box::new(service::chain_spec::kusama_config()?),
path if self.run.force_kusama => {
Box::new(service::KusamaChainSpec::from_json_file(std::path::PathBuf::from(path))?)
},
path => Box::new(service::PolkadotChainSpec::from_json_file(std::path::PathBuf::from(path))?),
})
}
}
/// Parses polkadot specific CLI arguments and run the service.
pub fn run(version: VersionInfo) -> sc_cli::Result<()> {
let opt = sc_cli::from_args::<Cli>(&version);
let mut config = service::Configuration::from_version(&version);
config.impl_name = "parity-polkadot";
let force_kusama = opt.run.force_kusama;
let grandpa_pause = if opt.grandpa_pause.is_empty() {
None
} else {
// should be enforced by cli parsing
assert_eq!(opt.grandpa_pause.len(), 2);
Some((opt.grandpa_pause[0], opt.grandpa_pause[1]))
};
match opt.subcommand {
pub fn run() -> Result<()> {
let cli = Cli::from_args();
match &cli.subcommand {
None => {
opt.run.base.init(&version)?;
opt.run.base.update_config(
&mut config,
|id| load_spec(id, force_kusama),
&version
)?;
let is_kusama = config.expect_chain_spec().is_kusama();
info!("{}", version.name);
info!(" version {}", config.full_version());
info!(" by {}, 2017-2020", version.author);
info!("📋 Chain specification: {}", config.expect_chain_spec().name());
info!("🏷 Node name: {}", config.name);
info!("👤 Role: {}", config.display_role());
let runtime = cli.create_runner(&cli.run.base)?;
let config = runtime.config();
let is_kusama = config.chain_spec.is_kusama();
let authority_discovery_enabled = cli.run.authority_discovery_enabled;
let grandpa_pause = if cli.run.grandpa_pause.is_empty() {
None
} else {
Some((cli.run.grandpa_pause[0], cli.run.grandpa_pause[1]))
};
if is_kusama {
info!("⛓ Native runtime: {}", service::KusamaExecutor::native_version().runtime_version);
......@@ -65,71 +79,73 @@ pub fn run(version: VersionInfo) -> sc_cli::Result<()> {
info!(" KUSAMA FOUNDATION ");
info!("----------------------------");
run_service_until_exit::<
run_node::<
service::kusama_runtime::RuntimeApi,
service::KusamaExecutor,
service::kusama_runtime::UncheckedExtrinsic,
>(config, opt.authority_discovery_enabled, grandpa_pause)
>(runtime, authority_discovery_enabled, grandpa_pause)
} else {
info!("⛓ Native runtime: {}", service::PolkadotExecutor::native_version().runtime_version);
run_service_until_exit::<
run_node::<
service::polkadot_runtime::RuntimeApi,
service::PolkadotExecutor,
service::polkadot_runtime::UncheckedExtrinsic,
>(config, opt.authority_discovery_enabled, grandpa_pause)
>(runtime, authority_discovery_enabled, grandpa_pause)
}
},
Some(Subcommand::Base(cmd)) => {
cmd.init(&version)?;
cmd.update_config(
&mut config,
|id| load_spec(id, force_kusama),
&version
)?;
let is_kusama = config.expect_chain_spec().is_kusama();
Some(Subcommand::Base(subcommand)) => {
let runtime = cli.create_runner(subcommand)?;
let is_kusama = runtime.config().chain_spec.is_kusama();
if is_kusama {
cmd.run(config, service::new_chain_ops::<
service::kusama_runtime::RuntimeApi,
service::KusamaExecutor,
service::kusama_runtime::UncheckedExtrinsic,
>)
runtime.run_subcommand(subcommand, |config|
service::new_chain_ops::<
service::kusama_runtime::RuntimeApi,
service::KusamaExecutor,
service::kusama_runtime::UncheckedExtrinsic,
>(config)
)
} else {
cmd.run(config, service::new_chain_ops::<
service::polkadot_runtime::RuntimeApi,
service::PolkadotExecutor,
service::polkadot_runtime::UncheckedExtrinsic,
>)
runtime.run_subcommand(subcommand, |config|
service::new_chain_ops::<
service::polkadot_runtime::RuntimeApi,
service::PolkadotExecutor,
service::polkadot_runtime::UncheckedExtrinsic,
>(config)
)
}
},
Some(Subcommand::ValidationWorker(args)) => {
Some(Subcommand::ValidationWorker(cmd)) => {
sc_cli::init_logger("");
if cfg!(feature = "browser") {
Err(sc_cli::Error::Input("Cannot run validation worker in browser".into()))
} else {
#[cfg(not(feature = "browser"))]
service::run_validation_worker(&args.mem_id)?;
service::run_validation_worker(&cmd.mem_id)?;
Ok(())
}
},
Some(Subcommand::Benchmark(cmd)) => {
cmd.init(&version)?;
cmd.update_config(&mut config, |id| load_spec(id, force_kusama), &version)?;
let is_kusama = config.expect_chain_spec().is_kusama();
let runtime = cli.create_runner(cmd)?;
let is_kusama = runtime.config().chain_spec.is_kusama();
if is_kusama {
cmd.run::<service::kusama_runtime::Block, service::KusamaExecutor>(config)
runtime.sync_run(|config| {
cmd.run::<service::kusama_runtime::Block, service::KusamaExecutor>(config)
})
} else {
cmd.run::<service::polkadot_runtime::Block, service::PolkadotExecutor>(config)
runtime.sync_run(|config| {
cmd.run::<service::polkadot_runtime::Block, service::PolkadotExecutor>(config)
})
}
},
}
}
fn run_service_until_exit<R, D, E>(
config: service::Configuration,
fn run_node<R, D, E>(
runtime: sc_cli::Runner<Cli>,
authority_discovery_enabled: bool,
grandpa_pause: Option<(u32, u32)>,
) -> sc_cli::Result<()>
......@@ -151,26 +167,17 @@ where
TLightClient<R, D>
>,
{
match config.role {
service::Role::Light =>
sc_cli::run_service_until_exit(
config,
|config| service::new_light::<R, D, E>(config),
),
_ =>
sc_cli::run_service_until_exit(
config,
|config| service::new_full::<R, D, E>(
config,
None,
None,
authority_discovery_enabled,
6000,
grandpa_pause,
)
.map(|(s, _)| s),
),
}
runtime.run_node(
|config| service::new_light::<R, D, E>(config),
|config| service::new_full::<R, D, E>(
config,
None,
None,
authority_discovery_enabled,
6000,
grandpa_pause,
).map(|(s, _)| s),
)
}
// We can't simply use `service::TLightClient` due to a
......
......@@ -19,7 +19,6 @@
#![warn(missing_docs)]
#![warn(unused_extern_crates)]
mod chain_spec;
#[cfg(feature = "browser")]
mod browser;
#[cfg(feature = "cli")]
......@@ -38,7 +37,5 @@ pub use cli::*;
#[cfg(feature = "cli")]
pub use command::*;
pub use chain_spec::*;
#[cfg(feature = "cli")]
pub use sc_cli::{VersionInfo, Error, Result};
pub use sc_cli::{Error, Result};
......@@ -66,11 +66,13 @@ use polkadot_cli::{
ProvideRuntimeApi, AbstractService, ParachainHost, IsKusama,
service::{self, Role}
};
pub use polkadot_cli::{VersionInfo, load_spec, service::Configuration};
pub use polkadot_cli::service::Configuration;
pub use polkadot_cli::Cli;
pub use polkadot_validation::SignedStatement;
pub use polkadot_primitives::parachain::CollatorId;
pub use sc_network::PeerId;
pub use service::RuntimeApiCollection;
pub use sc_cli::SubstrateCli;
const COLLATION_TIMEOUT: Duration = Duration::from_secs(30);
......@@ -348,7 +350,7 @@ where
P::ParachainContext: Send + 'static,
<P::ParachainContext as ParachainContext>::ProduceCandidate: Send,
{
let is_kusama = config.expect_chain_spec().is_kusama();
let is_kusama = config.chain_spec.is_kusama();
match (is_kusama, &config.role) {
(_, Role::Light) => return Err(
polkadot_service::Error::Other("light nodes are unsupported as collator".into())
......@@ -380,45 +382,6 @@ fn compute_targets(para_id: ParaId, session_keys: &[ValidatorId], roster: DutyRo
.collect()
}
/// Run a collator node with the given `RelayChainContext` and `ParachainContext`
/// built by the given `BuildParachainContext` and arguments to the underlying polkadot node.
///
/// This function blocks until done.
pub fn run_collator<P>(
build_parachain_context: P,
para_id: ParaId,
key: Arc<CollatorPair>,
config: Configuration,
) -> polkadot_cli::Result<()> where
P: BuildParachainContext,
P::ParachainContext: Send + 'static,
<P::ParachainContext as ParachainContext>::ProduceCandidate: Send,
{
match (config.expect_chain_spec().is_kusama(), &config.role) {
(_, Role::Light) => return Err(
polkadot_cli::Error::Input("light nodes are unsupported as collator".into())
).into(),
(true, _) =>
sc_cli::run_service_until_exit(config, |config| {
build_collator_service(
service::kusama_new_full(config, Some((key.public(), para_id)), None, false, 6000, None)?,
para_id,
key,
build_parachain_context,
)
}),
(false, _) =>
sc_cli::run_service_until_exit(config, |config| {
build_collator_service(
service::polkadot_new_full(config, Some((key.public(), para_id)), None, false, 6000, None)?,
para_id,
key,
build_parachain_context,
)
}),
}
}
#[cfg(test)]
mod tests {
use super::*;
......@@ -463,11 +426,15 @@ mod tests {
fn start_collator_is_send() {
fn check_send<T: Send>(_: T) {}
let cli = Cli::from_iter(&["-dev"]);
let task_executor = Arc::new(|_| unimplemented!());
let config = cli.create_configuration(&cli.run.base, task_executor).unwrap();
check_send(start_collator(
BuildDummyParachainContext,
0.into(),
Arc::new(CollatorPair::generate().0),
Default::default(),
config,
));
}
}
......@@ -570,14 +570,18 @@ pub trait TestNetFactory: Sized {
let listen_addr = build_multiaddr![Memory(rand::random::<u64>())];
let mut network_config = NetworkConfiguration::new(
"test-node",
"test-client",
Default::default(),
&std::env::current_dir().expect("current directory must exist"),
);
network_config.listen_addresses = vec![listen_addr.clone()];
network_config.transport = TransportConfig::MemoryOnly;
let network = NetworkWorker::new(sc_network::config::Params {
role: Role::Full,
executor: None,
network_config: NetworkConfiguration {
listen_addresses: vec![listen_addr.clone()],
transport: TransportConfig::MemoryOnly,
..NetworkConfiguration::default()
},
network_config,
chain: client.clone(),
finality_proof_provider: self.make_finality_proof_provider(
PeersClient::Full(client.clone(), backend.clone()),
......@@ -641,14 +645,18 @@ pub trait TestNetFactory: Sized {
let listen_addr = build_multiaddr![Memory(rand::random::<u64>())];
let mut network_config = NetworkConfiguration::new(
"test-node",
"test-client",
Default::default(),
&std::env::current_dir().expect("current directory must exist"),
);
network_config.listen_addresses = vec![listen_addr.clone()];
network_config.transport = TransportConfig::MemoryOnly;
let network = NetworkWorker::new(sc_network::config::Params {
role: Role::Full,
executor: None,
network_config: NetworkConfiguration {
listen_addresses: vec![listen_addr.clone()],
transport: TransportConfig::MemoryOnly,
..NetworkConfiguration::default()
},
network_config,
chain: client.clone(),
finality_proof_provider: self.make_finality_proof_provider(
PeersClient::Light(client.clone(), backend.clone())
......
......@@ -27,10 +27,10 @@ use primitives::{
parachain::{HeadData, BlockData, Id as ParaId, LocalValidationData, GlobalValidationSchedule},
};
use collator::{
InvalidHead, ParachainContext, Network, BuildParachainContext, load_spec, Configuration,
InvalidHead, ParachainContext, Network, BuildParachainContext, Cli, SubstrateCli,
};
use parking_lot::Mutex;