Skip to main content

reth_node_core/args/
rpc_state_cache.rs

1use super::{database::parse_byte_size, DefaultRpcServerArgs};
2use clap::{builder::Resettable, Args};
3use reth_rpc_server_types::constants::cache::{
4    DEFAULT_BAL_CACHE_MAX_BYTES, DEFAULT_BAL_CACHE_MAX_LEN, DEFAULT_BLOCK_CACHE_MAX_BYTES,
5    DEFAULT_BLOCK_CACHE_MAX_LEN, DEFAULT_CACHE_IDLE_TIMEOUT, DEFAULT_CONCURRENT_DB_REQUESTS,
6    DEFAULT_MAX_CACHED_TX_HASHES, DEFAULT_RECEIPT_CACHE_MAX_BYTES, DEFAULT_RECEIPT_CACHE_MAX_LEN,
7};
8use std::time::Duration;
9
10/// Parameters to configure RPC state cache.
11#[derive(Debug, Clone, Args, PartialEq, Eq)]
12#[command(next_help_heading = "RPC State Cache")]
13pub struct RpcStateCacheArgs {
14    /// Max number of blocks in cache.
15    #[arg(
16        long = "rpc-cache.max-blocks",
17        default_value_t = DefaultRpcServerArgs::get_global().rpc_state_cache.max_blocks,
18    )]
19    pub max_blocks: u32,
20
21    /// Max number receipts in cache.
22    #[arg(
23        long = "rpc-cache.max-receipts",
24        default_value_t = DefaultRpcServerArgs::get_global().rpc_state_cache.max_receipts,
25    )]
26    pub max_receipts: u32,
27
28    /// Max number of block access lists in cache.
29    #[arg(
30        long = "rpc-cache.max-bals",
31        default_value_t = DefaultRpcServerArgs::get_global().rpc_state_cache.max_bals,
32    )]
33    pub max_bals: u32,
34
35    /// Maximum estimated block cache memory in bytes or with a unit (e.g. 1GB, 500MB).
36    /// Units use powers of 1024. Zero disables caching. The entry count limit also applies.
37    #[arg(long = "rpc-cache.max-blocks-bytes", value_name = "BYTES", value_parser = parse_byte_size, default_value_t = DefaultRpcServerArgs::get_global().rpc_state_cache.max_blocks_bytes)]
38    pub max_blocks_bytes: usize,
39
40    /// Maximum estimated receipts cache memory in bytes or with a unit (e.g. 1GB, 500MB).
41    /// Units use powers of 1024. Zero disables caching. The entry count limit also applies.
42    #[arg(long = "rpc-cache.max-receipts-bytes", value_name = "BYTES", value_parser = parse_byte_size, default_value_t = DefaultRpcServerArgs::get_global().rpc_state_cache.max_receipts_bytes)]
43    pub max_receipts_bytes: usize,
44
45    /// Maximum estimated block access list cache memory in bytes or with a unit (e.g. 1GB, 500MB).
46    /// Units use powers of 1024. Zero disables caching. The entry count limit also applies.
47    #[arg(long = "rpc-cache.max-bals-bytes", value_name = "BYTES", value_parser = parse_byte_size, default_value_t = DefaultRpcServerArgs::get_global().rpc_state_cache.max_bals_bytes)]
48    pub max_bals_bytes: usize,
49
50    /// Evict blocks, receipts, and block access lists after this duration without a cache hit
51    /// (e.g. 5m, 30s). Zero disables expiration. Cleanup starts every 1 to 60 seconds and removes
52    /// at most five entries per cache per poll.
53    #[arg(long = "rpc-cache.idle-timeout", value_name = "DURATION", value_parser = humantime::parse_duration, default_value = humantime::format_duration(DefaultRpcServerArgs::get_global().rpc_state_cache.idle_timeout).to_string())]
54    pub idle_timeout: Duration,
55
56    /// Cache block access lists computed by RPC requests for transaction tracing.
57    #[arg(long = "rpc-cache.cache-computed-bals", default_value_t = DefaultRpcServerArgs::get_global().rpc_state_cache.cache_computed_bals)]
58    pub cache_computed_bals: bool,
59
60    /// Replay new canonical blocks to cache block access lists until native BAL support.
61    ///
62    /// Optionally replay the latest BLOCKS blocks sequentially on startup. Without a count, only
63    /// new blocks are prewarmed. Implies --rpc-cache.cache-computed-bals.
64    /// Prewarming stops when a canonical block with a block access list hash is received.
65    #[arg(
66        long = "rpc-cache.prewarm-bals",
67        value_name = "BLOCKS",
68        num_args = 0..=1,
69        default_missing_value = "0",
70        default_value = Resettable::from(DefaultRpcServerArgs::get_global().rpc_state_cache.prewarm_bals.map(|v| v.to_string().into())),
71        require_equals = true,
72    )]
73    pub prewarm_bals: Option<usize>,
74
75    /// Max number of concurrent database requests.
76    #[arg(
77        long = "rpc-cache.max-concurrent-db-requests",
78        default_value_t = DefaultRpcServerArgs::get_global().rpc_state_cache.max_concurrent_db_requests,
79    )]
80    pub max_concurrent_db_requests: usize,
81
82    /// Maximum number of transaction hashes to cache for transaction lookups.
83    #[arg(
84        long = "rpc-cache.max-cached-tx-hashes",
85        default_value_t = DefaultRpcServerArgs::get_global().rpc_state_cache.max_cached_tx_hashes,
86    )]
87    pub max_cached_tx_hashes: u32,
88}
89
90impl RpcStateCacheArgs {
91    /// Sets the Cache sizes to zero, effectively disabling caching.
92    pub const fn set_zero_lengths(&mut self) {
93        self.max_blocks = 0;
94        self.max_receipts = 0;
95        self.max_bals = 0;
96        self.max_blocks_bytes = 0;
97        self.max_receipts_bytes = 0;
98        self.max_bals_bytes = 0;
99        self.idle_timeout = Duration::ZERO;
100        self.cache_computed_bals = false;
101        self.prewarm_bals = None;
102    }
103}
104
105impl Default for RpcStateCacheArgs {
106    fn default() -> Self {
107        Self {
108            max_blocks: DEFAULT_BLOCK_CACHE_MAX_LEN,
109            max_receipts: DEFAULT_RECEIPT_CACHE_MAX_LEN,
110            max_bals: DEFAULT_BAL_CACHE_MAX_LEN,
111            max_blocks_bytes: DEFAULT_BLOCK_CACHE_MAX_BYTES,
112            max_receipts_bytes: DEFAULT_RECEIPT_CACHE_MAX_BYTES,
113            max_bals_bytes: DEFAULT_BAL_CACHE_MAX_BYTES,
114            idle_timeout: DEFAULT_CACHE_IDLE_TIMEOUT,
115            cache_computed_bals: false,
116            prewarm_bals: None,
117            max_concurrent_db_requests: DEFAULT_CONCURRENT_DB_REQUESTS,
118            max_cached_tx_hashes: DEFAULT_MAX_CACHED_TX_HASHES,
119        }
120    }
121}
122
123#[cfg(test)]
124mod tests {
125    use super::*;
126    use crate::node_config::NodeConfig;
127    use clap::Parser;
128
129    #[derive(Parser)]
130    struct CommandParser {
131        #[command(flatten)]
132        args: RpcStateCacheArgs,
133    }
134
135    #[test]
136    fn rpc_cache_defaults() {
137        let args = CommandParser::parse_from(["reth"]).args;
138        assert_eq!(args, RpcStateCacheArgs::default());
139    }
140
141    #[test]
142    fn rpc_cache_byte_limits_reject_invalid_values() {
143        let overflow = format!("{}0", usize::MAX);
144        let unit_overflow = format!("{}GB", usize::MAX);
145        for flag in [
146            "--rpc-cache.max-blocks-bytes",
147            "--rpc-cache.max-receipts-bytes",
148            "--rpc-cache.max-bals-bytes",
149        ] {
150            for value in ["-1", "-1GB", "1XB", "1.5GB", &overflow, &unit_overflow] {
151                assert!(
152                    CommandParser::try_parse_from(["reth", &format!("{flag}={value}")]).is_err(),
153                    "accepted {flag}={value}"
154                );
155            }
156        }
157    }
158
159    #[test]
160    fn rpc_cache_byte_limits_accept_units() {
161        for (value, expected) in [
162            ("0GB", 0),
163            ("1024B", 1024),
164            ("1KB", 1024),
165            ("500MB", 500 * 1024 * 1024),
166            ("1GB", 1024 * 1024 * 1024),
167            ("1gb", 1024 * 1024 * 1024),
168            (" 500 MB ", 500 * 1024 * 1024),
169            ("1TB", 1024usize.pow(4)),
170        ] {
171            let args = CommandParser::parse_from([
172                "reth",
173                "--rpc-cache.max-blocks-bytes",
174                value,
175                "--rpc-cache.max-receipts-bytes",
176                value,
177                "--rpc-cache.max-bals-bytes",
178                value,
179            ])
180            .args;
181            assert_eq!(args.max_blocks_bytes, expected);
182            assert_eq!(args.max_receipts_bytes, expected);
183            assert_eq!(args.max_bals_bytes, expected);
184        }
185    }
186
187    #[test]
188    fn disabling_rpc_cache_overrides_positive_byte_limits() {
189        let mut config = NodeConfig::default();
190        config.rpc.rpc_state_cache = RpcStateCacheArgs {
191            max_blocks_bytes: 1024,
192            max_receipts_bytes: 2048,
193            max_bals_bytes: 4096,
194            idle_timeout: Duration::from_secs(60),
195            cache_computed_bals: true,
196            prewarm_bals: Some(10),
197            ..Default::default()
198        };
199
200        let args = config.with_disabled_rpc_cache().rpc.rpc_state_cache;
201        assert_eq!(args.max_blocks, 0);
202        assert_eq!(args.max_receipts, 0);
203        assert_eq!(args.max_bals, 0);
204        assert_eq!(args.max_blocks_bytes, 0);
205        assert_eq!(args.max_receipts_bytes, 0);
206        assert_eq!(args.max_bals_bytes, 0);
207        assert_eq!(args.idle_timeout, Duration::ZERO);
208        assert!(!args.cache_computed_bals);
209        assert_eq!(args.prewarm_bals, None);
210    }
211}