diff --git a/bin/reth/src/db/clear.rs b/bin/reth/src/db/clear.rs index 626df4bae01d..e26f60631afe 100644 --- a/bin/reth/src/db/clear.rs +++ b/bin/reth/src/db/clear.rs @@ -33,7 +33,6 @@ impl TableViewer<()> for ClearViewer<'_, DB> { let tx = self.db.tx_mut()?; tx.clear::()?; tx.commit()?; - Ok(()) } } diff --git a/bin/reth/src/db/get.rs b/bin/reth/src/db/get.rs index a998a60396df..cb5527f3e64c 100644 --- a/bin/reth/src/db/get.rs +++ b/bin/reth/src/db/get.rs @@ -1,7 +1,10 @@ use crate::utils::DbTool; use clap::Parser; - -use reth_db::{database::Database, table::Table, RawKey, RawTable, TableType, TableViewer, Tables}; +use reth_db::{ + database::Database, + table::{DupSort, Table}, + RawKey, RawTable, TableViewer, Tables, +}; use tracing::error; /// The arguments for the `reth db get` command @@ -16,6 +19,10 @@ pub struct Command { #[arg(value_parser = maybe_json_value_parser)] pub key: String, + /// The subkey to get content for + #[arg(value_parser = maybe_json_value_parser)] + pub subkey: Option, + /// Output bytes instead of human-readable decoded value #[clap(long)] pub raw: bool, @@ -24,12 +31,6 @@ pub struct Command { impl Command { /// Execute `db get` command pub fn execute(self, tool: &DbTool<'_, DB>) -> eyre::Result<()> { - if self.table.table_type() == TableType::DupSort { - error!(target: "reth::cli", "Unsupported table."); - - return Ok(()) - } - self.table.view(&GetValueViewer { tool, args: &self })?; Ok(()) @@ -41,6 +42,13 @@ impl Command { serde_json::from_str::(&self.key).map_err(|e| eyre::eyre!(e)) } + + /// Get an instance of subkey for given dupsort table + fn table_subkey(&self) -> Result { + assert_eq!(T::NAME, self.table.name()); + serde_json::from_str::(&self.subkey.clone().unwrap_or_default()) + .map_err(|e| eyre::eyre!(e)) + } } struct GetValueViewer<'a, DB: Database> { @@ -52,7 +60,6 @@ impl TableViewer<()> for GetValueViewer<'_, DB> { type Error = eyre::Report; fn view(&self) -> Result<(), Self::Error> { - // get a key for given table let key = self.args.table_key::()?; let content = if self.args.raw { @@ -74,6 +81,24 @@ impl TableViewer<()> for GetValueViewer<'_, DB> { Ok(()) } + + fn view_dupsort(&self) -> Result<(), Self::Error> { + // get a key for given table + let key = self.args.table_key::()?; + + // process dupsort table + let subkey = self.args.table_subkey::()?; + + match self.tool.get_dup::(key, subkey)? { + Some(content) => { + println!("{}", serde_json::to_string_pretty(&content)?); + } + None => { + error!(target: "reth::cli", "No content for the given table subkey."); + } + }; + Ok(()) + } } /// Map the user input value to json diff --git a/bin/reth/src/db/list.rs b/bin/reth/src/db/list.rs index b6c04051adda..49cb4affe9fe 100644 --- a/bin/reth/src/db/list.rs +++ b/bin/reth/src/db/list.rs @@ -101,7 +101,7 @@ impl TableViewer<()> for ListTableViewer<'_> { final_entry_idx = total_entries - 1, table = self.args.table.name() ); - return Ok(()); + return Ok(()) } diff --git a/bin/reth/src/utils.rs b/bin/reth/src/utils.rs index 6994fd81e8c1..74af5288cebb 100644 --- a/bin/reth/src/utils.rs +++ b/bin/reth/src/utils.rs @@ -4,9 +4,9 @@ use boyer_moore_magiclen::BMByte; use eyre::Result; use reth_consensus_common::validation::validate_block_standalone; use reth_db::{ - cursor::DbCursorRO, + cursor::{DbCursorRO, DbDupCursorRO}, database::Database, - table::{Decode, Decompress, Table, TableRow}, + table::{Decode, Decompress, DupSort, Table, TableRow}, transaction::{DbTx, DbTxMut}, DatabaseError, RawTable, TableRawRow, }; @@ -194,6 +194,13 @@ impl<'a, DB: Database> DbTool<'a, DB> { self.db.view(|tx| tx.get::(key))?.map_err(|e| eyre::eyre!(e)) } + /// Grabs the content of the DupSort table for the given key and subkey + pub fn get_dup(&self, key: T::Key, subkey: T::SubKey) -> Result> { + self.db + .view(|tx| tx.cursor_dup_read::()?.seek_by_key_subkey(key, subkey))? + .map_err(|e| eyre::eyre!(e)) + } + /// Drops the database at the given path. pub fn drop(&mut self, path: impl AsRef) -> Result<()> { let path = path.as_ref(); diff --git a/crates/storage/db/src/tables/mod.rs b/crates/storage/db/src/tables/mod.rs index 275271f7bc39..dc19a406a96b 100644 --- a/crates/storage/db/src/tables/mod.rs +++ b/crates/storage/db/src/tables/mod.rs @@ -59,7 +59,10 @@ pub const NUM_TABLES: usize = 26; /// # Example /// /// ``` -/// use reth_db::{table::Table, TableViewer, Tables}; +/// use reth_db::{ +/// table::{DupSort, Table}, +/// TableViewer, Tables, +/// }; /// use std::str::FromStr; /// /// let headers = Tables::from_str("Headers").unwrap(); @@ -71,7 +74,12 @@ pub const NUM_TABLES: usize = 26; /// type Error = &'static str; /// /// fn view(&self) -> Result<(), Self::Error> { -/// // operate on table in generic way +/// // operate on table in a generic way +/// Ok(()) +/// } +/// +/// fn view_dupsort(&self) -> Result<(), Self::Error> { +/// // operate on a dupsort table in a generic way /// Ok(()) /// } /// } @@ -82,15 +90,24 @@ pub const NUM_TABLES: usize = 26; /// let _ = transactions.view(&viewer); /// ``` pub trait TableViewer { - /// type of error to return + /// The error type returned by the viewer. type Error; - /// operate on table in generic way + /// Operate on the table in a generic way. fn view(&self) -> Result; + + /// Operate on the dupsort table in a generic way. + /// By default, the `view` function is invoked unless overridden. + fn view_dupsort(&self) -> Result { + self.view::() + } } macro_rules! tables { - ([$(($table:ident, $type:expr)),*]) => { + ([ + (TableType::Table, [$($table:ident),*]), + (TableType::DupSort, [$($dupsort:ident),*]) + ]) => { #[derive(Debug, PartialEq, Copy, Clone)] /// Default tables that should be present inside database. pub enum Tables { @@ -98,11 +115,15 @@ macro_rules! tables { #[doc = concat!("Represents a ", stringify!($table), " table")] $table, )* + $( + #[doc = concat!("Represents a ", stringify!($dupsort), " dupsort table")] + $dupsort, + )* } impl Tables { /// Array of all tables in database - pub const ALL: [Tables; NUM_TABLES] = [$(Tables::$table,)*]; + pub const ALL: [Tables; NUM_TABLES] = [$(Tables::$table,)* $(Tables::$dupsort,)*]; /// The name of the given table in database pub const fn name(&self) -> &str { @@ -110,6 +131,9 @@ macro_rules! tables { $(Tables::$table => { $table::NAME },)* + $(Tables::$dupsort => { + $dupsort::NAME + },)* } } @@ -117,7 +141,10 @@ macro_rules! tables { pub const fn table_type(&self) -> TableType { match self { $(Tables::$table => { - $type + TableType::Table + },)* + $(Tables::$dupsort => { + TableType::DupSort },)* } } @@ -131,6 +158,9 @@ macro_rules! tables { $(Tables::$table => { visitor.view::<$table>() },)* + $(Tables::$dupsort => { + visitor.view_dupsort::<$dupsort>() + },)* } } } @@ -147,10 +177,13 @@ macro_rules! tables { fn from_str(s: &str) -> Result { match s { $($table::NAME => { - return Ok(Tables::$table) + Ok(Tables::$table) + },)* + $($dupsort::NAME => { + Ok(Tables::$dupsort) },)* _ => { - return Err("Unknown table".to_string()) + Err("Unknown table".to_string()) } } } @@ -159,32 +192,36 @@ macro_rules! tables { } tables!([ - (CanonicalHeaders, TableType::Table), - (HeaderTD, TableType::Table), - (HeaderNumbers, TableType::Table), - (Headers, TableType::Table), - (BlockBodyIndices, TableType::Table), - (BlockOmmers, TableType::Table), - (BlockWithdrawals, TableType::Table), - (TransactionBlock, TableType::Table), - (Transactions, TableType::Table), - (TxHashNumber, TableType::Table), - (Receipts, TableType::Table), - (PlainAccountState, TableType::Table), - (PlainStorageState, TableType::DupSort), - (Bytecodes, TableType::Table), - (AccountHistory, TableType::Table), - (StorageHistory, TableType::Table), - (AccountChangeSet, TableType::DupSort), - (StorageChangeSet, TableType::DupSort), - (HashedAccount, TableType::Table), - (HashedStorage, TableType::DupSort), - (AccountsTrie, TableType::Table), - (StoragesTrie, TableType::DupSort), - (TxSenders, TableType::Table), - (SyncStage, TableType::Table), - (SyncStageProgress, TableType::Table), - (PruneCheckpoints, TableType::Table) + ( + TableType::Table, + [ + CanonicalHeaders, + HeaderTD, + HeaderNumbers, + Headers, + BlockBodyIndices, + BlockOmmers, + BlockWithdrawals, + TransactionBlock, + Transactions, + TxHashNumber, + Receipts, + PlainAccountState, + Bytecodes, + AccountHistory, + StorageHistory, + HashedAccount, + AccountsTrie, + TxSenders, + SyncStage, + SyncStageProgress, + PruneCheckpoints + ] + ), + ( + TableType::DupSort, + [PlainStorageState, AccountChangeSet, StorageChangeSet, HashedStorage, StoragesTrie] + ) ]); /// Macro to declare key value table. @@ -439,20 +476,20 @@ mod tests { (TableType::Table, TxHashNumber::NAME), (TableType::Table, Receipts::NAME), (TableType::Table, PlainAccountState::NAME), - (TableType::DupSort, PlainStorageState::NAME), (TableType::Table, Bytecodes::NAME), (TableType::Table, AccountHistory::NAME), (TableType::Table, StorageHistory::NAME), - (TableType::DupSort, AccountChangeSet::NAME), - (TableType::DupSort, StorageChangeSet::NAME), (TableType::Table, HashedAccount::NAME), - (TableType::DupSort, HashedStorage::NAME), (TableType::Table, AccountsTrie::NAME), - (TableType::DupSort, StoragesTrie::NAME), (TableType::Table, TxSenders::NAME), (TableType::Table, SyncStage::NAME), (TableType::Table, SyncStageProgress::NAME), (TableType::Table, PruneCheckpoints::NAME), + (TableType::DupSort, PlainStorageState::NAME), + (TableType::DupSort, AccountChangeSet::NAME), + (TableType::DupSort, StorageChangeSet::NAME), + (TableType::DupSort, HashedStorage::NAME), + (TableType::DupSort, StoragesTrie::NAME), ]; #[test]