reth_cli_commands/stage/dump/
mod.rs1use crate::common::{AccessRights, CliNodeComponents, CliNodeTypes, Environment, EnvironmentArgs};
3use clap::Parser;
4use reth_chainspec::{EthChainSpec, EthereumHardforks};
5use reth_cli::chainspec::ChainSpecParser;
6use reth_db::{init_db, mdbx::DatabaseArguments, DatabaseEnv};
7use reth_db_api::{
8 cursor::DbCursorRO, database::Database, models::ClientVersion, table::TableImporter, tables,
9 transaction::DbTx,
10};
11use reth_db_common::DbTool;
12use reth_node_builder::NodeTypesWithDB;
13use reth_node_core::{
14 args::DatadirArgs,
15 dirs::{DataDirPath, PlatformPath},
16};
17use std::{path::PathBuf, sync::Arc};
18use tracing::info;
19
20mod hashing_storage;
21use hashing_storage::dump_hashing_storage_stage;
22
23mod hashing_account;
24use hashing_account::dump_hashing_account_stage;
25
26mod execution;
27use execution::dump_execution_stage;
28
29mod merkle;
30use merkle::dump_merkle_stage;
31
32#[derive(Debug, Parser)]
34pub struct Command<C: ChainSpecParser> {
35 #[command(flatten)]
36 env: EnvironmentArgs<C>,
37
38 #[command(subcommand)]
39 command: Stages,
40}
41
42#[derive(Debug, Clone, Parser)]
44pub enum Stages {
45 Execution(StageCommand),
47 StorageHashing(StageCommand),
49 AccountHashing(StageCommand),
51 Merkle(StageCommand),
53}
54
55#[derive(Debug, Clone, Parser)]
57pub struct StageCommand {
58 #[arg(long, value_name = "OUTPUT_PATH", verbatim_doc_comment)]
60 output_datadir: PlatformPath<DataDirPath>,
61
62 #[arg(long, short)]
64 from: u64,
65 #[arg(long, short)]
67 to: u64,
68 #[arg(long, short, default_value = "false")]
71 dry_run: bool,
72}
73
74macro_rules! handle_stage {
75 ($stage_fn:ident, $tool:expr, $command:expr) => {{
76 let StageCommand { output_datadir, from, to, dry_run, .. } = $command;
77 let output_datadir =
78 output_datadir.with_chain($tool.chain().chain(), DatadirArgs::default());
79 $stage_fn($tool, *from, *to, output_datadir, *dry_run).await?
80 }};
81
82 ($stage_fn:ident, $tool:expr, $command:expr, $executor:expr, $consensus:expr) => {{
83 let StageCommand { output_datadir, from, to, dry_run, .. } = $command;
84 let output_datadir =
85 output_datadir.with_chain($tool.chain().chain(), DatadirArgs::default());
86 $stage_fn($tool, *from, *to, output_datadir, *dry_run, $executor, $consensus).await?
87 }};
88}
89
90impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> Command<C> {
91 pub async fn execute<N, Comp, F>(self, components: F) -> eyre::Result<()>
93 where
94 N: CliNodeTypes<ChainSpec = C::ChainSpec>,
95 Comp: CliNodeComponents<N>,
96 F: FnOnce(Arc<C::ChainSpec>) -> Comp,
97 {
98 let Environment { provider_factory, .. } = self.env.init::<N>(AccessRights::RO)?;
99 let tool = DbTool::new(provider_factory)?;
100 let components = components(tool.chain());
101 let evm_config = components.evm_config().clone();
102 let consensus = components.consensus().clone();
103
104 match &self.command {
105 Stages::Execution(cmd) => {
106 handle_stage!(dump_execution_stage, &tool, cmd, evm_config, consensus)
107 }
108 Stages::StorageHashing(cmd) => handle_stage!(dump_hashing_storage_stage, &tool, cmd),
109 Stages::AccountHashing(cmd) => handle_stage!(dump_hashing_account_stage, &tool, cmd),
110 Stages::Merkle(cmd) => {
111 handle_stage!(dump_merkle_stage, &tool, cmd, evm_config, consensus)
112 }
113 }
114
115 Ok(())
116 }
117}
118
119impl<C: ChainSpecParser> Command<C> {
120 pub fn chain_spec(&self) -> Option<&Arc<C::ChainSpec>> {
122 Some(&self.env.chain)
123 }
124}
125
126pub(crate) fn setup<N: NodeTypesWithDB>(
129 from: u64,
130 to: u64,
131 output_db: &PathBuf,
132 db_tool: &DbTool<N>,
133) -> eyre::Result<(DatabaseEnv, u64)> {
134 assert!(from < to, "FROM block should be lower than TO block.");
135
136 info!(target: "reth::cli", ?output_db, "Creating separate db");
137
138 let output_datadir = init_db(output_db, DatabaseArguments::new(ClientVersion::default()))?;
139
140 output_datadir.update(|tx| {
141 tx.import_table_with_range::<tables::BlockBodyIndices, _>(
142 &db_tool.provider_factory.db_ref().tx()?,
143 Some(from - 1),
144 to + 1,
145 )
146 })??;
147
148 let (tip_block_number, _) = db_tool
149 .provider_factory
150 .db_ref()
151 .view(|tx| tx.cursor_read::<tables::BlockBodyIndices>()?.last())??
152 .expect("some");
153
154 Ok((output_datadir, tip_block_number))
155}