1use crate::args::{
4 types::{MaxU32, ZeroAsNoneU64},
5 GasPriceOracleArgs, RpcStateCacheArgs,
6};
7use alloy_primitives::Address;
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 collections::HashSet,
19 ffi::OsStr,
20 net::{IpAddr, Ipv4Addr},
21 path::PathBuf,
22 sync::OnceLock,
23 time::Duration,
24};
25use url::Url;
26
27use super::types::MaxOr;
28
29static RPC_SERVER_DEFAULTS: OnceLock<DefaultRpcServerArgs> = OnceLock::new();
31
32pub(crate) const RPC_DEFAULT_MAX_SUBS_PER_CONN: u32 = 1024;
34
35pub(crate) const RPC_DEFAULT_MAX_REQUEST_SIZE_MB: u32 = 15;
37
38pub(crate) const RPC_DEFAULT_MAX_RESPONSE_SIZE_MB: u32 = 160;
42
43pub(crate) const RPC_DEFAULT_MAX_CONNECTIONS: u32 = 500;
48
49#[derive(Debug, Clone)]
53pub struct DefaultRpcServerArgs {
54 http: bool,
55 http_addr: IpAddr,
56 http_port: u16,
57 http_disable_compression: bool,
58 http_api: Option<RpcModuleSelection>,
59 http_corsdomain: Option<String>,
60 ws: bool,
61 ws_addr: IpAddr,
62 ws_port: u16,
63 ws_allowed_origins: Option<String>,
64 ws_api: Option<RpcModuleSelection>,
65 ipcdisable: bool,
66 ipcpath: String,
67 ipc_socket_permissions: Option<String>,
68 auth_addr: IpAddr,
69 auth_port: u16,
70 auth_jwtsecret: Option<PathBuf>,
71 auth_ipc: bool,
72 auth_ipc_path: String,
73 disable_auth_server: bool,
74 rpc_jwtsecret: Option<JwtSecret>,
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_eth_proof_window: u64,
89 rpc_proof_permits: usize,
90 rpc_pending_block: PendingBlockKind,
91 rpc_forwarder: Option<Url>,
92 builder_disallow: Option<HashSet<Address>>,
93 rpc_state_cache: RpcStateCacheArgs,
94 gas_price_oracle: GasPriceOracleArgs,
95 rpc_send_raw_transaction_sync_timeout: Duration,
96}
97
98impl DefaultRpcServerArgs {
99 pub fn try_init(self) -> Result<(), Self> {
101 RPC_SERVER_DEFAULTS.set(self)
102 }
103
104 pub fn get_global() -> &'static Self {
106 RPC_SERVER_DEFAULTS.get_or_init(Self::default)
107 }
108
109 pub const fn with_http(mut self, v: bool) -> Self {
111 self.http = v;
112 self
113 }
114
115 pub const fn with_http_addr(mut self, v: IpAddr) -> Self {
117 self.http_addr = v;
118 self
119 }
120
121 pub const fn with_http_port(mut self, v: u16) -> Self {
123 self.http_port = v;
124 self
125 }
126
127 pub const fn with_http_disable_compression(mut self, v: bool) -> Self {
129 self.http_disable_compression = v;
130 self
131 }
132
133 pub fn with_http_api(mut self, v: Option<RpcModuleSelection>) -> Self {
135 self.http_api = v;
136 self
137 }
138
139 pub fn with_http_corsdomain(mut self, v: Option<String>) -> Self {
141 self.http_corsdomain = v;
142 self
143 }
144
145 pub const fn with_ws(mut self, v: bool) -> Self {
147 self.ws = v;
148 self
149 }
150
151 pub const fn with_ws_addr(mut self, v: IpAddr) -> Self {
153 self.ws_addr = v;
154 self
155 }
156
157 pub const fn with_ws_port(mut self, v: u16) -> Self {
159 self.ws_port = v;
160 self
161 }
162
163 pub fn with_ws_allowed_origins(mut self, v: Option<String>) -> Self {
165 self.ws_allowed_origins = v;
166 self
167 }
168
169 pub fn with_ws_api(mut self, v: Option<RpcModuleSelection>) -> Self {
171 self.ws_api = v;
172 self
173 }
174
175 pub const fn with_ipcdisable(mut self, v: bool) -> Self {
177 self.ipcdisable = v;
178 self
179 }
180
181 pub fn with_ipcpath(mut self, v: String) -> Self {
183 self.ipcpath = v;
184 self
185 }
186
187 pub fn with_ipc_socket_permissions(mut self, v: Option<String>) -> Self {
189 self.ipc_socket_permissions = v;
190 self
191 }
192
193 pub const fn with_auth_addr(mut self, v: IpAddr) -> Self {
195 self.auth_addr = v;
196 self
197 }
198
199 pub const fn with_auth_port(mut self, v: u16) -> Self {
201 self.auth_port = v;
202 self
203 }
204
205 pub fn with_auth_jwtsecret(mut self, v: Option<PathBuf>) -> Self {
207 self.auth_jwtsecret = v;
208 self
209 }
210
211 pub const fn with_auth_ipc(mut self, v: bool) -> Self {
213 self.auth_ipc = v;
214 self
215 }
216
217 pub fn with_auth_ipc_path(mut self, v: String) -> Self {
219 self.auth_ipc_path = v;
220 self
221 }
222
223 pub const fn with_disable_auth_server(mut self, v: bool) -> Self {
225 self.disable_auth_server = v;
226 self
227 }
228
229 pub const fn with_rpc_jwtsecret(mut self, v: Option<JwtSecret>) -> Self {
231 self.rpc_jwtsecret = v;
232 self
233 }
234
235 pub const fn with_rpc_max_request_size(mut self, v: MaxU32) -> Self {
237 self.rpc_max_request_size = v;
238 self
239 }
240
241 pub const fn with_rpc_max_response_size(mut self, v: MaxU32) -> Self {
243 self.rpc_max_response_size = v;
244 self
245 }
246
247 pub const fn with_rpc_max_subscriptions_per_connection(mut self, v: MaxU32) -> Self {
249 self.rpc_max_subscriptions_per_connection = v;
250 self
251 }
252
253 pub const fn with_rpc_max_connections(mut self, v: MaxU32) -> Self {
255 self.rpc_max_connections = v;
256 self
257 }
258
259 pub const fn with_rpc_max_tracing_requests(mut self, v: usize) -> Self {
261 self.rpc_max_tracing_requests = v;
262 self
263 }
264
265 pub const fn with_rpc_max_blocking_io_requests(mut self, v: usize) -> Self {
267 self.rpc_max_blocking_io_requests = v;
268 self
269 }
270
271 pub const fn with_rpc_max_trace_filter_blocks(mut self, v: u64) -> Self {
273 self.rpc_max_trace_filter_blocks = v;
274 self
275 }
276
277 pub const fn with_rpc_max_blocks_per_filter(mut self, v: ZeroAsNoneU64) -> Self {
279 self.rpc_max_blocks_per_filter = v;
280 self
281 }
282
283 pub const fn with_rpc_max_logs_per_response(mut self, v: ZeroAsNoneU64) -> Self {
285 self.rpc_max_logs_per_response = v;
286 self
287 }
288
289 pub const fn with_rpc_gas_cap(mut self, v: u64) -> Self {
291 self.rpc_gas_cap = v;
292 self
293 }
294
295 pub const fn with_rpc_evm_memory_limit(mut self, v: u64) -> Self {
297 self.rpc_evm_memory_limit = v;
298 self
299 }
300
301 pub const fn with_rpc_tx_fee_cap(mut self, v: u128) -> Self {
303 self.rpc_tx_fee_cap = v;
304 self
305 }
306
307 pub const fn with_rpc_max_simulate_blocks(mut self, v: u64) -> Self {
309 self.rpc_max_simulate_blocks = v;
310 self
311 }
312
313 pub const fn with_rpc_eth_proof_window(mut self, v: u64) -> Self {
315 self.rpc_eth_proof_window = v;
316 self
317 }
318
319 pub const fn with_rpc_proof_permits(mut self, v: usize) -> Self {
321 self.rpc_proof_permits = v;
322 self
323 }
324
325 pub const fn with_rpc_pending_block(mut self, v: PendingBlockKind) -> Self {
327 self.rpc_pending_block = v;
328 self
329 }
330
331 pub fn with_rpc_forwarder(mut self, v: Option<Url>) -> Self {
333 self.rpc_forwarder = v;
334 self
335 }
336
337 pub fn with_builder_disallow(mut self, v: Option<HashSet<Address>>) -> Self {
339 self.builder_disallow = v;
340 self
341 }
342
343 pub const fn with_rpc_state_cache(mut self, v: RpcStateCacheArgs) -> Self {
345 self.rpc_state_cache = v;
346 self
347 }
348
349 pub const fn with_gas_price_oracle(mut self, v: GasPriceOracleArgs) -> Self {
351 self.gas_price_oracle = v;
352 self
353 }
354
355 pub const fn with_rpc_send_raw_transaction_sync_timeout(mut self, v: Duration) -> Self {
357 self.rpc_send_raw_transaction_sync_timeout = v;
358 self
359 }
360}
361
362impl Default for DefaultRpcServerArgs {
363 fn default() -> Self {
364 Self {
365 http: false,
366 http_addr: Ipv4Addr::LOCALHOST.into(),
367 http_port: constants::DEFAULT_HTTP_RPC_PORT,
368 http_disable_compression: false,
369 http_api: None,
370 http_corsdomain: None,
371 ws: false,
372 ws_addr: Ipv4Addr::LOCALHOST.into(),
373 ws_port: constants::DEFAULT_WS_RPC_PORT,
374 ws_allowed_origins: None,
375 ws_api: None,
376 ipcdisable: false,
377 ipcpath: constants::DEFAULT_IPC_ENDPOINT.to_string(),
378 ipc_socket_permissions: None,
379 auth_addr: Ipv4Addr::LOCALHOST.into(),
380 auth_port: constants::DEFAULT_AUTH_PORT,
381 auth_jwtsecret: None,
382 auth_ipc: false,
383 auth_ipc_path: constants::DEFAULT_ENGINE_API_IPC_ENDPOINT.to_string(),
384 disable_auth_server: false,
385 rpc_jwtsecret: None,
386 rpc_max_request_size: RPC_DEFAULT_MAX_REQUEST_SIZE_MB.into(),
387 rpc_max_response_size: RPC_DEFAULT_MAX_RESPONSE_SIZE_MB.into(),
388 rpc_max_subscriptions_per_connection: RPC_DEFAULT_MAX_SUBS_PER_CONN.into(),
389 rpc_max_connections: RPC_DEFAULT_MAX_CONNECTIONS.into(),
390 rpc_max_tracing_requests: constants::default_max_tracing_requests(),
391 rpc_max_blocking_io_requests: constants::DEFAULT_MAX_BLOCKING_IO_REQUEST,
392 rpc_max_trace_filter_blocks: constants::DEFAULT_MAX_TRACE_FILTER_BLOCKS,
393 rpc_max_blocks_per_filter: constants::DEFAULT_MAX_BLOCKS_PER_FILTER.into(),
394 rpc_max_logs_per_response: (constants::DEFAULT_MAX_LOGS_PER_RESPONSE as u64).into(),
395 rpc_gas_cap: constants::gas_oracle::RPC_DEFAULT_GAS_CAP,
396 rpc_evm_memory_limit: (1 << 32) - 1,
397 rpc_tx_fee_cap: constants::DEFAULT_TX_FEE_CAP_WEI,
398 rpc_max_simulate_blocks: constants::DEFAULT_MAX_SIMULATE_BLOCKS,
399 rpc_eth_proof_window: constants::DEFAULT_ETH_PROOF_WINDOW,
400 rpc_proof_permits: constants::DEFAULT_PROOF_PERMITS,
401 rpc_pending_block: PendingBlockKind::Full,
402 rpc_forwarder: None,
403 builder_disallow: None,
404 rpc_state_cache: RpcStateCacheArgs::default(),
405 gas_price_oracle: GasPriceOracleArgs::default(),
406 rpc_send_raw_transaction_sync_timeout:
407 constants::RPC_DEFAULT_SEND_RAW_TX_SYNC_TIMEOUT_SECS,
408 }
409 }
410}
411
412#[derive(Debug, Clone, Args, PartialEq, Eq)]
414#[command(next_help_heading = "RPC")]
415pub struct RpcServerArgs {
416 #[arg(long, default_value_if("dev", "true", "true"), default_value_t = DefaultRpcServerArgs::get_global().http)]
418 pub http: bool,
419
420 #[arg(long = "http.addr", default_value_t = DefaultRpcServerArgs::get_global().http_addr)]
422 pub http_addr: IpAddr,
423
424 #[arg(long = "http.port", default_value_t = DefaultRpcServerArgs::get_global().http_port)]
426 pub http_port: u16,
427
428 #[arg(long = "http.disable-compression", default_value_t = DefaultRpcServerArgs::get_global().http_disable_compression)]
430 pub http_disable_compression: bool,
431
432 #[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())))]
434 pub http_api: Option<RpcModuleSelection>,
435
436 #[arg(long = "http.corsdomain", default_value = Resettable::from(DefaultRpcServerArgs::get_global().http_corsdomain.as_ref().map(|v| v.to_string().into())))]
438 pub http_corsdomain: Option<String>,
439
440 #[arg(long, default_value_t = DefaultRpcServerArgs::get_global().ws)]
442 pub ws: bool,
443
444 #[arg(long = "ws.addr", default_value_t = DefaultRpcServerArgs::get_global().ws_addr)]
446 pub ws_addr: IpAddr,
447
448 #[arg(long = "ws.port", default_value_t = DefaultRpcServerArgs::get_global().ws_port)]
450 pub ws_port: u16,
451
452 #[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())))]
454 pub ws_allowed_origins: Option<String>,
455
456 #[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())))]
458 pub ws_api: Option<RpcModuleSelection>,
459
460 #[arg(long, default_value_t = DefaultRpcServerArgs::get_global().ipcdisable)]
462 pub ipcdisable: bool,
463
464 #[arg(long, default_value_t = DefaultRpcServerArgs::get_global().ipcpath.clone())]
466 pub ipcpath: String,
467
468 #[arg(long = "ipc.permissions", default_value = Resettable::from(DefaultRpcServerArgs::get_global().ipc_socket_permissions.as_ref().map(|v| v.to_string().into())))]
472 pub ipc_socket_permissions: Option<String>,
473
474 #[arg(long = "authrpc.addr", default_value_t = DefaultRpcServerArgs::get_global().auth_addr)]
476 pub auth_addr: IpAddr,
477
478 #[arg(long = "authrpc.port", default_value_t = DefaultRpcServerArgs::get_global().auth_port)]
480 pub auth_port: u16,
481
482 #[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::<HashSet<Address>>, default_value = Resettable::from(DefaultRpcServerArgs::get_global().builder_disallow.as_ref().map(|v| format!("{:?}", v).into())))]
625 pub builder_disallow: Option<HashSet<Address>>,
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 = false)]
649 pub testing_skip_invalid_transactions: bool,
650}
651
652impl RpcServerArgs {
653 pub const fn with_http(mut self) -> Self {
655 self.http = true;
656 self
657 }
658
659 pub fn with_http_api(mut self, http_api: RpcModuleSelection) -> Self {
661 self.http_api = Some(http_api);
662 self
663 }
664
665 pub const fn with_ws(mut self) -> Self {
667 self.ws = true;
668 self
669 }
670
671 pub fn with_ws_api(mut self, ws_api: RpcModuleSelection) -> Self {
673 self.ws_api = Some(ws_api);
674 self
675 }
676
677 pub const fn with_auth_ipc(mut self) -> Self {
679 self.auth_ipc = true;
680 self
681 }
682
683 pub fn with_api(self, api: RpcModuleSelection) -> Self {
687 self.with_http_api(api.clone()).with_ws_api(api)
688 }
689
690 pub fn adjust_instance_ports(&mut self, instance: Option<u16>) {
705 if let Some(instance) = instance {
706 debug_assert_ne!(instance, 0, "instance must be non-zero");
707 self.auth_port += instance * 100 - 100;
709 self.http_port -= instance - 1;
711 self.ws_port += instance * 2 - 2;
713 self.ipcpath = format!("{}-{}", self.ipcpath, instance);
715 }
716 }
717
718 pub const fn with_http_unused_port(mut self) -> Self {
721 self.http_port = 0;
722 self
723 }
724
725 pub const fn with_ws_unused_port(mut self) -> Self {
728 self.ws_port = 0;
729 self
730 }
731
732 pub const fn with_auth_unused_port(mut self) -> Self {
735 self.auth_port = 0;
736 self
737 }
738
739 pub fn with_ipc_random_path(mut self) -> Self {
742 let random_string: String =
743 rand::rng().sample_iter(rand::distr::Alphanumeric).take(8).map(char::from).collect();
744 self.ipcpath = format!("{}-{}", self.ipcpath, random_string);
745 self
746 }
747
748 pub fn with_unused_ports(mut self) -> Self {
751 self = self.with_http_unused_port();
752 self = self.with_ws_unused_port();
753 self = self.with_auth_unused_port();
754 self = self.with_ipc_random_path();
755 self
756 }
757
758 pub fn apply<F>(self, f: F) -> Self
760 where
761 F: FnOnce(Self) -> Self,
762 {
763 f(self)
764 }
765
766 pub const fn with_send_raw_transaction_sync_timeout(mut self, timeout: Duration) -> Self {
768 self.rpc_send_raw_transaction_sync_timeout = timeout;
769 self
770 }
771}
772
773impl Default for RpcServerArgs {
774 fn default() -> Self {
775 let DefaultRpcServerArgs {
776 http,
777 http_addr,
778 http_port,
779 http_disable_compression,
780 http_api,
781 http_corsdomain,
782 ws,
783 ws_addr,
784 ws_port,
785 ws_allowed_origins,
786 ws_api,
787 ipcdisable,
788 ipcpath,
789 ipc_socket_permissions,
790 auth_addr,
791 auth_port,
792 auth_jwtsecret,
793 auth_ipc,
794 auth_ipc_path,
795 disable_auth_server,
796 rpc_jwtsecret,
797 rpc_max_request_size,
798 rpc_max_response_size,
799 rpc_max_subscriptions_per_connection,
800 rpc_max_connections,
801 rpc_max_tracing_requests,
802 rpc_max_blocking_io_requests,
803 rpc_max_trace_filter_blocks,
804 rpc_max_blocks_per_filter,
805 rpc_max_logs_per_response,
806 rpc_gas_cap,
807 rpc_evm_memory_limit,
808 rpc_tx_fee_cap,
809 rpc_max_simulate_blocks,
810 rpc_eth_proof_window,
811 rpc_proof_permits,
812 rpc_pending_block,
813 rpc_forwarder,
814 builder_disallow,
815 rpc_state_cache,
816 gas_price_oracle,
817 rpc_send_raw_transaction_sync_timeout,
818 } = DefaultRpcServerArgs::get_global().clone();
819 Self {
820 http,
821 http_addr,
822 http_port,
823 http_disable_compression,
824 http_api,
825 http_corsdomain,
826 ws,
827 ws_addr,
828 ws_port,
829 ws_allowed_origins,
830 ws_api,
831 ipcdisable,
832 ipcpath,
833 ipc_socket_permissions,
834 auth_addr,
835 auth_port,
836 auth_jwtsecret,
837 auth_ipc,
838 auth_ipc_path,
839 disable_auth_server,
840 rpc_jwtsecret,
841 rpc_max_request_size,
842 rpc_max_response_size,
843 rpc_max_subscriptions_per_connection,
844 rpc_max_connections,
845 rpc_max_tracing_requests,
846 rpc_max_blocking_io_requests,
847 rpc_max_trace_filter_blocks,
848 rpc_max_blocks_per_filter,
849 rpc_max_logs_per_response,
850 rpc_gas_cap,
851 rpc_evm_memory_limit,
852 rpc_tx_fee_cap,
853 rpc_max_simulate_blocks,
854 rpc_eth_proof_window,
855 rpc_proof_permits,
856 rpc_pending_block,
857 rpc_forwarder,
858 builder_disallow,
859 rpc_state_cache,
860 gas_price_oracle,
861 rpc_send_raw_transaction_sync_timeout,
862 testing_skip_invalid_transactions: false,
863 }
864 }
865}
866
867#[derive(Clone, Debug, Default)]
869#[non_exhaustive]
870struct RpcModuleSelectionValueParser;
871
872impl TypedValueParser for RpcModuleSelectionValueParser {
873 type Value = RpcModuleSelection;
874
875 fn parse_ref(
876 &self,
877 _cmd: &Command,
878 _arg: Option<&Arg>,
879 value: &OsStr,
880 ) -> Result<Self::Value, clap::Error> {
881 let val =
882 value.to_str().ok_or_else(|| clap::Error::new(clap::error::ErrorKind::InvalidUtf8))?;
883 Ok(val
885 .parse::<RpcModuleSelection>()
886 .expect("RpcModuleSelection parsing cannot fail with Other variant"))
887 }
888
889 fn possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>> {
890 let values = RethRpcModule::standard_variant_names().map(PossibleValue::new);
892 Some(Box::new(values))
893 }
894}
895
896#[cfg(test)]
897mod tests {
898 use super::*;
899 use clap::{Args, Parser};
900
901 #[derive(Parser)]
903 struct CommandParser<T: Args> {
904 #[command(flatten)]
905 args: T,
906 }
907
908 #[test]
909 fn test_rpc_server_args_parser() {
910 let args =
911 CommandParser::<RpcServerArgs>::parse_from(["reth", "--http.api", "eth,admin,debug"])
912 .args;
913
914 let apis = args.http_api.unwrap();
915 let expected = RpcModuleSelection::try_from_selection(["eth", "admin", "debug"]).unwrap();
916
917 assert_eq!(apis, expected);
918 }
919
920 #[test]
921 fn test_rpc_server_eth_call_bundle_args() {
922 let args =
923 CommandParser::<RpcServerArgs>::parse_from(["reth", "--http.api", "eth,admin,debug"])
924 .args;
925
926 let apis = args.http_api.unwrap();
927 let expected = RpcModuleSelection::try_from_selection(["eth", "admin", "debug"]).unwrap();
928
929 assert_eq!(apis, expected);
930 }
931
932 #[test]
933 fn test_rpc_server_args_parser_none() {
934 let args = CommandParser::<RpcServerArgs>::parse_from(["reth", "--http.api", "none"]).args;
935 let apis = args.http_api.unwrap();
936 let expected = RpcModuleSelection::Selection(Default::default());
937 assert_eq!(apis, expected);
938 }
939
940 #[test]
941 fn rpc_server_args_default_sanity_test() {
942 let default_args = RpcServerArgs::default();
943 let args = CommandParser::<RpcServerArgs>::parse_from(["reth"]).args;
944
945 assert_eq!(args, default_args);
946 }
947
948 #[test]
949 fn test_rpc_tx_fee_cap_parse_integer() {
950 let args = CommandParser::<RpcServerArgs>::parse_from(["reth", "--rpc.txfeecap", "2"]).args;
951 let expected = 2_000_000_000_000_000_000u128; assert_eq!(args.rpc_tx_fee_cap, expected);
953 }
954
955 #[test]
956 fn test_rpc_tx_fee_cap_parse_decimal() {
957 let args =
958 CommandParser::<RpcServerArgs>::parse_from(["reth", "--rpc.txfeecap", "1.5"]).args;
959 let expected = 1_500_000_000_000_000_000u128; assert_eq!(args.rpc_tx_fee_cap, expected);
961 }
962
963 #[test]
964 fn test_rpc_tx_fee_cap_parse_zero() {
965 let args = CommandParser::<RpcServerArgs>::parse_from(["reth", "--rpc.txfeecap", "0"]).args;
966 assert_eq!(args.rpc_tx_fee_cap, 0); }
968
969 #[test]
970 fn test_rpc_tx_fee_cap_parse_none() {
971 let args = CommandParser::<RpcServerArgs>::parse_from(["reth"]).args;
972 let expected = 1_000_000_000_000_000_000u128;
973 assert_eq!(args.rpc_tx_fee_cap, expected); }
975
976 #[test]
977 fn test_rpc_server_args() {
978 let args = RpcServerArgs {
979 http: true,
980 http_addr: "127.0.0.1".parse().unwrap(),
981 http_port: 8545,
982 http_disable_compression: false,
983 http_api: Some(RpcModuleSelection::try_from_selection(["eth", "admin"]).unwrap()),
984 http_corsdomain: Some("*".to_string()),
985 ws: true,
986 ws_addr: "127.0.0.1".parse().unwrap(),
987 ws_port: 8546,
988 ws_allowed_origins: Some("*".to_string()),
989 ws_api: Some(RpcModuleSelection::try_from_selection(["eth", "admin"]).unwrap()),
990 ipcdisable: false,
991 ipcpath: "reth.ipc".to_string(),
992 ipc_socket_permissions: Some("0o666".to_string()),
993 auth_addr: "127.0.0.1".parse().unwrap(),
994 auth_port: 8551,
995 auth_jwtsecret: Some(std::path::PathBuf::from("/tmp/jwt.hex")),
996 auth_ipc: false,
997 auth_ipc_path: "engine.ipc".to_string(),
998 disable_auth_server: false,
999 rpc_jwtsecret: Some(
1000 JwtSecret::from_hex(
1001 "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
1002 )
1003 .unwrap(),
1004 ),
1005 rpc_max_request_size: 15u32.into(),
1006 rpc_max_response_size: 160u32.into(),
1007 rpc_max_subscriptions_per_connection: 1024u32.into(),
1008 rpc_max_connections: 500u32.into(),
1009 rpc_max_tracing_requests: 16,
1010 rpc_max_blocking_io_requests: 256,
1011 rpc_max_trace_filter_blocks: 4000,
1012 rpc_max_blocks_per_filter: 1000u64.into(),
1013 rpc_max_logs_per_response: 10000u64.into(),
1014 rpc_gas_cap: 50_000_000,
1015 rpc_evm_memory_limit: 256,
1016 rpc_tx_fee_cap: 2_000_000_000_000_000_000u128,
1017 rpc_max_simulate_blocks: 256,
1018 rpc_eth_proof_window: 100_000,
1019 rpc_proof_permits: 16,
1020 rpc_pending_block: PendingBlockKind::Full,
1021 rpc_forwarder: Some("http://localhost:8545".parse().unwrap()),
1022 builder_disallow: None,
1023 rpc_state_cache: RpcStateCacheArgs {
1024 max_blocks: 5000,
1025 max_receipts: 2000,
1026 max_headers: 1000,
1027 max_concurrent_db_requests: 512,
1028 },
1029 gas_price_oracle: GasPriceOracleArgs {
1030 blocks: 20,
1031 ignore_price: 2,
1032 max_price: 500_000_000_000,
1033 percentile: 60,
1034 default_suggested_fee: None,
1035 },
1036 rpc_send_raw_transaction_sync_timeout: std::time::Duration::from_secs(30),
1037 testing_skip_invalid_transactions: true,
1038 };
1039
1040 let parsed_args = CommandParser::<RpcServerArgs>::parse_from([
1041 "reth",
1042 "--http",
1043 "--http.addr",
1044 "127.0.0.1",
1045 "--http.port",
1046 "8545",
1047 "--http.api",
1048 "eth,admin",
1049 "--http.corsdomain",
1050 "*",
1051 "--ws",
1052 "--ws.addr",
1053 "127.0.0.1",
1054 "--ws.port",
1055 "8546",
1056 "--ws.origins",
1057 "*",
1058 "--ws.api",
1059 "eth,admin",
1060 "--ipcpath",
1061 "reth.ipc",
1062 "--ipc.permissions",
1063 "0o666",
1064 "--authrpc.addr",
1065 "127.0.0.1",
1066 "--authrpc.port",
1067 "8551",
1068 "--authrpc.jwtsecret",
1069 "/tmp/jwt.hex",
1070 "--auth-ipc.path",
1071 "engine.ipc",
1072 "--rpc.jwtsecret",
1073 "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
1074 "--rpc.max-request-size",
1075 "15",
1076 "--rpc.max-response-size",
1077 "160",
1078 "--rpc.max-subscriptions-per-connection",
1079 "1024",
1080 "--rpc.max-connections",
1081 "500",
1082 "--rpc.max-tracing-requests",
1083 "16",
1084 "--rpc.max-blocking-io-requests",
1085 "256",
1086 "--rpc.max-trace-filter-blocks",
1087 "4000",
1088 "--rpc.max-blocks-per-filter",
1089 "1000",
1090 "--rpc.max-logs-per-response",
1091 "10000",
1092 "--rpc.gascap",
1093 "50000000",
1094 "--rpc.evm-memory-limit",
1095 "256",
1096 "--rpc.txfeecap",
1097 "2.0",
1098 "--rpc.max-simulate-blocks",
1099 "256",
1100 "--rpc.eth-proof-window",
1101 "100000",
1102 "--rpc.proof-permits",
1103 "16",
1104 "--rpc.pending-block",
1105 "full",
1106 "--rpc.forwarder",
1107 "http://localhost:8545",
1108 "--rpc-cache.max-blocks",
1109 "5000",
1110 "--rpc-cache.max-receipts",
1111 "2000",
1112 "--rpc-cache.max-headers",
1113 "1000",
1114 "--rpc-cache.max-concurrent-db-requests",
1115 "512",
1116 "--gpo.blocks",
1117 "20",
1118 "--gpo.ignoreprice",
1119 "2",
1120 "--gpo.maxprice",
1121 "500000000000",
1122 "--gpo.percentile",
1123 "60",
1124 "--rpc.send-raw-transaction-sync-timeout",
1125 "30s",
1126 "--testing.skip-invalid-transactions",
1127 ])
1128 .args;
1129
1130 assert_eq!(parsed_args, args);
1131 }
1132}