1#![doc(
4 html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
5 html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
6 issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
7)]
8#![cfg_attr(not(test), warn(unused_crate_dependencies))]
9#![cfg_attr(docsrs, feature(doc_cfg))]
10
11pub mod app;
13pub mod chainspec;
15pub mod commands;
17pub mod receipt_file_codec;
29
30pub mod ovm_file_codec;
34
35pub use app::CliApp;
36pub use commands::{import::ImportOpCommand, import_receipts::ImportReceiptsOpCommand};
37use reth_optimism_chainspec::OpChainSpec;
38use reth_rpc_server_types::{DefaultRpcModuleValidator, RpcModuleValidator};
39
40use std::{ffi::OsString, fmt, marker::PhantomData, sync::Arc};
41
42use chainspec::OpChainSpecParser;
43use clap::Parser;
44use commands::Commands;
45use futures_util::Future;
46use reth_cli::chainspec::ChainSpecParser;
47use reth_cli_commands::launcher::FnLauncher;
48use reth_cli_runner::CliRunner;
49use reth_db::DatabaseEnv;
50use reth_node_builder::{NodeBuilder, WithLaunchContext};
51use reth_node_core::{
52 args::{LogArgs, TraceArgs},
53 version::version_metadata,
54};
55use reth_optimism_node::args::RollupArgs;
56
57use reth_node_metrics as _;
60
61#[derive(Debug, Parser)]
65#[command(author, version = version_metadata().short_version.as_ref(), long_version = version_metadata().long_version.as_ref(), about = "Reth", long_about = None)]
66pub struct Cli<
67 Spec: ChainSpecParser = OpChainSpecParser,
68 Ext: clap::Args + fmt::Debug = RollupArgs,
69 Rpc: RpcModuleValidator = DefaultRpcModuleValidator,
70> {
71 #[command(subcommand)]
73 pub command: Commands<Spec, Ext>,
74
75 #[command(flatten)]
77 pub logs: LogArgs,
78
79 #[command(flatten)]
81 pub traces: TraceArgs,
82
83 #[arg(skip)]
85 _phantom: PhantomData<Rpc>,
86}
87
88impl Cli {
89 pub fn parse_args() -> Self {
91 Self::parse()
92 }
93
94 pub fn try_parse_args_from<I, T>(itr: I) -> Result<Self, clap::error::Error>
96 where
97 I: IntoIterator<Item = T>,
98 T: Into<OsString> + Clone,
99 {
100 Self::try_parse_from(itr)
101 }
102}
103
104impl<C, Ext, Rpc> Cli<C, Ext, Rpc>
105where
106 C: ChainSpecParser<ChainSpec = OpChainSpec>,
107 Ext: clap::Args + fmt::Debug,
108 Rpc: RpcModuleValidator,
109{
110 pub fn configure(self) -> CliApp<C, Ext, Rpc> {
115 CliApp::new(self)
116 }
117
118 pub fn run<L, Fut>(self, launcher: L) -> eyre::Result<()>
123 where
124 L: FnOnce(WithLaunchContext<NodeBuilder<Arc<DatabaseEnv>, C::ChainSpec>>, Ext) -> Fut,
125 Fut: Future<Output = eyre::Result<()>>,
126 {
127 self.with_runner(CliRunner::try_default_runtime()?, launcher)
128 }
129
130 pub fn with_runner<L, Fut>(self, runner: CliRunner, launcher: L) -> eyre::Result<()>
132 where
133 L: FnOnce(WithLaunchContext<NodeBuilder<Arc<DatabaseEnv>, C::ChainSpec>>, Ext) -> Fut,
134 Fut: Future<Output = eyre::Result<()>>,
135 {
136 let mut this = self.configure();
137 this.set_runner(runner);
138 this.run(FnLauncher::new::<C, Ext>(async move |builder, chain_spec| {
139 launcher(builder, chain_spec).await
140 }))
141 }
142}
143
144#[cfg(test)]
145mod test {
146 use crate::{chainspec::OpChainSpecParser, commands::Commands, Cli};
147 use clap::Parser;
148 use reth_cli_commands::{node::NoArgs, NodeCommand};
149 use reth_optimism_chainspec::{BASE_MAINNET, OP_DEV};
150 use reth_optimism_node::args::RollupArgs;
151
152 #[test]
153 fn parse_dev() {
154 let cmd = NodeCommand::<OpChainSpecParser, NoArgs>::parse_from(["op-reth", "--dev"]);
155 let chain = OP_DEV.clone();
156 assert_eq!(cmd.chain.chain, chain.chain);
157 assert_eq!(cmd.chain.genesis_hash(), chain.genesis_hash());
158 assert_eq!(
159 cmd.chain.paris_block_and_final_difficulty,
160 chain.paris_block_and_final_difficulty
161 );
162 assert_eq!(cmd.chain.hardforks, chain.hardforks);
163
164 assert!(cmd.rpc.http);
165 assert!(cmd.network.discovery.disable_discovery);
166
167 assert!(cmd.dev.dev);
168 }
169
170 #[test]
171 fn parse_node() {
172 let cmd = Cli::<OpChainSpecParser, RollupArgs>::parse_from([
173 "op-reth",
174 "node",
175 "--chain",
176 "base",
177 "--datadir",
178 "/mnt/datadirs/base",
179 "--instance",
180 "2",
181 "--http",
182 "--http.addr",
183 "0.0.0.0",
184 "--ws",
185 "--ws.addr",
186 "0.0.0.0",
187 "--http.api",
188 "admin,debug,eth,net,trace,txpool,web3,rpc,reth,ots",
189 "--rollup.sequencer-http",
190 "https://mainnet-sequencer.base.org",
191 "--rpc-max-tracing-requests",
192 "1000000",
193 "--rpc.gascap",
194 "18446744073709551615",
195 "--rpc.max-connections",
196 "429496729",
197 "--rpc.max-logs-per-response",
198 "0",
199 "--rpc.max-subscriptions-per-connection",
200 "10000",
201 "--metrics",
202 "9003",
203 "--tracing-otlp=http://localhost:4318/v1/traces",
204 "--log.file.max-size",
205 "100",
206 ]);
207
208 match cmd.command {
209 Commands::Node(command) => {
210 assert_eq!(command.chain.as_ref(), BASE_MAINNET.as_ref());
211 }
212 _ => panic!("unexpected command"),
213 }
214 }
215}