reth_cli_commands/db/checksum/
rocksdb.rs1use super::{checksum_hasher, PROGRESS_LOG_INTERVAL};
4use crate::common::CliNodeTypes;
5use clap::ValueEnum;
6use reth_chainspec::EthereumHardforks;
7use reth_db::{tables, DatabaseEnv};
8use reth_db_api::table::Table;
9use reth_db_common::DbTool;
10use reth_node_builder::NodeTypesWithDBAdapter;
11use reth_primitives_traits::FastInstant as Instant;
12use reth_provider::RocksDBProviderFactory;
13use std::hash::Hasher;
14use tracing::info;
15
16#[derive(Debug, Clone, Copy, ValueEnum)]
18pub enum RocksDbTable {
19 TransactionHashNumbers,
21 AccountsHistory,
23 StoragesHistory,
25}
26
27impl RocksDbTable {
28 const fn name(&self) -> &'static str {
30 match self {
31 Self::TransactionHashNumbers => tables::TransactionHashNumbers::NAME,
32 Self::AccountsHistory => tables::AccountsHistory::NAME,
33 Self::StoragesHistory => tables::StoragesHistory::NAME,
34 }
35 }
36}
37
38pub fn checksum_rocksdb<N: CliNodeTypes<ChainSpec: EthereumHardforks>>(
40 tool: &DbTool<NodeTypesWithDBAdapter<N, DatabaseEnv>>,
41 table: RocksDbTable,
42 limit: Option<usize>,
43) -> eyre::Result<()> {
44 let rocksdb = tool.provider_factory.rocksdb_provider();
45
46 let start_time = Instant::now();
47 let limit = limit.unwrap_or(usize::MAX);
48
49 info!(
50 "Computing checksum for RocksDB table `{}`, limit={:?}",
51 table.name(),
52 if limit == usize::MAX { None } else { Some(limit) }
53 );
54
55 let (checksum, total) = match table {
56 RocksDbTable::TransactionHashNumbers => {
57 checksum_rocksdb_table::<tables::TransactionHashNumbers>(&rocksdb, limit)?
58 }
59 RocksDbTable::AccountsHistory => {
60 checksum_rocksdb_table::<tables::AccountsHistory>(&rocksdb, limit)?
61 }
62 RocksDbTable::StoragesHistory => {
63 checksum_rocksdb_table::<tables::StoragesHistory>(&rocksdb, limit)?
64 }
65 };
66
67 let elapsed = start_time.elapsed();
68
69 info!(
70 "Checksum for RocksDB table `{}`: {:#x} ({} entries, elapsed: {:?})",
71 table.name(),
72 checksum,
73 total,
74 elapsed
75 );
76
77 Ok(())
78}
79
80fn checksum_rocksdb_table<T: Table>(
82 rocksdb: &reth_provider::providers::RocksDBProvider,
83 limit: usize,
84) -> eyre::Result<(u64, usize)> {
85 let iter = rocksdb.raw_iter::<T>()?;
86 let mut hasher = checksum_hasher();
87 let mut total = 0usize;
88
89 for entry in iter {
90 let (key_bytes, value_bytes) = entry?;
91
92 hasher.write(&key_bytes);
93 hasher.write(&value_bytes);
94
95 total += 1;
96
97 if total.is_multiple_of(PROGRESS_LOG_INTERVAL) {
98 info!("Hashed {total} entries.");
99 }
100
101 if total >= limit {
102 break;
103 }
104 }
105
106 Ok((hasher.finish(), total))
107}