// Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute // This file is part of Pezcumulus. // Pezcumulus 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. // Pezcumulus 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 Pezcumulus. If not, see . use clap::ValueEnum; use pezcumulus_client_cli::{ExportGenesisHeadCommand, ExportGenesisWasmCommand}; use pezkuwi_service::{ChainSpec, ParaId, PrometheusConfig}; use pezsc_cli::{ BizinikiwiCli, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, NetworkParams, Result as CliResult, RpcEndpoint, SharedParams, }; use pezsc_service::BasePath; use std::{ fmt::{Display, Formatter}, path::PathBuf, }; #[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: pezcumulus_client_cli::RunCmd, /// Relay chain arguments #[arg(raw = true)] pub relaychain_args: Vec, #[arg(long)] pub disable_block_announcements: bool, #[arg(long)] pub fail_pov_recovery: bool, /// Authoring style to use. #[arg(long, default_value_t = AuthoringPolicy::Lookahead)] pub authoring: AuthoringPolicy, } /// Collator implementation to use. #[derive(PartialEq, Debug, ValueEnum, Clone, Copy)] pub enum AuthoringPolicy { /// Use the lookahead collator. Builds blocks once per relay chain block, /// builds on relay chain forks. Lookahead, /// Use the slot-based collator which can handle elastic-scaling. Builds blocks based on time /// and can utilize multiple cores, always builds on the best relay chain block available. SlotBased, } impl Display for AuthoringPolicy { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { AuthoringPolicy::Lookahead => write!(f, "lookahead"), AuthoringPolicy::SlotBased => write!(f, "slot-based"), } } } #[derive(Debug, clap::Subcommand)] pub enum Subcommand { /// Build a chain specification. /// DEPRECATED: `build-spec` command will be removed after 1/04/2026. Use `export-chain-spec` /// command instead. #[deprecated( note = "build-spec command will be removed after 1/04/2026. Use export-chain-spec command instead" )] BuildSpec(pezsc_cli::BuildSpecCmd), /// Export the chain specification. ExportChainSpec(pezsc_cli::ExportChainSpecCmd), /// Export the genesis state of the teyrchain. #[command(alias = "export-genesis-state")] ExportGenesisHead(ExportGenesisHeadCommand), /// Export the genesis wasm of the teyrchain. ExportGenesisWasm(ExportGenesisWasmCommand), } #[derive(Debug)] pub struct RelayChainCli { /// The actual relay chain cli object. pub base: pezkuwi_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: &pezsc_service::Configuration, relay_chain_args: impl Iterator, ) -> Self { let base_path = para_config.base_path.path().join("pezkuwi"); 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, ) -> CliResult<()> where F: FnOnce(&mut pezsc_cli::LoggerBuilder), { unreachable!("PezkuwiCli 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 BizinikiwiCli for TestCollatorCli { fn impl_name() -> String { "Pezcumulus zombienet test teyrchain".into() } fn impl_version() -> String { String::new() } fn description() -> String { format!( "Pezcumulus zombienet test teyrchain\n\nThe command-line arguments provided first will be \ passed to the teyrchain node, while the arguments provided after -- will be passed \ to the relaychain node.\n\n\ {} [teyrchain-args] -- [relaychain-args]", Self::executable_name() ) } fn author() -> String { env!("CARGO_PKG_AUTHORS").into() } fn support_url() -> String { "https://github.com/pezkuwichain/pezkuwi-sdk/issues/new".into() } fn copyright_start_year() -> i32 { 2017 } fn load_spec( &self, id: &str, ) -> std::result::Result, String> { Ok(match id { "" => { tracing::info!("Using default test service chain spec."); Box::new(pezcumulus_test_service::get_chain_spec(Some(ParaId::from(2000)))) as Box<_> }, "elastic-scaling-mvp" => { tracing::info!("Using elastic-scaling mvp chain spec."); Box::new(pezcumulus_test_service::get_elastic_scaling_mvp_chain_spec(Some( ParaId::from(2100), ))) as Box<_> }, "elastic-scaling" => { tracing::info!("Using elastic-scaling chain spec."); Box::new(pezcumulus_test_service::get_elastic_scaling_chain_spec(Some( ParaId::from(2200), ))) as Box<_> }, "elastic-scaling-500ms" => { tracing::info!("Using elastic-scaling 500ms chain spec."); Box::new(pezcumulus_test_service::get_elastic_scaling_500ms_chain_spec(Some( ParaId::from(2300), ))) as Box<_> }, "elastic-scaling-multi-block-slot" => { tracing::info!("Using elastic-scaling multi-block-slot chain spec."); Box::new(pezcumulus_test_service::get_elastic_scaling_multi_block_slot_chain_spec( Some(ParaId::from(2400)), )) as Box<_> }, "sync-backing" => { tracing::info!("Using sync backing chain spec."); Box::new(pezcumulus_test_service::get_sync_backing_chain_spec(Some(ParaId::from( 2500, )))) as Box<_> }, "async-backing" => { tracing::info!("Using async backing chain spec."); Box::new(pezcumulus_test_service::get_async_backing_chain_spec(Some(ParaId::from( 2500, )))) as Box<_> }, "relay-parent-offset" => { Box::new(pezcumulus_test_service::get_relay_parent_offset_chain_spec(Some( ParaId::from(2600), ))) as Box<_> }, path => { let chain_spec: pezsc_chain_spec::GenericChainSpec = pezsc_chain_spec::GenericChainSpec::from_json_file(path.into())?; Box::new(chain_spec) }, }) } } impl BizinikiwiCli for RelayChainCli { fn impl_name() -> String { "Pezkuwi collator".into() } fn impl_version() -> String { String::new() } fn description() -> String { format!( "Pezkuwi collator\n\nThe command-line arguments provided first will be \ passed to the teyrchain node, while the arguments provided after -- will be passed \ to the relay chain node.\n\n\ {} [teyrchain-args] -- [relay_chain-args]", Self::executable_name() ) } fn author() -> String { env!("CARGO_PKG_AUTHORS").into() } fn support_url() -> String { "https://github.com/pezkuwichain/pezkuwi-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) } }