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" ...@@ -6,7 +6,6 @@ path = "src/main.rs"
name = "polkadot" name = "polkadot"
version = "0.7.29-pre1" version = "0.7.29-pre1"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
build = "build.rs"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
...@@ -15,9 +14,6 @@ futures = "0.3.4" ...@@ -15,9 +14,6 @@ futures = "0.3.4"
service = { package = "polkadot-service", path = "service" } service = { package = "polkadot-service", path = "service" }
parity-util-mem = { version = "*", default-features = false, features = ["jemalloc-global"] } parity-util-mem = { version = "*", default-features = false, features = ["jemalloc-global"] }
[build-dependencies]
vergen = "3.0.4"
[dev-dependencies] [dev-dependencies]
assert_cmd = "0.12" assert_cmd = "0.12"
nix = "0.17" nix = "0.17"
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
name = "polkadot-cli" name = "polkadot-cli"
version = "0.7.29-pre1" version = "0.7.29-pre1"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
description = "Polkadot node implementation in Rust." description = "Polkadot Relay-chain Client Node"
edition = "2018" edition = "2018"
[package.metadata.wasm-pack.profile.release] [package.metadata.wasm-pack.profile.release]
...@@ -29,11 +29,15 @@ service = { package = "polkadot-service", path = "../service", default-features ...@@ -29,11 +29,15 @@ service = { package = "polkadot-service", path = "../service", default-features
tokio = { version = "0.2.13", features = ["rt-threaded"], optional = true } tokio = { version = "0.2.13", features = ["rt-threaded"], optional = true }
frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master", 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-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 = { version = "0.2.57", optional = true }
wasm-bindgen-futures = { version = "0.4.7", 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 } 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] [features]
default = [ "wasmtime", "rocksdb", "cli" ] default = [ "wasmtime", "rocksdb", "cli" ]
wasmtime = [ "sc-cli/wasmtime" ] wasmtime = [ "sc-cli/wasmtime" ]
...@@ -41,6 +45,7 @@ rocksdb = [ "service/rocksdb" ] ...@@ -41,6 +45,7 @@ rocksdb = [ "service/rocksdb" ]
cli = [ cli = [
"tokio", "tokio",
"sc-cli", "sc-cli",
"sc-service",
"frame-benchmarking-cli", "frame-benchmarking-cli",
"service/full-node", "service/full-node",
] ]
......
...@@ -14,13 +14,6 @@ ...@@ -14,13 +14,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>. // 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() { fn main() {
generate_cargo_keys(ConstantsFlags::all()).expect(ERROR_MSG); substrate_build_script_utils::generate_cargo_keys();
println!("cargo:rerun-if-changed=.git/HEAD");
} }
...@@ -39,10 +39,10 @@ async fn start_inner(chain_spec: String, log_level: String) -> Result<Client, Bo ...@@ -39,10 +39,10 @@ async fn start_inner(chain_spec: String, log_level: String) -> Result<Client, Bo
let config = browser_configuration(chain_spec).await?; let config = browser_configuration(chain_spec).await?;
info!("Polkadot browser node"); info!("Polkadot browser node");
info!(" version {}", config.full_version()); info!(" version {}", config.impl_version);
info!(" by Parity Technologies, 2017-2020"); info!(" by Parity Technologies, 2017-2020");
info!("📋 Chain specification: {}", config.expect_chain_spec().name()); info!("📋 Chain specification: {}", config.chain_spec.name());
info!("🏷 Node name: {}", config.name); info!("🏷 Node name: {}", config.network.node_name);
info!("👤 Role: {}", config.display_role()); info!("👤 Role: {}", config.display_role());
// Create the service. This is the most heavy initialization step. // 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 { ...@@ -54,23 +54,6 @@ pub struct RunCmd {
/// Force using Kusama native runtime. /// Force using Kusama native runtime.
#[structopt(long = "force-kusama")] #[structopt(long = "force-kusama")]
pub force_kusama: bool, 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)] #[allow(missing_docs)]
#[structopt(long = "enable-authority-discovery")] #[structopt(long = "enable-authority-discovery")]
...@@ -85,3 +68,15 @@ pub struct Cli { ...@@ -85,3 +68,15 @@ pub struct Cli {
#[structopt(long = "grandpa-pause", number_of_values(2))] #[structopt(long = "grandpa-pause", number_of_values(2))]
pub grandpa_pause: Vec<u32>, 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; ...@@ -18,44 +18,58 @@ use log::info;
use sp_runtime::traits::BlakeTwo256; use sp_runtime::traits::BlakeTwo256;
use service::{IsKusama, Block, self, RuntimeApiCollection, TFullClient}; use service::{IsKusama, Block, self, RuntimeApiCollection, TFullClient};
use sp_api::ConstructRuntimeApi; use sp_api::ConstructRuntimeApi;
use sc_cli::{SubstrateCli, Result};
use sc_executor::NativeExecutionDispatch; use sc_executor::NativeExecutionDispatch;
use crate::chain_spec::load_spec;
use crate::cli::{Cli, Subcommand}; 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. /// Parses polkadot specific CLI arguments and run the service.
pub fn run(version: VersionInfo) -> sc_cli::Result<()> { pub fn run() -> Result<()> {
let opt = sc_cli::from_args::<Cli>(&version); let cli = Cli::from_args();
let mut config = service::Configuration::from_version(&version); match &cli.subcommand {
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 {
None => { None => {
opt.run.base.init(&version)?; let runtime = cli.create_runner(&cli.run.base)?;
opt.run.base.update_config( let config = runtime.config();
&mut config, let is_kusama = config.chain_spec.is_kusama();
|id| load_spec(id, force_kusama), let authority_discovery_enabled = cli.run.authority_discovery_enabled;
&version let grandpa_pause = if cli.run.grandpa_pause.is_empty() {
)?; None
} else {
let is_kusama = config.expect_chain_spec().is_kusama(); Some((cli.run.grandpa_pause[0], cli.run.grandpa_pause[1]))
};
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());
if is_kusama { if is_kusama {
info!("⛓ Native runtime: {}", service::KusamaExecutor::native_version().runtime_version); info!("⛓ Native runtime: {}", service::KusamaExecutor::native_version().runtime_version);
...@@ -65,71 +79,73 @@ pub fn run(version: VersionInfo) -> sc_cli::Result<()> { ...@@ -65,71 +79,73 @@ pub fn run(version: VersionInfo) -> sc_cli::Result<()> {
info!(" KUSAMA FOUNDATION "); info!(" KUSAMA FOUNDATION ");
info!("----------------------------"); info!("----------------------------");
run_service_until_exit::< run_node::<
service::kusama_runtime::RuntimeApi, service::kusama_runtime::RuntimeApi,
service::KusamaExecutor, service::KusamaExecutor,
service::kusama_runtime::UncheckedExtrinsic, service::kusama_runtime::UncheckedExtrinsic,
>(config, opt.authority_discovery_enabled, grandpa_pause) >(runtime, authority_discovery_enabled, grandpa_pause)
} else { } else {
info!("⛓ Native runtime: {}", service::PolkadotExecutor::native_version().runtime_version); info!("⛓ Native runtime: {}", service::PolkadotExecutor::native_version().runtime_version);
run_service_until_exit::< run_node::<
service::polkadot_runtime::RuntimeApi, service::polkadot_runtime::RuntimeApi,
service::PolkadotExecutor, service::PolkadotExecutor,
service::polkadot_runtime::UncheckedExtrinsic, service::polkadot_runtime::UncheckedExtrinsic,
>(config, opt.authority_discovery_enabled, grandpa_pause) >(runtime, authority_discovery_enabled, grandpa_pause)
} }
}, },
Some(Subcommand::Base(cmd)) => { Some(Subcommand::Base(subcommand)) => {
cmd.init(&version)?; let runtime = cli.create_runner(subcommand)?;
cmd.update_config( let is_kusama = runtime.config().chain_spec.is_kusama();
&mut config,
|id| load_spec(id, force_kusama),
&version
)?;
let is_kusama = config.expect_chain_spec().is_kusama();
if is_kusama { if is_kusama {
cmd.run(config, service::new_chain_ops::< runtime.run_subcommand(subcommand, |config|
service::kusama_runtime::RuntimeApi, service::new_chain_ops::<
service::KusamaExecutor, service::kusama_runtime::RuntimeApi,
service::kusama_runtime::UncheckedExtrinsic, service::KusamaExecutor,
>) service::kusama_runtime::UncheckedExtrinsic,
>(config)
)
} else { } else {
cmd.run(config, service::new_chain_ops::< runtime.run_subcommand(subcommand, |config|
service::polkadot_runtime::RuntimeApi, service::new_chain_ops::<
service::PolkadotExecutor, service::polkadot_runtime::RuntimeApi,
service::polkadot_runtime::UncheckedExtrinsic, service::PolkadotExecutor,
>) service::polkadot_runtime::UncheckedExtrinsic,
>(config)
)
} }
}, },
Some(Subcommand::ValidationWorker(args)) => { Some(Subcommand::ValidationWorker(cmd)) => {
sc_cli::init_logger(""); sc_cli::init_logger("");
if cfg!(feature = "browser") { if cfg!(feature = "browser") {
Err(sc_cli::Error::Input("Cannot run validation worker in browser".into())) Err(sc_cli::Error::Input("Cannot run validation worker in browser".into()))
} else { } else {
#[cfg(not(feature = "browser"))] #[cfg(not(feature = "browser"))]
service::run_validation_worker(&args.mem_id)?; service::run_validation_worker(&cmd.mem_id)?;
Ok(()) Ok(())
} }
}, },
Some(Subcommand::Benchmark(cmd)) => { Some(Subcommand::Benchmark(cmd)) => {
cmd.init(&version)?; let runtime = cli.create_runner(cmd)?;
cmd.update_config(&mut config, |id| load_spec(id, force_kusama), &version)?; let is_kusama = runtime.config().chain_spec.is_kusama();
let is_kusama = config.expect_chain_spec().is_kusama();
if 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 { } 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>( fn run_node<R, D, E>(
config: service::Configuration, runtime: sc_cli::Runner<Cli>,
authority_discovery_enabled: bool, authority_discovery_enabled: bool,
grandpa_pause: Option<(u32, u32)>, grandpa_pause: Option<(u32, u32)>,
) -> sc_cli::Result<()> ) -> sc_cli::Result<()>
...@@ -151,26 +167,17 @@ where ...@@ -151,26 +167,17 @@ where
TLightClient<R, D> TLightClient<R, D>
>, >,
{ {
match config.role { runtime.run_node(
service::Role::Light => |config| service::new_light::<R, D, E>(config),
sc_cli::run_service_until_exit( |config| service::new_full::<R, D, E>(
config, config,
|config| service::new_light::<R, D, E>(config), None,
), None,
_ => authority_discovery_enabled,
sc_cli::run_service_until_exit( 6000,
config, grandpa_pause,
|config| service::new_full::<R, D, E>( ).map(|(s, _)| s),
config, )
None,
None,
authority_discovery_enabled,
6000,
grandpa_pause,
)
.map(|(s, _)| s),
),
}
} }
// We can't simply use `service::TLightClient` due to a // We can't simply use `service::TLightClient` due to a
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#![warn(missing_docs)] #![warn(missing_docs)]
#![warn(unused_extern_crates)] #![warn(unused_extern_crates)]
mod chain_spec;
#[cfg(feature = "browser")] #[cfg(feature = "browser")]
mod browser; mod browser;
#[cfg(feature = "cli")] #[cfg(feature = "cli")]
...@@ -38,7 +37,5 @@ pub use cli::*; ...@@ -38,7 +37,5 @@ pub use cli::*;
#[cfg(feature = "cli")] #[cfg(feature = "cli")]
pub use command::*; pub use command::*;
pub use chain_spec::*;
#[cfg(feature = "cli")] #[cfg(feature = "cli")]
pub use sc_cli::{VersionInfo, Error, Result}; pub use sc_cli::{Error, Result};
...@@ -66,11 +66,13 @@ use polkadot_cli::{ ...@@ -66,11 +66,13 @@ use polkadot_cli::{
ProvideRuntimeApi, AbstractService, ParachainHost, IsKusama, ProvideRuntimeApi, AbstractService, ParachainHost, IsKusama,
service::{self, Role} 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_validation::SignedStatement;
pub use polkadot_primitives::parachain::CollatorId; pub use polkadot_primitives::parachain::CollatorId;
pub use sc_network::PeerId; pub use sc_network::PeerId;
pub use service::RuntimeApiCollection; pub use service::RuntimeApiCollection;
pub use sc_cli::SubstrateCli;
const COLLATION_TIMEOUT: Duration = Duration::from_secs(30); const COLLATION_TIMEOUT: Duration = Duration::from_secs(30);
...@@ -348,7 +350,7 @@ where ...@@ -348,7 +350,7 @@ where
P::ParachainContext: Send + 'static, P::ParachainContext: Send + 'static,
<P::ParachainContext as ParachainContext>::ProduceCandidate: Send, <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) { match (is_kusama, &config.role) {
(_, Role::Light) => return Err( (_, Role::Light) => return Err(
polkadot_service::Error::Other("light nodes are unsupported as collator".into()) 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 ...@@ -380,45 +382,6 @@ fn compute_targets(para_id: ParaId, session_keys: &[ValidatorId], roster: DutyRo
.collect() .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) {