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}