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 },
94 (BlockNumber::U64, Consensus::Aura(aura_id)) => {
95 new_aura_node_spec::<Block<u64>>(aura_id, extra_args)
96 },
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
197 Some(Subcommand::PurgeChain(cmd)) => {
198 let runner = cli.create_runner(cmd)?;
199 let polkadot_cli =
200 RelayChainCli::<CliConfig>::new(runner.config(), cli.relay_chain_args.iter());
201
202 runner.sync_run(|config| {
203 let polkadot_config = SubstrateCli::create_configuration(
204 &polkadot_cli,
205 &polkadot_cli,
206 config.tokio_handle.clone(),
207 )
208 .map_err(|err| format!("Relay chain argument error: {}", err))?;
209
210 cmd.run(config, polkadot_config)
211 })
212 },
213 Some(Subcommand::ExportGenesisHead(cmd)) => {
214 let runner = cli.create_runner(cmd)?;
215 runner.sync_run(|config| {
216 let node =
217 new_node_spec(&config, &cmd_config.runtime_resolver, &cli.node_extra_args())?;
218 node.run_export_genesis_head_cmd(config, cmd)
219 })
220 },
221 Some(Subcommand::ExportGenesisWasm(cmd)) => {
222 let runner = cli.create_runner(cmd)?;
223 runner.sync_run(|_config| {
224 let spec = cli.load_spec(&cmd.shared_params.chain.clone().unwrap_or_default())?;
225 cmd.run(&*spec)
226 })
227 },
228 Some(Subcommand::Benchmark(cmd)) => {
229 match cmd {
231 #[cfg(feature = "runtime-benchmarks")]
232 BenchmarkCmd::Pallet(cmd) => {
233 let chain = cmd
234 .shared_params
235 .chain
236 .as_ref()
237 .map(|chain| cli.load_spec(&chain))
238 .transpose()?;
239 cmd.run_with_spec::<HashingFor<Block<u32>>, ReclaimHostFunctions>(chain)
240 },
241 BenchmarkCmd::Block(cmd) => {
242 let runner = cli.create_runner(cmd)?;
246 runner.sync_run(|config| {
247 let node = new_node_spec(
248 &config,
249 &cmd_config.runtime_resolver,
250 &cli.node_extra_args(),
251 )?;
252 node.run_benchmark_block_cmd(config, cmd)
253 })
254 },
255 #[cfg(feature = "runtime-benchmarks")]
256 BenchmarkCmd::Storage(cmd) => {
257 let runner = cli.create_runner(cmd)?;
261 runner.sync_run(|config| {
262 let node = new_node_spec(
263 &config,
264 &cmd_config.runtime_resolver,
265 &cli.node_extra_args(),
266 )?;
267 node.run_benchmark_storage_cmd(config, cmd)
268 })
269 },
270 BenchmarkCmd::Machine(cmd) => {
271 let runner = cli.create_runner(cmd)?;
279 runner.sync_run(|config| cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone()))
280 },
281 #[allow(unreachable_patterns)]
282 _ => Err("Benchmarking sub-command unsupported or compilation feature missing. \
283 Make sure to compile omni-node with --features=runtime-benchmarks \
284 to enable all supported benchmarks."
285 .into()),
286 }
287 },
288 Some(Subcommand::Key(cmd)) => Ok(cmd.run(&cli)?),
289 None => {
290 let runner = cli.create_runner(&cli.run.normalize())?;
291 let polkadot_cli =
292 RelayChainCli::<CliConfig>::new(runner.config(), cli.relay_chain_args.iter());
293 let collator_options = cli.run.collator_options();
294
295 if cli.experimental_use_slot_based {
296 log::warn!(
297 "Deprecated: The flag --experimental-use-slot-based is no longer \
298 supported. Please use --authoring slot-based instead. This feature will be removed \
299 after May 2025."
300 );
301 }
302
303 runner.run_node_until_exit(|config| async move {
304 let node_extra_args = cli.node_extra_args();
305 let node_spec =
306 new_node_spec(&config, &cmd_config.runtime_resolver, &node_extra_args)?;
307
308 if let Some(dev_mode) = cli.dev_mode() {
309 return node_spec
310 .start_dev_node(config, dev_mode, node_extra_args)
311 .map_err(Into::into);
312 }
313
314 let old_name = match config.chain_spec.id() {
319 "asset-hub-polkadot" => Some("statemint"),
320 "asset-hub-kusama" => Some("statemine"),
321 "asset-hub-westend" => Some("westmint"),
322 "asset-hub-rococo" => Some("rockmine"),
323 _ => None,
324 };
325
326 if let Some(old_name) = old_name {
327 let new_path = config.base_path.config_dir(config.chain_spec.id());
328 let old_path = config.base_path.config_dir(old_name);
329
330 if old_path.exists() && new_path.exists() {
331 return Err(format!(
332 "Found legacy {} path {} and new Asset Hub path {}. \
333 Delete one path such that only one exists.",
334 old_name,
335 old_path.display(),
336 new_path.display()
337 )
338 .into());
339 }
340
341 if old_path.exists() {
342 std::fs::rename(old_path.clone(), new_path.clone())?;
343 info!(
344 "{} was renamed to Asset Hub. The filepath with associated data on disk \
345 has been renamed from {} to {}.",
346 old_name,
347 old_path.display(),
348 new_path.display()
349 );
350 }
351 }
352
353 let hwbench = (!cli.no_hardware_benchmarks)
354 .then(|| {
355 config.database.path().map(|database_path| {
356 let _ = std::fs::create_dir_all(database_path);
357 sc_sysinfo::gather_hwbench(
358 Some(database_path),
359 &SUBSTRATE_REFERENCE_HARDWARE,
360 )
361 })
362 })
363 .flatten();
364 let tokio_handle = config.tokio_handle.clone();
365 let polkadot_config =
366 SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle)
367 .map_err(|err| format!("Relay chain argument error: {}", err))?;
368
369 info!("✍️ Is collating: {}", if config.role.is_authority() { "yes" } else { "no" });
370
371 node_spec
372 .start_node(
373 config,
374 polkadot_config,
375 collator_options,
376 hwbench,
377 cli.node_extra_args(),
378 )
379 .await
380 .map_err(Into::into)
381 })
382 },
383 }
384}