// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus 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. // Cumulus 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 Cumulus. If not, see . use std::{net::SocketAddr, path::PathBuf}; use polkadot_service::{ChainSpec, ParaId, PrometheusConfig}; use sc_cli::{ CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, NetworkParams, Result as CliResult, SharedParams, SubstrateCli, }; use sc_service::BasePath; #[derive(Debug, clap::Parser)] #[command( version, propagate_version = true, args_conflicts_with_subcommands = true, subcommand_negates_reqs = true )] pub struct TestCollatorCli { #[command(subcommand)] pub subcommand: Option, #[command(flatten)] pub run: cumulus_client_cli::RunCmd, #[arg(default_value_t = 2000u32)] pub parachain_id: u32, /// Relay chain arguments #[arg(raw = true)] pub relaychain_args: Vec, #[arg(long)] pub use_null_consensus: bool, #[arg(long)] pub disable_block_announcements: bool, #[arg(long)] pub fail_pov_recovery: bool, } #[derive(Debug, clap::Subcommand)] pub enum Subcommand { /// Build a chain specification. BuildSpec(sc_cli::BuildSpecCmd), /// Export the genesis state of the parachain. ExportGenesisState(ExportGenesisStateCommand), /// Export the genesis wasm of the parachain. ExportGenesisWasm(ExportGenesisWasmCommand), } #[derive(Debug, clap::Parser)] #[group(skip)] pub struct ExportGenesisStateCommand { #[arg(default_value_t = 2000u32)] pub parachain_id: u32, #[command(flatten)] pub base: cumulus_client_cli::ExportGenesisStateCommand, } impl CliConfiguration for ExportGenesisStateCommand { fn shared_params(&self) -> &SharedParams { &self.base.shared_params } } /// Command for exporting the genesis wasm file. #[derive(Debug, clap::Parser)] #[group(skip)] pub struct ExportGenesisWasmCommand { #[arg(default_value_t = 2000u32)] pub parachain_id: u32, #[command(flatten)] pub base: cumulus_client_cli::ExportGenesisWasmCommand, } impl CliConfiguration for ExportGenesisWasmCommand { fn shared_params(&self) -> &SharedParams { &self.base.shared_params } } #[derive(Debug)] pub struct RelayChainCli { /// The actual relay chain cli object. pub base: polkadot_cli::RunCmd, /// Optional chain id that should be passed to the relay chain. pub chain_id: Option, /// The base path that should be used by the relay chain. pub base_path: Option, } impl RelayChainCli { /// Parse the relay chain CLI parameters using the para chain `Configuration`. pub fn new<'a>( para_config: &sc_service::Configuration, relay_chain_args: impl Iterator, ) -> Self { let base_path = para_config.base_path.path().join("polkadot"); Self { base_path: Some(base_path), chain_id: None, base: clap::Parser::parse_from(relay_chain_args), } } } impl CliConfiguration for RelayChainCli { fn shared_params(&self) -> &SharedParams { self.base.base.shared_params() } fn import_params(&self) -> Option<&ImportParams> { self.base.base.import_params() } fn network_params(&self) -> Option<&NetworkParams> { self.base.base.network_params() } fn keystore_params(&self) -> Option<&KeystoreParams> { self.base.base.keystore_params() } fn base_path(&self) -> CliResult> { Ok(self .shared_params() .base_path()? .or_else(|| self.base_path.clone().map(Into::into))) } fn rpc_addr(&self, default_listen_port: u16) -> CliResult> { self.base.base.rpc_addr(default_listen_port) } fn prometheus_config( &self, default_listen_port: u16, chain_spec: &Box, ) -> CliResult> { self.base.base.prometheus_config(default_listen_port, chain_spec) } fn init( &self, _support_url: &String, _impl_version: &String, _logger_hook: F, _config: &sc_service::Configuration, ) -> CliResult<()> where F: FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration), { unreachable!("PolkadotCli is never initialized; qed"); } fn chain_id(&self, is_dev: bool) -> CliResult { let chain_id = self.base.base.chain_id(is_dev)?; Ok(if chain_id.is_empty() { self.chain_id.clone().unwrap_or_default() } else { chain_id }) } fn role(&self, is_dev: bool) -> CliResult { self.base.base.role(is_dev) } fn transaction_pool( &self, is_dev: bool, ) -> CliResult { self.base.base.transaction_pool(is_dev) } fn trie_cache_maximum_size(&self) -> CliResult> { self.base.base.trie_cache_maximum_size() } fn rpc_methods(&self) -> CliResult { self.base.base.rpc_methods() } fn rpc_max_connections(&self) -> CliResult { self.base.base.rpc_max_connections() } fn rpc_cors(&self, is_dev: bool) -> CliResult>> { self.base.base.rpc_cors(is_dev) } fn default_heap_pages(&self) -> CliResult> { self.base.base.default_heap_pages() } fn force_authoring(&self) -> CliResult { self.base.base.force_authoring() } fn disable_grandpa(&self) -> CliResult { self.base.base.disable_grandpa() } fn max_runtime_instances(&self) -> CliResult> { self.base.base.max_runtime_instances() } fn announce_block(&self) -> CliResult { self.base.base.announce_block() } fn telemetry_endpoints( &self, chain_spec: &Box, ) -> CliResult> { self.base.base.telemetry_endpoints(chain_spec) } fn node_name(&self) -> CliResult { self.base.base.node_name() } } impl DefaultConfigurationValues for RelayChainCli { fn p2p_listen_port() -> u16 { 30334 } fn rpc_listen_port() -> u16 { 9945 } fn prometheus_listen_port() -> u16 { 9616 } } impl SubstrateCli for TestCollatorCli { fn impl_name() -> String { "Cumulus zombienet test parachain".into() } fn impl_version() -> String { String::new() } fn description() -> String { format!( "Cumulus zombienet test parachain\n\nThe command-line arguments provided first will be \ passed to the parachain node, while the arguments provided after -- will be passed \ to the relaychain node.\n\n\ {} [parachain-args] -- [relaychain-args]", Self::executable_name() ) } fn author() -> String { env!("CARGO_PKG_AUTHORS").into() } fn support_url() -> String { "https://github.com/paritytech/polkadot-sdk/issues/new".into() } fn copyright_start_year() -> i32 { 2017 } fn load_spec(&self, id: &str) -> std::result::Result, String> { Ok(match id { "" => Box::new(cumulus_test_service::get_chain_spec(Some(ParaId::from( self.parachain_id, )))) as Box<_>, path => { let chain_spec = cumulus_test_service::chain_spec::ChainSpec::from_json_file(path.into())?; Box::new(chain_spec) }, }) } } impl SubstrateCli for RelayChainCli { fn impl_name() -> String { "Polkadot collator".into() } fn impl_version() -> String { String::new() } fn description() -> String { format!( "Polkadot collator\n\nThe command-line arguments provided first will be \ passed to the parachain node, while the arguments provided after -- will be passed \ to the relay chain node.\n\n\ {} [parachain-args] -- [relay_chain-args]", Self::executable_name() ) } fn author() -> String { env!("CARGO_PKG_AUTHORS").into() } fn support_url() -> String { "https://github.com/paritytech/polkadot-sdk/issues/new".into() } fn copyright_start_year() -> i32 { 2017 } fn load_spec(&self, id: &str) -> std::result::Result, String> { ::from_iter([RelayChainCli::executable_name()].iter()) .load_spec(id) } }