reth_cli_commands/recover/
storage_tries.rs1use crate::common::{AccessRights, CliNodeTypes, Environment, EnvironmentArgs};
2use clap::Parser;
3use reth_chainspec::{EthChainSpec, EthereumHardforks};
4use reth_cli::chainspec::ChainSpecParser;
5use reth_cli_runner::CliContext;
6use reth_db::tables;
7use reth_db_api::{
8 cursor::{DbCursorRO, DbDupCursorRW},
9 transaction::DbTx,
10};
11use reth_provider::{BlockNumReader, HeaderProvider, ProviderError};
12use reth_trie::StateRoot;
13use reth_trie_db::DatabaseStateRoot;
14use tracing::*;
15
16#[derive(Debug, Parser)]
18pub struct Command<C: ChainSpecParser> {
19 #[command(flatten)]
20 env: EnvironmentArgs<C>,
21}
22
23impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> Command<C> {
24 pub async fn execute<N: CliNodeTypes<ChainSpec = C::ChainSpec>>(
26 self,
27 _ctx: CliContext,
28 ) -> eyre::Result<()> {
29 let Environment { provider_factory, .. } = self.env.init::<N>(AccessRights::RW)?;
30
31 let mut provider = provider_factory.provider_rw()?;
32 let best_block = provider.best_block_number()?;
33 let best_header = provider
34 .sealed_header(best_block)?
35 .ok_or_else(|| ProviderError::HeaderNotFound(best_block.into()))?;
36
37 let mut deleted_tries = 0;
38 let tx_mut = provider.tx_mut();
39 let mut hashed_account_cursor = tx_mut.cursor_read::<tables::HashedAccounts>()?;
40 let mut storage_trie_cursor = tx_mut.cursor_dup_read::<tables::StoragesTrie>()?;
41 let mut entry = storage_trie_cursor.first()?;
42
43 info!(target: "reth::cli", "Starting pruning of storage tries");
44 while let Some((hashed_address, _)) = entry {
45 if hashed_account_cursor.seek_exact(hashed_address)?.is_none() {
46 deleted_tries += 1;
47 storage_trie_cursor.delete_current_duplicates()?;
48 }
49
50 entry = storage_trie_cursor.next()?;
51 }
52
53 let state_root = StateRoot::from_tx(tx_mut).root()?;
54 if state_root != best_header.state_root {
55 eyre::bail!(
56 "Recovery failed. Incorrect state root. Expected: {:?}. Received: {:?}",
57 best_header.state_root,
58 state_root
59 );
60 }
61
62 provider.commit()?;
63 info!(target: "reth::cli", deleted = deleted_tries, "Finished recovery");
64
65 Ok(())
66 }
67}