diff --git a/bin/reth/src/args/database_args.rs b/bin/reth/src/args/database_args.rs deleted file mode 100644 index edaa26bbfa..0000000000 --- a/bin/reth/src/args/database_args.rs +++ /dev/null @@ -1,33 +0,0 @@ -//! clap [Args](clap::Args) for database configuration - -use clap::Args; -use reth_interfaces::db::LogLevel; - -/// Parameters for database configuration -#[derive(Debug, Args, PartialEq, Default, Clone, Copy)] -#[clap(next_help_heading = "Database")] -pub struct DatabaseArgs { - /// Database logging level. Levels higher than "notice" require a debug build. - #[arg(long = "db.log-level", value_enum)] - pub log_level: Option, -} - -#[cfg(test)] -mod tests { - use super::*; - use clap::Parser; - - /// A helper type to parse Args more easily - #[derive(Parser)] - struct CommandParser { - #[clap(flatten)] - args: T, - } - - #[test] - fn test_parse_database_args() { - let default_args = DatabaseArgs::default(); - let args = CommandParser::::parse_from(["reth"]).args; - assert_eq!(args, default_args); - } -} diff --git a/bin/reth/src/args/debug_args.rs b/bin/reth/src/args/debug_args.rs deleted file mode 100644 index c8f27a10a2..0000000000 --- a/bin/reth/src/args/debug_args.rs +++ /dev/null @@ -1,87 +0,0 @@ -//! clap [Args](clap::Args) for debugging purposes - -use clap::Args; -use reth_primitives::{TxHash, B256}; -use std::path::PathBuf; - -/// Parameters for debugging purposes -#[derive(Debug, Args, PartialEq, Default)] -#[clap(next_help_heading = "Debug")] -pub struct DebugArgs { - /// Prompt the downloader to download blocks one at a time. - /// - /// NOTE: This is for testing purposes only. - #[arg(long = "debug.continuous", help_heading = "Debug", conflicts_with = "tip")] - pub continuous: bool, - - /// Flag indicating whether the node should be terminated after the pipeline sync. - #[arg(long = "debug.terminate", help_heading = "Debug")] - pub terminate: bool, - - /// Set the chain tip manually for testing purposes. - /// - /// NOTE: This is a temporary flag - #[arg(long = "debug.tip", help_heading = "Debug", conflicts_with = "continuous")] - pub tip: Option, - - /// Runs the sync only up to the specified block. - #[arg(long = "debug.max-block", help_heading = "Debug")] - pub max_block: Option, - - /// Print opcode level traces directly to console during execution. - #[arg(long = "debug.print-inspector", help_heading = "Debug")] - pub print_inspector: bool, - - /// Hook on a specific block during execution. - #[arg( - long = "debug.hook-block", - help_heading = "Debug", - conflicts_with = "hook_transaction", - conflicts_with = "hook_all" - )] - pub hook_block: Option, - - /// Hook on a specific transaction during execution. - #[arg( - long = "debug.hook-transaction", - help_heading = "Debug", - conflicts_with = "hook_block", - conflicts_with = "hook_all" - )] - pub hook_transaction: Option, - - /// Hook on every transaction in a block. - #[arg( - long = "debug.hook-all", - help_heading = "Debug", - conflicts_with = "hook_block", - conflicts_with = "hook_transaction" - )] - pub hook_all: bool, - - /// The path to store engine API messages at. - /// If specified, all of the intercepted engine API messages - /// will be written to specified location. - #[arg(long = "debug.engine-api-store", help_heading = "Debug", value_name = "PATH")] - pub engine_api_store: Option, -} - -#[cfg(test)] -mod tests { - use super::*; - use clap::Parser; - - /// A helper type to parse Args more easily - #[derive(Parser)] - struct CommandParser { - #[clap(flatten)] - args: T, - } - - #[test] - fn test_parse_database_args() { - let default_args = DebugArgs::default(); - let args = CommandParser::::parse_from(["reth"]).args; - assert_eq!(args, default_args); - } -} diff --git a/bin/reth/src/args/dev_args.rs b/bin/reth/src/args/dev_args.rs deleted file mode 100644 index 929b3fd10c..0000000000 --- a/bin/reth/src/args/dev_args.rs +++ /dev/null @@ -1,107 +0,0 @@ -//! clap [Args](clap::Args) for Dev testnet configuration - -use std::time::Duration; - -use clap::Args; -use humantime::parse_duration; - -/// Parameters for Dev testnet configuration -#[derive(Debug, Args, PartialEq, Default, Clone, Copy)] -#[clap(next_help_heading = "Dev testnet")] -pub struct DevArgs { - /// Start the node in dev mode - /// - /// This mode uses a local proof-of-authority consensus engine with either fixed block times - /// or automatically mined blocks. - /// Disables network discovery and enables local http server. - /// Prefunds 20 accounts derived by mnemonic "test test test test test test test test test test - /// test junk" with 10 000 ETH each. - #[arg(long = "dev", alias = "auto-mine", help_heading = "Dev testnet", verbatim_doc_comment)] - pub dev: bool, - - /// How many transactions to mine per block. - #[arg( - long = "dev.block-max-transactions", - help_heading = "Dev testnet", - conflicts_with = "block_time" - )] - pub block_max_transactions: Option, - - /// Interval between blocks. - /// - /// Parses strings using [humantime::parse_duration] - /// --dev.block-time 12s - #[arg( - long = "dev.block-time", - help_heading = "Dev testnet", - conflicts_with = "block_max_transactions", - value_parser = parse_duration, - verbatim_doc_comment - )] - pub block_time: Option, -} - -#[cfg(test)] -mod tests { - use super::*; - use clap::Parser; - - /// A helper type to parse Args more easily - #[derive(Parser)] - struct CommandParser { - #[clap(flatten)] - args: T, - } - - #[test] - fn test_parse_dev_args() { - let args = CommandParser::::parse_from(["reth"]).args; - assert_eq!(args, DevArgs { dev: false, block_max_transactions: None, block_time: None }); - - let args = CommandParser::::parse_from(["reth", "--dev"]).args; - assert_eq!(args, DevArgs { dev: true, block_max_transactions: None, block_time: None }); - - let args = CommandParser::::parse_from(["reth", "--auto-mine"]).args; - assert_eq!(args, DevArgs { dev: true, block_max_transactions: None, block_time: None }); - - let args = CommandParser::::parse_from([ - "reth", - "--dev", - "--dev.block-max-transactions", - "2", - ]) - .args; - assert_eq!(args, DevArgs { dev: true, block_max_transactions: Some(2), block_time: None }); - - let args = - CommandParser::::parse_from(["reth", "--dev", "--dev.block-time", "1s"]).args; - assert_eq!( - args, - DevArgs { - dev: true, - block_max_transactions: None, - block_time: Some(std::time::Duration::from_secs(1)) - } - ); - } - - #[test] - fn test_parse_dev_args_conflicts() { - let args = CommandParser::::try_parse_from([ - "reth", - "--dev", - "--dev.block-max-transactions", - "2", - "--dev.block-time", - "1s", - ]); - assert!(args.is_err()); - } - - #[test] - fn dev_args_default_sanity_check() { - let default_args = DevArgs::default(); - let args = CommandParser::::parse_from(["reth"]).args; - assert_eq!(args, default_args); - } -} diff --git a/bin/reth/src/args/gas_price_oracle_args.rs b/bin/reth/src/args/gas_price_oracle_args.rs deleted file mode 100644 index 54087693af..0000000000 --- a/bin/reth/src/args/gas_price_oracle_args.rs +++ /dev/null @@ -1,86 +0,0 @@ -use crate::primitives::U256; -use clap::Args; -use reth_rpc::eth::gas_oracle::GasPriceOracleConfig; -use reth_rpc_builder::constants::{ - DEFAULT_GAS_PRICE_BLOCKS, DEFAULT_GAS_PRICE_PERCENTILE, DEFAULT_IGNORE_GAS_PRICE, - DEFAULT_MAX_GAS_PRICE, -}; - -/// Parameters to configure Gas Price Oracle -#[derive(Debug, Clone, Copy, Args, PartialEq, Eq)] -#[clap(next_help_heading = "Gas Price Oracle")] -pub struct GasPriceOracleArgs { - /// Number of recent blocks to check for gas price - #[arg(long = "gpo.blocks", default_value_t = DEFAULT_GAS_PRICE_BLOCKS)] - pub blocks: u32, - - /// Gas Price below which gpo will ignore transactions - #[arg(long = "gpo.ignoreprice", default_value_t = DEFAULT_IGNORE_GAS_PRICE.to())] - pub ignore_price: u64, - - /// Maximum transaction priority fee(or gasprice before London Fork) to be recommended by gpo - #[arg(long = "gpo.maxprice", default_value_t = DEFAULT_MAX_GAS_PRICE.to())] - pub max_price: u64, - - /// The percentile of gas prices to use for the estimate - #[arg(long = "gpo.percentile", default_value_t = DEFAULT_GAS_PRICE_PERCENTILE)] - pub percentile: u32, -} - -impl GasPriceOracleArgs { - /// Returns a [GasPriceOracleConfig] from the arguments. - pub fn gas_price_oracle_config(&self) -> GasPriceOracleConfig { - let Self { blocks, ignore_price, max_price, percentile } = self; - GasPriceOracleConfig { - max_price: Some(U256::from(*max_price)), - ignore_price: Some(U256::from(*ignore_price)), - percentile: *percentile, - blocks: *blocks, - ..Default::default() - } - } -} - -impl Default for GasPriceOracleArgs { - fn default() -> Self { - Self { - blocks: DEFAULT_GAS_PRICE_BLOCKS, - ignore_price: DEFAULT_IGNORE_GAS_PRICE.to(), - max_price: DEFAULT_MAX_GAS_PRICE.to(), - percentile: DEFAULT_GAS_PRICE_PERCENTILE, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use clap::Parser; - /// A helper type to parse Args more easily - #[derive(Parser)] - struct CommandParser { - #[clap(flatten)] - args: T, - } - - #[test] - fn test_parse_gpo_args() { - let args = CommandParser::::parse_from(["reth"]).args; - assert_eq!( - args, - GasPriceOracleArgs { - blocks: DEFAULT_GAS_PRICE_BLOCKS, - ignore_price: DEFAULT_IGNORE_GAS_PRICE.to(), - max_price: DEFAULT_MAX_GAS_PRICE.to(), - percentile: DEFAULT_GAS_PRICE_PERCENTILE, - } - ); - } - - #[test] - fn gpo_args_default_sanity_test() { - let default_args = GasPriceOracleArgs::default(); - let args = CommandParser::::parse_from(["reth"]).args; - assert_eq!(args, default_args); - } -} diff --git a/bin/reth/src/args/log_args.rs b/bin/reth/src/args/log_args.rs deleted file mode 100644 index 6584acc071..0000000000 --- a/bin/reth/src/args/log_args.rs +++ /dev/null @@ -1,179 +0,0 @@ -//! clap [Args](clap::Args) for logging configuration. - -use crate::dirs::{LogsDir, PlatformPath}; -use clap::{ArgAction, Args, ValueEnum}; -use reth_tracing::{ - tracing_subscriber::filter::Directive, FileInfo, FileWorkerGuard, LayerInfo, LogFormat, - RethTracer, Tracer, -}; -use std::{fmt, fmt::Display}; -use tracing::{level_filters::LevelFilter, Level}; -/// Constant to convert megabytes to bytes -const MB_TO_BYTES: u64 = 1024 * 1024; - -/// The log configuration. -#[derive(Debug, Args)] -#[command(next_help_heading = "Logging")] -pub struct LogArgs { - /// The format to use for logs written to stdout. - #[arg(long = "log.stdout.format", value_name = "FORMAT", global = true, default_value_t = LogFormat::Terminal)] - pub log_stdout_format: LogFormat, - - /// The filter to use for logs written to stdout. - #[arg( - long = "log.stdout.filter", - value_name = "FILTER", - global = true, - default_value = "info" - )] - pub log_stdout_filter: String, - - /// The format to use for logs written to the log file. - #[arg(long = "log.file.format", value_name = "FORMAT", global = true, default_value_t = LogFormat::Terminal)] - pub log_file_format: LogFormat, - - /// The filter to use for logs written to the log file. - #[arg(long = "log.file.filter", value_name = "FILTER", global = true, default_value = "debug")] - pub log_file_filter: String, - - /// The path to put log files in. - #[arg(long = "log.file.directory", value_name = "PATH", global = true, default_value_t)] - pub log_file_directory: PlatformPath, - - /// The maximum size (in MB) of one log file. - #[arg(long = "log.file.max-size", value_name = "SIZE", global = true, default_value_t = 200)] - pub log_file_max_size: u64, - - /// The maximum amount of log files that will be stored. If set to 0, background file logging - /// is disabled. - #[arg(long = "log.file.max-files", value_name = "COUNT", global = true, default_value_t = 5)] - pub log_file_max_files: usize, - - /// Write logs to journald. - #[arg(long = "log.journald", global = true)] - pub journald: bool, - - /// The filter to use for logs written to journald. - #[arg( - long = "log.journald.filter", - value_name = "FILTER", - global = true, - default_value = "error" - )] - pub journald_filter: String, - - /// Sets whether or not the formatter emits ANSI terminal escape codes for colors and other - /// text formatting. - #[arg( - long, - value_name = "COLOR", - global = true, - default_value_t = ColorMode::Always - )] - pub color: ColorMode, - /// The verbosity settings for the tracer. - #[clap(flatten)] - pub verbosity: Verbosity, -} - -impl LogArgs { - /// Creates a [LayerInfo] instance. - fn layer(&self, format: LogFormat, filter: String, use_color: bool) -> LayerInfo { - LayerInfo::new( - format, - filter, - self.verbosity.directive(), - if use_color { Some(self.color.to_string()) } else { None }, - ) - } - - /// File info from the current log options. - fn file_info(&self) -> FileInfo { - FileInfo::new( - self.log_file_directory.clone().into(), - self.log_file_max_size * MB_TO_BYTES, - self.log_file_max_files, - ) - } - - /// Initializes tracing with the configured options from cli args. - pub fn init_tracing(&self) -> eyre::Result> { - let mut tracer = RethTracer::new(); - - let stdout = self.layer(self.log_stdout_format, self.log_stdout_filter.clone(), true); - tracer = tracer.with_stdout(stdout); - - if self.journald { - tracer = tracer.with_journald(self.journald_filter.clone()); - } - - if self.log_file_max_files > 0 { - let info = self.file_info(); - let file = self.layer(self.log_file_format, self.log_file_filter.clone(), false); - tracer = tracer.with_file(file, info); - } - - let guard = tracer.init()?; - Ok(guard) - } -} - -/// The color mode for the cli. -#[derive(Debug, Copy, Clone, ValueEnum, Eq, PartialEq)] -pub enum ColorMode { - /// Colors on - Always, - /// Colors on - Auto, - /// Colors off - Never, -} - -impl Display for ColorMode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ColorMode::Always => write!(f, "always"), - ColorMode::Auto => write!(f, "auto"), - ColorMode::Never => write!(f, "never"), - } - } -} - -/// The verbosity settings for the cli. -#[derive(Debug, Copy, Clone, Args)] -#[command(next_help_heading = "Display")] -pub struct Verbosity { - /// Set the minimum log level. - /// - /// -v Errors - /// -vv Warnings - /// -vvv Info - /// -vvvv Debug - /// -vvvvv Traces (warning: very verbose!) - #[clap(short, long, action = ArgAction::Count, global = true, default_value_t = 3, verbatim_doc_comment, help_heading = "Display")] - verbosity: u8, - - /// Silence all log output. - #[clap(long, alias = "silent", short = 'q', global = true, help_heading = "Display")] - quiet: bool, -} - -impl Verbosity { - /// Get the corresponding [Directive] for the given verbosity, or none if the verbosity - /// corresponds to silent. - pub fn directive(&self) -> Directive { - if self.quiet { - LevelFilter::OFF.into() - } else { - let level = match self.verbosity - 1 { - 0 => Level::ERROR, - 1 => Level::WARN, - 2 => Level::INFO, - 3 => Level::DEBUG, - _ => Level::TRACE, - }; - - level.into() - } - } -} diff --git a/bin/reth/src/args/mod.rs b/bin/reth/src/args/mod.rs deleted file mode 100644 index abbaea4002..0000000000 --- a/bin/reth/src/args/mod.rs +++ /dev/null @@ -1,62 +0,0 @@ -//! Parameters for configuring the rpc more granularity via CLI - -/// NetworkArg struct for configuring the network -mod network_args; -pub use network_args::{DiscoveryArgs, NetworkArgs}; - -/// RpcServerArg struct for configuring the RPC -mod rpc_server_args; -pub use rpc_server_args::RpcServerArgs; - -/// RpcStateCacheArgs struct for configuring RPC state cache -mod rpc_state_cache_args; -pub use rpc_state_cache_args::RpcStateCacheArgs; - -/// DebugArgs struct for debugging purposes -mod debug_args; -pub use debug_args::DebugArgs; - -/// DatabaseArgs struct for configuring the database -mod database_args; -pub use database_args::DatabaseArgs; - -/// LogArgs struct for configuring the logger -mod log_args; -pub use log_args::{ColorMode, LogArgs}; - -mod secret_key; -pub use secret_key::{get_secret_key, SecretKeyError}; - -/// PayloadBuilderArgs struct for configuring the payload builder -mod payload_builder_args; -pub use payload_builder_args::PayloadBuilderArgs; - -/// Stage related arguments -mod stage_args; -pub use stage_args::StageEnum; - -/// Gas price oracle related arguments -mod gas_price_oracle_args; -pub use gas_price_oracle_args::GasPriceOracleArgs; - -/// TxPoolArgs for configuring the transaction pool -mod txpool_args; -pub use txpool_args::TxPoolArgs; - -/// DevArgs for configuring the dev testnet -mod dev_args; -pub use dev_args::DevArgs; - -/// PruneArgs for configuring the pruning and full node -mod pruning_args; -pub use pruning_args::PruningArgs; - -/// RollupArgs for configuring the op-reth rollup -#[cfg(feature = "optimism")] -mod rollup_args; -#[cfg(feature = "optimism")] -pub use rollup_args::RollupArgs; - -pub mod utils; - -pub mod types; diff --git a/bin/reth/src/args/network_args.rs b/bin/reth/src/args/network_args.rs deleted file mode 100644 index 23a4a124d5..0000000000 --- a/bin/reth/src/args/network_args.rs +++ /dev/null @@ -1,288 +0,0 @@ -//! clap [Args](clap::Args) for network related arguments. - -use crate::version::P2P_CLIENT_VERSION; -use clap::Args; -use reth_config::Config; -use reth_discv4::{DEFAULT_DISCOVERY_ADDR, DEFAULT_DISCOVERY_PORT}; -use reth_net_nat::NatResolver; -use reth_network::{HelloMessageWithProtocols, NetworkConfigBuilder}; -use reth_primitives::{mainnet_nodes, ChainSpec, NodeRecord}; -use secp256k1::SecretKey; -use std::{net::Ipv4Addr, path::PathBuf, sync::Arc}; - -/// Parameters for configuring the network more granularity via CLI -#[derive(Debug, Args, PartialEq, Eq)] -#[clap(next_help_heading = "Networking")] -pub struct NetworkArgs { - /// Disable the discovery service. - #[command(flatten)] - pub discovery: DiscoveryArgs, - - /// Comma separated enode URLs of trusted peers for P2P connections. - /// - /// --trusted-peers enode://abcd@192.168.0.1:30303 - #[arg(long, value_delimiter = ',')] - pub trusted_peers: Vec, - - /// Connect only to trusted peers - #[arg(long)] - pub trusted_only: bool, - - /// Comma separated enode URLs for P2P discovery bootstrap. - /// - /// Will fall back to a network-specific default if not specified. - #[arg(long, value_delimiter = ',')] - pub bootnodes: Option>, - - /// The path to the known peers file. Connected peers are dumped to this file on nodes - /// shutdown, and read on startup. Cannot be used with `--no-persist-peers`. - #[arg(long, value_name = "FILE", verbatim_doc_comment, conflicts_with = "no_persist_peers")] - pub peers_file: Option, - - /// Custom node identity - #[arg(long, value_name = "IDENTITY", default_value = P2P_CLIENT_VERSION)] - pub identity: String, - - /// Secret key to use for this node. - /// - /// This will also deterministically set the peer ID. If not specified, it will be set in the - /// data dir for the chain being used. - #[arg(long, value_name = "PATH")] - pub p2p_secret_key: Option, - - /// Do not persist peers. - #[arg(long, verbatim_doc_comment)] - pub no_persist_peers: bool, - - /// NAT resolution method (any|none|upnp|publicip|extip:\) - #[arg(long, default_value = "any")] - pub nat: NatResolver, - - /// Network listening address - #[arg(long = "addr", value_name = "ADDR", default_value_t = DEFAULT_DISCOVERY_ADDR)] - pub addr: Ipv4Addr, - - /// Network listening port - #[arg(long = "port", value_name = "PORT", default_value_t = DEFAULT_DISCOVERY_PORT)] - pub port: u16, - - /// Maximum number of outbound requests. default: 100 - #[arg(long)] - pub max_outbound_peers: Option, - - /// Maximum number of inbound requests. default: 30 - #[arg(long)] - pub max_inbound_peers: Option, -} - -impl NetworkArgs { - /// Build a [`NetworkConfigBuilder`] from a [`Config`] and a [`ChainSpec`], in addition to the - /// values in this option struct. - /// - /// The `default_peers_file` will be used as the default location to store the persistent peers - /// file if `no_persist_peers` is false, and there is no provided `peers_file`. - pub fn network_config( - &self, - config: &Config, - chain_spec: Arc, - secret_key: SecretKey, - default_peers_file: PathBuf, - ) -> NetworkConfigBuilder { - let chain_bootnodes = chain_spec.bootnodes().unwrap_or_else(mainnet_nodes); - let peers_file = self.peers_file.clone().unwrap_or(default_peers_file); - - // Configure peer connections - let peer_config = config - .peers - .clone() - .with_max_inbound_opt(self.max_inbound_peers) - .with_max_outbound_opt(self.max_outbound_peers); - - // Configure basic network stack - let mut network_config_builder = config - .network_config(self.nat, self.persistent_peers_file(peers_file), secret_key) - .peer_config(peer_config) - .boot_nodes(self.bootnodes.clone().unwrap_or(chain_bootnodes)) - .chain_spec(chain_spec); - - // Configure node identity - let peer_id = network_config_builder.get_peer_id(); - network_config_builder = network_config_builder.hello_message( - HelloMessageWithProtocols::builder(peer_id).client_version(&self.identity).build(), - ); - - self.discovery.apply_to_builder(network_config_builder) - } - - /// If `no_persist_peers` is true then this returns the path to the persistent peers file path. - pub fn persistent_peers_file(&self, peers_file: PathBuf) -> Option { - if self.no_persist_peers { - return None - } - - Some(peers_file) - } - - /// Sets the p2p port to zero, to allow the OS to assign a random unused port when - /// the network components bind to a socket. - pub fn with_unused_p2p_port(mut self) -> Self { - self.port = 0; - self - } - - /// Sets the p2p and discovery ports to zero, allowing the OD to assign a random unused port - /// when network components bind to sockets. - pub fn with_unused_ports(mut self) -> Self { - self = self.with_unused_p2p_port(); - self.discovery = self.discovery.with_unused_discovery_port(); - self - } -} - -impl Default for NetworkArgs { - fn default() -> Self { - Self { - discovery: DiscoveryArgs::default(), - trusted_peers: vec![], - trusted_only: false, - bootnodes: None, - peers_file: None, - identity: P2P_CLIENT_VERSION.to_string(), - p2p_secret_key: None, - no_persist_peers: false, - nat: NatResolver::Any, - addr: DEFAULT_DISCOVERY_ADDR, - port: DEFAULT_DISCOVERY_PORT, - max_outbound_peers: None, - max_inbound_peers: None, - } - } -} - -/// Arguments to setup discovery -#[derive(Debug, Args, PartialEq, Eq)] -pub struct DiscoveryArgs { - /// Disable the discovery service. - #[arg(short, long, default_value_if("dev", "true", "true"))] - pub disable_discovery: bool, - - /// Disable the DNS discovery. - #[arg(long, conflicts_with = "disable_discovery")] - pub disable_dns_discovery: bool, - - /// Disable Discv4 discovery. - #[arg(long, conflicts_with = "disable_discovery")] - pub disable_discv4_discovery: bool, - - /// The UDP address to use for P2P discovery/networking - #[arg(long = "discovery.addr", name = "discovery.addr", value_name = "DISCOVERY_ADDR", default_value_t = DEFAULT_DISCOVERY_ADDR)] - pub addr: Ipv4Addr, - - /// The UDP port to use for P2P discovery/networking - #[arg(long = "discovery.port", name = "discovery.port", value_name = "DISCOVERY_PORT", default_value_t = DEFAULT_DISCOVERY_PORT)] - pub port: u16, -} - -impl DiscoveryArgs { - /// Apply the discovery settings to the given [NetworkConfigBuilder] - pub fn apply_to_builder( - &self, - mut network_config_builder: NetworkConfigBuilder, - ) -> NetworkConfigBuilder { - if self.disable_discovery || self.disable_dns_discovery { - network_config_builder = network_config_builder.disable_dns_discovery(); - } - - if self.disable_discovery || self.disable_discv4_discovery { - network_config_builder = network_config_builder.disable_discv4_discovery(); - } - network_config_builder - } - - /// Set the discovery port to zero, to allow the OS to assign a random unused port when - /// discovery binds to the socket. - pub fn with_unused_discovery_port(mut self) -> Self { - self.port = 0; - self - } -} - -impl Default for DiscoveryArgs { - fn default() -> Self { - Self { - disable_discovery: false, - disable_dns_discovery: false, - disable_discv4_discovery: false, - addr: DEFAULT_DISCOVERY_ADDR, - port: DEFAULT_DISCOVERY_PORT, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use clap::Parser; - /// A helper type to parse Args more easily - #[derive(Parser)] - struct CommandParser { - #[clap(flatten)] - args: T, - } - - #[test] - fn parse_nat_args() { - let args = CommandParser::::parse_from(["reth", "--nat", "none"]).args; - assert_eq!(args.nat, NatResolver::None); - - let args = - CommandParser::::parse_from(["reth", "--nat", "extip:0.0.0.0"]).args; - assert_eq!(args.nat, NatResolver::ExternalIp("0.0.0.0".parse().unwrap())); - } - - #[test] - fn parse_peer_args() { - let args = - CommandParser::::parse_from(["reth", "--max-outbound-peers", "50"]).args; - assert_eq!(args.max_outbound_peers, Some(50)); - assert_eq!(args.max_inbound_peers, None); - - let args = CommandParser::::parse_from([ - "reth", - "--max-outbound-peers", - "75", - "--max-inbound-peers", - "15", - ]) - .args; - assert_eq!(args.max_outbound_peers, Some(75)); - assert_eq!(args.max_inbound_peers, Some(15)); - } - - #[test] - fn parse_trusted_peer_args() { - let args = - CommandParser::::parse_from([ - "reth", - "--trusted-peers", - "enode://d860a01f9722d78051619d1e2351aba3f43f943f6f00718d1b9baa4101932a1f5011f16bb2b1bb35db20d6fe28fa0bf09636d26a87d31de9ec6203eeedb1f666@18.138.108.67:30303,enode://22a8232c3abc76a16ae9d6c3b164f98775fe226f0917b0ca871128a74a8e9630b458460865bab457221f1d448dd9791d24c4e5d88786180ac185df813a68d4de@3.209.45.79:30303" - ]) - .args; - - assert_eq!( - args.trusted_peers, - vec![ - "enode://d860a01f9722d78051619d1e2351aba3f43f943f6f00718d1b9baa4101932a1f5011f16bb2b1bb35db20d6fe28fa0bf09636d26a87d31de9ec6203eeedb1f666@18.138.108.67:30303".parse().unwrap(), - "enode://22a8232c3abc76a16ae9d6c3b164f98775fe226f0917b0ca871128a74a8e9630b458460865bab457221f1d448dd9791d24c4e5d88786180ac185df813a68d4de@3.209.45.79:30303".parse().unwrap() - ] - ); - } - - #[test] - fn network_args_default_sanity_test() { - let default_args = NetworkArgs::default(); - let args = CommandParser::::parse_from(["reth"]).args; - - assert_eq!(args, default_args); - } -} diff --git a/bin/reth/src/args/payload_builder_args.rs b/bin/reth/src/args/payload_builder_args.rs deleted file mode 100644 index d7453372b1..0000000000 --- a/bin/reth/src/args/payload_builder_args.rs +++ /dev/null @@ -1,178 +0,0 @@ -use crate::{ - args::utils::parse_duration_from_secs, cli::config::PayloadBuilderConfig, - version::default_extradata, -}; -use clap::{ - builder::{RangedU64ValueParser, TypedValueParser}, - Arg, Args, Command, -}; -use reth_primitives::constants::{ - ETHEREUM_BLOCK_GAS_LIMIT, MAXIMUM_EXTRA_DATA_SIZE, SLOT_DURATION, -}; -use std::{borrow::Cow, ffi::OsStr, time::Duration}; - -/// Parameters for configuring the Payload Builder -#[derive(Debug, Args, PartialEq)] -#[clap(next_help_heading = "Builder")] -pub struct PayloadBuilderArgs { - /// Block extra data set by the payload builder. - #[arg(long = "builder.extradata", value_parser=ExtradataValueParser::default(), default_value_t = default_extradata())] - pub extradata: String, - - /// Target gas ceiling for built blocks. - #[arg(long = "builder.gaslimit", default_value = "30000000", value_name = "GAS_LIMIT")] - pub max_gas_limit: u64, - - /// The interval at which the job should build a new payload after the last (in seconds). - #[arg(long = "builder.interval", value_parser = parse_duration_from_secs, default_value = "1", value_name = "SECONDS")] - pub interval: Duration, - - /// The deadline for when the payload builder job should resolve. - #[arg(long = "builder.deadline", value_parser = parse_duration_from_secs, default_value = "12", value_name = "SECONDS")] - pub deadline: Duration, - - /// Maximum number of tasks to spawn for building a payload. - #[arg(long = "builder.max-tasks", default_value = "3", value_parser = RangedU64ValueParser::::new().range(1..))] - pub max_payload_tasks: usize, - - /// By default the pending block equals the latest block - /// to save resources and not leak txs from the tx-pool, - /// this flag enables computing of the pending block - /// from the tx-pool instead. - /// - /// If `compute_pending_block` is not enabled, the payload builder - /// will use the payload attributes from the latest block. Note - /// that this flag is not yet functional. - #[cfg(feature = "optimism")] - #[arg(long = "rollup.compute-pending-block")] - pub compute_pending_block: bool, -} - -impl Default for PayloadBuilderArgs { - fn default() -> Self { - Self { - extradata: default_extradata(), - max_gas_limit: ETHEREUM_BLOCK_GAS_LIMIT, - interval: Duration::from_secs(1), - deadline: SLOT_DURATION, - max_payload_tasks: 3, - #[cfg(feature = "optimism")] - compute_pending_block: false, - } - } -} - -impl PayloadBuilderConfig for PayloadBuilderArgs { - fn extradata(&self) -> Cow<'_, str> { - self.extradata.as_str().into() - } - - fn interval(&self) -> Duration { - self.interval - } - - fn deadline(&self) -> Duration { - self.deadline - } - - fn max_gas_limit(&self) -> u64 { - self.max_gas_limit - } - - fn max_payload_tasks(&self) -> usize { - self.max_payload_tasks - } - - #[cfg(feature = "optimism")] - fn compute_pending_block(&self) -> bool { - self.compute_pending_block - } -} - -#[derive(Clone, Debug, Default)] -#[non_exhaustive] -struct ExtradataValueParser; - -impl TypedValueParser for ExtradataValueParser { - type Value = String; - - fn parse_ref( - &self, - _cmd: &Command, - _arg: Option<&Arg>, - value: &OsStr, - ) -> Result { - let val = - value.to_str().ok_or_else(|| clap::Error::new(clap::error::ErrorKind::InvalidUtf8))?; - if val.as_bytes().len() > MAXIMUM_EXTRA_DATA_SIZE { - return Err(clap::Error::raw( - clap::error::ErrorKind::InvalidValue, - format!( - "Payload builder extradata size exceeds {MAXIMUM_EXTRA_DATA_SIZE}bytes limit" - ), - )) - } - Ok(val.to_string()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use clap::{Args, Parser}; - - /// A helper type to parse Args more easily - #[derive(Parser)] - struct CommandParser { - #[clap(flatten)] - args: T, - } - - #[test] - fn test_args_with_valid_max_tasks() { - let args = - CommandParser::::parse_from(["reth", "--builder.max-tasks", "1"]) - .args; - assert_eq!(args.max_payload_tasks, 1) - } - - #[test] - fn test_args_with_invalid_max_tasks() { - assert!(CommandParser::::try_parse_from([ - "reth", - "--builder.max-tasks", - "0" - ]) - .is_err()); - } - - #[test] - fn test_default_extradata() { - let extradata = default_extradata(); - let args = CommandParser::::parse_from([ - "reth", - "--builder.extradata", - extradata.as_str(), - ]) - .args; - assert_eq!(args.extradata, extradata); - } - - #[test] - fn test_invalid_extradata() { - let extradata = "x".repeat(MAXIMUM_EXTRA_DATA_SIZE + 1); - let args = CommandParser::::try_parse_from([ - "reth", - "--builder.extradata", - extradata.as_str(), - ]); - assert!(args.is_err()); - } - - #[test] - fn payload_builder_args_default_sanity_check() { - let default_args = PayloadBuilderArgs::default(); - let args = CommandParser::::parse_from(["reth"]).args; - assert_eq!(args, default_args); - } -} diff --git a/bin/reth/src/args/pruning_args.rs b/bin/reth/src/args/pruning_args.rs deleted file mode 100644 index ece803261c..0000000000 --- a/bin/reth/src/args/pruning_args.rs +++ /dev/null @@ -1,69 +0,0 @@ -//! Pruning and full node arguments - -use clap::Args; -use reth_config::config::PruneConfig; -use reth_primitives::{ - ChainSpec, PruneMode, PruneModes, ReceiptsLogPruneConfig, MINIMUM_PRUNING_DISTANCE, -}; -use std::sync::Arc; - -/// Parameters for pruning and full node -#[derive(Debug, Args, PartialEq, Default)] -#[clap(next_help_heading = "Pruning")] -pub struct PruningArgs { - /// Run full node. Only the most recent [`MINIMUM_PRUNING_DISTANCE`] block states are stored. - /// This flag takes priority over pruning configuration in reth.toml. - #[arg(long, default_value_t = false)] - pub full: bool, -} - -impl PruningArgs { - /// Returns pruning configuration. - pub fn prune_config(&self, chain_spec: Arc) -> eyre::Result> { - Ok(if self.full { - Some(PruneConfig { - block_interval: 5, - segments: PruneModes { - sender_recovery: Some(PruneMode::Full), - transaction_lookup: None, - receipts: chain_spec - .deposit_contract - .as_ref() - .map(|contract| PruneMode::Before(contract.block)), - account_history: Some(PruneMode::Distance(MINIMUM_PRUNING_DISTANCE)), - storage_history: Some(PruneMode::Distance(MINIMUM_PRUNING_DISTANCE)), - receipts_log_filter: ReceiptsLogPruneConfig( - chain_spec - .deposit_contract - .as_ref() - .map(|contract| (contract.address, PruneMode::Before(contract.block))) - .into_iter() - .collect(), - ), - }, - }) - } else { - None - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use clap::{Args, Parser}; - - /// A helper type to parse Args more easily - #[derive(Parser)] - struct CommandParser { - #[clap(flatten)] - args: T, - } - - #[test] - fn pruning_args_sanity_check() { - let default_args = PruningArgs::default(); - let args = CommandParser::::parse_from(["reth"]).args; - assert_eq!(args, default_args); - } -} diff --git a/bin/reth/src/args/rollup_args.rs b/bin/reth/src/args/rollup_args.rs deleted file mode 100644 index ec2a995113..0000000000 --- a/bin/reth/src/args/rollup_args.rs +++ /dev/null @@ -1,39 +0,0 @@ -//! clap [Args](clap::Args) for op-reth rollup configuration - -/// Parameters for rollup configuration -#[derive(Debug, Default, PartialEq, Eq, clap::Args)] -#[clap(next_help_heading = "Rollup")] -pub struct RollupArgs { - /// HTTP endpoint for the sequencer mempool - #[arg(long = "rollup.sequencer-http", value_name = "HTTP_URL")] - pub sequencer_http: Option, - - /// Disable transaction pool gossip - #[arg(long = "rollup.disable-tx-pool-gossip")] - pub disable_txpool_gossip: bool, - - /// Enable walkback to genesis on startup. This is useful for re-validating the existing DB - /// prior to beginning normal syncing. - #[arg(long = "rollup.enable-genesis-walkback")] - pub enable_genesis_walkback: bool, -} - -#[cfg(test)] -mod tests { - use super::*; - use clap::{Args, Parser}; - - /// A helper type to parse Args more easily - #[derive(Parser)] - struct CommandParser { - #[clap(flatten)] - args: T, - } - - #[test] - fn test_parse_database_args() { - let default_args = RollupArgs::default(); - let args = CommandParser::::parse_from(["reth"]).args; - assert_eq!(args, default_args); - } -} diff --git a/bin/reth/src/args/rpc_server_args.rs b/bin/reth/src/args/rpc_server_args.rs deleted file mode 100644 index e0c6fcd8f8..0000000000 --- a/bin/reth/src/args/rpc_server_args.rs +++ /dev/null @@ -1,802 +0,0 @@ -//! clap [Args](clap::Args) for RPC related arguments. - -use crate::{ - args::{ - types::{MaxU32, ZeroAsNoneU64}, - GasPriceOracleArgs, RpcStateCacheArgs, - }, - cli::{ - components::{RethNodeComponents, RethRpcComponents, RethRpcServerHandles}, - config::RethRpcConfig, - ext::RethNodeCommandConfig, - }, - utils::get_or_create_jwt_secret_from_path, -}; -use clap::{ - builder::{PossibleValue, RangedU64ValueParser, TypedValueParser}, - Arg, Args, Command, -}; -use futures::TryFutureExt; -use rand::Rng; -use reth_network_api::{NetworkInfo, Peers}; -use reth_node_api::EngineTypes; -use reth_provider::{ - AccountReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader, - EvmEnvProvider, HeaderProvider, StateProviderFactory, -}; -use reth_rpc::{ - eth::{cache::EthStateCacheConfig, gas_oracle::GasPriceOracleConfig, RPC_DEFAULT_GAS_CAP}, - JwtError, JwtSecret, -}; -use reth_rpc_builder::{ - auth::{AuthServerConfig, AuthServerHandle}, - constants, - error::RpcError, - EthConfig, IpcServerBuilder, RethRpcModule, RpcModuleBuilder, RpcModuleConfig, - RpcModuleSelection, RpcServerConfig, RpcServerHandle, ServerBuilder, TransportRpcModuleConfig, -}; -use reth_rpc_engine_api::{EngineApi, EngineApiServer}; -use reth_tasks::TaskSpawner; -use reth_transaction_pool::TransactionPool; -use std::{ - ffi::OsStr, - net::{IpAddr, Ipv4Addr, SocketAddr}, - path::PathBuf, -}; -use tracing::{debug, info}; - -/// Default max number of subscriptions per connection. -pub(crate) const RPC_DEFAULT_MAX_SUBS_PER_CONN: u32 = 1024; -/// Default max request size in MB. -pub(crate) const RPC_DEFAULT_MAX_REQUEST_SIZE_MB: u32 = 15; -/// Default max response size in MB. -/// -/// This is only relevant for very large trace responses. -pub(crate) const RPC_DEFAULT_MAX_RESPONSE_SIZE_MB: u32 = 150; -/// Default number of incoming connections. -pub(crate) const RPC_DEFAULT_MAX_CONNECTIONS: u32 = 500; - -/// Parameters for configuring the rpc more granularity via CLI -#[derive(Debug, Clone, Args, PartialEq, Eq)] -#[clap(next_help_heading = "RPC")] -pub struct RpcServerArgs { - /// Enable the HTTP-RPC server - #[arg(long, default_value_if("dev", "true", "true"))] - pub http: bool, - - /// Http server address to listen on - #[arg(long = "http.addr", default_value_t = IpAddr::V4(Ipv4Addr::LOCALHOST))] - pub http_addr: IpAddr, - - /// Http server port to listen on - #[arg(long = "http.port", default_value_t = constants::DEFAULT_HTTP_RPC_PORT)] - pub http_port: u16, - - /// Rpc Modules to be configured for the HTTP server - #[arg(long = "http.api", value_parser = RpcModuleSelectionValueParser::default())] - pub http_api: Option, - - /// Http Corsdomain to allow request from - #[arg(long = "http.corsdomain")] - pub http_corsdomain: Option, - - /// Enable the WS-RPC server - #[arg(long)] - pub ws: bool, - - /// Ws server address to listen on - #[arg(long = "ws.addr", default_value_t = IpAddr::V4(Ipv4Addr::LOCALHOST))] - pub ws_addr: IpAddr, - - /// Ws server port to listen on - #[arg(long = "ws.port", default_value_t = constants::DEFAULT_WS_RPC_PORT)] - pub ws_port: u16, - - /// Origins from which to accept WebSocket requests - #[arg(long = "ws.origins", name = "ws.origins")] - pub ws_allowed_origins: Option, - - /// Rpc Modules to be configured for the WS server - #[arg(long = "ws.api", value_parser = RpcModuleSelectionValueParser::default())] - pub ws_api: Option, - - /// Disable the IPC-RPC server - #[arg(long)] - pub ipcdisable: bool, - - /// Filename for IPC socket/pipe within the datadir - #[arg(long, default_value_t = constants::DEFAULT_IPC_ENDPOINT.to_string())] - pub ipcpath: String, - - /// Auth server address to listen on - #[arg(long = "authrpc.addr", default_value_t = IpAddr::V4(Ipv4Addr::LOCALHOST))] - pub auth_addr: IpAddr, - - /// Auth server port to listen on - #[arg(long = "authrpc.port", default_value_t = constants::DEFAULT_AUTH_PORT)] - pub auth_port: u16, - - /// Path to a JWT secret to use for the authenticated engine-API RPC server. - /// - /// This will enforce JWT authentication for all requests coming from the consensus layer. - /// - /// 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)] - pub auth_jwtsecret: Option, - - /// Hex encoded JWT secret to authenticate the regular RPC server(s), see `--http.api` and - /// `--ws.api`. - /// - /// 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)] - pub rpc_jwtsecret: Option, - - /// Set the maximum RPC request payload size for both HTTP and WS in megabytes. - #[arg(long, default_value_t = RPC_DEFAULT_MAX_REQUEST_SIZE_MB.into())] - pub rpc_max_request_size: MaxU32, - - /// Set the maximum RPC response payload size for both HTTP and WS in megabytes. - #[arg(long, visible_alias = "--rpc.returndata.limit", default_value_t = RPC_DEFAULT_MAX_RESPONSE_SIZE_MB.into())] - pub rpc_max_response_size: MaxU32, - - /// Set the the maximum concurrent subscriptions per connection. - #[arg(long, default_value_t = RPC_DEFAULT_MAX_SUBS_PER_CONN.into())] - pub rpc_max_subscriptions_per_connection: MaxU32, - - /// Maximum number of RPC server connections. - #[arg(long, value_name = "COUNT", default_value_t = RPC_DEFAULT_MAX_CONNECTIONS.into())] - pub rpc_max_connections: MaxU32, - - /// Maximum number of concurrent tracing requests. - #[arg(long, value_name = "COUNT", default_value_t = constants::DEFAULT_MAX_TRACING_REQUESTS)] - pub rpc_max_tracing_requests: u32, - - /// Maximum number of blocks that could be scanned per filter request. (0 = entire chain) - #[arg(long, value_name = "COUNT", default_value_t = ZeroAsNoneU64::new(constants::DEFAULT_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, value_name = "COUNT", default_value_t = ZeroAsNoneU64::new(constants::DEFAULT_MAX_LOGS_PER_RESPONSE as u64))] - pub rpc_max_logs_per_response: ZeroAsNoneU64, - - /// Maximum gas limit for `eth_call` and call tracing RPC methods. - #[arg( - long, - alias = "rpc.gascap", - value_name = "GAS_CAP", - value_parser = RangedU64ValueParser::::new().range(1..), - default_value_t = RPC_DEFAULT_GAS_CAP.into() - )] - pub rpc_gas_cap: u64, - - /// State cache configuration. - #[clap(flatten)] - pub rpc_state_cache: RpcStateCacheArgs, - - /// Gas price oracle configuration. - #[clap(flatten)] - pub gas_price_oracle: GasPriceOracleArgs, -} - -impl RpcServerArgs { - /// Enables the HTTP-RPC server. - pub fn with_http(mut self) -> Self { - self.http = true; - self - } - - /// Enables the WS-RPC server. - pub fn with_ws(mut self) -> Self { - self.ws = true; - self - } - - /// Change rpc port numbers based on the instance number. - /// * The `auth_port` is scaled by a factor of `instance * 100` - /// * The `http_port` is scaled by a factor of `-instance` - /// * The `ws_port` is scaled by a factor of `instance * 2` - /// * The `ipcpath` is appended with the instance number: `/tmp/reth.ipc-` - /// - /// # Panics - /// Warning: if `instance` is zero in debug mode, this will panic. - /// - /// This will also panic in debug mode if either: - /// * `instance` is greater than `655` (scaling would overflow `u16`) - /// * `self.auth_port / 100 + (instance - 1)` would overflow `u16` - /// - /// In release mode, this will silently wrap around. - pub fn adjust_instance_ports(&mut self, instance: u16) { - debug_assert_ne!(instance, 0, "instance must be non-zero"); - // auth port is scaled by a factor of instance * 100 - self.auth_port += instance * 100 - 100; - // http port is scaled by a factor of -instance - self.http_port -= instance - 1; - // ws port is scaled by a factor of instance * 2 - self.ws_port += instance * 2 - 2; - - // also adjust the ipc path by appending the instance number to the path used for the - // endpoint - self.ipcpath = format!("{}-{}", self.ipcpath, instance); - } - - /// Set the http port to zero, to allow the OS to assign a random unused port when the rpc - /// server binds to a socket. - pub fn with_http_unused_port(mut self) -> Self { - self.http_port = 0; - self - } - - /// Set the ws port to zero, to allow the OS to assign a random unused port when the rpc - /// server binds to a socket. - pub fn with_ws_unused_port(mut self) -> Self { - self.ws_port = 0; - self - } - - /// Set the auth port to zero, to allow the OS to assign a random unused port when the rpc - /// server binds to a socket. - pub fn with_auth_unused_port(mut self) -> Self { - self.auth_port = 0; - self - } - - /// Append a random string to the ipc path, to prevent possible collisions when multiple nodes - /// are being run on the same machine. - pub fn with_ipc_random_path(mut self) -> Self { - let random_string: String = rand::thread_rng() - .sample_iter(rand::distributions::Alphanumeric) - .take(8) - .map(char::from) - .collect(); - self.ipcpath = format!("{}-{}", self.ipcpath, random_string); - self - } - - /// Configure all ports to be set to a random unused port when bound, and set the IPC path to a - /// random path. - pub fn with_unused_ports(mut self) -> Self { - self = self.with_http_unused_port(); - self = self.with_ws_unused_port(); - self = self.with_auth_unused_port(); - self = self.with_ipc_random_path(); - self - } - - /// Configures and launches _all_ servers. - /// - /// Returns the handles for the launched regular RPC server(s) (if any) and the server handle - /// for the auth server that handles the `engine_` API that's accessed by the consensus - /// layer. - pub async fn start_servers( - &self, - components: &Reth, - engine_api: Engine, - jwt_secret: JwtSecret, - conf: &mut Conf, - ) -> eyre::Result - where - Reth: RethNodeComponents, - Engine: EngineApiServer, - Conf: RethNodeCommandConfig, - { - let auth_config = self.auth_server_config(jwt_secret)?; - - let module_config = self.transport_rpc_module_config(); - debug!(target: "reth::cli", http=?module_config.http(), ws=?module_config.ws(), "Using RPC module config"); - - let (mut modules, mut auth_module, mut registry) = RpcModuleBuilder::default() - .with_provider(components.provider()) - .with_pool(components.pool()) - .with_network(components.network()) - .with_events(components.events()) - .with_executor(components.task_executor()) - .build_with_auth_server(module_config, engine_api); - - let rpc_components = RethRpcComponents { - registry: &mut registry, - modules: &mut modules, - auth_module: &mut auth_module, - }; - // apply configured customization - conf.extend_rpc_modules(self, components, rpc_components)?; - - let server_config = self.rpc_server_config(); - let launch_rpc = modules.clone().start_server(server_config).map_ok(|handle| { - if let Some(url) = handle.ipc_endpoint() { - info!(target: "reth::cli", url=%url, "RPC IPC server started"); - } - if let Some(addr) = handle.http_local_addr() { - info!(target: "reth::cli", url=%addr, "RPC HTTP server started"); - } - if let Some(addr) = handle.ws_local_addr() { - info!(target: "reth::cli", url=%addr, "RPC WS server started"); - } - handle - }); - - let launch_auth = auth_module.clone().start_server(auth_config).map_ok(|handle| { - let addr = handle.local_addr(); - info!(target: "reth::cli", url=%addr, "RPC auth server started"); - handle - }); - - // launch servers concurrently - let (rpc, auth) = futures::future::try_join(launch_rpc, launch_auth).await?; - let handles = RethRpcServerHandles { rpc, auth }; - - // call hook - let rpc_components = RethRpcComponents { - registry: &mut registry, - modules: &mut modules, - auth_module: &mut auth_module, - }; - conf.on_rpc_server_started(self, components, rpc_components, handles.clone())?; - - Ok(handles) - } - - /// Convenience function for starting a rpc server with configs which extracted from cli args. - pub async fn start_rpc_server( - &self, - provider: Provider, - pool: Pool, - network: Network, - executor: Tasks, - events: Events, - ) -> Result - where - Provider: BlockReaderIdExt - + AccountReader - + HeaderProvider - + StateProviderFactory - + EvmEnvProvider - + ChainSpecProvider - + ChangeSetReader - + Clone - + Unpin - + 'static, - Pool: TransactionPool + Clone + 'static, - Network: NetworkInfo + Peers + Clone + 'static, - Tasks: TaskSpawner + Clone + 'static, - Events: CanonStateSubscriptions + Clone + 'static, - { - reth_rpc_builder::launch( - provider, - pool, - network, - self.transport_rpc_module_config(), - self.rpc_server_config(), - executor, - events, - ) - .await - } - - /// Create Engine API server. - pub async fn start_auth_server( - &self, - provider: Provider, - pool: Pool, - network: Network, - executor: Tasks, - engine_api: EngineApi, - jwt_secret: JwtSecret, - ) -> Result - where - Provider: BlockReaderIdExt - + ChainSpecProvider - + EvmEnvProvider - + HeaderProvider - + StateProviderFactory - + Clone - + Unpin - + 'static, - Pool: TransactionPool + Clone + 'static, - Network: NetworkInfo + Peers + Clone + 'static, - Tasks: TaskSpawner + Clone + 'static, - EngineT: EngineTypes + 'static, - { - let socket_address = SocketAddr::new(self.auth_addr, self.auth_port); - - reth_rpc_builder::auth::launch( - provider, - pool, - network, - executor, - engine_api, - socket_address, - jwt_secret, - ) - .await - } -} - -impl RethRpcConfig for RpcServerArgs { - fn is_ipc_enabled(&self) -> bool { - // By default IPC is enabled therefor it is enabled if the `ipcdisable` is false. - !self.ipcdisable - } - - fn ipc_path(&self) -> &str { - self.ipcpath.as_str() - } - - fn eth_config(&self) -> EthConfig { - EthConfig::default() - .max_tracing_requests(self.rpc_max_tracing_requests) - .max_blocks_per_filter(self.rpc_max_blocks_per_filter.unwrap_or_max()) - .max_logs_per_response(self.rpc_max_logs_per_response.unwrap_or_max() as usize) - .rpc_gas_cap(self.rpc_gas_cap) - .state_cache(self.state_cache_config()) - .gpo_config(self.gas_price_oracle_config()) - } - - fn state_cache_config(&self) -> EthStateCacheConfig { - EthStateCacheConfig { - max_blocks: self.rpc_state_cache.max_blocks, - max_receipts: self.rpc_state_cache.max_receipts, - max_envs: self.rpc_state_cache.max_envs, - max_concurrent_db_requests: self.rpc_state_cache.max_concurrent_db_requests, - } - } - - fn rpc_max_request_size_bytes(&self) -> u32 { - self.rpc_max_request_size.get().saturating_mul(1024 * 1024) - } - - fn rpc_max_response_size_bytes(&self) -> u32 { - self.rpc_max_response_size.get().saturating_mul(1024 * 1024) - } - - fn gas_price_oracle_config(&self) -> GasPriceOracleConfig { - self.gas_price_oracle.gas_price_oracle_config() - } - - fn transport_rpc_module_config(&self) -> TransportRpcModuleConfig { - let mut config = TransportRpcModuleConfig::default() - .with_config(RpcModuleConfig::new(self.eth_config())); - - if self.http { - config = config.with_http( - self.http_api - .clone() - .unwrap_or_else(|| RpcModuleSelection::standard_modules().into()), - ); - } - - if self.ws { - config = config.with_ws( - self.ws_api - .clone() - .unwrap_or_else(|| RpcModuleSelection::standard_modules().into()), - ); - } - - if self.is_ipc_enabled() { - config = config.with_ipc(RpcModuleSelection::default_ipc_modules()); - } - - config - } - - fn http_ws_server_builder(&self) -> ServerBuilder { - ServerBuilder::new() - .max_connections(self.rpc_max_connections.get()) - .max_request_body_size(self.rpc_max_request_size_bytes()) - .max_response_body_size(self.rpc_max_response_size_bytes()) - .max_subscriptions_per_connection(self.rpc_max_subscriptions_per_connection.get()) - } - - fn ipc_server_builder(&self) -> IpcServerBuilder { - IpcServerBuilder::default() - .max_subscriptions_per_connection(self.rpc_max_subscriptions_per_connection.get()) - .max_request_body_size(self.rpc_max_request_size_bytes()) - .max_response_body_size(self.rpc_max_response_size_bytes()) - .max_connections(self.rpc_max_connections.get()) - } - - fn rpc_server_config(&self) -> RpcServerConfig { - let mut config = RpcServerConfig::default().with_jwt_secret(self.rpc_secret_key()); - - if self.http { - let socket_address = SocketAddr::new(self.http_addr, self.http_port); - config = config - .with_http_address(socket_address) - .with_http(self.http_ws_server_builder()) - .with_http_cors(self.http_corsdomain.clone()) - .with_ws_cors(self.ws_allowed_origins.clone()); - } - - if self.ws { - let socket_address = SocketAddr::new(self.ws_addr, self.ws_port); - config = config.with_ws_address(socket_address).with_ws(self.http_ws_server_builder()); - } - - if self.is_ipc_enabled() { - config = - config.with_ipc(self.ipc_server_builder()).with_ipc_endpoint(self.ipcpath.clone()); - } - - config - } - - fn auth_server_config(&self, jwt_secret: JwtSecret) -> Result { - let address = SocketAddr::new(self.auth_addr, self.auth_port); - - Ok(AuthServerConfig::builder(jwt_secret).socket_addr(address).build()) - } - - fn auth_jwt_secret(&self, default_jwt_path: PathBuf) -> Result { - match self.auth_jwtsecret.as_ref() { - Some(fpath) => { - debug!(target: "reth::cli", user_path=?fpath, "Reading JWT auth secret file"); - JwtSecret::from_file(fpath) - } - None => get_or_create_jwt_secret_from_path(&default_jwt_path), - } - } - - fn rpc_secret_key(&self) -> Option { - self.rpc_jwtsecret.clone() - } -} - -impl Default for RpcServerArgs { - fn default() -> Self { - Self { - http: false, - http_addr: Ipv4Addr::LOCALHOST.into(), - http_port: constants::DEFAULT_HTTP_RPC_PORT, - 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(), - auth_addr: Ipv4Addr::LOCALHOST.into(), - auth_port: constants::DEFAULT_AUTH_PORT, - auth_jwtsecret: None, - 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_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: RPC_DEFAULT_GAS_CAP.into(), - gas_price_oracle: GasPriceOracleArgs::default(), - rpc_state_cache: RpcStateCacheArgs::default(), - } - } -} - -/// clap value parser for [RpcModuleSelection]. -#[derive(Clone, Debug, Default)] -#[non_exhaustive] -struct RpcModuleSelectionValueParser; - -impl TypedValueParser for RpcModuleSelectionValueParser { - type Value = RpcModuleSelection; - - fn parse_ref( - &self, - _cmd: &Command, - arg: Option<&Arg>, - value: &OsStr, - ) -> Result { - let val = - value.to_str().ok_or_else(|| clap::Error::new(clap::error::ErrorKind::InvalidUtf8))?; - val.parse::().map_err(|err| { - let arg = arg.map(|a| a.to_string()).unwrap_or_else(|| "...".to_owned()); - let possible_values = RethRpcModule::all_variants().to_vec().join(","); - let msg = format!( - "Invalid value '{val}' for {arg}: {err}.\n [possible values: {possible_values}]" - ); - clap::Error::raw(clap::error::ErrorKind::InvalidValue, msg) - }) - } - - fn possible_values(&self) -> Option + '_>> { - let values = RethRpcModule::all_variants().iter().map(PossibleValue::new); - Some(Box::new(values)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use clap::Parser; - use reth_rpc_builder::RpcModuleSelection::Selection; - use std::net::SocketAddrV4; - - /// A helper type to parse Args more easily - #[derive(Parser)] - struct CommandParser { - #[clap(flatten)] - args: T, - } - - #[test] - fn test_rpc_gas_cap() { - let args = CommandParser::::parse_from(["reth"]).args; - let config = args.eth_config(); - assert_eq!(config.rpc_gas_cap, Into::::into(RPC_DEFAULT_GAS_CAP)); - - let args = - CommandParser::::parse_from(["reth", "--rpc.gascap", "1000"]).args; - let config = args.eth_config(); - assert_eq!(config.rpc_gas_cap, 1000); - - let args = CommandParser::::try_parse_from(["reth", "--rpc.gascap", "0"]); - assert!(args.is_err()); - } - - #[test] - fn test_rpc_server_args_parser() { - let args = - CommandParser::::parse_from(["reth", "--http.api", "eth,admin,debug"]) - .args; - - let apis = args.http_api.unwrap(); - let expected = RpcModuleSelection::try_from_selection(["eth", "admin", "debug"]).unwrap(); - - assert_eq!(apis, expected); - } - - #[test] - fn test_rpc_server_eth_call_bundle_args() { - let args = CommandParser::::parse_from([ - "reth", - "--http.api", - "eth,admin,debug,eth-call-bundle", - ]) - .args; - - let apis = args.http_api.unwrap(); - let expected = - RpcModuleSelection::try_from_selection(["eth", "admin", "debug", "eth-call-bundle"]) - .unwrap(); - - assert_eq!(apis, expected); - } - - #[test] - fn test_rpc_server_args_parser_none() { - let args = CommandParser::::parse_from(["reth", "--http.api", "none"]).args; - let apis = args.http_api.unwrap(); - let expected = Selection(vec![]); - assert_eq!(apis, expected); - } - - #[test] - fn test_transport_rpc_module_config() { - let args = CommandParser::::parse_from([ - "reth", - "--http.api", - "eth,admin,debug", - "--http", - "--ws", - ]) - .args; - let config = args.transport_rpc_module_config(); - let expected = vec![RethRpcModule::Eth, RethRpcModule::Admin, RethRpcModule::Debug]; - assert_eq!(config.http().cloned().unwrap().into_selection(), expected); - assert_eq!( - config.ws().cloned().unwrap().into_selection(), - RpcModuleSelection::standard_modules() - ); - } - - #[test] - fn test_transport_rpc_module_trim_config() { - let args = CommandParser::::parse_from([ - "reth", - "--http.api", - " eth, admin, debug", - "--http", - "--ws", - ]) - .args; - let config = args.transport_rpc_module_config(); - let expected = vec![RethRpcModule::Eth, RethRpcModule::Admin, RethRpcModule::Debug]; - assert_eq!(config.http().cloned().unwrap().into_selection(), expected); - assert_eq!( - config.ws().cloned().unwrap().into_selection(), - RpcModuleSelection::standard_modules() - ); - } - - #[test] - fn test_unique_rpc_modules() { - let args = CommandParser::::parse_from([ - "reth", - "--http.api", - " eth, admin, debug, eth,admin", - "--http", - "--ws", - ]) - .args; - let config = args.transport_rpc_module_config(); - let expected = vec![RethRpcModule::Eth, RethRpcModule::Admin, RethRpcModule::Debug]; - assert_eq!(config.http().cloned().unwrap().into_selection(), expected); - assert_eq!( - config.ws().cloned().unwrap().into_selection(), - RpcModuleSelection::standard_modules() - ); - } - - #[test] - fn test_rpc_server_config() { - let args = CommandParser::::parse_from([ - "reth", - "--http.api", - "eth,admin,debug", - "--http", - "--ws", - "--ws.addr", - "127.0.0.1", - "--ws.port", - "8888", - ]) - .args; - let config = args.rpc_server_config(); - assert_eq!( - config.http_address().unwrap(), - SocketAddr::V4(SocketAddrV4::new( - Ipv4Addr::LOCALHOST, - constants::DEFAULT_HTTP_RPC_PORT - )) - ); - assert_eq!( - config.ws_address().unwrap(), - SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8888)) - ); - assert_eq!(config.ipc_endpoint().unwrap().path(), constants::DEFAULT_IPC_ENDPOINT); - } - - #[test] - fn test_zero_filter_limits() { - let args = CommandParser::::parse_from([ - "reth", - "--rpc-max-blocks-per-filter", - "0", - "--rpc-max-logs-per-response", - "0", - ]) - .args; - - let config = args.eth_config().filter_config(); - assert_eq!(config.max_blocks_per_filter, Some(u64::MAX)); - assert_eq!(config.max_logs_per_response, Some(usize::MAX)); - } - - #[test] - fn test_custom_filter_limits() { - let args = CommandParser::::parse_from([ - "reth", - "--rpc-max-blocks-per-filter", - "100", - "--rpc-max-logs-per-response", - "200", - ]) - .args; - - let config = args.eth_config().filter_config(); - assert_eq!(config.max_blocks_per_filter, Some(100)); - assert_eq!(config.max_logs_per_response, Some(200)); - } - - #[test] - fn rpc_server_args_default_sanity_test() { - let default_args = RpcServerArgs::default(); - let args = CommandParser::::parse_from(["reth"]).args; - - assert_eq!(args, default_args); - } -} diff --git a/bin/reth/src/args/rpc_state_cache_args.rs b/bin/reth/src/args/rpc_state_cache_args.rs deleted file mode 100644 index df909dbbd4..0000000000 --- a/bin/reth/src/args/rpc_state_cache_args.rs +++ /dev/null @@ -1,50 +0,0 @@ -use clap::Args; -use reth_rpc::eth::cache::{ - DEFAULT_BLOCK_CACHE_MAX_LEN, DEFAULT_CONCURRENT_DB_REQUESTS, DEFAULT_ENV_CACHE_MAX_LEN, - DEFAULT_RECEIPT_CACHE_MAX_LEN, -}; - -/// Parameters to configure RPC state cache. -#[derive(Debug, Clone, Args, PartialEq, Eq)] -#[clap(next_help_heading = "RPC State Cache")] - -pub struct RpcStateCacheArgs { - /// Max number of blocks in cache. - #[arg( - long = "rpc-cache.max-blocks", - default_value_t = DEFAULT_BLOCK_CACHE_MAX_LEN, - )] - pub max_blocks: u32, - - /// Max number receipts in cache. - #[arg( - long = "rpc-cache.max-receipts", - default_value_t = DEFAULT_RECEIPT_CACHE_MAX_LEN, - )] - pub max_receipts: u32, - - /// Max number of bytes for cached env data. - #[arg( - long = "rpc-cache.max-envs", - default_value_t = DEFAULT_ENV_CACHE_MAX_LEN, - )] - pub max_envs: u32, - - /// Max number of concurrent database requests. - #[arg( - long = "rpc-cache.max-concurrent-db-requests", - default_value_t = DEFAULT_CONCURRENT_DB_REQUESTS, - )] - pub max_concurrent_db_requests: usize, -} - -impl Default for RpcStateCacheArgs { - fn default() -> Self { - Self { - max_blocks: DEFAULT_BLOCK_CACHE_MAX_LEN, - max_receipts: DEFAULT_RECEIPT_CACHE_MAX_LEN, - max_envs: DEFAULT_ENV_CACHE_MAX_LEN, - max_concurrent_db_requests: DEFAULT_CONCURRENT_DB_REQUESTS, - } - } -} diff --git a/bin/reth/src/args/secret_key.rs b/bin/reth/src/args/secret_key.rs deleted file mode 100644 index e08f8caaf2..0000000000 --- a/bin/reth/src/args/secret_key.rs +++ /dev/null @@ -1,59 +0,0 @@ -use reth_network::config::rng_secret_key; -use reth_primitives::{fs, fs::FsPathError, hex::encode as hex_encode}; -use secp256k1::{Error as SecretKeyBaseError, SecretKey}; -use std::{ - io, - path::{Path, PathBuf}, -}; -use thiserror::Error; - -/// Errors returned by loading a [`SecretKey`], including IO errors. -#[derive(Error, Debug)] -pub enum SecretKeyError { - /// Error encountered during decoding of the secret key. - #[error(transparent)] - SecretKeyDecodeError(#[from] SecretKeyBaseError), - - /// Error related to file system path operations. - #[error(transparent)] - SecretKeyFsPathError(#[from] FsPathError), - - /// Represents an error when failed to access the key file. - #[error("failed to access key file {secret_file:?}: {error}")] - FailedToAccessKeyFile { - /// The encountered IO error. - error: io::Error, - /// Path to the secret key file. - secret_file: PathBuf, - }, -} - -/// Attempts to load a [`SecretKey`] from a specified path. If no file exists there, then it -/// generates a secret key and stores it in the provided path. I/O errors might occur during write -/// operations in the form of a [`SecretKeyError`] -pub fn get_secret_key(secret_key_path: &Path) -> Result { - let exists = secret_key_path.try_exists(); - - match exists { - Ok(true) => { - let contents = fs::read_to_string(secret_key_path)?; - Ok((contents.as_str().parse::()) - .map_err(SecretKeyError::SecretKeyDecodeError)?) - } - Ok(false) => { - if let Some(dir) = secret_key_path.parent() { - // Create parent directory - fs::create_dir_all(dir)?; - } - - let secret = rng_secret_key(); - let hex = hex_encode(secret.as_ref()); - fs::write(secret_key_path, hex)?; - Ok(secret) - } - Err(error) => Err(SecretKeyError::FailedToAccessKeyFile { - error, - secret_file: secret_key_path.to_path_buf(), - }), - } -} diff --git a/bin/reth/src/args/stage_args.rs b/bin/reth/src/args/stage_args.rs deleted file mode 100644 index 46618ff2f7..0000000000 --- a/bin/reth/src/args/stage_args.rs +++ /dev/null @@ -1,56 +0,0 @@ -//! Shared arguments related to stages - -/// Represents a specific stage within the data pipeline. -/// -/// Different stages within the pipeline have dedicated functionalities and operations. -#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, clap::ValueEnum)] -pub enum StageEnum { - /// The headers stage within the pipeline. - /// - /// This stage handles operations related to block headers. - Headers, - /// The bodies stage within the pipeline. - /// - /// This stage deals with block bodies and their associated data. - Bodies, - /// The senders stage within the pipeline. - /// - /// Responsible for sender-related processes and data recovery. - Senders, - /// The execution stage within the pipeline. - /// - /// Handles the execution of transactions and contracts. - Execution, - /// The account hashing stage within the pipeline. - /// - /// Manages operations related to hashing account data. - AccountHashing, - /// The storage hashing stage within the pipeline. - /// - /// Manages operations related to hashing storage data. - StorageHashing, - /// The hashing stage within the pipeline. - /// - /// Covers general data hashing operations. - Hashing, - /// The Merkle stage within the pipeline. - /// - /// Handles Merkle tree-related computations and data processing. - Merkle, - /// The transaction lookup stage within the pipeline. - /// - /// Deals with the retrieval and processing of transactions. - TxLookup, - /// The account history stage within the pipeline. - /// - /// Manages historical data related to accounts. - AccountHistory, - /// The storage history stage within the pipeline. - /// - /// Manages historical data related to storage. - StorageHistory, - /// The total difficulty stage within the pipeline. - /// - /// Handles computations and data related to total difficulty. - TotalDifficulty, -} diff --git a/bin/reth/src/args/txpool_args.rs b/bin/reth/src/args/txpool_args.rs deleted file mode 100644 index 7c7d718649..0000000000 --- a/bin/reth/src/args/txpool_args.rs +++ /dev/null @@ -1,124 +0,0 @@ -//! Transaction pool arguments - -use crate::cli::config::RethTransactionPoolConfig; -use clap::Args; -use reth_primitives::Address; -use reth_transaction_pool::{ - LocalTransactionConfig, PoolConfig, PriceBumpConfig, SubPoolLimit, DEFAULT_PRICE_BUMP, - REPLACE_BLOB_PRICE_BUMP, TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER, - TXPOOL_SUBPOOL_MAX_SIZE_MB_DEFAULT, TXPOOL_SUBPOOL_MAX_TXS_DEFAULT, -}; -/// Parameters for debugging purposes -#[derive(Debug, Args, PartialEq)] -#[clap(next_help_heading = "TxPool")] -pub struct TxPoolArgs { - /// Max number of transaction in the pending sub-pool. - #[arg(long = "txpool.pending_max_count", default_value_t = TXPOOL_SUBPOOL_MAX_TXS_DEFAULT)] - pub pending_max_count: usize, - /// Max size of the pending sub-pool in megabytes. - #[arg(long = "txpool.pending_max_size", default_value_t = TXPOOL_SUBPOOL_MAX_SIZE_MB_DEFAULT)] - pub pending_max_size: usize, - - /// Max number of transaction in the basefee sub-pool - #[arg(long = "txpool.basefee_max_count", default_value_t = TXPOOL_SUBPOOL_MAX_TXS_DEFAULT)] - pub basefee_max_count: usize, - /// Max size of the basefee sub-pool in megabytes. - #[arg(long = "txpool.basefee_max_size", default_value_t = TXPOOL_SUBPOOL_MAX_SIZE_MB_DEFAULT)] - pub basefee_max_size: usize, - - /// Max number of transaction in the queued sub-pool - #[arg(long = "txpool.queued_max_count", default_value_t = TXPOOL_SUBPOOL_MAX_TXS_DEFAULT)] - pub queued_max_count: usize, - /// Max size of the queued sub-pool in megabytes. - #[arg(long = "txpool.queued_max_size", default_value_t = TXPOOL_SUBPOOL_MAX_SIZE_MB_DEFAULT)] - pub queued_max_size: usize, - - /// Max number of executable transaction slots guaranteed per account - #[arg(long = "txpool.max_account_slots", default_value_t = TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER)] - pub max_account_slots: usize, - - /// Price bump (in %) for the transaction pool underpriced check. - #[arg(long = "txpool.pricebump", default_value_t = DEFAULT_PRICE_BUMP)] - pub price_bump: u128, - - /// Price bump percentage to replace an already existing blob transaction - #[arg(long = "blobpool.pricebump", default_value_t = REPLACE_BLOB_PRICE_BUMP)] - pub blob_transaction_price_bump: u128, - /// Flag to disable local transaction exemptions. - #[arg(long = "txpool.nolocals")] - pub no_locals: bool, - /// Flag to allow certain addresses as local - #[arg(long = "txpool.locals")] - pub locals: Vec
, -} - -impl Default for TxPoolArgs { - fn default() -> Self { - Self { - pending_max_count: TXPOOL_SUBPOOL_MAX_TXS_DEFAULT, - pending_max_size: TXPOOL_SUBPOOL_MAX_SIZE_MB_DEFAULT, - basefee_max_count: TXPOOL_SUBPOOL_MAX_TXS_DEFAULT, - basefee_max_size: TXPOOL_SUBPOOL_MAX_SIZE_MB_DEFAULT, - queued_max_count: TXPOOL_SUBPOOL_MAX_TXS_DEFAULT, - queued_max_size: TXPOOL_SUBPOOL_MAX_SIZE_MB_DEFAULT, - max_account_slots: TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER, - price_bump: DEFAULT_PRICE_BUMP, - blob_transaction_price_bump: REPLACE_BLOB_PRICE_BUMP, - no_locals: false, - locals: Default::default(), - } - } -} - -impl RethTransactionPoolConfig for TxPoolArgs { - /// Returns transaction pool configuration. - fn pool_config(&self) -> PoolConfig { - PoolConfig { - local_transactions_config: LocalTransactionConfig { - no_exemptions: self.no_locals, - local_addresses: self.locals.clone().into_iter().collect(), - }, - pending_limit: SubPoolLimit { - max_txs: self.pending_max_count, - max_size: self.pending_max_size * 1024 * 1024, - }, - basefee_limit: SubPoolLimit { - max_txs: self.basefee_max_count, - max_size: self.basefee_max_size * 1024 * 1024, - }, - queued_limit: SubPoolLimit { - max_txs: self.queued_max_count, - max_size: self.queued_max_size * 1024 * 1024, - }, - blob_limit: SubPoolLimit { - max_txs: self.queued_max_count, - max_size: self.queued_max_size * 1024 * 1024, - }, - max_account_slots: self.max_account_slots, - price_bumps: PriceBumpConfig { - default_price_bump: self.price_bump, - replace_blob_tx_price_bump: self.blob_transaction_price_bump, - }, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use clap::Parser; - - /// A helper type to parse Args more easily - #[derive(Parser)] - struct CommandParser { - #[clap(flatten)] - args: T, - } - - #[test] - fn txpool_args_default_sanity_test() { - let default_args = TxPoolArgs::default(); - let args = CommandParser::::parse_from(["reth"]).args; - assert_eq!(args, default_args); - } -} diff --git a/bin/reth/src/args/types.rs b/bin/reth/src/args/types.rs deleted file mode 100644 index b7fcbe5298..0000000000 --- a/bin/reth/src/args/types.rs +++ /dev/null @@ -1,120 +0,0 @@ -//! Additional helper types for CLI parsing. - -use std::{fmt, num::ParseIntError, str::FromStr}; - -/// A macro that generates types that maps "0" to "None" when parsing CLI arguments. - -macro_rules! zero_as_none { - ($type_name:ident, $inner_type:ty) => { - #[derive(Debug, Clone, Copy, PartialEq, Eq)] - /// A helper type that maps `0` to `None` when parsing CLI arguments. - pub struct $type_name(pub Option<$inner_type>); - - impl $type_name { - /// Returns the inner value. - pub const fn new(value: $inner_type) -> Self { - Self(Some(value)) - } - - /// Returns the inner value or `$inner_type::MAX` if `None`. - pub fn unwrap_or_max(self) -> $inner_type { - self.0.unwrap_or(<$inner_type>::MAX) - } - } - - impl std::fmt::Display for $type_name { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self.0 { - Some(value) => write!(f, "{}", value), - None => write!(f, "0"), - } - } - } - - impl From<$inner_type> for $type_name { - #[inline] - fn from(value: $inner_type) -> Self { - Self(if value == 0 { None } else { Some(value) }) - } - } - - impl std::str::FromStr for $type_name { - type Err = std::num::ParseIntError; - - fn from_str(s: &str) -> Result { - let value = s.parse::<$inner_type>()?; - Ok(Self::from(value)) - } - } - }; -} - -zero_as_none!(ZeroAsNoneU64, u64); -zero_as_none!(ZeroAsNoneU32, u32); - -/// A macro that generates types that map "max" to "MAX" when parsing CLI arguments. -macro_rules! max_values { - ($name:ident, $ty:ident) => { - #[derive(Debug, Clone, Copy, PartialEq, Eq)] - /// A helper type for parsing "max" as the maximum value of the specified type. - - pub struct $name(pub $ty); - - impl $name { - /// Returns the inner value. - pub const fn get(&self) -> $ty { - self.0 - } - } - - impl fmt::Display for $name { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } - } - - impl From<$ty> for $name { - #[inline] - fn from(value: $ty) -> Self { - Self(value) - } - } - - impl FromStr for $name { - type Err = ParseIntError; - - fn from_str(s: &str) -> Result { - if s.eq_ignore_ascii_case("max") { - Ok($name(<$ty>::MAX)) - } else { - s.parse::<$ty>().map($name) - } - } - } - }; -} -max_values!(MaxU32, u32); -max_values!(MaxU64, u64); - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_zero_parse() { - let val = "0".parse::().unwrap(); - assert_eq!(val, ZeroAsNoneU64(None)); - assert_eq!(val.unwrap_or_max(), u64::MAX); - } - - #[test] - fn test_from_u64() { - let original = 1u64; - let expected = ZeroAsNoneU64(Some(1u64)); - assert_eq!(ZeroAsNoneU64::from(original), expected); - - let original = 0u64; - let expected = ZeroAsNoneU64(None); - assert_eq!(ZeroAsNoneU64::from(original), expected); - } -} diff --git a/bin/reth/src/args/utils.rs b/bin/reth/src/args/utils.rs deleted file mode 100644 index 080aa5c0a2..0000000000 --- a/bin/reth/src/args/utils.rs +++ /dev/null @@ -1,292 +0,0 @@ -//! Clap parser utilities - -use reth_primitives::{fs, AllGenesisFormats, BlockHashOrNumber, ChainSpec, B256}; -use std::{ - net::{IpAddr, Ipv4Addr, SocketAddr, ToSocketAddrs}, - path::PathBuf, - str::FromStr, - sync::Arc, - time::Duration, -}; - -#[cfg(feature = "optimism")] -use reth_primitives::{BASE_GOERLI, BASE_MAINNET, BASE_SEPOLIA}; - -#[cfg(not(feature = "optimism"))] -use reth_primitives::{DEV, GOERLI, HOLESKY, MAINNET, SEPOLIA}; - -#[cfg(feature = "optimism")] -/// Chains supported by op-reth. First value should be used as the default. -pub const SUPPORTED_CHAINS: &[&str] = &["base", "base-goerli", "base-sepolia"]; -#[cfg(not(feature = "optimism"))] -/// Chains supported by reth. First value should be used as the default. -pub const SUPPORTED_CHAINS: &[&str] = &["mainnet", "sepolia", "goerli", "holesky", "dev"]; - -/// Helper to parse a [Duration] from seconds -pub fn parse_duration_from_secs(arg: &str) -> eyre::Result { - let seconds = arg.parse()?; - Ok(Duration::from_secs(seconds)) -} - -/// Clap value parser for [ChainSpec]s that takes either a built-in chainspec or the path -/// to a custom one. -pub fn chain_spec_value_parser(s: &str) -> eyre::Result, eyre::Error> { - Ok(match s { - #[cfg(not(feature = "optimism"))] - "mainnet" => MAINNET.clone(), - #[cfg(not(feature = "optimism"))] - "goerli" => GOERLI.clone(), - #[cfg(not(feature = "optimism"))] - "sepolia" => SEPOLIA.clone(), - #[cfg(not(feature = "optimism"))] - "holesky" => HOLESKY.clone(), - #[cfg(not(feature = "optimism"))] - "dev" => DEV.clone(), - #[cfg(feature = "optimism")] - "base_goerli" | "base-goerli" => BASE_GOERLI.clone(), - #[cfg(feature = "optimism")] - "base_sepolia" | "base-sepolia" => BASE_SEPOLIA.clone(), - #[cfg(feature = "optimism")] - "base" => BASE_MAINNET.clone(), - _ => { - let raw = fs::read_to_string(PathBuf::from(shellexpand::full(s)?.into_owned()))?; - serde_json::from_str(&raw)? - } - }) -} - -/// The help info for the --chain flag -pub fn chain_help() -> String { - format!("The chain this node is running.\nPossible values are either a built-in chain or the path to a chain specification file.\n\nBuilt-in chains:\n {}", SUPPORTED_CHAINS.join(", ")) -} - -/// Clap value parser for [ChainSpec]s. -/// -/// The value parser matches either a known chain, the path -/// to a json file, or a json formatted string in-memory. The json can be either -/// a serialized [ChainSpec] or Genesis struct. -pub fn genesis_value_parser(s: &str) -> eyre::Result, eyre::Error> { - Ok(match s { - #[cfg(not(feature = "optimism"))] - "mainnet" => MAINNET.clone(), - #[cfg(not(feature = "optimism"))] - "goerli" => GOERLI.clone(), - #[cfg(not(feature = "optimism"))] - "sepolia" => SEPOLIA.clone(), - #[cfg(not(feature = "optimism"))] - "holesky" => HOLESKY.clone(), - #[cfg(not(feature = "optimism"))] - "dev" => DEV.clone(), - #[cfg(feature = "optimism")] - "base_goerli" | "base-goerli" => BASE_GOERLI.clone(), - #[cfg(feature = "optimism")] - "base_sepolia" | "base-sepolia" => BASE_SEPOLIA.clone(), - #[cfg(feature = "optimism")] - "base" => BASE_MAINNET.clone(), - _ => { - // try to read json from path first - let raw = match fs::read_to_string(PathBuf::from(shellexpand::full(s)?.into_owned())) { - Ok(raw) => raw, - Err(io_err) => { - // valid json may start with "\n", but must contain "{" - if s.contains('{') { - s.to_string() - } else { - return Err(io_err.into()) // assume invalid path - } - } - }; - - // both serialized Genesis and ChainSpec structs supported - let genesis: AllGenesisFormats = serde_json::from_str(&raw)?; - - Arc::new(genesis.into()) - } - }) -} - -/// Parse [BlockHashOrNumber] -pub fn hash_or_num_value_parser(value: &str) -> eyre::Result { - match B256::from_str(value) { - Ok(hash) => Ok(BlockHashOrNumber::Hash(hash)), - Err(_) => Ok(BlockHashOrNumber::Number(value.parse()?)), - } -} - -/// Error thrown while parsing a socket address. -#[derive(thiserror::Error, Debug)] -pub enum SocketAddressParsingError { - /// Failed to convert the string into a socket addr - #[error("could not parse socket address: {0}")] - Io(#[from] std::io::Error), - /// Input must not be empty - #[error("cannot parse socket address from empty string")] - Empty, - /// Failed to parse the address - #[error("could not parse socket address from {0}")] - Parse(String), - /// Failed to parse port - #[error("could not parse port: {0}")] - Port(#[from] std::num::ParseIntError), -} - -/// Parse a [SocketAddr] from a `str`. -/// -/// The following formats are checked: -/// -/// - If the value can be parsed as a `u16` or starts with `:` it is considered a port, and the -/// hostname is set to `localhost`. -/// - If the value contains `:` it is assumed to be the format `:` -/// - Otherwise it is assumed to be a hostname -/// -/// An error is returned if the value is empty. -pub fn parse_socket_address(value: &str) -> eyre::Result { - if value.is_empty() { - return Err(SocketAddressParsingError::Empty) - } - - if let Some(port) = value.strip_prefix(':').or_else(|| value.strip_prefix("localhost:")) { - let port: u16 = port.parse()?; - return Ok(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), port)) - } - if let Ok(port) = value.parse::() { - return Ok(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), port)) - } - value - .to_socket_addrs()? - .next() - .ok_or_else(|| SocketAddressParsingError::Parse(value.to_string())) -} - -#[cfg(test)] -mod tests { - use super::*; - use proptest::prelude::Rng; - use reth_primitives::{ - hex, Address, ChainConfig, ChainSpecBuilder, Genesis, GenesisAccount, U256, - }; - use secp256k1::rand::thread_rng; - use std::collections::HashMap; - - #[test] - fn parse_known_chain_spec() { - for chain in SUPPORTED_CHAINS { - chain_spec_value_parser(chain).unwrap(); - genesis_value_parser(chain).unwrap(); - } - } - - #[test] - fn parse_chain_spec_from_memory() { - let custom_genesis_from_json = r#" -{ - "nonce": "0x0", - "timestamp": "0x653FEE9E", - "gasLimit": "0x1388", - "difficulty": "0x0", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "coinbase": "0x0000000000000000000000000000000000000000", - "alloc": { - "0x6Be02d1d3665660d22FF9624b7BE0551ee1Ac91b": { - "balance": "0x21" - } - }, - "number": "0x0", - "gasUsed": "0x0", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "config": { - "chainId": 2600, - "homesteadBlock": 0, - "eip150Block": 0, - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "berlinBlock": 0, - "londonBlock": 0, - "terminalTotalDifficulty": 0, - "terminalTotalDifficultyPassed": true, - "shanghaiTime": 0 - } -} -"#; - - let chain_from_json = genesis_value_parser(custom_genesis_from_json).unwrap(); - - // using structs - let config = ChainConfig { - chain_id: 2600, - homestead_block: Some(0), - eip150_block: Some(0), - eip155_block: Some(0), - eip158_block: Some(0), - byzantium_block: Some(0), - constantinople_block: Some(0), - petersburg_block: Some(0), - istanbul_block: Some(0), - berlin_block: Some(0), - london_block: Some(0), - shanghai_time: Some(0), - terminal_total_difficulty: Some(U256::ZERO), - terminal_total_difficulty_passed: true, - ..Default::default() - }; - let genesis = Genesis { - config, - nonce: 0, - timestamp: 1698688670, - gas_limit: 5000, - difficulty: U256::ZERO, - mix_hash: B256::ZERO, - coinbase: Address::ZERO, - ..Default::default() - }; - - // seed accounts after genesis struct created - let address = hex!("6Be02d1d3665660d22FF9624b7BE0551ee1Ac91b").into(); - let account = GenesisAccount::default().with_balance(U256::from(33)); - let genesis = genesis.extend_accounts(HashMap::from([(address, account)])); - - let custom_genesis_from_struct = serde_json::to_string(&genesis).unwrap(); - let chain_from_struct = genesis_value_parser(&custom_genesis_from_struct).unwrap(); - assert_eq!(chain_from_json.genesis(), chain_from_struct.genesis()); - - // chain spec - let chain_spec = ChainSpecBuilder::default() - .chain(2600.into()) - .genesis(genesis) - .cancun_activated() - .build(); - - let chain_spec_json = serde_json::to_string(&chain_spec).unwrap(); - let custom_genesis_from_spec = genesis_value_parser(&chain_spec_json).unwrap(); - - assert_eq!(custom_genesis_from_spec.chain(), chain_from_struct.chain()); - } - - #[test] - fn parse_socket_addresses() { - for value in ["localhost:9000", ":9000", "9000"] { - let socket_addr = parse_socket_address(value) - .unwrap_or_else(|_| panic!("could not parse socket address: {value}")); - - assert!(socket_addr.ip().is_loopback()); - assert_eq!(socket_addr.port(), 9000); - } - } - - #[test] - fn parse_socket_address_random() { - let port: u16 = thread_rng().gen(); - - for value in [format!("localhost:{port}"), format!(":{port}"), port.to_string()] { - let socket_addr = parse_socket_address(&value) - .unwrap_or_else(|_| panic!("could not parse socket address: {value}")); - - assert!(socket_addr.ip().is_loopback()); - assert_eq!(socket_addr.port(), port); - } - } -} diff --git a/bin/reth/src/cli/components.rs b/bin/reth/src/cli/components.rs deleted file mode 100644 index ef5543910d..0000000000 --- a/bin/reth/src/cli/components.rs +++ /dev/null @@ -1,180 +0,0 @@ -//! Components that are used by the node command. - -use reth_network::{NetworkEvents, NetworkProtocols}; -use reth_network_api::{NetworkInfo, Peers}; -use reth_primitives::ChainSpec; -use reth_provider::{ - AccountReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader, - EvmEnvProvider, StateProviderFactory, -}; -use reth_rpc_builder::{ - auth::{AuthRpcModule, AuthServerHandle}, - RethModuleRegistry, RpcServerHandle, TransportRpcModules, -}; -use reth_tasks::TaskSpawner; -use reth_transaction_pool::TransactionPool; -use std::sync::Arc; - -/// Helper trait to unify all provider traits for simplicity. -pub trait FullProvider: - BlockReaderIdExt - + AccountReader - + StateProviderFactory - + EvmEnvProvider - + ChainSpecProvider - + ChangeSetReader - + Clone - + Unpin - + 'static -{ -} - -impl FullProvider for T where - T: BlockReaderIdExt - + AccountReader - + StateProviderFactory - + EvmEnvProvider - + ChainSpecProvider - + ChangeSetReader - + Clone - + Unpin - + 'static -{ -} - -/// The trait that is implemented for the Node command. -pub trait RethNodeComponents: Clone + Send + Sync + 'static { - /// The Provider type that is provided by the node itself - type Provider: FullProvider; - /// The transaction pool type - type Pool: TransactionPool + Clone + Unpin + 'static; - /// The network type used to communicate with p2p. - type Network: NetworkInfo + Peers + NetworkProtocols + NetworkEvents + Clone + 'static; - /// The events type used to create subscriptions. - type Events: CanonStateSubscriptions + Clone + 'static; - /// The type that is used to spawn tasks. - type Tasks: TaskSpawner + Clone + Unpin + 'static; - - /// Returns the instance of the provider - fn provider(&self) -> Self::Provider; - - /// Returns the instance of the task executor. - fn task_executor(&self) -> Self::Tasks; - - /// Returns the instance of the transaction pool. - fn pool(&self) -> Self::Pool; - - /// Returns the instance of the network API. - fn network(&self) -> Self::Network; - - /// Returns the instance of the events subscription handler. - fn events(&self) -> Self::Events; - - /// Helper function to return the chain spec. - fn chain_spec(&self) -> Arc { - self.provider().chain_spec() - } -} - -/// Helper container to encapsulate [RethModuleRegistry],[TransportRpcModules] and [AuthRpcModule]. -/// -/// This can be used to access installed modules, or create commonly used handlers like -/// [reth_rpc::EthApi], and ultimately merge additional rpc handler into the configured transport -/// modules [TransportRpcModules] as well as configured authenticated methods [AuthRpcModule]. -#[derive(Debug)] -#[allow(clippy::type_complexity)] -pub struct RethRpcComponents<'a, Reth: RethNodeComponents> { - /// A Helper type the holds instances of the configured modules. - /// - /// This provides easy access to rpc handlers, such as [RethModuleRegistry::eth_api]. - pub registry: &'a mut RethModuleRegistry< - Reth::Provider, - Reth::Pool, - Reth::Network, - Reth::Tasks, - Reth::Events, - >, - /// Holds installed modules per transport type. - /// - /// This can be used to merge additional modules into the configured transports (http, ipc, - /// ws). See [TransportRpcModules::merge_configured] - pub modules: &'a mut TransportRpcModules, - /// Holds jwt authenticated rpc module. - /// - /// This can be used to merge additional modules into the configured authenticated methods - pub auth_module: &'a mut AuthRpcModule, -} - -/// A Generic implementation of the RethNodeComponents trait. -/// -/// Represents components required for the Reth node. -#[derive(Clone, Debug)] -pub struct RethNodeComponentsImpl { - /// Represents the provider instance. - pub provider: Provider, - /// Represents the transaction pool instance. - pub pool: Pool, - /// Represents the network instance used for communication. - pub network: Network, - /// Represents the task executor instance. - pub task_executor: Tasks, - /// Represents the events subscription handler instance. - pub events: Events, -} - -impl RethNodeComponents - for RethNodeComponentsImpl -where - Provider: FullProvider + Clone + 'static, - Tasks: TaskSpawner + Clone + Unpin + 'static, - Pool: TransactionPool + Clone + Unpin + 'static, - Network: NetworkInfo + Peers + NetworkProtocols + NetworkEvents + Clone + 'static, - Events: CanonStateSubscriptions + Clone + 'static, -{ - type Provider = Provider; - type Pool = Pool; - type Network = Network; - type Events = Events; - type Tasks = Tasks; - - fn provider(&self) -> Self::Provider { - self.provider.clone() - } - - fn task_executor(&self) -> Self::Tasks { - self.task_executor.clone() - } - - fn pool(&self) -> Self::Pool { - self.pool.clone() - } - - fn network(&self) -> Self::Network { - self.network.clone() - } - - fn events(&self) -> Self::Events { - self.events.clone() - } -} - -/// Contains the handles to the spawned RPC servers. -/// -/// This can be used to access the endpoints of the servers. -/// -/// # Example -/// -/// ```rust -/// use reth::{cli::components::RethRpcServerHandles, rpc::api::EthApiClient}; -/// # async fn t(handles: RethRpcServerHandles) { -/// let client = handles.rpc.http_client().expect("http server not started"); -/// let block_number = client.block_number().await.unwrap(); -/// # } -/// ``` -#[derive(Debug, Clone)] -pub struct RethRpcServerHandles { - /// The regular RPC server handle. - pub rpc: RpcServerHandle, - /// The handle to the auth server (engine API) - pub auth: AuthServerHandle, -} diff --git a/bin/reth/src/cli/config.rs b/bin/reth/src/cli/config.rs deleted file mode 100644 index f516752f33..0000000000 --- a/bin/reth/src/cli/config.rs +++ /dev/null @@ -1,147 +0,0 @@ -//! Config traits for various node components. - -use alloy_rlp::Encodable; -use reth_network::protocol::IntoRlpxSubProtocol; -use reth_primitives::{Bytes, BytesMut}; -use reth_rpc::{ - eth::{cache::EthStateCacheConfig, gas_oracle::GasPriceOracleConfig}, - JwtError, JwtSecret, -}; -use reth_rpc_builder::{ - auth::AuthServerConfig, error::RpcError, EthConfig, IpcServerBuilder, RpcServerConfig, - ServerBuilder, TransportRpcModuleConfig, -}; -use reth_transaction_pool::PoolConfig; -use std::{borrow::Cow, path::PathBuf, time::Duration}; - -/// A trait that provides a configured RPC server. -/// -/// This provides all basic config values for the RPC server and is implemented by the -/// [RpcServerArgs](crate::args::RpcServerArgs) type. -pub trait RethRpcConfig { - /// Returns whether ipc is enabled. - fn is_ipc_enabled(&self) -> bool; - - /// Returns the path to the target ipc socket if enabled. - fn ipc_path(&self) -> &str; - - /// The configured ethereum RPC settings. - fn eth_config(&self) -> EthConfig; - - /// Returns state cache configuration. - fn state_cache_config(&self) -> EthStateCacheConfig; - - /// Returns the max request size in bytes. - fn rpc_max_request_size_bytes(&self) -> u32; - - /// Returns the max response size in bytes. - fn rpc_max_response_size_bytes(&self) -> u32; - - /// Extracts the gas price oracle config from the args. - fn gas_price_oracle_config(&self) -> GasPriceOracleConfig; - - /// Creates the [TransportRpcModuleConfig] from cli args. - /// - /// This sets all the api modules, and configures additional settings like gas price oracle - /// settings in the [TransportRpcModuleConfig]. - fn transport_rpc_module_config(&self) -> TransportRpcModuleConfig; - - /// Returns the default server builder for http/ws - fn http_ws_server_builder(&self) -> ServerBuilder; - - /// Returns the default ipc server builder - fn ipc_server_builder(&self) -> IpcServerBuilder; - - /// Creates the [RpcServerConfig] from cli args. - fn rpc_server_config(&self) -> RpcServerConfig; - - /// Creates the [AuthServerConfig] from cli args. - fn auth_server_config(&self, jwt_secret: JwtSecret) -> Result; - - /// The execution layer and consensus layer clients SHOULD accept a configuration parameter: - /// jwt-secret, which designates a file containing the hex-encoded 256 bit secret key to be used - /// for verifying/generating JWT tokens. - /// - /// If such a parameter is given, but the file cannot be read, or does not contain a hex-encoded - /// key of 256 bits, the client SHOULD treat this as an error. - /// - /// If such a parameter is not given, the client SHOULD generate such a token, valid for the - /// duration of the execution, and SHOULD store the hex-encoded secret as a jwt.hex file on - /// the filesystem. This file can then be used to provision the counterpart client. - /// - /// The `default_jwt_path` provided as an argument will be used as the default location for the - /// jwt secret in case the `auth_jwtsecret` argument is not provided. - fn auth_jwt_secret(&self, default_jwt_path: PathBuf) -> Result; - - /// Returns the configured jwt secret key for the regular rpc servers, if any. - /// - /// Note: this is not used for the auth server (engine API). - fn rpc_secret_key(&self) -> Option; -} - -/// A trait that provides payload builder settings. -/// -/// This provides all basic payload builder settings and is implemented by the -/// [PayloadBuilderArgs](crate::args::PayloadBuilderArgs) type. -pub trait PayloadBuilderConfig { - /// Block extra data set by the payload builder. - fn extradata(&self) -> Cow<'_, str>; - - /// Returns the rlp-encoded extradata bytes. - fn extradata_rlp_bytes(&self) -> Bytes { - let mut extradata = BytesMut::new(); - self.extradata().as_bytes().encode(&mut extradata); - extradata.freeze().into() - } - - /// The interval at which the job should build a new payload after the last. - fn interval(&self) -> Duration; - - /// The deadline for when the payload builder job should resolve. - fn deadline(&self) -> Duration; - - /// Target gas ceiling for built blocks. - fn max_gas_limit(&self) -> u64; - - /// Maximum number of tasks to spawn for building a payload. - fn max_payload_tasks(&self) -> usize; - - /// Returns whether or not to construct the pending block. - #[cfg(feature = "optimism")] - fn compute_pending_block(&self) -> bool; -} - -/// A trait that represents the configured network and can be used to apply additional configuration -/// to the network. -pub trait RethNetworkConfig { - /// Adds a new additional protocol to the RLPx sub-protocol list. - /// - /// These additional protocols are negotiated during the RLPx handshake. - /// If both peers share the same protocol, the corresponding handler will be included alongside - /// the `eth` protocol. - /// - /// See also [ProtocolHandler](reth_network::protocol::ProtocolHandler) - fn add_rlpx_sub_protocol(&mut self, protocol: impl IntoRlpxSubProtocol); - - /// Returns the secret key used for authenticating sessions. - fn secret_key(&self) -> secp256k1::SecretKey; - - // TODO add more network config methods here -} - -impl RethNetworkConfig for reth_network::NetworkManager { - fn add_rlpx_sub_protocol(&mut self, protocol: impl IntoRlpxSubProtocol) { - reth_network::NetworkManager::add_rlpx_sub_protocol(self, protocol); - } - - fn secret_key(&self) -> secp256k1::SecretKey { - self.secret_key() - } -} - -/// A trait that provides all basic config values for the transaction pool and is implemented by the -/// [TxPoolArgs](crate::args::TxPoolArgs) type. -pub trait RethTransactionPoolConfig { - /// Returns transaction pool configuration. - fn pool_config(&self) -> PoolConfig; -} diff --git a/bin/reth/src/cli/ext.rs b/bin/reth/src/cli/ext.rs deleted file mode 100644 index 1bb80e3f3b..0000000000 --- a/bin/reth/src/cli/ext.rs +++ /dev/null @@ -1,362 +0,0 @@ -//! Support for integrating customizations into the CLI. - -use crate::cli::{ - components::{RethNodeComponents, RethRpcComponents, RethRpcServerHandles}, - config::{PayloadBuilderConfig, RethNetworkConfig, RethRpcConfig}, -}; -use clap::Args; -use reth_basic_payload_builder::{ - BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig, PayloadBuilder, -}; -use reth_node_api::EngineTypes; -use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService}; -use reth_provider::CanonStateSubscriptions; -use reth_tasks::TaskSpawner; -use std::{fmt, marker::PhantomData}; - -/// A trait that allows for extending parts of the CLI with additional functionality. -/// -/// This is intended as a way to allow to _extend_ the node command. For example, to register -/// additional RPC namespaces. -pub trait RethCliExt { - /// Provides additional configuration for the node CLI command. - /// - /// This supports additional CLI arguments that can be used to modify the node configuration. - /// - /// If no additional CLI arguments are required, the [NoArgs] wrapper type can be used. - type Node: RethNodeCommandExt; -} - -/// The default CLI extension. -impl RethCliExt for () { - type Node = DefaultRethNodeCommandConfig; -} - -/// A trait that allows for extending and customizing parts of the node command -/// [NodeCommand](crate::cli::node::NodeCommand). -/// -/// The functions are invoked during the initialization of the node command in the following order: -/// -/// 1. [configure_network](RethNodeCommandConfig::configure_network) -/// 2. [on_components_initialized](RethNodeCommandConfig::on_components_initialized) -/// 3. [spawn_payload_builder_service](RethNodeCommandConfig::spawn_payload_builder_service) -/// 4. [extend_rpc_modules](RethNodeCommandConfig::extend_rpc_modules) -/// 5. [on_rpc_server_started](RethNodeCommandConfig::on_rpc_server_started) -/// 6. [on_node_started](RethNodeCommandConfig::on_node_started) -pub trait RethNodeCommandConfig: fmt::Debug { - /// Invoked with the network configuration before the network is configured. - /// - /// This allows additional configuration of the network before it is launched. - fn configure_network( - &mut self, - config: &mut Conf, - components: &Reth, - ) -> eyre::Result<()> - where - Conf: RethNetworkConfig, - Reth: RethNodeComponents, - { - let _ = config; - let _ = components; - Ok(()) - } - - /// Event hook called once all components have been initialized. - /// - /// This is called as soon as the node components have been initialized. - fn on_components_initialized( - &mut self, - components: &Reth, - ) -> eyre::Result<()> { - let _ = components; - Ok(()) - } - - /// Event hook called once the node has been launched. - /// - /// This is called last after the node has been launched. - fn on_node_started(&mut self, components: &Reth) -> eyre::Result<()> { - let _ = components; - Ok(()) - } - - /// Event hook called once the rpc servers has been started. - /// - /// This is called after the rpc server has been started. - fn on_rpc_server_started( - &mut self, - config: &Conf, - components: &Reth, - rpc_components: RethRpcComponents<'_, Reth>, - handles: RethRpcServerHandles, - ) -> eyre::Result<()> - where - Conf: RethRpcConfig, - Reth: RethNodeComponents, - { - let _ = config; - let _ = components; - let _ = rpc_components; - let _ = handles; - Ok(()) - } - - /// Allows for registering additional RPC modules for the transports. - /// - /// This is expected to call the merge functions of [reth_rpc_builder::TransportRpcModules], for - /// example [reth_rpc_builder::TransportRpcModules::merge_configured]. - /// - /// This is called before the rpc server will be started [Self::on_rpc_server_started]. - fn extend_rpc_modules( - &mut self, - config: &Conf, - components: &Reth, - rpc_components: RethRpcComponents<'_, Reth>, - ) -> eyre::Result<()> - where - Conf: RethRpcConfig, - Reth: RethNodeComponents, - { - let _ = config; - let _ = components; - let _ = rpc_components; - Ok(()) - } - - /// Configures the [PayloadBuilderService] for the node, spawns it and returns the - /// [PayloadBuilderHandle]. - /// - /// By default this spawns a [BasicPayloadJobGenerator] with the default configuration - /// [BasicPayloadJobGeneratorConfig]. - fn spawn_payload_builder_service( - &mut self, - conf: &Conf, - components: &Reth, - payload_builder: Builder, - ) -> eyre::Result> - where - Conf: PayloadBuilderConfig, - Reth: RethNodeComponents, - Engine: EngineTypes + 'static, - Builder: PayloadBuilder< - Reth::Pool, - Reth::Provider, - Attributes = Engine::PayloadBuilderAttributes, - BuiltPayload = Engine::BuiltPayload, - > + Unpin - + 'static, - { - let payload_job_config = BasicPayloadJobGeneratorConfig::default() - .interval(conf.interval()) - .deadline(conf.deadline()) - .max_payload_tasks(conf.max_payload_tasks()) - .extradata(conf.extradata_rlp_bytes()) - .max_gas_limit(conf.max_gas_limit()); - - // no extradata for optimism - #[cfg(feature = "optimism")] - let payload_job_config = payload_job_config.extradata(Default::default()); - - let payload_generator = BasicPayloadJobGenerator::with_builder( - components.provider(), - components.pool(), - components.task_executor(), - payload_job_config, - components.chain_spec(), - payload_builder, - ); - let (payload_service, payload_builder) = PayloadBuilderService::new( - payload_generator, - components.events().canonical_state_stream(), - ); - - components - .task_executor() - .spawn_critical("payload builder service", Box::pin(payload_service)); - - Ok(payload_builder) - } -} - -/// A trait that allows for extending parts of the CLI with additional functionality. -pub trait RethNodeCommandExt: RethNodeCommandConfig + fmt::Debug + clap::Args {} - -// blanket impl for all types that implement the required traits. -impl RethNodeCommandExt for T where T: RethNodeCommandConfig + fmt::Debug + clap::Args {} - -/// The default configuration for the reth node command -/// [Command](crate::cli::node::NodeCommand). -/// -/// This is a convenience type for [NoArgs<()>]. -#[derive(Debug, Clone, Copy, Default, Args)] -#[non_exhaustive] -pub struct DefaultRethNodeCommandConfig; - -impl RethNodeCommandConfig for DefaultRethNodeCommandConfig {} - -impl RethNodeCommandConfig for () {} - -/// A helper type for [RethCliExt] extension that don't require any additional clap Arguments. -#[derive(Debug, Clone, Copy)] -pub struct NoArgsCliExt(PhantomData); - -impl RethCliExt for NoArgsCliExt { - type Node = NoArgs; -} - -/// A helper struct that allows for wrapping a [RethNodeCommandConfig] value without providing -/// additional CLI arguments. -/// -/// Note: This type must be manually filled with a [RethNodeCommandConfig] manually before executing -/// the [NodeCommand](crate::cli::node::NodeCommand). -#[derive(Debug, Clone, Copy, Default, Args)] -pub struct NoArgs { - #[clap(skip)] - inner: Option, -} - -impl NoArgs { - /// Creates a new instance of the wrapper type. - pub fn with(inner: T) -> Self { - Self { inner: Some(inner) } - } - - /// Sets the inner value. - pub fn set(&mut self, inner: T) { - self.inner = Some(inner) - } - - /// Transforms the configured value. - pub fn map(self, inner: U) -> NoArgs { - NoArgs::with(inner) - } - - /// Returns the inner value if it exists. - pub fn inner(&self) -> Option<&T> { - self.inner.as_ref() - } - - /// Returns a mutable reference to the inner value if it exists. - pub fn inner_mut(&mut self) -> Option<&mut T> { - self.inner.as_mut() - } - - /// Consumes the wrapper and returns the inner value if it exists. - pub fn into_inner(self) -> Option { - self.inner - } -} - -impl RethNodeCommandConfig for NoArgs { - fn configure_network( - &mut self, - config: &mut Conf, - components: &Reth, - ) -> eyre::Result<()> - where - Conf: RethNetworkConfig, - Reth: RethNodeComponents, - { - if let Some(conf) = self.inner_mut() { - conf.configure_network(config, components) - } else { - Ok(()) - } - } - - fn on_components_initialized( - &mut self, - components: &Reth, - ) -> eyre::Result<()> { - if let Some(conf) = self.inner_mut() { - conf.on_components_initialized(components) - } else { - Ok(()) - } - } - - fn on_node_started(&mut self, components: &Reth) -> eyre::Result<()> { - if let Some(conf) = self.inner_mut() { - conf.on_node_started(components) - } else { - Ok(()) - } - } - - fn on_rpc_server_started( - &mut self, - config: &Conf, - components: &Reth, - rpc_components: RethRpcComponents<'_, Reth>, - handles: RethRpcServerHandles, - ) -> eyre::Result<()> - where - Conf: RethRpcConfig, - Reth: RethNodeComponents, - { - if let Some(conf) = self.inner_mut() { - conf.on_rpc_server_started(config, components, rpc_components, handles) - } else { - Ok(()) - } - } - - fn extend_rpc_modules( - &mut self, - config: &Conf, - components: &Reth, - rpc_components: RethRpcComponents<'_, Reth>, - ) -> eyre::Result<()> - where - Conf: RethRpcConfig, - Reth: RethNodeComponents, - { - if let Some(conf) = self.inner_mut() { - conf.extend_rpc_modules(config, components, rpc_components) - } else { - Ok(()) - } - } - - fn spawn_payload_builder_service( - &mut self, - conf: &Conf, - components: &Reth, - payload_builder: Builder, - ) -> eyre::Result> - where - Conf: PayloadBuilderConfig, - Reth: RethNodeComponents, - Engine: EngineTypes + 'static, - Builder: PayloadBuilder< - Reth::Pool, - Reth::Provider, - Attributes = Engine::PayloadBuilderAttributes, - BuiltPayload = Engine::BuiltPayload, - > + Unpin - + 'static, - { - self.inner_mut() - .ok_or_else(|| eyre::eyre!("config value must be set"))? - .spawn_payload_builder_service(conf, components, payload_builder) - } -} - -impl From for NoArgs { - fn from(value: T) -> Self { - Self::with(value) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn assert_ext() {} - - #[test] - fn ensure_ext() { - assert_ext::(); - assert_ext::>(); - } -} diff --git a/bin/reth/src/cli/mod.rs b/bin/reth/src/cli/mod.rs index ef17785d60..64f013addc 100644 --- a/bin/reth/src/cli/mod.rs +++ b/bin/reth/src/cli/mod.rs @@ -17,10 +17,15 @@ use reth_primitives::ChainSpec; use reth_tracing::FileWorkerGuard; use std::sync::Arc; -pub mod components; -pub mod config; +/// Re-export of the `reth_node_core` types specifically in the `cli` module. +/// +/// This is re-exported because the types in `reth_node_core::cli` originally existed in +/// `reth::cli` but were moved to the `reth_node_core` crate. This re-export avoids a breaking +/// change. +pub use crate::core::cli::*; + pub mod db_type; -pub mod ext; + /// The main reth cli interface. /// /// This is the entrypoint to the executable. diff --git a/bin/reth/src/dirs.rs b/bin/reth/src/dirs.rs deleted file mode 100644 index e751ba50ab..0000000000 --- a/bin/reth/src/dirs.rs +++ /dev/null @@ -1,384 +0,0 @@ -//! reth data directories. - -use crate::utils::parse_path; -use reth_primitives::Chain; -use std::{ - env::VarError, - fmt::{Debug, Display, Formatter}, - path::{Path, PathBuf}, - str::FromStr, -}; - -/// Constructs a string to be used as a path for configuration and db paths. -pub fn config_path_prefix(chain: Chain) -> String { - chain.to_string() -} - -/// Returns the path to the reth data directory. -/// -/// Refer to [dirs_next::data_dir] for cross-platform behavior. -pub fn data_dir() -> Option { - dirs_next::data_dir().map(|root| root.join("reth")) -} - -/// Returns the path to the reth database. -/// -/// Refer to [dirs_next::data_dir] for cross-platform behavior. -pub fn database_path() -> Option { - data_dir().map(|root| root.join("db")) -} - -/// Returns the path to the reth configuration directory. -/// -/// Refer to [dirs_next::config_dir] for cross-platform behavior. -pub fn config_dir() -> Option { - dirs_next::config_dir().map(|root| root.join("reth")) -} - -/// Returns the path to the reth cache directory. -/// -/// Refer to [dirs_next::cache_dir] for cross-platform behavior. -pub fn cache_dir() -> Option { - dirs_next::cache_dir().map(|root| root.join("reth")) -} - -/// Returns the path to the reth logs directory. -/// -/// Refer to [dirs_next::cache_dir] for cross-platform behavior. -pub fn logs_dir() -> Option { - cache_dir().map(|root| root.join("logs")) -} - -/// Returns the path to the reth data dir. -/// -/// The data dir should contain a subdirectory for each chain, and those chain directories will -/// include all information for that chain, such as the p2p secret. -#[derive(Clone, Copy, Debug, Default)] -#[non_exhaustive] -pub struct DataDirPath; - -impl XdgPath for DataDirPath { - fn resolve() -> Option { - data_dir() - } -} - -/// Returns the path to the reth logs directory. -/// -/// Refer to [dirs_next::cache_dir] for cross-platform behavior. -#[derive(Clone, Copy, Debug, Default)] -#[non_exhaustive] -pub struct LogsDir; - -impl XdgPath for LogsDir { - fn resolve() -> Option { - logs_dir() - } -} - -/// A small helper trait for unit structs that represent a standard path following the XDG -/// path specification. -pub trait XdgPath { - /// Resolve the standard path. - fn resolve() -> Option; -} - -/// A wrapper type that either parses a user-given path or defaults to an -/// OS-specific path. -/// -/// The [FromStr] implementation supports shell expansions and common patterns such as `~` for the -/// home directory. -/// -/// # Example -/// -/// ``` -/// use reth::dirs::{DataDirPath, PlatformPath}; -/// use std::str::FromStr; -/// -/// // Resolves to the platform-specific database path -/// let default: PlatformPath = PlatformPath::default(); -/// // Resolves to `$(pwd)/my/path/to/datadir` -/// let custom: PlatformPath = PlatformPath::from_str("my/path/to/datadir").unwrap(); -/// -/// assert_ne!(default.as_ref(), custom.as_ref()); -/// ``` -#[derive(Debug, PartialEq)] -pub struct PlatformPath(PathBuf, std::marker::PhantomData); - -impl Display for PlatformPath { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0.display()) - } -} - -impl Clone for PlatformPath { - fn clone(&self) -> Self { - Self(self.0.clone(), std::marker::PhantomData) - } -} - -impl Default for PlatformPath { - fn default() -> Self { - Self( - D::resolve().expect("Could not resolve default path. Set one manually."), - std::marker::PhantomData, - ) - } -} - -impl FromStr for PlatformPath { - type Err = shellexpand::LookupError; - - fn from_str(s: &str) -> Result { - Ok(Self(parse_path(s)?, std::marker::PhantomData)) - } -} - -impl AsRef for PlatformPath { - fn as_ref(&self) -> &Path { - self.0.as_path() - } -} - -impl From> for PathBuf { - fn from(value: PlatformPath) -> Self { - value.0 - } -} - -impl PlatformPath { - /// Returns the path joined with another path - pub fn join>(&self, path: P) -> PlatformPath { - PlatformPath::(self.0.join(path), std::marker::PhantomData) - } -} - -impl PlatformPath { - /// Converts the path to a `ChainPath` with the given `Chain`. - pub fn with_chain(&self, chain: Chain) -> ChainPath { - // extract chain name - let chain_name = config_path_prefix(chain); - - let path = self.0.join(chain_name); - - let platform_path = PlatformPath::(path, std::marker::PhantomData); - ChainPath::new(platform_path, chain) - } - - /// Map the inner path to a new type `T`. - pub fn map_to(&self) -> PlatformPath { - PlatformPath(self.0.clone(), std::marker::PhantomData) - } -} - -/// An Optional wrapper type around [PlatformPath]. -/// -/// This is useful for when a path is optional, such as the `--data-dir` flag. -#[derive(Clone, Debug, PartialEq)] -pub struct MaybePlatformPath(Option>); - -// === impl MaybePlatformPath === - -impl MaybePlatformPath { - /// Returns the path if it is set, otherwise returns the default path for the given chain. - pub fn unwrap_or_chain_default(&self, chain: Chain) -> ChainPath { - ChainPath( - self.0.clone().unwrap_or_else(|| PlatformPath::default().with_chain(chain).0), - chain, - ) - } - - /// Returns the default platform path for the specified [Chain]. - pub fn chain_default(chain: Chain) -> ChainPath { - PlatformPath::default().with_chain(chain) - } - - /// Returns true if a custom path is set - pub fn is_some(&self) -> bool { - self.0.is_some() - } - - /// Returns the path if it is set, otherwise returns `None`. - pub fn as_ref(&self) -> Option<&Path> { - self.0.as_ref().map(|p| p.as_ref()) - } - - /// Returns the path if it is set, otherwise returns the default path, without any chain - /// directory. - pub fn unwrap_or_default(&self) -> PlatformPath { - self.0.clone().unwrap_or_default() - } -} - -impl Display for MaybePlatformPath { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - if let Some(path) = &self.0 { - path.fmt(f) - } else { - // NOTE: this is a workaround for making it work with clap's `default_value_t` which - // computes the default value via `Default -> Display -> FromStr` - write!(f, "default") - } - } -} - -impl Default for MaybePlatformPath { - fn default() -> Self { - Self(None) - } -} - -impl FromStr for MaybePlatformPath { - type Err = shellexpand::LookupError; - - fn from_str(s: &str) -> Result { - let p = match s { - "default" => { - // NOTE: this is a workaround for making it work with clap's `default_value_t` which - // computes the default value via `Default -> Display -> FromStr` - None - } - _ => Some(PlatformPath::from_str(s)?), - }; - Ok(Self(p)) - } -} - -impl From for MaybePlatformPath { - fn from(path: PathBuf) -> Self { - Self(Some(PlatformPath(path, std::marker::PhantomData))) - } -} - -/// Wrapper type around PlatformPath that includes a `Chain`, used for separating reth data for -/// different networks. -/// -/// If the chain is either mainnet, goerli, or sepolia, then the path will be: -/// * mainnet: `/mainnet` -/// * goerli: `/goerli` -/// * sepolia: `/sepolia` -/// Otherwise, the path will be dependent on the chain ID: -/// * `/` -#[derive(Clone, Debug, PartialEq)] -pub struct ChainPath(PlatformPath, Chain); - -impl ChainPath { - /// Returns a new `ChainPath` given a `PlatformPath` and a `Chain`. - pub fn new(path: PlatformPath, chain: Chain) -> Self { - Self(path, chain) - } - - /// Returns the path to the reth data directory for this chain. - /// - /// `/` - pub fn data_dir_path(&self) -> PathBuf { - self.0.as_ref().into() - } - - /// Returns the path to the db directory for this chain. - /// - /// `//db` - pub fn db_path(&self) -> PathBuf { - self.0.join("db").into() - } - - /// Returns the path to the snapshots directory for this chain. - pub fn snapshots_path(&self) -> PathBuf { - self.0.join("snapshots").into() - } - - /// Returns the path to the reth p2p secret key for this chain. - /// - /// `//discovery-secret` - pub fn p2p_secret_path(&self) -> PathBuf { - self.0.join("discovery-secret").into() - } - - /// Returns the path to the known peers file for this chain. - /// - /// `//known-peers.json` - pub fn known_peers_path(&self) -> PathBuf { - self.0.join("known-peers.json").into() - } - - /// Returns the path to the blobstore directory for this chain where blobs of unfinalized - /// transactions are stored. - /// - /// `//blobstore` - pub fn blobstore_path(&self) -> PathBuf { - self.0.join("blobstore").into() - } - - /// Returns the path to the local transactions backup file - /// - /// `//txpool-transactions-backup.rlp` - pub fn txpool_transactions_path(&self) -> PathBuf { - self.0.join("txpool-transactions-backup.rlp").into() - } - - /// Returns the path to the config file for this chain. - /// - /// `//reth.toml` - pub fn config_path(&self) -> PathBuf { - self.0.join("reth.toml").into() - } - - /// Returns the path to the jwtsecret file for this chain. - /// - /// `//jwt.hex` - pub fn jwt_path(&self) -> PathBuf { - self.0.join("jwt.hex").into() - } -} - -impl AsRef for ChainPath { - fn as_ref(&self) -> &Path { - self.0.as_ref() - } -} - -impl Display for ChainPath { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl From> for PathBuf { - fn from(value: ChainPath) -> Self { - value.0.into() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_maybe_data_dir_path() { - let path = MaybePlatformPath::::default(); - let path = path.unwrap_or_chain_default(Chain::mainnet()); - assert!(path.as_ref().ends_with("reth/mainnet"), "{:?}", path); - - let db_path = path.db_path(); - assert!(db_path.ends_with("reth/mainnet/db"), "{:?}", db_path); - - let path = MaybePlatformPath::::from_str("my/path/to/datadir").unwrap(); - let path = path.unwrap_or_chain_default(Chain::mainnet()); - assert!(path.as_ref().ends_with("my/path/to/datadir"), "{:?}", path); - } - - #[test] - fn test_maybe_testnet_datadir_path() { - let path = MaybePlatformPath::::default(); - let path = path.unwrap_or_chain_default(Chain::goerli()); - assert!(path.as_ref().ends_with("reth/goerli"), "{:?}", path); - - let path = MaybePlatformPath::::default(); - let path = path.unwrap_or_chain_default(Chain::holesky()); - assert!(path.as_ref().ends_with("reth/holesky"), "{:?}", path); - - let path = MaybePlatformPath::::default(); - let path = path.unwrap_or_chain_default(Chain::sepolia()); - assert!(path.as_ref().ends_with("reth/sepolia"), "{:?}", path); - } -} diff --git a/bin/reth/src/init.rs b/bin/reth/src/init.rs deleted file mode 100644 index de75bf9d54..0000000000 --- a/bin/reth/src/init.rs +++ /dev/null @@ -1,348 +0,0 @@ -//! Reth genesis initialization utility functions. - -use reth_db::{ - cursor::DbCursorRO, - database::Database, - tables, - transaction::{DbTx, DbTxMut}, -}; -use reth_interfaces::{db::DatabaseError, provider::ProviderResult}; -use reth_primitives::{ - stage::StageId, Account, Bytecode, ChainSpec, Receipts, StorageEntry, B256, U256, -}; -use reth_provider::{ - bundle_state::{BundleStateInit, RevertsInit}, - BundleStateWithReceipts, DatabaseProviderRW, HashingWriter, HistoryWriter, OriginalValuesKnown, - ProviderError, ProviderFactory, -}; -use std::{ - collections::{BTreeMap, HashMap}, - sync::Arc, -}; -use tracing::debug; - -/// Database initialization error type. -#[derive(Debug, thiserror::Error, PartialEq, Eq, Clone)] -pub enum InitDatabaseError { - /// An existing genesis block was found in the database, and its hash did not match the hash of - /// the chainspec. - #[error("genesis hash in the database does not match the specified chainspec: chainspec is {chainspec_hash}, database is {database_hash}")] - GenesisHashMismatch { - /// Expected genesis hash. - chainspec_hash: B256, - /// Actual genesis hash. - database_hash: B256, - }, - - /// Provider error. - #[error(transparent)] - Provider(#[from] ProviderError), -} - -impl From for InitDatabaseError { - fn from(error: DatabaseError) -> Self { - Self::Provider(ProviderError::Database(error)) - } -} - -/// Write the genesis block if it has not already been written -pub fn init_genesis( - db: Arc, - chain: Arc, -) -> Result { - let genesis = chain.genesis(); - - let hash = chain.genesis_hash(); - - let tx = db.tx()?; - if let Some((_, db_hash)) = tx.cursor_read::()?.first()? { - if db_hash == hash { - debug!("Genesis already written, skipping."); - return Ok(hash) - } - - return Err(InitDatabaseError::GenesisHashMismatch { - chainspec_hash: hash, - database_hash: db_hash, - }) - } - - drop(tx); - debug!("Writing genesis block."); - - // use transaction to insert genesis header - let factory = ProviderFactory::new(&db, chain.clone()); - let provider_rw = factory.provider_rw()?; - insert_genesis_hashes(&provider_rw, genesis)?; - insert_genesis_history(&provider_rw, genesis)?; - provider_rw.commit()?; - - // Insert header - let tx = db.tx_mut()?; - insert_genesis_header::(&tx, chain.clone())?; - - insert_genesis_state::(&tx, genesis)?; - - // insert sync stage - for stage in StageId::ALL.iter() { - tx.put::(stage.to_string(), Default::default())?; - } - - tx.commit()?; - Ok(hash) -} - -/// Inserts the genesis state into the database. -pub fn insert_genesis_state( - tx: &::TXMut, - genesis: &reth_primitives::Genesis, -) -> ProviderResult<()> { - let mut state_init: BundleStateInit = HashMap::new(); - let mut reverts_init = HashMap::new(); - let mut contracts: HashMap = HashMap::new(); - - for (address, account) in &genesis.alloc { - let bytecode_hash = if let Some(code) = &account.code { - let bytecode = Bytecode::new_raw(code.clone()); - let hash = bytecode.hash_slow(); - contracts.insert(hash, bytecode); - Some(hash) - } else { - None - }; - - // get state - let storage = account - .storage - .as_ref() - .map(|m| { - m.iter() - .map(|(key, value)| { - let value = U256::from_be_bytes(value.0); - (*key, (U256::ZERO, value)) - }) - .collect::>() - }) - .unwrap_or_default(); - - reverts_init.insert( - *address, - (Some(None), storage.keys().map(|k| StorageEntry::new(*k, U256::ZERO)).collect()), - ); - - state_init.insert( - *address, - ( - None, - Some(Account { - nonce: account.nonce.unwrap_or_default(), - balance: account.balance, - bytecode_hash, - }), - storage, - ), - ); - } - let all_reverts_init: RevertsInit = HashMap::from([(0, reverts_init)]); - - let bundle = BundleStateWithReceipts::new_init( - state_init, - all_reverts_init, - contracts.into_iter().collect(), - Receipts::new(), - 0, - ); - - bundle.write_to_db(tx, OriginalValuesKnown::Yes)?; - - Ok(()) -} - -/// Inserts hashes for the genesis state. -pub fn insert_genesis_hashes( - provider: &DatabaseProviderRW<&DB>, - genesis: &reth_primitives::Genesis, -) -> ProviderResult<()> { - // insert and hash accounts to hashing table - let alloc_accounts = genesis - .alloc - .clone() - .into_iter() - .map(|(addr, account)| (addr, Some(Account::from_genesis_account(account)))); - provider.insert_account_for_hashing(alloc_accounts)?; - - let alloc_storage = genesis.alloc.clone().into_iter().filter_map(|(addr, account)| { - // only return Some if there is storage - account.storage.map(|storage| { - ( - addr, - storage.into_iter().map(|(key, value)| StorageEntry { key, value: value.into() }), - ) - }) - }); - provider.insert_storage_for_hashing(alloc_storage)?; - - Ok(()) -} - -/// Inserts history indices for genesis accounts and storage. -pub fn insert_genesis_history( - provider: &DatabaseProviderRW<&DB>, - genesis: &reth_primitives::Genesis, -) -> ProviderResult<()> { - let account_transitions = - genesis.alloc.keys().map(|addr| (*addr, vec![0])).collect::>(); - provider.insert_account_history_index(account_transitions)?; - - let storage_transitions = genesis - .alloc - .iter() - .filter_map(|(addr, account)| account.storage.as_ref().map(|storage| (addr, storage))) - .flat_map(|(addr, storage)| storage.iter().map(|(key, _)| ((*addr, *key), vec![0]))) - .collect::>(); - provider.insert_storage_history_index(storage_transitions)?; - - Ok(()) -} - -/// Inserts header for the genesis state. -pub fn insert_genesis_header( - tx: &::TXMut, - chain: Arc, -) -> ProviderResult<()> { - let header = chain.sealed_genesis_header(); - - tx.put::(0, header.hash)?; - tx.put::(header.hash, 0)?; - tx.put::(0, Default::default())?; - tx.put::(0, header.difficulty.into())?; - tx.put::(0, header.header)?; - - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - - use reth_db::{ - models::{storage_sharded_key::StorageShardedKey, ShardedKey}, - table::{Table, TableRow}, - test_utils::create_test_rw_db, - DatabaseEnv, - }; - use reth_primitives::{ - Address, Chain, ForkTimestamps, Genesis, GenesisAccount, IntegerList, GOERLI, - GOERLI_GENESIS_HASH, MAINNET, MAINNET_GENESIS_HASH, SEPOLIA, SEPOLIA_GENESIS_HASH, - }; - use std::collections::HashMap; - - fn collect_table_entries( - tx: &::TX, - ) -> Result>, InitDatabaseError> - where - DB: Database, - T: Table, - { - Ok(tx.cursor_read::()?.walk_range(..)?.collect::, _>>()?) - } - - #[test] - fn success_init_genesis_mainnet() { - let db = create_test_rw_db(); - let genesis_hash = init_genesis(db, MAINNET.clone()).unwrap(); - - // actual, expected - assert_eq!(genesis_hash, MAINNET_GENESIS_HASH); - } - - #[test] - fn success_init_genesis_goerli() { - let db = create_test_rw_db(); - let genesis_hash = init_genesis(db, GOERLI.clone()).unwrap(); - - // actual, expected - assert_eq!(genesis_hash, GOERLI_GENESIS_HASH); - } - - #[test] - fn success_init_genesis_sepolia() { - let db = create_test_rw_db(); - let genesis_hash = init_genesis(db, SEPOLIA.clone()).unwrap(); - - // actual, expected - assert_eq!(genesis_hash, SEPOLIA_GENESIS_HASH); - } - - #[test] - fn fail_init_inconsistent_db() { - let db = create_test_rw_db(); - init_genesis(db.clone(), SEPOLIA.clone()).unwrap(); - - // Try to init db with a different genesis block - let genesis_hash = init_genesis(db, MAINNET.clone()); - - assert_eq!( - genesis_hash.unwrap_err(), - InitDatabaseError::GenesisHashMismatch { - chainspec_hash: MAINNET_GENESIS_HASH, - database_hash: SEPOLIA_GENESIS_HASH - } - ) - } - - #[test] - fn init_genesis_history() { - let address_with_balance = Address::with_last_byte(1); - let address_with_storage = Address::with_last_byte(2); - let storage_key = B256::with_last_byte(1); - let chain_spec = Arc::new(ChainSpec { - chain: Chain::from_id(1), - genesis: Genesis { - alloc: HashMap::from([ - ( - address_with_balance, - GenesisAccount { balance: U256::from(1), ..Default::default() }, - ), - ( - address_with_storage, - GenesisAccount { - storage: Some(HashMap::from([(storage_key, B256::random())])), - ..Default::default() - }, - ), - ]), - ..Default::default() - }, - hardforks: BTreeMap::default(), - fork_timestamps: ForkTimestamps::default(), - genesis_hash: None, - paris_block_and_final_difficulty: None, - deposit_contract: None, - ..Default::default() - }); - - let db = create_test_rw_db(); - init_genesis(db.clone(), chain_spec).unwrap(); - - let tx = db.tx().expect("failed to init tx"); - - assert_eq!( - collect_table_entries::, tables::AccountHistory>(&tx) - .expect("failed to collect"), - vec![ - (ShardedKey::new(address_with_balance, u64::MAX), IntegerList::new([0]).unwrap()), - (ShardedKey::new(address_with_storage, u64::MAX), IntegerList::new([0]).unwrap()) - ], - ); - - assert_eq!( - collect_table_entries::, tables::StorageHistory>(&tx) - .expect("failed to collect"), - vec![( - StorageShardedKey::new(address_with_storage, storage_key, u64::MAX), - IntegerList::new([0]).unwrap() - )], - ); - } -} diff --git a/bin/reth/src/lib.rs b/bin/reth/src/lib.rs index 7b9d330d98..7d505cd5cc 100644 --- a/bin/reth/src/lib.rs +++ b/bin/reth/src/lib.rs @@ -28,16 +28,11 @@ #![allow(dead_code)] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -pub mod args; pub mod builder; pub mod cli; pub mod commands; -pub mod dirs; -pub mod init; pub mod prometheus_exporter; pub mod runner; -pub mod utils; -pub mod version; /// Re-exported payload related types pub mod payload { @@ -46,10 +41,43 @@ pub mod payload { } /// Re-exported from `reth_node_core`. -pub mod node_core { +pub mod core { pub use reth_node_core::*; } +/// Re-export of the `reth_node_core` types specifically in the `args` module. +/// +/// This is re-exported because the types in `reth_node_core::args` originally existed in +/// `reth::args` but were moved to the `reth_node_core` crate. This re-export avoids a breaking +/// change. +pub mod args { + pub use reth_node_core::args::*; +} + +/// Re-exported from `reth_node_core`, also to prevent a breaking change. See the comment on +/// the `reth_node_core::args` re-export for more details. +pub mod version { + pub use reth_node_core::version::*; +} + +/// Re-exported from `reth_node_core`, also to prevent a breaking change. See the comment on +/// the `reth_node_core::args` re-export for more details. +pub mod utils { + pub use reth_node_core::utils::*; +} + +/// Re-exported from `reth_node_core`, also to prevent a breaking change. See the comment on +/// the `reth_node_core::args` re-export for more details. +pub mod init { + pub use reth_node_core::init::*; +} + +/// Re-exported from `reth_node_core`, also to prevent a breaking change. See the comment on +/// the `reth_node_core::args` re-export for more details. +pub mod dirs { + pub use reth_node_core::dirs::*; +} + /// Re-exported from `reth_provider`. pub mod providers { pub use reth_provider::*; diff --git a/bin/reth/src/utils.rs b/bin/reth/src/utils.rs deleted file mode 100644 index 38a824fb9a..0000000000 --- a/bin/reth/src/utils.rs +++ /dev/null @@ -1,293 +0,0 @@ -//! Common CLI utility functions. - -use boyer_moore_magiclen::BMByte; -use eyre::Result; -use reth_consensus_common::validation::validate_block_standalone; -use reth_db::{ - cursor::{DbCursorRO, DbDupCursorRO}, - database::Database, - table::{Decode, Decompress, DupSort, Table, TableRow}, - transaction::{DbTx, DbTxMut}, - DatabaseError, RawTable, TableRawRow, -}; -use reth_interfaces::p2p::{ - bodies::client::BodiesClient, - headers::client::{HeadersClient, HeadersRequest}, - priority::Priority, -}; -use reth_network::NetworkManager; -use reth_primitives::{ - fs, BlockHashOrNumber, ChainSpec, HeadersDirection, SealedBlock, SealedHeader, -}; -use reth_provider::BlockReader; -use reth_rpc::{JwtError, JwtSecret}; -use std::{ - env::VarError, - path::{Path, PathBuf}, - rc::Rc, - sync::Arc, -}; -use tracing::{debug, info, trace, warn}; - -/// Exposing `open_db_read_only` function -pub mod db { - pub use reth_db::open_db_read_only; -} - -/// Get a single header from network -pub async fn get_single_header( - client: Client, - id: BlockHashOrNumber, -) -> Result -where - Client: HeadersClient, -{ - let request = HeadersRequest { direction: HeadersDirection::Rising, limit: 1, start: id }; - - let (peer_id, response) = - client.get_headers_with_priority(request, Priority::High).await?.split(); - - if response.len() != 1 { - client.report_bad_message(peer_id); - eyre::bail!("Invalid number of headers received. Expected: 1. Received: {}", response.len()) - } - - let header = response.into_iter().next().unwrap().seal_slow(); - - let valid = match id { - BlockHashOrNumber::Hash(hash) => header.hash() == hash, - BlockHashOrNumber::Number(number) => header.number == number, - }; - - if !valid { - client.report_bad_message(peer_id); - eyre::bail!( - "Received invalid header. Received: {:?}. Expected: {:?}", - header.num_hash(), - id - ); - } - - Ok(header) -} - -/// Get a body from network based on header -pub async fn get_single_body( - client: Client, - chain_spec: Arc, - header: SealedHeader, -) -> Result -where - Client: BodiesClient, -{ - let (peer_id, response) = client.get_block_body(header.hash).await?.split(); - - if response.is_none() { - client.report_bad_message(peer_id); - eyre::bail!("Invalid number of bodies received. Expected: 1. Received: 0") - } - - let block = response.unwrap(); - let block = SealedBlock { - header, - body: block.transactions, - ommers: block.ommers, - withdrawals: block.withdrawals, - }; - - validate_block_standalone(&block, &chain_spec)?; - - Ok(block) -} - -/// Wrapper over DB that implements many useful DB queries. -pub struct DbTool<'a, DB: Database> { - pub(crate) db: &'a DB, - pub(crate) chain: Arc, -} - -impl<'a, DB: Database> DbTool<'a, DB> { - /// Takes a DB where the tables have already been created. - pub(crate) fn new(db: &'a DB, chain: Arc) -> eyre::Result { - Ok(Self { db, chain }) - } - - /// Grabs the contents of the table within a certain index range and places the - /// entries into a [`HashMap`][std::collections::HashMap]. - /// - /// [`ListFilter`] can be used to further - /// filter down the desired results. (eg. List only rows which include `0xd3adbeef`) - pub fn list(&self, filter: &ListFilter) -> Result<(Vec>, usize)> { - let bmb = Rc::new(BMByte::from(&filter.search)); - if bmb.is_none() && filter.has_search() { - eyre::bail!("Invalid search.") - } - - let mut hits = 0; - - let data = self.db.view(|tx| { - let mut cursor = - tx.cursor_read::>().expect("Was not able to obtain a cursor."); - - let map_filter = |row: Result, _>| { - if let Ok((k, v)) = row { - let (key, value) = (k.into_key(), v.into_value()); - - if key.len() + value.len() < filter.min_row_size { - return None - } - if key.len() < filter.min_key_size { - return None - } - if value.len() < filter.min_value_size { - return None - } - - let result = || { - if filter.only_count { - return None - } - Some(( - ::Key::decode(&key).unwrap(), - ::Value::decompress(&value).unwrap(), - )) - }; - - match &*bmb { - Some(searcher) => { - if searcher.find_first_in(&value).is_some() || - searcher.find_first_in(&key).is_some() - { - hits += 1; - return result() - } - } - None => { - hits += 1; - return result() - } - } - } - None - }; - - if filter.reverse { - Ok(cursor - .walk_back(None)? - .skip(filter.skip) - .filter_map(map_filter) - .take(filter.len) - .collect::>()) - } else { - Ok(cursor - .walk(None)? - .skip(filter.skip) - .filter_map(map_filter) - .take(filter.len) - .collect::>()) - } - })?; - - Ok((data.map_err(|e: DatabaseError| eyre::eyre!(e))?, hits)) - } - - /// Grabs the content of the table for the given key - pub fn get(&self, key: T::Key) -> Result> { - self.db.view(|tx| tx.get::(key))?.map_err(|e| eyre::eyre!(e)) - } - - /// Grabs the content of the DupSort table for the given key and subkey - pub fn get_dup(&self, key: T::Key, subkey: T::SubKey) -> Result> { - self.db - .view(|tx| tx.cursor_dup_read::()?.seek_by_key_subkey(key, subkey))? - .map_err(|e| eyre::eyre!(e)) - } - - /// Drops the database at the given path. - pub fn drop(&mut self, path: impl AsRef) -> Result<()> { - let path = path.as_ref(); - info!(target: "reth::cli", "Dropping database at {:?}", path); - fs::remove_dir_all(path)?; - Ok(()) - } - - /// Drops the provided table from the database. - pub fn drop_table(&mut self) -> Result<()> { - self.db.update(|tx| tx.clear::())??; - Ok(()) - } -} - -/// Parses a user-specified path with support for environment variables and common shorthands (e.g. -/// ~ for the user's home directory). -pub fn parse_path(value: &str) -> Result> { - shellexpand::full(value).map(|path| PathBuf::from(path.into_owned())) -} - -/// Filters the results coming from the database. -#[derive(Debug)] -pub struct ListFilter { - /// Skip first N entries. - pub skip: usize, - /// Take N entries. - pub len: usize, - /// Sequence of bytes that will be searched on values and keys from the database. - pub search: Vec, - /// Minimum row size. - pub min_row_size: usize, - /// Minimum key size. - pub min_key_size: usize, - /// Minimum value size. - pub min_value_size: usize, - /// Reverse order of entries. - pub reverse: bool, - /// Only counts the number of filtered entries without decoding and returning them. - pub only_count: bool, -} - -impl ListFilter { - /// If `search` has a list of bytes, then filter for rows that have this sequence. - pub fn has_search(&self) -> bool { - !self.search.is_empty() - } - - /// Updates the page with new `skip` and `len` values. - pub fn update_page(&mut self, skip: usize, len: usize) { - self.skip = skip; - self.len = len; - } -} - -/// Attempts to retrieve or create a JWT secret from the specified path. -pub fn get_or_create_jwt_secret_from_path(path: &Path) -> Result { - if path.exists() { - debug!(target: "reth::cli", ?path, "Reading JWT auth secret file"); - JwtSecret::from_file(path) - } else { - info!(target: "reth::cli", ?path, "Creating JWT auth secret file"); - JwtSecret::try_create(path) - } -} - -/// Collect the peers from the [NetworkManager] and write them to the given `persistent_peers_file`, -/// if configured. -pub fn write_peers_to_file(network: &NetworkManager, persistent_peers_file: Option) -where - C: BlockReader + Unpin, -{ - if let Some(file_path) = persistent_peers_file { - let known_peers = network.all_peers().collect::>(); - if let Ok(known_peers) = serde_json::to_string_pretty(&known_peers) { - trace!(target: "reth::cli", peers_file =?file_path, num_peers=%known_peers.len(), "Saving current peers"); - let parent_dir = file_path.parent().map(fs::create_dir_all).transpose(); - match parent_dir.and_then(|_| fs::write(&file_path, known_peers)) { - Ok(_) => { - info!(target: "reth::cli", peers_file=?file_path, "Wrote network peers to file"); - } - Err(err) => { - warn!(target: "reth::cli", ?err, peers_file=?file_path, "Failed to write network peers to file"); - } - } - } - } -} diff --git a/bin/reth/src/version.rs b/bin/reth/src/version.rs deleted file mode 100644 index 56933848a5..0000000000 --- a/bin/reth/src/version.rs +++ /dev/null @@ -1,104 +0,0 @@ -//! Version information for reth. - -/// The short version information for reth. -/// -/// - The latest version from Cargo.toml -/// - The short SHA of the latest commit. -/// -/// # Example -/// -/// ```text -/// 0.1.0 (defa64b2) -/// ``` -pub(crate) const SHORT_VERSION: &str = - concat!(env!("CARGO_PKG_VERSION"), " (", env!("VERGEN_GIT_SHA"), ")"); - -/// The long version information for reth. -/// -/// - The latest version from Cargo.toml -/// - The long SHA of the latest commit. -/// - The build datetime -/// - The build features -/// -/// # Example: -/// -/// ```text -/// Version: 0.1.0 -/// Commit SHA: defa64b2 -/// Build Timestamp: 2023-05-19T01:47:19.815651705Z -/// Build Features: jemalloc -/// ``` -pub(crate) const LONG_VERSION: &str = const_str::concat!( - "Version: ", - env!("CARGO_PKG_VERSION"), - "\n", - "Commit SHA: ", - env!("VERGEN_GIT_SHA"), - "\n", - "Build Timestamp: ", - env!("VERGEN_BUILD_TIMESTAMP"), - "\n", - "Build Features: ", - env!("VERGEN_CARGO_FEATURES"), - "\n", - "Build Profile: ", - build_profile_name() -); - -/// The version information for reth formatted for P2P (devp2p). -/// -/// - The latest version from Cargo.toml -/// - The target triple -/// -/// # Example -/// -/// ```text -/// reth/v{major}.{minor}.{patch}-{sha1}/{target} -/// ``` -/// e.g.: `reth/v0.1.0-alpha.1-428a6dc2f/aarch64-apple-darwin` -pub(crate) const P2P_CLIENT_VERSION: &str = concat!( - "reth/v", - env!("CARGO_PKG_VERSION"), - "-", - env!("VERGEN_GIT_SHA"), - "/", - env!("VERGEN_CARGO_TARGET_TRIPLE") -); - -/// The default extradata used for payload building. -/// -/// - The latest version from Cargo.toml -/// - The OS identifier -/// -/// # Example -/// -/// ```text -/// reth/v{major}.{minor}.{patch}/{OS} -/// ``` -pub fn default_extradata() -> String { - format!("reth/v{}/{}", env!("CARGO_PKG_VERSION"), std::env::consts::OS) -} - -const fn build_profile_name() -> &'static str { - // Derived from https://stackoverflow.com/questions/73595435/how-to-get-profile-from-cargo-toml-in-build-rs-or-at-runtime - // We split on the path separator of the *host* machine, which may be different from - // `std::path::MAIN_SEPARATOR_STR`. - const OUT_DIR: &str = env!("OUT_DIR"); - const SEP: char = if const_str::contains!(OUT_DIR, "/") { '/' } else { '\\' }; - let parts = const_str::split!(OUT_DIR, SEP); - parts[parts.len() - 4] -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn assert_extradata_less_32bytes() { - let extradata = default_extradata(); - assert!( - extradata.as_bytes().len() <= 32, - "extradata must be less than 32 bytes: {extradata}" - ) - } -} diff --git a/crates/node-core/src/args/network_args.rs b/crates/node-core/src/args/network_args.rs index 57f6149ec7..23a4a124d5 100644 --- a/crates/node-core/src/args/network_args.rs +++ b/crates/node-core/src/args/network_args.rs @@ -122,6 +122,21 @@ impl NetworkArgs { Some(peers_file) } + + /// Sets the p2p port to zero, to allow the OS to assign a random unused port when + /// the network components bind to a socket. + pub fn with_unused_p2p_port(mut self) -> Self { + self.port = 0; + self + } + + /// Sets the p2p and discovery ports to zero, allowing the OD to assign a random unused port + /// when network components bind to sockets. + pub fn with_unused_ports(mut self) -> Self { + self = self.with_unused_p2p_port(); + self.discovery = self.discovery.with_unused_discovery_port(); + self + } } impl Default for NetworkArgs { @@ -183,6 +198,13 @@ impl DiscoveryArgs { } network_config_builder } + + /// Set the discovery port to zero, to allow the OS to assign a random unused port when + /// discovery binds to the socket. + pub fn with_unused_discovery_port(mut self) -> Self { + self.port = 0; + self + } } impl Default for DiscoveryArgs { diff --git a/crates/node-core/src/args/rpc_server_args.rs b/crates/node-core/src/args/rpc_server_args.rs index 9b153c2fbf..e0c6fcd8f8 100644 --- a/crates/node-core/src/args/rpc_server_args.rs +++ b/crates/node-core/src/args/rpc_server_args.rs @@ -17,6 +17,7 @@ use clap::{ Arg, Args, Command, }; use futures::TryFutureExt; +use rand::Rng; use reth_network_api::{NetworkInfo, Peers}; use reth_node_api::EngineTypes; use reth_provider::{ @@ -220,6 +221,49 @@ impl RpcServerArgs { self.ipcpath = format!("{}-{}", self.ipcpath, instance); } + /// Set the http port to zero, to allow the OS to assign a random unused port when the rpc + /// server binds to a socket. + pub fn with_http_unused_port(mut self) -> Self { + self.http_port = 0; + self + } + + /// Set the ws port to zero, to allow the OS to assign a random unused port when the rpc + /// server binds to a socket. + pub fn with_ws_unused_port(mut self) -> Self { + self.ws_port = 0; + self + } + + /// Set the auth port to zero, to allow the OS to assign a random unused port when the rpc + /// server binds to a socket. + pub fn with_auth_unused_port(mut self) -> Self { + self.auth_port = 0; + self + } + + /// Append a random string to the ipc path, to prevent possible collisions when multiple nodes + /// are being run on the same machine. + pub fn with_ipc_random_path(mut self) -> Self { + let random_string: String = rand::thread_rng() + .sample_iter(rand::distributions::Alphanumeric) + .take(8) + .map(char::from) + .collect(); + self.ipcpath = format!("{}-{}", self.ipcpath, random_string); + self + } + + /// Configure all ports to be set to a random unused port when bound, and set the IPC path to a + /// random path. + pub fn with_unused_ports(mut self) -> Self { + self = self.with_http_unused_port(); + self = self.with_ws_unused_port(); + self = self.with_auth_unused_port(); + self = self.with_ipc_random_path(); + self + } + /// Configures and launches _all_ servers. /// /// Returns the handles for the launched regular RPC server(s) (if any) and the server handle diff --git a/crates/node-core/src/utils.rs b/crates/node-core/src/utils.rs index 38a824fb9a..7b92ec7f12 100644 --- a/crates/node-core/src/utils.rs +++ b/crates/node-core/src/utils.rs @@ -102,13 +102,15 @@ where /// Wrapper over DB that implements many useful DB queries. pub struct DbTool<'a, DB: Database> { - pub(crate) db: &'a DB, - pub(crate) chain: Arc, + /// The database that the db tool will use. + pub db: &'a DB, + /// The [ChainSpec] that the db tool will use. + pub chain: Arc, } impl<'a, DB: Database> DbTool<'a, DB> { /// Takes a DB where the tables have already been created. - pub(crate) fn new(db: &'a DB, chain: Arc) -> eyre::Result { + pub fn new(db: &'a DB, chain: Arc) -> eyre::Result { Ok(Self { db, chain }) } diff --git a/crates/node-core/src/version.rs b/crates/node-core/src/version.rs index 56933848a5..06afd7e4dc 100644 --- a/crates/node-core/src/version.rs +++ b/crates/node-core/src/version.rs @@ -10,7 +10,7 @@ /// ```text /// 0.1.0 (defa64b2) /// ``` -pub(crate) const SHORT_VERSION: &str = +pub const SHORT_VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), " (", env!("VERGEN_GIT_SHA"), ")"); /// The long version information for reth. @@ -28,7 +28,7 @@ pub(crate) const SHORT_VERSION: &str = /// Build Timestamp: 2023-05-19T01:47:19.815651705Z /// Build Features: jemalloc /// ``` -pub(crate) const LONG_VERSION: &str = const_str::concat!( +pub const LONG_VERSION: &str = const_str::concat!( "Version: ", env!("CARGO_PKG_VERSION"), "\n",