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_max_request_size: MaxU32,
75 rpc_max_response_size: MaxU32,
76 rpc_max_subscriptions_per_connection: MaxU32,
77 rpc_max_connections: MaxU32,
78 rpc_max_tracing_requests: usize,
79 rpc_max_blocking_io_requests: usize,
80 rpc_max_trace_filter_blocks: u64,
81 rpc_max_blocks_per_filter: ZeroAsNoneU64,
82 rpc_max_logs_per_response: ZeroAsNoneU64,
83 rpc_gas_cap: u64,
84 rpc_evm_memory_limit: u64,
85 rpc_tx_fee_cap: u128,
86 rpc_max_simulate_blocks: u64,
87 rpc_eth_proof_window: u64,
88 rpc_proof_permits: usize,
89 rpc_pending_block: PendingBlockKind,
90 rpc_forwarder: Option<Url>,
91 builder_disallow: Option<AddressSet>,
92 rpc_state_cache: RpcStateCacheArgs,
93 gas_price_oracle: GasPriceOracleArgs,
94 rpc_send_raw_transaction_sync_timeout: Duration,
95}
96
97impl DefaultRpcServerArgs {
98 pub fn try_init(self) -> Result<(), Self> {
100 RPC_SERVER_DEFAULTS.set(self)
101 }
102
103 pub fn get_global() -> &'static Self {
105 RPC_SERVER_DEFAULTS.get_or_init(Self::default)
106 }
107
108 pub const fn with_http(mut self, v: bool) -> Self {
110 self.http = v;
111 self
112 }
113
114 pub const fn with_http_addr(mut self, v: IpAddr) -> Self {
116 self.http_addr = v;
117 self
118 }
119
120 pub const fn with_http_port(mut self, v: u16) -> Self {
122 self.http_port = v;
123 self
124 }
125
126 pub const fn with_http_disable_compression(mut self, v: bool) -> Self {
128 self.http_disable_compression = v;
129 self
130 }
131
132 pub fn with_http_api(mut self, v: Option<RpcModuleSelection>) -> Self {
134 self.http_api = v;
135 self
136 }
137
138 pub fn with_http_corsdomain(mut self, v: Option<String>) -> Self {
140 self.http_corsdomain = v;
141 self
142 }
143
144 pub const fn with_ws(mut self, v: bool) -> Self {
146 self.ws = v;
147 self
148 }
149
150 pub const fn with_ws_addr(mut self, v: IpAddr) -> Self {
152 self.ws_addr = v;
153 self
154 }
155
156 pub const fn with_ws_port(mut self, v: u16) -> Self {
158 self.ws_port = v;
159 self
160 }
161
162 pub fn with_ws_allowed_origins(mut self, v: Option<String>) -> Self {
164 self.ws_allowed_origins = v;
165 self
166 }
167
168 pub fn with_ws_api(mut self, v: Option<RpcModuleSelection>) -> Self {
170 self.ws_api = v;
171 self
172 }
173
174 pub const fn with_ipcdisable(mut self, v: bool) -> Self {
176 self.ipcdisable = v;
177 self
178 }
179
180 pub fn with_ipcpath(mut self, v: String) -> Self {
182 self.ipcpath = v;
183 self
184 }
185
186 pub fn with_ipc_socket_permissions(mut self, v: Option<String>) -> Self {
188 self.ipc_socket_permissions = v;
189 self
190 }
191
192 pub const fn with_auth_addr(mut self, v: IpAddr) -> Self {
194 self.auth_addr = v;
195 self
196 }
197
198 pub const fn with_auth_port(mut self, v: u16) -> Self {
200 self.auth_port = v;
201 self
202 }
203
204 pub fn with_auth_jwtsecret(mut self, v: Option<PathBuf>) -> Self {
206 self.auth_jwtsecret = v;
207 self
208 }
209
210 pub const fn with_auth_ipc(mut self, v: bool) -> Self {
212 self.auth_ipc = v;
213 self
214 }
215
216 pub fn with_auth_ipc_path(mut self, v: String) -> Self {
218 self.auth_ipc_path = v;
219 self
220 }
221
222 pub const fn with_disable_auth_server(mut self, v: bool) -> Self {
224 self.disable_auth_server = v;
225 self
226 }
227
228 pub const fn with_rpc_jwtsecret(mut self, v: Option<JwtSecret>) -> Self {
230 self.rpc_jwtsecret = v;
231 self
232 }
233
234 pub const fn with_rpc_max_request_size(mut self, v: MaxU32) -> Self {
236 self.rpc_max_request_size = v;
237 self
238 }
239
240 pub const fn with_rpc_max_response_size(mut self, v: MaxU32) -> Self {
242 self.rpc_max_response_size = v;
243 self
244 }
245
246 pub const fn with_rpc_max_subscriptions_per_connection(mut self, v: MaxU32) -> Self {
248 self.rpc_max_subscriptions_per_connection = v;
249 self
250 }
251
252 pub const fn with_rpc_max_connections(mut self, v: MaxU32) -> Self {
254 self.rpc_max_connections = v;
255 self
256 }
257
258 pub const fn with_rpc_max_tracing_requests(mut self, v: usize) -> Self {
260 self.rpc_max_tracing_requests = v;
261 self
262 }
263
264 pub const fn with_rpc_max_blocking_io_requests(mut self, v: usize) -> Self {
266 self.rpc_max_blocking_io_requests = v;
267 self
268 }
269
270 pub const fn with_rpc_max_trace_filter_blocks(mut self, v: u64) -> Self {
272 self.rpc_max_trace_filter_blocks = v;
273 self
274 }
275
276 pub const fn with_rpc_max_blocks_per_filter(mut self, v: ZeroAsNoneU64) -> Self {
278 self.rpc_max_blocks_per_filter = v;
279 self
280 }
281
282 pub const fn with_rpc_max_logs_per_response(mut self, v: ZeroAsNoneU64) -> Self {
284 self.rpc_max_logs_per_response = v;
285 self
286 }
287
288 pub const fn with_rpc_gas_cap(mut self, v: u64) -> Self {
290 self.rpc_gas_cap = v;
291 self
292 }
293
294 pub const fn with_rpc_evm_memory_limit(mut self, v: u64) -> Self {
296 self.rpc_evm_memory_limit = v;
297 self
298 }
299
300 pub const fn with_rpc_tx_fee_cap(mut self, v: u128) -> Self {
302 self.rpc_tx_fee_cap = v;
303 self
304 }
305
306 pub const fn with_rpc_max_simulate_blocks(mut self, v: u64) -> Self {
308 self.rpc_max_simulate_blocks = v;
309 self
310 }
311
312 pub const fn with_rpc_eth_proof_window(mut self, v: u64) -> Self {
314 self.rpc_eth_proof_window = v;
315 self
316 }
317
318 pub const fn with_rpc_proof_permits(mut self, v: usize) -> Self {
320 self.rpc_proof_permits = v;
321 self
322 }
323
324 pub const fn with_rpc_pending_block(mut self, v: PendingBlockKind) -> Self {
326 self.rpc_pending_block = v;
327 self
328 }
329
330 pub fn with_rpc_forwarder(mut self, v: Option<Url>) -> Self {
332 self.rpc_forwarder = v;
333 self
334 }
335
336 pub fn with_builder_disallow(mut self, v: Option<AddressSet>) -> Self {
338 self.builder_disallow = v;
339 self
340 }
341
342 pub const fn with_rpc_state_cache(mut self, v: RpcStateCacheArgs) -> Self {
344 self.rpc_state_cache = v;
345 self
346 }
347
348 pub const fn with_gas_price_oracle(mut self, v: GasPriceOracleArgs) -> Self {
350 self.gas_price_oracle = v;
351 self
352 }
353
354 pub const fn with_rpc_send_raw_transaction_sync_timeout(mut self, v: Duration) -> Self {
356 self.rpc_send_raw_transaction_sync_timeout = v;
357 self
358 }
359}
360
361impl Default for DefaultRpcServerArgs {
362 fn default() -> Self {
363 Self {
364 http: false,
365 http_addr: Ipv4Addr::LOCALHOST.into(),
366 http_port: constants::DEFAULT_HTTP_RPC_PORT,
367 http_disable_compression: false,
368 http_api: None,
369 http_corsdomain: None,
370 ws: false,
371 ws_addr: Ipv4Addr::LOCALHOST.into(),
372 ws_port: constants::DEFAULT_WS_RPC_PORT,
373 ws_allowed_origins: None,
374 ws_api: None,
375 ipcdisable: false,
376 ipcpath: constants::DEFAULT_IPC_ENDPOINT.to_string(),
377 ipc_socket_permissions: None,
378 auth_addr: Ipv4Addr::LOCALHOST.into(),
379 auth_port: constants::DEFAULT_AUTH_PORT,
380 auth_jwtsecret: None,
381 auth_ipc: false,
382 auth_ipc_path: constants::DEFAULT_ENGINE_API_IPC_ENDPOINT.to_string(),
383 disable_auth_server: false,
384 rpc_jwtsecret: None,
385 rpc_max_request_size: RPC_DEFAULT_MAX_REQUEST_SIZE_MB.into(),
386 rpc_max_response_size: RPC_DEFAULT_MAX_RESPONSE_SIZE_MB.into(),
387 rpc_max_subscriptions_per_connection: RPC_DEFAULT_MAX_SUBS_PER_CONN.into(),
388 rpc_max_connections: RPC_DEFAULT_MAX_CONNECTIONS.into(),
389 rpc_max_tracing_requests: constants::default_max_tracing_requests(),
390 rpc_max_blocking_io_requests: constants::DEFAULT_MAX_BLOCKING_IO_REQUEST,
391 rpc_max_trace_filter_blocks: constants::DEFAULT_MAX_TRACE_FILTER_BLOCKS,
392 rpc_max_blocks_per_filter: constants::DEFAULT_MAX_BLOCKS_PER_FILTER.into(),
393 rpc_max_logs_per_response: (constants::DEFAULT_MAX_LOGS_PER_RESPONSE as u64).into(),
394 rpc_gas_cap: constants::gas_oracle::RPC_DEFAULT_GAS_CAP,
395 rpc_evm_memory_limit: (1 << 32) - 1,
396 rpc_tx_fee_cap: constants::DEFAULT_TX_FEE_CAP_WEI,
397 rpc_max_simulate_blocks: constants::DEFAULT_MAX_SIMULATE_BLOCKS,
398 rpc_eth_proof_window: constants::DEFAULT_ETH_PROOF_WINDOW,
399 rpc_proof_permits: constants::DEFAULT_PROOF_PERMITS,
400 rpc_pending_block: PendingBlockKind::Full,
401 rpc_forwarder: None,
402 builder_disallow: None,
403 rpc_state_cache: RpcStateCacheArgs::default(),
404 gas_price_oracle: GasPriceOracleArgs::default(),
405 rpc_send_raw_transaction_sync_timeout:
406 constants::RPC_DEFAULT_SEND_RAW_TX_SYNC_TIMEOUT_SECS,
407 }
408 }
409}
410
411#[derive(Debug, Clone, Args, PartialEq, Eq)]
413#[command(next_help_heading = "RPC")]
414pub struct RpcServerArgs {
415 #[arg(long, default_value_if("dev", "true", "true"), default_value_t = DefaultRpcServerArgs::get_global().http)]
417 pub http: bool,
418
419 #[arg(long = "http.addr", default_value_t = DefaultRpcServerArgs::get_global().http_addr)]
421 pub http_addr: IpAddr,
422
423 #[arg(long = "http.port", default_value_t = DefaultRpcServerArgs::get_global().http_port)]
425 pub http_port: u16,
426
427 #[arg(long = "http.disable-compression", default_value_t = DefaultRpcServerArgs::get_global().http_disable_compression)]
429 pub http_disable_compression: bool,
430
431 #[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())))]
433 pub http_api: Option<RpcModuleSelection>,
434
435 #[arg(long = "http.corsdomain", default_value = Resettable::from(DefaultRpcServerArgs::get_global().http_corsdomain.as_ref().map(|v| v.to_string().into())))]
437 pub http_corsdomain: Option<String>,
438
439 #[arg(long, default_value_t = DefaultRpcServerArgs::get_global().ws)]
441 pub ws: bool,
442
443 #[arg(long = "ws.addr", default_value_t = DefaultRpcServerArgs::get_global().ws_addr)]
445 pub ws_addr: IpAddr,
446
447 #[arg(long = "ws.port", default_value_t = DefaultRpcServerArgs::get_global().ws_port)]
449 pub ws_port: u16,
450
451 #[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())))]
453 pub ws_allowed_origins: Option<String>,
454
455 #[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())))]
457 pub ws_api: Option<RpcModuleSelection>,
458
459 #[arg(long, default_value_t = DefaultRpcServerArgs::get_global().ipcdisable)]
461 pub ipcdisable: bool,
462
463 #[arg(long, default_value_t = DefaultRpcServerArgs::get_global().ipcpath.clone())]
465 pub ipcpath: String,
466
467 #[arg(long = "ipc.permissions", default_value = Resettable::from(DefaultRpcServerArgs::get_global().ipc_socket_permissions.as_ref().map(|v| v.to_string().into())))]
471 pub ipc_socket_permissions: Option<String>,
472
473 #[arg(long = "authrpc.addr", default_value_t = DefaultRpcServerArgs::get_global().auth_addr)]
475 pub auth_addr: IpAddr,
476
477 #[arg(long = "authrpc.port", default_value_t = DefaultRpcServerArgs::get_global().auth_port)]
479 pub auth_port: u16,
480
481 #[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())))]
489 pub auth_jwtsecret: Option<PathBuf>,
490
491 #[arg(long, default_value_t = DefaultRpcServerArgs::get_global().auth_ipc)]
493 pub auth_ipc: bool,
494
495 #[arg(long = "auth-ipc.path", default_value_t = DefaultRpcServerArgs::get_global().auth_ipc_path.clone())]
497 pub auth_ipc_path: String,
498
499 #[arg(long = "disable-auth-server", alias = "disable-engine-api", default_value_t = DefaultRpcServerArgs::get_global().disable_auth_server)]
504 pub disable_auth_server: bool,
505
506 #[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())))]
512 pub rpc_jwtsecret: Option<JwtSecret>,
513
514 #[arg(long = "rpc.max-request-size", alias = "rpc-max-request-size", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_request_size)]
516 pub rpc_max_request_size: MaxU32,
517
518 #[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)]
520 pub rpc_max_response_size: MaxU32,
521
522 #[arg(long = "rpc.max-subscriptions-per-connection", alias = "rpc-max-subscriptions-per-connection", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_subscriptions_per_connection)]
524 pub rpc_max_subscriptions_per_connection: MaxU32,
525
526 #[arg(long = "rpc.max-connections", alias = "rpc-max-connections", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_connections)]
528 pub rpc_max_connections: MaxU32,
529
530 #[arg(long = "rpc.max-tracing-requests", alias = "rpc-max-tracing-requests", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_tracing_requests)]
537 pub rpc_max_tracing_requests: usize,
538
539 #[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)]
545 pub rpc_max_blocking_io_requests: usize,
546
547 #[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)]
549 pub rpc_max_trace_filter_blocks: u64,
550
551 #[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)]
553 pub rpc_max_blocks_per_filter: ZeroAsNoneU64,
554
555 #[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)]
557 pub rpc_max_logs_per_response: ZeroAsNoneU64,
558
559 #[arg(
561 long = "rpc.gascap",
562 alias = "rpc-gascap",
563 value_name = "GAS_CAP",
564 value_parser = MaxOr::new(RangedU64ValueParser::<u64>::new().range(1..)),
565 default_value_t = DefaultRpcServerArgs::get_global().rpc_gas_cap
566 )]
567 pub rpc_gas_cap: u64,
568
569 #[arg(
571 long = "rpc.evm-memory-limit",
572 alias = "rpc-evm-memory-limit",
573 value_name = "MEMORY_LIMIT",
574 value_parser = MaxOr::new(RangedU64ValueParser::<u64>::new().range(1..)),
575 default_value_t = DefaultRpcServerArgs::get_global().rpc_evm_memory_limit
576 )]
577 pub rpc_evm_memory_limit: u64,
578
579 #[arg(
581 long = "rpc.txfeecap",
582 alias = "rpc-txfeecap",
583 value_name = "TX_FEE_CAP",
584 value_parser = parse_ether_value,
585 default_value = "1.0"
586 )]
587 pub rpc_tx_fee_cap: u128,
588
589 #[arg(
591 long = "rpc.max-simulate-blocks",
592 value_name = "BLOCKS_COUNT",
593 default_value_t = DefaultRpcServerArgs::get_global().rpc_max_simulate_blocks
594 )]
595 pub rpc_max_simulate_blocks: u64,
596
597 #[arg(
601 long = "rpc.eth-proof-window",
602 default_value_t = DefaultRpcServerArgs::get_global().rpc_eth_proof_window,
603 value_parser = RangedU64ValueParser::<u64>::new().range(..=constants::MAX_ETH_PROOF_WINDOW)
604 )]
605 pub rpc_eth_proof_window: u64,
606
607 #[arg(long = "rpc.proof-permits", alias = "rpc-proof-permits", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_proof_permits)]
609 pub rpc_proof_permits: usize,
610
611 #[arg(long = "rpc.pending-block", default_value = "full", value_name = "KIND")]
616 pub rpc_pending_block: PendingBlockKind,
617
618 #[arg(long = "rpc.forwarder", alias = "rpc-forwarder", value_name = "FORWARDER")]
620 pub rpc_forwarder: Option<Url>,
621
622 #[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())))]
625 pub builder_disallow: Option<AddressSet>,
626
627 #[command(flatten)]
629 pub rpc_state_cache: RpcStateCacheArgs,
630
631 #[command(flatten)]
633 pub gas_price_oracle: GasPriceOracleArgs,
634
635 #[arg(
637 long = "rpc.send-raw-transaction-sync-timeout",
638 value_name = "SECONDS",
639 default_value = "30s",
640 value_parser = parse_duration_from_secs_or_ms,
641 )]
642 pub rpc_send_raw_transaction_sync_timeout: Duration,
643
644 #[arg(long = "testing.skip-invalid-transactions", default_value_t = true)]
649 pub testing_skip_invalid_transactions: bool,
650
651 #[arg(long = "testing.skip-gas-limit-ramp-check", default_value_t = false, hide = true)]
657 pub testing_skip_gas_limit_ramp_check: bool,
658
659 #[arg(long = "testing.gas-limit", value_name = "GAS_LIMIT", hide = true)]
665 pub testing_gas_limit: Option<u64>,
666
667 #[arg(long = "rpc.force-blob-sidecar-upcasting", default_value_t = false)]
673 pub rpc_force_blob_sidecar_upcasting: bool,
674}
675
676impl RpcServerArgs {
677 pub const fn with_http(mut self) -> Self {
679 self.http = true;
680 self
681 }
682
683 pub fn with_http_api(mut self, http_api: RpcModuleSelection) -> Self {
685 self.http_api = Some(http_api);
686 self
687 }
688
689 pub const fn with_ws(mut self) -> Self {
691 self.ws = true;
692 self
693 }
694
695 pub fn with_ws_api(mut self, ws_api: RpcModuleSelection) -> Self {
697 self.ws_api = Some(ws_api);
698 self
699 }
700
701 pub const fn with_auth_ipc(mut self) -> Self {
703 self.auth_ipc = true;
704 self
705 }
706
707 pub fn with_api(self, api: RpcModuleSelection) -> Self {
711 self.with_http_api(api.clone()).with_ws_api(api)
712 }
713
714 pub fn adjust_instance_ports(&mut self, instance: Option<u16>) {
729 if let Some(instance) = instance {
730 debug_assert_ne!(instance, 0, "instance must be non-zero");
731 self.auth_port += instance * 100 - 100;
733 self.http_port -= instance - 1;
735 self.ws_port += instance * 2 - 2;
737 self.ipcpath = format!("{}-{}", self.ipcpath, instance);
739 }
740 }
741
742 pub const fn with_http_unused_port(mut self) -> Self {
745 self.http_port = 0;
746 self
747 }
748
749 pub const fn with_ws_unused_port(mut self) -> Self {
752 self.ws_port = 0;
753 self
754 }
755
756 pub const fn with_auth_unused_port(mut self) -> Self {
759 self.auth_port = 0;
760 self
761 }
762
763 pub fn with_ipc_random_path(mut self) -> Self {
766 let random_string: String =
767 rand::rng().sample_iter(rand::distr::Alphanumeric).take(8).map(char::from).collect();
768 self.ipcpath = format!("{}-{}", self.ipcpath, random_string);
769 self
770 }
771
772 pub fn with_unused_ports(mut self) -> Self {
775 self = self.with_http_unused_port();
776 self = self.with_ws_unused_port();
777 self = self.with_auth_unused_port();
778 self = self.with_ipc_random_path();
779 self
780 }
781
782 pub fn apply<F>(self, f: F) -> Self
784 where
785 F: FnOnce(Self) -> Self,
786 {
787 f(self)
788 }
789
790 pub const fn with_send_raw_transaction_sync_timeout(mut self, timeout: Duration) -> Self {
792 self.rpc_send_raw_transaction_sync_timeout = timeout;
793 self
794 }
795
796 pub fn is_namespace_enabled(&self, ns: RethRpcModule) -> bool {
798 if self.http && self.http_api.as_ref().is_some_and(|api| api.contains(&ns)) {
799 return true;
800 }
801 if self.ws && self.ws_api.as_ref().is_some_and(|api| api.contains(&ns)) {
802 return true;
803 }
804 !self.ipcdisable
806 }
807
808 pub const fn with_force_blob_sidecar_upcasting(mut self) -> Self {
810 self.rpc_force_blob_sidecar_upcasting = true;
811 self
812 }
813}
814
815impl Default for RpcServerArgs {
816 fn default() -> Self {
817 let DefaultRpcServerArgs {
818 http,
819 http_addr,
820 http_port,
821 http_disable_compression,
822 http_api,
823 http_corsdomain,
824 ws,
825 ws_addr,
826 ws_port,
827 ws_allowed_origins,
828 ws_api,
829 ipcdisable,
830 ipcpath,
831 ipc_socket_permissions,
832 auth_addr,
833 auth_port,
834 auth_jwtsecret,
835 auth_ipc,
836 auth_ipc_path,
837 disable_auth_server,
838 rpc_jwtsecret,
839 rpc_max_request_size,
840 rpc_max_response_size,
841 rpc_max_subscriptions_per_connection,
842 rpc_max_connections,
843 rpc_max_tracing_requests,
844 rpc_max_blocking_io_requests,
845 rpc_max_trace_filter_blocks,
846 rpc_max_blocks_per_filter,
847 rpc_max_logs_per_response,
848 rpc_gas_cap,
849 rpc_evm_memory_limit,
850 rpc_tx_fee_cap,
851 rpc_max_simulate_blocks,
852 rpc_eth_proof_window,
853 rpc_proof_permits,
854 rpc_pending_block,
855 rpc_forwarder,
856 builder_disallow,
857 rpc_state_cache,
858 gas_price_oracle,
859 rpc_send_raw_transaction_sync_timeout,
860 } = DefaultRpcServerArgs::get_global().clone();
861 Self {
862 http,
863 http_addr,
864 http_port,
865 http_disable_compression,
866 http_api,
867 http_corsdomain,
868 ws,
869 ws_addr,
870 ws_port,
871 ws_allowed_origins,
872 ws_api,
873 ipcdisable,
874 ipcpath,
875 ipc_socket_permissions,
876 auth_addr,
877 auth_port,
878 auth_jwtsecret,
879 auth_ipc,
880 auth_ipc_path,
881 disable_auth_server,
882 rpc_jwtsecret,
883 rpc_max_request_size,
884 rpc_max_response_size,
885 rpc_max_subscriptions_per_connection,
886 rpc_max_connections,
887 rpc_max_tracing_requests,
888 rpc_max_blocking_io_requests,
889 rpc_max_trace_filter_blocks,
890 rpc_max_blocks_per_filter,
891 rpc_max_logs_per_response,
892 rpc_gas_cap,
893 rpc_evm_memory_limit,
894 rpc_tx_fee_cap,
895 rpc_max_simulate_blocks,
896 rpc_eth_proof_window,
897 rpc_proof_permits,
898 rpc_pending_block,
899 rpc_forwarder,
900 builder_disallow,
901 rpc_state_cache,
902 gas_price_oracle,
903 rpc_send_raw_transaction_sync_timeout,
904 testing_skip_invalid_transactions: true,
905 testing_skip_gas_limit_ramp_check: false,
906 testing_gas_limit: None,
907 rpc_force_blob_sidecar_upcasting: false,
908 }
909 }
910}
911
912#[derive(Clone, Debug, Default)]
914#[non_exhaustive]
915struct RpcModuleSelectionValueParser;
916
917impl TypedValueParser for RpcModuleSelectionValueParser {
918 type Value = RpcModuleSelection;
919
920 fn parse_ref(
921 &self,
922 _cmd: &Command,
923 _arg: Option<&Arg>,
924 value: &OsStr,
925 ) -> Result<Self::Value, clap::Error> {
926 let val =
927 value.to_str().ok_or_else(|| clap::Error::new(clap::error::ErrorKind::InvalidUtf8))?;
928 Ok(val
930 .parse::<RpcModuleSelection>()
931 .expect("RpcModuleSelection parsing cannot fail with Other variant"))
932 }
933
934 fn possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>> {
935 let values = RethRpcModule::standard_variant_names().map(PossibleValue::new);
937 Some(Box::new(values))
938 }
939}
940
941#[cfg(test)]
942mod tests {
943 use super::*;
944 use clap::{Args, Parser};
945
946 #[derive(Parser)]
948 struct CommandParser<T: Args> {
949 #[command(flatten)]
950 args: T,
951 }
952
953 #[test]
954 fn test_rpc_server_args_parser() {
955 let args =
956 CommandParser::<RpcServerArgs>::parse_from(["reth", "--http.api", "eth,admin,debug"])
957 .args;
958
959 let apis = args.http_api.unwrap();
960 let expected = RpcModuleSelection::try_from_selection(["eth", "admin", "debug"]).unwrap();
961
962 assert_eq!(apis, expected);
963 }
964
965 #[test]
966 fn test_rpc_server_eth_call_bundle_args() {
967 let args =
968 CommandParser::<RpcServerArgs>::parse_from(["reth", "--http.api", "eth,admin,debug"])
969 .args;
970
971 let apis = args.http_api.unwrap();
972 let expected = RpcModuleSelection::try_from_selection(["eth", "admin", "debug"]).unwrap();
973
974 assert_eq!(apis, expected);
975 }
976
977 #[test]
978 fn test_rpc_server_args_parser_none() {
979 let args = CommandParser::<RpcServerArgs>::parse_from(["reth", "--http.api", "none"]).args;
980 let apis = args.http_api.unwrap();
981 let expected = RpcModuleSelection::Selection(Default::default());
982 assert_eq!(apis, expected);
983 }
984
985 #[test]
986 fn rpc_server_args_default_sanity_test() {
987 let default_args = RpcServerArgs::default();
988 let args = CommandParser::<RpcServerArgs>::parse_from(["reth"]).args;
989
990 assert_eq!(args, default_args);
991 }
992
993 #[test]
994 fn test_rpc_tx_fee_cap_parse_integer() {
995 let args = CommandParser::<RpcServerArgs>::parse_from(["reth", "--rpc.txfeecap", "2"]).args;
996 let expected = 2_000_000_000_000_000_000u128; assert_eq!(args.rpc_tx_fee_cap, expected);
998 }
999
1000 #[test]
1001 fn test_rpc_tx_fee_cap_parse_decimal() {
1002 let args =
1003 CommandParser::<RpcServerArgs>::parse_from(["reth", "--rpc.txfeecap", "1.5"]).args;
1004 let expected = 1_500_000_000_000_000_000u128; assert_eq!(args.rpc_tx_fee_cap, expected);
1006 }
1007
1008 #[test]
1009 fn test_rpc_tx_fee_cap_parse_zero() {
1010 let args = CommandParser::<RpcServerArgs>::parse_from(["reth", "--rpc.txfeecap", "0"]).args;
1011 assert_eq!(args.rpc_tx_fee_cap, 0); }
1013
1014 #[test]
1015 fn test_rpc_tx_fee_cap_parse_none() {
1016 let args = CommandParser::<RpcServerArgs>::parse_from(["reth"]).args;
1017 let expected = 1_000_000_000_000_000_000u128;
1018 assert_eq!(args.rpc_tx_fee_cap, expected); }
1020
1021 #[test]
1022 fn test_rpc_server_args() {
1023 let args = RpcServerArgs {
1024 http: true,
1025 http_addr: "127.0.0.1".parse().unwrap(),
1026 http_port: 8545,
1027 http_disable_compression: false,
1028 http_api: Some(RpcModuleSelection::try_from_selection(["eth", "admin"]).unwrap()),
1029 http_corsdomain: Some("*".to_string()),
1030 ws: true,
1031 ws_addr: "127.0.0.1".parse().unwrap(),
1032 ws_port: 8546,
1033 ws_allowed_origins: Some("*".to_string()),
1034 ws_api: Some(RpcModuleSelection::try_from_selection(["eth", "admin"]).unwrap()),
1035 ipcdisable: false,
1036 ipcpath: "reth.ipc".to_string(),
1037 ipc_socket_permissions: Some("0o666".to_string()),
1038 auth_addr: "127.0.0.1".parse().unwrap(),
1039 auth_port: 8551,
1040 auth_jwtsecret: Some(std::path::PathBuf::from("/tmp/jwt.hex")),
1041 auth_ipc: false,
1042 auth_ipc_path: "engine.ipc".to_string(),
1043 disable_auth_server: false,
1044 rpc_jwtsecret: Some(
1045 JwtSecret::from_hex(
1046 "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
1047 )
1048 .unwrap(),
1049 ),
1050 rpc_max_request_size: 15u32.into(),
1051 rpc_max_response_size: 160u32.into(),
1052 rpc_max_subscriptions_per_connection: 1024u32.into(),
1053 rpc_max_connections: 500u32.into(),
1054 rpc_max_tracing_requests: 16,
1055 rpc_max_blocking_io_requests: 256,
1056 rpc_max_trace_filter_blocks: 4000,
1057 rpc_max_blocks_per_filter: 1000u64.into(),
1058 rpc_max_logs_per_response: 10000u64.into(),
1059 rpc_gas_cap: 50_000_000,
1060 rpc_evm_memory_limit: 256,
1061 rpc_tx_fee_cap: 2_000_000_000_000_000_000u128,
1062 rpc_max_simulate_blocks: 256,
1063 rpc_eth_proof_window: 100_000,
1064 rpc_proof_permits: 16,
1065 rpc_pending_block: PendingBlockKind::Full,
1066 rpc_forwarder: Some("http://localhost:8545".parse().unwrap()),
1067 builder_disallow: None,
1068 rpc_state_cache: RpcStateCacheArgs {
1069 max_blocks: 5000,
1070 max_receipts: 2000,
1071 max_headers: 1000,
1072 max_concurrent_db_requests: 512,
1073 max_cached_tx_hashes: 30_000,
1074 },
1075 gas_price_oracle: GasPriceOracleArgs {
1076 blocks: 20,
1077 ignore_price: 2,
1078 max_price: 500_000_000_000,
1079 percentile: 60,
1080 default_suggested_fee: None,
1081 },
1082 rpc_send_raw_transaction_sync_timeout: std::time::Duration::from_secs(30),
1083 testing_skip_invalid_transactions: true,
1084 testing_skip_gas_limit_ramp_check: false,
1085 testing_gas_limit: None,
1086 rpc_force_blob_sidecar_upcasting: false,
1087 };
1088
1089 let parsed_args = CommandParser::<RpcServerArgs>::parse_from([
1090 "reth",
1091 "--http",
1092 "--http.addr",
1093 "127.0.0.1",
1094 "--http.port",
1095 "8545",
1096 "--http.api",
1097 "eth,admin",
1098 "--http.corsdomain",
1099 "*",
1100 "--ws",
1101 "--ws.addr",
1102 "127.0.0.1",
1103 "--ws.port",
1104 "8546",
1105 "--ws.origins",
1106 "*",
1107 "--ws.api",
1108 "eth,admin",
1109 "--ipcpath",
1110 "reth.ipc",
1111 "--ipc.permissions",
1112 "0o666",
1113 "--authrpc.addr",
1114 "127.0.0.1",
1115 "--authrpc.port",
1116 "8551",
1117 "--authrpc.jwtsecret",
1118 "/tmp/jwt.hex",
1119 "--auth-ipc.path",
1120 "engine.ipc",
1121 "--rpc.jwtsecret",
1122 "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
1123 "--rpc.max-request-size",
1124 "15",
1125 "--rpc.max-response-size",
1126 "160",
1127 "--rpc.max-subscriptions-per-connection",
1128 "1024",
1129 "--rpc.max-connections",
1130 "500",
1131 "--rpc.max-tracing-requests",
1132 "16",
1133 "--rpc.max-blocking-io-requests",
1134 "256",
1135 "--rpc.max-trace-filter-blocks",
1136 "4000",
1137 "--rpc.max-blocks-per-filter",
1138 "1000",
1139 "--rpc.max-logs-per-response",
1140 "10000",
1141 "--rpc.gascap",
1142 "50000000",
1143 "--rpc.evm-memory-limit",
1144 "256",
1145 "--rpc.txfeecap",
1146 "2.0",
1147 "--rpc.max-simulate-blocks",
1148 "256",
1149 "--rpc.eth-proof-window",
1150 "100000",
1151 "--rpc.proof-permits",
1152 "16",
1153 "--rpc.pending-block",
1154 "full",
1155 "--rpc.forwarder",
1156 "http://localhost:8545",
1157 "--rpc-cache.max-blocks",
1158 "5000",
1159 "--rpc-cache.max-receipts",
1160 "2000",
1161 "--rpc-cache.max-headers",
1162 "1000",
1163 "--rpc-cache.max-concurrent-db-requests",
1164 "512",
1165 "--gpo.blocks",
1166 "20",
1167 "--gpo.ignoreprice",
1168 "2",
1169 "--gpo.maxprice",
1170 "500000000000",
1171 "--gpo.percentile",
1172 "60",
1173 "--rpc.send-raw-transaction-sync-timeout",
1174 "30s",
1175 "--testing.skip-invalid-transactions",
1176 ])
1177 .args;
1178
1179 assert_eq!(parsed_args, args);
1180 }
1181}