reth_optimism_cli/
app.rs

1use crate::{Cli, Commands};
2use eyre::{eyre, Result};
3use reth_cli::chainspec::ChainSpecParser;
4use reth_cli_commands::launcher::Launcher;
5use reth_cli_runner::CliRunner;
6use reth_node_metrics::recorder::install_prometheus_recorder;
7use reth_optimism_chainspec::OpChainSpec;
8use reth_optimism_consensus::OpBeaconConsensus;
9use reth_optimism_node::{OpExecutorProvider, OpNode};
10use reth_tracing::{FileWorkerGuard, Layers};
11use std::{fmt, sync::Arc};
12use tracing::info;
13
14/// A wrapper around a parsed CLI that handles command execution.
15#[derive(Debug)]
16pub struct CliApp<Spec: ChainSpecParser, Ext: clap::Args + fmt::Debug> {
17    cli: Cli<Spec, Ext>,
18    runner: Option<CliRunner>,
19    layers: Option<Layers>,
20    guard: Option<FileWorkerGuard>,
21}
22
23impl<C, Ext> CliApp<C, Ext>
24where
25    C: ChainSpecParser<ChainSpec = OpChainSpec>,
26    Ext: clap::Args + fmt::Debug,
27{
28    pub(crate) fn new(cli: Cli<C, Ext>) -> Self {
29        Self { cli, runner: None, layers: Some(Layers::new()), guard: None }
30    }
31
32    /// Sets the runner for the CLI commander.
33    ///
34    /// This replaces any existing runner with the provided one.
35    pub fn set_runner(&mut self, runner: CliRunner) {
36        self.runner = Some(runner);
37    }
38
39    /// Access to tracing layers.
40    ///
41    /// Returns a mutable reference to the tracing layers, or error
42    /// if tracing initialized and layers have detached already.
43    pub fn access_tracing_layers(&mut self) -> Result<&mut Layers> {
44        self.layers.as_mut().ok_or_else(|| eyre!("Tracing already initialized"))
45    }
46
47    /// Execute the configured cli command.
48    ///
49    /// This accepts a closure that is used to launch the node via the
50    /// [`NodeCommand`](reth_cli_commands::node::NodeCommand).
51    pub fn run(mut self, launcher: impl Launcher<C, Ext>) -> Result<()> {
52        let runner = match self.runner.take() {
53            Some(runner) => runner,
54            None => CliRunner::try_default_runtime()?,
55        };
56
57        // add network name to logs dir
58        // Add network name if available to the logs dir
59        if let Some(chain_spec) = self.cli.command.chain_spec() {
60            self.cli.logs.log_file_directory =
61                self.cli.logs.log_file_directory.join(chain_spec.chain.to_string());
62        }
63
64        self.init_tracing()?;
65        // Install the prometheus recorder to be sure to record all metrics
66        let _ = install_prometheus_recorder();
67
68        let components = |spec: Arc<OpChainSpec>| {
69            (OpExecutorProvider::optimism(spec.clone()), OpBeaconConsensus::new(spec))
70        };
71
72        match self.cli.command {
73            Commands::Node(command) => {
74                runner.run_command_until_exit(|ctx| command.execute(ctx, launcher))
75            }
76            Commands::Init(command) => {
77                runner.run_blocking_until_ctrl_c(command.execute::<OpNode>())
78            }
79            Commands::InitState(command) => {
80                runner.run_blocking_until_ctrl_c(command.execute::<OpNode>())
81            }
82            Commands::ImportOp(command) => {
83                runner.run_blocking_until_ctrl_c(command.execute::<OpNode>())
84            }
85            Commands::ImportReceiptsOp(command) => {
86                runner.run_blocking_until_ctrl_c(command.execute::<OpNode>())
87            }
88            Commands::DumpGenesis(command) => runner.run_blocking_until_ctrl_c(command.execute()),
89            Commands::Db(command) => runner.run_blocking_until_ctrl_c(command.execute::<OpNode>()),
90            Commands::Stage(command) => {
91                runner.run_command_until_exit(|ctx| command.execute::<OpNode, _>(ctx, components))
92            }
93            Commands::P2P(command) => runner.run_until_ctrl_c(command.execute::<OpNode>()),
94            Commands::Config(command) => runner.run_until_ctrl_c(command.execute()),
95            Commands::Recover(command) => {
96                runner.run_command_until_exit(|ctx| command.execute::<OpNode>(ctx))
97            }
98            Commands::Prune(command) => runner.run_until_ctrl_c(command.execute::<OpNode>()),
99            #[cfg(feature = "dev")]
100            Commands::TestVectors(command) => runner.run_until_ctrl_c(command.execute()),
101            Commands::ReExecute(command) => {
102                runner.run_until_ctrl_c(command.execute::<OpNode>(components))
103            }
104        }
105    }
106
107    /// Initializes tracing with the configured options.
108    ///
109    /// If file logging is enabled, this function stores guard to the struct.
110    pub fn init_tracing(&mut self) -> Result<()> {
111        if self.guard.is_none() {
112            let layers = self.layers.take().unwrap_or_default();
113            self.guard = self.cli.logs.init_tracing_with_layers(layers)?;
114            info!(target: "reth::cli", "Initialized tracing, debug log directory: {}", self.cli.logs.log_file_directory);
115        }
116        Ok(())
117    }
118}