From 6810cd1295f99e2bec87c06023cb9cd45700793e Mon Sep 17 00:00:00 2001 From: Mateusz Date: Thu, 22 Jun 2023 20:04:01 +0200 Subject: [PATCH] feat(db): add helper enum for table name (#2935) Co-authored-by: Matthias Seitz --- bin/reth/src/db/get.rs | 92 ++++---- bin/reth/src/db/list.rs | 85 +++++++ bin/reth/src/db/mod.rs | 99 +-------- bin/reth/src/prometheus_exporter.rs | 10 +- bin/reth/src/utils.rs | 4 +- crates/storage/db/src/abstraction/table.rs | 6 +- .../storage/db/src/implementation/mdbx/mod.rs | 11 +- .../storage/db/src/implementation/mdbx/tx.rs | 12 +- crates/storage/db/src/tables/mod.rs | 210 +++++++++++++++--- crates/storage/db/src/tables/raw.rs | 4 +- 10 files changed, 333 insertions(+), 200 deletions(-) create mode 100644 bin/reth/src/db/list.rs diff --git a/bin/reth/src/db/get.rs b/bin/reth/src/db/get.rs index 32ede8c7a1..5e4b127b37 100644 --- a/bin/reth/src/db/get.rs +++ b/bin/reth/src/db/get.rs @@ -1,8 +1,7 @@ use crate::utils::DbTool; use clap::Parser; -use eyre::WrapErr; -use reth_db::{database::Database, table::Table, tables}; -use serde::Deserialize; + +use reth_db::{database::Database, table::Table, TableType, TableViewer, Tables}; use tracing::error; /// The arguments for the `reth db get` command @@ -12,75 +11,60 @@ pub struct Command { /// /// NOTE: The dupsort tables are not supported now. #[arg()] - pub table: String, // TODO: Convert to enum + pub table: Tables, - /// The key to get content for + /// The key to get content for #[arg(value_parser = maybe_json_value_parser)] pub key: String, } impl Command { /// Execute `db get` command - pub fn execute(self, mut tool: DbTool<'_, DB>) -> eyre::Result<()> { - macro_rules! table_get { - ([$($table:ident),*]) => { - match self.table.as_str() { - $(stringify!($table) => { - let table_key = self.table_key::().wrap_err("Could not parse the given table key.")?; + pub fn execute(self, tool: &DbTool<'_, DB>) -> eyre::Result<()> { + if self.table.table_type() == TableType::DupSort { + error!(target: "reth::cli", "Unsupported table."); - match tool.get::(table_key)? { - Some(content) => { - println!("{}", serde_json::to_string_pretty(&content)?); - } - None => { - error!(target: "reth::cli", "No content for the given table key."); - }, - }; - return Ok(()); - },)* - _ => { - error!(target: "reth::cli", "Unknown or unsupported table."); - return Ok(()); - } - } - } + return Ok(()) } - table_get!([ - CanonicalHeaders, - HeaderTD, - HeaderNumbers, - Headers, - BlockBodyIndices, - BlockOmmers, - BlockWithdrawals, - TransactionBlock, - Transactions, - TxHashNumber, - Receipts, - PlainAccountState, - Bytecodes, - AccountHistory, - StorageHistory, - HashedAccount, - AccountsTrie, - TxSenders, - SyncStage, - SyncStageProgress - ]); + self.table.view(&GetValueViewer { tool, args: &self })?; + + Ok(()) } /// Get an instance of key for given table - fn table_key(&self) -> Result - where - for<'a> T::Key: Deserialize<'a>, - { - assert_eq!(T::NAME, self.table); + pub fn table_key(&self) -> Result { + assert_eq!(T::NAME, self.table.name()); serde_json::from_str::(&self.key).map_err(|e| eyre::eyre!(e)) } } +struct GetValueViewer<'a, DB: Database> { + tool: &'a DbTool<'a, DB>, + args: &'a Command, +} + +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::()?; + + match self.tool.get::(key)? { + Some(content) => { + println!("{}", serde_json::to_string_pretty(&content)?); + } + None => { + error!(target: "reth::cli", "No content for the given table key."); + } + }; + + Ok(()) + } +} + /// Map the user input value to json fn maybe_json_value_parser(value: &str) -> Result { if serde_json::from_str::(value).is_ok() { diff --git a/bin/reth/src/db/list.rs b/bin/reth/src/db/list.rs new file mode 100644 index 0000000000..a4059fcf9c --- /dev/null +++ b/bin/reth/src/db/list.rs @@ -0,0 +1,85 @@ +use crate::utils::DbTool; +use clap::Parser; + +use super::tui::DbListTUI; +use eyre::WrapErr; +use reth_db::{ + database::Database, + mdbx::{Env, WriteMap}, + table::Table, + TableType, TableViewer, Tables, +}; +use tracing::error; + +const DEFAULT_NUM_ITEMS: &str = "5"; + +#[derive(Parser, Debug)] +/// The arguments for the `reth db list` command +pub struct Command { + /// The table name + table: Tables, + /// Skip first N entries + #[arg(long, short, default_value = "0")] + skip: usize, + /// Reverse the order of the entries. If enabled last table entries are read. + #[arg(long, short, default_value = "false")] + reverse: bool, + /// How many items to take from the walker + #[arg(long, short, default_value = DEFAULT_NUM_ITEMS)] + len: usize, + /// Dump as JSON instead of using TUI. + #[arg(long, short)] + json: bool, +} + +impl Command { + /// Execute `db list` command + pub fn execute(self, tool: &DbTool<'_, Env>) -> eyre::Result<()> { + if self.table.table_type() == TableType::DupSort { + error!(target: "reth::cli", "Unsupported table."); + } + + self.table.view(&ListTableViewer { tool, args: &self })?; + + Ok(()) + } +} + +struct ListTableViewer<'a> { + tool: &'a DbTool<'a, Env>, + args: &'a Command, +} + +impl TableViewer<()> for ListTableViewer<'_> { + type Error = eyre::Report; + + fn view(&self) -> Result<(), Self::Error> { + self.tool.db.view(|tx| { + let table_db = tx.inner.open_db(Some(self.args.table.name())).wrap_err("Could not open db.")?; + let stats = tx.inner.db_stat(&table_db).wrap_err(format!("Could not find table: {}", stringify!($table)))?; + let total_entries = stats.entries(); + if self.args.skip > total_entries - 1 { + error!( + target: "reth::cli", + "Start index {start} is greater than the final entry index ({final_entry_idx}) in the table {table}", + start = self.args.skip, + final_entry_idx = total_entries - 1, + table = self.args.table.name() + ); + return Ok(()); + } + + if self.args.json { + let list_result = self.tool.list::(self.args.skip, self.args.len, self.args.reverse)?.into_iter().collect::>(); + println!("{}", serde_json::to_string_pretty(&list_result)?); + Ok(()) + } else { + DbListTUI::<_, T>::new(|skip, count| { + self.tool.list::(skip, count, self.args.reverse).unwrap() + }, self.args.skip, self.args.len, total_entries).run() + } + })??; + + Ok(()) + } +} diff --git a/bin/reth/src/db/mod.rs b/bin/reth/src/db/mod.rs index 43051d07b6..27f188c2a4 100644 --- a/bin/reth/src/db/mod.rs +++ b/bin/reth/src/db/mod.rs @@ -10,15 +10,15 @@ use eyre::WrapErr; use human_bytes::human_bytes; use reth_db::{ database::Database, - tables, version::{get_db_version, DatabaseVersionError, DB_VERSION}, + Tables, }; use reth_primitives::ChainSpec; use reth_staged_sync::utils::init::init_db; use std::sync::Arc; -use tracing::error; mod get; +mod list; /// DB List TUI mod tui; @@ -57,15 +57,13 @@ pub struct Command { command: Subcommands, } -const DEFAULT_NUM_ITEMS: &str = "5"; - #[derive(Subcommand, Debug)] /// `reth db` subcommands pub enum Subcommands { /// Lists all the tables, their entry count and their size Stats, /// Lists the contents of a table - List(ListArgs), + List(list::Command), /// Gets the content of a table for the given key Get(get::Command), /// Deletes all database entries @@ -76,25 +74,6 @@ pub enum Subcommands { Path, } -#[derive(Parser, Debug)] -/// The arguments for the `reth db list` command -pub struct ListArgs { - /// The table name - table: String, // TODO: Convert to enum - /// Skip first N entries - #[arg(long, short, default_value = "0")] - skip: usize, - /// Reverse the order of the entries. If enabled last table entries are read. - #[arg(long, short, default_value = "false")] - reverse: bool, - /// How many items to take from the walker - #[arg(long, short, default_value = DEFAULT_NUM_ITEMS)] - len: usize, - /// Dump as JSON instead of using TUI. - #[arg(long, short)] - json: bool, -} - impl Command { /// Execute `db` command pub async fn execute(self) -> eyre::Result<()> { @@ -122,7 +101,7 @@ impl Command { tool.db.view(|tx| { let mut tables = - tables::TABLES.iter().map(|(_, name)| name).collect::>(); + Tables::ALL.iter().map(|table| table.name()).collect::>(); tables.sort(); for table in tables { let table_db = @@ -157,75 +136,11 @@ impl Command { println!("{stats_table}"); } - Subcommands::List(args) => { - macro_rules! table_tui { - ($arg:expr, $start:expr, $len:expr => [$($table:ident),*]) => { - match $arg { - $(stringify!($table) => { - tool.db.view(|tx| { - let table_db = tx.inner.open_db(Some(stringify!($table))).wrap_err("Could not open db.")?; - let stats = tx.inner.db_stat(&table_db).wrap_err(format!("Could not find table: {}", stringify!($table)))?; - let total_entries = stats.entries(); - if $start > total_entries - 1 { - error!( - target: "reth::cli", - "Start index {start} is greater than the final entry index ({final_entry_idx}) in the table {table}", - start = $start, - final_entry_idx = total_entries - 1, - table = stringify!($table) - ); - return Ok(()); - } - - if args.json { - let list_result = tool.list::(args.skip, args.len,args.reverse)?.into_iter().collect::>(); - println!("{}", serde_json::to_string_pretty(&list_result)?); - Ok(()) - } else { - tui::DbListTUI::<_, tables::$table>::new(|skip, count| { - tool.list::(skip, count, args.reverse).unwrap() - }, $start, $len, total_entries).run() - } - })?? - },)* - _ => { - error!(target: "reth::cli", "Unknown table."); - return Ok(()); - } - } - } - } - - table_tui!(args.table.as_str(), args.skip, args.len => [ - CanonicalHeaders, - HeaderTD, - HeaderNumbers, - Headers, - BlockBodyIndices, - BlockOmmers, - BlockWithdrawals, - TransactionBlock, - Transactions, - TxHashNumber, - Receipts, - PlainStorageState, - PlainAccountState, - Bytecodes, - AccountHistory, - StorageHistory, - AccountChangeSet, - StorageChangeSet, - HashedAccount, - HashedStorage, - AccountsTrie, - StoragesTrie, - TxSenders, - SyncStage, - SyncStageProgress - ]); + Subcommands::List(command) => { + command.execute(&tool)?; } Subcommands::Get(command) => { - command.execute(tool)?; + command.execute(&tool)?; } Subcommands::Drop => { tool.drop(db_path)?; diff --git a/bin/reth/src/prometheus_exporter.rs b/bin/reth/src/prometheus_exporter.rs index 2896f0689a..0c9c3bb481 100644 --- a/bin/reth/src/prometheus_exporter.rs +++ b/bin/reth/src/prometheus_exporter.rs @@ -73,7 +73,7 @@ pub(crate) async fn initialize_with_db_metrics( // TODO: A generic stats abstraction for other DB types to deduplicate this and `reth db // stats` let _ = db.view(|tx| { - for table in tables::TABLES.iter().map(|(_, name)| name) { + for table in tables::Tables::ALL.iter().map(|table| table.name()) { let table_db = tx.inner.open_db(Some(table)).wrap_err("Could not open db.")?; @@ -89,10 +89,10 @@ pub(crate) async fn initialize_with_db_metrics( let num_pages = leaf_pages + branch_pages + overflow_pages; let table_size = page_size * num_pages; - absolute_counter!("db.table_size", table_size as u64, "table" => *table); - absolute_counter!("db.table_pages", leaf_pages as u64, "table" => *table, "type" => "leaf"); - absolute_counter!("db.table_pages", branch_pages as u64, "table" => *table, "type" => "branch"); - absolute_counter!("db.table_pages", overflow_pages as u64, "table" => *table, "type" => "overflow"); + absolute_counter!("db.table_size", table_size as u64, "table" => table); + absolute_counter!("db.table_pages", leaf_pages as u64, "table" => table, "type" => "leaf"); + absolute_counter!("db.table_pages", branch_pages as u64, "table" => table, "type" => "branch"); + absolute_counter!("db.table_pages", overflow_pages as u64, "table" => table, "type" => "overflow"); } Ok::<(), eyre::Report>(()) diff --git a/bin/reth/src/utils.rs b/bin/reth/src/utils.rs index fc659cec3c..a6c1b6e0fa 100644 --- a/bin/reth/src/utils.rs +++ b/bin/reth/src/utils.rs @@ -71,7 +71,7 @@ impl<'a, DB: Database> DbTool<'a, DB> { /// Grabs the contents of the table within a certain index range and places the /// entries into a [`HashMap`][std::collections::HashMap]. pub fn list( - &mut self, + &self, skip: usize, len: usize, reverse: bool, @@ -90,7 +90,7 @@ impl<'a, DB: Database> DbTool<'a, DB> { } /// Grabs the content of the table for the given key - pub fn get(&mut self, key: T::Key) -> Result> { + pub fn get(&self, key: T::Key) -> Result> { self.db.view(|tx| tx.get::(key))?.map_err(|e| eyre::eyre!(e)) } diff --git a/crates/storage/db/src/abstraction/table.rs b/crates/storage/db/src/abstraction/table.rs index be8af0a836..65d611f868 100644 --- a/crates/storage/db/src/abstraction/table.rs +++ b/crates/storage/db/src/abstraction/table.rs @@ -4,7 +4,7 @@ use crate::{ DatabaseError, }; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use std::{ fmt::Debug, marker::{Send, Sync}, @@ -53,9 +53,9 @@ pub trait Decode: Send + Sync + Sized + Debug { } /// Generic trait that enforces the database key to implement [`Encode`] and [`Decode`]. -pub trait Key: Encode + Decode + Ord + Clone {} +pub trait Key: Encode + Decode + Ord + Clone + Serialize + for<'a> Deserialize<'a> {} -impl Key for T where T: Encode + Decode + Ord + Clone {} +impl Key for T where T: Encode + Decode + Ord + Clone + Serialize + for<'a> Deserialize<'a> {} /// Generic trait that enforces the database value to implement [`Compress`] and [`Decompress`]. pub trait Value: Compress + Decompress + Serialize {} diff --git a/crates/storage/db/src/implementation/mdbx/mod.rs b/crates/storage/db/src/implementation/mdbx/mod.rs index 68f60b554f..616029acd5 100644 --- a/crates/storage/db/src/implementation/mdbx/mod.rs +++ b/crates/storage/db/src/implementation/mdbx/mod.rs @@ -2,7 +2,7 @@ use crate::{ database::{Database, DatabaseGAT}, - tables::{TableType, TABLES}, + tables::{TableType, Tables}, utils::default_page_size, DatabaseError, }; @@ -67,7 +67,7 @@ impl Env { let env = Env { inner: Environment::new() - .set_max_dbs(TABLES.len()) + .set_max_dbs(Tables::ALL.len()) .set_geometry(Geometry { // Maximum database size of 4 terabytes size: Some(0..(4 * TERABYTE)), @@ -96,13 +96,14 @@ impl Env { pub fn create_tables(&self) -> Result<(), DatabaseError> { let tx = self.inner.begin_rw_txn().map_err(|e| DatabaseError::InitTransaction(e.into()))?; - for (table_type, table) in TABLES { - let flags = match table_type { + for table in Tables::ALL { + let flags = match table.table_type() { TableType::Table => DatabaseFlags::default(), TableType::DupSort => DatabaseFlags::DUP_SORT, }; - tx.create_db(Some(table), flags).map_err(|e| DatabaseError::TableCreation(e.into()))?; + tx.create_db(Some(table.name()), flags) + .map_err(|e| DatabaseError::TableCreation(e.into()))?; } tx.commit().map_err(|e| DatabaseError::Commit(e.into()))?; diff --git a/crates/storage/db/src/implementation/mdbx/tx.rs b/crates/storage/db/src/implementation/mdbx/tx.rs index d6abdd7122..5644723b9d 100644 --- a/crates/storage/db/src/implementation/mdbx/tx.rs +++ b/crates/storage/db/src/implementation/mdbx/tx.rs @@ -3,14 +3,14 @@ use super::cursor::Cursor; use crate::{ table::{Compress, DupSort, Encode, Table, TableImporter}, - tables::{utils::decode_one, NUM_TABLES, TABLES}, + tables::{utils::decode_one, Tables, NUM_TABLES}, transaction::{DbTx, DbTxGAT, DbTxMut, DbTxMutGAT}, DatabaseError, }; use parking_lot::RwLock; use reth_libmdbx::{EnvironmentKind, Transaction, TransactionKind, WriteFlags, DBI, RW}; use reth_metrics::metrics::{self, histogram}; -use std::{marker::PhantomData, sync::Arc, time::Instant}; +use std::{marker::PhantomData, str::FromStr, sync::Arc, time::Instant}; /// Wrapper for the libmdbx transaction. #[derive(Debug)] @@ -39,13 +39,9 @@ impl<'env, K: TransactionKind, E: EnvironmentKind> Tx<'env, K, E> { pub fn get_dbi(&self) -> Result { let mut handles = self.db_handles.write(); - let table_index = TABLES - .iter() - .enumerate() - .find_map(|(idx, (_, table))| (table == &T::NAME).then_some(idx)) - .expect("Requested table should be part of `TABLES`."); + let table = Tables::from_str(T::NAME).expect("Requested table should be part of `Tables`."); - let dbi_handle = handles.get_mut(table_index).expect("should exist"); + let dbi_handle = handles.get_mut(table as usize).expect("should exist"); if dbi_handle.is_none() { *dbi_handle = Some( self.inner diff --git a/crates/storage/db/src/tables/mod.rs b/crates/storage/db/src/tables/mod.rs index a33d69f84c..ba44ce1ea0 100644 --- a/crates/storage/db/src/tables/mod.rs +++ b/crates/storage/db/src/tables/mod.rs @@ -17,7 +17,9 @@ pub mod models; mod raw; pub(crate) mod utils; +use crate::abstraction::table::Table; pub use raw::{RawDupSort, RawKey, RawTable, RawValue}; +use std::{fmt::Display, str::FromStr}; /// Declaration of all Database tables. use crate::{ @@ -40,7 +42,7 @@ use reth_primitives::{ }; /// Enum for the types of tables present in libmdbx. -#[derive(Debug)] +#[derive(Debug, PartialEq, Copy, Clone)] pub enum TableType { /// key value table Table, @@ -51,34 +53,138 @@ pub enum TableType { /// Number of tables that should be present inside database. pub const NUM_TABLES: usize = 25; -/// Default tables that should be present inside database. -pub const TABLES: [(TableType, &str); NUM_TABLES] = [ - (TableType::Table, CanonicalHeaders::const_name()), - (TableType::Table, HeaderTD::const_name()), - (TableType::Table, HeaderNumbers::const_name()), - (TableType::Table, Headers::const_name()), - (TableType::Table, BlockBodyIndices::const_name()), - (TableType::Table, BlockOmmers::const_name()), - (TableType::Table, BlockWithdrawals::const_name()), - (TableType::Table, TransactionBlock::const_name()), - (TableType::Table, Transactions::const_name()), - (TableType::Table, TxHashNumber::const_name()), - (TableType::Table, Receipts::const_name()), - (TableType::Table, PlainAccountState::const_name()), - (TableType::DupSort, PlainStorageState::const_name()), - (TableType::Table, Bytecodes::const_name()), - (TableType::Table, AccountHistory::const_name()), - (TableType::Table, StorageHistory::const_name()), - (TableType::DupSort, AccountChangeSet::const_name()), - (TableType::DupSort, StorageChangeSet::const_name()), - (TableType::Table, HashedAccount::const_name()), - (TableType::DupSort, HashedStorage::const_name()), - (TableType::Table, AccountsTrie::const_name()), - (TableType::DupSort, StoragesTrie::const_name()), - (TableType::Table, TxSenders::const_name()), - (TableType::Table, SyncStage::const_name()), - (TableType::Table, SyncStageProgress::const_name()), -]; +/// The general purpose of this is to use with a combination of Tables enum, +/// by implementing a `TableViewer` trait you can operate on db tables in an abstract way. +/// +/// # Example +/// +/// ``` +/// use reth_db::{ table::Table, TableViewer, Tables }; +/// use std::str::FromStr; +/// +/// let headers = Tables::from_str("Headers").unwrap(); +/// let transactions = Tables::from_str("Transactions").unwrap(); +/// +/// struct MyTableViewer; +/// +/// impl TableViewer<()> for MyTableViewer { +/// type Error = &'static str; +/// +/// fn view(&self) -> Result<(), Self::Error> { +/// // operate on table in generic way +/// Ok(()) +/// } +/// } +/// +/// let viewer = MyTableViewer {}; +/// +/// let _ = headers.view(&viewer); +/// let _ = transactions.view(&viewer); +/// ``` +pub trait TableViewer { + /// type of error to return + type Error; + + /// operate on table in generic way + fn view(&self) -> Result; +} + +macro_rules! tables { + ([$(($table:ident, $type:expr)),*]) => { + #[derive(Debug, PartialEq, Copy, Clone)] + /// Default tables that should be present inside database. + pub enum Tables { + $( + #[doc = concat!("Represents a ", stringify!($table), " table")] + $table, + )* + } + + impl Tables { + /// Array of all tables in database + pub const ALL: [Tables; NUM_TABLES] = [$(Tables::$table,)*]; + + /// The name of the given table in database + pub const fn name(&self) -> &str { + match self { + $(Tables::$table => { + $table::NAME + },)* + } + } + + /// The type of the given table in database + pub const fn table_type(&self) -> TableType { + match self { + $(Tables::$table => { + $type + },)* + } + } + + /// Allows to operate on specific table type + pub fn view(&self, visitor: &T) -> Result + where + T: TableViewer, + { + match self { + $(Tables::$table => { + visitor.view::<$table>() + },)* + } + } + } + + impl Display for Tables { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.name()) + } + } + + impl FromStr for Tables { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + $($table::NAME => { + return Ok(Tables::$table) + },)* + _ => { + return Err("Unknown table".to_string()) + } + } + } + } + }; +} + +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) +]); #[macro_export] /// Macro to declare key value table. @@ -315,3 +421,49 @@ table!( pub type BlockNumberList = IntegerList; /// Encoded stage id. pub type StageId = String; + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use crate::*; + + const TABLES: [(TableType, &str); NUM_TABLES] = [ + (TableType::Table, CanonicalHeaders::const_name()), + (TableType::Table, HeaderTD::const_name()), + (TableType::Table, HeaderNumbers::const_name()), + (TableType::Table, Headers::const_name()), + (TableType::Table, BlockBodyIndices::const_name()), + (TableType::Table, BlockOmmers::const_name()), + (TableType::Table, BlockWithdrawals::const_name()), + (TableType::Table, TransactionBlock::const_name()), + (TableType::Table, Transactions::const_name()), + (TableType::Table, TxHashNumber::const_name()), + (TableType::Table, Receipts::const_name()), + (TableType::Table, PlainAccountState::const_name()), + (TableType::DupSort, PlainStorageState::const_name()), + (TableType::Table, Bytecodes::const_name()), + (TableType::Table, AccountHistory::const_name()), + (TableType::Table, StorageHistory::const_name()), + (TableType::DupSort, AccountChangeSet::const_name()), + (TableType::DupSort, StorageChangeSet::const_name()), + (TableType::Table, HashedAccount::const_name()), + (TableType::DupSort, HashedStorage::const_name()), + (TableType::Table, AccountsTrie::const_name()), + (TableType::DupSort, StoragesTrie::const_name()), + (TableType::Table, TxSenders::const_name()), + (TableType::Table, SyncStage::const_name()), + (TableType::Table, SyncStageProgress::const_name()), + ]; + + #[test] + fn parse_table_from_str() { + for (table_index, &(table_type, table_name)) in TABLES.iter().enumerate() { + let table = Tables::from_str(table_name).unwrap(); + + assert_eq!(table as usize, table_index); + assert_eq!(table.table_type(), table_type); + assert_eq!(table.name(), table_name); + } + } +} diff --git a/crates/storage/db/src/tables/raw.rs b/crates/storage/db/src/tables/raw.rs index 883c759b62..a1cf04ff3d 100644 --- a/crates/storage/db/src/tables/raw.rs +++ b/crates/storage/db/src/tables/raw.rs @@ -2,7 +2,7 @@ use crate::{ table::{Compress, Decode, Decompress, DupSort, Encode, Key, Table, Value}, DatabaseError, }; -use serde::Serialize; +use serde::{Deserialize, Serialize}; /// Raw table that can be used to access any table and its data in raw mode. /// This is useful for delayed decoding/encoding of data. @@ -39,7 +39,7 @@ impl DupSort for RawDupSort { } /// Raw table key. -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] pub struct RawKey { key: Vec, _phantom: std::marker::PhantomData,