feat: introduce ChainSpecParser generic in cli types (#10582)

This commit is contained in:
Arsenii Kulikov
2024-08-30 00:13:16 +04:00
committed by GitHub
parent be57b648a7
commit 51524f2534
43 changed files with 400 additions and 325 deletions

4
Cargo.lock generated
View File

@ -6074,6 +6074,7 @@ dependencies = [
"reth-beacon-consensus", "reth-beacon-consensus",
"reth-blockchain-tree", "reth-blockchain-tree",
"reth-chainspec", "reth-chainspec",
"reth-cli",
"reth-cli-commands", "reth-cli-commands",
"reth-cli-runner", "reth-cli-runner",
"reth-cli-util", "reth-cli-util",
@ -6399,6 +6400,7 @@ dependencies = [
"ratatui", "ratatui",
"reth-beacon-consensus", "reth-beacon-consensus",
"reth-chainspec", "reth-chainspec",
"reth-cli",
"reth-cli-runner", "reth-cli-runner",
"reth-cli-util", "reth-cli-util",
"reth-config", "reth-config",
@ -7019,7 +7021,6 @@ name = "reth-ethereum-cli"
version = "1.0.6" version = "1.0.6"
dependencies = [ dependencies = [
"alloy-genesis", "alloy-genesis",
"clap",
"eyre", "eyre",
"reth-chainspec", "reth-chainspec",
"reth-cli", "reth-cli",
@ -7603,6 +7604,7 @@ dependencies = [
"proptest", "proptest",
"rand 0.8.5", "rand 0.8.5",
"reth-chainspec", "reth-chainspec",
"reth-cli",
"reth-cli-util", "reth-cli-util",
"reth-config", "reth-config",
"reth-consensus-common", "reth-consensus-common",

View File

@ -14,6 +14,7 @@ workspace = true
[dependencies] [dependencies]
# reth # reth
reth-cli.workspace = true
reth-chainspec.workspace = true reth-chainspec.workspace = true
reth-config.workspace = true reth-config.workspace = true
reth-primitives.workspace = true reth-primitives.workspace = true

View File

@ -1,16 +1,14 @@
//! CLI definition and entrypoint to executable //! CLI definition and entrypoint to executable
use crate::{ use crate::{
args::{ args::{utils::chain_help, LogArgs},
utils::{chain_help, chain_value_parser, SUPPORTED_CHAINS},
LogArgs,
},
commands::debug_cmd, commands::debug_cmd,
macros::block_executor, macros::block_executor,
version::{LONG_VERSION, SHORT_VERSION}, version::{LONG_VERSION, SHORT_VERSION},
}; };
use clap::{value_parser, Parser, Subcommand}; use clap::{value_parser, Parser, Subcommand};
use reth_chainspec::ChainSpec; use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_cli_commands::{ use reth_cli_commands::{
config_cmd, db, dump_genesis, import, init_cmd, init_state, config_cmd, db, dump_genesis, import, init_cmd, init_state,
node::{self, NoArgs}, node::{self, NoArgs},
@ -19,6 +17,7 @@ use reth_cli_commands::{
use reth_cli_runner::CliRunner; use reth_cli_runner::CliRunner;
use reth_db::DatabaseEnv; use reth_db::DatabaseEnv;
use reth_node_builder::{NodeBuilder, WithLaunchContext}; use reth_node_builder::{NodeBuilder, WithLaunchContext};
use reth_node_core::args::utils::DefaultChainSpecParser;
use reth_tracing::FileWorkerGuard; use reth_tracing::FileWorkerGuard;
use std::{ffi::OsString, fmt, future::Future, sync::Arc}; use std::{ffi::OsString, fmt, future::Future, sync::Arc};
use tracing::info; use tracing::info;
@ -35,10 +34,10 @@ pub use crate::core::cli::*;
/// This is the entrypoint to the executable. /// This is the entrypoint to the executable.
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
#[command(author, version = SHORT_VERSION, long_version = LONG_VERSION, about = "Reth", long_about = None)] #[command(author, version = SHORT_VERSION, long_version = LONG_VERSION, about = "Reth", long_about = None)]
pub struct Cli<Ext: clap::Args + fmt::Debug = NoArgs> { pub struct Cli<C: ChainSpecParser = DefaultChainSpecParser, Ext: clap::Args + fmt::Debug = NoArgs> {
/// The command to run /// The command to run
#[command(subcommand)] #[command(subcommand)]
command: Commands<Ext>, command: Commands<C, Ext>,
/// The chain this node is running. /// The chain this node is running.
/// ///
@ -47,11 +46,11 @@ pub struct Cli<Ext: clap::Args + fmt::Debug = NoArgs> {
long, long,
value_name = "CHAIN_OR_PATH", value_name = "CHAIN_OR_PATH",
long_help = chain_help(), long_help = chain_help(),
default_value = SUPPORTED_CHAINS[0], default_value = C::SUPPORTED_CHAINS[0],
value_parser = chain_value_parser, value_parser = C::parser(),
global = true, global = true,
)] )]
chain: Arc<ChainSpec>, chain: Arc<C::ChainSpec>,
/// Add a new instance of a node. /// Add a new instance of a node.
/// ///
@ -89,7 +88,7 @@ impl Cli {
} }
} }
impl<Ext: clap::Args + fmt::Debug> Cli<Ext> { impl<C: ChainSpecParser<ChainSpec = ChainSpec>, Ext: clap::Args + fmt::Debug> Cli<C, Ext> {
/// Execute the configured cli command. /// Execute the configured cli command.
/// ///
/// This accepts a closure that is used to launch the node via the /// This accepts a closure that is used to launch the node via the
@ -117,14 +116,14 @@ impl<Ext: clap::Args + fmt::Debug> Cli<Ext> {
/// ///
/// ```no_run /// ```no_run
/// use clap::Parser; /// use clap::Parser;
/// use reth::cli::Cli; /// use reth::{args::utils::DefaultChainSpecParser, cli::Cli};
/// ///
/// #[derive(Debug, Parser)] /// #[derive(Debug, Parser)]
/// pub struct MyArgs { /// pub struct MyArgs {
/// pub enable: bool, /// pub enable: bool,
/// } /// }
/// ///
/// Cli::parse() /// Cli::<DefaultChainSpecParser, MyArgs>::parse()
/// .run(|builder, my_args: MyArgs| async move { /// .run(|builder, my_args: MyArgs| async move {
/// // launch the node /// // launch the node
/// ///
@ -187,38 +186,38 @@ impl<Ext: clap::Args + fmt::Debug> Cli<Ext> {
/// Commands to be executed /// Commands to be executed
#[derive(Debug, Subcommand)] #[derive(Debug, Subcommand)]
pub enum Commands<Ext: clap::Args + fmt::Debug = NoArgs> { pub enum Commands<C: ChainSpecParser, Ext: clap::Args + fmt::Debug> {
/// Start the node /// Start the node
#[command(name = "node")] #[command(name = "node")]
Node(node::NodeCommand<Ext>), Node(Box<node::NodeCommand<C, Ext>>),
/// Initialize the database from a genesis file. /// Initialize the database from a genesis file.
#[command(name = "init")] #[command(name = "init")]
Init(init_cmd::InitCommand), Init(init_cmd::InitCommand<C>),
/// Initialize the database from a state dump file. /// Initialize the database from a state dump file.
#[command(name = "init-state")] #[command(name = "init-state")]
InitState(init_state::InitStateCommand), InitState(init_state::InitStateCommand<C>),
/// This syncs RLP encoded blocks from a file. /// This syncs RLP encoded blocks from a file.
#[command(name = "import")] #[command(name = "import")]
Import(import::ImportCommand), Import(import::ImportCommand<C>),
/// This syncs RLP encoded OP blocks below Bedrock from a file, without executing. /// This syncs RLP encoded OP blocks below Bedrock from a file, without executing.
#[cfg(feature = "optimism")] #[cfg(feature = "optimism")]
#[command(name = "import-op")] #[command(name = "import-op")]
ImportOp(reth_optimism_cli::ImportOpCommand), ImportOp(reth_optimism_cli::ImportOpCommand<C>),
/// This imports RLP encoded receipts from a file. /// This imports RLP encoded receipts from a file.
#[cfg(feature = "optimism")] #[cfg(feature = "optimism")]
#[command(name = "import-receipts-op")] #[command(name = "import-receipts-op")]
ImportReceiptsOp(reth_optimism_cli::ImportReceiptsOpCommand), ImportReceiptsOp(reth_optimism_cli::ImportReceiptsOpCommand<C>),
/// Dumps genesis block JSON configuration to stdout. /// Dumps genesis block JSON configuration to stdout.
DumpGenesis(dump_genesis::DumpGenesisCommand), DumpGenesis(dump_genesis::DumpGenesisCommand<C>),
/// Database debugging utilities /// Database debugging utilities
#[command(name = "db")] #[command(name = "db")]
Db(db::Command), Db(db::Command<C>),
/// Manipulate individual stages. /// Manipulate individual stages.
#[command(name = "stage")] #[command(name = "stage")]
Stage(stage::Command), Stage(stage::Command<C>),
/// P2P Debugging utilities /// P2P Debugging utilities
#[command(name = "p2p")] #[command(name = "p2p")]
P2P(p2p::Command), P2P(p2p::Command<C>),
/// Generate Test Vectors /// Generate Test Vectors
#[cfg(feature = "dev")] #[cfg(feature = "dev")]
#[command(name = "test-vectors")] #[command(name = "test-vectors")]
@ -228,13 +227,13 @@ pub enum Commands<Ext: clap::Args + fmt::Debug = NoArgs> {
Config(config_cmd::Command), Config(config_cmd::Command),
/// Various debug routines /// Various debug routines
#[command(name = "debug")] #[command(name = "debug")]
Debug(debug_cmd::Command), Debug(debug_cmd::Command<C>),
/// Scripts for node recovery /// Scripts for node recovery
#[command(name = "recover")] #[command(name = "recover")]
Recover(recover::Command), Recover(recover::Command<C>),
/// Prune according to the configuration without any limits /// Prune according to the configuration without any limits
#[command(name = "prune")] #[command(name = "prune")]
Prune(prune::PruneCommand), Prune(prune::PruneCommand<C>),
} }
#[cfg(test)] #[cfg(test)]
@ -242,6 +241,7 @@ mod tests {
use super::*; use super::*;
use crate::args::ColorMode; use crate::args::ColorMode;
use clap::CommandFactory; use clap::CommandFactory;
use reth_node_core::args::utils::SUPPORTED_CHAINS;
#[test] #[test]
fn parse_color_mode() { fn parse_color_mode() {
@ -254,7 +254,7 @@ mod tests {
/// runtime /// runtime
#[test] #[test]
fn test_parse_help_all_subcommands() { fn test_parse_help_all_subcommands() {
let reth = Cli::<NoArgs>::command(); let reth = Cli::<DefaultChainSpecParser, NoArgs>::command();
for sub_command in reth.get_subcommands() { for sub_command in reth.get_subcommands() {
let err = Cli::try_parse_args_from(["reth", sub_command.get_name(), "--help"]) let err = Cli::try_parse_args_from(["reth", sub_command.get_name(), "--help"])
.err() .err()

View File

@ -10,6 +10,8 @@ use reth_beacon_consensus::EthBeaconConsensus;
use reth_blockchain_tree::{ use reth_blockchain_tree::{
BlockchainTree, BlockchainTreeConfig, ShareableBlockchainTree, TreeExternals, BlockchainTree, BlockchainTreeConfig, ShareableBlockchainTree, TreeExternals,
}; };
use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_cli_commands::common::{AccessRights, Environment, EnvironmentArgs}; use reth_cli_commands::common::{AccessRights, Environment, EnvironmentArgs};
use reth_cli_runner::CliContext; use reth_cli_runner::CliContext;
use reth_consensus::Consensus; use reth_consensus::Consensus;
@ -46,9 +48,9 @@ use tracing::*;
/// This debug routine requires that the node is positioned at the block before the target. /// This debug routine requires that the node is positioned at the block before the target.
/// The script will then parse the block and attempt to build a similar one. /// The script will then parse the block and attempt to build a similar one.
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Command { pub struct Command<C: ChainSpecParser> {
#[command(flatten)] #[command(flatten)]
env: EnvironmentArgs, env: EnvironmentArgs<C>,
/// Overrides the KZG trusted setup by reading from the supplied file. /// Overrides the KZG trusted setup by reading from the supplied file.
#[arg(long, value_name = "PATH")] #[arg(long, value_name = "PATH")]
@ -77,7 +79,7 @@ pub struct Command {
blobs_bundle_path: Option<PathBuf>, blobs_bundle_path: Option<PathBuf>,
} }
impl Command { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
/// Fetches the best block block from the database. /// Fetches the best block block from the database.
/// ///
/// If the database is empty, returns the genesis block. /// If the database is empty, returns the genesis block.

View File

@ -5,6 +5,8 @@ use std::{path::PathBuf, sync::Arc};
use clap::Parser; use clap::Parser;
use futures::{stream::select as stream_select, StreamExt}; use futures::{stream::select as stream_select, StreamExt};
use reth_beacon_consensus::EthBeaconConsensus; use reth_beacon_consensus::EthBeaconConsensus;
use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_cli_commands::common::{AccessRights, Environment, EnvironmentArgs}; use reth_cli_commands::common::{AccessRights, Environment, EnvironmentArgs};
use reth_cli_runner::CliContext; use reth_cli_runner::CliContext;
use reth_cli_util::get_secret_key; use reth_cli_util::get_secret_key;
@ -38,9 +40,9 @@ use crate::{args::NetworkArgs, macros::block_executor, utils::get_single_header}
/// `reth debug execution` command /// `reth debug execution` command
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Command { pub struct Command<C: ChainSpecParser> {
#[command(flatten)] #[command(flatten)]
env: EnvironmentArgs, env: EnvironmentArgs<C>,
#[command(flatten)] #[command(flatten)]
network: NetworkArgs, network: NetworkArgs,
@ -55,7 +57,7 @@ pub struct Command {
pub interval: u64, pub interval: u64,
} }
impl Command { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
fn build_pipeline<DB, Client>( fn build_pipeline<DB, Client>(
&self, &self,
config: &Config, config: &Config,

View File

@ -4,6 +4,8 @@ use std::{path::PathBuf, sync::Arc};
use backon::{ConstantBuilder, Retryable}; use backon::{ConstantBuilder, Retryable};
use clap::Parser; use clap::Parser;
use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_cli_commands::common::{AccessRights, Environment, EnvironmentArgs}; use reth_cli_commands::common::{AccessRights, Environment, EnvironmentArgs};
use reth_cli_runner::CliContext; use reth_cli_runner::CliContext;
use reth_cli_util::get_secret_key; use reth_cli_util::get_secret_key;
@ -38,9 +40,9 @@ use crate::{
/// The script will then download the block from p2p network and attempt to calculate and verify /// The script will then download the block from p2p network and attempt to calculate and verify
/// merkle root for it. /// merkle root for it.
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Command { pub struct Command<C: ChainSpecParser> {
#[command(flatten)] #[command(flatten)]
env: EnvironmentArgs, env: EnvironmentArgs<C>,
#[command(flatten)] #[command(flatten)]
network: NetworkArgs, network: NetworkArgs,
@ -54,7 +56,7 @@ pub struct Command {
skip_node_depth: Option<usize>, skip_node_depth: Option<usize>,
} }
impl Command { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
async fn build_network( async fn build_network(
&self, &self,
config: &Config, config: &Config,

View File

@ -5,6 +5,8 @@ use std::{path::PathBuf, sync::Arc};
use backon::{ConstantBuilder, Retryable}; use backon::{ConstantBuilder, Retryable};
use clap::Parser; use clap::Parser;
use reth_beacon_consensus::EthBeaconConsensus; use reth_beacon_consensus::EthBeaconConsensus;
use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_cli_commands::common::{AccessRights, Environment, EnvironmentArgs}; use reth_cli_commands::common::{AccessRights, Environment, EnvironmentArgs};
use reth_cli_runner::CliContext; use reth_cli_runner::CliContext;
use reth_cli_util::get_secret_key; use reth_cli_util::get_secret_key;
@ -33,9 +35,9 @@ use crate::{args::NetworkArgs, macros::block_executor, utils::get_single_header}
/// `reth debug merkle` command /// `reth debug merkle` command
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Command { pub struct Command<C: ChainSpecParser> {
#[command(flatten)] #[command(flatten)]
env: EnvironmentArgs, env: EnvironmentArgs<C>,
#[command(flatten)] #[command(flatten)]
network: NetworkArgs, network: NetworkArgs,
@ -53,7 +55,7 @@ pub struct Command {
skip_node_depth: Option<usize>, skip_node_depth: Option<usize>,
} }
impl Command { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
async fn build_network( async fn build_network(
&self, &self,
config: &Config, config: &Config,

View File

@ -1,6 +1,8 @@
//! `reth debug` command. Collection of various debugging routines. //! `reth debug` command. Collection of various debugging routines.
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_cli_runner::CliContext; use reth_cli_runner::CliContext;
mod build_block; mod build_block;
@ -11,27 +13,27 @@ mod replay_engine;
/// `reth debug` command /// `reth debug` command
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Command { pub struct Command<C: ChainSpecParser> {
#[command(subcommand)] #[command(subcommand)]
command: Subcommands, command: Subcommands<C>,
} }
/// `reth debug` subcommands /// `reth debug` subcommands
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
pub enum Subcommands { pub enum Subcommands<C: ChainSpecParser> {
/// Debug the roundtrip execution of blocks as well as the generated data. /// Debug the roundtrip execution of blocks as well as the generated data.
Execution(execution::Command), Execution(execution::Command<C>),
/// Debug the clean & incremental state root calculations. /// Debug the clean & incremental state root calculations.
Merkle(merkle::Command), Merkle(merkle::Command<C>),
/// Debug in-memory state root calculation. /// Debug in-memory state root calculation.
InMemoryMerkle(in_memory_merkle::Command), InMemoryMerkle(in_memory_merkle::Command<C>),
/// Debug block building. /// Debug block building.
BuildBlock(build_block::Command), BuildBlock(build_block::Command<C>),
/// Debug engine API by replaying stored messages. /// Debug engine API by replaying stored messages.
ReplayEngine(replay_engine::Command), ReplayEngine(replay_engine::Command<C>),
} }
impl Command { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
/// Execute `debug` command /// Execute `debug` command
pub async fn execute(self, ctx: CliContext) -> eyre::Result<()> { pub async fn execute(self, ctx: CliContext) -> eyre::Result<()> {
match self.command { match self.command {

View File

@ -7,6 +7,8 @@ use reth_beacon_consensus::{hooks::EngineHooks, BeaconConsensusEngine, EthBeacon
use reth_blockchain_tree::{ use reth_blockchain_tree::{
BlockchainTree, BlockchainTreeConfig, ShareableBlockchainTree, TreeExternals, BlockchainTree, BlockchainTreeConfig, ShareableBlockchainTree, TreeExternals,
}; };
use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_cli_commands::common::{AccessRights, Environment, EnvironmentArgs}; use reth_cli_commands::common::{AccessRights, Environment, EnvironmentArgs};
use reth_cli_runner::CliContext; use reth_cli_runner::CliContext;
use reth_cli_util::get_secret_key; use reth_cli_util::get_secret_key;
@ -35,9 +37,9 @@ use crate::{args::NetworkArgs, macros::block_executor};
/// This script will read stored engine API messages and replay them by the timestamp. /// This script will read stored engine API messages and replay them by the timestamp.
/// It does not require /// It does not require
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Command { pub struct Command<C: ChainSpecParser> {
#[command(flatten)] #[command(flatten)]
env: EnvironmentArgs, env: EnvironmentArgs<C>,
#[command(flatten)] #[command(flatten)]
network: NetworkArgs, network: NetworkArgs,
@ -51,7 +53,7 @@ pub struct Command {
interval: u64, interval: u64,
} }
impl Command { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
async fn build_network( async fn build_network(
&self, &self,
config: &Config, config: &Config,

View File

@ -23,7 +23,7 @@ pub struct EngineArgs {
#[cfg(not(feature = "optimism"))] #[cfg(not(feature = "optimism"))]
fn main() { fn main() {
use clap::Parser; use clap::Parser;
use reth::cli::Cli; use reth::{args::utils::DefaultChainSpecParser, cli::Cli};
use reth_node_builder::EngineNodeLauncher; use reth_node_builder::EngineNodeLauncher;
use reth_node_ethereum::{node::EthereumAddOns, EthereumNode}; use reth_node_ethereum::{node::EthereumAddOns, EthereumNode};
use reth_provider::providers::BlockchainProvider2; use reth_provider::providers::BlockchainProvider2;
@ -35,30 +35,32 @@ fn main() {
std::env::set_var("RUST_BACKTRACE", "1"); std::env::set_var("RUST_BACKTRACE", "1");
} }
if let Err(err) = Cli::<EngineArgs>::parse().run(|builder, engine_args| async move { if let Err(err) =
let enable_engine2 = engine_args.experimental; Cli::<DefaultChainSpecParser, EngineArgs>::parse().run(|builder, engine_args| async move {
match enable_engine2 { let enable_engine2 = engine_args.experimental;
true => { match enable_engine2 {
let handle = builder true => {
.with_types_and_provider::<EthereumNode, BlockchainProvider2<_>>() let handle = builder
.with_components(EthereumNode::components()) .with_types_and_provider::<EthereumNode, BlockchainProvider2<_>>()
.with_add_ons::<EthereumAddOns>() .with_components(EthereumNode::components())
.launch_with_fn(|builder| { .with_add_ons::<EthereumAddOns>()
let launcher = EngineNodeLauncher::new( .launch_with_fn(|builder| {
builder.task_executor().clone(), let launcher = EngineNodeLauncher::new(
builder.config().datadir(), builder.task_executor().clone(),
); builder.config().datadir(),
builder.launch_with(launcher) );
}) builder.launch_with(launcher)
.await?; })
handle.node_exit_future.await .await?;
handle.node_exit_future.await
}
false => {
let handle = builder.launch_node(EthereumNode::default()).await?;
handle.node_exit_future.await
}
} }
false => { })
let handle = builder.launch_node(EthereumNode::default()).await?; {
handle.node_exit_future.await
}
}
}) {
eprintln!("Error: {err:?}"); eprintln!("Error: {err:?}");
std::process::exit(1); std::process::exit(1);
} }

View File

@ -17,6 +17,8 @@ compile_error!("Cannot build the `op-reth` binary with the `optimism` feature fl
#[cfg(feature = "optimism")] #[cfg(feature = "optimism")]
fn main() { fn main() {
use reth::args::utils::DefaultChainSpecParser;
reth_cli_util::sigsegv_handler::install(); reth_cli_util::sigsegv_handler::install();
// Enable backtraces unless a RUST_BACKTRACE value has already been explicitly provided. // Enable backtraces unless a RUST_BACKTRACE value has already been explicitly provided.
@ -24,56 +26,58 @@ fn main() {
std::env::set_var("RUST_BACKTRACE", "1"); std::env::set_var("RUST_BACKTRACE", "1");
} }
if let Err(err) = Cli::<RollupArgs>::parse().run(|builder, rollup_args| async move { if let Err(err) =
let enable_engine2 = rollup_args.experimental; Cli::<DefaultChainSpecParser, RollupArgs>::parse().run(|builder, rollup_args| async move {
let sequencer_http_arg = rollup_args.sequencer_http.clone(); let enable_engine2 = rollup_args.experimental;
match enable_engine2 { let sequencer_http_arg = rollup_args.sequencer_http.clone();
true => { match enable_engine2 {
let handle = builder true => {
.with_types_and_provider::<OptimismNode, BlockchainProvider2<_>>() let handle = builder
.with_components(OptimismNode::components(rollup_args)) .with_types_and_provider::<OptimismNode, BlockchainProvider2<_>>()
.with_add_ons::<OptimismAddOns>() .with_components(OptimismNode::components(rollup_args))
.extend_rpc_modules(move |ctx| { .with_add_ons::<OptimismAddOns>()
// register sequencer tx forwarder .extend_rpc_modules(move |ctx| {
if let Some(sequencer_http) = sequencer_http_arg { // register sequencer tx forwarder
ctx.registry if let Some(sequencer_http) = sequencer_http_arg {
.eth_api() ctx.registry
.set_sequencer_client(SequencerClient::new(sequencer_http)); .eth_api()
} .set_sequencer_client(SequencerClient::new(sequencer_http));
}
Ok(()) Ok(())
}) })
.launch_with_fn(|builder| { .launch_with_fn(|builder| {
let launcher = EngineNodeLauncher::new( let launcher = EngineNodeLauncher::new(
builder.task_executor().clone(), builder.task_executor().clone(),
builder.config().datadir(), builder.config().datadir(),
); );
builder.launch_with(launcher) builder.launch_with(launcher)
}) })
.await?; .await?;
handle.node_exit_future.await handle.node_exit_future.await
}
false => {
let handle = builder
.node(OptimismNode::new(rollup_args.clone()))
.extend_rpc_modules(move |ctx| {
// register sequencer tx forwarder
if let Some(sequencer_http) = sequencer_http_arg {
ctx.registry
.eth_api()
.set_sequencer_client(SequencerClient::new(sequencer_http));
}
Ok(())
})
.launch()
.await?;
handle.node_exit_future.await
}
} }
false => { })
let handle = builder {
.node(OptimismNode::new(rollup_args.clone()))
.extend_rpc_modules(move |ctx| {
// register sequencer tx forwarder
if let Some(sequencer_http) = sequencer_http_arg {
ctx.registry
.eth_api()
.set_sequencer_client(SequencerClient::new(sequencer_http));
}
Ok(())
})
.launch()
.await?;
handle.node_exit_future.await
}
}
}) {
eprintln!("Error: {err:?}"); eprintln!("Error: {err:?}");
std::process::exit(1); std::process::exit(1);
} }

View File

@ -2,12 +2,40 @@ use std::sync::Arc;
use clap::builder::TypedValueParser; use clap::builder::TypedValueParser;
#[derive(Debug, Clone)]
struct Parser<C>(std::marker::PhantomData<C>);
impl<C: ChainSpecParser> TypedValueParser for Parser<C> {
type Value = Arc<C::ChainSpec>;
fn parse_ref(
&self,
_cmd: &clap::Command,
arg: Option<&clap::Arg>,
value: &std::ffi::OsStr,
) -> Result<Self::Value, clap::Error> {
let val =
value.to_str().ok_or_else(|| clap::Error::new(clap::error::ErrorKind::InvalidUtf8))?;
C::parse(val).map_err(|err| {
let arg = arg.map(|a| a.to_string()).unwrap_or_else(|| "...".to_owned());
let possible_values = C::SUPPORTED_CHAINS.join(",");
let msg = format!(
"Invalid value '{val}' for {arg}: {err}.\n [possible values: {possible_values}]"
);
clap::Error::raw(clap::error::ErrorKind::InvalidValue, msg)
})
}
}
/// Trait for parsing chain specifications. /// Trait for parsing chain specifications.
/// ///
/// This trait extends [`clap::builder::TypedValueParser`] to provide a parser for chain /// This trait extends [`clap::builder::TypedValueParser`] to provide a parser for chain
/// specifications. Implementers of this trait must provide a list of supported chains and a /// specifications. Implementers of this trait must provide a list of supported chains and a
/// function to parse a given string into a chain spec. /// function to parse a given string into a chain spec.
pub trait ChainSpecParser<ChainSpec>: TypedValueParser<Value = Arc<ChainSpec>> + Default { pub trait ChainSpecParser: Clone + Send + Sync + 'static {
/// The chain specification type.
type ChainSpec: std::fmt::Debug + Send + Sync;
/// List of supported chains. /// List of supported chains.
const SUPPORTED_CHAINS: &'static [&'static str]; const SUPPORTED_CHAINS: &'static [&'static str];
@ -21,5 +49,10 @@ pub trait ChainSpecParser<ChainSpec>: TypedValueParser<Value = Arc<ChainSpec>> +
/// ///
/// This function will return an error if the input string cannot be parsed into a valid /// This function will return an error if the input string cannot be parsed into a valid
/// chain spec. /// chain spec.
fn parse(s: &str) -> eyre::Result<Arc<ChainSpec>>; fn parse(s: &str) -> eyre::Result<Arc<Self::ChainSpec>>;
/// Produces a [`TypedValueParser`] for this chain spec parser.
fn parser() -> impl TypedValueParser<Value = Arc<Self::ChainSpec>> {
Parser(std::marker::PhantomData::<Self>)
}
} }

View File

@ -12,6 +12,7 @@ repository.workspace = true
[dependencies] [dependencies]
reth-beacon-consensus.workspace = true reth-beacon-consensus.workspace = true
reth-chainspec.workspace = true reth-chainspec.workspace = true
reth-cli.workspace = true
reth-cli-runner.workspace = true reth-cli-runner.workspace = true
reth-cli-util.workspace = true reth-cli-util.workspace = true
reth-config.workspace = true reth-config.workspace = true

View File

@ -3,16 +3,14 @@
use clap::Parser; use clap::Parser;
use reth_beacon_consensus::EthBeaconConsensus; use reth_beacon_consensus::EthBeaconConsensus;
use reth_chainspec::ChainSpec; use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_config::{config::EtlConfig, Config}; use reth_config::{config::EtlConfig, Config};
use reth_db::{init_db, open_db_read_only, DatabaseEnv}; use reth_db::{init_db, open_db_read_only, DatabaseEnv};
use reth_db_common::init::init_genesis; use reth_db_common::init::init_genesis;
use reth_downloaders::{bodies::noop::NoopBodiesDownloader, headers::noop::NoopHeaderDownloader}; use reth_downloaders::{bodies::noop::NoopBodiesDownloader, headers::noop::NoopHeaderDownloader};
use reth_evm::noop::NoopBlockExecutorProvider; use reth_evm::noop::NoopBlockExecutorProvider;
use reth_node_core::{ use reth_node_core::{
args::{ args::{utils::chain_help, DatabaseArgs, DatadirArgs},
utils::{chain_help, chain_value_parser, SUPPORTED_CHAINS},
DatabaseArgs, DatadirArgs,
},
dirs::{ChainPath, DataDirPath}, dirs::{ChainPath, DataDirPath},
}; };
use reth_primitives::B256; use reth_primitives::B256;
@ -25,7 +23,7 @@ use tracing::{debug, info, warn};
/// Struct to hold config and datadir paths /// Struct to hold config and datadir paths
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct EnvironmentArgs { pub struct EnvironmentArgs<C: ChainSpecParser> {
/// Parameters for datadir configuration /// Parameters for datadir configuration
#[command(flatten)] #[command(flatten)]
pub datadir: DatadirArgs, pub datadir: DatadirArgs,
@ -41,17 +39,17 @@ pub struct EnvironmentArgs {
long, long,
value_name = "CHAIN_OR_PATH", value_name = "CHAIN_OR_PATH",
long_help = chain_help(), long_help = chain_help(),
default_value = SUPPORTED_CHAINS[0], default_value = C::SUPPORTED_CHAINS[0],
value_parser = chain_value_parser value_parser = C::parser()
)] )]
pub chain: Arc<ChainSpec>, pub chain: Arc<C::ChainSpec>,
/// All database related arguments /// All database related arguments
#[command(flatten)] #[command(flatten)]
pub db: DatabaseArgs, pub db: DatabaseArgs,
} }
impl EnvironmentArgs { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> EnvironmentArgs<C> {
/// Initializes environment according to [`AccessRights`] and returns an instance of /// Initializes environment according to [`AccessRights`] and returns an instance of
/// [`Environment`]. /// [`Environment`].
pub fn init(&self, access: AccessRights) -> eyre::Result<Environment> { pub fn init(&self, access: AccessRights) -> eyre::Result<Environment> {

View File

@ -1,5 +1,7 @@
use crate::common::{AccessRights, Environment, EnvironmentArgs}; use crate::common::{AccessRights, Environment, EnvironmentArgs};
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_db::version::{get_db_version, DatabaseVersionError, DB_VERSION}; use reth_db::version::{get_db_version, DatabaseVersionError, DB_VERSION};
use reth_db_common::DbTool; use reth_db_common::DbTool;
use std::io::{self, Write}; use std::io::{self, Write};
@ -15,9 +17,9 @@ mod tui;
/// `reth db` command /// `reth db` command
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Command { pub struct Command<C: ChainSpecParser> {
#[command(flatten)] #[command(flatten)]
env: EnvironmentArgs, env: EnvironmentArgs<C>,
#[command(subcommand)] #[command(subcommand)]
command: Subcommands, command: Subcommands,
@ -60,7 +62,7 @@ macro_rules! db_ro_exec {
}; };
} }
impl Command { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
/// Execute `db` command /// Execute `db` command
pub async fn execute(self) -> eyre::Result<()> { pub async fn execute(self) -> eyre::Result<()> {
let data_dir = self.env.datadir.clone().resolve_datadir(self.env.chain.chain); let data_dir = self.env.datadir.clone().resolve_datadir(self.env.chain.chain);
@ -155,13 +157,19 @@ impl Command {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use reth_node_core::args::utils::SUPPORTED_CHAINS; use reth_node_core::args::utils::{DefaultChainSpecParser, SUPPORTED_CHAINS};
use std::path::Path; use std::path::Path;
#[test] #[test]
fn parse_stats_globals() { fn parse_stats_globals() {
let path = format!("../{}", SUPPORTED_CHAINS[0]); let path = format!("../{}", SUPPORTED_CHAINS[0]);
let cmd = Command::try_parse_from(["reth", "--datadir", &path, "stats"]).unwrap(); let cmd = Command::<DefaultChainSpecParser>::try_parse_from([
"reth",
"--datadir",
&path,
"stats",
])
.unwrap();
assert_eq!(cmd.env.datadir.resolve_datadir(cmd.env.chain.chain).as_ref(), Path::new(&path)); assert_eq!(cmd.env.datadir.resolve_datadir(cmd.env.chain.chain).as_ref(), Path::new(&path));
} }
} }

View File

@ -1,12 +1,14 @@
//! Command that dumps genesis block JSON configuration to stdout //! Command that dumps genesis block JSON configuration to stdout
use std::sync::Arc;
use clap::Parser; use clap::Parser;
use reth_chainspec::ChainSpec; use reth_chainspec::ChainSpec;
use reth_node_core::args::utils::{chain_help, chain_value_parser, SUPPORTED_CHAINS}; use reth_cli::chainspec::ChainSpecParser;
use std::sync::Arc; use reth_node_core::args::utils::chain_help;
/// Dumps genesis block JSON configuration to stdout /// Dumps genesis block JSON configuration to stdout
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct DumpGenesisCommand { pub struct DumpGenesisCommand<C: ChainSpecParser> {
/// The chain this node is running. /// The chain this node is running.
/// ///
/// Possible values are either a built-in chain or the path to a chain specification file. /// Possible values are either a built-in chain or the path to a chain specification file.
@ -14,13 +16,13 @@ pub struct DumpGenesisCommand {
long, long,
value_name = "CHAIN_OR_PATH", value_name = "CHAIN_OR_PATH",
long_help = chain_help(), long_help = chain_help(),
default_value = SUPPORTED_CHAINS[0], default_value = C::SUPPORTED_CHAINS[0],
value_parser = chain_value_parser value_parser = C::parser()
)] )]
chain: Arc<ChainSpec>, chain: Arc<C::ChainSpec>,
} }
impl DumpGenesisCommand { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> DumpGenesisCommand<C> {
/// Execute the `dump-genesis` command /// Execute the `dump-genesis` command
pub async fn execute(self) -> eyre::Result<()> { pub async fn execute(self) -> eyre::Result<()> {
println!("{}", serde_json::to_string_pretty(self.chain.genesis())?); println!("{}", serde_json::to_string_pretty(self.chain.genesis())?);
@ -31,11 +33,12 @@ impl DumpGenesisCommand {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use reth_node_core::args::utils::{DefaultChainSpecParser, SUPPORTED_CHAINS};
#[test] #[test]
fn parse_dump_genesis_command_chain_args() { fn parse_dump_genesis_command_chain_args() {
for chain in SUPPORTED_CHAINS { for chain in SUPPORTED_CHAINS {
let args: DumpGenesisCommand = let args: DumpGenesisCommand<DefaultChainSpecParser> =
DumpGenesisCommand::parse_from(["reth", "--chain", chain]); DumpGenesisCommand::parse_from(["reth", "--chain", chain]);
assert_eq!( assert_eq!(
Ok(args.chain.chain), Ok(args.chain.chain),

View File

@ -4,6 +4,7 @@ use clap::Parser;
use futures::{Stream, StreamExt}; use futures::{Stream, StreamExt};
use reth_beacon_consensus::EthBeaconConsensus; use reth_beacon_consensus::EthBeaconConsensus;
use reth_chainspec::ChainSpec; use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_config::Config; use reth_config::Config;
use reth_consensus::Consensus; use reth_consensus::Consensus;
use reth_db::tables; use reth_db::tables;
@ -34,9 +35,9 @@ use tracing::{debug, error, info};
/// Syncs RLP encoded blocks from a file. /// Syncs RLP encoded blocks from a file.
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct ImportCommand { pub struct ImportCommand<C: ChainSpecParser> {
#[command(flatten)] #[command(flatten)]
env: EnvironmentArgs, env: EnvironmentArgs<C>,
/// Disables stages that require state. /// Disables stages that require state.
#[arg(long, verbatim_doc_comment)] #[arg(long, verbatim_doc_comment)]
@ -54,7 +55,7 @@ pub struct ImportCommand {
path: PathBuf, path: PathBuf,
} }
impl ImportCommand { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> ImportCommand<C> {
/// Execute `import` command /// Execute `import` command
pub async fn execute<E, F>(self, executor: F) -> eyre::Result<()> pub async fn execute<E, F>(self, executor: F) -> eyre::Result<()>
where where
@ -228,12 +229,13 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use reth_node_core::args::utils::SUPPORTED_CHAINS; use reth_node_core::args::utils::{DefaultChainSpecParser, SUPPORTED_CHAINS};
#[test] #[test]
fn parse_common_import_command_chain_args() { fn parse_common_import_command_chain_args() {
for chain in SUPPORTED_CHAINS { for chain in SUPPORTED_CHAINS {
let args: ImportCommand = ImportCommand::parse_from(["reth", "--chain", chain, "."]); let args: ImportCommand<DefaultChainSpecParser> =
ImportCommand::parse_from(["reth", "--chain", chain, "."]);
assert_eq!( assert_eq!(
Ok(args.env.chain.chain), Ok(args.env.chain.chain),
chain.parse::<reth_chainspec::Chain>(), chain.parse::<reth_chainspec::Chain>(),

View File

@ -2,17 +2,19 @@
use crate::common::{AccessRights, Environment, EnvironmentArgs}; use crate::common::{AccessRights, Environment, EnvironmentArgs};
use clap::Parser; use clap::Parser;
use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_provider::BlockHashReader; use reth_provider::BlockHashReader;
use tracing::info; use tracing::info;
/// Initializes the database with the genesis block. /// Initializes the database with the genesis block.
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct InitCommand { pub struct InitCommand<C: ChainSpecParser> {
#[command(flatten)] #[command(flatten)]
env: EnvironmentArgs, env: EnvironmentArgs<C>,
} }
impl InitCommand { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> InitCommand<C> {
/// Execute the `init` command /// Execute the `init` command
pub async fn execute(self) -> eyre::Result<()> { pub async fn execute(self) -> eyre::Result<()> {
info!(target: "reth::cli", "reth init starting"); info!(target: "reth::cli", "reth init starting");

View File

@ -2,6 +2,8 @@
use crate::common::{AccessRights, Environment, EnvironmentArgs}; use crate::common::{AccessRights, Environment, EnvironmentArgs};
use clap::Parser; use clap::Parser;
use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_config::config::EtlConfig; use reth_config::config::EtlConfig;
use reth_db_api::database::Database; use reth_db_api::database::Database;
use reth_db_common::init::init_from_state_dump; use reth_db_common::init::init_from_state_dump;
@ -13,9 +15,9 @@ use tracing::info;
/// Initializes the database with the genesis block. /// Initializes the database with the genesis block.
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct InitStateCommand { pub struct InitStateCommand<C: ChainSpecParser> {
#[command(flatten)] #[command(flatten)]
env: EnvironmentArgs, env: EnvironmentArgs<C>,
/// JSONL file with state dump. /// JSONL file with state dump.
/// ///
@ -38,7 +40,7 @@ pub struct InitStateCommand {
state: PathBuf, state: PathBuf,
} }
impl InitStateCommand { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> InitStateCommand<C> {
/// Execute the `init` command /// Execute the `init` command
pub async fn execute(self) -> eyre::Result<()> { pub async fn execute(self) -> eyre::Result<()> {
info!(target: "reth::cli", "Reth init-state starting"); info!(target: "reth::cli", "Reth init-state starting");

View File

@ -2,13 +2,14 @@
use clap::{value_parser, Args, Parser}; use clap::{value_parser, Args, Parser};
use reth_chainspec::ChainSpec; use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_cli_runner::CliContext; use reth_cli_runner::CliContext;
use reth_cli_util::parse_socket_address; use reth_cli_util::parse_socket_address;
use reth_db::{init_db, DatabaseEnv}; use reth_db::{init_db, DatabaseEnv};
use reth_node_builder::{NodeBuilder, WithLaunchContext}; use reth_node_builder::{NodeBuilder, WithLaunchContext};
use reth_node_core::{ use reth_node_core::{
args::{ args::{
utils::{chain_help, chain_value_parser, SUPPORTED_CHAINS}, utils::{chain_help, DefaultChainSpecParser},
DatabaseArgs, DatadirArgs, DebugArgs, DevArgs, NetworkArgs, PayloadBuilderArgs, DatabaseArgs, DatadirArgs, DebugArgs, DevArgs, NetworkArgs, PayloadBuilderArgs,
PruningArgs, RpcServerArgs, TxPoolArgs, PruningArgs, RpcServerArgs, TxPoolArgs,
}, },
@ -20,7 +21,10 @@ use std::{ffi::OsString, fmt, future::Future, net::SocketAddr, path::PathBuf, sy
/// Start the node /// Start the node
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct NodeCommand<Ext: clap::Args + fmt::Debug = NoArgs> { pub struct NodeCommand<
C: ChainSpecParser = DefaultChainSpecParser,
Ext: clap::Args + fmt::Debug = NoArgs,
> {
/// The path to the configuration file to use. /// The path to the configuration file to use.
#[arg(long, value_name = "FILE", verbatim_doc_comment)] #[arg(long, value_name = "FILE", verbatim_doc_comment)]
pub config: Option<PathBuf>, pub config: Option<PathBuf>,
@ -32,12 +36,12 @@ pub struct NodeCommand<Ext: clap::Args + fmt::Debug = NoArgs> {
long, long,
value_name = "CHAIN_OR_PATH", value_name = "CHAIN_OR_PATH",
long_help = chain_help(), long_help = chain_help(),
default_value = SUPPORTED_CHAINS[0], default_value = C::SUPPORTED_CHAINS[0],
default_value_if("dev", "true", "dev"), default_value_if("dev", "true", "dev"),
value_parser = chain_value_parser, value_parser = C::parser(),
required = false, required = false,
)] )]
pub chain: Arc<ChainSpec>, pub chain: Arc<C::ChainSpec>,
/// Enable Prometheus metrics. /// Enable Prometheus metrics.
/// ///
@ -109,7 +113,7 @@ pub struct NodeCommand<Ext: clap::Args + fmt::Debug = NoArgs> {
pub ext: Ext, pub ext: Ext,
} }
impl NodeCommand { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> NodeCommand<C> {
/// Parsers only the default CLI arguments /// Parsers only the default CLI arguments
pub fn parse_args() -> Self { pub fn parse_args() -> Self {
Self::parse() Self::parse()
@ -125,7 +129,7 @@ impl NodeCommand {
} }
} }
impl<Ext: clap::Args + fmt::Debug> NodeCommand<Ext> { impl<C: ChainSpecParser<ChainSpec = ChainSpec>, Ext: clap::Args + fmt::Debug> NodeCommand<C, Ext> {
/// Launches the node /// Launches the node
/// ///
/// This transforms the node command into a node config and launches the node using the given /// This transforms the node command into a node config and launches the node using the given
@ -203,6 +207,7 @@ pub struct NoArgs;
mod tests { mod tests {
use super::*; use super::*;
use reth_discv4::DEFAULT_DISCOVERY_PORT; use reth_discv4::DEFAULT_DISCOVERY_PORT;
use reth_node_core::args::utils::SUPPORTED_CHAINS;
use std::{ use std::{
net::{IpAddr, Ipv4Addr}, net::{IpAddr, Ipv4Addr},
path::Path, path::Path,
@ -210,28 +215,29 @@ mod tests {
#[test] #[test]
fn parse_help_node_command() { fn parse_help_node_command() {
let err = NodeCommand::try_parse_args_from(["reth", "--help"]).unwrap_err(); let err = NodeCommand::<DefaultChainSpecParser>::try_parse_args_from(["reth", "--help"])
.unwrap_err();
assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp); assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
} }
#[test] #[test]
fn parse_common_node_command_chain_args() { fn parse_common_node_command_chain_args() {
for chain in SUPPORTED_CHAINS { for chain in SUPPORTED_CHAINS {
let args: NodeCommand = NodeCommand::<NoArgs>::parse_from(["reth", "--chain", chain]); let args: NodeCommand = NodeCommand::parse_from(["reth", "--chain", chain]);
assert_eq!(args.chain.chain, chain.parse::<reth_chainspec::Chain>().unwrap()); assert_eq!(args.chain.chain, chain.parse::<reth_chainspec::Chain>().unwrap());
} }
} }
#[test] #[test]
fn parse_discovery_addr() { fn parse_discovery_addr() {
let cmd = let cmd: NodeCommand =
NodeCommand::try_parse_args_from(["reth", "--discovery.addr", "127.0.0.1"]).unwrap(); NodeCommand::try_parse_args_from(["reth", "--discovery.addr", "127.0.0.1"]).unwrap();
assert_eq!(cmd.network.discovery.addr, IpAddr::V4(Ipv4Addr::LOCALHOST)); assert_eq!(cmd.network.discovery.addr, IpAddr::V4(Ipv4Addr::LOCALHOST));
} }
#[test] #[test]
fn parse_addr() { fn parse_addr() {
let cmd = NodeCommand::try_parse_args_from([ let cmd: NodeCommand = NodeCommand::try_parse_args_from([
"reth", "reth",
"--discovery.addr", "--discovery.addr",
"127.0.0.1", "127.0.0.1",
@ -245,13 +251,14 @@ mod tests {
#[test] #[test]
fn parse_discovery_port() { fn parse_discovery_port() {
let cmd = NodeCommand::try_parse_args_from(["reth", "--discovery.port", "300"]).unwrap(); let cmd: NodeCommand =
NodeCommand::try_parse_args_from(["reth", "--discovery.port", "300"]).unwrap();
assert_eq!(cmd.network.discovery.port, 300); assert_eq!(cmd.network.discovery.port, 300);
} }
#[test] #[test]
fn parse_port() { fn parse_port() {
let cmd = let cmd: NodeCommand =
NodeCommand::try_parse_args_from(["reth", "--discovery.port", "300", "--port", "99"]) NodeCommand::try_parse_args_from(["reth", "--discovery.port", "300", "--port", "99"])
.unwrap(); .unwrap();
assert_eq!(cmd.network.discovery.port, 300); assert_eq!(cmd.network.discovery.port, 300);
@ -260,27 +267,29 @@ mod tests {
#[test] #[test]
fn parse_metrics_port() { fn parse_metrics_port() {
let cmd = NodeCommand::try_parse_args_from(["reth", "--metrics", "9001"]).unwrap(); let cmd: NodeCommand =
NodeCommand::try_parse_args_from(["reth", "--metrics", "9001"]).unwrap();
assert_eq!(cmd.metrics, Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 9001))); assert_eq!(cmd.metrics, Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 9001)));
let cmd = NodeCommand::try_parse_args_from(["reth", "--metrics", ":9001"]).unwrap(); let cmd: NodeCommand =
NodeCommand::try_parse_args_from(["reth", "--metrics", ":9001"]).unwrap();
assert_eq!(cmd.metrics, Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 9001))); assert_eq!(cmd.metrics, Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 9001)));
let cmd = let cmd: NodeCommand =
NodeCommand::try_parse_args_from(["reth", "--metrics", "localhost:9001"]).unwrap(); NodeCommand::try_parse_args_from(["reth", "--metrics", "localhost:9001"]).unwrap();
assert_eq!(cmd.metrics, Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 9001))); assert_eq!(cmd.metrics, Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 9001)));
} }
#[test] #[test]
fn parse_config_path() { fn parse_config_path() {
let cmd = let cmd: NodeCommand =
NodeCommand::try_parse_args_from(["reth", "--config", "my/path/to/reth.toml"]).unwrap(); 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 // 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 data_dir = cmd.datadir.resolve_datadir(cmd.chain.chain);
let config_path = cmd.config.unwrap_or_else(|| data_dir.config()); let config_path = cmd.config.unwrap_or_else(|| data_dir.config());
assert_eq!(config_path, Path::new("my/path/to/reth.toml")); assert_eq!(config_path, Path::new("my/path/to/reth.toml"));
let cmd = NodeCommand::try_parse_args_from(["reth"]).unwrap(); let cmd: NodeCommand = NodeCommand::try_parse_args_from(["reth"]).unwrap();
// always store reth.toml in the data dir, not the chain specific data dir // 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 data_dir = cmd.datadir.resolve_datadir(cmd.chain.chain);
@ -291,14 +300,14 @@ mod tests {
#[test] #[test]
fn parse_db_path() { fn parse_db_path() {
let cmd = NodeCommand::try_parse_args_from(["reth"]).unwrap(); let cmd: NodeCommand = NodeCommand::try_parse_args_from(["reth"]).unwrap();
let data_dir = cmd.datadir.resolve_datadir(cmd.chain.chain); let data_dir = cmd.datadir.resolve_datadir(cmd.chain.chain);
let db_path = data_dir.db(); let db_path = data_dir.db();
let end = format!("reth/{}/db", SUPPORTED_CHAINS[0]); let end = format!("reth/{}/db", SUPPORTED_CHAINS[0]);
assert!(db_path.ends_with(end), "{:?}", cmd.config); assert!(db_path.ends_with(end), "{:?}", cmd.config);
let cmd = let cmd: NodeCommand =
NodeCommand::try_parse_args_from(["reth", "--datadir", "my/custom/path"]).unwrap(); NodeCommand::try_parse_args_from(["reth", "--datadir", "my/custom/path"]).unwrap();
let data_dir = cmd.datadir.resolve_datadir(cmd.chain.chain); let data_dir = cmd.datadir.resolve_datadir(cmd.chain.chain);
@ -308,7 +317,7 @@ mod tests {
#[test] #[test]
fn parse_dev() { fn parse_dev() {
let cmd = NodeCommand::<NoArgs>::parse_from(["reth", "--dev"]); let cmd: NodeCommand = NodeCommand::parse_from(["reth", "--dev"]);
let chain = reth_chainspec::DEV.clone(); let chain = reth_chainspec::DEV.clone();
assert_eq!(cmd.chain.chain, chain.chain); assert_eq!(cmd.chain.chain, chain.chain);
assert_eq!(cmd.chain.genesis_hash, chain.genesis_hash); assert_eq!(cmd.chain.genesis_hash, chain.genesis_hash);
@ -326,7 +335,7 @@ mod tests {
#[test] #[test]
fn parse_instance() { fn parse_instance() {
let mut cmd = NodeCommand::<NoArgs>::parse_from(["reth"]); let mut cmd: NodeCommand = NodeCommand::parse_from(["reth"]);
cmd.rpc.adjust_instance_ports(cmd.instance); cmd.rpc.adjust_instance_ports(cmd.instance);
cmd.network.port = DEFAULT_DISCOVERY_PORT + cmd.instance - 1; cmd.network.port = DEFAULT_DISCOVERY_PORT + cmd.instance - 1;
// check rpc port numbers // check rpc port numbers
@ -336,7 +345,7 @@ mod tests {
// check network listening port number // check network listening port number
assert_eq!(cmd.network.port, 30303); assert_eq!(cmd.network.port, 30303);
let mut cmd = NodeCommand::<NoArgs>::parse_from(["reth", "--instance", "2"]); let mut cmd: NodeCommand = NodeCommand::parse_from(["reth", "--instance", "2"]);
cmd.rpc.adjust_instance_ports(cmd.instance); cmd.rpc.adjust_instance_ports(cmd.instance);
cmd.network.port = DEFAULT_DISCOVERY_PORT + cmd.instance - 1; cmd.network.port = DEFAULT_DISCOVERY_PORT + cmd.instance - 1;
// check rpc port numbers // check rpc port numbers
@ -346,7 +355,7 @@ mod tests {
// check network listening port number // check network listening port number
assert_eq!(cmd.network.port, 30304); assert_eq!(cmd.network.port, 30304);
let mut cmd = NodeCommand::<NoArgs>::parse_from(["reth", "--instance", "3"]); let mut cmd: NodeCommand = NodeCommand::parse_from(["reth", "--instance", "3"]);
cmd.rpc.adjust_instance_ports(cmd.instance); cmd.rpc.adjust_instance_ports(cmd.instance);
cmd.network.port = DEFAULT_DISCOVERY_PORT + cmd.instance - 1; cmd.network.port = DEFAULT_DISCOVERY_PORT + cmd.instance - 1;
// check rpc port numbers // check rpc port numbers
@ -359,21 +368,25 @@ mod tests {
#[test] #[test]
fn parse_with_unused_ports() { fn parse_with_unused_ports() {
let cmd = NodeCommand::<NoArgs>::parse_from(["reth", "--with-unused-ports"]); let cmd: NodeCommand = NodeCommand::parse_from(["reth", "--with-unused-ports"]);
assert!(cmd.with_unused_ports); assert!(cmd.with_unused_ports);
} }
#[test] #[test]
fn with_unused_ports_conflicts_with_instance() { fn with_unused_ports_conflicts_with_instance() {
let err = let err = NodeCommand::<DefaultChainSpecParser>::try_parse_args_from([
NodeCommand::try_parse_args_from(["reth", "--with-unused-ports", "--instance", "2"]) "reth",
.unwrap_err(); "--with-unused-ports",
"--instance",
"2",
])
.unwrap_err();
assert_eq!(err.kind(), clap::error::ErrorKind::ArgumentConflict); assert_eq!(err.kind(), clap::error::ErrorKind::ArgumentConflict);
} }
#[test] #[test]
fn with_unused_ports_check_zero() { fn with_unused_ports_check_zero() {
let mut cmd = NodeCommand::<NoArgs>::parse_from(["reth"]); let mut cmd: NodeCommand = NodeCommand::parse_from(["reth"]);
cmd.rpc = cmd.rpc.with_unused_ports(); cmd.rpc = cmd.rpc.with_unused_ports();
cmd.network = cmd.network.with_unused_ports(); cmd.network = cmd.network.with_unused_ports();

View File

@ -5,15 +5,13 @@ use std::{path::PathBuf, sync::Arc};
use backon::{ConstantBuilder, Retryable}; use backon::{ConstantBuilder, Retryable};
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use reth_chainspec::ChainSpec; use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_cli_util::{get_secret_key, hash_or_num_value_parser}; use reth_cli_util::{get_secret_key, hash_or_num_value_parser};
use reth_config::Config; use reth_config::Config;
use reth_network::{BlockDownloaderProvider, NetworkConfigBuilder}; use reth_network::{BlockDownloaderProvider, NetworkConfigBuilder};
use reth_network_p2p::bodies::client::BodiesClient; use reth_network_p2p::bodies::client::BodiesClient;
use reth_node_core::{ use reth_node_core::{
args::{ args::{utils::chain_help, DatabaseArgs, DatadirArgs, NetworkArgs},
utils::{chain_help, chain_value_parser, SUPPORTED_CHAINS},
DatabaseArgs, DatadirArgs, NetworkArgs,
},
utils::get_single_header, utils::get_single_header,
}; };
use reth_primitives::BlockHashOrNumber; use reth_primitives::BlockHashOrNumber;
@ -22,7 +20,7 @@ mod rlpx;
/// `reth p2p` command /// `reth p2p` command
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Command { pub struct Command<C: ChainSpecParser> {
/// The path to the configuration file to use. /// The path to the configuration file to use.
#[arg(long, value_name = "FILE", verbatim_doc_comment)] #[arg(long, value_name = "FILE", verbatim_doc_comment)]
config: Option<PathBuf>, config: Option<PathBuf>,
@ -34,10 +32,10 @@ pub struct Command {
long, long,
value_name = "CHAIN_OR_PATH", value_name = "CHAIN_OR_PATH",
long_help = chain_help(), long_help = chain_help(),
default_value = SUPPORTED_CHAINS[0], default_value = C::SUPPORTED_CHAINS[0],
value_parser = chain_value_parser value_parser = C::parser()
)] )]
chain: Arc<ChainSpec>, chain: Arc<C::ChainSpec>,
/// The number of retries per request /// The number of retries per request
#[arg(long, default_value = "5")] #[arg(long, default_value = "5")]
@ -75,7 +73,7 @@ pub enum Subcommands {
Rlpx(rlpx::Command), Rlpx(rlpx::Command),
} }
impl Command { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
/// Execute `p2p` command /// Execute `p2p` command
pub async fn execute(self) -> eyre::Result<()> { pub async fn execute(self) -> eyre::Result<()> {
let data_dir = self.datadir.clone().resolve_datadir(self.chain.chain); let data_dir = self.datadir.clone().resolve_datadir(self.chain.chain);

View File

@ -1,18 +1,20 @@
//! Command that runs pruning without any limits. //! Command that runs pruning without any limits.
use crate::common::{AccessRights, Environment, EnvironmentArgs}; use crate::common::{AccessRights, Environment, EnvironmentArgs};
use clap::Parser; use clap::Parser;
use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_prune::PrunerBuilder; use reth_prune::PrunerBuilder;
use reth_static_file::StaticFileProducer; use reth_static_file::StaticFileProducer;
use tracing::info; use tracing::info;
/// Prunes according to the configuration without any limits /// Prunes according to the configuration without any limits
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct PruneCommand { pub struct PruneCommand<C: ChainSpecParser> {
#[command(flatten)] #[command(flatten)]
env: EnvironmentArgs, env: EnvironmentArgs<C>,
} }
impl PruneCommand { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> PruneCommand<C> {
/// Execute the `prune` command /// Execute the `prune` command
pub async fn execute(self) -> eyre::Result<()> { pub async fn execute(self) -> eyre::Result<()> {
let Environment { config, provider_factory, .. } = self.env.init(AccessRights::RW)?; let Environment { config, provider_factory, .. } = self.env.init(AccessRights::RW)?;

View File

@ -1,25 +1,27 @@
//! `reth recover` command. //! `reth recover` command.
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_cli_runner::CliContext; use reth_cli_runner::CliContext;
mod storage_tries; mod storage_tries;
/// `reth recover` command /// `reth recover` command
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Command { pub struct Command<C: ChainSpecParser> {
#[command(subcommand)] #[command(subcommand)]
command: Subcommands, command: Subcommands<C>,
} }
/// `reth recover` subcommands /// `reth recover` subcommands
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
pub enum Subcommands { pub enum Subcommands<C: ChainSpecParser> {
/// Recover the node by deleting dangling storage tries. /// Recover the node by deleting dangling storage tries.
StorageTries(storage_tries::Command), StorageTries(storage_tries::Command<C>),
} }
impl Command { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
/// Execute `recover` command /// Execute `recover` command
pub async fn execute(self, ctx: CliContext) -> eyre::Result<()> { pub async fn execute(self, ctx: CliContext) -> eyre::Result<()> {
match self.command { match self.command {

View File

@ -1,5 +1,7 @@
use crate::common::{AccessRights, Environment, EnvironmentArgs}; use crate::common::{AccessRights, Environment, EnvironmentArgs};
use clap::Parser; use clap::Parser;
use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_cli_runner::CliContext; use reth_cli_runner::CliContext;
use reth_db::tables; use reth_db::tables;
use reth_db_api::{ use reth_db_api::{
@ -13,12 +15,12 @@ use tracing::*;
/// `reth recover storage-tries` command /// `reth recover storage-tries` command
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Command { pub struct Command<C: ChainSpecParser> {
#[command(flatten)] #[command(flatten)]
env: EnvironmentArgs, env: EnvironmentArgs<C>,
} }
impl Command { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
/// Execute `storage-tries` recovery command /// Execute `storage-tries` recovery command
pub async fn execute(self, _ctx: CliContext) -> eyre::Result<()> { pub async fn execute(self, _ctx: CliContext) -> eyre::Result<()> {
let Environment { provider_factory, .. } = self.env.init(AccessRights::RW)?; let Environment { provider_factory, .. } = self.env.init(AccessRights::RW)?;

View File

@ -2,6 +2,8 @@
use crate::common::{AccessRights, Environment, EnvironmentArgs}; use crate::common::{AccessRights, Environment, EnvironmentArgs};
use clap::Parser; use clap::Parser;
use itertools::Itertools; use itertools::Itertools;
use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_db::{static_file::iter_static_files, tables}; use reth_db::{static_file::iter_static_files, tables};
use reth_db_api::transaction::DbTxMut; use reth_db_api::transaction::DbTxMut;
use reth_db_common::{ use reth_db_common::{
@ -15,14 +17,14 @@ use reth_static_file_types::{find_fixed_range, StaticFileSegment};
/// `reth drop-stage` command /// `reth drop-stage` command
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Command { pub struct Command<C: ChainSpecParser> {
#[command(flatten)] #[command(flatten)]
env: EnvironmentArgs, env: EnvironmentArgs<C>,
stage: StageEnum, stage: StageEnum,
} }
impl Command { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
/// Execute `db` command /// Execute `db` command
pub async fn execute(self) -> eyre::Result<()> { pub async fn execute(self) -> eyre::Result<()> {
let Environment { provider_factory, .. } = self.env.init(AccessRights::RW)?; let Environment { provider_factory, .. } = self.env.init(AccessRights::RW)?;

View File

@ -2,6 +2,7 @@
use crate::common::{AccessRights, Environment, EnvironmentArgs}; use crate::common::{AccessRights, Environment, EnvironmentArgs};
use clap::Parser; use clap::Parser;
use reth_chainspec::ChainSpec; use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_db::{init_db, mdbx::DatabaseArguments, tables, DatabaseEnv}; use reth_db::{init_db, mdbx::DatabaseArguments, tables, DatabaseEnv};
use reth_db_api::{ use reth_db_api::{
cursor::DbCursorRO, database::Database, models::ClientVersion, table::TableImporter, cursor::DbCursorRO, database::Database, models::ClientVersion, table::TableImporter,
@ -30,9 +31,9 @@ use merkle::dump_merkle_stage;
/// `reth dump-stage` command /// `reth dump-stage` command
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Command { pub struct Command<C: ChainSpecParser> {
#[command(flatten)] #[command(flatten)]
env: EnvironmentArgs, env: EnvironmentArgs<C>,
#[command(subcommand)] #[command(subcommand)]
command: Stages, command: Stages,
@ -84,7 +85,7 @@ macro_rules! handle_stage {
}}; }};
} }
impl Command { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
/// Execute `dump-stage` command /// Execute `dump-stage` command
pub async fn execute<E, F>(self, executor: F) -> eyre::Result<()> pub async fn execute<E, F>(self, executor: F) -> eyre::Result<()>
where where

View File

@ -4,6 +4,7 @@ use std::sync::Arc;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use reth_chainspec::ChainSpec; use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_cli_runner::CliContext; use reth_cli_runner::CliContext;
use reth_evm::execute::BlockExecutorProvider; use reth_evm::execute::BlockExecutorProvider;
@ -14,30 +15,30 @@ pub mod unwind;
/// `reth stage` command /// `reth stage` command
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Command { pub struct Command<C: ChainSpecParser> {
#[command(subcommand)] #[command(subcommand)]
command: Subcommands, command: Subcommands<C>,
} }
/// `reth stage` subcommands /// `reth stage` subcommands
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
pub enum Subcommands { pub enum Subcommands<C: ChainSpecParser> {
/// Run a single stage. /// Run a single stage.
/// ///
/// Note that this won't use the Pipeline and as a result runs stages /// Note that this won't use the Pipeline and as a result runs stages
/// assuming that all the data can be held in memory. It is not recommended /// assuming that all the data can be held in memory. It is not recommended
/// to run a stage for really large block ranges if your computer does not have /// to run a stage for really large block ranges if your computer does not have
/// a lot of memory to store all the data. /// a lot of memory to store all the data.
Run(run::Command), Run(run::Command<C>),
/// Drop a stage's tables from the database. /// Drop a stage's tables from the database.
Drop(drop::Command), Drop(drop::Command<C>),
/// Dumps a stage from a range into a new database. /// Dumps a stage from a range into a new database.
Dump(dump::Command), Dump(dump::Command<C>),
/// Unwinds a certain block range, deleting it from the database. /// Unwinds a certain block range, deleting it from the database.
Unwind(unwind::Command), Unwind(unwind::Command<C>),
} }
impl Command { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
/// Execute `stage` command /// Execute `stage` command
pub async fn execute<E, F>(self, ctx: CliContext, executor: F) -> eyre::Result<()> pub async fn execute<E, F>(self, ctx: CliContext, executor: F) -> eyre::Result<()>
where where

View File

@ -6,6 +6,7 @@ use crate::common::{AccessRights, Environment, EnvironmentArgs};
use clap::Parser; use clap::Parser;
use reth_beacon_consensus::EthBeaconConsensus; use reth_beacon_consensus::EthBeaconConsensus;
use reth_chainspec::ChainSpec; use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_cli_runner::CliContext; use reth_cli_runner::CliContext;
use reth_cli_util::get_secret_key; use reth_cli_util::get_secret_key;
use reth_config::config::{HashingConfig, SenderRecoveryConfig, TransactionLookupConfig}; use reth_config::config::{HashingConfig, SenderRecoveryConfig, TransactionLookupConfig};
@ -49,9 +50,9 @@ use tracing::*;
/// `reth stage` command /// `reth stage` command
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Command { pub struct Command<C: ChainSpecParser> {
#[command(flatten)] #[command(flatten)]
env: EnvironmentArgs, env: EnvironmentArgs<C>,
/// Enable Prometheus metrics. /// Enable Prometheus metrics.
/// ///
@ -99,7 +100,7 @@ pub struct Command {
network: NetworkArgs, network: NetworkArgs,
} }
impl Command { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
/// Execute `stage` command /// Execute `stage` command
pub async fn execute<E, F>(self, ctx: CliContext, executor: F) -> eyre::Result<()> pub async fn execute<E, F>(self, ctx: CliContext, executor: F) -> eyre::Result<()>
where where

View File

@ -3,6 +3,8 @@
use crate::common::{AccessRights, Environment, EnvironmentArgs}; use crate::common::{AccessRights, Environment, EnvironmentArgs};
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use reth_beacon_consensus::EthBeaconConsensus; use reth_beacon_consensus::EthBeaconConsensus;
use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_config::Config; use reth_config::Config;
use reth_consensus::Consensus; use reth_consensus::Consensus;
use reth_db_api::database::Database; use reth_db_api::database::Database;
@ -28,9 +30,9 @@ use tracing::info;
/// `reth stage unwind` command /// `reth stage unwind` command
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Command { pub struct Command<C: ChainSpecParser> {
#[command(flatten)] #[command(flatten)]
env: EnvironmentArgs, env: EnvironmentArgs<C>,
#[command(flatten)] #[command(flatten)]
network: NetworkArgs, network: NetworkArgs,
@ -44,7 +46,7 @@ pub struct Command {
offline: bool, offline: bool,
} }
impl Command { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
/// Execute `db stage unwind` command /// Execute `db stage unwind` command
pub async fn execute(self) -> eyre::Result<()> { pub async fn execute(self) -> eyre::Result<()> {
let Environment { provider_factory, config, .. } = self.env.init(AccessRights::RW)?; let Environment { provider_factory, config, .. } = self.env.init(AccessRights::RW)?;
@ -207,14 +209,28 @@ impl Subcommands {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use reth_node_core::args::utils::DefaultChainSpecParser;
use super::*; use super::*;
#[test] #[test]
fn parse_unwind() { fn parse_unwind() {
let cmd = Command::parse_from(["reth", "--datadir", "dir", "to-block", "100"]); let cmd = Command::<DefaultChainSpecParser>::parse_from([
"reth",
"--datadir",
"dir",
"to-block",
"100",
]);
assert_eq!(cmd.command, Subcommands::ToBlock { target: BlockHashOrNumber::Number(100) }); assert_eq!(cmd.command, Subcommands::ToBlock { target: BlockHashOrNumber::Number(100) });
let cmd = Command::parse_from(["reth", "--datadir", "dir", "num-blocks", "100"]); let cmd = Command::<DefaultChainSpecParser>::parse_from([
"reth",
"--datadir",
"dir",
"num-blocks",
"100",
]);
assert_eq!(cmd.command, Subcommands::NumBlocks { amount: 100 }); assert_eq!(cmd.command, Subcommands::NumBlocks { amount: 100 });
} }
} }

View File

@ -19,5 +19,4 @@ alloy-genesis.workspace = true
eyre.workspace = true eyre.workspace = true
shellexpand.workspace = true shellexpand.workspace = true
serde_json.workspace = true serde_json.workspace = true
clap = { workspace = true, features = ["derive", "env"] }

View File

@ -1,8 +1,7 @@
use alloy_genesis::Genesis; use alloy_genesis::Genesis;
use clap::{builder::TypedValueParser, error::Result, Arg, Command};
use reth_chainspec::{ChainSpec, DEV, HOLESKY, MAINNET, SEPOLIA}; use reth_chainspec::{ChainSpec, DEV, HOLESKY, MAINNET, SEPOLIA};
use reth_cli::chainspec::ChainSpecParser; use reth_cli::chainspec::ChainSpecParser;
use std::{ffi::OsStr, fs, path::PathBuf, sync::Arc}; use std::{fs, path::PathBuf, sync::Arc};
/// Clap value parser for [`ChainSpec`]s. /// Clap value parser for [`ChainSpec`]s.
/// ///
@ -40,7 +39,9 @@ fn chain_value_parser(s: &str) -> eyre::Result<Arc<ChainSpec>, eyre::Error> {
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct EthChainSpecParser; pub struct EthChainSpecParser;
impl ChainSpecParser<ChainSpec> for EthChainSpecParser { impl ChainSpecParser for EthChainSpecParser {
type ChainSpec = ChainSpec;
const SUPPORTED_CHAINS: &'static [&'static str] = &["mainnet", "sepolia", "holesky", "dev"]; const SUPPORTED_CHAINS: &'static [&'static str] = &["mainnet", "sepolia", "holesky", "dev"];
fn parse(s: &str) -> eyre::Result<Arc<ChainSpec>> { fn parse(s: &str) -> eyre::Result<Arc<ChainSpec>> {
@ -48,35 +49,6 @@ impl ChainSpecParser<ChainSpec> for EthChainSpecParser {
} }
} }
impl TypedValueParser for EthChainSpecParser {
type Value = Arc<ChainSpec>;
fn parse_ref(
&self,
_cmd: &Command,
arg: Option<&Arg>,
value: &OsStr,
) -> Result<Self::Value, clap::Error> {
let val =
value.to_str().ok_or_else(|| clap::Error::new(clap::error::ErrorKind::InvalidUtf8))?;
<Self as ChainSpecParser<ChainSpec>>::parse(val).map_err(|err| {
let arg = arg.map(|a| a.to_string()).unwrap_or_else(|| "...".to_owned());
let possible_values = Self::SUPPORTED_CHAINS.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<Box<dyn Iterator<Item = clap::builder::PossibleValue> + '_>> {
let values = Self::SUPPORTED_CHAINS.iter().map(clap::builder::PossibleValue::new);
Some(Box::new(values))
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -84,7 +56,7 @@ mod tests {
#[test] #[test]
fn parse_known_chain_spec() { fn parse_known_chain_spec() {
for &chain in EthChainSpecParser::SUPPORTED_CHAINS { for &chain in EthChainSpecParser::SUPPORTED_CHAINS {
assert!(<EthChainSpecParser as ChainSpecParser<ChainSpec>>::parse(chain).is_ok()); assert!(<EthChainSpecParser as ChainSpecParser>::parse(chain).is_ok());
} }
} }
} }

View File

@ -14,6 +14,7 @@ workspace = true
# reth # reth
reth-chainspec.workspace = true reth-chainspec.workspace = true
reth-primitives.workspace = true reth-primitives.workspace = true
reth-cli.workspace = true
reth-cli-util.workspace = true reth-cli-util.workspace = true
reth-fs-util.workspace = true reth-fs-util.workspace = true
reth-db = { workspace = true, features = ["mdbx"] } reth-db = { workspace = true, features = ["mdbx"] }

View File

@ -6,6 +6,7 @@ use alloy_genesis::Genesis;
use reth_chainspec::ChainSpec; use reth_chainspec::ChainSpec;
#[cfg(not(feature = "optimism"))] #[cfg(not(feature = "optimism"))]
use reth_chainspec::{DEV, HOLESKY, MAINNET, SEPOLIA}; use reth_chainspec::{DEV, HOLESKY, MAINNET, SEPOLIA};
use reth_cli::chainspec::ChainSpecParser;
use reth_fs_util as fs; use reth_fs_util as fs;
#[cfg(feature = "optimism")] #[cfg(feature = "optimism")]
use reth_optimism_chainspec::{BASE_MAINNET, BASE_SEPOLIA, OP_DEV, OP_MAINNET, OP_SEPOLIA}; use reth_optimism_chainspec::{BASE_MAINNET, BASE_SEPOLIA, OP_DEV, OP_MAINNET, OP_SEPOLIA};
@ -75,6 +76,20 @@ pub fn parse_custom_chain_spec(s: &str) -> eyre::Result<ChainSpec, eyre::Error>
Ok(genesis.into()) Ok(genesis.into())
} }
/// Default chain specification parser.
#[derive(Debug, Clone, Default)]
pub struct DefaultChainSpecParser;
impl ChainSpecParser for DefaultChainSpecParser {
type ChainSpec = ChainSpec;
const SUPPORTED_CHAINS: &'static [&'static str] = SUPPORTED_CHAINS;
fn parse(s: &str) -> eyre::Result<Arc<ChainSpec>> {
chain_value_parser(s)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@ -1,6 +1,5 @@
use std::{ffi::OsStr, sync::Arc}; use std::sync::Arc;
use clap::{builder::TypedValueParser, error::Result, Arg, Command};
use reth_cli::chainspec::ChainSpecParser; use reth_cli::chainspec::ChainSpecParser;
use reth_node_core::args::utils::parse_custom_chain_spec; use reth_node_core::args::utils::parse_custom_chain_spec;
use reth_optimism_chainspec::{ use reth_optimism_chainspec::{
@ -26,7 +25,9 @@ fn chain_value_parser(s: &str) -> eyre::Result<Arc<OpChainSpec>, eyre::Error> {
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct OpChainSpecParser; pub struct OpChainSpecParser;
impl ChainSpecParser<OpChainSpec> for OpChainSpecParser { impl ChainSpecParser for OpChainSpecParser {
type ChainSpec = OpChainSpec;
const SUPPORTED_CHAINS: &'static [&'static str] = &[ const SUPPORTED_CHAINS: &'static [&'static str] = &[
"dev", "dev",
"optimism", "optimism",
@ -42,37 +43,6 @@ impl ChainSpecParser<OpChainSpec> for OpChainSpecParser {
} }
} }
impl TypedValueParser for OpChainSpecParser {
type Value = Arc<OpChainSpec>;
fn parse_ref(
&self,
_cmd: &Command,
arg: Option<&Arg>,
value: &OsStr,
) -> Result<Self::Value, clap::Error> {
let val =
value.to_str().ok_or_else(|| clap::Error::new(clap::error::ErrorKind::InvalidUtf8))?;
<Self as ChainSpecParser<OpChainSpec>>::parse(val).map_err(|err| {
let arg = arg.map(|a| a.to_string()).unwrap_or_else(|| "...".to_owned());
let possible_values = Self::SUPPORTED_CHAINS.join(", ");
clap::Error::raw(
clap::error::ErrorKind::InvalidValue,
format!(
"Invalid value '{val}' for {arg}: {err}. [possible values: {possible_values}]"
),
)
})
}
fn possible_values(
&self,
) -> Option<Box<dyn Iterator<Item = clap::builder::PossibleValue> + '_>> {
let values = Self::SUPPORTED_CHAINS.iter().map(clap::builder::PossibleValue::new);
Some(Box::new(values))
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -80,7 +50,7 @@ mod tests {
#[test] #[test]
fn parse_known_chain_spec() { fn parse_known_chain_spec() {
for &chain in OpChainSpecParser::SUPPORTED_CHAINS { for &chain in OpChainSpecParser::SUPPORTED_CHAINS {
assert!(<OpChainSpecParser as ChainSpecParser<OpChainSpec>>::parse(chain).is_ok()); assert!(<OpChainSpecParser as ChainSpecParser>::parse(chain).is_ok());
} }
} }
} }

View File

@ -1,6 +1,8 @@
//! Command that initializes the node by importing OP Mainnet chain segment below Bedrock, from a //! Command that initializes the node by importing OP Mainnet chain segment below Bedrock, from a
//! file. //! file.
use clap::Parser; use clap::Parser;
use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_cli_commands::common::{AccessRights, Environment, EnvironmentArgs}; use reth_cli_commands::common::{AccessRights, Environment, EnvironmentArgs};
use reth_consensus::noop::NoopConsensus; use reth_consensus::noop::NoopConsensus;
use reth_db::tables; use reth_db::tables;
@ -21,9 +23,9 @@ use crate::commands::build_pipeline::build_import_pipeline;
/// Syncs RLP encoded blocks from a file. /// Syncs RLP encoded blocks from a file.
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct ImportOpCommand { pub struct ImportOpCommand<C: ChainSpecParser> {
#[command(flatten)] #[command(flatten)]
env: EnvironmentArgs, env: EnvironmentArgs<C>,
/// Chunk byte length to read from file. /// Chunk byte length to read from file.
#[arg(long, value_name = "CHUNK_LEN", verbatim_doc_comment)] #[arg(long, value_name = "CHUNK_LEN", verbatim_doc_comment)]
@ -37,7 +39,7 @@ pub struct ImportOpCommand {
path: PathBuf, path: PathBuf,
} }
impl ImportOpCommand { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> ImportOpCommand<C> {
/// Execute `import` command /// Execute `import` command
pub async fn execute(self) -> eyre::Result<()> { pub async fn execute(self) -> eyre::Result<()> {
info!(target: "reth::cli", "reth {} starting", SHORT_VERSION); info!(target: "reth::cli", "reth {} starting", SHORT_VERSION);

View File

@ -4,6 +4,8 @@
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use clap::Parser; use clap::Parser;
use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_cli_commands::common::{AccessRights, Environment, EnvironmentArgs}; use reth_cli_commands::common::{AccessRights, Environment, EnvironmentArgs};
use reth_db::tables; use reth_db::tables;
use reth_db_api::database::Database; use reth_db_api::database::Database;
@ -27,9 +29,9 @@ use crate::file_codec_ovm_receipt::HackReceiptFileCodec;
/// Initializes the database with the genesis block. /// Initializes the database with the genesis block.
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct ImportReceiptsOpCommand { pub struct ImportReceiptsOpCommand<C: ChainSpecParser> {
#[command(flatten)] #[command(flatten)]
env: EnvironmentArgs, env: EnvironmentArgs<C>,
/// Chunk byte length to read from file. /// Chunk byte length to read from file.
#[arg(long, value_name = "CHUNK_LEN", verbatim_doc_comment)] #[arg(long, value_name = "CHUNK_LEN", verbatim_doc_comment)]
@ -43,7 +45,7 @@ pub struct ImportReceiptsOpCommand {
path: PathBuf, path: PathBuf,
} }
impl ImportReceiptsOpCommand { impl<C: ChainSpecParser<ChainSpec = ChainSpec>> ImportReceiptsOpCommand<C> {
/// Execute `import` command /// Execute `import` command
pub async fn execute(self) -> eyre::Result<()> { pub async fn execute(self) -> eyre::Result<()> {
info!(target: "reth::cli", "reth {} starting", SHORT_VERSION); info!(target: "reth::cli", "reth {} starting", SHORT_VERSION);

View File

@ -1,3 +1,4 @@
use crate::chainspec::OpChainSpecParser;
use clap::Subcommand; use clap::Subcommand;
use import::ImportOpCommand; use import::ImportOpCommand;
use import_receipts::ImportReceiptsOpCommand; use import_receipts::ImportReceiptsOpCommand;
@ -18,37 +19,37 @@ pub mod import_receipts;
pub enum Commands<Ext: clap::Args + fmt::Debug = NoArgs> { pub enum Commands<Ext: clap::Args + fmt::Debug = NoArgs> {
/// Start the node /// Start the node
#[command(name = "node")] #[command(name = "node")]
Node(node::NodeCommand<Ext>), Node(Box<node::NodeCommand<OpChainSpecParser, Ext>>),
/// Initialize the database from a genesis file. /// Initialize the database from a genesis file.
#[command(name = "init")] #[command(name = "init")]
Init(init_cmd::InitCommand), Init(init_cmd::InitCommand<OpChainSpecParser>),
/// Initialize the database from a state dump file. /// Initialize the database from a state dump file.
#[command(name = "init-state")] #[command(name = "init-state")]
InitState(init_state::InitStateCommand), InitState(init_state::InitStateCommand<OpChainSpecParser>),
/// This syncs RLP encoded OP blocks below Bedrock from a file, without executing. /// This syncs RLP encoded OP blocks below Bedrock from a file, without executing.
#[command(name = "import-op")] #[command(name = "import-op")]
ImportOp(ImportOpCommand), ImportOp(ImportOpCommand<OpChainSpecParser>),
/// This imports RLP encoded receipts from a file. /// This imports RLP encoded receipts from a file.
#[command(name = "import-receipts-op")] #[command(name = "import-receipts-op")]
ImportReceiptsOp(ImportReceiptsOpCommand), ImportReceiptsOp(ImportReceiptsOpCommand<OpChainSpecParser>),
/// Dumps genesis block JSON configuration to stdout. /// Dumps genesis block JSON configuration to stdout.
DumpGenesis(dump_genesis::DumpGenesisCommand), DumpGenesis(dump_genesis::DumpGenesisCommand<OpChainSpecParser>),
/// Database debugging utilities /// Database debugging utilities
#[command(name = "db")] #[command(name = "db")]
Db(db::Command), Db(db::Command<OpChainSpecParser>),
/// Manipulate individual stages. /// Manipulate individual stages.
#[command(name = "stage")] #[command(name = "stage")]
Stage(stage::Command), Stage(Box<stage::Command<OpChainSpecParser>>),
/// P2P Debugging utilities /// P2P Debugging utilities
#[command(name = "p2p")] #[command(name = "p2p")]
P2P(p2p::Command), P2P(p2p::Command<OpChainSpecParser>),
/// Write config to stdout /// Write config to stdout
#[command(name = "config")] #[command(name = "config")]
Config(config_cmd::Command), Config(config_cmd::Command),
/// Scripts for node recovery /// Scripts for node recovery
#[command(name = "recover")] #[command(name = "recover")]
Recover(recover::Command), Recover(recover::Command<OpChainSpecParser>),
/// Prune according to the configuration without any limits /// Prune according to the configuration without any limits
#[command(name = "prune")] #[command(name = "prune")]
Prune(prune::PruneCommand), Prune(prune::PruneCommand<OpChainSpecParser>),
} }

View File

@ -60,7 +60,7 @@ pub struct Cli<Ext: clap::Args + fmt::Debug = NoArgs> {
value_name = "CHAIN_OR_PATH", value_name = "CHAIN_OR_PATH",
long_help = chain_help(), long_help = chain_help(),
default_value = OpChainSpecParser::SUPPORTED_CHAINS[0], default_value = OpChainSpecParser::SUPPORTED_CHAINS[0],
value_parser = OpChainSpecParser::default(), value_parser = OpChainSpecParser::parser(),
global = true, global = true,
)] )]
chain: Arc<ChainSpec>, chain: Arc<ChainSpec>,

View File

@ -21,13 +21,16 @@ use std::{
use clap::Parser; use clap::Parser;
use futures_util::{stream::FuturesUnordered, StreamExt}; use futures_util::{stream::FuturesUnordered, StreamExt};
use mined_sidecar::MinedSidecarStream; use mined_sidecar::MinedSidecarStream;
use reth::{builder::NodeHandle, cli::Cli, primitives::B256, providers::CanonStateSubscriptions}; use reth::{
args::utils::DefaultChainSpecParser, builder::NodeHandle, cli::Cli, primitives::B256,
providers::CanonStateSubscriptions,
};
use reth_node_ethereum::EthereumNode; use reth_node_ethereum::EthereumNode;
pub mod mined_sidecar; pub mod mined_sidecar;
fn main() { fn main() {
Cli::<BeaconSidecarConfig>::parse() Cli::<DefaultChainSpecParser, BeaconSidecarConfig>::parse()
.run(|builder, beacon_config| async move { .run(|builder, beacon_config| async move {
// launch the node // launch the node
let NodeHandle { node, node_exit_future } = let NodeHandle { node, node_exit_future } =

View File

@ -21,13 +21,13 @@ use alloy_rpc_types_beacon::events::PayloadAttributesEvent;
use clap::Parser; use clap::Parser;
use futures_util::stream::StreamExt; use futures_util::stream::StreamExt;
use mev_share_sse::{client::EventStream, EventClient}; use mev_share_sse::{client::EventStream, EventClient};
use reth::cli::Cli; use reth::{args::utils::DefaultChainSpecParser, cli::Cli};
use reth_node_ethereum::EthereumNode; use reth_node_ethereum::EthereumNode;
use std::net::{IpAddr, Ipv4Addr}; use std::net::{IpAddr, Ipv4Addr};
use tracing::{info, warn}; use tracing::{info, warn};
fn main() { fn main() {
Cli::<BeaconEventsConfig>::parse() Cli::<DefaultChainSpecParser, BeaconEventsConfig>::parse()
.run(|builder, args| async move { .run(|builder, args| async move {
let handle = builder.node(EthereumNode::default()).launch().await?; let handle = builder.node(EthereumNode::default()).launch().await?;

View File

@ -13,6 +13,7 @@
use clap::Parser; use clap::Parser;
use futures_util::StreamExt; use futures_util::StreamExt;
use reth::{ use reth::{
args::utils::DefaultChainSpecParser,
builder::NodeHandle, builder::NodeHandle,
cli::Cli, cli::Cli,
primitives::{Address, BlockNumberOrTag, IntoRecoveredTransaction}, primitives::{Address, BlockNumberOrTag, IntoRecoveredTransaction},
@ -28,7 +29,7 @@ use reth_node_ethereum::node::EthereumNode;
use reth_rpc_types::state::EvmOverrides; use reth_rpc_types::state::EvmOverrides;
fn main() { fn main() {
Cli::<RethCliTxpoolExt>::parse() Cli::<DefaultChainSpecParser, RethCliTxpoolExt>::parse()
.run(|builder, args| async move { .run(|builder, args| async move {
// launch the node // launch the node
let NodeHandle { node, node_exit_future } = let NodeHandle { node, node_exit_future } =

View File

@ -14,12 +14,12 @@
use clap::Parser; use clap::Parser;
use jsonrpsee::{core::RpcResult, proc_macros::rpc}; use jsonrpsee::{core::RpcResult, proc_macros::rpc};
use reth::cli::Cli; use reth::{args::utils::DefaultChainSpecParser, cli::Cli};
use reth_node_ethereum::EthereumNode; use reth_node_ethereum::EthereumNode;
use reth_transaction_pool::TransactionPool; use reth_transaction_pool::TransactionPool;
fn main() { fn main() {
Cli::<RethCliTxpoolExt>::parse() Cli::<DefaultChainSpecParser, RethCliTxpoolExt>::parse()
.run(|builder, args| async move { .run(|builder, args| async move {
let handle = builder let handle = builder
.node(EthereumNode::default()) .node(EthereumNode::default())

View File

@ -13,6 +13,7 @@
use clap::Parser; use clap::Parser;
use futures_util::StreamExt; use futures_util::StreamExt;
use reth::{ use reth::{
args::utils::DefaultChainSpecParser,
builder::NodeHandle, builder::NodeHandle,
cli::Cli, cli::Cli,
primitives::{Address, IntoRecoveredTransaction}, primitives::{Address, IntoRecoveredTransaction},
@ -25,7 +26,7 @@ use reth::{
use reth_node_ethereum::node::EthereumNode; use reth_node_ethereum::node::EthereumNode;
fn main() { fn main() {
Cli::<RethCliTxpoolExt>::parse() Cli::<DefaultChainSpecParser, RethCliTxpoolExt>::parse()
.run(|builder, args| async move { .run(|builder, args| async move {
// launch the node // launch the node
let NodeHandle { node, node_exit_future } = let NodeHandle { node, node_exit_future } =