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::{args::LogArgs, version::version_metadata};
52use reth_optimism_node::args::RollupArgs;
53
54use reth_node_metrics as _;
57
58#[derive(Debug, Parser)]
62#[command(author, version = version_metadata().short_version.as_ref(), long_version = version_metadata().long_version.as_ref(), about = "Reth", long_about = None)]
63pub struct Cli<
64 Spec: ChainSpecParser = OpChainSpecParser,
65 Ext: clap::Args + fmt::Debug = RollupArgs,
66 Rpc: RpcModuleValidator = DefaultRpcModuleValidator,
67> {
68 #[command(subcommand)]
70 pub command: Commands<Spec, Ext>,
71
72 #[command(flatten)]
74 pub logs: LogArgs,
75
76 #[arg(skip)]
78 _phantom: PhantomData<Rpc>,
79}
80
81impl Cli {
82 pub fn parse_args() -> Self {
84 Self::parse()
85 }
86
87 pub fn try_parse_args_from<I, T>(itr: I) -> Result<Self, clap::error::Error>
89 where
90 I: IntoIterator<Item = T>,
91 T: Into<OsString> + Clone,
92 {
93 Self::try_parse_from(itr)
94 }
95}
96
97impl<C, Ext, Rpc> Cli<C, Ext, Rpc>
98where
99 C: ChainSpecParser<ChainSpec = OpChainSpec>,
100 Ext: clap::Args + fmt::Debug,
101 Rpc: RpcModuleValidator,
102{
103 pub fn configure(self) -> CliApp<C, Ext, Rpc> {
108 CliApp::new(self)
109 }
110
111 pub fn run<L, Fut>(self, launcher: L) -> eyre::Result<()>
116 where
117 L: FnOnce(WithLaunchContext<NodeBuilder<Arc<DatabaseEnv>, C::ChainSpec>>, Ext) -> Fut,
118 Fut: Future<Output = eyre::Result<()>>,
119 {
120 self.with_runner(CliRunner::try_default_runtime()?, launcher)
121 }
122
123 pub fn with_runner<L, Fut>(self, runner: CliRunner, launcher: L) -> eyre::Result<()>
125 where
126 L: FnOnce(WithLaunchContext<NodeBuilder<Arc<DatabaseEnv>, C::ChainSpec>>, Ext) -> Fut,
127 Fut: Future<Output = eyre::Result<()>>,
128 {
129 let mut this = self.configure();
130 this.set_runner(runner);
131 this.run(FnLauncher::new::<C, Ext>(async move |builder, chain_spec| {
132 launcher(builder, chain_spec).await
133 }))
134 }
135}
136
137#[cfg(test)]
138mod test {
139 use crate::{chainspec::OpChainSpecParser, commands::Commands, Cli};
140 use clap::Parser;
141 use reth_cli_commands::{node::NoArgs, NodeCommand};
142 use reth_optimism_chainspec::{BASE_MAINNET, OP_DEV};
143 use reth_optimism_node::args::RollupArgs;
144
145 #[test]
146 fn parse_dev() {
147 let cmd = NodeCommand::<OpChainSpecParser, NoArgs>::parse_from(["op-reth", "--dev"]);
148 let chain = OP_DEV.clone();
149 assert_eq!(cmd.chain.chain, chain.chain);
150 assert_eq!(cmd.chain.genesis_hash(), chain.genesis_hash());
151 assert_eq!(
152 cmd.chain.paris_block_and_final_difficulty,
153 chain.paris_block_and_final_difficulty
154 );
155 assert_eq!(cmd.chain.hardforks, chain.hardforks);
156
157 assert!(cmd.rpc.http);
158 assert!(cmd.network.discovery.disable_discovery);
159
160 assert!(cmd.dev.dev);
161 }
162
163 #[test]
164 fn parse_node() {
165 let cmd = Cli::<OpChainSpecParser, RollupArgs>::parse_from([
166 "op-reth",
167 "node",
168 "--chain",
169 "base",
170 "--datadir",
171 "/mnt/datadirs/base",
172 "--instance",
173 "2",
174 "--http",
175 "--http.addr",
176 "0.0.0.0",
177 "--ws",
178 "--ws.addr",
179 "0.0.0.0",
180 "--http.api",
181 "admin,debug,eth,net,trace,txpool,web3,rpc,reth,ots",
182 "--rollup.sequencer-http",
183 "https://mainnet-sequencer.base.org",
184 "--rpc-max-tracing-requests",
185 "1000000",
186 "--rpc.gascap",
187 "18446744073709551615",
188 "--rpc.max-connections",
189 "429496729",
190 "--rpc.max-logs-per-response",
191 "0",
192 "--rpc.max-subscriptions-per-connection",
193 "10000",
194 "--metrics",
195 "9003",
196 "--log.file.max-size",
197 "100",
198 ]);
199
200 match cmd.command {
201 Commands::Node(command) => {
202 assert_eq!(command.chain.as_ref(), BASE_MAINNET.as_ref());
203 }
204 _ => panic!("unexpected command"),
205 }
206 }
207}