mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-04-30 03:01:58 -04:00
chore: move node command to reth-cli-commands (#9395)
This commit is contained in:
@@ -5,17 +5,16 @@ use crate::{
|
||||
utils::{chain_help, chain_value_parser, SUPPORTED_CHAINS},
|
||||
LogArgs,
|
||||
},
|
||||
commands::{
|
||||
debug_cmd, import,
|
||||
node::{self, NoArgs},
|
||||
},
|
||||
commands::{debug_cmd, import},
|
||||
macros::block_executor,
|
||||
version::{LONG_VERSION, SHORT_VERSION},
|
||||
};
|
||||
use clap::{value_parser, Parser, Subcommand};
|
||||
use reth_chainspec::ChainSpec;
|
||||
use reth_cli_commands::{
|
||||
config_cmd, db, dump_genesis, init_cmd, init_state, p2p, prune, recover, stage,
|
||||
config_cmd, db, dump_genesis, init_cmd, init_state,
|
||||
node::{self, NoArgs},
|
||||
p2p, prune, recover, stage,
|
||||
};
|
||||
use reth_cli_runner::CliRunner;
|
||||
use reth_db::DatabaseEnv;
|
||||
|
||||
@@ -2,4 +2,3 @@
|
||||
|
||||
pub mod debug_cmd;
|
||||
pub mod import;
|
||||
pub mod node;
|
||||
|
||||
@@ -1,389 +0,0 @@
|
||||
//! Main node command for launching a node
|
||||
|
||||
use crate::args::{
|
||||
utils::{chain_help, chain_value_parser, SUPPORTED_CHAINS},
|
||||
DatabaseArgs, DatadirArgs, DebugArgs, DevArgs, NetworkArgs, PayloadBuilderArgs, PruningArgs,
|
||||
RpcServerArgs, TxPoolArgs,
|
||||
};
|
||||
use clap::{value_parser, Args, Parser};
|
||||
use reth_chainspec::ChainSpec;
|
||||
use reth_cli_runner::CliContext;
|
||||
use reth_cli_util::parse_socket_address;
|
||||
use reth_db::{init_db, DatabaseEnv};
|
||||
use reth_node_builder::{NodeBuilder, WithLaunchContext};
|
||||
use reth_node_core::{node_config::NodeConfig, version};
|
||||
use std::{ffi::OsString, fmt, future::Future, net::SocketAddr, path::PathBuf, sync::Arc};
|
||||
|
||||
/// Start the node
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct NodeCommand<Ext: clap::Args + fmt::Debug = NoArgs> {
|
||||
/// The path to the configuration file to use.
|
||||
#[arg(long, value_name = "FILE", verbatim_doc_comment)]
|
||||
pub config: Option<PathBuf>,
|
||||
|
||||
/// The chain this node is running.
|
||||
///
|
||||
/// Possible values are either a built-in chain or the path to a chain specification file.
|
||||
#[arg(
|
||||
long,
|
||||
value_name = "CHAIN_OR_PATH",
|
||||
long_help = chain_help(),
|
||||
default_value = SUPPORTED_CHAINS[0],
|
||||
default_value_if("dev", "true", "dev"),
|
||||
value_parser = chain_value_parser,
|
||||
required = false,
|
||||
)]
|
||||
pub chain: Arc<ChainSpec>,
|
||||
|
||||
/// Enable Prometheus metrics.
|
||||
///
|
||||
/// The metrics will be served at the given interface and port.
|
||||
#[arg(long, value_name = "SOCKET", value_parser = parse_socket_address, help_heading = "Metrics")]
|
||||
pub metrics: Option<SocketAddr>,
|
||||
|
||||
/// Add a new instance of a node.
|
||||
///
|
||||
/// Configures the ports of the node to avoid conflicts with the defaults.
|
||||
/// This is useful for running multiple nodes on the same machine.
|
||||
///
|
||||
/// Max number of instances is 200. It is chosen in a way so that it's not possible to have
|
||||
/// port numbers that conflict with each other.
|
||||
///
|
||||
/// Changes to the following port numbers:
|
||||
/// - `DISCOVERY_PORT`: default + `instance` - 1
|
||||
/// - `AUTH_PORT`: default + `instance` * 100 - 100
|
||||
/// - `HTTP_RPC_PORT`: default - `instance` + 1
|
||||
/// - `WS_RPC_PORT`: default + `instance` * 2 - 2
|
||||
#[arg(long, value_name = "INSTANCE", global = true, default_value_t = 1, value_parser = value_parser!(u16).range(..=200))]
|
||||
pub instance: u16,
|
||||
|
||||
/// Sets all ports to unused, allowing the OS to choose random unused ports when sockets are
|
||||
/// bound.
|
||||
///
|
||||
/// Mutually exclusive with `--instance`.
|
||||
#[arg(long, conflicts_with = "instance", global = true)]
|
||||
pub with_unused_ports: bool,
|
||||
|
||||
/// All datadir related arguments
|
||||
#[command(flatten)]
|
||||
pub datadir: DatadirArgs,
|
||||
|
||||
/// All networking related arguments
|
||||
#[command(flatten)]
|
||||
pub network: NetworkArgs,
|
||||
|
||||
/// All rpc related arguments
|
||||
#[command(flatten)]
|
||||
pub rpc: RpcServerArgs,
|
||||
|
||||
/// All txpool related arguments with --txpool prefix
|
||||
#[command(flatten)]
|
||||
pub txpool: TxPoolArgs,
|
||||
|
||||
/// All payload builder related arguments
|
||||
#[command(flatten)]
|
||||
pub builder: PayloadBuilderArgs,
|
||||
|
||||
/// All debug related arguments with --debug prefix
|
||||
#[command(flatten)]
|
||||
pub debug: DebugArgs,
|
||||
|
||||
/// All database related arguments
|
||||
#[command(flatten)]
|
||||
pub db: DatabaseArgs,
|
||||
|
||||
/// All dev related arguments with --dev prefix
|
||||
#[command(flatten)]
|
||||
pub dev: DevArgs,
|
||||
|
||||
/// All pruning related arguments
|
||||
#[command(flatten)]
|
||||
pub pruning: PruningArgs,
|
||||
|
||||
/// Additional cli arguments
|
||||
#[command(flatten, next_help_heading = "Extension")]
|
||||
pub ext: Ext,
|
||||
}
|
||||
|
||||
impl NodeCommand {
|
||||
/// Parsers only the default CLI arguments
|
||||
pub fn parse_args() -> Self {
|
||||
Self::parse()
|
||||
}
|
||||
|
||||
/// Parsers only the default [`NodeCommand`] arguments from the given iterator
|
||||
pub fn try_parse_args_from<I, T>(itr: I) -> Result<Self, clap::error::Error>
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
T: Into<OsString> + Clone,
|
||||
{
|
||||
Self::try_parse_from(itr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ext: clap::Args + fmt::Debug> NodeCommand<Ext> {
|
||||
/// Launches the node
|
||||
///
|
||||
/// This transforms the node command into a node config and launches the node using the given
|
||||
/// closure.
|
||||
pub async fn execute<L, Fut>(self, ctx: CliContext, launcher: L) -> eyre::Result<()>
|
||||
where
|
||||
L: FnOnce(WithLaunchContext<NodeBuilder<Arc<DatabaseEnv>>>, Ext) -> Fut,
|
||||
Fut: Future<Output = eyre::Result<()>>,
|
||||
{
|
||||
tracing::info!(target: "reth::cli", version = ?version::SHORT_VERSION, "Starting reth");
|
||||
|
||||
let Self {
|
||||
datadir,
|
||||
config,
|
||||
chain,
|
||||
metrics,
|
||||
instance,
|
||||
with_unused_ports,
|
||||
network,
|
||||
rpc,
|
||||
txpool,
|
||||
builder,
|
||||
debug,
|
||||
db,
|
||||
dev,
|
||||
pruning,
|
||||
ext,
|
||||
} = self;
|
||||
|
||||
// set up node config
|
||||
let mut node_config = NodeConfig {
|
||||
datadir,
|
||||
config,
|
||||
chain,
|
||||
metrics,
|
||||
instance,
|
||||
network,
|
||||
rpc,
|
||||
txpool,
|
||||
builder,
|
||||
debug,
|
||||
db,
|
||||
dev,
|
||||
pruning,
|
||||
};
|
||||
|
||||
// Register the prometheus recorder before creating the database,
|
||||
// because database init needs it to register metrics.
|
||||
let _ = node_config.install_prometheus_recorder()?;
|
||||
|
||||
let data_dir = node_config.datadir();
|
||||
let db_path = data_dir.db();
|
||||
|
||||
tracing::info!(target: "reth::cli", path = ?db_path, "Opening database");
|
||||
let database = Arc::new(init_db(db_path.clone(), self.db.database_args())?.with_metrics());
|
||||
|
||||
if with_unused_ports {
|
||||
node_config = node_config.with_unused_ports();
|
||||
}
|
||||
|
||||
let builder = NodeBuilder::new(node_config)
|
||||
.with_database(database)
|
||||
.with_launch_context(ctx.task_executor);
|
||||
|
||||
launcher(builder, ext).await
|
||||
}
|
||||
}
|
||||
|
||||
/// No Additional arguments
|
||||
#[derive(Debug, Clone, Copy, Default, Args)]
|
||||
#[non_exhaustive]
|
||||
pub struct NoArgs;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use reth_discv4::DEFAULT_DISCOVERY_PORT;
|
||||
use std::{
|
||||
net::{IpAddr, Ipv4Addr},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn parse_help_node_command() {
|
||||
let err = NodeCommand::try_parse_args_from(["reth", "--help"]).unwrap_err();
|
||||
assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_common_node_command_chain_args() {
|
||||
for chain in SUPPORTED_CHAINS {
|
||||
let args: NodeCommand = NodeCommand::<NoArgs>::parse_from(["reth", "--chain", chain]);
|
||||
assert_eq!(args.chain.chain, chain.parse::<reth_chainspec::Chain>().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_discovery_addr() {
|
||||
let cmd =
|
||||
NodeCommand::try_parse_args_from(["reth", "--discovery.addr", "127.0.0.1"]).unwrap();
|
||||
assert_eq!(cmd.network.discovery.addr, IpAddr::V4(Ipv4Addr::LOCALHOST));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_addr() {
|
||||
let cmd = NodeCommand::try_parse_args_from([
|
||||
"reth",
|
||||
"--discovery.addr",
|
||||
"127.0.0.1",
|
||||
"--addr",
|
||||
"127.0.0.1",
|
||||
])
|
||||
.unwrap();
|
||||
assert_eq!(cmd.network.discovery.addr, IpAddr::V4(Ipv4Addr::LOCALHOST));
|
||||
assert_eq!(cmd.network.addr, IpAddr::V4(Ipv4Addr::LOCALHOST));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_discovery_port() {
|
||||
let cmd = NodeCommand::try_parse_args_from(["reth", "--discovery.port", "300"]).unwrap();
|
||||
assert_eq!(cmd.network.discovery.port, 300);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_port() {
|
||||
let cmd =
|
||||
NodeCommand::try_parse_args_from(["reth", "--discovery.port", "300", "--port", "99"])
|
||||
.unwrap();
|
||||
assert_eq!(cmd.network.discovery.port, 300);
|
||||
assert_eq!(cmd.network.port, 99);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_metrics_port() {
|
||||
let cmd = NodeCommand::try_parse_args_from(["reth", "--metrics", "9001"]).unwrap();
|
||||
assert_eq!(cmd.metrics, Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 9001)));
|
||||
|
||||
let cmd = NodeCommand::try_parse_args_from(["reth", "--metrics", ":9001"]).unwrap();
|
||||
assert_eq!(cmd.metrics, Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 9001)));
|
||||
|
||||
let cmd =
|
||||
NodeCommand::try_parse_args_from(["reth", "--metrics", "localhost:9001"]).unwrap();
|
||||
assert_eq!(cmd.metrics, Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 9001)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_config_path() {
|
||||
let cmd =
|
||||
NodeCommand::try_parse_args_from(["reth", "--config", "my/path/to/reth.toml"]).unwrap();
|
||||
// always store reth.toml in the data dir, not the chain specific data dir
|
||||
let data_dir = cmd.datadir.resolve_datadir(cmd.chain.chain);
|
||||
let config_path = cmd.config.unwrap_or_else(|| data_dir.config());
|
||||
assert_eq!(config_path, Path::new("my/path/to/reth.toml"));
|
||||
|
||||
let cmd = NodeCommand::try_parse_args_from(["reth"]).unwrap();
|
||||
|
||||
// always store reth.toml in the data dir, not the chain specific data dir
|
||||
let data_dir = cmd.datadir.resolve_datadir(cmd.chain.chain);
|
||||
let config_path = cmd.config.clone().unwrap_or_else(|| data_dir.config());
|
||||
let end = format!("{}/reth.toml", SUPPORTED_CHAINS[0]);
|
||||
assert!(config_path.ends_with(end), "{:?}", cmd.config);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_db_path() {
|
||||
let cmd = NodeCommand::try_parse_args_from(["reth"]).unwrap();
|
||||
let data_dir = cmd.datadir.resolve_datadir(cmd.chain.chain);
|
||||
|
||||
let db_path = data_dir.db();
|
||||
let end = format!("reth/{}/db", SUPPORTED_CHAINS[0]);
|
||||
assert!(db_path.ends_with(end), "{:?}", cmd.config);
|
||||
|
||||
let cmd =
|
||||
NodeCommand::try_parse_args_from(["reth", "--datadir", "my/custom/path"]).unwrap();
|
||||
let data_dir = cmd.datadir.resolve_datadir(cmd.chain.chain);
|
||||
|
||||
let db_path = data_dir.db();
|
||||
assert_eq!(db_path, Path::new("my/custom/path/db"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(feature = "optimism"))] // dev mode not yet supported in op-reth
|
||||
fn parse_dev() {
|
||||
let cmd = NodeCommand::<NoArgs>::parse_from(["reth", "--dev"]);
|
||||
let chain = reth_chainspec::DEV.clone();
|
||||
assert_eq!(cmd.chain.chain, chain.chain);
|
||||
assert_eq!(cmd.chain.genesis_hash, chain.genesis_hash);
|
||||
assert_eq!(
|
||||
cmd.chain.paris_block_and_final_difficulty,
|
||||
chain.paris_block_and_final_difficulty
|
||||
);
|
||||
assert_eq!(cmd.chain.hardforks, chain.hardforks);
|
||||
|
||||
assert!(cmd.rpc.http);
|
||||
assert!(cmd.network.discovery.disable_discovery);
|
||||
|
||||
assert!(cmd.dev.dev);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_instance() {
|
||||
let mut cmd = NodeCommand::<NoArgs>::parse_from(["reth"]);
|
||||
cmd.rpc.adjust_instance_ports(cmd.instance);
|
||||
cmd.network.port = DEFAULT_DISCOVERY_PORT + cmd.instance - 1;
|
||||
// check rpc port numbers
|
||||
assert_eq!(cmd.rpc.auth_port, 8551);
|
||||
assert_eq!(cmd.rpc.http_port, 8545);
|
||||
assert_eq!(cmd.rpc.ws_port, 8546);
|
||||
// check network listening port number
|
||||
assert_eq!(cmd.network.port, 30303);
|
||||
|
||||
let mut cmd = NodeCommand::<NoArgs>::parse_from(["reth", "--instance", "2"]);
|
||||
cmd.rpc.adjust_instance_ports(cmd.instance);
|
||||
cmd.network.port = DEFAULT_DISCOVERY_PORT + cmd.instance - 1;
|
||||
// check rpc port numbers
|
||||
assert_eq!(cmd.rpc.auth_port, 8651);
|
||||
assert_eq!(cmd.rpc.http_port, 8544);
|
||||
assert_eq!(cmd.rpc.ws_port, 8548);
|
||||
// check network listening port number
|
||||
assert_eq!(cmd.network.port, 30304);
|
||||
|
||||
let mut cmd = NodeCommand::<NoArgs>::parse_from(["reth", "--instance", "3"]);
|
||||
cmd.rpc.adjust_instance_ports(cmd.instance);
|
||||
cmd.network.port = DEFAULT_DISCOVERY_PORT + cmd.instance - 1;
|
||||
// check rpc port numbers
|
||||
assert_eq!(cmd.rpc.auth_port, 8751);
|
||||
assert_eq!(cmd.rpc.http_port, 8543);
|
||||
assert_eq!(cmd.rpc.ws_port, 8550);
|
||||
// check network listening port number
|
||||
assert_eq!(cmd.network.port, 30305);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_with_unused_ports() {
|
||||
let cmd = NodeCommand::<NoArgs>::parse_from(["reth", "--with-unused-ports"]);
|
||||
assert!(cmd.with_unused_ports);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_unused_ports_conflicts_with_instance() {
|
||||
let err =
|
||||
NodeCommand::try_parse_args_from(["reth", "--with-unused-ports", "--instance", "2"])
|
||||
.unwrap_err();
|
||||
assert_eq!(err.kind(), clap::error::ErrorKind::ArgumentConflict);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_unused_ports_check_zero() {
|
||||
let mut cmd = NodeCommand::<NoArgs>::parse_from(["reth"]);
|
||||
cmd.rpc = cmd.rpc.with_unused_ports();
|
||||
cmd.network = cmd.network.with_unused_ports();
|
||||
|
||||
// make sure the rpc ports are zero
|
||||
assert_eq!(cmd.rpc.auth_port, 0);
|
||||
assert_eq!(cmd.rpc.http_port, 0);
|
||||
assert_eq!(cmd.rpc.ws_port, 0);
|
||||
|
||||
// make sure the network ports are zero
|
||||
assert_eq!(cmd.network.port, 0);
|
||||
assert_eq!(cmd.network.discovery.port, 0);
|
||||
|
||||
// make sure the ipc path is not the default
|
||||
assert_ne!(cmd.rpc.ipcpath, String::from("/tmp/reth.ipc"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user