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