pd/
cli.rs

1//! Command-line interface utilities for the `pd` daemon.
2
3use {
4    clap::{Parser, Subcommand},
5    std::{net::SocketAddr, path::PathBuf},
6    url::Url,
7};
8
9#[derive(Debug, Parser)]
10#[clap(name = "pd", about = "The Penumbra daemon.", version)]
11pub struct Opt {
12    /// Command to run.
13    #[clap(subcommand)]
14    pub cmd: RootCommand,
15}
16
17#[derive(Debug, Subcommand)]
18pub enum RootCommand {
19    /// Starts the Penumbra daemon.
20    Start {
21        /// The path used to store all `pd`-related data and configuration.
22        /// If unset, defaults to ~/.penumbra/network_data/node0/pd.
23        #[clap(long, env = "PENUMBRA_PD_HOME", display_order = 100)]
24        home: Option<PathBuf>,
25        /// Bind the ABCI server to this socket.
26        ///
27        /// The ABCI server is used by Tendermint to drive the application state.
28        #[clap(
29            short,
30            long,
31            env = "PENUMBRA_PD_ABCI_BIND",
32            default_value = "127.0.0.1:26658",
33            display_order = 400
34        )]
35        // TODO: Add support for Unix domain sockets, available in tower-abci >=0.10.0
36        abci_bind: SocketAddr,
37        /// Bind the gRPC server to this socket.
38        ///
39        /// The gRPC server supports both grpc (HTTP/2) and grpc-web (HTTP/1.1) clients.
40        ///
41        /// If `grpc_auto_https` is set, this defaults to `0.0.0.0:443` and uses HTTPS.
42        ///
43        /// If `grpc_auto_https` is not set, this defaults to `127.0.0.1:8080` without HTTPS.
44        #[clap(short, long, env = "PENUMBRA_PD_GRPC_BIND", display_order = 201)]
45        grpc_bind: Option<SocketAddr>,
46        /// If set, serve gRPC using auto-managed HTTPS with this domain name.
47        ///
48        /// NOTE: This option automatically provisions TLS certificates from
49        /// Let's Encrypt and caches them in the `home` directory.  The
50        /// production LE CA has rate limits, so be careful using this option
51        /// with `pd network unsafe-reset-all`, which will delete the certificates
52        /// and force re-issuance, possibly hitting the rate limit. See the
53        /// `--acme-staging` option.
54        #[clap(long, value_name = "DOMAIN", display_order = 200)]
55        grpc_auto_https: Option<String>,
56        /// Enable use of the LetsEncrypt ACME staging API (https://letsencrypt.org/docs/staging-environment/),
57        /// which is more forgiving of ratelimits. Set this option to `true`
58        /// if you're trying out the `--grpc-auto-https` option for the first time,
59        /// to validate your configuration, before subjecting yourself to production
60        /// ratelimits. This option has no effect if `--grpc-auto-https` is not set.
61        #[clap(long, display_order = 201)]
62        acme_staging: bool,
63        /// Bind the metrics endpoint to this socket.
64        #[clap(
65            short,
66            long,
67            env = "PENUMBRA_PD_METRICS_BIND",
68            default_value = "127.0.0.1:9000",
69            display_order = 300
70        )]
71        metrics_bind: SocketAddr,
72        /// The JSON-RPC address of the CometBFT node driving this `pd`
73        /// instance.
74        ///
75        /// This is used to proxy requests from the gRPC server to CometBFT,
76        /// so clients only need to connect to one endpoint and don't need to
77        /// worry about the peculiarities of CometBFT's JSON-RPC encoding
78        /// format.
79        #[clap(
80            short,
81            long,
82            env = "PENUMBRA_PD_COMETBFT_PROXY_URL",
83            default_value = "http://127.0.0.1:26657",
84            display_order = 401,
85            // Support old arg name for a while, as we migrate Tendermint -> CometBFT.
86            alias = "tendermint-addr",
87        )]
88        cometbft_addr: Url,
89        /// Enable expensive RPCs, currently a no-op.
90        #[clap(short, long, display_order = 500)]
91        enable_expensive_rpc: bool,
92    },
93
94    /// Generate, join, or reset a network.
95    Network {
96        /// Path to directory to store output in. Must not exist. Defaults to
97        /// ~/.penumbra/network_data".
98        #[clap(long)]
99        network_dir: Option<PathBuf>,
100        #[clap(subcommand)]
101        net_cmd: NetworkCommand,
102    },
103
104    /// Export the storage state the full node.
105    Export {
106        /// The home directory of the full node.
107        #[clap(long, env = "PENUMBRA_PD_HOME", display_order = 100)]
108        home: PathBuf,
109        /// The directory where the exported node state will be written.
110        #[clap(long, display_order = 200, alias = "export-path")]
111        export_directory: PathBuf,
112        /// An optional filepath for a compressed archive containing the exported
113        /// node state, e.g. ~/pd-backup.tar.gz.
114        #[clap(long, display_order = 200)]
115        export_archive: Option<PathBuf>,
116        /// Whether to prune the JMT tree.
117        #[clap(long, display_order = 300)]
118        prune: bool,
119    },
120
121    /// Run a migration before resuming post-upgrade.
122    Migrate {
123        /// The home directory of the full node.
124        ///
125        /// Migration is performed in-place on the home directory.
126        #[clap(long, env = "PENUMBRA_PD_HOME", display_order = 100)]
127        home: Option<PathBuf>,
128        /// If set, also migrate the CometBFT state located in this home directory.
129        /// If both `--home` and `--comet-home` are unset, will attempt to migrate
130        /// CometBFT state alongside the auto-located `pd` state.
131        // Note: this does _NOT_ use an env var because we are trying to
132        // get explicit consent to muck around in another daemon's state.
133        #[clap(long, display_order = 200)]
134        comet_home: Option<PathBuf>,
135        /// If set, force a migration to occur even if the chain is not halted.
136        /// Will not override a detected mismatch in state versions, or on signs
137        /// of corruption. This is "expert mode" and potentially destructive.
138        #[clap(long, display_order = 1000)]
139        force: bool,
140        /// If set, edit local state to permit the node to start, despite
141        /// a pre-existing halt order, e.g. via governance. This option
142        /// can be useful for relayer operators, to run a temporary archive node
143        /// across upgrade boundaries.
144        #[clap(long, display_order = 1000)]
145        ready_to_start: bool,
146        /// Optional migration subcommand. If not specified, runs the default migration.
147        #[clap(subcommand)]
148        migration_type: Option<MigrateCommand>,
149    },
150}
151
152#[derive(Debug, Subcommand)]
153pub enum MigrateCommand {
154    /// Reset the chain's halt bit to allow it to start.
155    ReadyToStart,
156    /// Perform IBC client recovery, overwriting an old client ID with a new one.
157    IbcRecovery {
158        /// The old IBC client ID to replace.
159        #[clap(long, short = 'o', value_name = "OLD_CLIENT_ID")]
160        old_client_id: String,
161        /// The new IBC client ID to use.
162        #[clap(long, short = 'n', value_name = "NEW_CLIENT_ID")]
163        new_client_id: String,
164        /// Optional app version to set during migration.
165        #[clap(long, value_name = "VERSION")]
166        target_app_version: Option<u64>,
167    },
168    /// Perform a no-op migration that resets the halt bit and produces a new genesis.
169    NoOp {
170        /// Optional app version to set during migration.
171        #[clap(long, value_name = "VERSION")]
172        target_app_version: Option<u64>,
173    },
174}
175
176#[derive(Debug, Subcommand)]
177pub enum NetworkCommand {
178    /// Generates a directory structure containing necessary files to create a new
179    /// network config from genesis, based on input configuration.
180    Generate {
181        /// The `timeout_commit` parameter (block interval) to configure Tendermint with.
182        #[clap(long)]
183        timeout_commit: Option<tendermint::Timeout>,
184        /// Number of blocks per epoch.
185        #[clap(long)]
186        epoch_duration: Option<u64>,
187        /// Number of blocks that must elapse before unbonding stake is released.
188        #[clap(long)]
189        unbonding_delay: Option<u64>,
190        /// Maximum number of validators in the consensus set.
191        #[clap(long)]
192        active_validator_limit: Option<u64>,
193        /// Whether to preserve the chain ID (useful for public networks) or append a random suffix (useful for dev/testing).
194        #[clap(long)]
195        preserve_chain_id: bool,
196        /// Path to CSV file containing initial allocations [default: latest testnet].
197        #[clap(long, parse(from_os_str))]
198        allocations_input_file: Option<PathBuf>,
199        /// Penumbra wallet address to include in genesis allocations.
200        /// Intended to make dev experience nicer on first run:
201        /// generate a wallet, view its address, then generate a devnet
202        /// with that address included in the base allocations.
203        #[clap(long)]
204        allocation_address: Option<penumbra_sdk_keys::Address>,
205        #[clap(long, parse(from_os_str))]
206        /// Path to JSON file containing initial validator configs [default: latest testnet].
207        validators_input_file: Option<PathBuf>,
208        /// Testnet name [default: latest testnet].
209        #[clap(long)]
210        chain_id: Option<String>,
211        /// The duration, in number of blocks, that a governance proposal
212        /// can be voted on.
213        #[clap(long)]
214        proposal_voting_blocks: Option<u64>,
215        /// The fixed gas price for all transactions on the network.
216        /// Described as "simple" because the single value will be reused
217        /// for all gas price types: block space, compact block space, verification, and execution.
218        /// The numeric value is one-thousandths of the base unit of the fee token,
219        /// so `--gas-price-simple=1000` means all resources will have a cost of 1upenumbra.
220        #[clap(long)]
221        gas_price_simple: Option<u64>,
222        /// Base hostname for a validator's p2p service. If multiple validators
223        /// exist in the genesis, e.g. via `--validators-input-file`, then
224        /// numeric suffixes are automatically added, e.g. "-0", "-1", etc.
225        /// Helpful for when you know the validator DNS names ahead of time,
226        /// e.g. in Kubernetes service addresses. These option is most useful
227        /// to provide peering on a private network setup. If you plan to expose
228        /// the validator P2P services to the internet, see the `--external-addresses` option.
229        #[clap(long)]
230        peer_address_template: Option<String>,
231        /// Public addresses and ports for the Tendermint P2P services of the genesis
232        /// validator. Accepts comma-separated values, to support multiple validators.
233        /// If `--validators-input-file` is used to increase the number
234        /// of validators, and the `--external-addresses` flag is set, then the number of
235        /// external addresses must equal the number of validators. See the
236        /// `--peer-address-template` flag if you don't plan to expose the network
237        /// to public peers.
238        #[clap(long)]
239        // TODO we should support DNS names here. However, there are complications:
240        // https://github.com/tendermint/tendermint/issues/1521
241        external_addresses: Option<String>,
242    },
243
244    /// Like `network generate`, but joins the network to which the specified node belongs.
245    /// Requires a URL for the CometBFT RPC for the bootstrap node.
246    Join {
247        /// URL of the remote CometBFT RPC endpoint for bootstrapping connection.
248        #[clap(env = "PENUMBRA_PD_JOIN_URL")]
249        node: Url,
250        /// Optional URL of archived node state in .tar.gz format. The archive will be
251        /// downloaded and extracted locally, allowing the node to join a network at a block height
252        /// higher than 0. Supports loading the archive from a local file, if set with file scheme
253        /// explicitly, e.g. `file:///path/to/archive.tar.gz`.
254        #[clap(long, env = "PENUMBRA_PD_ARCHIVE_URL")]
255        archive_url: Option<Url>,
256        /// Human-readable name to identify node on network
257        // Default: 'node-#'
258        #[clap(long, env = "PENUMBRA_PD_TM_EXTERNAL_ADDR")]
259        moniker: Option<String>,
260        /// Public URL to advertise for this node's Tendermint P2P service.
261        /// Setting this option will instruct other nodes on the network to connect
262        /// to yours. Must be in the form of a socket, e.g. "1.2.3.4:26656".
263        #[clap(long, env = "PENUMBRA_PD_TM_EXTERNAL_ADDR")]
264        external_address: Option<SocketAddr>,
265        /// When generating Tendermint config, use this socket to bind the Tendermint RPC service.
266        #[clap(long, env = "PENUMBRA_PD_TM_RPC_BIND", default_value = "0.0.0.0:26657")]
267        tendermint_rpc_bind: SocketAddr,
268        /// When generating Tendermint config, use this socket to bind the Tendermint P2P service.
269        #[clap(long, env = "PENUMBRA_PD_TM_P2P_BIND", default_value = "0.0.0.0:26656")]
270        tendermint_p2p_bind: SocketAddr,
271        /// Leave the downloaded archive file on disk after extraction.
272        #[clap(long, env = "PENUMBRA_PD_LEAVE_ARCHIVE", action)]
273        leave_archive: bool,
274    },
275
276    /// Reset all `pd` network state. This is a destructive action!
277    UnsafeResetAll {},
278}