reth_node_core/args/
rocksdb.rs

1//! clap [Args](clap::Args) for `RocksDB` table routing configuration
2
3use clap::{ArgAction, Args};
4
5/// Default value for `RocksDB` routing flags.
6///
7/// When the `edge` feature is enabled, defaults to `true` to enable edge storage features.
8/// Otherwise defaults to `false` for legacy behavior.
9const fn default_rocksdb_flag() -> bool {
10    cfg!(feature = "edge")
11}
12
13/// Parameters for `RocksDB` table routing configuration.
14///
15/// These flags control which database tables are stored in `RocksDB` instead of MDBX.
16/// All flags are genesis-initialization-only: changing them after genesis requires a re-sync.
17#[derive(Debug, Args, PartialEq, Eq, Clone, Copy)]
18#[command(next_help_heading = "RocksDB")]
19pub struct RocksDbArgs {
20    /// Route all supported tables to `RocksDB` instead of MDBX.
21    ///
22    /// This enables `RocksDB` for `tx-hash`, `storages-history`, and `account-history` tables.
23    /// Cannot be combined with individual flags set to false.
24    #[arg(long = "rocksdb.all", action = ArgAction::SetTrue)]
25    pub all: bool,
26
27    /// Route tx hash -> number table to `RocksDB` instead of MDBX.
28    ///
29    /// This is a genesis-initialization-only flag: changing it after genesis requires a re-sync.
30    /// Defaults to `true` when the `edge` feature is enabled, `false` otherwise.
31    #[arg(long = "rocksdb.tx-hash", default_value_t = default_rocksdb_flag(), action = ArgAction::Set)]
32    pub tx_hash: bool,
33
34    /// Route storages history tables to `RocksDB` instead of MDBX.
35    ///
36    /// This is a genesis-initialization-only flag: changing it after genesis requires a re-sync.
37    /// Defaults to `true` when the `edge` feature is enabled, `false` otherwise.
38    #[arg(long = "rocksdb.storages-history", default_value_t = default_rocksdb_flag(), action = ArgAction::Set)]
39    pub storages_history: bool,
40
41    /// Route account history tables to `RocksDB` instead of MDBX.
42    ///
43    /// This is a genesis-initialization-only flag: changing it after genesis requires a re-sync.
44    /// Defaults to `true` when the `edge` feature is enabled, `false` otherwise.
45    #[arg(long = "rocksdb.account-history", default_value_t = default_rocksdb_flag(), action = ArgAction::Set)]
46    pub account_history: bool,
47}
48
49impl Default for RocksDbArgs {
50    fn default() -> Self {
51        Self {
52            all: false,
53            tx_hash: default_rocksdb_flag(),
54            storages_history: default_rocksdb_flag(),
55            account_history: default_rocksdb_flag(),
56        }
57    }
58}
59
60impl RocksDbArgs {
61    /// Validates the `RocksDB` arguments.
62    ///
63    /// Returns an error if `--rocksdb.all` is used with any individual flag set to `false`.
64    pub const fn validate(&self) -> Result<(), RocksDbArgsError> {
65        if self.all {
66            if !self.tx_hash {
67                return Err(RocksDbArgsError::ConflictingFlags("tx-hash"));
68            }
69            if !self.storages_history {
70                return Err(RocksDbArgsError::ConflictingFlags("storages-history"));
71            }
72            if !self.account_history {
73                return Err(RocksDbArgsError::ConflictingFlags("account-history"));
74            }
75        }
76        Ok(())
77    }
78}
79
80/// Error type for `RocksDB` argument validation.
81#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
82pub enum RocksDbArgsError {
83    /// `--rocksdb.all` cannot be combined with an individual flag set to false.
84    #[error("--rocksdb.all cannot be combined with --rocksdb.{0}=false")]
85    ConflictingFlags(&'static str),
86}
87
88#[cfg(test)]
89mod tests {
90    use super::*;
91    use clap::Parser;
92
93    #[derive(Parser)]
94    struct CommandParser<T: Args> {
95        #[command(flatten)]
96        args: T,
97    }
98
99    #[test]
100    fn test_default_rocksdb_args() {
101        let args = CommandParser::<RocksDbArgs>::parse_from(["reth"]).args;
102        assert_eq!(args, RocksDbArgs::default());
103    }
104
105    #[test]
106    fn test_parse_all_flag() {
107        let args = CommandParser::<RocksDbArgs>::parse_from(["reth", "--rocksdb.all"]).args;
108        assert!(args.all);
109        assert_eq!(args.tx_hash, default_rocksdb_flag());
110    }
111
112    #[test]
113    fn test_parse_individual_flags() {
114        let args = CommandParser::<RocksDbArgs>::parse_from([
115            "reth",
116            "--rocksdb.tx-hash=true",
117            "--rocksdb.storages-history=false",
118            "--rocksdb.account-history=true",
119        ])
120        .args;
121        assert!(!args.all);
122        assert!(args.tx_hash);
123        assert!(!args.storages_history);
124        assert!(args.account_history);
125    }
126
127    #[test]
128    fn test_validate_all_with_true_ok() {
129        let args =
130            RocksDbArgs { all: true, tx_hash: true, storages_history: true, account_history: true };
131        assert!(args.validate().is_ok());
132    }
133
134    #[test]
135    fn test_validate_all_with_false_errors() {
136        let args = RocksDbArgs {
137            all: true,
138            tx_hash: false,
139            storages_history: true,
140            account_history: true,
141        };
142        assert_eq!(args.validate(), Err(RocksDbArgsError::ConflictingFlags("tx-hash")));
143
144        let args = RocksDbArgs {
145            all: true,
146            tx_hash: true,
147            storages_history: false,
148            account_history: true,
149        };
150        assert_eq!(args.validate(), Err(RocksDbArgsError::ConflictingFlags("storages-history")));
151
152        let args = RocksDbArgs {
153            all: true,
154            tx_hash: true,
155            storages_history: true,
156            account_history: false,
157        };
158        assert_eq!(args.validate(), Err(RocksDbArgsError::ConflictingFlags("account-history")));
159    }
160}