Skip to main content

linera_service/cli/
command.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::{borrow::Cow, num::NonZeroU16, path::PathBuf};
5
6use chrono::{DateTime, Utc};
7use linera_base::{
8    crypto::{AccountPublicKey, CryptoHash, ValidatorPublicKey},
9    data_types::{Amount, BlockHeight, Epoch, Timestamp},
10    identifiers::{Account, AccountOwner, ApplicationId, ChainId, ModuleId, StreamId},
11    time::Duration,
12    vm::VmRuntime,
13};
14use linera_client::{
15    chain_listener::ChainListenerConfig,
16    client_options::{
17        ApplicationPermissionsConfig, ChainOwnershipConfig, ResourceControlPolicyConfig,
18    },
19    util,
20};
21use linera_rpc::config::CrossChainConfig;
22
23use crate::{
24    cli::validator, query_subscription::parse_subscription_ttl, task_processor::parse_operator,
25};
26
27const DEFAULT_TOKENS_PER_CHAIN: Amount = Amount::from_millis(100);
28const DEFAULT_TRANSACTIONS_PER_BLOCK: usize = 1;
29const DEFAULT_WRAP_UP_MAX_IN_FLIGHT: usize = 5;
30const DEFAULT_NUM_CHAINS: usize = 10;
31const DEFAULT_BPS: usize = 10;
32
33/// Specification for a validator to be added to the committee.
34#[derive(Clone, Debug)]
35pub struct ValidatorToAdd {
36    /// The validator's public key.
37    pub public_key: ValidatorPublicKey,
38    /// The validator's account public key.
39    pub account_key: AccountPublicKey,
40    /// The network address of the validator.
41    pub address: String,
42    /// The number of votes assigned to the validator.
43    pub votes: u64,
44}
45
46impl std::str::FromStr for ValidatorToAdd {
47    type Err = anyhow::Error;
48
49    fn from_str(s: &str) -> Result<Self, Self::Err> {
50        let parts: Vec<&str> = s.split(',').collect();
51        anyhow::ensure!(
52            parts.len() == 4,
53            "Validator spec must be in format: public_key,account_key,address,votes"
54        );
55
56        Ok(ValidatorToAdd {
57            public_key: parts[0].parse()?,
58            account_key: parts[1].parse()?,
59            address: parts[2].to_string(),
60            votes: parts[3].parse()?,
61        })
62    }
63}
64
65/// Which client the benchmark drives its chains with.
66#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, clap::ValueEnum, serde::Serialize)]
67#[serde(rename_all = "kebab-case")]
68pub enum ClientMode {
69    /// A real `ChainClient`: executes every block locally and keeps chain state, so it
70    /// measures what a client experiences.
71    ///
72    /// Two network round trips per block with the root `--allow-fast-blocks` option, which
73    /// is off by default; without it the client skips the fast round and pays a third for
74    /// the validated-then-confirmed path.
75    #[default]
76    Full,
77    /// A storage-free proposer: keeps no chain state and executes nothing, so the generator
78    /// stops being part of what is measured.
79    ///
80    /// Always proposes in `Round::Fast`, which a single-super-owner chain designates as its
81    /// first round; it cannot use the validated-then-confirmed path, so unlike `full` this
82    /// is unaffected by `--allow-fast-blocks`. Three round trips per block.
83    ///
84    /// Reads the validator set and quorum weights from the wallet's *genesis* committee, so
85    /// on a network whose committee has since changed it would target stale addresses. Fine
86    /// for a freshly provisioned benchmark network; check before pointing it at a long-lived
87    /// one.
88    Lite,
89}
90
91#[derive(Clone, clap::Args, serde::Serialize)]
92#[serde(rename_all = "kebab-case")]
93/// Options controlling the behavior of the benchmark command.
94pub struct BenchmarkOptions {
95    /// How many chains to use.
96    #[arg(long, default_value_t = DEFAULT_NUM_CHAINS)]
97    pub num_chains: usize,
98
99    /// How many tokens to assign to each newly created chain.
100    /// These need to cover the transaction fees per chain for the benchmark.
101    #[arg(long, default_value_t = DEFAULT_TOKENS_PER_CHAIN)]
102    pub tokens_per_chain: Amount,
103
104    /// How many transactions to put in each block.
105    #[arg(long, default_value_t = DEFAULT_TRANSACTIONS_PER_BLOCK)]
106    pub transactions_per_block: usize,
107
108    /// The application ID of a fungible token on the wallet's default chain.
109    /// If none is specified, the benchmark uses the native token.
110    #[arg(long)]
111    pub fungible_application_id: Option<ApplicationId>,
112
113    /// The fixed BPS (Blocks Per Second) rate that block proposals will be sent at.
114    #[arg(long, default_value_t = DEFAULT_BPS)]
115    pub bps: usize,
116
117    /// If provided, will close the chains after the benchmark is finished. Keep in mind that
118    /// closing the chains might take a while, and will increase the validator latency while
119    /// they're being closed.
120    #[arg(long)]
121    pub close_chains: bool,
122
123    /// A comma-separated list of host:port pairs to query for health metrics.
124    /// If provided, the benchmark will check these endpoints for validator health
125    /// and terminate if any validator is unhealthy.
126    /// Example: "127.0.0.1:21100,validator-1.some-network.linera.net:21100"
127    #[arg(long)]
128    pub health_check_endpoints: Option<String>,
129
130    /// The maximum number of in-flight requests to validators when wrapping up the benchmark.
131    /// While wrapping up, this controls the concurrency level when processing inboxes and
132    /// closing chains.
133    #[arg(long, default_value_t = DEFAULT_WRAP_UP_MAX_IN_FLIGHT)]
134    pub wrap_up_max_in_flight: usize,
135
136    /// Confirm before starting the benchmark.
137    #[arg(long)]
138    pub confirm_before_start: bool,
139
140    /// How long to run the benchmark for. If not provided, the benchmark will run until
141    /// it is interrupted.
142    #[arg(long)]
143    pub runtime_in_seconds: Option<u64>,
144
145    /// The delay between chains, in milliseconds. For example, if set to 200ms, the first
146    /// chain will start, then the second will start 200 ms after the first one, the third
147    /// 200 ms after the second one, and so on.
148    /// This is used for slowly ramping up the TPS, so we don't pound the validators with the full
149    /// TPS all at once.
150    #[arg(long)]
151    pub delay_between_chains_ms: Option<u64>,
152
153    /// Path to YAML file containing chain IDs to send transfers to.
154    /// If not provided, only transfers between chains in the same wallet.
155    #[arg(long)]
156    pub config_path: Option<PathBuf>,
157
158    /// Transaction distribution mode. If false (default), distributes transactions evenly
159    /// across chains within each block. If true, sends all transactions in each block
160    /// to a single chain, rotating through chains for subsequent blocks.
161    #[arg(long)]
162    pub single_destination_per_block: bool,
163
164    /// Which client to drive the chains with.
165    #[arg(long, value_enum, default_value_t = ClientMode::Full)]
166    pub client_mode: ClientMode,
167
168    /// How many distinct destination chains each chain sends to. Unset means every other
169    /// benchmarked chain, so cross-chain fan-out grows with `--num-chains` and cannot be
170    /// varied on its own; setting it pins fan-out while everything else is held fixed.
171    #[arg(long)]
172    pub fan_out: Option<usize>,
173
174    /// Keep sending cross-chain messages but never drain the inboxes they fill, isolating
175    /// the sending side. Inboxes then grow for the whole run, which is fine for a short
176    /// benchmark and is not a realistic steady state. `--client-mode lite` only.
177    #[arg(long)]
178    pub skip_message_processing: bool,
179
180    /// The maximum number of incoming message bundles to drain into each block, on top of
181    /// its own operations. Defaults to twice the block's operation count, so a backlog is
182    /// spread over several blocks instead of one huge one. `--client-mode lite` only.
183    #[arg(long)]
184    pub max_incoming_bundles_per_block: Option<usize>,
185
186    /// Mix self-transfers in with the cross-chain ones, so roughly half the traffic stays
187    /// on its own chain. Which half is random, not alternating: the generator shuffles its
188    /// destination list, so this sets the ratio rather than an order. Without this a chain
189    /// only ever sends elsewhere; with `--fan-out 0` it only ever sends to itself, and this
190    /// flag is then ignored. Under `--single-destination-per-block` the mix applies per
191    /// block rather than per transaction, so whole blocks are self-transfers.
192    #[arg(long)]
193    pub mixed_self_transfers: bool,
194
195    /// Broadcast each confirmed certificate in its compact, value-free form (hash plus
196    /// signatures) where possible. A validator that has forgotten the value transparently
197    /// gets a retry with the full certificate. `--client-mode lite` only.
198    #[arg(long)]
199    pub light_certificates: bool,
200}
201
202impl Default for BenchmarkOptions {
203    fn default() -> Self {
204        Self {
205            num_chains: DEFAULT_NUM_CHAINS,
206            tokens_per_chain: DEFAULT_TOKENS_PER_CHAIN,
207            transactions_per_block: DEFAULT_TRANSACTIONS_PER_BLOCK,
208            wrap_up_max_in_flight: DEFAULT_WRAP_UP_MAX_IN_FLIGHT,
209            fungible_application_id: None,
210            bps: DEFAULT_BPS,
211            close_chains: false,
212            health_check_endpoints: None,
213            confirm_before_start: false,
214            runtime_in_seconds: None,
215            delay_between_chains_ms: None,
216            config_path: None,
217            single_destination_per_block: false,
218            client_mode: ClientMode::default(),
219            fan_out: None,
220            mixed_self_transfers: false,
221            skip_message_processing: false,
222            max_incoming_bundles_per_block: None,
223            light_certificates: false,
224        }
225    }
226}
227
228#[derive(Clone, clap::Subcommand, serde::Serialize)]
229#[serde(rename_all = "kebab-case")]
230/// The benchmarking subcommands.
231pub enum BenchmarkCommand {
232    /// Start a single benchmark process, maintaining a given TPS.
233    Single {
234        /// The benchmark options.
235        #[command(flatten)]
236        options: BenchmarkOptions,
237    },
238
239    /// Run multiple benchmark processes in parallel.
240    Multi {
241        /// The benchmark options.
242        #[command(flatten)]
243        options: BenchmarkOptions,
244
245        /// The number of benchmark processes to run in parallel.
246        #[arg(long, default_value = "1")]
247        processes: usize,
248
249        /// The faucet (which implicitly defines the network)
250        #[arg(long, env = "LINERA_FAUCET_URL")]
251        faucet: String,
252
253        /// If specified, a directory with a random name will be created in this directory, and the
254        /// client state will be stored there.
255        /// If not specified, a temporary directory will be used for each client.
256        #[arg(long)]
257        client_state_dir: Option<String>,
258
259        /// The delay between starting the benchmark processes, in seconds.
260        /// If --cross-wallet-transfers is true, this will be ignored.
261        #[arg(long, default_value = "10")]
262        delay_between_processes: u64,
263
264        /// Whether to send transfers between chains in different wallets.
265        #[arg(long)]
266        cross_wallet_transfers: bool,
267    },
268}
269
270impl BenchmarkCommand {
271    /// Returns the number of transactions per block configured for this benchmark.
272    pub fn transactions_per_block(&self) -> usize {
273        match self {
274            Self::Single { options } => options.transactions_per_block,
275            Self::Multi { options, .. } => options.transactions_per_block,
276        }
277    }
278}
279
280use crate::util::{
281    DEFAULT_PAUSE_AFTER_GQL_MUTATIONS_SECS, DEFAULT_PAUSE_AFTER_LINERA_SERVICE_SECS,
282};
283
284/// Optional overrides for fields in the active resource control policy.
285#[derive(Clone, Default, clap::Args)]
286pub struct ResourceControlPolicyOverrides {
287    /// Set the price per unit of Wasm fuel.
288    #[arg(long)]
289    pub wasm_fuel_unit: Option<Amount>,
290
291    /// Set the price per unit of EVM fuel.
292    #[arg(long)]
293    pub evm_fuel_unit: Option<Amount>,
294
295    /// Set the price per read operation.
296    #[arg(long)]
297    pub read_operation: Option<Amount>,
298
299    /// Set the price per write operation.
300    #[arg(long)]
301    pub write_operation: Option<Amount>,
302
303    /// Set the price per byte read from runtime.
304    #[arg(long)]
305    pub byte_runtime: Option<Amount>,
306
307    /// Set the price per byte read.
308    #[arg(long)]
309    pub byte_read: Option<Amount>,
310
311    /// Set the price per byte written.
312    #[arg(long)]
313    pub byte_written: Option<Amount>,
314
315    /// Set the base price to read a blob.
316    #[arg(long)]
317    pub blob_read: Option<Amount>,
318
319    /// Set the base price to publish a blob.
320    #[arg(long)]
321    pub blob_published: Option<Amount>,
322
323    /// Set the price to read a blob, per byte.
324    #[arg(long)]
325    pub blob_byte_read: Option<Amount>,
326
327    /// The price to publish a blob, per byte.
328    #[arg(long)]
329    pub blob_byte_published: Option<Amount>,
330
331    /// Set the base price of sending an operation from a block..
332    #[arg(long)]
333    pub operation: Option<Amount>,
334
335    /// Set the additional price for each byte in the argument of a user operation.
336    #[arg(long)]
337    pub operation_byte: Option<Amount>,
338
339    /// Set the base price of sending a message from a block..
340    #[arg(long)]
341    pub message: Option<Amount>,
342
343    /// Set the additional price for each byte in the argument of a user message.
344    #[arg(long)]
345    pub message_byte: Option<Amount>,
346
347    /// Set the price per query to a service as an oracle.
348    #[arg(long)]
349    pub service_as_oracle_query: Option<Amount>,
350
351    /// Set the price for performing an HTTP request.
352    #[arg(long)]
353    pub http_request: Option<Amount>,
354
355    /// Set the maximum amount of Wasm fuel per block.
356    #[arg(long)]
357    pub maximum_wasm_fuel_per_block: Option<u64>,
358
359    /// Set the maximum amount of EVM fuel per block.
360    #[arg(long)]
361    pub maximum_evm_fuel_per_block: Option<u64>,
362
363    /// Set the maximum time in milliseconds that a block can spend executing services as oracles.
364    #[arg(long)]
365    pub maximum_service_oracle_execution_ms: Option<u64>,
366
367    /// Set the maximum size of a block, in bytes.
368    #[arg(long)]
369    pub maximum_block_size: Option<u64>,
370
371    /// Set the maximum size of data blobs, compressed bytecode and other binary blobs,
372    /// in bytes.
373    #[arg(long)]
374    pub maximum_blob_size: Option<u64>,
375
376    /// Set the maximum number of published blobs per block.
377    #[arg(long)]
378    pub maximum_published_blobs: Option<u64>,
379
380    /// Set the maximum size of decompressed contract or service bytecode, in bytes.
381    #[arg(long)]
382    pub maximum_bytecode_size: Option<u64>,
383
384    /// Set the maximum size of a block proposal, in bytes.
385    #[arg(long)]
386    pub maximum_block_proposal_size: Option<u64>,
387
388    /// Set the maximum read data per block.
389    #[arg(long)]
390    pub maximum_bytes_read_per_block: Option<u64>,
391
392    /// Set the maximum write data per block.
393    #[arg(long)]
394    pub maximum_bytes_written_per_block: Option<u64>,
395
396    /// Set the maximum size of oracle responses.
397    #[arg(long)]
398    pub maximum_oracle_response_bytes: Option<u64>,
399
400    /// Set the maximum size in bytes of a received HTTP response.
401    #[arg(long)]
402    pub maximum_http_response_bytes: Option<u64>,
403
404    /// Set the maximum amount of time allowed to wait for an HTTP response.
405    #[arg(long)]
406    pub http_request_timeout_ms: Option<u64>,
407
408    /// Set the list of hosts that contracts and services can send HTTP requests to.
409    #[arg(long, value_delimiter = ',')]
410    pub http_request_allow_list: Option<Vec<String>>,
411
412    /// Set the list of application IDs for which message- and event-related fees are waived.
413    #[arg(long, value_delimiter = ',')]
414    pub free_application_ids: Option<Vec<String>>,
415
416    /// Set the protocol flags that are enabled.
417    #[arg(long, value_delimiter = ',')]
418    pub flags: Option<Vec<String>>,
419}
420
421/// The subcommands of the Linera client binary.
422#[derive(Clone, clap::Subcommand)]
423pub enum ClientCommand {
424    /// Transfer funds
425    Transfer {
426        /// Sending chain ID (must be one of our chains)
427        #[arg(long = "from")]
428        sender: Account,
429
430        /// Recipient account
431        #[arg(long = "to")]
432        recipient: Account,
433
434        /// Amount to transfer
435        amount: Amount,
436    },
437
438    /// Open (i.e. activate) a new chain deriving the UID from an existing one.
439    OpenChain {
440        /// Chain ID (must be one of our chains).
441        #[arg(long = "from")]
442        chain_id: Option<ChainId>,
443
444        /// The new owner (otherwise create a key pair and remember it)
445        #[arg(long = "owner")]
446        owner: Option<AccountOwner>,
447
448        /// The initial balance of the new chain. This is subtracted from the parent chain's
449        /// balance.
450        #[arg(long = "initial-balance", default_value = "0")]
451        balance: Amount,
452
453        /// The account on the new chain credited with the initial balance. Defaults to the
454        /// chain account, which is the only balance that pays fees for blocks the account
455        /// itself does not authenticate.
456        #[arg(long = "balance-account", default_value = "0x00")]
457        account: AccountOwner,
458
459        /// Whether to create a super owner for the new chain.
460        #[arg(long)]
461        super_owner: bool,
462    },
463
464    /// Open (i.e. activate) a new multi-owner chain deriving the UID from an existing one.
465    ///
466    /// If the wallet holds the key pair for exactly one of the new chain's owners, that
467    /// owner is automatically assigned as the chain's preferred owner. Otherwise the chain
468    /// can be assigned explicitly using the `assign` command.
469    OpenMultiOwnerChain {
470        /// Chain ID (must be one of our chains).
471        #[arg(long = "from")]
472        chain_id: Option<ChainId>,
473
474        /// Options configuring the new chain's ownership.
475        #[clap(flatten)]
476        ownership_config: ChainOwnershipConfig,
477
478        /// Options configuring the new chain's application permissions.
479        #[clap(flatten)]
480        application_permissions_config: ApplicationPermissionsConfig,
481
482        /// The initial balance of the new chain. This is subtracted from the parent chain's
483        /// balance.
484        #[arg(long = "initial-balance", default_value = "0")]
485        balance: Amount,
486
487        /// The account on the new chain credited with the initial balance. Defaults to the
488        /// chain account, which is the only balance that pays fees for blocks the account
489        /// itself does not authenticate.
490        #[arg(long = "balance-account", default_value = "0x00")]
491        account: AccountOwner,
492    },
493
494    /// Display who owns the chain, and how the owners work together proposing blocks.
495    ShowOwnership {
496        /// The ID of the chain whose owners will be changed.
497        #[clap(long)]
498        chain_id: Option<ChainId>,
499    },
500
501    /// Change who owns the chain, and how the owners work together proposing blocks.
502    ///
503    /// Specify the complete set of new owners, by public key. Existing owners that are
504    /// not included will be removed.
505    ///
506    /// If the chain's current preferred owner is no longer one of the chain's owners
507    /// and the wallet holds the key pair for exactly one of the new owners, that owner
508    /// is automatically assigned as the chain's preferred owner.
509    ChangeOwnership {
510        /// The ID of the chain whose owners will be changed.
511        #[clap(long)]
512        chain_id: Option<ChainId>,
513
514        /// Options configuring the new chain's ownership.
515        #[clap(flatten)]
516        ownership_config: ChainOwnershipConfig,
517    },
518
519    /// Change the preferred owner of a chain.
520    SetPreferredOwner {
521        /// The ID of the chain whose preferred owner will be changed.
522        #[clap(long)]
523        chain_id: Option<ChainId>,
524
525        /// The new preferred owner.
526        #[arg(long)]
527        owner: AccountOwner,
528    },
529
530    /// Changes the application permissions configuration.
531    ChangeApplicationPermissions {
532        /// The ID of the chain to which the new permissions will be applied.
533        #[arg(long)]
534        chain_id: Option<ChainId>,
535
536        /// Options configuring the new chain's application permissions.
537        #[clap(flatten)]
538        application_permissions_config: ApplicationPermissionsConfig,
539    },
540
541    /// Close an existing chain.
542    ///
543    /// A closed chain cannot execute operations or accept messages anymore.
544    /// It can still reject incoming messages, so they bounce back to the sender.
545    CloseChain {
546        /// Chain ID (must be one of our chains)
547        chain_id: ChainId,
548    },
549
550    /// Publish a checkpoint of the chain's execution state.
551    ///
552    /// The resulting block contains a single checkpoint operation. Future nodes can
553    /// bootstrap from the published state snapshot instead of replaying the chain's
554    /// earlier history.
555    Checkpoint {
556        /// The chain to checkpoint. If not specified, the wallet's default chain is used.
557        chain_id: Option<ChainId>,
558    },
559
560    /// Print out the network description.
561    ShowNetworkDescription,
562
563    /// Read the current native-token balance of the given account directly from the local
564    /// state.
565    ///
566    /// NOTE: The local balance does not reflect messages that are waiting to be picked in
567    /// the local inbox, or that have not been synchronized from validators yet. Use
568    /// `linera sync` then either `linera query-balance` or `linera process-inbox &&
569    /// linera local-balance` for a consolidated balance.
570    LocalBalance {
571        /// The account to read, written as `OWNER@CHAIN-ID` or simply `CHAIN-ID` for the
572        /// chain balance. By default, we read the chain balance of the default chain in
573        /// the wallet.
574        account: Option<Account>,
575    },
576
577    /// Simulate the execution of one block made of pending messages from the local inbox,
578    /// then read the native-token balance of the account from the local state.
579    ///
580    /// NOTE: The balance does not reflect messages that have not been synchronized from
581    /// validators yet. Call `linera sync` first to do so.
582    QueryBalance {
583        /// The account to query, written as `OWNER@CHAIN-ID` or simply `CHAIN-ID` for the
584        /// chain balance. By default, we read the chain balance of the default chain in
585        /// the wallet.
586        account: Option<Account>,
587    },
588
589    /// (DEPRECATED) Synchronize the local state of the chain with a quorum validators, then query the
590    /// local balance.
591    ///
592    /// This command is deprecated. Use `linera sync && linera query-balance` instead.
593    SyncBalance {
594        /// The account to query, written as `OWNER@CHAIN-ID` or simply `CHAIN-ID` for the
595        /// chain balance. By default, we read the chain balance of the default chain in
596        /// the wallet.
597        account: Option<Account>,
598    },
599
600    /// Synchronize the local state of the chain with a quorum validators.
601    Sync {
602        /// The chain to synchronize with validators. If omitted, synchronizes the
603        /// default chain of the wallet.
604        chain_id: Option<ChainId>,
605
606        /// Stop synchronizing at this block height (exclusive). For instance,
607        /// `--next-height 0` downloads zero blocks, `--next-height 10` downloads
608        /// blocks 0 through 9.
609        #[arg(long)]
610        next_height: Option<BlockHeight>,
611
612        /// Stop synchronizing at the first block with a timestamp greater than this
613        /// value (inclusive). The format is `YYYY-MM-DDTHH:MM:SS` or
614        /// `YYYY-MM-DD HH:MM:SS` in UTC.
615        #[arg(long)]
616        until_block_time: Option<Timestamp>,
617    },
618
619    /// Process all pending incoming messages from the inbox of the given chain by creating as many
620    /// blocks as needed to execute all (non-failing) messages. Failing messages will be
621    /// marked as rejected and may bounce to their sender depending on their configuration.
622    ProcessInbox {
623        /// The chain to process. If omitted, uses the default chain of the wallet.
624        chain_id: Option<ChainId>,
625    },
626
627    /// Query validators for shard information about a specific chain.
628    QueryShardInfo {
629        /// The chain to query shard information for.
630        chain_id: ChainId,
631    },
632
633    /// Deprecates all committees up to and including the specified one.
634    RevokeEpochs {
635        /// The highest epoch to deprecate.
636        epoch: Epoch,
637    },
638
639    /// View or update the resource control policy
640    ResourceControlPolicy {
641        /// Overrides for individual resource control policy parameters.
642        #[command(flatten)]
643        overrides: ResourceControlPolicyOverrides,
644    },
645
646    /// Run benchmarks to test network performance.
647    #[command(subcommand)]
648    Benchmark(BenchmarkCommand),
649
650    /// Create genesis configuration for a Linera deployment.
651    /// Create initial user chains and print information to be used for initialization of validator setup.
652    /// This will also create an initial wallet for the owner of the initial "root" chains.
653    CreateGenesisConfig {
654        /// Sets the file describing the public configurations of all validators
655        #[arg(long = "committee")]
656        committee_config_path: PathBuf,
657
658        /// The output config path to be consumed by the server
659        #[arg(long = "genesis")]
660        genesis_config_path: PathBuf,
661
662        /// Known initial balance of the chain
663        #[arg(long, default_value = "0")]
664        initial_funding: Amount,
665
666        /// The start timestamp: no blocks can be created before this time.
667        #[arg(long)]
668        start_timestamp: Option<DateTime<Utc>>,
669
670        /// Number of initial (aka "root") chains to create in addition to the admin chain.
671        num_other_initial_chains: u32,
672
673        /// Configure the resource control policy (notably fees) according to pre-defined
674        /// settings.
675        #[arg(long, default_value = "no-fees")]
676        policy_config: ResourceControlPolicyConfig,
677
678        /// Set the price per unit of Wasm fuel.
679        /// (This will overwrite value from `--policy-config`)
680        #[arg(long)]
681        wasm_fuel_unit_price: Option<Amount>,
682
683        /// Set the price per unit of EVM fuel.
684        /// (This will overwrite value from `--policy-config`)
685        #[arg(long)]
686        evm_fuel_unit_price: Option<Amount>,
687
688        /// Set the price per read operation.
689        /// (This will overwrite value from `--policy-config`)
690        #[arg(long)]
691        read_operation_price: Option<Amount>,
692
693        /// Set the price per write operation.
694        /// (This will overwrite value from `--policy-config`)
695        #[arg(long)]
696        write_operation_price: Option<Amount>,
697
698        /// Set the price per byte read from runtime.
699        /// (This will overwrite value from `--policy-config`)
700        #[arg(long)]
701        byte_runtime_price: Option<Amount>,
702
703        /// Set the price per byte read.
704        /// (This will overwrite value from `--policy-config`)
705        #[arg(long)]
706        byte_read_price: Option<Amount>,
707
708        /// Set the price per byte written.
709        /// (This will overwrite value from `--policy-config`)
710        #[arg(long)]
711        byte_written_price: Option<Amount>,
712
713        /// Set the base price to read a blob.
714        /// (This will overwrite value from `--policy-config`)
715        #[arg(long)]
716        blob_read_price: Option<Amount>,
717
718        /// Set the base price to publish a blob.
719        /// (This will overwrite value from `--policy-config`)
720        #[arg(long)]
721        blob_published_price: Option<Amount>,
722
723        /// Set the price to read a blob, per byte.
724        /// (This will overwrite value from `--policy-config`)
725        #[arg(long)]
726        blob_byte_read_price: Option<Amount>,
727
728        /// Set the price to publish a blob, per byte.
729        /// (This will overwrite value from `--policy-config`)
730        #[arg(long)]
731        blob_byte_published_price: Option<Amount>,
732
733        /// Set the base price of sending an operation from a block..
734        /// (This will overwrite value from `--policy-config`)
735        #[arg(long)]
736        operation_price: Option<Amount>,
737
738        /// Set the additional price for each byte in the argument of a user operation.
739        /// (This will overwrite value from `--policy-config`)
740        #[arg(long)]
741        operation_byte_price: Option<Amount>,
742
743        /// Set the base price of sending a message from a block..
744        /// (This will overwrite value from `--policy-config`)
745        #[arg(long)]
746        message_price: Option<Amount>,
747
748        /// Set the additional price for each byte in the argument of a user message.
749        /// (This will overwrite value from `--policy-config`)
750        #[arg(long)]
751        message_byte_price: Option<Amount>,
752
753        /// Set the price per query to a service as an oracle.
754        #[arg(long)]
755        service_as_oracle_query_price: Option<Amount>,
756
757        /// Set the price for performing an HTTP request.
758        #[arg(long)]
759        http_request_price: Option<Amount>,
760
761        /// Set the maximum amount of Wasm fuel per block.
762        /// (This will overwrite value from `--policy-config`)
763        #[arg(long)]
764        maximum_wasm_fuel_per_block: Option<u64>,
765
766        /// Set the maximum amount of EVM fuel per block.
767        /// (This will overwrite value from `--policy-config`)
768        #[arg(long)]
769        maximum_evm_fuel_per_block: Option<u64>,
770
771        /// Set the maximum time in milliseconds that a block can spend executing services as oracles.
772        #[arg(long)]
773        maximum_service_oracle_execution_ms: Option<u64>,
774
775        /// Set the maximum size of a block.
776        /// (This will overwrite value from `--policy-config`)
777        #[arg(long)]
778        maximum_block_size: Option<u64>,
779
780        /// Set the maximum size of decompressed contract or service bytecode, in bytes.
781        /// (This will overwrite value from `--policy-config`)
782        #[arg(long)]
783        maximum_bytecode_size: Option<u64>,
784
785        /// Set the maximum size of data blobs, compressed bytecode and other binary blobs,
786        /// in bytes.
787        /// (This will overwrite value from `--policy-config`)
788        #[arg(long)]
789        maximum_blob_size: Option<u64>,
790
791        /// Set the maximum number of published blobs per block.
792        /// (This will overwrite value from `--policy-config`)
793        #[arg(long)]
794        maximum_published_blobs: Option<u64>,
795
796        /// Set the maximum size of a block proposal, in bytes.
797        /// (This will overwrite value from `--policy-config`)
798        #[arg(long)]
799        maximum_block_proposal_size: Option<u64>,
800
801        /// Set the maximum read data per block.
802        /// (This will overwrite value from `--policy-config`)
803        #[arg(long)]
804        maximum_bytes_read_per_block: Option<u64>,
805
806        /// Set the maximum write data per block.
807        /// (This will overwrite value from `--policy-config`)
808        #[arg(long)]
809        maximum_bytes_written_per_block: Option<u64>,
810
811        /// Set the maximum size of oracle responses.
812        /// (This will overwrite value from `--policy-config`)
813        #[arg(long)]
814        maximum_oracle_response_bytes: Option<u64>,
815
816        /// Set the maximum size in bytes of a received HTTP response.
817        #[arg(long)]
818        maximum_http_response_bytes: Option<u64>,
819
820        /// Set the maximum amount of time allowed to wait for an HTTP response.
821        #[arg(long)]
822        http_request_timeout_ms: Option<u64>,
823
824        /// Set the list of hosts that contracts and services can send HTTP requests to.
825        #[arg(long, value_delimiter = ',')]
826        http_request_allow_list: Option<Vec<String>>,
827
828        /// Set the list of application IDs for which message- and event-related fees are waived.
829        #[arg(long, value_delimiter = ',')]
830        free_application_ids: Option<Vec<String>>,
831
832        /// Set the protocol flags that are enabled.
833        #[arg(long, value_delimiter = ',')]
834        flags: Option<Vec<String>>,
835
836        /// Force this wallet to generate keys using a PRNG and a given seed. USE FOR
837        /// TESTING ONLY.
838        #[arg(long)]
839        testing_prng_seed: Option<u64>,
840
841        /// A unique name to identify this network.
842        #[arg(long)]
843        network_name: Option<String>,
844    },
845
846    /// Watch the network for notifications.
847    Watch {
848        /// The chain ID to watch.
849        chain_id: Option<ChainId>,
850
851        /// Show all notifications from all validators.
852        #[arg(long)]
853        raw: bool,
854    },
855
856    /// Run a GraphQL service to explore and extend the chains of the wallet.
857    Service {
858        /// Configuration for the chain listener backing the service.
859        #[command(flatten)]
860        config: ChainListenerConfig,
861
862        /// The port on which to run the server
863        #[arg(long)]
864        port: NonZeroU16,
865
866        /// The port to expose metrics on.
867        #[cfg(with_metrics)]
868        #[arg(long)]
869        metrics_port: NonZeroU16,
870
871        /// Application IDs of operator applications to watch.
872        /// When specified, a task processor is started alongside the node service.
873        #[arg(long = "operator-application-ids")]
874        operator_application_ids: Vec<ApplicationId>,
875
876        /// A controller to execute a dynamic set of applications running on a dynamic set of
877        /// chains.
878        #[arg(long = "controller-id")]
879        controller_application_id: Option<ApplicationId>,
880
881        /// Supported operators and their binary paths.
882        /// Format: `name=path` or just `name` (uses name as path).
883        /// Example: `--operators my-operator=/path/to/binary`
884        #[arg(long = "operators", value_parser = parse_operator)]
885        operators: Vec<(String, PathBuf)>,
886
887        /// Delay in seconds before retrying a failed operator task batch.
888        /// Only relevant when operators are configured via `--operator-application-ids`
889        /// or `--controller-id`.
890        #[arg(long, default_value = "5")]
891        task_retry_delay_secs: u64,
892
893        /// Number of seconds after which a still-running operator task group is logged and
894        /// counted as slow. The group is not interrupted and runs to completion.
895        /// Only relevant when operators are configured via `--operator-application-ids`
896        /// or `--controller-id`.
897        #[arg(long, default_value = "300")]
898        slow_task_group_secs: u64,
899
900        /// Run in read-only mode: disallow mutations and prevent queries from scheduling
901        /// operations. Use this when exposing the service to untrusted clients.
902        #[arg(long)]
903        read_only: bool,
904
905        /// Enable the application query response cache with the given per-chain capacity.
906        /// Each entry stores a serialized GraphQL response keyed by
907        /// (application_id, request_bytes). Incompatible with `--long-lived-services`.
908        #[arg(long, env = "LINERA_QUERY_CACHE_SIZE")]
909        query_cache_size: Option<usize>,
910
911        /// Allow a named GraphQL subscription query.
912        /// The operation name is extracted from the query string.
913        /// Repeatable.
914        /// Example: `--allow-subscription 'query CounterValue { getCounter { value } }'`
915        #[arg(long = "allow-subscription")]
916        allowed_subscriptions: Vec<String>,
917
918        /// Set a minimum TTL (in seconds) for a subscription query's cached result.
919        /// When set, invalidations that arrive before the TTL expires are deferred
920        /// until the remaining time elapses. Format: `Name=Secs`.
921        /// Repeatable.
922        /// Example: `--subscription-ttl-secs CounterValue=30`
923        #[arg(long = "subscription-ttl-secs", value_parser = parse_subscription_ttl)]
924        subscription_ttls: Vec<(String, u64)>,
925
926        /// Start in paused mode: do not synchronize chains from the network.
927        /// The service will serve queries from local state only, without downloading
928        /// new blocks or processing incoming messages.
929        #[arg(long)]
930        pause: bool,
931    },
932
933    /// Query an application with a read-only GraphQL query.
934    QueryApplication {
935        /// The chain on which the application is running.
936        #[arg(long)]
937        chain_id: Option<ChainId>,
938
939        /// The application to query.
940        #[arg(long)]
941        application_id: ApplicationId,
942
943        /// The GraphQL query to send (e.g. "value" for a counter application).
944        query: String,
945    },
946
947    /// Run a GraphQL service that exposes a faucet where users can claim tokens.
948    /// This gives away the chain's tokens, and is mainly intended for testing.
949    Faucet {
950        /// The chain that gives away its tokens.
951        chain_id: Option<ChainId>,
952
953        /// The port on which to run the server
954        #[arg(long, default_value = "8080")]
955        port: u16,
956
957        /// The port for prometheus to scrape.
958        #[cfg(with_metrics)]
959        #[arg(long, default_value = "9090")]
960        metrics_port: u16,
961
962        /// The number of tokens to send to each new chain.
963        #[arg(long)]
964        amount: Amount,
965
966        /// The number of tokens to send per daily claim. Set to 0 to disable daily claims.
967        #[arg(long, default_value = "0")]
968        daily_claim_amount: Amount,
969
970        /// The end timestamp: The faucet will rate-limit the token supply so it runs out of money
971        /// no earlier than this.
972        #[arg(long)]
973        limit_rate_until: Option<DateTime<Utc>>,
974
975        /// Configuration for the faucet chain listener.
976        #[command(flatten)]
977        config: ChainListenerConfig,
978
979        /// Path to the persistent storage file for faucet mappings.
980        #[arg(long)]
981        storage_path: PathBuf,
982
983        /// Maximum number of operations to include in a single block (default: 100).
984        #[arg(long, default_value = "100")]
985        max_batch_size: usize,
986    },
987
988    /// Publish module.
989    PublishModule {
990        /// Path to the Wasm file for the application "contract" bytecode.
991        contract: PathBuf,
992
993        /// Path to the Wasm file for the application "service" bytecode.
994        service: PathBuf,
995
996        /// The virtual machine runtime to use.
997        #[arg(long, default_value = "wasm")]
998        vm_runtime: VmRuntime,
999
1000        /// Optional path to an insta SNAP file containing the YAML serialization
1001        /// of the application's `Formats`. When provided, the formats are
1002        /// BCS-encoded and published as a third blob alongside the contract
1003        /// and service blobs; the resulting `ModuleId` carries the formats blob
1004        /// hash.
1005        #[arg(long)]
1006        formats: Option<PathBuf>,
1007
1008        /// An optional chain ID to publish the module. The default chain of the wallet
1009        /// is used otherwise.
1010        publisher: Option<ChainId>,
1011    },
1012
1013    /// Print events from a specific chain and stream from a specified index.
1014    ListEventsFromIndex {
1015        /// The chain to query. If omitted, query the default chain of the wallet.
1016        chain_id: Option<ChainId>,
1017
1018        /// The stream being considered.
1019        #[arg(long)]
1020        stream_id: StreamId,
1021
1022        /// Index of the message to start with
1023        #[arg(long, default_value = "0")]
1024        start_index: u32,
1025    },
1026
1027    /// Publish a data blob of binary data.
1028    PublishDataBlob {
1029        /// Path to data blob file to be published.
1030        blob_path: PathBuf,
1031        /// An optional chain ID to publish the blob. The default chain of the wallet
1032        /// is used otherwise.
1033        publisher: Option<ChainId>,
1034    },
1035
1036    // TODO(#2490): Consider removing or renaming this.
1037    /// Verify that a data blob is readable.
1038    ReadDataBlob {
1039        /// The hash of the content.
1040        hash: CryptoHash,
1041        /// An optional chain ID to verify the blob. The default chain of the wallet
1042        /// is used otherwise.
1043        reader: Option<ChainId>,
1044    },
1045
1046    /// Describe an existing application: print its `ApplicationDescription` (module
1047    /// ID, creator chain, parameters and required dependencies) as JSON. The
1048    /// description is content-addressed and fetched from the validators, so the
1049    /// application need not be registered on the wallet's default chain.
1050    DescribeApplication {
1051        /// The ID of the application to describe.
1052        application_id: ApplicationId,
1053    },
1054
1055    /// Create an application.
1056    CreateApplication {
1057        /// The module ID of the application to create.
1058        module_id: ModuleId,
1059
1060        /// An optional chain ID to host the application. The default chain of the wallet
1061        /// is used otherwise.
1062        creator: Option<ChainId>,
1063
1064        /// The shared parameters as JSON string.
1065        #[arg(long)]
1066        json_parameters: Option<String>,
1067
1068        /// Path to a JSON file containing the shared parameters.
1069        #[arg(long)]
1070        json_parameters_path: Option<PathBuf>,
1071
1072        /// The instantiation argument as a JSON string.
1073        #[arg(long)]
1074        json_argument: Option<String>,
1075
1076        /// Path to a JSON file containing the instantiation argument.
1077        #[arg(long)]
1078        json_argument_path: Option<PathBuf>,
1079
1080        /// The list of required dependencies of application, if any.
1081        #[arg(long, num_args(0..))]
1082        required_application_ids: Option<Vec<ApplicationId>>,
1083    },
1084
1085    /// Create an application, and publish the required module.
1086    PublishAndCreate {
1087        /// Path to the Wasm file for the application "contract" bytecode.
1088        contract: PathBuf,
1089
1090        /// Path to the Wasm file for the application "service" bytecode.
1091        service: PathBuf,
1092
1093        /// The virtual machine runtime to use.
1094        #[arg(long, default_value = "wasm")]
1095        vm_runtime: VmRuntime,
1096
1097        /// An optional chain ID to publish the module. The default chain of the wallet
1098        /// is used otherwise.
1099        publisher: Option<ChainId>,
1100
1101        /// The shared parameters as JSON string.
1102        #[arg(long)]
1103        json_parameters: Option<String>,
1104
1105        /// Path to a JSON file containing the shared parameters.
1106        #[arg(long)]
1107        json_parameters_path: Option<PathBuf>,
1108
1109        /// The instantiation argument as a JSON string.
1110        #[arg(long)]
1111        json_argument: Option<String>,
1112
1113        /// Path to a JSON file containing the instantiation argument.
1114        #[arg(long)]
1115        json_argument_path: Option<PathBuf>,
1116
1117        /// The list of required dependencies of application, if any.
1118        #[arg(long, num_args(0..))]
1119        required_application_ids: Option<Vec<ApplicationId>>,
1120    },
1121
1122    /// Create an unassigned key pair.
1123    Keygen,
1124
1125    /// Link the owner to the chain.
1126    /// Expects that the caller has a private key corresponding to the `public_key`,
1127    /// otherwise block proposals will fail when signing with it.
1128    Assign {
1129        /// The owner to assign.
1130        #[arg(long)]
1131        owner: AccountOwner,
1132
1133        /// The ID of the chain.
1134        #[arg(long)]
1135        chain_id: ChainId,
1136    },
1137
1138    /// Retry a block we unsuccessfully tried to propose earlier.
1139    ///
1140    /// As long as a block is pending most other commands will fail, since it is unsafe to propose
1141    /// multiple blocks at the same height.
1142    RetryPendingBlock {
1143        /// The chain with the pending block. If not specified, the wallet's default chain is used.
1144        chain_id: Option<ChainId>,
1145    },
1146
1147    /// Execute a raw user operation on an application.
1148    ///
1149    /// The operation bytes are provided as a hex string (BCS-encoded).
1150    ExecuteOperation {
1151        /// The application to send the operation to.
1152        #[arg(long)]
1153        application_id: ApplicationId,
1154
1155        /// BCS-encoded operation bytes as a hex string.
1156        #[arg(long)]
1157        operation: String,
1158
1159        /// Chain ID to submit the operation on. Defaults to the wallet's default chain.
1160        #[arg(long)]
1161        chain_id: Option<ChainId>,
1162    },
1163
1164    /// Show the contents of the wallet.
1165    #[command(subcommand)]
1166    Wallet(WalletCommand),
1167
1168    /// Show the information about a chain.
1169    #[command(subcommand)]
1170    Chain(ChainCommand),
1171
1172    /// Manage Linera projects.
1173    #[command(subcommand)]
1174    Project(ProjectCommand),
1175
1176    /// Manage a local Linera Network.
1177    #[command(subcommand)]
1178    Net(NetCommand),
1179
1180    /// Manage validators in the committee.
1181    #[command(subcommand)]
1182    Validator(validator::Command),
1183
1184    /// Operation on the storage.
1185    #[command(subcommand)]
1186    Storage(DatabaseToolCommand),
1187
1188    /// Print CLI help in Markdown format, and exit.
1189    #[command(hide = true)]
1190    HelpMarkdown,
1191
1192    /// Extract a Bash and GraphQL script embedded in a markdown file and print it on
1193    /// `stdout`.
1194    #[command(hide = true)]
1195    ExtractScriptFromMarkdown {
1196        /// The source file
1197        path: PathBuf,
1198
1199        /// Insert a pause of N seconds after calls to `linera service`.
1200        #[arg(long, default_value = DEFAULT_PAUSE_AFTER_LINERA_SERVICE_SECS, value_parser = util::parse_secs)]
1201        pause_after_linera_service: Duration,
1202
1203        /// Insert a pause of N seconds after GraphQL queries.
1204        #[arg(long, default_value = DEFAULT_PAUSE_AFTER_GQL_MUTATIONS_SECS, value_parser = util::parse_secs)]
1205        pause_after_gql_mutations: Duration,
1206    },
1207
1208    /// Generate shell completion scripts
1209    Completion {
1210        /// The shell to generate completions for
1211        #[arg(value_enum)]
1212        shell: clap_complete::Shell,
1213    },
1214}
1215
1216impl ClientCommand {
1217    /// Returns the log file name to use based on the [`ClientCommand`] that will run.
1218    pub fn log_file_name(&self) -> Cow<'static, str> {
1219        match self {
1220            ClientCommand::Transfer { .. }
1221            | ClientCommand::OpenChain { .. }
1222            | ClientCommand::OpenMultiOwnerChain { .. }
1223            | ClientCommand::ShowOwnership { .. }
1224            | ClientCommand::ChangeOwnership { .. }
1225            | ClientCommand::SetPreferredOwner { .. }
1226            | ClientCommand::ChangeApplicationPermissions { .. }
1227            | ClientCommand::CloseChain { .. }
1228            | ClientCommand::Checkpoint { .. }
1229            | ClientCommand::ShowNetworkDescription
1230            | ClientCommand::LocalBalance { .. }
1231            | ClientCommand::QueryBalance { .. }
1232            | ClientCommand::SyncBalance { .. }
1233            | ClientCommand::Sync { .. }
1234            | ClientCommand::ProcessInbox { .. }
1235            | ClientCommand::QueryShardInfo { .. }
1236            | ClientCommand::ResourceControlPolicy { .. }
1237            | ClientCommand::RevokeEpochs { .. }
1238            | ClientCommand::CreateGenesisConfig { .. }
1239            | ClientCommand::PublishModule { .. }
1240            | ClientCommand::ListEventsFromIndex { .. }
1241            | ClientCommand::PublishDataBlob { .. }
1242            | ClientCommand::ReadDataBlob { .. }
1243            | ClientCommand::DescribeApplication { .. }
1244            | ClientCommand::CreateApplication { .. }
1245            | ClientCommand::PublishAndCreate { .. }
1246            | ClientCommand::Keygen
1247            | ClientCommand::Assign { .. }
1248            | ClientCommand::Wallet { .. }
1249            | ClientCommand::Chain { .. }
1250            | ClientCommand::Validator { .. }
1251            | ClientCommand::RetryPendingBlock { .. }
1252            | ClientCommand::QueryApplication { .. } => "client".into(),
1253            ClientCommand::ExecuteOperation { .. } => "client".into(),
1254            ClientCommand::Benchmark(BenchmarkCommand::Single { .. }) => "single-benchmark".into(),
1255            ClientCommand::Benchmark(BenchmarkCommand::Multi { .. }) => "multi-benchmark".into(),
1256            ClientCommand::Net { .. } => "net".into(),
1257            ClientCommand::Project { .. } => "project".into(),
1258            ClientCommand::Watch { .. } => "watch".into(),
1259            ClientCommand::Storage { .. } => "storage".into(),
1260            ClientCommand::Service { port, .. } => format!("service-{port}").into(),
1261            ClientCommand::Faucet { .. } => "faucet".into(),
1262            ClientCommand::HelpMarkdown
1263            | ClientCommand::ExtractScriptFromMarkdown { .. }
1264            | ClientCommand::Completion { .. } => "tool".into(),
1265        }
1266    }
1267}
1268
1269#[derive(Clone, clap::Parser)]
1270/// The subcommands for managing the storage database.
1271pub enum DatabaseToolCommand {
1272    /// Delete all the namespaces in the database
1273    DeleteAll,
1274
1275    /// Delete a single namespace from the database
1276    DeleteNamespace,
1277
1278    /// Check existence of a namespace in the database
1279    CheckExistence,
1280
1281    /// Initialize a namespace in the database
1282    Initialize {
1283        /// The path to the genesis configuration file.
1284        #[arg(long = "genesis")]
1285        genesis_config_path: PathBuf,
1286    },
1287
1288    /// List the namespaces in the database
1289    ListNamespaces,
1290
1291    /// List the blob IDs in the database
1292    ListBlobIds,
1293
1294    /// List the chain IDs in the database
1295    ListChainIds,
1296
1297    /// List the event IDs in the database
1298    ListEventIds,
1299}
1300
1301#[expect(clippy::large_enum_variant)]
1302#[derive(Clone, clap::Parser)]
1303/// The subcommands for managing a local Linera network.
1304pub enum NetCommand {
1305    /// Start a Local Linera Network
1306    Up {
1307        /// The number of initial "root" chains created in the genesis config on top of
1308        /// the default "admin" chain. All initial chains belong to the first "admin"
1309        /// wallet. It is recommended to use at least one other initial chain for the
1310        /// faucet.
1311        #[arg(long, default_value = "2")]
1312        other_initial_chains: u32,
1313
1314        /// The initial amount of native tokens credited in the initial "root" chains,
1315        /// including the default "admin" chain.
1316        #[arg(long, default_value = "1000000")]
1317        initial_amount: u128,
1318
1319        /// The number of validators in the local test network.
1320        #[arg(long, default_value = "1")]
1321        validators: usize,
1322
1323        /// The number of proxies in the local test network.
1324        #[arg(long, default_value = "1")]
1325        proxies: usize,
1326
1327        /// The number of shards per validator in the local test network.
1328        #[arg(long, default_value = "1")]
1329        shards: usize,
1330
1331        /// Configure the resource control policy (notably fees) according to pre-defined
1332        /// settings.
1333        #[arg(long, default_value = "no-fees")]
1334        policy_config: ResourceControlPolicyConfig,
1335
1336        /// The configuration for cross-chain messages.
1337        #[clap(flatten)]
1338        cross_chain_config: CrossChainConfig,
1339
1340        /// Force this wallet to generate keys using a PRNG and a given seed. USE FOR
1341        /// TESTING ONLY.
1342        #[arg(long)]
1343        testing_prng_seed: Option<u64>,
1344
1345        /// Run with a specific path where the wallet and validator input files are.
1346        /// If none, then a temporary directory is created.
1347        #[arg(long)]
1348        path: Option<String>,
1349
1350        /// External protocol used, either `grpc` or `grpcs`.
1351        #[arg(long, default_value = "grpc")]
1352        external_protocol: String,
1353
1354        /// If present, a faucet is started on a dedicated chain with its own wallet.
1355        #[arg(long, default_value = "false")]
1356        with_faucet: bool,
1357
1358        /// The port on which to run the faucet server
1359        #[arg(long, default_value = "8080")]
1360        faucet_port: NonZeroU16,
1361
1362        /// The number of tokens to send to each new chain created by the faucet.
1363        #[arg(long, default_value = "1000")]
1364        faucet_amount: Amount,
1365
1366        /// Whether to start a block exporter for each validator.
1367        #[arg(long, default_value = "false")]
1368        with_block_exporter: bool,
1369
1370        /// The number of block exporters to start.
1371        #[arg(long, default_value = "1")]
1372        num_block_exporters: usize,
1373
1374        /// The address of the block exporter.
1375        #[arg(long, default_value = "localhost")]
1376        exporter_address: String,
1377
1378        /// The port on which to run the block exporter.
1379        #[arg(long, default_value = "8081")]
1380        exporter_port: NonZeroU16,
1381
1382        /// Set the list of hosts that contracts and services can send HTTP requests to.
1383        #[arg(long, value_delimiter = ',')]
1384        http_request_allow_list: Option<Vec<String>>,
1385    },
1386
1387    /// Print a bash helper script to make `linera net up` easier to use. The script is
1388    /// meant to be installed in `~/.bash_profile` or sourced when needed.
1389    Helper,
1390}
1391
1392#[derive(Clone, clap::Subcommand)]
1393/// The subcommands for managing the wallet.
1394pub enum WalletCommand {
1395    /// Show the contents of the wallet.
1396    Show {
1397        /// The chain to show the metadata.
1398        chain_id: Option<ChainId>,
1399        /// Only print a non-formatted list of the wallet's chain IDs.
1400        #[arg(long)]
1401        short: bool,
1402        /// Print only the chains that we have a key pair for.
1403        #[arg(long)]
1404        owned: bool,
1405    },
1406
1407    /// Change the wallet default chain.
1408    SetDefault {
1409        /// The chain to set as the default.
1410        chain_id: ChainId,
1411    },
1412
1413    /// Initialize a wallet from the genesis configuration.
1414    Init {
1415        /// The path to the genesis configuration for a Linera deployment. Either this or `--faucet`
1416        /// must be specified.
1417        ///
1418        /// Overrides `--faucet` if provided.
1419        #[arg(long = "genesis")]
1420        genesis_config_path: Option<PathBuf>,
1421
1422        /// The address of a faucet.
1423        #[arg(long, env = "LINERA_FAUCET_URL")]
1424        faucet: Option<String>,
1425
1426        /// Force this wallet to generate keys using a PRNG and a given seed. USE FOR
1427        /// TESTING ONLY.
1428        #[arg(long)]
1429        testing_prng_seed: Option<u64>,
1430    },
1431
1432    /// Request a new chain from a faucet and add it to the wallet.
1433    RequestChain {
1434        /// The address of a faucet.
1435        #[arg(long, env = "LINERA_FAUCET_URL")]
1436        faucet: String,
1437
1438        /// Whether this chain should become the default chain.
1439        #[arg(long)]
1440        set_default: bool,
1441
1442        /// Whether to credit the claimed tokens to the new owner's account rather than to the
1443        /// chain account. Only blocks authenticated by that owner can then pay fees.
1444        #[arg(long)]
1445        fund_owner_account: bool,
1446    },
1447
1448    /// Export the genesis configuration to a JSON file.
1449    ///
1450    /// By default, exports the genesis config from the current wallet. Alternatively,
1451    /// use `--faucet` to retrieve the genesis config directly from a faucet URL.
1452    ExportGenesis {
1453        /// Path to save the genesis configuration JSON file.
1454        output: PathBuf,
1455
1456        /// The address of a faucet to retrieve the genesis config from.
1457        /// If not specified, the genesis config is read from the current wallet.
1458        #[arg(long)]
1459        faucet: Option<String>,
1460    },
1461
1462    /// Add a new followed chain (i.e. a chain without keypair) to the wallet.
1463    FollowChain {
1464        /// The chain ID.
1465        chain_id: ChainId,
1466        /// Synchronize the new chain and download all its blocks from the validators.
1467        #[arg(long)]
1468        sync: bool,
1469    },
1470
1471    /// Forgets the specified chain's keys. The chain will still be followed by the
1472    /// wallet.
1473    ForgetKeys {
1474        /// The chain whose keys will be forgotten.
1475        chain_id: ChainId,
1476    },
1477
1478    /// Forgets the specified chain, including the associated key pair. The default
1479    /// chain cannot be forgotten; switch to another chain with `set-default` first.
1480    ForgetChain {
1481        /// The chain to forget.
1482        chain_id: ChainId,
1483    },
1484}
1485
1486#[derive(Clone, clap::Subcommand)]
1487/// The subcommands for inspecting chains.
1488pub enum ChainCommand {
1489    /// Show the contents of a block.
1490    ShowBlock {
1491        /// The height of the block.
1492        height: BlockHeight,
1493        /// The chain to show the block (if not specified, the default chain from the
1494        /// wallet is used).
1495        chain_id: Option<ChainId>,
1496    },
1497
1498    /// Show the chain description of a chain.
1499    ShowChainDescription {
1500        /// The chain ID to show (if not specified, the default chain from the wallet is
1501        /// used).
1502        chain_id: Option<ChainId>,
1503    },
1504}
1505
1506#[derive(Clone, clap::Parser)]
1507/// The subcommands for managing Linera projects.
1508pub enum ProjectCommand {
1509    /// Create a new Linera project.
1510    New {
1511        /// The project name. A directory of the same name will be created in the current directory.
1512        name: String,
1513
1514        /// Use the given clone of the Linera repository instead of remote crates.
1515        #[arg(long)]
1516        linera_root: Option<PathBuf>,
1517
1518        /// Use the given directory for the project instead of creating a new one.
1519        /// The directory will be created if it doesn't exist.
1520        #[arg(long)]
1521        dir: Option<PathBuf>,
1522    },
1523
1524    /// Test a Linera project.
1525    ///
1526    /// Equivalent to running `cargo test` with the appropriate test runner.
1527    Test {
1528        /// The path of the root of the Linera project to test.
1529        path: Option<PathBuf>,
1530    },
1531
1532    /// Build and publish a Linera project.
1533    PublishAndCreate {
1534        /// The path of the root of the Linera project.
1535        /// Defaults to current working directory if unspecified.
1536        path: Option<PathBuf>,
1537
1538        /// Specify the name of the Linera project.
1539        /// This is used to locate the generated bytecode files. The generated bytecode files should
1540        /// be of the form `<name>_{contract,service}.wasm`.
1541        ///
1542        /// Defaults to the package name in Cargo.toml, with dashes replaced by
1543        /// underscores.
1544        name: Option<String>,
1545
1546        /// An optional chain ID to publish the module. The default chain of the wallet
1547        /// is used otherwise.
1548        publisher: Option<ChainId>,
1549
1550        /// The virtual machine runtime to use.
1551        #[arg(long, default_value = "wasm")]
1552        vm_runtime: VmRuntime,
1553
1554        /// The shared parameters as JSON string.
1555        #[arg(long)]
1556        json_parameters: Option<String>,
1557
1558        /// Path to a JSON file containing the shared parameters.
1559        #[arg(long)]
1560        json_parameters_path: Option<PathBuf>,
1561
1562        /// The instantiation argument as a JSON string.
1563        #[arg(long)]
1564        json_argument: Option<String>,
1565
1566        /// Path to a JSON file containing the instantiation argument.
1567        #[arg(long)]
1568        json_argument_path: Option<PathBuf>,
1569
1570        /// The list of required dependencies of application, if any.
1571        #[arg(long, num_args(0..))]
1572        required_application_ids: Option<Vec<ApplicationId>>,
1573    },
1574}