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