reth_cli_commands/
import.rs1use crate::{
3 common::{AccessRights, CliNodeComponents, CliNodeTypes, Environment, EnvironmentArgs},
4 import_core::{import_blocks_from_file, ImportConfig},
5};
6use clap::Parser;
7use reth_chainspec::{ChainSpecProvider, EthChainSpec, EthereumHardforks};
8use reth_cli::chainspec::ChainSpecParser;
9use reth_node_core::version::version_metadata;
10use std::{path::PathBuf, sync::Arc};
11use tracing::info;
12
13pub use crate::import_core::build_import_pipeline_impl as build_import_pipeline;
14
15#[derive(Debug, Parser)]
17pub struct ImportCommand<C: ChainSpecParser> {
18 #[command(flatten)]
19 env: EnvironmentArgs<C>,
20
21 #[arg(long, verbatim_doc_comment)]
23 no_state: bool,
24
25 #[arg(long, value_name = "CHUNK_LEN", verbatim_doc_comment)]
27 chunk_len: Option<u64>,
28
29 #[arg(value_name = "IMPORT_PATH", required = true, num_args = 1.., verbatim_doc_comment)]
34 paths: Vec<PathBuf>,
35}
36
37impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> ImportCommand<C> {
38 pub async fn execute<N, Comp>(
40 self,
41 components: impl FnOnce(Arc<N::ChainSpec>) -> Comp,
42 ) -> eyre::Result<()>
43 where
44 N: CliNodeTypes<ChainSpec = C::ChainSpec>,
45 Comp: CliNodeComponents<N>,
46 {
47 info!(target: "reth::cli", "reth {} starting", version_metadata().short_version);
48
49 let Environment { provider_factory, config, .. } = self.env.init::<N>(AccessRights::RW)?;
50
51 let components = components(provider_factory.chain_spec());
52
53 info!(target: "reth::cli", "Starting import of {} file(s)", self.paths.len());
54
55 let import_config = ImportConfig { no_state: self.no_state, chunk_len: self.chunk_len };
56
57 let executor = components.evm_config().clone();
58 let consensus = Arc::new(components.consensus().clone());
59
60 let mut total_imported_blocks = 0;
61 let mut total_imported_txns = 0;
62 let mut total_decoded_blocks = 0;
63 let mut total_decoded_txns = 0;
64
65 for (index, path) in self.paths.iter().enumerate() {
67 info!(target: "reth::cli", "Importing file {} of {}: {}", index + 1, self.paths.len(), path.display());
68
69 let result = import_blocks_from_file(
70 path,
71 import_config.clone(),
72 provider_factory.clone(),
73 &config,
74 executor.clone(),
75 consensus.clone(),
76 )
77 .await?;
78
79 total_imported_blocks += result.total_imported_blocks;
80 total_imported_txns += result.total_imported_txns;
81 total_decoded_blocks += result.total_decoded_blocks;
82 total_decoded_txns += result.total_decoded_txns;
83
84 if !result.is_complete() {
85 return Err(eyre::eyre!(
86 "Chain was partially imported from file: {}. Imported {}/{} blocks, {}/{} transactions",
87 path.display(),
88 result.total_imported_blocks,
89 result.total_decoded_blocks,
90 result.total_imported_txns,
91 result.total_decoded_txns
92 ));
93 }
94
95 info!(target: "reth::cli",
96 "Successfully imported file {}: {} blocks, {} transactions",
97 path.display(), result.total_imported_blocks, result.total_imported_txns);
98 }
99
100 info!(target: "reth::cli",
101 "All files imported successfully. Total: {}/{} blocks, {}/{} transactions",
102 total_imported_blocks, total_decoded_blocks, total_imported_txns, total_decoded_txns);
103
104 Ok(())
105 }
106}
107
108impl<C: ChainSpecParser> ImportCommand<C> {
109 pub fn chain_spec(&self) -> Option<&Arc<C::ChainSpec>> {
111 Some(&self.env.chain)
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118 use reth_ethereum_cli::chainspec::{EthereumChainSpecParser, SUPPORTED_CHAINS};
119
120 #[test]
121 fn parse_common_import_command_chain_args() {
122 for chain in SUPPORTED_CHAINS {
123 let args: ImportCommand<EthereumChainSpecParser> =
124 ImportCommand::parse_from(["reth", "--chain", chain, "."]);
125 assert_eq!(
126 Ok(args.env.chain.chain),
127 chain.parse::<reth_chainspec::Chain>(),
128 "failed to parse chain {chain}"
129 );
130 }
131 }
132
133 #[test]
134 fn parse_import_command_with_multiple_paths() {
135 let args: ImportCommand<EthereumChainSpecParser> =
136 ImportCommand::parse_from(["reth", "file1.rlp", "file2.rlp", "file3.rlp"]);
137 assert_eq!(args.paths.len(), 3);
138 assert_eq!(args.paths[0], PathBuf::from("file1.rlp"));
139 assert_eq!(args.paths[1], PathBuf::from("file2.rlp"));
140 assert_eq!(args.paths[2], PathBuf::from("file3.rlp"));
141 }
142}