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