diff --git a/crates/node/core/src/args/mod.rs b/crates/node/core/src/args/mod.rs index 0ef393eec3..0251c5256d 100644 --- a/crates/node/core/src/args/mod.rs +++ b/crates/node/core/src/args/mod.rs @@ -6,7 +6,7 @@ pub use network::{DiscoveryArgs, NetworkArgs}; /// RpcServerArg struct for configuring the RPC mod rpc_server; -pub use rpc_server::RpcServerArgs; +pub use rpc_server::{DefaultRpcServerArgs, RpcServerArgs}; /// `RpcStateCacheArgs` struct for configuring RPC state cache mod rpc_state_cache; diff --git a/crates/node/core/src/args/rpc_server.rs b/crates/node/core/src/args/rpc_server.rs index 175cf7cad7..4d73abf7ad 100644 --- a/crates/node/core/src/args/rpc_server.rs +++ b/crates/node/core/src/args/rpc_server.rs @@ -7,7 +7,7 @@ use crate::args::{ use alloy_primitives::Address; use alloy_rpc_types_engine::JwtSecret; use clap::{ - builder::{PossibleValue, RangedU64ValueParser, TypedValueParser}, + builder::{PossibleValue, RangedU64ValueParser, Resettable, TypedValueParser}, Arg, Args, Command, }; use rand::Rng; @@ -19,12 +19,16 @@ use std::{ ffi::OsStr, net::{IpAddr, Ipv4Addr}, path::PathBuf, + sync::OnceLock, time::Duration, }; use url::Url; use super::types::MaxOr; +/// Global static RPC server defaults +static RPC_SERVER_DEFAULTS: OnceLock = OnceLock::new(); + /// Default max number of subscriptions per connection. pub(crate) const RPC_DEFAULT_MAX_SUBS_PER_CONN: u32 = 1024; @@ -42,74 +46,437 @@ pub(crate) const RPC_DEFAULT_MAX_RESPONSE_SIZE_MB: u32 = 160; /// Once exceeded, the server can reject new connections. pub(crate) const RPC_DEFAULT_MAX_CONNECTIONS: u32 = 500; +/// Default values for RPC server that can be customized +/// +/// Global defaults can be set via [`DefaultRpcServerArgs::try_init`]. +#[derive(Debug, Clone)] +pub struct DefaultRpcServerArgs { + http: bool, + http_addr: IpAddr, + http_port: u16, + http_disable_compression: bool, + http_api: Option, + http_corsdomain: Option, + ws: bool, + ws_addr: IpAddr, + ws_port: u16, + ws_allowed_origins: Option, + ws_api: Option, + ipcdisable: bool, + ipcpath: String, + ipc_socket_permissions: Option, + auth_addr: IpAddr, + auth_port: u16, + auth_jwtsecret: Option, + auth_ipc: bool, + auth_ipc_path: String, + disable_auth_server: bool, + rpc_jwtsecret: Option, + rpc_max_request_size: MaxU32, + rpc_max_response_size: MaxU32, + rpc_max_subscriptions_per_connection: MaxU32, + rpc_max_connections: MaxU32, + rpc_max_tracing_requests: usize, + rpc_max_blocking_io_requests: usize, + rpc_max_trace_filter_blocks: u64, + rpc_max_blocks_per_filter: ZeroAsNoneU64, + rpc_max_logs_per_response: ZeroAsNoneU64, + rpc_gas_cap: u64, + rpc_evm_memory_limit: u64, + rpc_tx_fee_cap: u128, + rpc_max_simulate_blocks: u64, + rpc_eth_proof_window: u64, + rpc_proof_permits: usize, + rpc_pending_block: PendingBlockKind, + rpc_forwarder: Option, + builder_disallow: Option>, + rpc_state_cache: RpcStateCacheArgs, + gas_price_oracle: GasPriceOracleArgs, + rpc_send_raw_transaction_sync_timeout: Duration, +} + +impl DefaultRpcServerArgs { + /// Initialize the global RPC server defaults with this configuration + pub fn try_init(self) -> Result<(), Self> { + RPC_SERVER_DEFAULTS.set(self) + } + + /// Get a reference to the global RPC server defaults + pub fn get_global() -> &'static Self { + RPC_SERVER_DEFAULTS.get_or_init(Self::default) + } + + /// Set the default HTTP enabled state + pub const fn with_http(mut self, v: bool) -> Self { + self.http = v; + self + } + + /// Set the default HTTP address + pub const fn with_http_addr(mut self, v: IpAddr) -> Self { + self.http_addr = v; + self + } + + /// Set the default HTTP port + pub const fn with_http_port(mut self, v: u16) -> Self { + self.http_port = v; + self + } + + /// Set whether to disable HTTP compression by default + pub const fn with_http_disable_compression(mut self, v: bool) -> Self { + self.http_disable_compression = v; + self + } + + /// Set the default HTTP API modules + pub fn with_http_api(mut self, v: Option) -> Self { + self.http_api = v; + self + } + + /// Set the default HTTP CORS domain + pub fn with_http_corsdomain(mut self, v: Option) -> Self { + self.http_corsdomain = v; + self + } + + /// Set the default WS enabled state + pub const fn with_ws(mut self, v: bool) -> Self { + self.ws = v; + self + } + + /// Set the default WS address + pub const fn with_ws_addr(mut self, v: IpAddr) -> Self { + self.ws_addr = v; + self + } + + /// Set the default WS port + pub const fn with_ws_port(mut self, v: u16) -> Self { + self.ws_port = v; + self + } + + /// Set the default WS allowed origins + pub fn with_ws_allowed_origins(mut self, v: Option) -> Self { + self.ws_allowed_origins = v; + self + } + + /// Set the default WS API modules + pub fn with_ws_api(mut self, v: Option) -> Self { + self.ws_api = v; + self + } + + /// Set whether to disable IPC by default + pub const fn with_ipcdisable(mut self, v: bool) -> Self { + self.ipcdisable = v; + self + } + + /// Set the default IPC path + pub fn with_ipcpath(mut self, v: String) -> Self { + self.ipcpath = v; + self + } + + /// Set the default IPC socket permissions + pub fn with_ipc_socket_permissions(mut self, v: Option) -> Self { + self.ipc_socket_permissions = v; + self + } + + /// Set the default auth server address + pub const fn with_auth_addr(mut self, v: IpAddr) -> Self { + self.auth_addr = v; + self + } + + /// Set the default auth server port + pub const fn with_auth_port(mut self, v: u16) -> Self { + self.auth_port = v; + self + } + + /// Set the default auth JWT secret path + pub fn with_auth_jwtsecret(mut self, v: Option) -> Self { + self.auth_jwtsecret = v; + self + } + + /// Set the default auth IPC enabled state + pub const fn with_auth_ipc(mut self, v: bool) -> Self { + self.auth_ipc = v; + self + } + + /// Set the default auth IPC path + pub fn with_auth_ipc_path(mut self, v: String) -> Self { + self.auth_ipc_path = v; + self + } + + /// Set whether to disable the auth server by default + pub const fn with_disable_auth_server(mut self, v: bool) -> Self { + self.disable_auth_server = v; + self + } + + /// Set the default RPC JWT secret + pub const fn with_rpc_jwtsecret(mut self, v: Option) -> Self { + self.rpc_jwtsecret = v; + self + } + + /// Set the default max request size + pub const fn with_rpc_max_request_size(mut self, v: MaxU32) -> Self { + self.rpc_max_request_size = v; + self + } + + /// Set the default max response size + pub const fn with_rpc_max_response_size(mut self, v: MaxU32) -> Self { + self.rpc_max_response_size = v; + self + } + + /// Set the default max subscriptions per connection + pub const fn with_rpc_max_subscriptions_per_connection(mut self, v: MaxU32) -> Self { + self.rpc_max_subscriptions_per_connection = v; + self + } + + /// Set the default max connections + pub const fn with_rpc_max_connections(mut self, v: MaxU32) -> Self { + self.rpc_max_connections = v; + self + } + + /// Set the default max tracing requests + pub const fn with_rpc_max_tracing_requests(mut self, v: usize) -> Self { + self.rpc_max_tracing_requests = v; + self + } + + /// Set the default max blocking IO requests + pub const fn with_rpc_max_blocking_io_requests(mut self, v: usize) -> Self { + self.rpc_max_blocking_io_requests = v; + self + } + + /// Set the default max trace filter blocks + pub const fn with_rpc_max_trace_filter_blocks(mut self, v: u64) -> Self { + self.rpc_max_trace_filter_blocks = v; + self + } + + /// Set the default max blocks per filter + pub const fn with_rpc_max_blocks_per_filter(mut self, v: ZeroAsNoneU64) -> Self { + self.rpc_max_blocks_per_filter = v; + self + } + + /// Set the default max logs per response + pub const fn with_rpc_max_logs_per_response(mut self, v: ZeroAsNoneU64) -> Self { + self.rpc_max_logs_per_response = v; + self + } + + /// Set the default gas cap + pub const fn with_rpc_gas_cap(mut self, v: u64) -> Self { + self.rpc_gas_cap = v; + self + } + + /// Set the default EVM memory limit + pub const fn with_rpc_evm_memory_limit(mut self, v: u64) -> Self { + self.rpc_evm_memory_limit = v; + self + } + + /// Set the default tx fee cap + pub const fn with_rpc_tx_fee_cap(mut self, v: u128) -> Self { + self.rpc_tx_fee_cap = v; + self + } + + /// Set the default max simulate blocks + pub const fn with_rpc_max_simulate_blocks(mut self, v: u64) -> Self { + self.rpc_max_simulate_blocks = v; + self + } + + /// Set the default eth proof window + pub const fn with_rpc_eth_proof_window(mut self, v: u64) -> Self { + self.rpc_eth_proof_window = v; + self + } + + /// Set the default proof permits + pub const fn with_rpc_proof_permits(mut self, v: usize) -> Self { + self.rpc_proof_permits = v; + self + } + + /// Set the default pending block kind + pub const fn with_rpc_pending_block(mut self, v: PendingBlockKind) -> Self { + self.rpc_pending_block = v; + self + } + + /// Set the default RPC forwarder + pub fn with_rpc_forwarder(mut self, v: Option) -> Self { + self.rpc_forwarder = v; + self + } + + /// Set the default builder disallow addresses + pub fn with_builder_disallow(mut self, v: Option>) -> Self { + self.builder_disallow = v; + self + } + + /// Set the default RPC state cache args + pub const fn with_rpc_state_cache(mut self, v: RpcStateCacheArgs) -> Self { + self.rpc_state_cache = v; + self + } + + /// Set the default gas price oracle args + pub const fn with_gas_price_oracle(mut self, v: GasPriceOracleArgs) -> Self { + self.gas_price_oracle = v; + self + } + + /// Set the default send raw transaction sync timeout + pub const fn with_rpc_send_raw_transaction_sync_timeout(mut self, v: Duration) -> Self { + self.rpc_send_raw_transaction_sync_timeout = v; + self + } +} + +impl Default for DefaultRpcServerArgs { + fn default() -> Self { + Self { + http: false, + http_addr: Ipv4Addr::LOCALHOST.into(), + http_port: constants::DEFAULT_HTTP_RPC_PORT, + http_disable_compression: false, + http_api: None, + http_corsdomain: None, + ws: false, + ws_addr: Ipv4Addr::LOCALHOST.into(), + ws_port: constants::DEFAULT_WS_RPC_PORT, + ws_allowed_origins: None, + ws_api: None, + ipcdisable: false, + ipcpath: constants::DEFAULT_IPC_ENDPOINT.to_string(), + ipc_socket_permissions: None, + auth_addr: Ipv4Addr::LOCALHOST.into(), + auth_port: constants::DEFAULT_AUTH_PORT, + auth_jwtsecret: None, + auth_ipc: false, + auth_ipc_path: constants::DEFAULT_ENGINE_API_IPC_ENDPOINT.to_string(), + disable_auth_server: false, + rpc_jwtsecret: None, + rpc_max_request_size: RPC_DEFAULT_MAX_REQUEST_SIZE_MB.into(), + rpc_max_response_size: RPC_DEFAULT_MAX_RESPONSE_SIZE_MB.into(), + rpc_max_subscriptions_per_connection: RPC_DEFAULT_MAX_SUBS_PER_CONN.into(), + rpc_max_connections: RPC_DEFAULT_MAX_CONNECTIONS.into(), + rpc_max_tracing_requests: constants::default_max_tracing_requests(), + rpc_max_blocking_io_requests: constants::DEFAULT_MAX_BLOCKING_IO_REQUEST, + rpc_max_trace_filter_blocks: constants::DEFAULT_MAX_TRACE_FILTER_BLOCKS, + rpc_max_blocks_per_filter: constants::DEFAULT_MAX_BLOCKS_PER_FILTER.into(), + rpc_max_logs_per_response: (constants::DEFAULT_MAX_LOGS_PER_RESPONSE as u64).into(), + rpc_gas_cap: constants::gas_oracle::RPC_DEFAULT_GAS_CAP, + rpc_evm_memory_limit: (1 << 32) - 1, + rpc_tx_fee_cap: constants::DEFAULT_TX_FEE_CAP_WEI, + rpc_max_simulate_blocks: constants::DEFAULT_MAX_SIMULATE_BLOCKS, + rpc_eth_proof_window: constants::DEFAULT_ETH_PROOF_WINDOW, + rpc_proof_permits: constants::DEFAULT_PROOF_PERMITS, + rpc_pending_block: PendingBlockKind::Full, + rpc_forwarder: None, + builder_disallow: None, + rpc_state_cache: RpcStateCacheArgs::default(), + gas_price_oracle: GasPriceOracleArgs::default(), + rpc_send_raw_transaction_sync_timeout: + constants::RPC_DEFAULT_SEND_RAW_TX_SYNC_TIMEOUT_SECS, + } + } +} + /// Parameters for configuring the rpc more granularity via CLI #[derive(Debug, Clone, Args, PartialEq, Eq)] #[command(next_help_heading = "RPC")] pub struct RpcServerArgs { /// Enable the HTTP-RPC server - #[arg(long, default_value_if("dev", "true", "true"))] + #[arg(long, default_value_if("dev", "true", "true"), default_value_t = DefaultRpcServerArgs::get_global().http)] pub http: bool, /// Http server address to listen on - #[arg(long = "http.addr", default_value_t = IpAddr::V4(Ipv4Addr::LOCALHOST))] + #[arg(long = "http.addr", default_value_t = DefaultRpcServerArgs::get_global().http_addr)] pub http_addr: IpAddr, /// Http server port to listen on - #[arg(long = "http.port", default_value_t = constants::DEFAULT_HTTP_RPC_PORT)] + #[arg(long = "http.port", default_value_t = DefaultRpcServerArgs::get_global().http_port)] pub http_port: u16, /// Disable compression for HTTP responses - #[arg(long = "http.disable-compression", default_value_t = false)] + #[arg(long = "http.disable-compression", default_value_t = DefaultRpcServerArgs::get_global().http_disable_compression)] pub http_disable_compression: bool, /// Rpc Modules to be configured for the HTTP server - #[arg(long = "http.api", value_parser = RpcModuleSelectionValueParser::default())] + #[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())))] pub http_api: Option, /// Http Corsdomain to allow request from - #[arg(long = "http.corsdomain")] + #[arg(long = "http.corsdomain", default_value = Resettable::from(DefaultRpcServerArgs::get_global().http_corsdomain.as_ref().map(|v| v.to_string().into())))] pub http_corsdomain: Option, /// Enable the WS-RPC server - #[arg(long)] + #[arg(long, default_value_t = DefaultRpcServerArgs::get_global().ws)] pub ws: bool, /// Ws server address to listen on - #[arg(long = "ws.addr", default_value_t = IpAddr::V4(Ipv4Addr::LOCALHOST))] + #[arg(long = "ws.addr", default_value_t = DefaultRpcServerArgs::get_global().ws_addr)] pub ws_addr: IpAddr, /// Ws server port to listen on - #[arg(long = "ws.port", default_value_t = constants::DEFAULT_WS_RPC_PORT)] + #[arg(long = "ws.port", default_value_t = DefaultRpcServerArgs::get_global().ws_port)] pub ws_port: u16, /// Origins from which to accept `WebSocket` requests - #[arg(id = "ws.origins", long = "ws.origins", alias = "ws.corsdomain")] + #[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())))] pub ws_allowed_origins: Option, /// Rpc Modules to be configured for the WS server - #[arg(long = "ws.api", value_parser = RpcModuleSelectionValueParser::default())] + #[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())))] pub ws_api: Option, /// Disable the IPC-RPC server - #[arg(long)] + #[arg(long, default_value_t = DefaultRpcServerArgs::get_global().ipcdisable)] pub ipcdisable: bool, /// Filename for IPC socket/pipe within the datadir - #[arg(long, default_value_t = constants::DEFAULT_IPC_ENDPOINT.to_string())] + #[arg(long, default_value_t = DefaultRpcServerArgs::get_global().ipcpath.clone())] pub ipcpath: String, /// Set the permissions for the IPC socket file, in octal format. /// /// If not specified, the permissions will be set by the system's umask. - #[arg(long = "ipc.permissions")] + #[arg(long = "ipc.permissions", default_value = Resettable::from(DefaultRpcServerArgs::get_global().ipc_socket_permissions.as_ref().map(|v| v.to_string().into())))] pub ipc_socket_permissions: Option, /// Auth server address to listen on - #[arg(long = "authrpc.addr", default_value_t = IpAddr::V4(Ipv4Addr::LOCALHOST))] + #[arg(long = "authrpc.addr", default_value_t = DefaultRpcServerArgs::get_global().auth_addr)] pub auth_addr: IpAddr, /// Auth server port to listen on - #[arg(long = "authrpc.port", default_value_t = constants::DEFAULT_AUTH_PORT)] + #[arg(long = "authrpc.port", default_value_t = DefaultRpcServerArgs::get_global().auth_port)] pub auth_port: u16, /// Path to a JWT secret to use for the authenticated engine-API RPC server. @@ -118,22 +485,22 @@ pub struct RpcServerArgs { /// /// If no path is provided, a secret will be generated and stored in the datadir under /// `//jwt.hex`. For mainnet this would be `~/.reth/mainnet/jwt.hex` by default. - #[arg(long = "authrpc.jwtsecret", value_name = "PATH", global = true, required = false)] + #[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())))] pub auth_jwtsecret: Option, /// Enable auth engine API over IPC - #[arg(long)] + #[arg(long, default_value_t = DefaultRpcServerArgs::get_global().auth_ipc)] pub auth_ipc: bool, /// Filename for auth IPC socket/pipe within the datadir - #[arg(long = "auth-ipc.path", default_value_t = constants::DEFAULT_ENGINE_API_IPC_ENDPOINT.to_string())] + #[arg(long = "auth-ipc.path", default_value_t = DefaultRpcServerArgs::get_global().auth_ipc_path.clone())] pub auth_ipc_path: String, /// Disable the auth/engine API server. /// /// This will prevent the authenticated engine-API server from starting. Use this if you're /// running a node that doesn't need to serve engine API requests. - #[arg(long = "disable-auth-server", alias = "disable-engine-api")] + #[arg(long = "disable-auth-server", alias = "disable-engine-api", default_value_t = DefaultRpcServerArgs::get_global().disable_auth_server)] pub disable_auth_server: bool, /// Hex encoded JWT secret to authenticate the regular RPC server(s), see `--http.api` and @@ -141,23 +508,23 @@ pub struct RpcServerArgs { /// /// This is __not__ used for the authenticated engine-API RPC server, see /// `--authrpc.jwtsecret`. - #[arg(long = "rpc.jwtsecret", value_name = "HEX", global = true, required = false)] + #[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())))] pub rpc_jwtsecret: Option, /// Set the maximum RPC request payload size for both HTTP and WS in megabytes. - #[arg(long = "rpc.max-request-size", alias = "rpc-max-request-size", default_value_t = RPC_DEFAULT_MAX_REQUEST_SIZE_MB.into())] + #[arg(long = "rpc.max-request-size", alias = "rpc-max-request-size", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_request_size)] pub rpc_max_request_size: MaxU32, /// Set the maximum RPC response payload size for both HTTP and WS in megabytes. - #[arg(long = "rpc.max-response-size", alias = "rpc-max-response-size", visible_alias = "rpc.returndata.limit", default_value_t = RPC_DEFAULT_MAX_RESPONSE_SIZE_MB.into())] + #[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)] pub rpc_max_response_size: MaxU32, /// Set the maximum concurrent subscriptions per connection. - #[arg(long = "rpc.max-subscriptions-per-connection", alias = "rpc-max-subscriptions-per-connection", default_value_t = RPC_DEFAULT_MAX_SUBS_PER_CONN.into())] + #[arg(long = "rpc.max-subscriptions-per-connection", alias = "rpc-max-subscriptions-per-connection", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_subscriptions_per_connection)] pub rpc_max_subscriptions_per_connection: MaxU32, /// Maximum number of RPC server connections. - #[arg(long = "rpc.max-connections", alias = "rpc-max-connections", value_name = "COUNT", default_value_t = RPC_DEFAULT_MAX_CONNECTIONS.into())] + #[arg(long = "rpc.max-connections", alias = "rpc-max-connections", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_connections)] pub rpc_max_connections: MaxU32, /// Maximum number of concurrent tracing requests. @@ -166,7 +533,7 @@ pub struct RpcServerArgs { /// Tracing requests are generally CPU bound. /// Choosing a value that is higher than the available CPU cores can have a negative impact on /// the performance of the node and affect the node's ability to maintain sync. - #[arg(long = "rpc.max-tracing-requests", alias = "rpc-max-tracing-requests", value_name = "COUNT", default_value_t = constants::default_max_tracing_requests())] + #[arg(long = "rpc.max-tracing-requests", alias = "rpc-max-tracing-requests", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_tracing_requests)] pub rpc_max_tracing_requests: usize, /// Maximum number of concurrent blocking IO requests. @@ -174,19 +541,19 @@ pub struct RpcServerArgs { /// Blocking IO requests include `eth_call`, `eth_estimateGas`, and similar methods that /// require EVM execution. These are spawned as blocking tasks to avoid blocking the async /// runtime. - #[arg(long = "rpc.max-blocking-io-requests", alias = "rpc-max-blocking-io-requests", value_name = "COUNT", default_value_t = constants::DEFAULT_MAX_BLOCKING_IO_REQUEST)] + #[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)] pub rpc_max_blocking_io_requests: usize, /// Maximum number of blocks for `trace_filter` requests. - #[arg(long = "rpc.max-trace-filter-blocks", alias = "rpc-max-trace-filter-blocks", value_name = "COUNT", default_value_t = constants::DEFAULT_MAX_TRACE_FILTER_BLOCKS)] + #[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)] pub rpc_max_trace_filter_blocks: u64, /// Maximum number of blocks that could be scanned per filter request. (0 = entire chain) - #[arg(long = "rpc.max-blocks-per-filter", alias = "rpc-max-blocks-per-filter", value_name = "COUNT", default_value_t = ZeroAsNoneU64::new(constants::DEFAULT_MAX_BLOCKS_PER_FILTER))] + #[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)] pub rpc_max_blocks_per_filter: ZeroAsNoneU64, /// Maximum number of logs that can be returned in a single response. (0 = no limit) - #[arg(long = "rpc.max-logs-per-response", alias = "rpc-max-logs-per-response", value_name = "COUNT", default_value_t = ZeroAsNoneU64::new(constants::DEFAULT_MAX_LOGS_PER_RESPONSE as u64))] + #[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)] pub rpc_max_logs_per_response: ZeroAsNoneU64, /// Maximum gas limit for `eth_call` and call tracing RPC methods. @@ -195,7 +562,7 @@ pub struct RpcServerArgs { alias = "rpc-gascap", value_name = "GAS_CAP", value_parser = MaxOr::new(RangedU64ValueParser::::new().range(1..)), - default_value_t = constants::gas_oracle::RPC_DEFAULT_GAS_CAP + default_value_t = DefaultRpcServerArgs::get_global().rpc_gas_cap )] pub rpc_gas_cap: u64, @@ -205,7 +572,7 @@ pub struct RpcServerArgs { alias = "rpc-evm-memory-limit", value_name = "MEMORY_LIMIT", value_parser = MaxOr::new(RangedU64ValueParser::::new().range(1..)), - default_value_t = (1 << 32) - 1 + default_value_t = DefaultRpcServerArgs::get_global().rpc_evm_memory_limit )] pub rpc_evm_memory_limit: u64, @@ -223,7 +590,7 @@ pub struct RpcServerArgs { #[arg( long = "rpc.max-simulate-blocks", value_name = "BLOCKS_COUNT", - default_value_t = constants::DEFAULT_MAX_SIMULATE_BLOCKS + default_value_t = DefaultRpcServerArgs::get_global().rpc_max_simulate_blocks )] pub rpc_max_simulate_blocks: u64, @@ -232,7 +599,7 @@ pub struct RpcServerArgs { /// configured number of blocks from current tip (up to `tip - window`). #[arg( long = "rpc.eth-proof-window", - default_value_t = constants::DEFAULT_ETH_PROOF_WINDOW, + default_value_t = DefaultRpcServerArgs::get_global().rpc_eth_proof_window, value_parser = RangedU64ValueParser::::new().range(..=constants::MAX_ETH_PROOF_WINDOW) )] pub rpc_eth_proof_window: u64, @@ -254,7 +621,7 @@ pub struct RpcServerArgs { /// Path to file containing disallowed addresses, json-encoded list of strings. Block /// validation API will reject blocks containing transactions from these addresses. - #[arg(long = "builder.disallow", value_name = "PATH", value_parser = reth_cli_util::parsers::read_json_from_file::>)] + #[arg(long = "builder.disallow", value_name = "PATH", value_parser = reth_cli_util::parsers::read_json_from_file::>, default_value = Resettable::from(DefaultRpcServerArgs::get_global().builder_disallow.as_ref().map(|v| format!("{:?}", v).into())))] pub builder_disallow: Option>, /// State cache configuration. @@ -398,50 +765,93 @@ impl RpcServerArgs { impl Default for RpcServerArgs { fn default() -> Self { + let DefaultRpcServerArgs { + http, + http_addr, + http_port, + http_disable_compression, + http_api, + http_corsdomain, + ws, + ws_addr, + ws_port, + ws_allowed_origins, + ws_api, + ipcdisable, + ipcpath, + ipc_socket_permissions, + auth_addr, + auth_port, + auth_jwtsecret, + auth_ipc, + auth_ipc_path, + disable_auth_server, + rpc_jwtsecret, + rpc_max_request_size, + rpc_max_response_size, + rpc_max_subscriptions_per_connection, + rpc_max_connections, + rpc_max_tracing_requests, + rpc_max_blocking_io_requests, + rpc_max_trace_filter_blocks, + rpc_max_blocks_per_filter, + rpc_max_logs_per_response, + rpc_gas_cap, + rpc_evm_memory_limit, + rpc_tx_fee_cap, + rpc_max_simulate_blocks, + rpc_eth_proof_window, + rpc_proof_permits, + rpc_pending_block, + rpc_forwarder, + builder_disallow, + rpc_state_cache, + gas_price_oracle, + rpc_send_raw_transaction_sync_timeout, + } = DefaultRpcServerArgs::get_global().clone(); Self { - http: false, - http_addr: Ipv4Addr::LOCALHOST.into(), - http_port: constants::DEFAULT_HTTP_RPC_PORT, - http_disable_compression: false, - http_api: None, - http_corsdomain: None, - ws: false, - ws_addr: Ipv4Addr::LOCALHOST.into(), - ws_port: constants::DEFAULT_WS_RPC_PORT, - ws_allowed_origins: None, - ws_api: None, - ipcdisable: false, - ipcpath: constants::DEFAULT_IPC_ENDPOINT.to_string(), - ipc_socket_permissions: None, - auth_addr: Ipv4Addr::LOCALHOST.into(), - auth_port: constants::DEFAULT_AUTH_PORT, - auth_jwtsecret: None, - auth_ipc: false, - auth_ipc_path: constants::DEFAULT_ENGINE_API_IPC_ENDPOINT.to_string(), - disable_auth_server: false, - rpc_jwtsecret: None, - rpc_max_request_size: RPC_DEFAULT_MAX_REQUEST_SIZE_MB.into(), - rpc_max_response_size: RPC_DEFAULT_MAX_RESPONSE_SIZE_MB.into(), - rpc_max_subscriptions_per_connection: RPC_DEFAULT_MAX_SUBS_PER_CONN.into(), - rpc_max_connections: RPC_DEFAULT_MAX_CONNECTIONS.into(), - rpc_max_tracing_requests: constants::default_max_tracing_requests(), - rpc_max_blocking_io_requests: constants::DEFAULT_MAX_BLOCKING_IO_REQUEST, - rpc_max_trace_filter_blocks: constants::DEFAULT_MAX_TRACE_FILTER_BLOCKS, - rpc_max_blocks_per_filter: constants::DEFAULT_MAX_BLOCKS_PER_FILTER.into(), - rpc_max_logs_per_response: (constants::DEFAULT_MAX_LOGS_PER_RESPONSE as u64).into(), - rpc_gas_cap: constants::gas_oracle::RPC_DEFAULT_GAS_CAP, - rpc_evm_memory_limit: (1 << 32) - 1, - rpc_tx_fee_cap: constants::DEFAULT_TX_FEE_CAP_WEI, - rpc_max_simulate_blocks: constants::DEFAULT_MAX_SIMULATE_BLOCKS, - rpc_eth_proof_window: constants::DEFAULT_ETH_PROOF_WINDOW, - rpc_pending_block: PendingBlockKind::Full, - gas_price_oracle: GasPriceOracleArgs::default(), - rpc_state_cache: RpcStateCacheArgs::default(), - rpc_proof_permits: constants::DEFAULT_PROOF_PERMITS, - rpc_forwarder: None, - builder_disallow: Default::default(), - rpc_send_raw_transaction_sync_timeout: - constants::RPC_DEFAULT_SEND_RAW_TX_SYNC_TIMEOUT_SECS, + http, + http_addr, + http_port, + http_disable_compression, + http_api, + http_corsdomain, + ws, + ws_addr, + ws_port, + ws_allowed_origins, + ws_api, + ipcdisable, + ipcpath, + ipc_socket_permissions, + auth_addr, + auth_port, + auth_jwtsecret, + auth_ipc, + auth_ipc_path, + disable_auth_server, + rpc_jwtsecret, + rpc_max_request_size, + rpc_max_response_size, + rpc_max_subscriptions_per_connection, + rpc_max_connections, + rpc_max_tracing_requests, + rpc_max_blocking_io_requests, + rpc_max_trace_filter_blocks, + rpc_max_blocks_per_filter, + rpc_max_logs_per_response, + rpc_gas_cap, + rpc_evm_memory_limit, + rpc_tx_fee_cap, + rpc_max_simulate_blocks, + rpc_eth_proof_window, + rpc_proof_permits, + rpc_pending_block, + rpc_forwarder, + builder_disallow, + rpc_state_cache, + gas_price_oracle, + rpc_send_raw_transaction_sync_timeout, } } } @@ -554,4 +964,159 @@ mod tests { let expected = 1_000_000_000_000_000_000u128; assert_eq!(args.rpc_tx_fee_cap, expected); // 1 ETH default cap } + + #[test] + fn test_rpc_server_args() { + let args = RpcServerArgs { + http: true, + http_addr: "127.0.0.1".parse().unwrap(), + http_port: 8545, + http_disable_compression: false, + http_api: Some(RpcModuleSelection::try_from_selection(["eth", "admin"]).unwrap()), + http_corsdomain: Some("*".to_string()), + ws: true, + ws_addr: "127.0.0.1".parse().unwrap(), + ws_port: 8546, + ws_allowed_origins: Some("*".to_string()), + ws_api: Some(RpcModuleSelection::try_from_selection(["eth", "admin"]).unwrap()), + ipcdisable: false, + ipcpath: "reth.ipc".to_string(), + ipc_socket_permissions: Some("0o666".to_string()), + auth_addr: "127.0.0.1".parse().unwrap(), + auth_port: 8551, + auth_jwtsecret: Some(std::path::PathBuf::from("/tmp/jwt.hex")), + auth_ipc: false, + auth_ipc_path: "engine.ipc".to_string(), + disable_auth_server: false, + rpc_jwtsecret: Some( + JwtSecret::from_hex( + "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + ) + .unwrap(), + ), + rpc_max_request_size: 15u32.into(), + rpc_max_response_size: 160u32.into(), + rpc_max_subscriptions_per_connection: 1024u32.into(), + rpc_max_connections: 500u32.into(), + rpc_max_tracing_requests: 16, + rpc_max_blocking_io_requests: 256, + rpc_max_trace_filter_blocks: 4000, + rpc_max_blocks_per_filter: 1000u64.into(), + rpc_max_logs_per_response: 10000u64.into(), + rpc_gas_cap: 50_000_000, + rpc_evm_memory_limit: 256, + rpc_tx_fee_cap: 2_000_000_000_000_000_000u128, + rpc_max_simulate_blocks: 256, + rpc_eth_proof_window: 100_000, + rpc_proof_permits: 16, + rpc_pending_block: PendingBlockKind::Full, + rpc_forwarder: Some("http://localhost:8545".parse().unwrap()), + builder_disallow: None, + rpc_state_cache: RpcStateCacheArgs { + max_blocks: 5000, + max_receipts: 2000, + max_headers: 1000, + max_concurrent_db_requests: 512, + }, + gas_price_oracle: GasPriceOracleArgs { + blocks: 20, + ignore_price: 2, + max_price: 500_000_000_000, + percentile: 60, + default_suggested_fee: None, + }, + rpc_send_raw_transaction_sync_timeout: std::time::Duration::from_secs(30), + }; + + let parsed_args = CommandParser::::parse_from([ + "reth", + "--http", + "--http.addr", + "127.0.0.1", + "--http.port", + "8545", + "--http.api", + "eth,admin", + "--http.corsdomain", + "*", + "--ws", + "--ws.addr", + "127.0.0.1", + "--ws.port", + "8546", + "--ws.origins", + "*", + "--ws.api", + "eth,admin", + "--ipcpath", + "reth.ipc", + "--ipc.permissions", + "0o666", + "--authrpc.addr", + "127.0.0.1", + "--authrpc.port", + "8551", + "--authrpc.jwtsecret", + "/tmp/jwt.hex", + "--auth-ipc.path", + "engine.ipc", + "--rpc.jwtsecret", + "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + "--rpc.max-request-size", + "15", + "--rpc.max-response-size", + "160", + "--rpc.max-subscriptions-per-connection", + "1024", + "--rpc.max-connections", + "500", + "--rpc.max-tracing-requests", + "16", + "--rpc.max-blocking-io-requests", + "256", + "--rpc.max-trace-filter-blocks", + "4000", + "--rpc.max-blocks-per-filter", + "1000", + "--rpc.max-logs-per-response", + "10000", + "--rpc.gascap", + "50000000", + "--rpc.evm-memory-limit", + "256", + "--rpc.txfeecap", + "2.0", + "--rpc.max-simulate-blocks", + "256", + "--rpc.eth-proof-window", + "100000", + "--rpc.proof-permits", + "16", + "--rpc.pending-block", + "full", + "--rpc.forwarder", + "http://localhost:8545", + "--rpc-cache.max-blocks", + "5000", + "--rpc-cache.max-receipts", + "2000", + "--rpc-cache.max-headers", + "1000", + "--rpc-cache.max-concurrent-db-requests", + "512", + "--gpo.blocks", + "20", + "--gpo.ignoreprice", + "2", + "--gpo.maxprice", + "500000000000", + "--gpo.percentile", + "60", + "--rpc.send-raw-transaction-sync-timeout", + "30s", + ]) + .args; + + assert_eq!(parsed_args, args); + } }