Skip to main content

reth_node_core/args/
rpc_server.rs

1//! clap [Args](clap::Args) for RPC related arguments.
2
3use crate::args::{
4    types::{MaxU32, ZeroAsNoneU64},
5    GasPriceOracleArgs, RpcStateCacheArgs,
6};
7use alloy_primitives::map::AddressSet;
8use alloy_rpc_types_engine::JwtSecret;
9use clap::{
10    builder::{PossibleValue, RangedU64ValueParser, Resettable, TypedValueParser},
11    Arg, Args, Command,
12};
13use rand::Rng;
14use reth_cli_util::{parse_duration_from_secs_or_ms, parse_ether_value};
15use reth_rpc_eth_types::builder::config::PendingBlockKind;
16use reth_rpc_server_types::{constants, RethRpcModule, RpcModuleSelection};
17use std::{
18    ffi::OsStr,
19    net::{IpAddr, Ipv4Addr},
20    path::PathBuf,
21    sync::OnceLock,
22    time::Duration,
23};
24use url::Url;
25
26use super::types::MaxOr;
27
28/// Global static RPC server defaults
29static RPC_SERVER_DEFAULTS: OnceLock<DefaultRpcServerArgs> = OnceLock::new();
30
31/// Default max number of subscriptions per connection.
32pub(crate) const RPC_DEFAULT_MAX_SUBS_PER_CONN: u32 = 1024;
33
34/// Default max request size in MB.
35pub(crate) const RPC_DEFAULT_MAX_REQUEST_SIZE_MB: u32 = 15;
36
37/// Default max response size in MB.
38///
39/// This is only relevant for very large trace responses.
40pub(crate) const RPC_DEFAULT_MAX_RESPONSE_SIZE_MB: u32 = 160;
41
42/// Default number of incoming connections.
43///
44/// This restricts how many active connections (http, ws) the server accepts.
45/// Once exceeded, the server can reject new connections.
46pub(crate) const RPC_DEFAULT_MAX_CONNECTIONS: u32 = 500;
47
48/// Default values for RPC server that can be customized
49///
50/// Global defaults can be set via [`DefaultRpcServerArgs::try_init`].
51#[derive(Debug, Clone)]
52pub struct DefaultRpcServerArgs {
53    http: bool,
54    http_addr: IpAddr,
55    http_port: u16,
56    http_disable_compression: bool,
57    http_compression_algorithms: Option<Vec<String>>,
58    http_decompression_algorithms: Option<Vec<String>>,
59    http_api: Option<RpcModuleSelection>,
60    http_corsdomain: Option<String>,
61    ws: bool,
62    ws_addr: IpAddr,
63    ws_port: u16,
64    ws_allowed_origins: Option<String>,
65    ws_api: Option<RpcModuleSelection>,
66    ipcdisable: bool,
67    ipcpath: String,
68    ipc_socket_permissions: Option<String>,
69    auth_addr: IpAddr,
70    auth_port: u16,
71    auth_jwtsecret: Option<PathBuf>,
72    auth_ipc: bool,
73    auth_ipc_path: String,
74    disable_auth_server: bool,
75    rpc_jwtsecret: Option<JwtSecret>,
76    rpc_disable_metrics: bool,
77    rpc_max_request_size: MaxU32,
78    rpc_max_response_size: MaxU32,
79    rpc_max_subscriptions_per_connection: MaxU32,
80    rpc_max_connections: MaxU32,
81    rpc_max_tracing_requests: usize,
82    rpc_max_blocking_io_requests: usize,
83    rpc_max_trace_filter_blocks: u64,
84    rpc_max_blocks_per_filter: ZeroAsNoneU64,
85    rpc_max_logs_per_response: ZeroAsNoneU64,
86    rpc_gas_cap: u64,
87    rpc_evm_memory_limit: u64,
88    rpc_tx_fee_cap: u128,
89    rpc_max_simulate_blocks: u64,
90    rpc_compute_state_root_for_eth_simulate: bool,
91    rpc_eth_proof_window: u64,
92    rpc_proof_permits: usize,
93    rpc_pending_block: PendingBlockKind,
94    rpc_forwarder: Option<Url>,
95    builder_disallow: Option<AddressSet>,
96    rpc_state_cache: RpcStateCacheArgs,
97    gas_price_oracle: GasPriceOracleArgs,
98    rpc_send_raw_transaction_sync_timeout: Duration,
99}
100
101impl DefaultRpcServerArgs {
102    /// Initialize the global RPC server defaults with this configuration
103    pub fn try_init(self) -> Result<(), Self> {
104        RPC_SERVER_DEFAULTS.set(self)
105    }
106
107    /// Get a reference to the global RPC server defaults
108    pub fn get_global() -> &'static Self {
109        RPC_SERVER_DEFAULTS.get_or_init(Self::default)
110    }
111
112    /// Set the default HTTP enabled state
113    pub const fn with_http(mut self, v: bool) -> Self {
114        self.http = v;
115        self
116    }
117
118    /// Set the default HTTP address
119    pub const fn with_http_addr(mut self, v: IpAddr) -> Self {
120        self.http_addr = v;
121        self
122    }
123
124    /// Set the default HTTP port
125    pub const fn with_http_port(mut self, v: u16) -> Self {
126        self.http_port = v;
127        self
128    }
129
130    /// Set whether to disable HTTP compression by default
131    pub const fn with_http_disable_compression(mut self, v: bool) -> Self {
132        self.http_disable_compression = v;
133        self
134    }
135
136    /// Set the default allowed HTTP response compression algorithms
137    pub fn with_http_compression_algorithms(mut self, v: Option<Vec<String>>) -> Self {
138        self.http_compression_algorithms = v;
139        self
140    }
141
142    /// Set the default allowed HTTP request decompression algorithms
143    pub fn with_http_decompression_algorithms(mut self, v: Option<Vec<String>>) -> Self {
144        self.http_decompression_algorithms = v;
145        self
146    }
147
148    /// Set the default HTTP API modules
149    pub fn with_http_api(mut self, v: Option<RpcModuleSelection>) -> Self {
150        self.http_api = v;
151        self
152    }
153
154    /// Set the default HTTP CORS domain
155    pub fn with_http_corsdomain(mut self, v: Option<String>) -> Self {
156        self.http_corsdomain = v;
157        self
158    }
159
160    /// Set the default WS enabled state
161    pub const fn with_ws(mut self, v: bool) -> Self {
162        self.ws = v;
163        self
164    }
165
166    /// Set the default WS address
167    pub const fn with_ws_addr(mut self, v: IpAddr) -> Self {
168        self.ws_addr = v;
169        self
170    }
171
172    /// Set the default WS port
173    pub const fn with_ws_port(mut self, v: u16) -> Self {
174        self.ws_port = v;
175        self
176    }
177
178    /// Set the default WS allowed origins
179    pub fn with_ws_allowed_origins(mut self, v: Option<String>) -> Self {
180        self.ws_allowed_origins = v;
181        self
182    }
183
184    /// Set the default WS API modules
185    pub fn with_ws_api(mut self, v: Option<RpcModuleSelection>) -> Self {
186        self.ws_api = v;
187        self
188    }
189
190    /// Set whether to disable IPC by default
191    pub const fn with_ipcdisable(mut self, v: bool) -> Self {
192        self.ipcdisable = v;
193        self
194    }
195
196    /// Set the default IPC path
197    pub fn with_ipcpath(mut self, v: String) -> Self {
198        self.ipcpath = v;
199        self
200    }
201
202    /// Set the default IPC socket permissions
203    pub fn with_ipc_socket_permissions(mut self, v: Option<String>) -> Self {
204        self.ipc_socket_permissions = v;
205        self
206    }
207
208    /// Set the default auth server address
209    pub const fn with_auth_addr(mut self, v: IpAddr) -> Self {
210        self.auth_addr = v;
211        self
212    }
213
214    /// Set the default auth server port
215    pub const fn with_auth_port(mut self, v: u16) -> Self {
216        self.auth_port = v;
217        self
218    }
219
220    /// Set the default auth JWT secret path
221    pub fn with_auth_jwtsecret(mut self, v: Option<PathBuf>) -> Self {
222        self.auth_jwtsecret = v;
223        self
224    }
225
226    /// Set the default auth IPC enabled state
227    pub const fn with_auth_ipc(mut self, v: bool) -> Self {
228        self.auth_ipc = v;
229        self
230    }
231
232    /// Set the default auth IPC path
233    pub fn with_auth_ipc_path(mut self, v: String) -> Self {
234        self.auth_ipc_path = v;
235        self
236    }
237
238    /// Set whether to disable the auth server by default
239    pub const fn with_disable_auth_server(mut self, v: bool) -> Self {
240        self.disable_auth_server = v;
241        self
242    }
243
244    /// Set the default RPC JWT secret
245    pub const fn with_rpc_jwtsecret(mut self, v: Option<JwtSecret>) -> Self {
246        self.rpc_jwtsecret = v;
247        self
248    }
249
250    /// Set whether to disable RPC request metrics by default
251    pub const fn with_rpc_disable_metrics(mut self, v: bool) -> Self {
252        self.rpc_disable_metrics = v;
253        self
254    }
255
256    /// Set the default max request size
257    pub const fn with_rpc_max_request_size(mut self, v: MaxU32) -> Self {
258        self.rpc_max_request_size = v;
259        self
260    }
261
262    /// Set the default max response size
263    pub const fn with_rpc_max_response_size(mut self, v: MaxU32) -> Self {
264        self.rpc_max_response_size = v;
265        self
266    }
267
268    /// Set the default max subscriptions per connection
269    pub const fn with_rpc_max_subscriptions_per_connection(mut self, v: MaxU32) -> Self {
270        self.rpc_max_subscriptions_per_connection = v;
271        self
272    }
273
274    /// Set the default max connections
275    pub const fn with_rpc_max_connections(mut self, v: MaxU32) -> Self {
276        self.rpc_max_connections = v;
277        self
278    }
279
280    /// Set the default max tracing requests
281    pub const fn with_rpc_max_tracing_requests(mut self, v: usize) -> Self {
282        self.rpc_max_tracing_requests = v;
283        self
284    }
285
286    /// Set the default max blocking IO requests
287    pub const fn with_rpc_max_blocking_io_requests(mut self, v: usize) -> Self {
288        self.rpc_max_blocking_io_requests = v;
289        self
290    }
291
292    /// Set the default max trace filter blocks
293    pub const fn with_rpc_max_trace_filter_blocks(mut self, v: u64) -> Self {
294        self.rpc_max_trace_filter_blocks = v;
295        self
296    }
297
298    /// Set the default max blocks per filter
299    pub const fn with_rpc_max_blocks_per_filter(mut self, v: ZeroAsNoneU64) -> Self {
300        self.rpc_max_blocks_per_filter = v;
301        self
302    }
303
304    /// Set the default max logs per response
305    pub const fn with_rpc_max_logs_per_response(mut self, v: ZeroAsNoneU64) -> Self {
306        self.rpc_max_logs_per_response = v;
307        self
308    }
309
310    /// Set the default gas cap
311    pub const fn with_rpc_gas_cap(mut self, v: u64) -> Self {
312        self.rpc_gas_cap = v;
313        self
314    }
315
316    /// Set the default EVM memory limit
317    pub const fn with_rpc_evm_memory_limit(mut self, v: u64) -> Self {
318        self.rpc_evm_memory_limit = v;
319        self
320    }
321
322    /// Set the default tx fee cap
323    pub const fn with_rpc_tx_fee_cap(mut self, v: u128) -> Self {
324        self.rpc_tx_fee_cap = v;
325        self
326    }
327
328    /// Set the default max simulate blocks
329    pub const fn with_rpc_max_simulate_blocks(mut self, v: u64) -> Self {
330        self.rpc_max_simulate_blocks = v;
331        self
332    }
333
334    /// Set whether to compute state roots for `eth_simulateV1` responses by default.
335    pub const fn with_rpc_compute_state_root_for_eth_simulate(mut self, v: bool) -> Self {
336        self.rpc_compute_state_root_for_eth_simulate = v;
337        self
338    }
339
340    /// Set the default eth proof window
341    pub const fn with_rpc_eth_proof_window(mut self, v: u64) -> Self {
342        self.rpc_eth_proof_window = v;
343        self
344    }
345
346    /// Set the default proof permits
347    pub const fn with_rpc_proof_permits(mut self, v: usize) -> Self {
348        self.rpc_proof_permits = v;
349        self
350    }
351
352    /// Set the default pending block kind
353    pub const fn with_rpc_pending_block(mut self, v: PendingBlockKind) -> Self {
354        self.rpc_pending_block = v;
355        self
356    }
357
358    /// Set the default RPC forwarder
359    pub fn with_rpc_forwarder(mut self, v: Option<Url>) -> Self {
360        self.rpc_forwarder = v;
361        self
362    }
363
364    /// Set the default builder disallow addresses
365    pub fn with_builder_disallow(mut self, v: Option<AddressSet>) -> Self {
366        self.builder_disallow = v;
367        self
368    }
369
370    /// Set the default RPC state cache args
371    pub const fn with_rpc_state_cache(mut self, v: RpcStateCacheArgs) -> Self {
372        self.rpc_state_cache = v;
373        self
374    }
375
376    /// Set the default gas price oracle args
377    pub const fn with_gas_price_oracle(mut self, v: GasPriceOracleArgs) -> Self {
378        self.gas_price_oracle = v;
379        self
380    }
381
382    /// Set the default send raw transaction sync timeout
383    pub const fn with_rpc_send_raw_transaction_sync_timeout(mut self, v: Duration) -> Self {
384        self.rpc_send_raw_transaction_sync_timeout = v;
385        self
386    }
387}
388
389impl Default for DefaultRpcServerArgs {
390    fn default() -> Self {
391        Self {
392            http: false,
393            http_addr: Ipv4Addr::LOCALHOST.into(),
394            http_port: constants::DEFAULT_HTTP_RPC_PORT,
395            http_disable_compression: false,
396            http_compression_algorithms: None,
397            http_decompression_algorithms: None,
398            http_api: None,
399            http_corsdomain: None,
400            ws: false,
401            ws_addr: Ipv4Addr::LOCALHOST.into(),
402            ws_port: constants::DEFAULT_WS_RPC_PORT,
403            ws_allowed_origins: None,
404            ws_api: None,
405            ipcdisable: false,
406            ipcpath: constants::DEFAULT_IPC_ENDPOINT.to_string(),
407            ipc_socket_permissions: None,
408            auth_addr: Ipv4Addr::LOCALHOST.into(),
409            auth_port: constants::DEFAULT_AUTH_PORT,
410            auth_jwtsecret: None,
411            auth_ipc: false,
412            auth_ipc_path: constants::DEFAULT_ENGINE_API_IPC_ENDPOINT.to_string(),
413            disable_auth_server: false,
414            rpc_jwtsecret: None,
415            rpc_disable_metrics: false,
416            rpc_max_request_size: RPC_DEFAULT_MAX_REQUEST_SIZE_MB.into(),
417            rpc_max_response_size: RPC_DEFAULT_MAX_RESPONSE_SIZE_MB.into(),
418            rpc_max_subscriptions_per_connection: RPC_DEFAULT_MAX_SUBS_PER_CONN.into(),
419            rpc_max_connections: RPC_DEFAULT_MAX_CONNECTIONS.into(),
420            rpc_max_tracing_requests: constants::default_max_tracing_requests(),
421            rpc_max_blocking_io_requests: constants::DEFAULT_MAX_BLOCKING_IO_REQUEST,
422            rpc_max_trace_filter_blocks: constants::DEFAULT_MAX_TRACE_FILTER_BLOCKS,
423            rpc_max_blocks_per_filter: constants::DEFAULT_MAX_BLOCKS_PER_FILTER.into(),
424            rpc_max_logs_per_response: (constants::DEFAULT_MAX_LOGS_PER_RESPONSE as u64).into(),
425            rpc_gas_cap: constants::gas_oracle::RPC_DEFAULT_GAS_CAP,
426            rpc_evm_memory_limit: (1 << 32) - 1,
427            rpc_tx_fee_cap: constants::DEFAULT_TX_FEE_CAP_WEI,
428            rpc_max_simulate_blocks: constants::DEFAULT_MAX_SIMULATE_BLOCKS,
429            rpc_compute_state_root_for_eth_simulate: false,
430            rpc_eth_proof_window: constants::DEFAULT_ETH_PROOF_WINDOW,
431            rpc_proof_permits: constants::DEFAULT_PROOF_PERMITS,
432            rpc_pending_block: PendingBlockKind::Full,
433            rpc_forwarder: None,
434            builder_disallow: None,
435            rpc_state_cache: RpcStateCacheArgs::default(),
436            gas_price_oracle: GasPriceOracleArgs::default(),
437            rpc_send_raw_transaction_sync_timeout:
438                constants::RPC_DEFAULT_SEND_RAW_TX_SYNC_TIMEOUT_SECS,
439        }
440    }
441}
442
443/// Parameters for configuring the rpc more granularity via CLI
444#[derive(Debug, Clone, Args, PartialEq, Eq)]
445#[command(next_help_heading = "RPC")]
446pub struct RpcServerArgs {
447    /// Enable the HTTP-RPC server
448    #[arg(long, default_value_if("dev", "true", "true"), default_value_t = DefaultRpcServerArgs::get_global().http)]
449    pub http: bool,
450
451    /// Http server address to listen on
452    #[arg(long = "http.addr", default_value_t = DefaultRpcServerArgs::get_global().http_addr)]
453    pub http_addr: IpAddr,
454
455    /// Http server port to listen on
456    #[arg(long = "http.port", default_value_t = DefaultRpcServerArgs::get_global().http_port)]
457    pub http_port: u16,
458
459    /// Disable compression for HTTP responses
460    #[arg(long = "http.disable-compression", default_value_t = DefaultRpcServerArgs::get_global().http_disable_compression)]
461    pub http_disable_compression: bool,
462
463    /// Comma-separated list of allowed compression algorithms for HTTP responses.
464    ///
465    /// If not specified, all supported algorithms are enabled.
466    ///
467    /// Client `Accept-Encoding` quality values select among allowed algorithms; ties prefer
468    /// zstd > br > gzip > deflate. Omitted quality values default to 1; without an acceptable
469    /// allowed algorithm, the response is uncompressed. List order is ignored.
470    #[arg(
471        long = "http.compression",
472        value_name = "ALGOS",
473        value_delimiter = ',',
474        value_parser = ["zstd", "gzip", "deflate", "br"],
475        default_value = Resettable::from(DefaultRpcServerArgs::get_global().http_compression_algorithms.as_ref().map(|v| v.join(",").into()))
476    )]
477    pub http_compression_algorithms: Option<Vec<String>>,
478
479    /// Comma-separated list of allowed decompression algorithms for HTTP requests.
480    ///
481    /// Request decompression is disabled when not specified.
482    #[arg(
483        long = "http.decompression",
484        value_name = "ALGOS",
485        value_delimiter = ',',
486        value_parser = ["zstd", "gzip", "deflate", "br"],
487        default_value = Resettable::from(DefaultRpcServerArgs::get_global().http_decompression_algorithms.as_ref().map(|v| v.join(",").into()))
488    )]
489    pub http_decompression_algorithms: Option<Vec<String>>,
490
491    /// Rpc Modules to be configured for the HTTP server
492    #[arg(long = "http.api", value_parser = RpcModuleSelectionValueParser::default(), default_value = Resettable::from(DefaultRpcServerArgs::get_global().http_api.as_ref().map(|v| v.to_string().into())))]
493    pub http_api: Option<RpcModuleSelection>,
494
495    /// Http Corsdomain to allow request from
496    #[arg(long = "http.corsdomain", default_value = Resettable::from(DefaultRpcServerArgs::get_global().http_corsdomain.as_ref().map(|v| v.to_string().into())))]
497    pub http_corsdomain: Option<String>,
498
499    /// Enable the WS-RPC server
500    #[arg(long, default_value_t = DefaultRpcServerArgs::get_global().ws)]
501    pub ws: bool,
502
503    /// Ws server address to listen on
504    #[arg(long = "ws.addr", default_value_t = DefaultRpcServerArgs::get_global().ws_addr)]
505    pub ws_addr: IpAddr,
506
507    /// Ws server port to listen on
508    #[arg(long = "ws.port", default_value_t = DefaultRpcServerArgs::get_global().ws_port)]
509    pub ws_port: u16,
510
511    /// Origins from which to accept `WebSocket` requests
512    #[arg(id = "ws.origins", long = "ws.origins", alias = "ws.corsdomain", default_value = Resettable::from(DefaultRpcServerArgs::get_global().ws_allowed_origins.as_ref().map(|v| v.to_string().into())))]
513    pub ws_allowed_origins: Option<String>,
514
515    /// Rpc Modules to be configured for the WS server
516    #[arg(long = "ws.api", value_parser = RpcModuleSelectionValueParser::default(), default_value = Resettable::from(DefaultRpcServerArgs::get_global().ws_api.as_ref().map(|v| v.to_string().into())))]
517    pub ws_api: Option<RpcModuleSelection>,
518
519    /// Disable the IPC-RPC server
520    #[arg(long, default_value_t = DefaultRpcServerArgs::get_global().ipcdisable)]
521    pub ipcdisable: bool,
522
523    /// Filename for IPC socket/pipe within the datadir
524    #[arg(long, default_value_t = DefaultRpcServerArgs::get_global().ipcpath.clone())]
525    pub ipcpath: String,
526
527    /// Set the permissions for the IPC socket file, in octal format.
528    ///
529    /// If not specified, the permissions will be set by the system's umask.
530    #[arg(long = "ipc.permissions", default_value = Resettable::from(DefaultRpcServerArgs::get_global().ipc_socket_permissions.as_ref().map(|v| v.to_string().into())))]
531    pub ipc_socket_permissions: Option<String>,
532
533    /// Auth server address to listen on
534    #[arg(long = "authrpc.addr", default_value_t = DefaultRpcServerArgs::get_global().auth_addr)]
535    pub auth_addr: IpAddr,
536
537    /// Auth server port to listen on
538    #[arg(long = "authrpc.port", default_value_t = DefaultRpcServerArgs::get_global().auth_port)]
539    pub auth_port: u16,
540
541    /// Path to a JWT secret to use for the authenticated engine-API RPC server.
542    ///
543    /// This will enforce JWT authentication for all requests coming from the consensus layer.
544    ///
545    /// If no path is provided, a secret will be generated and stored in the datadir under
546    /// `<DIR>/<CHAIN_ID>/jwt.hex`. For mainnet this would be `~/.local/share/reth/mainnet/jwt.hex`
547    /// by default.
548    #[arg(long = "authrpc.jwtsecret", value_name = "PATH", global = true, required = false, conflicts_with = "auth_jwtsecret_hex", default_value = Resettable::from(DefaultRpcServerArgs::get_global().auth_jwtsecret.as_ref().map(|v| v.to_string_lossy().into())))]
549    pub auth_jwtsecret: Option<PathBuf>,
550
551    /// Hex encoded JWT secret to use for the authenticated engine-API RPC server.
552    ///
553    /// This will enforce JWT authentication for all requests coming from the consensus layer.
554    /// Cannot be used together with `--authrpc.jwtsecret`.
555    #[arg(
556        long = "authrpc.jwtsecret-hex",
557        value_name = "HEX",
558        global = true,
559        required = false,
560        conflicts_with = "auth_jwtsecret"
561    )]
562    pub auth_jwtsecret_hex: Option<JwtSecret>,
563
564    /// Enable auth engine API over IPC
565    #[arg(long, default_value_t = DefaultRpcServerArgs::get_global().auth_ipc)]
566    pub auth_ipc: bool,
567
568    /// Filename for auth IPC socket/pipe within the datadir
569    #[arg(long = "auth-ipc.path", default_value_t = DefaultRpcServerArgs::get_global().auth_ipc_path.clone())]
570    pub auth_ipc_path: String,
571
572    /// Disable the auth/engine API server.
573    ///
574    /// This will prevent the authenticated engine-API server from starting. Use this if you're
575    /// running a node that doesn't need to serve engine API requests.
576    #[arg(long = "disable-auth-server", alias = "disable-engine-api", default_value_t = DefaultRpcServerArgs::get_global().disable_auth_server)]
577    pub disable_auth_server: bool,
578
579    /// Hex encoded JWT secret to authenticate the regular RPC server(s), see `--http.api` and
580    /// `--ws.api`.
581    ///
582    /// This is __not__ used for the authenticated engine-API RPC server, see
583    /// `--authrpc.jwtsecret`.
584    #[arg(long = "rpc.jwtsecret", value_name = "HEX", global = true, required = false, default_value = Resettable::from(DefaultRpcServerArgs::get_global().rpc_jwtsecret.as_ref().map(|v| format!("{:?}", v).into())))]
585    pub rpc_jwtsecret: Option<JwtSecret>,
586
587    /// Disable built-in RPC request metrics.
588    #[arg(long = "rpc.disable-metrics", default_value_t = DefaultRpcServerArgs::get_global().rpc_disable_metrics)]
589    pub rpc_disable_metrics: bool,
590
591    /// Set the maximum RPC request payload size for both HTTP and WS in megabytes.
592    ///
593    /// For compressed HTTP requests, this limit applies to both the compressed and decompressed
594    /// payloads.
595    #[arg(long = "rpc.max-request-size", alias = "rpc-max-request-size", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_request_size)]
596    pub rpc_max_request_size: MaxU32,
597
598    /// Set the maximum RPC response payload size for both HTTP and WS in megabytes.
599    #[arg(long = "rpc.max-response-size", alias = "rpc-max-response-size", visible_alias = "rpc.returndata.limit", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_response_size)]
600    pub rpc_max_response_size: MaxU32,
601
602    /// Set the maximum concurrent subscriptions per connection.
603    #[arg(long = "rpc.max-subscriptions-per-connection", alias = "rpc-max-subscriptions-per-connection", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_subscriptions_per_connection)]
604    pub rpc_max_subscriptions_per_connection: MaxU32,
605
606    /// Maximum number of RPC server connections.
607    #[arg(long = "rpc.max-connections", alias = "rpc-max-connections", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_connections)]
608    pub rpc_max_connections: MaxU32,
609
610    /// Maximum number of concurrent tracing requests.
611    ///
612    /// By default this chooses a sensible value based on the number of available cores.
613    /// Tracing requests are generally CPU bound.
614    /// Choosing a value that is higher than the available CPU cores can have a negative impact on
615    /// the performance of the node and affect the node's ability to maintain sync.
616    #[arg(long = "rpc.max-tracing-requests", alias = "rpc-max-tracing-requests", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_tracing_requests)]
617    pub rpc_max_tracing_requests: usize,
618
619    /// Maximum number of concurrent blocking IO requests.
620    ///
621    /// Blocking IO requests include `eth_call`, `eth_estimateGas`, and similar methods that
622    /// require EVM execution. These are spawned as blocking tasks to avoid blocking the async
623    /// runtime.
624    #[arg(long = "rpc.max-blocking-io-requests", alias = "rpc-max-blocking-io-requests", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_blocking_io_requests)]
625    pub rpc_max_blocking_io_requests: usize,
626
627    /// Maximum number of blocks for `trace_filter` requests.
628    #[arg(long = "rpc.max-trace-filter-blocks", alias = "rpc-max-trace-filter-blocks", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_trace_filter_blocks)]
629    pub rpc_max_trace_filter_blocks: u64,
630
631    /// Maximum number of blocks that could be scanned per filter request. (0 = entire chain)
632    #[arg(long = "rpc.max-blocks-per-filter", alias = "rpc-max-blocks-per-filter", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_blocks_per_filter)]
633    pub rpc_max_blocks_per_filter: ZeroAsNoneU64,
634
635    /// Maximum number of logs that can be returned in a single response. (0 = no limit)
636    #[arg(long = "rpc.max-logs-per-response", alias = "rpc-max-logs-per-response", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_logs_per_response)]
637    pub rpc_max_logs_per_response: ZeroAsNoneU64,
638
639    /// Maximum gas limit for `eth_call` and call tracing RPC methods.
640    #[arg(
641        long = "rpc.gascap",
642        alias = "rpc-gascap",
643        value_name = "GAS_CAP",
644        value_parser = MaxOr::new(RangedU64ValueParser::<u64>::new().range(1..)),
645        default_value_t = DefaultRpcServerArgs::get_global().rpc_gas_cap
646    )]
647    pub rpc_gas_cap: u64,
648
649    /// Maximum memory the EVM can allocate per RPC request.
650    #[arg(
651        long = "rpc.evm-memory-limit",
652        alias = "rpc-evm-memory-limit",
653        value_name = "MEMORY_LIMIT",
654        value_parser = MaxOr::new(RangedU64ValueParser::<u64>::new().range(1..)),
655        default_value_t = DefaultRpcServerArgs::get_global().rpc_evm_memory_limit
656    )]
657    pub rpc_evm_memory_limit: u64,
658
659    /// Maximum eth transaction fee (in ether) that can be sent via the RPC APIs (0 = no cap)
660    #[arg(
661        long = "rpc.txfeecap",
662        alias = "rpc-txfeecap",
663        value_name = "TX_FEE_CAP",
664        value_parser = parse_ether_value,
665        default_value = "1.0"
666    )]
667    pub rpc_tx_fee_cap: u128,
668
669    /// Maximum number of blocks for `eth_simulateV1` call.
670    #[arg(
671        long = "rpc.max-simulate-blocks",
672        value_name = "BLOCKS_COUNT",
673        default_value_t = DefaultRpcServerArgs::get_global().rpc_max_simulate_blocks
674    )]
675    pub rpc_max_simulate_blocks: u64,
676
677    /// Compute state roots for `eth_simulateV1` responses.
678    #[arg(
679        long = "rpc.compute-state-root-for-eth-simulate",
680        env = "RETH_RPC_COMPUTE_STATE_ROOT_FOR_ETH_SIMULATE",
681        default_value_t = DefaultRpcServerArgs::get_global().rpc_compute_state_root_for_eth_simulate
682    )]
683    pub rpc_compute_state_root_for_eth_simulate: bool,
684
685    /// The maximum proof window for historical proof generation.
686    /// This value allows for generating historical proofs up to
687    /// configured number of blocks from current tip (up to `tip - window`).
688    #[arg(
689        long = "rpc.eth-proof-window",
690        default_value_t = DefaultRpcServerArgs::get_global().rpc_eth_proof_window,
691        value_parser = RangedU64ValueParser::<u64>::new().range(..=constants::MAX_ETH_PROOF_WINDOW)
692    )]
693    pub rpc_eth_proof_window: u64,
694
695    /// Maximum number of concurrent getproof requests.
696    #[arg(long = "rpc.proof-permits", alias = "rpc-proof-permits", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_proof_permits)]
697    pub rpc_proof_permits: usize,
698
699    /// Configures the pending block behavior for RPC responses.
700    ///
701    /// Options: full (include all transactions), empty (header only), none (disable pending
702    /// blocks).
703    #[arg(long = "rpc.pending-block", default_value = "full", value_name = "KIND")]
704    pub rpc_pending_block: PendingBlockKind,
705
706    /// Endpoint to forward transactions to.
707    #[arg(long = "rpc.forwarder", alias = "rpc-forwarder", value_name = "FORWARDER")]
708    pub rpc_forwarder: Option<Url>,
709
710    /// Path to file containing disallowed addresses, json-encoded list of strings. Block
711    /// validation API will reject blocks containing transactions from these addresses.
712    #[arg(long = "builder.disallow", value_name = "PATH", value_parser = reth_cli_util::parsers::read_json_from_file::<AddressSet>, default_value = Resettable::from(DefaultRpcServerArgs::get_global().builder_disallow.as_ref().map(|v| format!("{:?}", v).into())))]
713    pub builder_disallow: Option<AddressSet>,
714
715    /// State cache configuration.
716    #[command(flatten)]
717    pub rpc_state_cache: RpcStateCacheArgs,
718
719    /// Gas price oracle configuration.
720    #[command(flatten)]
721    pub gas_price_oracle: GasPriceOracleArgs,
722
723    /// Timeout for `send_raw_transaction_sync` RPC method.
724    #[arg(
725        long = "rpc.send-raw-transaction-sync-timeout",
726        value_name = "SECONDS",
727        default_value = "30s",
728        value_parser = parse_duration_from_secs_or_ms,
729    )]
730    pub rpc_send_raw_transaction_sync_timeout: Duration,
731
732    /// Skip invalid transactions in `testing_buildBlockV1` instead of failing.
733    ///
734    /// When enabled, transactions that fail execution will be skipped, and all subsequent
735    /// transactions from the same sender will also be skipped.
736    #[arg(long = "testing.skip-invalid-transactions", default_value_t = false)]
737    pub testing_skip_invalid_transactions: bool,
738
739    /// Override the gas limit used by `testing_buildBlockV1`.
740    ///
741    /// When set, `testing_buildBlockV1` will use this exact value instead of moving toward the
742    /// payload builder's configured gas limit. Accepts short notation: K for thousand, M for
743    /// million, G for billion (e.g., 1G = 1 billion).
744    #[arg(long = "testing.gas-limit", value_name = "GAS_LIMIT", hide = true)]
745    pub testing_gas_limit: Option<u64>,
746
747    /// Force upcasting EIP-4844 blob sidecars to EIP-7594 format when Osaka is active.
748    ///
749    /// When enabled, blob transactions submitted via `eth_sendRawTransaction` with EIP-4844
750    /// sidecars will be automatically converted to EIP-7594 format if the next block is Osaka.
751    /// By default this is disabled, meaning transactions are submitted as-is.
752    #[arg(long = "rpc.force-blob-sidecar-upcasting", default_value_t = false)]
753    pub rpc_force_blob_sidecar_upcasting: bool,
754}
755
756impl RpcServerArgs {
757    /// Enables the HTTP-RPC server.
758    pub const fn with_http(mut self) -> Self {
759        self.http = true;
760        self
761    }
762
763    /// Configures modules for the HTTP-RPC server.
764    pub fn with_http_api(mut self, http_api: RpcModuleSelection) -> Self {
765        self.http_api = Some(http_api);
766        self
767    }
768
769    /// Enables the WS-RPC server.
770    pub const fn with_ws(mut self) -> Self {
771        self.ws = true;
772        self
773    }
774
775    /// Configures modules for WS-RPC server.
776    pub fn with_ws_api(mut self, ws_api: RpcModuleSelection) -> Self {
777        self.ws_api = Some(ws_api);
778        self
779    }
780
781    /// Enables the Auth IPC
782    pub const fn with_auth_ipc(mut self) -> Self {
783        self.auth_ipc = true;
784        self
785    }
786
787    /// Configures modules for both the HTTP-RPC server and WS-RPC server.
788    ///
789    /// This is the same as calling both [`Self::with_http_api`] and [`Self::with_ws_api`].
790    pub fn with_api(self, api: RpcModuleSelection) -> Self {
791        self.with_http_api(api.clone()).with_ws_api(api)
792    }
793
794    /// Change rpc port numbers based on the instance number, if provided.
795    /// * The `auth_port` is scaled by a factor of `instance * 100`
796    /// * The `http_port` is scaled by a factor of `-instance`
797    /// * The `ws_port` is scaled by a factor of `instance * 2`
798    /// * The `ipcpath` is appended with the instance number: `/tmp/reth.ipc-<instance>`
799    ///
800    /// # Panics
801    /// Warning: if `instance` is zero in debug mode, this will panic.
802    ///
803    /// This will also panic in debug mode if either:
804    /// * `instance` is greater than `655` (scaling would overflow `u16`)
805    /// * `self.auth_port / 100 + (instance - 1)` would overflow `u16`
806    ///
807    /// In release mode, this will silently wrap around.
808    pub fn adjust_instance_ports(&mut self, instance: Option<u16>) {
809        if let Some(instance) = instance {
810            debug_assert_ne!(instance, 0, "instance must be non-zero");
811            // auth port is scaled by a factor of instance * 100
812            self.auth_port += instance * 100 - 100;
813            // http port is scaled by a factor of -instance
814            self.http_port -= instance - 1;
815            // ws port is scaled by a factor of instance * 2
816            self.ws_port += instance * 2 - 2;
817            // append instance file to ipc path
818            self.ipcpath = format!("{}-{}", self.ipcpath, instance);
819        }
820    }
821
822    /// Set the http port to zero, to allow the OS to assign a random unused port when the rpc
823    /// server binds to a socket.
824    pub const fn with_http_unused_port(mut self) -> Self {
825        self.http_port = 0;
826        self
827    }
828
829    /// Set the ws port to zero, to allow the OS to assign a random unused port when the rpc
830    /// server binds to a socket.
831    pub const fn with_ws_unused_port(mut self) -> Self {
832        self.ws_port = 0;
833        self
834    }
835
836    /// Set the auth port to zero, to allow the OS to assign a random unused port when the rpc
837    /// server binds to a socket.
838    pub const fn with_auth_unused_port(mut self) -> Self {
839        self.auth_port = 0;
840        self
841    }
842
843    /// Append a random string to the ipc path, to prevent possible collisions when multiple nodes
844    /// are being run on the same machine.
845    pub fn with_ipc_random_path(mut self) -> Self {
846        let random_string: String =
847            rand::rng().sample_iter(rand::distr::Alphanumeric).take(8).map(char::from).collect();
848        self.ipcpath = format!("{}-{}", self.ipcpath, random_string);
849        self
850    }
851
852    /// Configure all ports to be set to a random unused port when bound, and set the IPC path to a
853    /// random path.
854    pub fn with_unused_ports(mut self) -> Self {
855        self = self.with_http_unused_port();
856        self = self.with_ws_unused_port();
857        self = self.with_auth_unused_port();
858        self = self.with_ipc_random_path();
859        self
860    }
861
862    /// Apply a function to the args.
863    pub fn apply<F>(self, f: F) -> Self
864    where
865        F: FnOnce(Self) -> Self,
866    {
867        f(self)
868    }
869
870    /// Configures the timeout for send raw transaction sync.
871    pub const fn with_send_raw_transaction_sync_timeout(mut self, timeout: Duration) -> Self {
872        self.rpc_send_raw_transaction_sync_timeout = timeout;
873        self
874    }
875
876    /// Returns `true` if the given RPC namespace is enabled on any transport.
877    pub fn is_namespace_enabled(&self, ns: RethRpcModule) -> bool {
878        if self.http && self.http_api.as_ref().is_some_and(|api| api.contains(&ns)) {
879            return true;
880        }
881        if self.ws && self.ws_api.as_ref().is_some_and(|api| api.contains(&ns)) {
882            return true;
883        }
884        // IPC exposes all modules when enabled
885        !self.ipcdisable
886    }
887
888    /// Enables forced blob sidecar upcasting from EIP-4844 to EIP-7594 format.
889    pub const fn with_force_blob_sidecar_upcasting(mut self) -> Self {
890        self.rpc_force_blob_sidecar_upcasting = true;
891        self
892    }
893}
894
895impl Default for RpcServerArgs {
896    fn default() -> Self {
897        let DefaultRpcServerArgs {
898            http,
899            http_addr,
900            http_port,
901            http_disable_compression,
902            http_compression_algorithms,
903            http_decompression_algorithms,
904            http_api,
905            http_corsdomain,
906            ws,
907            ws_addr,
908            ws_port,
909            ws_allowed_origins,
910            ws_api,
911            ipcdisable,
912            ipcpath,
913            ipc_socket_permissions,
914            auth_addr,
915            auth_port,
916            auth_jwtsecret,
917            auth_ipc,
918            auth_ipc_path,
919            disable_auth_server,
920            rpc_jwtsecret,
921            rpc_disable_metrics,
922            rpc_max_request_size,
923            rpc_max_response_size,
924            rpc_max_subscriptions_per_connection,
925            rpc_max_connections,
926            rpc_max_tracing_requests,
927            rpc_max_blocking_io_requests,
928            rpc_max_trace_filter_blocks,
929            rpc_max_blocks_per_filter,
930            rpc_max_logs_per_response,
931            rpc_gas_cap,
932            rpc_evm_memory_limit,
933            rpc_tx_fee_cap,
934            rpc_max_simulate_blocks,
935            rpc_compute_state_root_for_eth_simulate,
936            rpc_eth_proof_window,
937            rpc_proof_permits,
938            rpc_pending_block,
939            rpc_forwarder,
940            builder_disallow,
941            rpc_state_cache,
942            gas_price_oracle,
943            rpc_send_raw_transaction_sync_timeout,
944        } = DefaultRpcServerArgs::get_global().clone();
945        Self {
946            http,
947            http_addr,
948            http_port,
949            http_disable_compression,
950            http_compression_algorithms,
951            http_decompression_algorithms,
952            http_api,
953            http_corsdomain,
954            ws,
955            ws_addr,
956            ws_port,
957            ws_allowed_origins,
958            ws_api,
959            ipcdisable,
960            ipcpath,
961            ipc_socket_permissions,
962            auth_addr,
963            auth_port,
964            auth_jwtsecret,
965            auth_jwtsecret_hex: None,
966            auth_ipc,
967            auth_ipc_path,
968            disable_auth_server,
969            rpc_jwtsecret,
970            rpc_disable_metrics,
971            rpc_max_request_size,
972            rpc_max_response_size,
973            rpc_max_subscriptions_per_connection,
974            rpc_max_connections,
975            rpc_max_tracing_requests,
976            rpc_max_blocking_io_requests,
977            rpc_max_trace_filter_blocks,
978            rpc_max_blocks_per_filter,
979            rpc_max_logs_per_response,
980            rpc_gas_cap,
981            rpc_evm_memory_limit,
982            rpc_tx_fee_cap,
983            rpc_max_simulate_blocks,
984            rpc_compute_state_root_for_eth_simulate,
985            rpc_eth_proof_window,
986            rpc_proof_permits,
987            rpc_pending_block,
988            rpc_forwarder,
989            builder_disallow,
990            rpc_state_cache,
991            gas_price_oracle,
992            rpc_send_raw_transaction_sync_timeout,
993            testing_skip_invalid_transactions: false,
994            testing_gas_limit: None,
995            rpc_force_blob_sidecar_upcasting: false,
996        }
997    }
998}
999
1000/// clap value parser for [`RpcModuleSelection`] with configurable validation.
1001#[derive(Clone, Debug, Default)]
1002#[non_exhaustive]
1003struct RpcModuleSelectionValueParser;
1004
1005impl TypedValueParser for RpcModuleSelectionValueParser {
1006    type Value = RpcModuleSelection;
1007
1008    fn parse_ref(
1009        &self,
1010        _cmd: &Command,
1011        _arg: Option<&Arg>,
1012        value: &OsStr,
1013    ) -> Result<Self::Value, clap::Error> {
1014        let val =
1015            value.to_str().ok_or_else(|| clap::Error::new(clap::error::ErrorKind::InvalidUtf8))?;
1016        // This will now accept any module name, creating Other(name) for unknowns
1017        Ok(val
1018            .parse::<RpcModuleSelection>()
1019            .expect("RpcModuleSelection parsing cannot fail with Other variant"))
1020    }
1021
1022    fn possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>> {
1023        // Only show standard modules in help text (excludes "other")
1024        let values = RethRpcModule::standard_variant_names().map(PossibleValue::new);
1025        Some(Box::new(values))
1026    }
1027}
1028
1029#[cfg(test)]
1030mod tests {
1031    use super::*;
1032    use clap::{Args, Parser};
1033
1034    /// A helper type to parse Args more easily
1035    #[derive(Parser)]
1036    struct CommandParser<T: Args> {
1037        #[command(flatten)]
1038        args: T,
1039    }
1040
1041    #[test]
1042    fn test_rpc_server_args_parser() {
1043        let args =
1044            CommandParser::<RpcServerArgs>::parse_from(["reth", "--http.api", "eth,admin,debug"])
1045                .args;
1046
1047        let apis = args.http_api.unwrap();
1048        let expected = RpcModuleSelection::try_from_selection(["eth", "admin", "debug"]).unwrap();
1049
1050        assert_eq!(apis, expected);
1051    }
1052
1053    #[test]
1054    fn test_rpc_server_eth_call_bundle_args() {
1055        let args =
1056            CommandParser::<RpcServerArgs>::parse_from(["reth", "--http.api", "eth,admin,debug"])
1057                .args;
1058
1059        let apis = args.http_api.unwrap();
1060        let expected = RpcModuleSelection::try_from_selection(["eth", "admin", "debug"]).unwrap();
1061
1062        assert_eq!(apis, expected);
1063    }
1064
1065    #[test]
1066    fn test_rpc_server_args_parser_none() {
1067        let args = CommandParser::<RpcServerArgs>::parse_from(["reth", "--http.api", "none"]).args;
1068        let apis = args.http_api.unwrap();
1069        let expected = RpcModuleSelection::Selection(Default::default());
1070        assert_eq!(apis, expected);
1071    }
1072
1073    #[test]
1074    fn http_compression_algorithms_are_optional() {
1075        let args = CommandParser::<RpcServerArgs>::parse_from(["reth"]).args;
1076        assert!(args.http_compression_algorithms.is_none());
1077
1078        let args = CommandParser::<RpcServerArgs>::parse_from([
1079            "reth",
1080            "--http.compression",
1081            "zstd,gzip,deflate,br",
1082        ])
1083        .args;
1084        assert_eq!(
1085            args.http_compression_algorithms.as_deref().unwrap(),
1086            ["zstd", "gzip", "deflate", "br"]
1087        );
1088
1089        let result =
1090            CommandParser::<RpcServerArgs>::try_parse_from(["reth", "--http.compression", "gizp"]);
1091        assert!(result.is_err());
1092    }
1093
1094    #[test]
1095    fn rpc_server_args_default_sanity_test() {
1096        let default_args = RpcServerArgs::default();
1097        let args = CommandParser::<RpcServerArgs>::parse_from(["reth"]).args;
1098
1099        assert_eq!(args, default_args);
1100    }
1101
1102    #[test]
1103    fn http_request_decompression_is_opt_in() {
1104        let args = CommandParser::<RpcServerArgs>::parse_from(["reth"]).args;
1105        assert!(args.http_decompression_algorithms.is_none());
1106
1107        let args = CommandParser::<RpcServerArgs>::parse_from([
1108            "reth",
1109            "--http.decompression",
1110            "zstd,gzip,deflate,br",
1111        ])
1112        .args;
1113        assert_eq!(
1114            args.http_decompression_algorithms.as_deref().unwrap(),
1115            ["zstd", "gzip", "deflate", "br"]
1116        );
1117    }
1118
1119    #[test]
1120    fn invalid_http_request_decompression_algorithm_is_rejected() {
1121        let result = CommandParser::<RpcServerArgs>::try_parse_from([
1122            "reth",
1123            "--http.decompression",
1124            "gizp",
1125        ]);
1126        assert!(result.is_err());
1127    }
1128
1129    #[test]
1130    fn test_rpc_disable_metrics_arg() {
1131        let args = CommandParser::<RpcServerArgs>::parse_from(["reth"]).args;
1132        assert!(!args.rpc_disable_metrics);
1133
1134        let args =
1135            CommandParser::<RpcServerArgs>::parse_from(["reth", "--rpc.disable-metrics"]).args;
1136        assert!(args.rpc_disable_metrics);
1137    }
1138
1139    #[test]
1140    fn test_rpc_tx_fee_cap_parse_integer() {
1141        let args = CommandParser::<RpcServerArgs>::parse_from(["reth", "--rpc.txfeecap", "2"]).args;
1142        let expected = 2_000_000_000_000_000_000u128; // 2 ETH in wei
1143        assert_eq!(args.rpc_tx_fee_cap, expected);
1144    }
1145
1146    #[test]
1147    fn test_rpc_tx_fee_cap_parse_decimal() {
1148        let args =
1149            CommandParser::<RpcServerArgs>::parse_from(["reth", "--rpc.txfeecap", "1.5"]).args;
1150        let expected = 1_500_000_000_000_000_000u128; // 1.5 ETH in wei
1151        assert_eq!(args.rpc_tx_fee_cap, expected);
1152    }
1153
1154    #[test]
1155    fn test_rpc_tx_fee_cap_parse_zero() {
1156        let args = CommandParser::<RpcServerArgs>::parse_from(["reth", "--rpc.txfeecap", "0"]).args;
1157        assert_eq!(args.rpc_tx_fee_cap, 0); // 0 = no cap
1158    }
1159
1160    #[test]
1161    fn test_rpc_tx_fee_cap_parse_none() {
1162        let args = CommandParser::<RpcServerArgs>::parse_from(["reth"]).args;
1163        let expected = 1_000_000_000_000_000_000u128;
1164        assert_eq!(args.rpc_tx_fee_cap, expected); // 1 ETH default cap
1165    }
1166
1167    #[test]
1168    fn test_rpc_server_args() {
1169        let args = RpcServerArgs {
1170            http: true,
1171            http_addr: "127.0.0.1".parse().unwrap(),
1172            http_port: 8545,
1173            http_disable_compression: false,
1174            http_compression_algorithms: None,
1175            http_decompression_algorithms: None,
1176            http_api: Some(RpcModuleSelection::try_from_selection(["eth", "admin"]).unwrap()),
1177            http_corsdomain: Some("*".to_string()),
1178            ws: true,
1179            ws_addr: "127.0.0.1".parse().unwrap(),
1180            ws_port: 8546,
1181            ws_allowed_origins: Some("*".to_string()),
1182            ws_api: Some(RpcModuleSelection::try_from_selection(["eth", "admin"]).unwrap()),
1183            ipcdisable: false,
1184            ipcpath: "reth.ipc".to_string(),
1185            ipc_socket_permissions: Some("0o666".to_string()),
1186            auth_addr: "127.0.0.1".parse().unwrap(),
1187            auth_port: 8551,
1188            auth_jwtsecret: Some(std::path::PathBuf::from("/tmp/jwt.hex")),
1189            auth_jwtsecret_hex: None,
1190            auth_ipc: false,
1191            auth_ipc_path: "engine.ipc".to_string(),
1192            disable_auth_server: false,
1193            rpc_jwtsecret: Some(
1194                JwtSecret::from_hex(
1195                    "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
1196                )
1197                .unwrap(),
1198            ),
1199            rpc_disable_metrics: false,
1200            rpc_max_request_size: 15u32.into(),
1201            rpc_max_response_size: 160u32.into(),
1202            rpc_max_subscriptions_per_connection: 1024u32.into(),
1203            rpc_max_connections: 500u32.into(),
1204            rpc_max_tracing_requests: 16,
1205            rpc_max_blocking_io_requests: 256,
1206            rpc_max_trace_filter_blocks: 4000,
1207            rpc_max_blocks_per_filter: 1000u64.into(),
1208            rpc_max_logs_per_response: 10000u64.into(),
1209            rpc_gas_cap: 50_000_000,
1210            rpc_evm_memory_limit: 256,
1211            rpc_tx_fee_cap: 2_000_000_000_000_000_000u128,
1212            rpc_max_simulate_blocks: 256,
1213            rpc_compute_state_root_for_eth_simulate: false,
1214            rpc_eth_proof_window: 100_000,
1215            rpc_proof_permits: 16,
1216            rpc_pending_block: PendingBlockKind::Full,
1217            rpc_forwarder: Some("http://localhost:8545".parse().unwrap()),
1218            builder_disallow: None,
1219            rpc_state_cache: RpcStateCacheArgs {
1220                max_blocks: 5000,
1221                max_receipts: 2000,
1222                max_headers: 1000,
1223                max_bals: 1000,
1224                max_concurrent_db_requests: 512,
1225                max_cached_tx_hashes: 100_000,
1226            },
1227            gas_price_oracle: GasPriceOracleArgs {
1228                blocks: 20,
1229                ignore_price: 2,
1230                max_price: 500_000_000_000,
1231                percentile: 60,
1232                default_suggested_fee: None,
1233            },
1234            rpc_send_raw_transaction_sync_timeout: std::time::Duration::from_secs(30),
1235            testing_skip_invalid_transactions: true,
1236            testing_gas_limit: None,
1237            rpc_force_blob_sidecar_upcasting: false,
1238        };
1239
1240        let parsed_args = CommandParser::<RpcServerArgs>::parse_from([
1241            "reth",
1242            "--http",
1243            "--http.addr",
1244            "127.0.0.1",
1245            "--http.port",
1246            "8545",
1247            "--http.api",
1248            "eth,admin",
1249            "--http.corsdomain",
1250            "*",
1251            "--ws",
1252            "--ws.addr",
1253            "127.0.0.1",
1254            "--ws.port",
1255            "8546",
1256            "--ws.origins",
1257            "*",
1258            "--ws.api",
1259            "eth,admin",
1260            "--ipcpath",
1261            "reth.ipc",
1262            "--ipc.permissions",
1263            "0o666",
1264            "--authrpc.addr",
1265            "127.0.0.1",
1266            "--authrpc.port",
1267            "8551",
1268            "--authrpc.jwtsecret",
1269            "/tmp/jwt.hex",
1270            "--auth-ipc.path",
1271            "engine.ipc",
1272            "--rpc.jwtsecret",
1273            "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
1274            "--rpc.max-request-size",
1275            "15",
1276            "--rpc.max-response-size",
1277            "160",
1278            "--rpc.max-subscriptions-per-connection",
1279            "1024",
1280            "--rpc.max-connections",
1281            "500",
1282            "--rpc.max-tracing-requests",
1283            "16",
1284            "--rpc.max-blocking-io-requests",
1285            "256",
1286            "--rpc.max-trace-filter-blocks",
1287            "4000",
1288            "--rpc.max-blocks-per-filter",
1289            "1000",
1290            "--rpc.max-logs-per-response",
1291            "10000",
1292            "--rpc.gascap",
1293            "50000000",
1294            "--rpc.evm-memory-limit",
1295            "256",
1296            "--rpc.txfeecap",
1297            "2.0",
1298            "--rpc.max-simulate-blocks",
1299            "256",
1300            "--rpc.eth-proof-window",
1301            "100000",
1302            "--rpc.proof-permits",
1303            "16",
1304            "--rpc.pending-block",
1305            "full",
1306            "--rpc.forwarder",
1307            "http://localhost:8545",
1308            "--rpc-cache.max-blocks",
1309            "5000",
1310            "--rpc-cache.max-receipts",
1311            "2000",
1312            "--rpc-cache.max-headers",
1313            "1000",
1314            "--rpc-cache.max-bals",
1315            "1000",
1316            "--rpc-cache.max-concurrent-db-requests",
1317            "512",
1318            "--gpo.blocks",
1319            "20",
1320            "--gpo.ignoreprice",
1321            "2",
1322            "--gpo.maxprice",
1323            "500000000000",
1324            "--gpo.percentile",
1325            "60",
1326            "--rpc.send-raw-transaction-sync-timeout",
1327            "30s",
1328            "--testing.skip-invalid-transactions",
1329        ])
1330        .args;
1331
1332        assert_eq!(parsed_args, args);
1333    }
1334
1335    #[test]
1336    fn parse_auth_jwtsecret_hex() {
1337        let hex = "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef";
1338        let args =
1339            CommandParser::<RpcServerArgs>::parse_from(["reth", "--authrpc.jwtsecret-hex", hex])
1340                .args;
1341
1342        let expected = JwtSecret::from_hex(hex).unwrap();
1343        assert_eq!(args.auth_jwtsecret_hex, Some(expected));
1344        assert_eq!(args.auth_jwtsecret, None);
1345    }
1346
1347    #[test]
1348    fn parse_auth_jwtsecret_hex_with_0x_prefix() {
1349        let hex = "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef";
1350        let args =
1351            CommandParser::<RpcServerArgs>::parse_from(["reth", "--authrpc.jwtsecret-hex", hex])
1352                .args;
1353
1354        let expected = JwtSecret::from_hex(hex).unwrap();
1355        assert_eq!(args.auth_jwtsecret_hex, Some(expected));
1356        assert_eq!(args.auth_jwtsecret, None);
1357    }
1358
1359    #[test]
1360    fn test_auth_jwtsecret_and_hex_are_mutually_exclusive() {
1361        let result = CommandParser::<RpcServerArgs>::try_parse_from([
1362            "reth",
1363            "--authrpc.jwtsecret",
1364            "/tmp/jwt.hex",
1365            "--authrpc.jwtsecret-hex",
1366            "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
1367        ]);
1368
1369        assert!(result.is_err());
1370    }
1371}