1use 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
28static RPC_SERVER_DEFAULTS: OnceLock<DefaultRpcServerArgs> = OnceLock::new();
30
31pub(crate) const RPC_DEFAULT_MAX_SUBS_PER_CONN: u32 = 1024;
33
34pub(crate) const RPC_DEFAULT_MAX_REQUEST_SIZE_MB: u32 = 15;
36
37pub(crate) const RPC_DEFAULT_MAX_RESPONSE_SIZE_MB: u32 = 160;
41
42pub(crate) const RPC_DEFAULT_MAX_CONNECTIONS: u32 = 500;
47
48#[derive(Debug, Clone)]
52pub struct DefaultRpcServerArgs {
53 http: bool,
54 http_addr: IpAddr,
55 http_port: u16,
56 http_disable_compression: bool,
57 http_api: Option<RpcModuleSelection>,
58 http_corsdomain: Option<String>,
59 ws: bool,
60 ws_addr: IpAddr,
61 ws_port: u16,
62 ws_allowed_origins: Option<String>,
63 ws_api: Option<RpcModuleSelection>,
64 ipcdisable: bool,
65 ipcpath: String,
66 ipc_socket_permissions: Option<String>,
67 auth_addr: IpAddr,
68 auth_port: u16,
69 auth_jwtsecret: Option<PathBuf>,
70 auth_ipc: bool,
71 auth_ipc_path: String,
72 disable_auth_server: bool,
73 rpc_jwtsecret: Option<JwtSecret>,
74 rpc_disable_metrics: bool,
75 rpc_max_request_size: MaxU32,
76 rpc_max_response_size: MaxU32,
77 rpc_max_subscriptions_per_connection: MaxU32,
78 rpc_max_connections: MaxU32,
79 rpc_max_tracing_requests: usize,
80 rpc_max_blocking_io_requests: usize,
81 rpc_max_trace_filter_blocks: u64,
82 rpc_max_blocks_per_filter: ZeroAsNoneU64,
83 rpc_max_logs_per_response: ZeroAsNoneU64,
84 rpc_gas_cap: u64,
85 rpc_evm_memory_limit: u64,
86 rpc_tx_fee_cap: u128,
87 rpc_max_simulate_blocks: u64,
88 rpc_compute_state_root_for_eth_simulate: bool,
89 rpc_eth_proof_window: u64,
90 rpc_proof_permits: usize,
91 rpc_pending_block: PendingBlockKind,
92 rpc_forwarder: Option<Url>,
93 builder_disallow: Option<AddressSet>,
94 rpc_state_cache: RpcStateCacheArgs,
95 gas_price_oracle: GasPriceOracleArgs,
96 rpc_send_raw_transaction_sync_timeout: Duration,
97}
98
99impl DefaultRpcServerArgs {
100 pub fn try_init(self) -> Result<(), Self> {
102 RPC_SERVER_DEFAULTS.set(self)
103 }
104
105 pub fn get_global() -> &'static Self {
107 RPC_SERVER_DEFAULTS.get_or_init(Self::default)
108 }
109
110 pub const fn with_http(mut self, v: bool) -> Self {
112 self.http = v;
113 self
114 }
115
116 pub const fn with_http_addr(mut self, v: IpAddr) -> Self {
118 self.http_addr = v;
119 self
120 }
121
122 pub const fn with_http_port(mut self, v: u16) -> Self {
124 self.http_port = v;
125 self
126 }
127
128 pub const fn with_http_disable_compression(mut self, v: bool) -> Self {
130 self.http_disable_compression = v;
131 self
132 }
133
134 pub fn with_http_api(mut self, v: Option<RpcModuleSelection>) -> Self {
136 self.http_api = v;
137 self
138 }
139
140 pub fn with_http_corsdomain(mut self, v: Option<String>) -> Self {
142 self.http_corsdomain = v;
143 self
144 }
145
146 pub const fn with_ws(mut self, v: bool) -> Self {
148 self.ws = v;
149 self
150 }
151
152 pub const fn with_ws_addr(mut self, v: IpAddr) -> Self {
154 self.ws_addr = v;
155 self
156 }
157
158 pub const fn with_ws_port(mut self, v: u16) -> Self {
160 self.ws_port = v;
161 self
162 }
163
164 pub fn with_ws_allowed_origins(mut self, v: Option<String>) -> Self {
166 self.ws_allowed_origins = v;
167 self
168 }
169
170 pub fn with_ws_api(mut self, v: Option<RpcModuleSelection>) -> Self {
172 self.ws_api = v;
173 self
174 }
175
176 pub const fn with_ipcdisable(mut self, v: bool) -> Self {
178 self.ipcdisable = v;
179 self
180 }
181
182 pub fn with_ipcpath(mut self, v: String) -> Self {
184 self.ipcpath = v;
185 self
186 }
187
188 pub fn with_ipc_socket_permissions(mut self, v: Option<String>) -> Self {
190 self.ipc_socket_permissions = v;
191 self
192 }
193
194 pub const fn with_auth_addr(mut self, v: IpAddr) -> Self {
196 self.auth_addr = v;
197 self
198 }
199
200 pub const fn with_auth_port(mut self, v: u16) -> Self {
202 self.auth_port = v;
203 self
204 }
205
206 pub fn with_auth_jwtsecret(mut self, v: Option<PathBuf>) -> Self {
208 self.auth_jwtsecret = v;
209 self
210 }
211
212 pub const fn with_auth_ipc(mut self, v: bool) -> Self {
214 self.auth_ipc = v;
215 self
216 }
217
218 pub fn with_auth_ipc_path(mut self, v: String) -> Self {
220 self.auth_ipc_path = v;
221 self
222 }
223
224 pub const fn with_disable_auth_server(mut self, v: bool) -> Self {
226 self.disable_auth_server = v;
227 self
228 }
229
230 pub const fn with_rpc_jwtsecret(mut self, v: Option<JwtSecret>) -> Self {
232 self.rpc_jwtsecret = v;
233 self
234 }
235
236 pub const fn with_rpc_disable_metrics(mut self, v: bool) -> Self {
238 self.rpc_disable_metrics = v;
239 self
240 }
241
242 pub const fn with_rpc_max_request_size(mut self, v: MaxU32) -> Self {
244 self.rpc_max_request_size = v;
245 self
246 }
247
248 pub const fn with_rpc_max_response_size(mut self, v: MaxU32) -> Self {
250 self.rpc_max_response_size = v;
251 self
252 }
253
254 pub const fn with_rpc_max_subscriptions_per_connection(mut self, v: MaxU32) -> Self {
256 self.rpc_max_subscriptions_per_connection = v;
257 self
258 }
259
260 pub const fn with_rpc_max_connections(mut self, v: MaxU32) -> Self {
262 self.rpc_max_connections = v;
263 self
264 }
265
266 pub const fn with_rpc_max_tracing_requests(mut self, v: usize) -> Self {
268 self.rpc_max_tracing_requests = v;
269 self
270 }
271
272 pub const fn with_rpc_max_blocking_io_requests(mut self, v: usize) -> Self {
274 self.rpc_max_blocking_io_requests = v;
275 self
276 }
277
278 pub const fn with_rpc_max_trace_filter_blocks(mut self, v: u64) -> Self {
280 self.rpc_max_trace_filter_blocks = v;
281 self
282 }
283
284 pub const fn with_rpc_max_blocks_per_filter(mut self, v: ZeroAsNoneU64) -> Self {
286 self.rpc_max_blocks_per_filter = v;
287 self
288 }
289
290 pub const fn with_rpc_max_logs_per_response(mut self, v: ZeroAsNoneU64) -> Self {
292 self.rpc_max_logs_per_response = v;
293 self
294 }
295
296 pub const fn with_rpc_gas_cap(mut self, v: u64) -> Self {
298 self.rpc_gas_cap = v;
299 self
300 }
301
302 pub const fn with_rpc_evm_memory_limit(mut self, v: u64) -> Self {
304 self.rpc_evm_memory_limit = v;
305 self
306 }
307
308 pub const fn with_rpc_tx_fee_cap(mut self, v: u128) -> Self {
310 self.rpc_tx_fee_cap = v;
311 self
312 }
313
314 pub const fn with_rpc_max_simulate_blocks(mut self, v: u64) -> Self {
316 self.rpc_max_simulate_blocks = v;
317 self
318 }
319
320 pub const fn with_rpc_compute_state_root_for_eth_simulate(mut self, v: bool) -> Self {
322 self.rpc_compute_state_root_for_eth_simulate = v;
323 self
324 }
325
326 pub const fn with_rpc_eth_proof_window(mut self, v: u64) -> Self {
328 self.rpc_eth_proof_window = v;
329 self
330 }
331
332 pub const fn with_rpc_proof_permits(mut self, v: usize) -> Self {
334 self.rpc_proof_permits = v;
335 self
336 }
337
338 pub const fn with_rpc_pending_block(mut self, v: PendingBlockKind) -> Self {
340 self.rpc_pending_block = v;
341 self
342 }
343
344 pub fn with_rpc_forwarder(mut self, v: Option<Url>) -> Self {
346 self.rpc_forwarder = v;
347 self
348 }
349
350 pub fn with_builder_disallow(mut self, v: Option<AddressSet>) -> Self {
352 self.builder_disallow = v;
353 self
354 }
355
356 pub const fn with_rpc_state_cache(mut self, v: RpcStateCacheArgs) -> Self {
358 self.rpc_state_cache = v;
359 self
360 }
361
362 pub const fn with_gas_price_oracle(mut self, v: GasPriceOracleArgs) -> Self {
364 self.gas_price_oracle = v;
365 self
366 }
367
368 pub const fn with_rpc_send_raw_transaction_sync_timeout(mut self, v: Duration) -> Self {
370 self.rpc_send_raw_transaction_sync_timeout = v;
371 self
372 }
373}
374
375impl Default for DefaultRpcServerArgs {
376 fn default() -> Self {
377 Self {
378 http: false,
379 http_addr: Ipv4Addr::LOCALHOST.into(),
380 http_port: constants::DEFAULT_HTTP_RPC_PORT,
381 http_disable_compression: false,
382 http_api: None,
383 http_corsdomain: None,
384 ws: false,
385 ws_addr: Ipv4Addr::LOCALHOST.into(),
386 ws_port: constants::DEFAULT_WS_RPC_PORT,
387 ws_allowed_origins: None,
388 ws_api: None,
389 ipcdisable: false,
390 ipcpath: constants::DEFAULT_IPC_ENDPOINT.to_string(),
391 ipc_socket_permissions: None,
392 auth_addr: Ipv4Addr::LOCALHOST.into(),
393 auth_port: constants::DEFAULT_AUTH_PORT,
394 auth_jwtsecret: None,
395 auth_ipc: false,
396 auth_ipc_path: constants::DEFAULT_ENGINE_API_IPC_ENDPOINT.to_string(),
397 disable_auth_server: false,
398 rpc_jwtsecret: None,
399 rpc_disable_metrics: false,
400 rpc_max_request_size: RPC_DEFAULT_MAX_REQUEST_SIZE_MB.into(),
401 rpc_max_response_size: RPC_DEFAULT_MAX_RESPONSE_SIZE_MB.into(),
402 rpc_max_subscriptions_per_connection: RPC_DEFAULT_MAX_SUBS_PER_CONN.into(),
403 rpc_max_connections: RPC_DEFAULT_MAX_CONNECTIONS.into(),
404 rpc_max_tracing_requests: constants::default_max_tracing_requests(),
405 rpc_max_blocking_io_requests: constants::DEFAULT_MAX_BLOCKING_IO_REQUEST,
406 rpc_max_trace_filter_blocks: constants::DEFAULT_MAX_TRACE_FILTER_BLOCKS,
407 rpc_max_blocks_per_filter: constants::DEFAULT_MAX_BLOCKS_PER_FILTER.into(),
408 rpc_max_logs_per_response: (constants::DEFAULT_MAX_LOGS_PER_RESPONSE as u64).into(),
409 rpc_gas_cap: constants::gas_oracle::RPC_DEFAULT_GAS_CAP,
410 rpc_evm_memory_limit: (1 << 32) - 1,
411 rpc_tx_fee_cap: constants::DEFAULT_TX_FEE_CAP_WEI,
412 rpc_max_simulate_blocks: constants::DEFAULT_MAX_SIMULATE_BLOCKS,
413 rpc_compute_state_root_for_eth_simulate: false,
414 rpc_eth_proof_window: constants::DEFAULT_ETH_PROOF_WINDOW,
415 rpc_proof_permits: constants::DEFAULT_PROOF_PERMITS,
416 rpc_pending_block: PendingBlockKind::Full,
417 rpc_forwarder: None,
418 builder_disallow: None,
419 rpc_state_cache: RpcStateCacheArgs::default(),
420 gas_price_oracle: GasPriceOracleArgs::default(),
421 rpc_send_raw_transaction_sync_timeout:
422 constants::RPC_DEFAULT_SEND_RAW_TX_SYNC_TIMEOUT_SECS,
423 }
424 }
425}
426
427#[derive(Debug, Clone, Args, PartialEq, Eq)]
429#[command(next_help_heading = "RPC")]
430pub struct RpcServerArgs {
431 #[arg(long, default_value_if("dev", "true", "true"), default_value_t = DefaultRpcServerArgs::get_global().http)]
433 pub http: bool,
434
435 #[arg(long = "http.addr", default_value_t = DefaultRpcServerArgs::get_global().http_addr)]
437 pub http_addr: IpAddr,
438
439 #[arg(long = "http.port", default_value_t = DefaultRpcServerArgs::get_global().http_port)]
441 pub http_port: u16,
442
443 #[arg(long = "http.disable-compression", default_value_t = DefaultRpcServerArgs::get_global().http_disable_compression)]
445 pub http_disable_compression: bool,
446
447 #[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())))]
449 pub http_api: Option<RpcModuleSelection>,
450
451 #[arg(long = "http.corsdomain", default_value = Resettable::from(DefaultRpcServerArgs::get_global().http_corsdomain.as_ref().map(|v| v.to_string().into())))]
453 pub http_corsdomain: Option<String>,
454
455 #[arg(long, default_value_t = DefaultRpcServerArgs::get_global().ws)]
457 pub ws: bool,
458
459 #[arg(long = "ws.addr", default_value_t = DefaultRpcServerArgs::get_global().ws_addr)]
461 pub ws_addr: IpAddr,
462
463 #[arg(long = "ws.port", default_value_t = DefaultRpcServerArgs::get_global().ws_port)]
465 pub ws_port: u16,
466
467 #[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())))]
469 pub ws_allowed_origins: Option<String>,
470
471 #[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())))]
473 pub ws_api: Option<RpcModuleSelection>,
474
475 #[arg(long, default_value_t = DefaultRpcServerArgs::get_global().ipcdisable)]
477 pub ipcdisable: bool,
478
479 #[arg(long, default_value_t = DefaultRpcServerArgs::get_global().ipcpath.clone())]
481 pub ipcpath: String,
482
483 #[arg(long = "ipc.permissions", default_value = Resettable::from(DefaultRpcServerArgs::get_global().ipc_socket_permissions.as_ref().map(|v| v.to_string().into())))]
487 pub ipc_socket_permissions: Option<String>,
488
489 #[arg(long = "authrpc.addr", default_value_t = DefaultRpcServerArgs::get_global().auth_addr)]
491 pub auth_addr: IpAddr,
492
493 #[arg(long = "authrpc.port", default_value_t = DefaultRpcServerArgs::get_global().auth_port)]
495 pub auth_port: u16,
496
497 #[arg(long = "authrpc.jwtsecret", value_name = "PATH", global = true, required = false, default_value = Resettable::from(DefaultRpcServerArgs::get_global().auth_jwtsecret.as_ref().map(|v| v.to_string_lossy().into())))]
505 pub auth_jwtsecret: Option<PathBuf>,
506
507 #[arg(long, default_value_t = DefaultRpcServerArgs::get_global().auth_ipc)]
509 pub auth_ipc: bool,
510
511 #[arg(long = "auth-ipc.path", default_value_t = DefaultRpcServerArgs::get_global().auth_ipc_path.clone())]
513 pub auth_ipc_path: String,
514
515 #[arg(long = "disable-auth-server", alias = "disable-engine-api", default_value_t = DefaultRpcServerArgs::get_global().disable_auth_server)]
520 pub disable_auth_server: bool,
521
522 #[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())))]
528 pub rpc_jwtsecret: Option<JwtSecret>,
529
530 #[arg(long = "rpc.disable-metrics", default_value_t = DefaultRpcServerArgs::get_global().rpc_disable_metrics)]
532 pub rpc_disable_metrics: bool,
533
534 #[arg(long = "rpc.max-request-size", alias = "rpc-max-request-size", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_request_size)]
536 pub rpc_max_request_size: MaxU32,
537
538 #[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)]
540 pub rpc_max_response_size: MaxU32,
541
542 #[arg(long = "rpc.max-subscriptions-per-connection", alias = "rpc-max-subscriptions-per-connection", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_subscriptions_per_connection)]
544 pub rpc_max_subscriptions_per_connection: MaxU32,
545
546 #[arg(long = "rpc.max-connections", alias = "rpc-max-connections", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_connections)]
548 pub rpc_max_connections: MaxU32,
549
550 #[arg(long = "rpc.max-tracing-requests", alias = "rpc-max-tracing-requests", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_tracing_requests)]
557 pub rpc_max_tracing_requests: usize,
558
559 #[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)]
565 pub rpc_max_blocking_io_requests: usize,
566
567 #[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)]
569 pub rpc_max_trace_filter_blocks: u64,
570
571 #[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)]
573 pub rpc_max_blocks_per_filter: ZeroAsNoneU64,
574
575 #[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)]
577 pub rpc_max_logs_per_response: ZeroAsNoneU64,
578
579 #[arg(
581 long = "rpc.gascap",
582 alias = "rpc-gascap",
583 value_name = "GAS_CAP",
584 value_parser = MaxOr::new(RangedU64ValueParser::<u64>::new().range(1..)),
585 default_value_t = DefaultRpcServerArgs::get_global().rpc_gas_cap
586 )]
587 pub rpc_gas_cap: u64,
588
589 #[arg(
591 long = "rpc.evm-memory-limit",
592 alias = "rpc-evm-memory-limit",
593 value_name = "MEMORY_LIMIT",
594 value_parser = MaxOr::new(RangedU64ValueParser::<u64>::new().range(1..)),
595 default_value_t = DefaultRpcServerArgs::get_global().rpc_evm_memory_limit
596 )]
597 pub rpc_evm_memory_limit: u64,
598
599 #[arg(
601 long = "rpc.txfeecap",
602 alias = "rpc-txfeecap",
603 value_name = "TX_FEE_CAP",
604 value_parser = parse_ether_value,
605 default_value = "1.0"
606 )]
607 pub rpc_tx_fee_cap: u128,
608
609 #[arg(
611 long = "rpc.max-simulate-blocks",
612 value_name = "BLOCKS_COUNT",
613 default_value_t = DefaultRpcServerArgs::get_global().rpc_max_simulate_blocks
614 )]
615 pub rpc_max_simulate_blocks: u64,
616
617 #[arg(
619 long = "rpc.compute-state-root-for-eth-simulate",
620 env = "RETH_RPC_COMPUTE_STATE_ROOT_FOR_ETH_SIMULATE",
621 default_value_t = DefaultRpcServerArgs::get_global().rpc_compute_state_root_for_eth_simulate
622 )]
623 pub rpc_compute_state_root_for_eth_simulate: bool,
624
625 #[arg(
629 long = "rpc.eth-proof-window",
630 default_value_t = DefaultRpcServerArgs::get_global().rpc_eth_proof_window,
631 value_parser = RangedU64ValueParser::<u64>::new().range(..=constants::MAX_ETH_PROOF_WINDOW)
632 )]
633 pub rpc_eth_proof_window: u64,
634
635 #[arg(long = "rpc.proof-permits", alias = "rpc-proof-permits", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_proof_permits)]
637 pub rpc_proof_permits: usize,
638
639 #[arg(long = "rpc.pending-block", default_value = "full", value_name = "KIND")]
644 pub rpc_pending_block: PendingBlockKind,
645
646 #[arg(long = "rpc.forwarder", alias = "rpc-forwarder", value_name = "FORWARDER")]
648 pub rpc_forwarder: Option<Url>,
649
650 #[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())))]
653 pub builder_disallow: Option<AddressSet>,
654
655 #[command(flatten)]
657 pub rpc_state_cache: RpcStateCacheArgs,
658
659 #[command(flatten)]
661 pub gas_price_oracle: GasPriceOracleArgs,
662
663 #[arg(
665 long = "rpc.send-raw-transaction-sync-timeout",
666 value_name = "SECONDS",
667 default_value = "30s",
668 value_parser = parse_duration_from_secs_or_ms,
669 )]
670 pub rpc_send_raw_transaction_sync_timeout: Duration,
671
672 #[arg(long = "testing.skip-invalid-transactions", default_value_t = true)]
677 pub testing_skip_invalid_transactions: bool,
678
679 #[arg(long = "testing.gas-limit", value_name = "GAS_LIMIT", hide = true)]
685 pub testing_gas_limit: Option<u64>,
686
687 #[arg(long = "rpc.force-blob-sidecar-upcasting", default_value_t = false)]
693 pub rpc_force_blob_sidecar_upcasting: bool,
694}
695
696impl RpcServerArgs {
697 pub const fn with_http(mut self) -> Self {
699 self.http = true;
700 self
701 }
702
703 pub fn with_http_api(mut self, http_api: RpcModuleSelection) -> Self {
705 self.http_api = Some(http_api);
706 self
707 }
708
709 pub const fn with_ws(mut self) -> Self {
711 self.ws = true;
712 self
713 }
714
715 pub fn with_ws_api(mut self, ws_api: RpcModuleSelection) -> Self {
717 self.ws_api = Some(ws_api);
718 self
719 }
720
721 pub const fn with_auth_ipc(mut self) -> Self {
723 self.auth_ipc = true;
724 self
725 }
726
727 pub fn with_api(self, api: RpcModuleSelection) -> Self {
731 self.with_http_api(api.clone()).with_ws_api(api)
732 }
733
734 pub fn adjust_instance_ports(&mut self, instance: Option<u16>) {
749 if let Some(instance) = instance {
750 debug_assert_ne!(instance, 0, "instance must be non-zero");
751 self.auth_port += instance * 100 - 100;
753 self.http_port -= instance - 1;
755 self.ws_port += instance * 2 - 2;
757 self.ipcpath = format!("{}-{}", self.ipcpath, instance);
759 }
760 }
761
762 pub const fn with_http_unused_port(mut self) -> Self {
765 self.http_port = 0;
766 self
767 }
768
769 pub const fn with_ws_unused_port(mut self) -> Self {
772 self.ws_port = 0;
773 self
774 }
775
776 pub const fn with_auth_unused_port(mut self) -> Self {
779 self.auth_port = 0;
780 self
781 }
782
783 pub fn with_ipc_random_path(mut self) -> Self {
786 let random_string: String =
787 rand::rng().sample_iter(rand::distr::Alphanumeric).take(8).map(char::from).collect();
788 self.ipcpath = format!("{}-{}", self.ipcpath, random_string);
789 self
790 }
791
792 pub fn with_unused_ports(mut self) -> Self {
795 self = self.with_http_unused_port();
796 self = self.with_ws_unused_port();
797 self = self.with_auth_unused_port();
798 self = self.with_ipc_random_path();
799 self
800 }
801
802 pub fn apply<F>(self, f: F) -> Self
804 where
805 F: FnOnce(Self) -> Self,
806 {
807 f(self)
808 }
809
810 pub const fn with_send_raw_transaction_sync_timeout(mut self, timeout: Duration) -> Self {
812 self.rpc_send_raw_transaction_sync_timeout = timeout;
813 self
814 }
815
816 pub fn is_namespace_enabled(&self, ns: RethRpcModule) -> bool {
818 if self.http && self.http_api.as_ref().is_some_and(|api| api.contains(&ns)) {
819 return true;
820 }
821 if self.ws && self.ws_api.as_ref().is_some_and(|api| api.contains(&ns)) {
822 return true;
823 }
824 !self.ipcdisable
826 }
827
828 pub const fn with_force_blob_sidecar_upcasting(mut self) -> Self {
830 self.rpc_force_blob_sidecar_upcasting = true;
831 self
832 }
833}
834
835impl Default for RpcServerArgs {
836 fn default() -> Self {
837 let DefaultRpcServerArgs {
838 http,
839 http_addr,
840 http_port,
841 http_disable_compression,
842 http_api,
843 http_corsdomain,
844 ws,
845 ws_addr,
846 ws_port,
847 ws_allowed_origins,
848 ws_api,
849 ipcdisable,
850 ipcpath,
851 ipc_socket_permissions,
852 auth_addr,
853 auth_port,
854 auth_jwtsecret,
855 auth_ipc,
856 auth_ipc_path,
857 disable_auth_server,
858 rpc_jwtsecret,
859 rpc_disable_metrics,
860 rpc_max_request_size,
861 rpc_max_response_size,
862 rpc_max_subscriptions_per_connection,
863 rpc_max_connections,
864 rpc_max_tracing_requests,
865 rpc_max_blocking_io_requests,
866 rpc_max_trace_filter_blocks,
867 rpc_max_blocks_per_filter,
868 rpc_max_logs_per_response,
869 rpc_gas_cap,
870 rpc_evm_memory_limit,
871 rpc_tx_fee_cap,
872 rpc_max_simulate_blocks,
873 rpc_compute_state_root_for_eth_simulate,
874 rpc_eth_proof_window,
875 rpc_proof_permits,
876 rpc_pending_block,
877 rpc_forwarder,
878 builder_disallow,
879 rpc_state_cache,
880 gas_price_oracle,
881 rpc_send_raw_transaction_sync_timeout,
882 } = DefaultRpcServerArgs::get_global().clone();
883 Self {
884 http,
885 http_addr,
886 http_port,
887 http_disable_compression,
888 http_api,
889 http_corsdomain,
890 ws,
891 ws_addr,
892 ws_port,
893 ws_allowed_origins,
894 ws_api,
895 ipcdisable,
896 ipcpath,
897 ipc_socket_permissions,
898 auth_addr,
899 auth_port,
900 auth_jwtsecret,
901 auth_ipc,
902 auth_ipc_path,
903 disable_auth_server,
904 rpc_jwtsecret,
905 rpc_disable_metrics,
906 rpc_max_request_size,
907 rpc_max_response_size,
908 rpc_max_subscriptions_per_connection,
909 rpc_max_connections,
910 rpc_max_tracing_requests,
911 rpc_max_blocking_io_requests,
912 rpc_max_trace_filter_blocks,
913 rpc_max_blocks_per_filter,
914 rpc_max_logs_per_response,
915 rpc_gas_cap,
916 rpc_evm_memory_limit,
917 rpc_tx_fee_cap,
918 rpc_max_simulate_blocks,
919 rpc_compute_state_root_for_eth_simulate,
920 rpc_eth_proof_window,
921 rpc_proof_permits,
922 rpc_pending_block,
923 rpc_forwarder,
924 builder_disallow,
925 rpc_state_cache,
926 gas_price_oracle,
927 rpc_send_raw_transaction_sync_timeout,
928 testing_skip_invalid_transactions: true,
929 testing_gas_limit: None,
930 rpc_force_blob_sidecar_upcasting: false,
931 }
932 }
933}
934
935#[derive(Clone, Debug, Default)]
937#[non_exhaustive]
938struct RpcModuleSelectionValueParser;
939
940impl TypedValueParser for RpcModuleSelectionValueParser {
941 type Value = RpcModuleSelection;
942
943 fn parse_ref(
944 &self,
945 _cmd: &Command,
946 _arg: Option<&Arg>,
947 value: &OsStr,
948 ) -> Result<Self::Value, clap::Error> {
949 let val =
950 value.to_str().ok_or_else(|| clap::Error::new(clap::error::ErrorKind::InvalidUtf8))?;
951 Ok(val
953 .parse::<RpcModuleSelection>()
954 .expect("RpcModuleSelection parsing cannot fail with Other variant"))
955 }
956
957 fn possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>> {
958 let values = RethRpcModule::standard_variant_names().map(PossibleValue::new);
960 Some(Box::new(values))
961 }
962}
963
964#[cfg(test)]
965mod tests {
966 use super::*;
967 use clap::{Args, Parser};
968
969 #[derive(Parser)]
971 struct CommandParser<T: Args> {
972 #[command(flatten)]
973 args: T,
974 }
975
976 #[test]
977 fn test_rpc_server_args_parser() {
978 let args =
979 CommandParser::<RpcServerArgs>::parse_from(["reth", "--http.api", "eth,admin,debug"])
980 .args;
981
982 let apis = args.http_api.unwrap();
983 let expected = RpcModuleSelection::try_from_selection(["eth", "admin", "debug"]).unwrap();
984
985 assert_eq!(apis, expected);
986 }
987
988 #[test]
989 fn test_rpc_server_eth_call_bundle_args() {
990 let args =
991 CommandParser::<RpcServerArgs>::parse_from(["reth", "--http.api", "eth,admin,debug"])
992 .args;
993
994 let apis = args.http_api.unwrap();
995 let expected = RpcModuleSelection::try_from_selection(["eth", "admin", "debug"]).unwrap();
996
997 assert_eq!(apis, expected);
998 }
999
1000 #[test]
1001 fn test_rpc_server_args_parser_none() {
1002 let args = CommandParser::<RpcServerArgs>::parse_from(["reth", "--http.api", "none"]).args;
1003 let apis = args.http_api.unwrap();
1004 let expected = RpcModuleSelection::Selection(Default::default());
1005 assert_eq!(apis, expected);
1006 }
1007
1008 #[test]
1009 fn rpc_server_args_default_sanity_test() {
1010 let default_args = RpcServerArgs::default();
1011 let args = CommandParser::<RpcServerArgs>::parse_from(["reth"]).args;
1012
1013 assert_eq!(args, default_args);
1014 }
1015
1016 #[test]
1017 fn test_rpc_disable_metrics_arg() {
1018 let args = CommandParser::<RpcServerArgs>::parse_from(["reth"]).args;
1019 assert!(!args.rpc_disable_metrics);
1020
1021 let args =
1022 CommandParser::<RpcServerArgs>::parse_from(["reth", "--rpc.disable-metrics"]).args;
1023 assert!(args.rpc_disable_metrics);
1024 }
1025
1026 #[test]
1027 fn test_rpc_tx_fee_cap_parse_integer() {
1028 let args = CommandParser::<RpcServerArgs>::parse_from(["reth", "--rpc.txfeecap", "2"]).args;
1029 let expected = 2_000_000_000_000_000_000u128; assert_eq!(args.rpc_tx_fee_cap, expected);
1031 }
1032
1033 #[test]
1034 fn test_rpc_tx_fee_cap_parse_decimal() {
1035 let args =
1036 CommandParser::<RpcServerArgs>::parse_from(["reth", "--rpc.txfeecap", "1.5"]).args;
1037 let expected = 1_500_000_000_000_000_000u128; assert_eq!(args.rpc_tx_fee_cap, expected);
1039 }
1040
1041 #[test]
1042 fn test_rpc_tx_fee_cap_parse_zero() {
1043 let args = CommandParser::<RpcServerArgs>::parse_from(["reth", "--rpc.txfeecap", "0"]).args;
1044 assert_eq!(args.rpc_tx_fee_cap, 0); }
1046
1047 #[test]
1048 fn test_rpc_tx_fee_cap_parse_none() {
1049 let args = CommandParser::<RpcServerArgs>::parse_from(["reth"]).args;
1050 let expected = 1_000_000_000_000_000_000u128;
1051 assert_eq!(args.rpc_tx_fee_cap, expected); }
1053
1054 #[test]
1055 fn test_rpc_server_args() {
1056 let args = RpcServerArgs {
1057 http: true,
1058 http_addr: "127.0.0.1".parse().unwrap(),
1059 http_port: 8545,
1060 http_disable_compression: false,
1061 http_api: Some(RpcModuleSelection::try_from_selection(["eth", "admin"]).unwrap()),
1062 http_corsdomain: Some("*".to_string()),
1063 ws: true,
1064 ws_addr: "127.0.0.1".parse().unwrap(),
1065 ws_port: 8546,
1066 ws_allowed_origins: Some("*".to_string()),
1067 ws_api: Some(RpcModuleSelection::try_from_selection(["eth", "admin"]).unwrap()),
1068 ipcdisable: false,
1069 ipcpath: "reth.ipc".to_string(),
1070 ipc_socket_permissions: Some("0o666".to_string()),
1071 auth_addr: "127.0.0.1".parse().unwrap(),
1072 auth_port: 8551,
1073 auth_jwtsecret: Some(std::path::PathBuf::from("/tmp/jwt.hex")),
1074 auth_ipc: false,
1075 auth_ipc_path: "engine.ipc".to_string(),
1076 disable_auth_server: false,
1077 rpc_jwtsecret: Some(
1078 JwtSecret::from_hex(
1079 "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
1080 )
1081 .unwrap(),
1082 ),
1083 rpc_disable_metrics: false,
1084 rpc_max_request_size: 15u32.into(),
1085 rpc_max_response_size: 160u32.into(),
1086 rpc_max_subscriptions_per_connection: 1024u32.into(),
1087 rpc_max_connections: 500u32.into(),
1088 rpc_max_tracing_requests: 16,
1089 rpc_max_blocking_io_requests: 256,
1090 rpc_max_trace_filter_blocks: 4000,
1091 rpc_max_blocks_per_filter: 1000u64.into(),
1092 rpc_max_logs_per_response: 10000u64.into(),
1093 rpc_gas_cap: 50_000_000,
1094 rpc_evm_memory_limit: 256,
1095 rpc_tx_fee_cap: 2_000_000_000_000_000_000u128,
1096 rpc_max_simulate_blocks: 256,
1097 rpc_compute_state_root_for_eth_simulate: false,
1098 rpc_eth_proof_window: 100_000,
1099 rpc_proof_permits: 16,
1100 rpc_pending_block: PendingBlockKind::Full,
1101 rpc_forwarder: Some("http://localhost:8545".parse().unwrap()),
1102 builder_disallow: None,
1103 rpc_state_cache: RpcStateCacheArgs {
1104 max_blocks: 5000,
1105 max_receipts: 2000,
1106 max_headers: 1000,
1107 max_bals: 1000,
1108 max_concurrent_db_requests: 512,
1109 max_cached_tx_hashes: 30_000,
1110 },
1111 gas_price_oracle: GasPriceOracleArgs {
1112 blocks: 20,
1113 ignore_price: 2,
1114 max_price: 500_000_000_000,
1115 percentile: 60,
1116 default_suggested_fee: None,
1117 },
1118 rpc_send_raw_transaction_sync_timeout: std::time::Duration::from_secs(30),
1119 testing_skip_invalid_transactions: true,
1120 testing_gas_limit: None,
1121 rpc_force_blob_sidecar_upcasting: false,
1122 };
1123
1124 let parsed_args = CommandParser::<RpcServerArgs>::parse_from([
1125 "reth",
1126 "--http",
1127 "--http.addr",
1128 "127.0.0.1",
1129 "--http.port",
1130 "8545",
1131 "--http.api",
1132 "eth,admin",
1133 "--http.corsdomain",
1134 "*",
1135 "--ws",
1136 "--ws.addr",
1137 "127.0.0.1",
1138 "--ws.port",
1139 "8546",
1140 "--ws.origins",
1141 "*",
1142 "--ws.api",
1143 "eth,admin",
1144 "--ipcpath",
1145 "reth.ipc",
1146 "--ipc.permissions",
1147 "0o666",
1148 "--authrpc.addr",
1149 "127.0.0.1",
1150 "--authrpc.port",
1151 "8551",
1152 "--authrpc.jwtsecret",
1153 "/tmp/jwt.hex",
1154 "--auth-ipc.path",
1155 "engine.ipc",
1156 "--rpc.jwtsecret",
1157 "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
1158 "--rpc.max-request-size",
1159 "15",
1160 "--rpc.max-response-size",
1161 "160",
1162 "--rpc.max-subscriptions-per-connection",
1163 "1024",
1164 "--rpc.max-connections",
1165 "500",
1166 "--rpc.max-tracing-requests",
1167 "16",
1168 "--rpc.max-blocking-io-requests",
1169 "256",
1170 "--rpc.max-trace-filter-blocks",
1171 "4000",
1172 "--rpc.max-blocks-per-filter",
1173 "1000",
1174 "--rpc.max-logs-per-response",
1175 "10000",
1176 "--rpc.gascap",
1177 "50000000",
1178 "--rpc.evm-memory-limit",
1179 "256",
1180 "--rpc.txfeecap",
1181 "2.0",
1182 "--rpc.max-simulate-blocks",
1183 "256",
1184 "--rpc.eth-proof-window",
1185 "100000",
1186 "--rpc.proof-permits",
1187 "16",
1188 "--rpc.pending-block",
1189 "full",
1190 "--rpc.forwarder",
1191 "http://localhost:8545",
1192 "--rpc-cache.max-blocks",
1193 "5000",
1194 "--rpc-cache.max-receipts",
1195 "2000",
1196 "--rpc-cache.max-headers",
1197 "1000",
1198 "--rpc-cache.max-bals",
1199 "1000",
1200 "--rpc-cache.max-concurrent-db-requests",
1201 "512",
1202 "--gpo.blocks",
1203 "20",
1204 "--gpo.ignoreprice",
1205 "2",
1206 "--gpo.maxprice",
1207 "500000000000",
1208 "--gpo.percentile",
1209 "60",
1210 "--rpc.send-raw-transaction-sync-timeout",
1211 "30s",
1212 "--testing.skip-invalid-transactions",
1213 ])
1214 .args;
1215
1216 assert_eq!(parsed_args, args);
1217 }
1218}