referrerpolicy=no-referrer-when-downgrade

polkadot_omni_node_lib/
cli.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Cumulus.
3// SPDX-License-Identifier: Apache-2.0
4
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// 	http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17//! CLI options of the omni-node. See [`Command`].
18
19use crate::{
20	chain_spec::DiskChainSpecLoader,
21	common::{
22		chain_spec::{Extensions, LoadSpec},
23		NodeExtraArgs,
24	},
25};
26use chain_spec_builder::ChainSpecBuilder;
27use clap::{Command, CommandFactory, FromArgMatches, ValueEnum};
28use sc_chain_spec::ChainSpec;
29use sc_cli::{
30	CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, NetworkParams,
31	RpcEndpoint, SharedParams, SubstrateCli,
32};
33use sc_service::{config::PrometheusConfig, BasePath};
34use std::{
35	fmt::{Debug, Display, Formatter},
36	marker::PhantomData,
37	path::PathBuf,
38};
39/// Trait that can be used to customize some of the customer-facing info related to the node binary
40/// that is being built using this library.
41///
42/// The related info is shown to the customer as part of logs or help messages.
43/// It does not impact functionality.
44pub trait CliConfig {
45	/// The version of the resulting node binary.
46	fn impl_version() -> String;
47
48	/// The description of the resulting node binary.
49	fn description(executable_name: String) -> String {
50		format!(
51			"The command-line arguments provided first will be passed to the parachain node, \n\
52			and the arguments provided after -- will be passed to the relay chain node. \n\
53			\n\
54			Example: \n\
55			\n\
56			{} [parachain-args] -- [relay-chain-args]",
57			executable_name
58		)
59	}
60
61	/// The author of the resulting node binary.
62	fn author() -> String;
63
64	/// The support URL for the resulting node binary.
65	fn support_url() -> String;
66
67	/// The starting copyright year of the resulting node binary.
68	fn copyright_start_year() -> u16;
69}
70
71/// Sub-commands supported by the collator.
72#[derive(Debug, clap::Subcommand)]
73pub enum Subcommand {
74	/// Key management CLI utilities
75	#[command(subcommand)]
76	Key(sc_cli::KeySubcommand),
77
78	/// Build a chain specification.
79	///
80	/// The `build-spec` command relies on the chain specification built (hard-coded) into the node
81	/// binary, and may utilize the genesis presets of the runtimes  also embedded in the nodes
82	/// that support  this command. Since `polkadot-omni-node` does not contain any embedded
83	/// runtime, and requires a `chain-spec` path to be passed to its `--chain` flag, the command
84	/// isn't bringing significant value as it does for other node binaries (e.g. the
85	///  `polkadot` binary).
86	///
87	/// For a more versatile `chain-spec` manipulation experience please check out the
88	/// `polkadot-omni-node chain-spec-builder` subcommand.
89	#[deprecated(
90		note = "build-spec will be removed after 1/06/2025. Use chain-spec-builder instead"
91	)]
92	BuildSpec(sc_cli::BuildSpecCmd),
93
94	/// Validate blocks.
95	CheckBlock(sc_cli::CheckBlockCmd),
96
97	/// Export blocks.
98	ExportBlocks(sc_cli::ExportBlocksCmd),
99
100	/// Export the state of a given block into a chain spec.
101	ExportState(sc_cli::ExportStateCmd),
102
103	/// Import blocks.
104	ImportBlocks(sc_cli::ImportBlocksCmd),
105
106	/// Revert the chain to a previous state.
107	Revert(sc_cli::RevertCmd),
108
109	/// Subcommand for generating and managing chain specifications.
110	///
111	/// A `chain-spec-builder` subcommand corresponds to the existing `chain-spec-builder` tool
112	/// (<https://crates.io/crates/staging-chain-spec-builder>), which can be used already standalone.
113	/// It provides the same functionality as the tool but bundled with `polkadot-omni-node` to
114	/// enable easier access to chain-spec generation, patching, converting to raw or validation,
115	/// from a single binary, which can be used as a parachain node tool
116	/// For a detailed usage guide please check out the standalone tool's crates.io or docs.rs
117	/// pages:
118	/// - <https://crates.io/crates/staging-chain-spec-builder>
119	/// - <https://docs.rs/staging-chain-spec-builder/latest/staging_chain_spec_builder/>
120	ChainSpecBuilder(ChainSpecBuilder),
121
122	/// Remove the whole chain.
123	PurgeChain(cumulus_client_cli::PurgeChainCmd),
124	/// Export the genesis state of the parachain.
125	#[command(alias = "export-genesis-state")]
126	ExportGenesisHead(cumulus_client_cli::ExportGenesisHeadCommand),
127
128	/// Export the genesis wasm of the parachain.
129	ExportGenesisWasm(cumulus_client_cli::ExportGenesisWasmCommand),
130
131	/// Sub-commands concerned with benchmarking.
132	/// The pallet benchmarking moved to the `pallet` sub-command.
133	#[command(subcommand)]
134	Benchmark(frame_benchmarking_cli::BenchmarkCmd),
135}
136
137/// CLI Options shipped with `polkadot-omni-node`.
138#[derive(clap::Parser)]
139#[command(
140	propagate_version = true,
141	args_conflicts_with_subcommands = true,
142	subcommand_negates_reqs = true
143)]
144pub struct Cli<Config: CliConfig> {
145	#[arg(skip)]
146	pub(crate) chain_spec_loader: Option<Box<dyn LoadSpec>>,
147
148	/// Possible subcommands. See [`Subcommand`].
149	#[command(subcommand)]
150	pub subcommand: Option<Subcommand>,
151
152	/// The shared parameters with all cumulus-based parachain nodes.
153	#[command(flatten)]
154	pub run: cumulus_client_cli::RunCmd,
155
156	/// Start a dev node that produces a block each `dev_block_time` ms.
157	///
158	/// This is a dev option. It enables a manual sealing, meaning blocks are produced manually
159	/// rather than being part of an actual network consensus process. Using the option won't
160	/// result in starting or connecting to a parachain network. The resulting node will work on
161	/// its own, running the wasm blob and artificially producing a block each `dev_block_time` ms,
162	/// as if it was part of a parachain.
163	///
164	/// The `--dev` flag sets the `dev_block_time` to a default value of 3000ms unless explicitly
165	/// provided.
166	#[arg(long)]
167	pub dev_block_time: Option<u64>,
168
169	/// DEPRECATED: This feature has been stabilized, pLease use `--authoring slot-based` instead.
170	///
171	/// Use slot-based collator which can handle elastic scaling.
172	/// Use with care, this flag is unstable and subject to change.
173	#[arg(long, conflicts_with = "authoring")]
174	pub experimental_use_slot_based: bool,
175
176	/// Authoring style to use.
177	#[arg(long, default_value_t = AuthoringPolicy::Lookahead)]
178	pub authoring: AuthoringPolicy,
179
180	/// Disable automatic hardware benchmarks.
181	///
182	/// By default these benchmarks are automatically ran at startup and measure
183	/// the CPU speed, the memory bandwidth and the disk speed.
184	///
185	/// The results are then printed out in the logs, and also sent as part of
186	/// telemetry, if telemetry is enabled.
187	#[arg(long)]
188	pub no_hardware_benchmarks: bool,
189
190	/// Export all `PoVs` build by this collator to the given folder.
191	///
192	/// This is useful for debugging issues that are occurring while validating these `PoVs` on the
193	/// relay chain.
194	#[arg(long)]
195	pub export_pov_to_path: Option<PathBuf>,
196
197	/// Relay chain arguments
198	#[arg(raw = true)]
199	pub relay_chain_args: Vec<String>,
200
201	/// Enable the statement store.
202	///
203	/// The statement store is a store for statements validated using the runtime API
204	/// `validate_statement`. It should be enabled for chains that provide this runtime API.
205	#[arg(long)]
206	pub enable_statement_store: bool,
207
208	#[arg(skip)]
209	pub(crate) _phantom: PhantomData<Config>,
210}
211
212/// Collator implementation to use.
213#[derive(PartialEq, Debug, ValueEnum, Clone, Copy)]
214pub enum AuthoringPolicy {
215	/// Use the lookahead collator. Builds a block once per imported relay chain block and
216	/// on relay chain forks. Default for asynchronous backing chains.
217	Lookahead,
218	/// Use the slot-based collator. Builds a block based on time. Can utilize multiple cores,
219	/// always builds on the best relay chain block available. Should be used with elastic-scaling
220	/// chains.
221	SlotBased,
222}
223
224impl Display for AuthoringPolicy {
225	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
226		match self {
227			AuthoringPolicy::Lookahead => write!(f, "lookahead"),
228			AuthoringPolicy::SlotBased => write!(f, "slot-based"),
229		}
230	}
231}
232
233impl<Config: CliConfig> Cli<Config> {
234	pub(crate) fn node_extra_args(&self) -> NodeExtraArgs {
235		NodeExtraArgs {
236			authoring_policy: self
237				.experimental_use_slot_based
238				.then(|| AuthoringPolicy::SlotBased)
239				.unwrap_or(self.authoring),
240			export_pov: self.export_pov_to_path.clone(),
241			max_pov_percentage: self.run.experimental_max_pov_percentage,
242			enable_statement_store: self.enable_statement_store,
243		}
244	}
245}
246
247impl<Config: CliConfig> SubstrateCli for Cli<Config> {
248	fn impl_name() -> String {
249		Self::executable_name()
250	}
251
252	fn impl_version() -> String {
253		Config::impl_version()
254	}
255
256	fn description() -> String {
257		Config::description(Self::executable_name())
258	}
259
260	fn author() -> String {
261		Config::author()
262	}
263
264	fn support_url() -> String {
265		Config::support_url()
266	}
267
268	fn copyright_start_year() -> i32 {
269		Config::copyright_start_year() as i32
270	}
271
272	fn load_spec(&self, id: &str) -> Result<Box<dyn ChainSpec>, String> {
273		match &self.chain_spec_loader {
274			Some(chain_spec_loader) => chain_spec_loader.load_spec(id),
275			None => DiskChainSpecLoader.load_spec(id),
276		}
277	}
278}
279
280/// The relay chain CLI flags. These are passed in after a `--` at the end.
281#[derive(Debug)]
282pub struct RelayChainCli<Config: CliConfig> {
283	/// The actual relay chain cli object.
284	pub base: polkadot_cli::RunCmd,
285
286	/// Optional chain id that should be passed to the relay chain.
287	pub chain_id: Option<String>,
288
289	/// The base path that should be used by the relay chain.
290	pub base_path: Option<PathBuf>,
291
292	_phantom: PhantomData<Config>,
293}
294
295impl<Config: CliConfig> RelayChainCli<Config> {
296	fn polkadot_cmd() -> Command {
297		let help_template = color_print::cformat!(
298			"The arguments that are passed to the relay chain node. \n\
299			\n\
300			<bold><underline>RELAY_CHAIN_ARGS:</></> \n\
301			{{options}}",
302		);
303
304		polkadot_cli::RunCmd::command()
305			.no_binary_name(true)
306			.help_template(help_template)
307	}
308
309	/// Parse the relay chain CLI parameters using the parachain `Configuration`.
310	pub fn new<'a>(
311		para_config: &sc_service::Configuration,
312		relay_chain_args: impl Iterator<Item = &'a String>,
313	) -> Self {
314		let polkadot_cmd = Self::polkadot_cmd();
315		let matches = polkadot_cmd.get_matches_from(relay_chain_args);
316		let base = FromArgMatches::from_arg_matches(&matches).unwrap_or_else(|e| e.exit());
317
318		let extension = Extensions::try_get(&*para_config.chain_spec);
319		let chain_id = extension.map(|e| e.relay_chain.clone());
320
321		let base_path = para_config.base_path.path().join("polkadot");
322		Self { base, chain_id, base_path: Some(base_path), _phantom: Default::default() }
323	}
324}
325
326impl<Config: CliConfig> SubstrateCli for RelayChainCli<Config> {
327	fn impl_name() -> String {
328		Cli::<Config>::impl_name()
329	}
330
331	fn impl_version() -> String {
332		Cli::<Config>::impl_version()
333	}
334
335	fn description() -> String {
336		Cli::<Config>::description()
337	}
338
339	fn author() -> String {
340		Cli::<Config>::author()
341	}
342
343	fn support_url() -> String {
344		Cli::<Config>::support_url()
345	}
346
347	fn copyright_start_year() -> i32 {
348		Cli::<Config>::copyright_start_year()
349	}
350
351	fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn ChainSpec>, String> {
352		polkadot_cli::Cli::from_iter([Self::executable_name()].iter()).load_spec(id)
353	}
354}
355
356impl<Config: CliConfig> DefaultConfigurationValues for RelayChainCli<Config> {
357	fn p2p_listen_port() -> u16 {
358		30334
359	}
360
361	fn rpc_listen_port() -> u16 {
362		9945
363	}
364
365	fn prometheus_listen_port() -> u16 {
366		9616
367	}
368}
369
370impl<Config: CliConfig> CliConfiguration<Self> for RelayChainCli<Config> {
371	fn shared_params(&self) -> &SharedParams {
372		self.base.base.shared_params()
373	}
374
375	fn import_params(&self) -> Option<&ImportParams> {
376		self.base.base.import_params()
377	}
378
379	fn network_params(&self) -> Option<&NetworkParams> {
380		self.base.base.network_params()
381	}
382
383	fn keystore_params(&self) -> Option<&KeystoreParams> {
384		self.base.base.keystore_params()
385	}
386
387	fn base_path(&self) -> sc_cli::Result<Option<BasePath>> {
388		Ok(self
389			.shared_params()
390			.base_path()?
391			.or_else(|| self.base_path.clone().map(Into::into)))
392	}
393
394	fn rpc_addr(&self, default_listen_port: u16) -> sc_cli::Result<Option<Vec<RpcEndpoint>>> {
395		self.base.base.rpc_addr(default_listen_port)
396	}
397
398	fn prometheus_config(
399		&self,
400		default_listen_port: u16,
401		chain_spec: &Box<dyn ChainSpec>,
402	) -> sc_cli::Result<Option<PrometheusConfig>> {
403		self.base.base.prometheus_config(default_listen_port, chain_spec)
404	}
405
406	fn init<F>(
407		&self,
408		_support_url: &String,
409		_impl_version: &String,
410		_logger_hook: F,
411	) -> sc_cli::Result<()>
412	where
413		F: FnOnce(&mut sc_cli::LoggerBuilder),
414	{
415		unreachable!("PolkadotCli is never initialized; qed");
416	}
417
418	fn chain_id(&self, is_dev: bool) -> sc_cli::Result<String> {
419		let chain_id = self.base.base.chain_id(is_dev)?;
420
421		Ok(if chain_id.is_empty() { self.chain_id.clone().unwrap_or_default() } else { chain_id })
422	}
423
424	fn role(&self, is_dev: bool) -> sc_cli::Result<sc_service::Role> {
425		self.base.base.role(is_dev)
426	}
427
428	fn transaction_pool(
429		&self,
430		is_dev: bool,
431	) -> sc_cli::Result<sc_service::config::TransactionPoolOptions> {
432		self.base.base.transaction_pool(is_dev)
433	}
434
435	fn trie_cache_maximum_size(&self) -> sc_cli::Result<Option<usize>> {
436		self.base.base.trie_cache_maximum_size()
437	}
438
439	fn rpc_methods(&self) -> sc_cli::Result<sc_service::config::RpcMethods> {
440		self.base.base.rpc_methods()
441	}
442
443	fn rpc_max_connections(&self) -> sc_cli::Result<u32> {
444		self.base.base.rpc_max_connections()
445	}
446
447	fn rpc_cors(&self, is_dev: bool) -> sc_cli::Result<Option<Vec<String>>> {
448		self.base.base.rpc_cors(is_dev)
449	}
450
451	fn default_heap_pages(&self) -> sc_cli::Result<Option<u64>> {
452		self.base.base.default_heap_pages()
453	}
454
455	fn force_authoring(&self) -> sc_cli::Result<bool> {
456		self.base.base.force_authoring()
457	}
458
459	fn disable_grandpa(&self) -> sc_cli::Result<bool> {
460		self.base.base.disable_grandpa()
461	}
462
463	fn max_runtime_instances(&self) -> sc_cli::Result<Option<usize>> {
464		self.base.base.max_runtime_instances()
465	}
466
467	fn announce_block(&self) -> sc_cli::Result<bool> {
468		self.base.base.announce_block()
469	}
470
471	fn telemetry_endpoints(
472		&self,
473		chain_spec: &Box<dyn ChainSpec>,
474	) -> sc_cli::Result<Option<sc_telemetry::TelemetryEndpoints>> {
475		self.base.base.telemetry_endpoints(chain_spec)
476	}
477
478	fn node_name(&self) -> sc_cli::Result<String> {
479		self.base.base.node_name()
480	}
481}