1use crate::{
18 cli::{Cli, RelayChainCli, Subcommand},
19 common::{
20 chain_spec::LoadSpec,
21 runtime::{
22 AuraConsensusId, Consensus, Runtime, RuntimeResolver as RuntimeResolverT,
23 RuntimeResolver,
24 },
25 types::Block,
26 NodeBlock, NodeExtraArgs,
27 },
28 extra_subcommand::DefaultExtraSubcommands,
29 fake_runtime_api,
30 nodes::DynNodeSpecExt,
31 runtime::BlockNumber,
32};
33use clap::{CommandFactory, FromArgMatches};
34#[cfg(feature = "runtime-benchmarks")]
35use cumulus_client_service::storage_proof_size::HostFunctions as ReclaimHostFunctions;
36use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE};
37use log::info;
38use sc_cli::{CliConfiguration, Result, SubstrateCli};
39#[cfg(feature = "runtime-benchmarks")]
40use sp_runtime::traits::HashingFor;
41
42const DEFAULT_DEV_BLOCK_TIME_MS: u64 = 3000;
43
44pub struct RunConfig {
47 pub chain_spec_loader: Box<dyn LoadSpec>,
49 pub runtime_resolver: Box<dyn RuntimeResolver>,
51}
52
53impl RunConfig {
54 pub fn new(
56 runtime_resolver: Box<dyn RuntimeResolver>,
57 chain_spec_loader: Box<dyn LoadSpec>,
58 ) -> Self {
59 RunConfig { runtime_resolver, chain_spec_loader }
60 }
61}
62
63pub fn new_aura_node_spec<Block>(
64 aura_id: AuraConsensusId,
65 extra_args: &NodeExtraArgs,
66) -> Box<dyn DynNodeSpecExt>
67where
68 Block: NodeBlock,
69{
70 match aura_id {
71 AuraConsensusId::Sr25519 => crate::nodes::aura::new_aura_node_spec::<
72 Block,
73 fake_runtime_api::aura_sr25519::RuntimeApi,
74 sp_consensus_aura::sr25519::AuthorityId,
75 >(extra_args),
76 AuraConsensusId::Ed25519 => crate::nodes::aura::new_aura_node_spec::<
77 Block,
78 fake_runtime_api::aura_ed25519::RuntimeApi,
79 sp_consensus_aura::ed25519::AuthorityId,
80 >(extra_args),
81 }
82}
83
84fn new_node_spec(
85 config: &sc_service::Configuration,
86 runtime_resolver: &Box<dyn RuntimeResolverT>,
87 extra_args: &NodeExtraArgs,
88) -> std::result::Result<Box<dyn DynNodeSpecExt>, sc_cli::Error> {
89 let runtime = runtime_resolver.runtime(config.chain_spec.as_ref())?;
90
91 Ok(match runtime {
92 Runtime::Omni(block_number, consensus) => match (block_number, consensus) {
93 (BlockNumber::U32, Consensus::Aura(aura_id)) =>
94 new_aura_node_spec::<Block<u32>>(aura_id, extra_args),
95 (BlockNumber::U64, Consensus::Aura(aura_id)) =>
96 new_aura_node_spec::<Block<u64>>(aura_id, extra_args),
97 },
98 })
99}
100
101pub fn run<CliConfig: crate::cli::CliConfig>(cmd_config: RunConfig) -> Result<()> {
103 run_with_custom_cli::<CliConfig, DefaultExtraSubcommands>(cmd_config)
104}
105
106pub fn run_with_custom_cli<CliConfig, ExtraSubcommand>(cmd_config: RunConfig) -> Result<()>
123where
124 CliConfig: crate::cli::CliConfig,
125 ExtraSubcommand: crate::extra_subcommand::ExtraSubcommand,
126{
127 let cli_command = Cli::<CliConfig>::command();
128 let cli_command = ExtraSubcommand::augment_subcommands(cli_command);
129 let cli_command = Cli::<CliConfig>::setup_command(cli_command);
130
131 let matches = cli_command.get_matches();
133
134 if let Ok(extra) = ExtraSubcommand::from_arg_matches(&matches) {
136 extra.handle(&cmd_config)?;
139 return Ok(())
140 }
141
142 let mut cli =
144 Cli::<CliConfig>::from_arg_matches(&matches).map_err(|e| sc_cli::Error::Cli(e.into()))?;
145 cli.chain_spec_loader = Some(cmd_config.chain_spec_loader);
146
147 #[allow(deprecated)]
148 match &cli.subcommand {
149 Some(Subcommand::BuildSpec(cmd)) => {
150 let runner = cli.create_runner(cmd)?;
151 runner.sync_run(|config| cmd.run(config.chain_spec, config.network))
152 },
153 Some(Subcommand::CheckBlock(cmd)) => {
154 let runner = cli.create_runner(cmd)?;
155 runner.async_run(|config| {
156 let node =
157 new_node_spec(&config, &cmd_config.runtime_resolver, &cli.node_extra_args())?;
158 node.prepare_check_block_cmd(config, cmd)
159 })
160 },
161 Some(Subcommand::ExportBlocks(cmd)) => {
162 let runner = cli.create_runner(cmd)?;
163 runner.async_run(|config| {
164 let node =
165 new_node_spec(&config, &cmd_config.runtime_resolver, &cli.node_extra_args())?;
166 node.prepare_export_blocks_cmd(config, cmd)
167 })
168 },
169 Some(Subcommand::ExportState(cmd)) => {
170 let runner = cli.create_runner(cmd)?;
171 runner.async_run(|config| {
172 let node =
173 new_node_spec(&config, &cmd_config.runtime_resolver, &cli.node_extra_args())?;
174 node.prepare_export_state_cmd(config, cmd)
175 })
176 },
177 Some(Subcommand::ImportBlocks(cmd)) => {
178 let runner = cli.create_runner(cmd)?;
179 runner.async_run(|config| {
180 let node =
181 new_node_spec(&config, &cmd_config.runtime_resolver, &cli.node_extra_args())?;
182 node.prepare_import_blocks_cmd(config, cmd)
183 })
184 },
185 Some(Subcommand::Revert(cmd)) => {
186 let runner = cli.create_runner(cmd)?;
187 runner.async_run(|config| {
188 let node =
189 new_node_spec(&config, &cmd_config.runtime_resolver, &cli.node_extra_args())?;
190 node.prepare_revert_cmd(config, cmd)
191 })
192 },
193 Some(Subcommand::ChainSpecBuilder(cmd)) =>
194 cmd.run().map_err(|err| sc_cli::Error::Application(err.into())),
195
196 Some(Subcommand::PurgeChain(cmd)) => {
197 let runner = cli.create_runner(cmd)?;
198 let polkadot_cli =
199 RelayChainCli::<CliConfig>::new(runner.config(), cli.relay_chain_args.iter());
200
201 runner.sync_run(|config| {
202 let polkadot_config = SubstrateCli::create_configuration(
203 &polkadot_cli,
204 &polkadot_cli,
205 config.tokio_handle.clone(),
206 )
207 .map_err(|err| format!("Relay chain argument error: {}", err))?;
208
209 cmd.run(config, polkadot_config)
210 })
211 },
212 Some(Subcommand::ExportGenesisHead(cmd)) => {
213 let runner = cli.create_runner(cmd)?;
214 runner.sync_run(|config| {
215 let node =
216 new_node_spec(&config, &cmd_config.runtime_resolver, &cli.node_extra_args())?;
217 node.run_export_genesis_head_cmd(config, cmd)
218 })
219 },
220 Some(Subcommand::ExportGenesisWasm(cmd)) => {
221 let runner = cli.create_runner(cmd)?;
222 runner.sync_run(|_config| {
223 let spec = cli.load_spec(&cmd.shared_params.chain.clone().unwrap_or_default())?;
224 cmd.run(&*spec)
225 })
226 },
227 Some(Subcommand::Benchmark(cmd)) => {
228 match cmd {
230 #[cfg(feature = "runtime-benchmarks")]
231 BenchmarkCmd::Pallet(cmd) => {
232 let chain = cmd
233 .shared_params
234 .chain
235 .as_ref()
236 .map(|chain| cli.load_spec(&chain))
237 .transpose()?;
238 cmd.run_with_spec::<HashingFor<Block<u32>>, ReclaimHostFunctions>(chain)
239 },
240 BenchmarkCmd::Block(cmd) => {
241 let runner = cli.create_runner(cmd)?;
245 runner.sync_run(|config| {
246 let node = new_node_spec(
247 &config,
248 &cmd_config.runtime_resolver,
249 &cli.node_extra_args(),
250 )?;
251 node.run_benchmark_block_cmd(config, cmd)
252 })
253 },
254 #[cfg(feature = "runtime-benchmarks")]
255 BenchmarkCmd::Storage(cmd) => {
256 let runner = cli.create_runner(cmd)?;
260 runner.sync_run(|config| {
261 let node = new_node_spec(
262 &config,
263 &cmd_config.runtime_resolver,
264 &cli.node_extra_args(),
265 )?;
266 node.run_benchmark_storage_cmd(config, cmd)
267 })
268 },
269 BenchmarkCmd::Machine(cmd) => {
270 let runner = cli.create_runner(cmd)?;
278 runner.sync_run(|config| cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone()))
279 },
280 #[allow(unreachable_patterns)]
281 _ => Err("Benchmarking sub-command unsupported or compilation feature missing. \
282 Make sure to compile omni-node with --features=runtime-benchmarks \
283 to enable all supported benchmarks."
284 .into()),
285 }
286 },
287 Some(Subcommand::Key(cmd)) => Ok(cmd.run(&cli)?),
288 None => {
289 let runner = cli.create_runner(&cli.run.normalize())?;
290 let polkadot_cli =
291 RelayChainCli::<CliConfig>::new(runner.config(), cli.relay_chain_args.iter());
292 let collator_options = cli.run.collator_options();
293
294 if cli.experimental_use_slot_based {
295 log::warn!(
296 "Deprecated: The flag --experimental-use-slot-based is no longer \
297 supported. Please use --authoring slot-based instead. This feature will be removed \
298 after May 2025."
299 );
300 }
301
302 runner.run_node_until_exit(|config| async move {
303 let node_spec =
304 new_node_spec(&config, &cmd_config.runtime_resolver, &cli.node_extra_args())?;
305
306 if cli.run.base.is_dev()? {
307 let dev_block_time = cli.dev_block_time.unwrap_or(DEFAULT_DEV_BLOCK_TIME_MS);
310 return node_spec
311 .start_manual_seal_node(config, dev_block_time)
312 .map_err(Into::into);
313 }
314
315 if let Some(dev_block_time) = cli.dev_block_time {
316 return node_spec
317 .start_manual_seal_node(config, dev_block_time)
318 .map_err(Into::into);
319 }
320
321 let old_name = match config.chain_spec.id() {
326 "asset-hub-polkadot" => Some("statemint"),
327 "asset-hub-kusama" => Some("statemine"),
328 "asset-hub-westend" => Some("westmint"),
329 "asset-hub-rococo" => Some("rockmine"),
330 _ => None,
331 };
332
333 if let Some(old_name) = old_name {
334 let new_path = config.base_path.config_dir(config.chain_spec.id());
335 let old_path = config.base_path.config_dir(old_name);
336
337 if old_path.exists() && new_path.exists() {
338 return Err(format!(
339 "Found legacy {} path {} and new Asset Hub path {}. \
340 Delete one path such that only one exists.",
341 old_name,
342 old_path.display(),
343 new_path.display()
344 )
345 .into());
346 }
347
348 if old_path.exists() {
349 std::fs::rename(old_path.clone(), new_path.clone())?;
350 info!(
351 "{} was renamed to Asset Hub. The filepath with associated data on disk \
352 has been renamed from {} to {}.",
353 old_name,
354 old_path.display(),
355 new_path.display()
356 );
357 }
358 }
359
360 let hwbench = (!cli.no_hardware_benchmarks)
361 .then(|| {
362 config.database.path().map(|database_path| {
363 let _ = std::fs::create_dir_all(database_path);
364 sc_sysinfo::gather_hwbench(
365 Some(database_path),
366 &SUBSTRATE_REFERENCE_HARDWARE,
367 )
368 })
369 })
370 .flatten();
371 let tokio_handle = config.tokio_handle.clone();
372 let polkadot_config =
373 SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle)
374 .map_err(|err| format!("Relay chain argument error: {}", err))?;
375
376 info!("✍️ Is collating: {}", if config.role.is_authority() { "yes" } else { "no" });
377
378 node_spec
379 .start_node(
380 config,
381 polkadot_config,
382 collator_options,
383 hwbench,
384 cli.node_extra_args(),
385 )
386 .await
387 .map_err(Into::into)
388 })
389 },
390 }
391}