Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Support db get for duptables (CLI) #4653

Merged
merged 15 commits into from
Dec 21, 2023
1 change: 0 additions & 1 deletion bin/reth/src/db/clear.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ impl<DB: Database> TableViewer<()> for ClearViewer<'_, DB> {
let tx = self.db.tx_mut()?;
tx.clear::<T>()?;
tx.commit()?;

Ok(())
}
}
43 changes: 34 additions & 9 deletions bin/reth/src/db/get.rs
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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<String>,

/// Output bytes instead of human-readable decoded value
#[clap(long)]
pub raw: bool,
Expand All @@ -24,12 +31,6 @@ pub struct Command {
impl Command {
/// Execute `db get` command
pub fn execute<DB: Database>(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(())
Expand All @@ -41,6 +42,13 @@ impl Command {

serde_json::from_str::<T::Key>(&self.key).map_err(|e| eyre::eyre!(e))
}

/// Get an instance of subkey for given dupsort table
fn table_subkey<T: DupSort>(&self) -> Result<T::SubKey, eyre::Error> {
assert_eq!(T::NAME, self.table.name());
serde_json::from_str::<T::SubKey>(&self.subkey.clone().unwrap_or_default())
.map_err(|e| eyre::eyre!(e))
}
}

struct GetValueViewer<'a, DB: Database> {
Expand All @@ -52,7 +60,6 @@ impl<DB: Database> TableViewer<()> for GetValueViewer<'_, DB> {
type Error = eyre::Report;

fn view<T: Table>(&self) -> Result<(), Self::Error> {
// get a key for given table
let key = self.args.table_key::<T>()?;

let content = if self.args.raw {
Expand All @@ -74,6 +81,24 @@ impl<DB: Database> TableViewer<()> for GetValueViewer<'_, DB> {

Ok(())
}

fn view_dupsort<T: DupSort>(&self) -> Result<(), Self::Error> {
// get a key for given table
let key = self.args.table_key::<T>()?;

// process dupsort table
let subkey = self.args.table_subkey::<T>()?;

match self.tool.get_dup::<T>(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
Expand Down
2 changes: 1 addition & 1 deletion bin/reth/src/db/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ impl TableViewer<()> for ListTableViewer<'_> {
final_entry_idx = total_entries - 1,
table = self.args.table.name()
);
return Ok(());
return Ok(())
}


Expand Down
11 changes: 9 additions & 2 deletions bin/reth/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -194,6 +194,13 @@ impl<'a, DB: Database> DbTool<'a, DB> {
self.db.view(|tx| tx.get::<T>(key))?.map_err(|e| eyre::eyre!(e))
}

/// Grabs the content of the DupSort table for the given key and subkey
pub fn get_dup<T: DupSort>(&self, key: T::Key, subkey: T::SubKey) -> Result<Option<T::Value>> {
self.db
.view(|tx| tx.cursor_dup_read::<T>()?.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<Path>) -> Result<()> {
let path = path.as_ref();
Expand Down
117 changes: 77 additions & 40 deletions crates/storage/db/src/tables/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -71,7 +74,12 @@ pub const NUM_TABLES: usize = 26;
/// type Error = &'static str;
///
/// fn view<T: Table>(&self) -> Result<(), Self::Error> {
/// // operate on table in generic way
/// // operate on table in a generic way
/// Ok(())
/// }
///
/// fn view_dupsort<T: DupSort>(&self) -> Result<(), Self::Error> {
/// // operate on a dupsort table in a generic way
/// Ok(())
/// }
/// }
Expand All @@ -82,42 +90,61 @@ pub const NUM_TABLES: usize = 26;
/// let _ = transactions.view(&viewer);
/// ```
pub trait TableViewer<R> {
/// 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<T: Table>(&self) -> Result<R, Self::Error>;

/// Operate on the dupsort table in a generic way.
/// By default, the `view` function is invoked unless overridden.
fn view_dupsort<T: DupSort>(&self) -> Result<R, Self::Error> {
self.view::<T>()
}
}

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 {
$(
#[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 {
match self {
$(Tables::$table => {
$table::NAME
},)*
$(Tables::$dupsort => {
$dupsort::NAME
},)*
}
}

/// The type of the given table in database
pub const fn table_type(&self) -> TableType {
match self {
$(Tables::$table => {
$type
TableType::Table
},)*
$(Tables::$dupsort => {
TableType::DupSort
},)*
}
}
Expand All @@ -131,6 +158,9 @@ macro_rules! tables {
$(Tables::$table => {
visitor.view::<$table>()
},)*
$(Tables::$dupsort => {
visitor.view_dupsort::<$dupsort>()
},)*
}
}
}
Expand All @@ -147,10 +177,13 @@ macro_rules! tables {
fn from_str(s: &str) -> Result<Self, Self::Err> {
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())
}
}
}
Expand All @@ -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.
Expand Down Expand Up @@ -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]
Expand Down
Loading