Skip to main content

tempo/
cli.rs

1//! CLI type definitions for the Tempo node.
2
3use crate::{defaults, follow, tempo_cmd};
4use reth_ethereum_cli::Cli;
5use reth_rpc_server_types::{RethRpcModule, RpcModuleSelection, RpcModuleValidator};
6use tempo_chainspec::spec::TempoChainSpecParser;
7use tempo_faucet::args::FaucetArgs;
8use tempo_node::TempoNodeArgs;
9
10pub type TempoCli =
11    Cli<TempoChainSpecParser, TempoArgs, TempoRpcModuleValidator, tempo_cmd::TempoSubcommand>;
12
13pub(crate) const TEMPO_CUSTOM_RPC_MODULES: &[&str] = &["consensus", "operator", "tempo", "token"];
14
15#[derive(Debug, Clone, Copy)]
16pub struct TempoRpcModuleValidator;
17
18impl RpcModuleValidator for TempoRpcModuleValidator {
19    fn parse_selection(s: &str) -> Result<RpcModuleSelection, String> {
20        let selection = s
21            .parse::<RpcModuleSelection>()
22            .map_err(|e| format!("Failed to parse RPC modules: {e}"))?;
23
24        if let RpcModuleSelection::Selection(modules) = &selection {
25            for module in modules {
26                let RethRpcModule::Other(name) = module else {
27                    continue;
28                };
29
30                if !TEMPO_CUSTOM_RPC_MODULES.contains(&name.as_str()) {
31                    return Err(format!("Unknown RPC module: '{name}'"));
32                }
33            }
34        }
35
36        Ok(selection)
37    }
38}
39
40// TODO: migrate this to tempo_node eventually.
41#[derive(Debug, Clone, clap::Args)]
42pub struct TempoArgs {
43    /// Run in follow mode from an upstream node.
44    /// If provided without a value, defaults to the RPC URL for the selected chain.
45    #[arg(long, value_name = "WEBSOCKET_URL", default_missing_value = "auto", num_args(0..=1), env = "TEMPO_FOLLOW")]
46    pub(crate) follow: Option<follow::FollowMode>,
47
48    /// Disable consensus certification in follow mode. The follower syncs execution
49    /// state from the upstream node without validating consensus state.
50    /// DO NOT USE IN PRODUCTION.
51    #[arg(long = "follow.nocertify", requires = "follow")]
52    pub(crate) follow_nocertify: bool,
53
54    /// DEPRECATED. Certification is now enabled by default in follow mode. Use
55    /// --follow.nocertify to disable. This argument is a no-op.
56    #[arg(long = "follow.experimental.certify", requires = "follow", hide = true)]
57    pub(crate) follow_experimental_certify: bool,
58
59    /// HTTP endpoint that returns a JSON object mapping chain IDs to bootnode lists.
60    ///
61    /// The endpoint must return JSON in the format:
62    /// `{ "<chain_id>": ["enode://...", ...] }`
63    ///
64    /// Bootnodes for the current chain are added as peer hints to the discovery service.
65    ///
66    /// Set to "none" to disable.
67    #[arg(
68        long = "tempo.bootnodes-endpoint",
69        value_name = "URL",
70        default_value = "https://peers.tempo.xyz",
71        env = "TEMPO_BOOTNODES_ENDPOINT"
72    )]
73    pub(crate) bootnodes_endpoint: String,
74
75    #[command(flatten)]
76    pub(crate) telemetry: defaults::TelemetryArgs,
77
78    #[command(flatten)]
79    pub(crate) consensus: tempo_consensus::Args,
80
81    #[command(flatten)]
82    pub(crate) faucet_args: FaucetArgs,
83
84    #[command(flatten)]
85    pub(crate) node_args: TempoNodeArgs,
86
87    #[command(flatten)]
88    #[cfg(feature = "pyroscope")]
89    pub(crate) pyroscope_args: PyroscopeArgs,
90}
91
92impl TempoArgs {
93    pub(crate) fn is_following_uncertified(&self) -> bool {
94        self.follow.is_some() && self.follow_nocertify
95    }
96
97    /// Whether the consensus engine should be active.
98    ///
99    /// The engine runs when not in dev mode and not following uncertified.
100    pub fn has_consensus_engine(&self, dev: bool) -> bool {
101        !dev && !self.is_following_uncertified()
102    }
103}
104
105/// Command line arguments for configuring Pyroscope continuous profiling.
106#[cfg(feature = "pyroscope")]
107#[derive(Debug, Clone, PartialEq, Eq, clap::Args)]
108pub(crate) struct PyroscopeArgs {
109    /// Enable Pyroscope continuous profiling
110    #[arg(long = "pyroscope.enabled", default_value_t = false)]
111    pub(crate) pyroscope_enabled: bool,
112
113    /// Pyroscope server URL
114    #[arg(long = "pyroscope.server-url", default_value = "http://localhost:4040")]
115    pub(crate) server_url: String,
116
117    /// Application name for Pyroscope
118    #[arg(long = "pyroscope.application-name", default_value = "tempo")]
119    pub(crate) application_name: String,
120
121    /// Sample rate for profiling (default: 100 Hz)
122    #[arg(long = "pyroscope.sample-rate", default_value_t = 100)]
123    pub(crate) sample_rate: u32,
124}