diff --git a/crates/cli/commands/src/node.rs b/crates/cli/commands/src/node.rs index cba857a3a8..a0d729499d 100644 --- a/crates/cli/commands/src/node.rs +++ b/crates/cli/commands/src/node.rs @@ -10,7 +10,8 @@ use reth_node_builder::NodeBuilder; use reth_node_core::{ args::{ DatabaseArgs, DatadirArgs, DebugArgs, DevArgs, EngineArgs, EraArgs, MetricArgs, - NetworkArgs, PayloadBuilderArgs, PruningArgs, RpcServerArgs, StaticFilesArgs, TxPoolArgs, + NetworkArgs, PayloadBuilderArgs, PruningArgs, RocksDbArgs, RpcServerArgs, StaticFilesArgs, + TxPoolArgs, }, node_config::NodeConfig, version, @@ -102,6 +103,10 @@ pub struct NodeCommand number table to `RocksDB` instead of MDBX. + #[arg(long = "rocksdb.tx-hash", action = ArgAction::Set)] + pub tx_hash: Option, + + /// Route storages history tables to `RocksDB` instead of MDBX. + #[arg(long = "rocksdb.storages-history", action = ArgAction::Set)] + pub storages_history: Option, + + /// Route account history tables to `RocksDB` instead of MDBX. + #[arg(long = "rocksdb.account-history", action = ArgAction::Set)] + pub account_history: Option, +} + +impl RocksDbArgs { + /// Validates the `RocksDB` arguments. + /// + /// Returns an error if `--rocksdb.all` is used with any individual flag set to `false`. + pub fn validate(&self) -> Result<(), RocksDbArgsError> { + if self.all { + if self.tx_hash == Some(false) { + return Err(RocksDbArgsError::ConflictingFlags("tx-hash")); + } + if self.storages_history == Some(false) { + return Err(RocksDbArgsError::ConflictingFlags("storages-history")); + } + if self.account_history == Some(false) { + return Err(RocksDbArgsError::ConflictingFlags("account-history")); + } + } + Ok(()) + } +} + +/// Error type for `RocksDB` argument validation. +#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)] +pub enum RocksDbArgsError { + /// `--rocksdb.all` cannot be combined with an individual flag set to false. + #[error("--rocksdb.all cannot be combined with --rocksdb.{0}=false")] + ConflictingFlags(&'static str), +} + +#[cfg(test)] +mod tests { + use super::*; + use clap::Parser; + + #[derive(Parser)] + struct CommandParser { + #[command(flatten)] + args: T, + } + + #[test] + fn test_default_rocksdb_args() { + let args = CommandParser::::parse_from(["reth"]).args; + assert_eq!(args, RocksDbArgs::default()); + } + + #[test] + fn test_parse_all_flag() { + let args = CommandParser::::parse_from(["reth", "--rocksdb.all"]).args; + assert!(args.all); + assert_eq!(args.tx_hash, None); + } + + #[test] + fn test_parse_individual_flags() { + let args = CommandParser::::parse_from([ + "reth", + "--rocksdb.tx-hash=true", + "--rocksdb.storages-history=false", + "--rocksdb.account-history=true", + ]) + .args; + assert!(!args.all); + assert_eq!(args.tx_hash, Some(true)); + assert_eq!(args.storages_history, Some(false)); + assert_eq!(args.account_history, Some(true)); + } + + #[test] + fn test_validate_all_alone_ok() { + let args = RocksDbArgs { all: true, ..Default::default() }; + assert!(args.validate().is_ok()); + } + + #[test] + fn test_validate_all_with_true_ok() { + let args = RocksDbArgs { all: true, tx_hash: Some(true), ..Default::default() }; + assert!(args.validate().is_ok()); + } + + #[test] + fn test_validate_all_with_false_errors() { + let args = RocksDbArgs { all: true, tx_hash: Some(false), ..Default::default() }; + assert_eq!(args.validate(), Err(RocksDbArgsError::ConflictingFlags("tx-hash"))); + + let args = RocksDbArgs { all: true, storages_history: Some(false), ..Default::default() }; + assert_eq!(args.validate(), Err(RocksDbArgsError::ConflictingFlags("storages-history"))); + + let args = RocksDbArgs { all: true, account_history: Some(false), ..Default::default() }; + assert_eq!(args.validate(), Err(RocksDbArgsError::ConflictingFlags("account-history"))); + } +} diff --git a/crates/node/core/src/node_config.rs b/crates/node/core/src/node_config.rs index 1d5b1700cb..aeff14a875 100644 --- a/crates/node/core/src/node_config.rs +++ b/crates/node/core/src/node_config.rs @@ -3,7 +3,7 @@ use crate::{ args::{ DatabaseArgs, DatadirArgs, DebugArgs, DevArgs, EngineArgs, NetworkArgs, PayloadBuilderArgs, - PruningArgs, RpcServerArgs, StaticFilesArgs, TxPoolArgs, + PruningArgs, RocksDbArgs, RpcServerArgs, StaticFilesArgs, TxPoolArgs, }, dirs::{ChainPath, DataDirPath}, utils::get_single_header, @@ -21,6 +21,7 @@ use reth_primitives_traits::SealedHeader; use reth_stages_types::StageId; use reth_storage_api::{ BlockHashReader, DatabaseProviderFactory, HeaderProvider, StageCheckpointReader, + StorageSettings, }; use reth_storage_errors::provider::ProviderResult; use reth_transaction_pool::TransactionPool; @@ -150,6 +151,9 @@ pub struct NodeConfig { /// All static files related arguments pub static_files: StaticFilesArgs, + + /// All `RocksDB` table routing arguments + pub rocksdb: RocksDbArgs, } impl NodeConfig { @@ -181,6 +185,7 @@ impl NodeConfig { engine: EngineArgs::default(), era: EraArgs::default(), static_files: StaticFilesArgs::default(), + rocksdb: RocksDbArgs::default(), } } @@ -255,6 +260,7 @@ impl NodeConfig { engine, era, static_files, + rocksdb, .. } = self; NodeConfig { @@ -274,6 +280,7 @@ impl NodeConfig { engine, era, static_files, + rocksdb, } } @@ -350,6 +357,22 @@ impl NodeConfig { self.pruning.prune_config(&self.chain) } + /// Returns the effective storage settings derived from static-file and `RocksDB` CLI args. + pub fn storage_settings(&self) -> StorageSettings { + let tx_hash = self.rocksdb.all || self.rocksdb.tx_hash.unwrap_or(false); + let storages_history = self.rocksdb.all || self.rocksdb.storages_history.unwrap_or(false); + let account_history = self.rocksdb.all || self.rocksdb.account_history.unwrap_or(false); + + StorageSettings { + receipts_in_static_files: self.static_files.receipts, + transaction_senders_in_static_files: self.static_files.transaction_senders, + account_changesets_in_static_files: self.static_files.account_changesets, + transaction_hash_numbers_in_rocksdb: tx_hash, + storages_history_in_rocksdb: storages_history, + account_history_in_rocksdb: account_history, + } + } + /// Returns the max block that the node should run to, looking it up from the network if /// necessary pub async fn max_block( @@ -544,6 +567,7 @@ impl NodeConfig { engine: self.engine, era: self.era, static_files: self.static_files, + rocksdb: self.rocksdb, } } @@ -585,6 +609,7 @@ impl Clone for NodeConfig { engine: self.engine.clone(), era: self.era.clone(), static_files: self.static_files, + rocksdb: self.rocksdb, } } } diff --git a/docs/vocs/docs/pages/cli/op-reth/node.mdx b/docs/vocs/docs/pages/cli/op-reth/node.mdx index 25e248076c..cba041cbe7 100644 --- a/docs/vocs/docs/pages/cli/op-reth/node.mdx +++ b/docs/vocs/docs/pages/cli/op-reth/node.mdx @@ -897,6 +897,27 @@ Pruning: --prune.bodies.before Prune storage history before the specified block number. The specified block number is not pruned +RocksDB: + --rocksdb.all + Route all supported tables to `RocksDB` instead of MDBX. + + This enables `RocksDB` for `tx-hash`, `storages-history`, and `account-history` tables. Cannot be combined with individual flags set to false. + + --rocksdb.tx-hash + Route tx hash -> number table to `RocksDB` instead of MDBX + + [possible values: true, false] + + --rocksdb.storages-history + Route storages history tables to `RocksDB` instead of MDBX + + [possible values: true, false] + + --rocksdb.account-history + Route account history tables to `RocksDB` instead of MDBX + + [possible values: true, false] + Engine: --engine.persistence-threshold Configure persistence threshold for the engine. This determines how many canonical blocks must be in-memory, ahead of the last persisted block, before flushing canonical blocks to disk again. diff --git a/docs/vocs/docs/pages/cli/reth/node.mdx b/docs/vocs/docs/pages/cli/reth/node.mdx index 9eb5b2ddbf..328a22c445 100644 --- a/docs/vocs/docs/pages/cli/reth/node.mdx +++ b/docs/vocs/docs/pages/cli/reth/node.mdx @@ -897,6 +897,27 @@ Pruning: --prune.bodies.before Prune storage history before the specified block number. The specified block number is not pruned +RocksDB: + --rocksdb.all + Route all supported tables to `RocksDB` instead of MDBX. + + This enables `RocksDB` for `tx-hash`, `storages-history`, and `account-history` tables. Cannot be combined with individual flags set to false. + + --rocksdb.tx-hash + Route tx hash -> number table to `RocksDB` instead of MDBX + + [possible values: true, false] + + --rocksdb.storages-history + Route storages history tables to `RocksDB` instead of MDBX + + [possible values: true, false] + + --rocksdb.account-history + Route account history tables to `RocksDB` instead of MDBX + + [possible values: true, false] + Engine: --engine.persistence-threshold Configure persistence threshold for the engine. This determines how many canonical blocks must be in-memory, ahead of the last persisted block, before flushing canonical blocks to disk again.