use super::setup; use eyre::Result; use reth_db::{tables, DatabaseEnv}; use reth_db_api::{database::Database, table::TableImporter}; use reth_db_common::DbTool; use reth_node_core::dirs::{ChainPath, DataDirPath}; use reth_primitives::BlockNumber; use reth_provider::{providers::StaticFileProvider, ProviderFactory}; use reth_stages::{stages::AccountHashingStage, Stage, StageCheckpoint, UnwindInput}; use tracing::info; pub(crate) async fn dump_hashing_account_stage( db_tool: &DbTool, from: BlockNumber, to: BlockNumber, output_datadir: ChainPath, should_run: bool, ) -> Result<()> { let (output_db, tip_block_number) = setup(from, to, &output_datadir.db(), db_tool)?; // Import relevant AccountChangeSets output_db.update(|tx| { tx.import_table_with_range::( &db_tool.provider_factory.db_ref().tx()?, Some(from), to, ) })??; unwind_and_copy(db_tool, from, tip_block_number, &output_db)?; if should_run { dry_run( ProviderFactory::new( output_db, db_tool.chain(), StaticFileProvider::read_write(output_datadir.static_files())?, ), to, from, )?; } Ok(()) } /// Dry-run an unwind to FROM block and copy the necessary table data to the new database. fn unwind_and_copy( db_tool: &DbTool, from: u64, tip_block_number: u64, output_db: &DatabaseEnv, ) -> eyre::Result<()> { let provider = db_tool.provider_factory.provider_rw()?; let mut exec_stage = AccountHashingStage::default(); exec_stage.unwind( &provider, UnwindInput { unwind_to: from, checkpoint: StageCheckpoint::new(tip_block_number), bad_block: None, }, )?; let unwind_inner_tx = provider.into_tx(); output_db.update(|tx| tx.import_table::(&unwind_inner_tx))??; Ok(()) } /// Try to re-execute the stage straight away fn dry_run( output_provider_factory: ProviderFactory, to: u64, from: u64, ) -> eyre::Result<()> { info!(target: "reth::cli", "Executing stage."); let provider = output_provider_factory.provider_rw()?; let mut stage = AccountHashingStage { clean_threshold: 1, // Forces hashing from scratch ..Default::default() }; loop { let input = reth_stages::ExecInput { target: Some(to), checkpoint: Some(StageCheckpoint::new(from)), }; if stage.execute(&provider, input)?.done { break } } info!(target: "reth::cli", "Success."); Ok(()) }