reth_cli_commands/stage/dump/
hashing_storage.rs

1use super::setup;
2use eyre::Result;
3use reth_db::DatabaseEnv;
4use reth_db_api::{database::Database, table::TableImporter, tables};
5use reth_db_common::DbTool;
6use reth_node_core::dirs::{ChainPath, DataDirPath};
7use reth_provider::{
8    providers::{ProviderNodeTypes, StaticFileProvider},
9    DatabaseProviderFactory, ProviderFactory,
10};
11use reth_stages::{stages::StorageHashingStage, Stage, StageCheckpoint, UnwindInput};
12use std::sync::Arc;
13use tracing::info;
14
15pub(crate) async fn dump_hashing_storage_stage<N: ProviderNodeTypes<DB = Arc<DatabaseEnv>>>(
16    db_tool: &DbTool<N>,
17    from: u64,
18    to: u64,
19    output_datadir: ChainPath<DataDirPath>,
20    should_run: bool,
21) -> Result<()> {
22    let (output_db, tip_block_number) = setup(from, to, &output_datadir.db(), db_tool)?;
23
24    unwind_and_copy(db_tool, from, tip_block_number, &output_db)?;
25
26    if should_run {
27        dry_run(
28            ProviderFactory::<N>::new(
29                Arc::new(output_db),
30                db_tool.chain(),
31                StaticFileProvider::read_write(output_datadir.static_files())?,
32            )?,
33            to,
34            from,
35        )?;
36    }
37
38    Ok(())
39}
40
41/// Dry-run an unwind to FROM block and copy the necessary table data to the new database.
42fn unwind_and_copy<N: ProviderNodeTypes>(
43    db_tool: &DbTool<N>,
44    from: u64,
45    tip_block_number: u64,
46    output_db: &DatabaseEnv,
47) -> eyre::Result<()> {
48    let provider = db_tool.provider_factory.database_provider_rw()?;
49
50    let mut exec_stage = StorageHashingStage::default();
51
52    exec_stage.unwind(
53        &provider,
54        UnwindInput {
55            unwind_to: from,
56            checkpoint: StageCheckpoint::new(tip_block_number),
57            bad_block: None,
58        },
59    )?;
60    let unwind_inner_tx = provider.into_tx();
61
62    // TODO optimize we can actually just get the entries we need for both these tables
63    output_db
64        .update(|tx| tx.import_dupsort::<tables::PlainStorageState, _>(&unwind_inner_tx))??;
65    output_db
66        .update(|tx| tx.import_dupsort::<tables::StorageChangeSets, _>(&unwind_inner_tx))??;
67
68    Ok(())
69}
70
71/// Try to re-execute the stage straight away
72fn dry_run<N: ProviderNodeTypes>(
73    output_provider_factory: ProviderFactory<N>,
74    to: u64,
75    from: u64,
76) -> eyre::Result<()> {
77    info!(target: "reth::cli", "Executing stage.");
78
79    let provider = output_provider_factory.database_provider_rw()?;
80    let mut stage = StorageHashingStage {
81        clean_threshold: 1, // Forces hashing from scratch
82        ..Default::default()
83    };
84
85    loop {
86        let input = reth_stages::ExecInput {
87            target: Some(to),
88            checkpoint: Some(StageCheckpoint::new(from)),
89        };
90        if stage.execute(&provider, input)?.done {
91            break
92        }
93    }
94
95    info!(target: "reth::cli", "Success.");
96
97    Ok(())
98}