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

Co-authored-by: Dragan Pilipovic <admin@Admins-MacBook-Pro.local>
Co-authored-by: Roman Krasiuk <rokrassyuk@gmail.com>
This commit is contained in:
Srdjan
2023-12-21 15:45:46 +01:00
committed by GitHub
parent c066aa60af
commit b37cd833a4
5 changed files with 121 additions and 53 deletions

View File

@ -33,7 +33,6 @@ impl<DB: Database> TableViewer<()> for ClearViewer<'_, DB> {
let tx = self.db.tx_mut()?;
tx.clear::<T>()?;
tx.commit()?;
Ok(())
}
}

View File

@ -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<String>,
/// 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<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(())
@ -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> {
@ -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 {
@ -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

View File

@ -101,7 +101,7 @@ impl TableViewer<()> for ListTableViewer<'_> {
final_entry_idx = total_entries - 1,
table = self.args.table.name()
);
return Ok(());
return Ok(())
}

View File

@ -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::<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();

View File

@ -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<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(())
/// }
/// }
@ -82,15 +90,24 @@ 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 {
@ -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<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())
}
}
}
@ -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]