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, Epoch},
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#[cfg(feature = "benchmark")]
23use serde::Serialize;
24
25#[cfg(feature = "benchmark")]
26const DEFAULT_NUM_CHAINS: usize = 10;
27#[cfg(feature = "benchmark")]
28const DEFAULT_TOKENS_PER_CHAIN: Amount = Amount::from_millis(100);
29#[cfg(feature = "benchmark")]
30const DEFAULT_TRANSACTIONS_PER_BLOCK: usize = 1;
31#[cfg(feature = "benchmark")]
32const DEFAULT_WRAP_UP_MAX_IN_FLIGHT: usize = 5;
33
34// Make sure that the default values are consts, and that they are used in the Default impl.
35#[cfg(feature = "benchmark")]
36#[derive(Clone, Serialize, clap::Args)]
37#[serde(rename_all = "kebab-case")]
38pub struct BenchmarkCommand {
39 /// How many chains to use for the benchmark
40 #[arg(long, default_value_t = DEFAULT_NUM_CHAINS)]
41 pub num_chains: usize,
42
43 /// How many tokens to assign to each newly created chain.
44 /// These need to cover the transaction fees per chain for the benchmark.
45 #[arg(long, default_value_t = DEFAULT_TOKENS_PER_CHAIN)]
46 pub tokens_per_chain: Amount,
47
48 /// How many transactions to put in each block.
49 #[arg(long, default_value_t = DEFAULT_TRANSACTIONS_PER_BLOCK)]
50 pub transactions_per_block: usize,
51
52 /// The application ID of a fungible token on the wallet's default chain.
53 /// If none is specified, the benchmark uses the native token.
54 #[arg(long)]
55 pub fungible_application_id: Option<linera_base::identifiers::ApplicationId>,
56
57 /// If provided, will be long running, and block proposals will be sent at the
58 /// provided fixed BPS rate.
59 #[arg(long)]
60 pub bps: Option<usize>,
61
62 /// If provided, will close the chains after the benchmark is finished. Keep in mind that
63 /// closing the chains might take a while, and will increase the validator latency while
64 /// they're being closed.
65 #[arg(long)]
66 pub close_chains: bool,
67 /// A comma-separated list of host:port pairs to query for health metrics.
68 /// If provided, the benchmark will check these endpoints for validator health
69 /// and terminate if any validator is unhealthy.
70 /// Example: "127.0.0.1:21100,validator-1.some-network.linera.net:21100"
71 #[arg(long)]
72 pub health_check_endpoints: Option<String>,
73 /// The maximum number of in-flight requests to validators when wrapping up the benchmark.
74 /// While wrapping up, this controls the concurrency level when processing inboxes and
75 /// closing chains.
76 #[arg(long, default_value_t = DEFAULT_WRAP_UP_MAX_IN_FLIGHT)]
77 pub wrap_up_max_in_flight: usize,
78
79 /// Confirm before starting the benchmark.
80 #[arg(long)]
81 pub confirm_before_start: bool,
82}
83
84#[cfg(feature = "benchmark")]
85impl Default for BenchmarkCommand {
86 fn default() -> Self {
87 Self {
88 num_chains: DEFAULT_NUM_CHAINS,
89 tokens_per_chain: DEFAULT_TOKENS_PER_CHAIN,
90 transactions_per_block: DEFAULT_TRANSACTIONS_PER_BLOCK,
91 wrap_up_max_in_flight: DEFAULT_WRAP_UP_MAX_IN_FLIGHT,
92 fungible_application_id: None,
93 bps: None,
94 close_chains: false,
95 health_check_endpoints: None,
96 confirm_before_start: false,
97 }
98 }
99}
100
101#[cfg(feature = "kubernetes")]
102use crate::cli_wrappers::local_kubernetes_net::BuildMode;
103use crate::util::{
104 DEFAULT_PAUSE_AFTER_GQL_MUTATIONS_SECS, DEFAULT_PAUSE_AFTER_LINERA_SERVICE_SECS,
105};
106
107#[derive(Clone, clap::Subcommand)]
108pub enum ClientCommand {
109 /// Transfer funds
110 Transfer {
111 /// Sending chain ID (must be one of our chains)
112 #[arg(long = "from")]
113 sender: Account,
114
115 /// Recipient account
116 #[arg(long = "to")]
117 recipient: Account,
118
119 /// Amount to transfer
120 amount: Amount,
121 },
122
123 /// Open (i.e. activate) a new chain deriving the UID from an existing one.
124 OpenChain {
125 /// Chain ID (must be one of our chains).
126 #[arg(long = "from")]
127 chain_id: Option<ChainId>,
128
129 /// The new owner (otherwise create a key pair and remember it)
130 #[arg(long = "owner")]
131 owner: Option<AccountOwner>,
132
133 /// The initial balance of the new chain. This is subtracted from the parent chain's
134 /// balance.
135 #[arg(long = "initial-balance", default_value = "0")]
136 balance: Amount,
137 },
138
139 /// Open (i.e. activate) a new multi-owner chain deriving the UID from an existing one.
140 OpenMultiOwnerChain {
141 /// Chain ID (must be one of our chains).
142 #[arg(long = "from")]
143 chain_id: Option<ChainId>,
144
145 #[clap(flatten)]
146 ownership_config: ChainOwnershipConfig,
147
148 #[clap(flatten)]
149 application_permissions_config: ApplicationPermissionsConfig,
150
151 /// The initial balance of the new chain. This is subtracted from the parent chain's
152 /// balance.
153 #[arg(long = "initial-balance", default_value = "0")]
154 balance: Amount,
155 },
156
157 /// Change who owns the chain, and how the owners work together proposing blocks.
158 ///
159 /// Specify the complete set of new owners, by public key. Existing owners that are
160 /// not included will be removed.
161 ChangeOwnership {
162 /// The ID of the chain whose owners will be changed.
163 #[clap(long)]
164 chain_id: Option<ChainId>,
165
166 #[clap(flatten)]
167 ownership_config: ChainOwnershipConfig,
168 },
169
170 /// Change the preferred owner of a chain.
171 SetPreferredOwner {
172 /// The ID of the chain whose preferred owner will be changed.
173 #[clap(long)]
174 chain_id: Option<ChainId>,
175
176 /// The new preferred owner.
177 #[arg(long)]
178 owner: AccountOwner,
179 },
180
181 /// Changes the application permissions configuration.
182 ChangeApplicationPermissions {
183 /// The ID of the chain to which the new permissions will be applied.
184 #[arg(long)]
185 chain_id: Option<ChainId>,
186
187 #[clap(flatten)]
188 application_permissions_config: ApplicationPermissionsConfig,
189 },
190
191 /// Close an existing chain.
192 ///
193 /// A closed chain cannot execute operations or accept messages anymore.
194 /// It can still reject incoming messages, so they bounce back to the sender.
195 CloseChain {
196 /// Chain ID (must be one of our chains)
197 chain_id: ChainId,
198 },
199
200 /// Read the current native-token balance of the given account directly from the local
201 /// state.
202 ///
203 /// NOTE: The local balance does not reflect messages that are waiting to be picked in
204 /// the local inbox, or that have not been synchronized from validators yet. Use
205 /// `linera sync` then either `linera query-balance` or `linera process-inbox &&
206 /// linera local-balance` for a consolidated balance.
207 LocalBalance {
208 /// The account to read, written as `CHAIN-ID:OWNER` or simply `CHAIN-ID` for the
209 /// chain balance. By default, we read the chain balance of the default chain in
210 /// the wallet.
211 account: Option<Account>,
212 },
213
214 /// Simulate the execution of one block made of pending messages from the local inbox,
215 /// then read the native-token balance of the account from the local state.
216 ///
217 /// NOTE: The balance does not reflect messages that have not been synchronized from
218 /// validators yet. Call `linera sync` first to do so.
219 QueryBalance {
220 /// The account to query, written as `CHAIN-ID:OWNER` or simply `CHAIN-ID` for the
221 /// chain balance. By default, we read the chain balance of the default chain in
222 /// the wallet.
223 account: Option<Account>,
224 },
225
226 /// (DEPRECATED) Synchronize the local state of the chain with a quorum validators, then query the
227 /// local balance.
228 ///
229 /// This command is deprecated. Use `linera sync && linera query-balance` instead.
230 SyncBalance {
231 /// The account to query, written as `CHAIN-ID:OWNER` or simply `CHAIN-ID` for the
232 /// chain balance. By default, we read the chain balance of the default chain in
233 /// the wallet.
234 account: Option<Account>,
235 },
236
237 /// Synchronize the local state of the chain with a quorum validators.
238 Sync {
239 /// The chain to synchronize with validators. If omitted, synchronizes the
240 /// default chain of the wallet.
241 chain_id: Option<ChainId>,
242 },
243
244 /// Process all pending incoming messages from the inbox of the given chain by creating as many
245 /// blocks as needed to execute all (non-failing) messages. Failing messages will be
246 /// marked as rejected and may bounce to their sender depending on their configuration.
247 ProcessInbox {
248 /// The chain to process. If omitted, uses the default chain of the wallet.
249 chain_id: Option<ChainId>,
250 },
251
252 /// Show the version and genesis config hash of a new validator, and print a warning if it is
253 /// incompatible. Also print some information about the given chain while we are at it.
254 QueryValidator {
255 /// The new validator's address.
256 address: String,
257 /// The chain to query. If omitted, query the default chain of the wallet.
258 chain_id: Option<ChainId>,
259 /// The public key of the validator. If given, the signature of the chain query
260 /// info will be checked.
261 #[arg(long)]
262 public_key: Option<ValidatorPublicKey>,
263 },
264
265 /// Show the current set of validators for a chain. Also print some information about
266 /// the given chain while we are at it.
267 QueryValidators {
268 /// The chain to query. If omitted, query the default chain of the wallet.
269 chain_id: Option<ChainId>,
270 },
271
272 /// Synchronizes a validator with the local state of chains.
273 SyncValidator {
274 /// The public address of the validator to synchronize.
275 address: String,
276
277 /// The chains to synchronize, or the default chain if empty.
278 #[arg(long, num_args = 0..)]
279 chains: Vec<ChainId>,
280 },
281
282 /// Add or modify a validator (admin only)
283 SetValidator {
284 /// The public key of the validator.
285 #[arg(long)]
286 public_key: ValidatorPublicKey,
287
288 /// The public key of the account controlled by the validator.
289 #[arg(long)]
290 account_key: AccountPublicKey,
291
292 /// Network address
293 #[arg(long)]
294 address: String,
295
296 /// Voting power
297 #[arg(long, default_value = "1")]
298 votes: u64,
299
300 /// Skip the version and genesis config checks.
301 #[arg(long)]
302 skip_online_check: bool,
303 },
304
305 /// Remove a validator (admin only)
306 RemoveValidator {
307 /// The public key of the validator.
308 #[arg(long)]
309 public_key: ValidatorPublicKey,
310 },
311
312 /// Deprecates all committees up to and including the specified one.
313 RevokeEpochs { epoch: Epoch },
314
315 /// View or update the resource control policy
316 ResourceControlPolicy {
317 /// Set the price per unit of Wasm fuel.
318 #[arg(long)]
319 wasm_fuel_unit: Option<Amount>,
320
321 /// Set the price per unit of EVM fuel.
322 #[arg(long)]
323 evm_fuel_unit: Option<Amount>,
324
325 /// Set the price per read operation.
326 #[arg(long)]
327 read_operation: Option<Amount>,
328
329 /// Set the price per write operation.
330 #[arg(long)]
331 write_operation: Option<Amount>,
332
333 /// Set the price per byte read.
334 #[arg(long)]
335 byte_read: Option<Amount>,
336
337 /// Set the price per byte written.
338 #[arg(long)]
339 byte_written: Option<Amount>,
340
341 /// Set the base price to read a blob.
342 #[arg(long)]
343 blob_read: Option<Amount>,
344
345 /// Set the base price to publish a blob.
346 #[arg(long)]
347 blob_published: Option<Amount>,
348
349 /// Set the price to read a blob, per byte.
350 #[arg(long)]
351 blob_byte_read: Option<Amount>,
352
353 /// The price to publish a blob, per byte.
354 #[arg(long)]
355 blob_byte_published: Option<Amount>,
356
357 /// Set the price per byte stored.
358 #[arg(long)]
359 byte_stored: Option<Amount>,
360
361 /// Set the base price of sending an operation from a block..
362 #[arg(long)]
363 operation: Option<Amount>,
364
365 /// Set the additional price for each byte in the argument of a user operation.
366 #[arg(long)]
367 operation_byte: Option<Amount>,
368
369 /// Set the base price of sending a message from a block..
370 #[arg(long)]
371 message: Option<Amount>,
372
373 /// Set the additional price for each byte in the argument of a user message.
374 #[arg(long)]
375 message_byte: Option<Amount>,
376
377 /// Set the price per query to a service as an oracle.
378 #[arg(long)]
379 service_as_oracle_query: Option<Amount>,
380
381 /// Set the price for performing an HTTP request.
382 #[arg(long)]
383 http_request: Option<Amount>,
384
385 /// Set the maximum amount of Wasm fuel per block.
386 #[arg(long)]
387 maximum_wasm_fuel_per_block: Option<u64>,
388
389 /// Set the maximum amount of EVM fuel per block.
390 #[arg(long)]
391 maximum_evm_fuel_per_block: Option<u64>,
392
393 /// Set the maximum time in milliseconds that a block can spend executing services as oracles.
394 #[arg(long)]
395 maximum_service_oracle_execution_ms: Option<u64>,
396
397 /// Set the maximum size of a block, in bytes.
398 #[arg(long)]
399 maximum_block_size: Option<u64>,
400
401 /// Set the maximum size of data blobs, compressed bytecode and other binary blobs,
402 /// in bytes.
403 #[arg(long)]
404 maximum_blob_size: Option<u64>,
405
406 /// Set the maximum number of published blobs per block.
407 #[arg(long)]
408 maximum_published_blobs: Option<u64>,
409
410 /// Set the maximum size of decompressed contract or service bytecode, in bytes.
411 #[arg(long)]
412 maximum_bytecode_size: Option<u64>,
413
414 /// Set the maximum size of a block proposal, in bytes.
415 #[arg(long)]
416 maximum_block_proposal_size: Option<u64>,
417
418 /// Set the maximum read data per block.
419 #[arg(long)]
420 maximum_bytes_read_per_block: Option<u64>,
421
422 /// Set the maximum write data per block.
423 #[arg(long)]
424 maximum_bytes_written_per_block: Option<u64>,
425
426 /// Set the maximum size of oracle responses.
427 #[arg(long)]
428 maximum_oracle_response_bytes: Option<u64>,
429
430 /// Set the maximum size in bytes of a received HTTP response.
431 #[arg(long)]
432 maximum_http_response_bytes: Option<u64>,
433
434 /// Set the maximum amount of time allowed to wait for an HTTP response.
435 #[arg(long)]
436 http_request_timeout_ms: Option<u64>,
437
438 /// Set the list of hosts that contracts and services can send HTTP requests to.
439 #[arg(long)]
440 http_request_allow_list: Option<Vec<String>>,
441 },
442
443 /// Start a benchmark, maintaining a given TPS or just sending one transfer per chain in bulk mode.
444 #[cfg(feature = "benchmark")]
445 Benchmark(BenchmarkCommand),
446
447 /// Runs multiple `linera benchmark` processes in parallel.
448 #[cfg(feature = "benchmark")]
449 MultiBenchmark {
450 /// The number of `linera benchmark` processes to run in parallel.
451 #[arg(long = "processes", default_value = "1")]
452 processes: usize,
453
454 /// The faucet (which implicitly defines the network)
455 #[arg(long = "faucet")]
456 faucet: String,
457
458 /// If running on local SSD, specify the directory to store the storage and wallet.
459 /// If not specified, a temporary directory will be used for each client.
460 #[arg(long = "ssd-dir")]
461 ssd_dir: Option<String>,
462
463 /// The benchmark command to run.
464 #[clap(flatten)]
465 command: BenchmarkCommand,
466
467 /// The delay between starting the benchmark processes, in seconds.
468 #[arg(long, default_value = "10")]
469 delay_between_processes: u64,
470 },
471
472 /// Create genesis configuration for a Linera deployment.
473 /// Create initial user chains and print information to be used for initialization of validator setup.
474 /// This will also create an initial wallet for the owner of the initial "root" chains.
475 CreateGenesisConfig {
476 /// Sets the file describing the public configurations of all validators
477 #[arg(long = "committee")]
478 committee_config_path: PathBuf,
479
480 /// The output config path to be consumed by the server
481 #[arg(long = "genesis")]
482 genesis_config_path: PathBuf,
483
484 /// Known initial balance of the chain
485 #[arg(long, default_value = "0")]
486 initial_funding: Amount,
487
488 /// The start timestamp: no blocks can be created before this time.
489 #[arg(long)]
490 start_timestamp: Option<DateTime<Utc>>,
491
492 /// Number of initial (aka "root") chains to create in addition to the admin chain.
493 num_other_initial_chains: u32,
494
495 /// Configure the resource control policy (notably fees) according to pre-defined
496 /// settings.
497 #[arg(long, default_value = "no-fees")]
498 policy_config: ResourceControlPolicyConfig,
499
500 /// Set the price per unit of Wasm fuel.
501 /// (This will overwrite value from `--policy-config`)
502 #[arg(long)]
503 wasm_fuel_unit_price: Option<Amount>,
504
505 /// Set the price per unit of EVM fuel.
506 /// (This will overwrite value from `--policy-config`)
507 #[arg(long)]
508 evm_fuel_unit_price: Option<Amount>,
509
510 /// Set the price per read operation.
511 /// (This will overwrite value from `--policy-config`)
512 #[arg(long)]
513 read_operation_price: Option<Amount>,
514
515 /// Set the price per write operation.
516 /// (This will overwrite value from `--policy-config`)
517 #[arg(long)]
518 write_operation_price: Option<Amount>,
519
520 /// Set the price per byte read.
521 /// (This will overwrite value from `--policy-config`)
522 #[arg(long)]
523 byte_read_price: Option<Amount>,
524
525 /// Set the price per byte written.
526 /// (This will overwrite value from `--policy-config`)
527 #[arg(long)]
528 byte_written_price: Option<Amount>,
529
530 /// Set the base price to read a blob.
531 /// (This will overwrite value from `--policy-config`)
532 #[arg(long)]
533 blob_read_price: Option<Amount>,
534
535 /// Set the base price to publish a blob.
536 /// (This will overwrite value from `--policy-config`)
537 #[arg(long)]
538 blob_published_price: Option<Amount>,
539
540 /// Set the price to read a blob, per byte.
541 /// (This will overwrite value from `--policy-config`)
542 #[arg(long)]
543 blob_byte_read_price: Option<Amount>,
544
545 /// Set the price to publish a blob, per byte.
546 /// (This will overwrite value from `--policy-config`)
547 #[arg(long)]
548 blob_byte_published_price: Option<Amount>,
549
550 /// Set the price per byte stored.
551 /// (This will overwrite value from `--policy-config`)
552 #[arg(long)]
553 byte_stored_price: Option<Amount>,
554
555 /// Set the base price of sending an operation from a block..
556 /// (This will overwrite value from `--policy-config`)
557 #[arg(long)]
558 operation_price: Option<Amount>,
559
560 /// Set the additional price for each byte in the argument of a user operation.
561 /// (This will overwrite value from `--policy-config`)
562 #[arg(long)]
563 operation_byte_price: Option<Amount>,
564
565 /// Set the base price of sending a message from a block..
566 /// (This will overwrite value from `--policy-config`)
567 #[arg(long)]
568 message_price: Option<Amount>,
569
570 /// Set the additional price for each byte in the argument of a user message.
571 /// (This will overwrite value from `--policy-config`)
572 #[arg(long)]
573 message_byte_price: Option<Amount>,
574
575 /// Set the price per query to a service as an oracle.
576 #[arg(long)]
577 service_as_oracle_query_price: Option<Amount>,
578
579 /// Set the price for performing an HTTP request.
580 #[arg(long)]
581 http_request_price: Option<Amount>,
582
583 /// Set the maximum amount of Wasm fuel per block.
584 /// (This will overwrite value from `--policy-config`)
585 #[arg(long)]
586 maximum_wasm_fuel_per_block: Option<u64>,
587
588 /// Set the maximum amount of EVM fuel per block.
589 /// (This will overwrite value from `--policy-config`)
590 #[arg(long)]
591 maximum_evm_fuel_per_block: Option<u64>,
592
593 /// Set the maximum time in milliseconds that a block can spend executing services as oracles.
594 #[arg(long)]
595 maximum_service_oracle_execution_ms: Option<u64>,
596
597 /// Set the maximum size of a block.
598 /// (This will overwrite value from `--policy-config`)
599 #[arg(long)]
600 maximum_block_size: Option<u64>,
601
602 /// Set the maximum size of decompressed contract or service bytecode, in bytes.
603 /// (This will overwrite value from `--policy-config`)
604 #[arg(long)]
605 maximum_bytecode_size: Option<u64>,
606
607 /// Set the maximum size of data blobs, compressed bytecode and other binary blobs,
608 /// in bytes.
609 /// (This will overwrite value from `--policy-config`)
610 #[arg(long)]
611 maximum_blob_size: Option<u64>,
612
613 /// Set the maximum number of published blobs per block.
614 /// (This will overwrite value from `--policy-config`)
615 #[arg(long)]
616 maximum_published_blobs: Option<u64>,
617
618 /// Set the maximum size of a block proposal, in bytes.
619 /// (This will overwrite value from `--policy-config`)
620 #[arg(long)]
621 maximum_block_proposal_size: Option<u64>,
622
623 /// Set the maximum read data per block.
624 /// (This will overwrite value from `--policy-config`)
625 #[arg(long)]
626 maximum_bytes_read_per_block: Option<u64>,
627
628 /// Set the maximum write data per block.
629 /// (This will overwrite value from `--policy-config`)
630 #[arg(long)]
631 maximum_bytes_written_per_block: Option<u64>,
632
633 /// Set the maximum size of oracle responses.
634 /// (This will overwrite value from `--policy-config`)
635 #[arg(long)]
636 maximum_oracle_response_bytes: Option<u64>,
637
638 /// Set the maximum size in bytes of a received HTTP response.
639 #[arg(long)]
640 maximum_http_response_bytes: Option<u64>,
641
642 /// Set the maximum amount of time allowed to wait for an HTTP response.
643 #[arg(long)]
644 http_request_timeout_ms: Option<u64>,
645
646 /// Set the list of hosts that contracts and services can send HTTP requests to.
647 #[arg(long)]
648 http_request_allow_list: Option<Vec<String>>,
649
650 /// Force this wallet to generate keys using a PRNG and a given seed. USE FOR
651 /// TESTING ONLY.
652 #[arg(long)]
653 testing_prng_seed: Option<u64>,
654
655 /// A unique name to identify this network.
656 #[arg(long)]
657 network_name: Option<String>,
658 },
659
660 /// Watch the network for notifications.
661 Watch {
662 /// The chain ID to watch.
663 chain_id: Option<ChainId>,
664
665 /// Show all notifications from all validators.
666 #[arg(long)]
667 raw: bool,
668 },
669
670 /// Run a GraphQL service to explore and extend the chains of the wallet.
671 Service {
672 #[command(flatten)]
673 config: ChainListenerConfig,
674
675 /// The port on which to run the server
676 #[arg(long)]
677 port: NonZeroU16,
678 },
679
680 /// Run a GraphQL service that exposes a faucet where users can claim tokens.
681 /// This gives away the chain's tokens, and is mainly intended for testing.
682 Faucet {
683 /// The chain that gives away its tokens.
684 chain_id: Option<ChainId>,
685
686 /// The port on which to run the server
687 #[arg(long, default_value = "8080")]
688 port: NonZeroU16,
689
690 /// The number of tokens to send to each new chain.
691 #[arg(long)]
692 amount: Amount,
693
694 /// The end timestamp: The faucet will rate-limit the token supply so it runs out of money
695 /// no earlier than this.
696 #[arg(long)]
697 limit_rate_until: Option<DateTime<Utc>>,
698
699 /// Configuration for the faucet chain listener.
700 #[command(flatten)]
701 config: ChainListenerConfig,
702 },
703
704 /// Publish module.
705 PublishModule {
706 /// Path to the Wasm file for the application "contract" bytecode.
707 contract: PathBuf,
708
709 /// Path to the Wasm file for the application "service" bytecode.
710 service: PathBuf,
711
712 /// The virtual machine runtime to use.
713 #[arg(long, default_value = "wasm")]
714 vm_runtime: VmRuntime,
715
716 /// An optional chain ID to publish the module. The default chain of the wallet
717 /// is used otherwise.
718 publisher: Option<ChainId>,
719 },
720
721 /// Print events from a specific chain and stream from a specified index.
722 ListEventsFromIndex {
723 /// The chain to query. If omitted, query the default chain of the wallet.
724 chain_id: Option<ChainId>,
725
726 /// The stream being considered.
727 #[arg(long)]
728 stream_id: StreamId,
729
730 /// Index of the message to start with
731 #[arg(long, default_value = "0")]
732 start_index: u32,
733 },
734
735 /// Publish a data blob of binary data.
736 PublishDataBlob {
737 /// Path to data blob file to be published.
738 blob_path: PathBuf,
739 /// An optional chain ID to publish the blob. The default chain of the wallet
740 /// is used otherwise.
741 publisher: Option<ChainId>,
742 },
743
744 // TODO(#2490): Consider removing or renaming this.
745 /// Verify that a data blob is readable.
746 ReadDataBlob {
747 /// The hash of the content.
748 hash: CryptoHash,
749 /// An optional chain ID to verify the blob. The default chain of the wallet
750 /// is used otherwise.
751 reader: Option<ChainId>,
752 },
753
754 /// Create an application.
755 CreateApplication {
756 /// The module ID of the application to create.
757 module_id: ModuleId,
758
759 /// An optional chain ID to host the application. The default chain of the wallet
760 /// is used otherwise.
761 creator: Option<ChainId>,
762
763 /// The shared parameters as JSON string.
764 #[arg(long)]
765 json_parameters: Option<String>,
766
767 /// Path to a JSON file containing the shared parameters.
768 #[arg(long)]
769 json_parameters_path: Option<PathBuf>,
770
771 /// The instantiation argument as a JSON string.
772 #[arg(long)]
773 json_argument: Option<String>,
774
775 /// Path to a JSON file containing the instantiation argument.
776 #[arg(long)]
777 json_argument_path: Option<PathBuf>,
778
779 /// The list of required dependencies of application, if any.
780 #[arg(long, num_args(0..))]
781 required_application_ids: Option<Vec<ApplicationId>>,
782 },
783
784 /// Create an application, and publish the required module.
785 PublishAndCreate {
786 /// Path to the Wasm file for the application "contract" bytecode.
787 contract: PathBuf,
788
789 /// Path to the Wasm file for the application "service" bytecode.
790 service: PathBuf,
791
792 /// The virtual machine runtime to use.
793 #[arg(long, default_value = "wasm")]
794 vm_runtime: VmRuntime,
795
796 /// An optional chain ID to publish the module. The default chain of the wallet
797 /// is used otherwise.
798 publisher: Option<ChainId>,
799
800 /// The shared parameters as JSON string.
801 #[arg(long)]
802 json_parameters: Option<String>,
803
804 /// Path to a JSON file containing the shared parameters.
805 #[arg(long)]
806 json_parameters_path: Option<PathBuf>,
807
808 /// The instantiation argument as a JSON string.
809 #[arg(long)]
810 json_argument: Option<String>,
811
812 /// Path to a JSON file containing the instantiation argument.
813 #[arg(long)]
814 json_argument_path: Option<PathBuf>,
815
816 /// The list of required dependencies of application, if any.
817 #[arg(long, num_args(0..))]
818 required_application_ids: Option<Vec<ApplicationId>>,
819 },
820
821 /// Create an unassigned key pair.
822 Keygen,
823
824 /// Link the owner to the chain.
825 /// Expects that the caller has a private key corresponding to the `public_key`,
826 /// otherwise block proposals will fail when signing with it.
827 Assign {
828 /// The owner to assign.
829 #[arg(long)]
830 owner: AccountOwner,
831
832 /// The ID of the chain.
833 #[arg(long)]
834 chain_id: ChainId,
835 },
836
837 /// Retry a block we unsuccessfully tried to propose earlier.
838 ///
839 /// As long as a block is pending most other commands will fail, since it is unsafe to propose
840 /// multiple blocks at the same height.
841 RetryPendingBlock {
842 /// The chain with the pending block. If not specified, the wallet's default chain is used.
843 chain_id: Option<ChainId>,
844 },
845
846 /// Show the contents of the wallet.
847 #[command(subcommand)]
848 Wallet(WalletCommand),
849
850 /// Manage Linera projects.
851 #[command(subcommand)]
852 Project(ProjectCommand),
853
854 /// Manage a local Linera Network.
855 #[command(subcommand)]
856 Net(NetCommand),
857
858 /// Operation on the storage.
859 #[command(subcommand)]
860 Storage(DatabaseToolCommand),
861
862 /// Print CLI help in Markdown format, and exit.
863 #[command(hide = true)]
864 HelpMarkdown,
865
866 /// Extract a Bash and GraphQL script embedded in a markdown file and print it on
867 /// `stdout`.
868 #[command(hide = true)]
869 ExtractScriptFromMarkdown {
870 /// The source file
871 path: PathBuf,
872
873 /// Insert a pause of N seconds after calls to `linera service`.
874 #[arg(long, default_value = DEFAULT_PAUSE_AFTER_LINERA_SERVICE_SECS, value_parser = util::parse_secs)]
875 pause_after_linera_service: Duration,
876
877 /// Insert a pause of N seconds after GraphQL queries.
878 #[arg(long, default_value = DEFAULT_PAUSE_AFTER_GQL_MUTATIONS_SECS, value_parser = util::parse_secs)]
879 pause_after_gql_mutations: Duration,
880 },
881}
882
883impl ClientCommand {
884 /// Returns the log file name to use based on the [`ClientCommand`] that will run.
885 pub fn log_file_name(&self) -> Cow<'static, str> {
886 match self {
887 ClientCommand::Transfer { .. }
888 | ClientCommand::OpenChain { .. }
889 | ClientCommand::OpenMultiOwnerChain { .. }
890 | ClientCommand::ChangeOwnership { .. }
891 | ClientCommand::SetPreferredOwner { .. }
892 | ClientCommand::ChangeApplicationPermissions { .. }
893 | ClientCommand::CloseChain { .. }
894 | ClientCommand::LocalBalance { .. }
895 | ClientCommand::QueryBalance { .. }
896 | ClientCommand::SyncBalance { .. }
897 | ClientCommand::Sync { .. }
898 | ClientCommand::ProcessInbox { .. }
899 | ClientCommand::QueryValidator { .. }
900 | ClientCommand::QueryValidators { .. }
901 | ClientCommand::SyncValidator { .. }
902 | ClientCommand::SetValidator { .. }
903 | ClientCommand::RemoveValidator { .. }
904 | ClientCommand::ResourceControlPolicy { .. }
905 | ClientCommand::RevokeEpochs { .. }
906 | ClientCommand::CreateGenesisConfig { .. }
907 | ClientCommand::PublishModule { .. }
908 | ClientCommand::ListEventsFromIndex { .. }
909 | ClientCommand::PublishDataBlob { .. }
910 | ClientCommand::ReadDataBlob { .. }
911 | ClientCommand::CreateApplication { .. }
912 | ClientCommand::PublishAndCreate { .. }
913 | ClientCommand::Keygen
914 | ClientCommand::Assign { .. }
915 | ClientCommand::Wallet { .. }
916 | ClientCommand::RetryPendingBlock { .. } => "client".into(),
917 #[cfg(feature = "benchmark")]
918 ClientCommand::Benchmark { .. } => "benchmark".into(),
919 #[cfg(feature = "benchmark")]
920 ClientCommand::MultiBenchmark { .. } => "multi-benchmark".into(),
921 ClientCommand::Net { .. } => "net".into(),
922 ClientCommand::Project { .. } => "project".into(),
923 ClientCommand::Watch { .. } => "watch".into(),
924 ClientCommand::Storage { .. } => "storage".into(),
925 ClientCommand::Service { port, .. } => format!("service-{port}").into(),
926 ClientCommand::Faucet { .. } => "faucet".into(),
927 ClientCommand::HelpMarkdown | ClientCommand::ExtractScriptFromMarkdown { .. } => {
928 "tool".into()
929 }
930 }
931 }
932}
933
934#[derive(Clone, clap::Parser)]
935pub enum DatabaseToolCommand {
936 /// Delete all the namespaces in the database
937 DeleteAll,
938
939 /// Delete a single namespace from the database
940 DeleteNamespace,
941
942 /// Check existence of a namespace in the database
943 CheckExistence,
944
945 /// Initialize a namespace in the database
946 Initialize {
947 #[arg(long = "genesis")]
948 genesis_config_path: PathBuf,
949 },
950
951 /// List the namespaces in the database
952 ListNamespaces,
953
954 /// List the blob IDs in the database
955 ListBlobIds,
956
957 /// List the chain IDs in the database
958 ListChainIds,
959}
960
961#[allow(clippy::large_enum_variant)]
962#[derive(Clone, clap::Parser)]
963pub enum NetCommand {
964 /// Start a Local Linera Network
965 Up {
966 /// The number of initial "root" chains created in the genesis config on top of
967 /// the default "admin" chain. All initial chains belong to the first "admin"
968 /// wallet. It is recommended to use at least one other initial chain for the
969 /// faucet.
970 #[arg(long, default_value = "2")]
971 other_initial_chains: u32,
972
973 /// The initial amount of native tokens credited in the initial "root" chains,
974 /// including the default "admin" chain.
975 #[arg(long, default_value = "1000000")]
976 initial_amount: u128,
977
978 /// The number of validators in the local test network.
979 #[arg(long, default_value = "1")]
980 validators: usize,
981
982 /// The number of shards per validator in the local test network.
983 #[arg(long, default_value = "1")]
984 shards: usize,
985
986 /// Configure the resource control policy (notably fees) according to pre-defined
987 /// settings.
988 #[arg(long, default_value = "no-fees")]
989 policy_config: ResourceControlPolicyConfig,
990
991 /// The configuration for cross-chain messages.
992 #[clap(flatten)]
993 cross_chain_config: CrossChainConfig,
994
995 /// Force this wallet to generate keys using a PRNG and a given seed. USE FOR
996 /// TESTING ONLY.
997 #[arg(long)]
998 testing_prng_seed: Option<u64>,
999
1000 /// Start the local network on a local Kubernetes deployment.
1001 #[cfg(feature = "kubernetes")]
1002 #[arg(long)]
1003 kubernetes: bool,
1004
1005 /// If this is not set, we'll build the binaries from within the Docker container
1006 /// If it's set, but with no directory path arg, we'll look for the binaries based on `current_binary_parent`
1007 /// If it's set, but with a directory path arg, we'll get the binaries from that path directory
1008 #[cfg(feature = "kubernetes")]
1009 #[arg(long, num_args=0..=1)]
1010 binaries: Option<Option<PathBuf>>,
1011
1012 /// Don't build docker image. This assumes that the image is already built.
1013 #[cfg(feature = "kubernetes")]
1014 #[arg(long, default_value = "false")]
1015 no_build: bool,
1016
1017 /// The name of the docker image to use.
1018 #[cfg(feature = "kubernetes")]
1019 #[arg(long, default_value = "linera:latest")]
1020 docker_image_name: String,
1021
1022 /// The build mode to use.
1023 #[cfg(feature = "kubernetes")]
1024 #[arg(long, default_value = "release")]
1025 build_mode: BuildMode,
1026
1027 /// Run with a specific path where the wallet and validator input files are.
1028 /// If none, then a temporary directory is created.
1029 #[arg(long)]
1030 path: Option<String>,
1031
1032 /// External protocol used, either `grpc` or `grpcs`.
1033 #[arg(long, default_value = "grpc")]
1034 external_protocol: String,
1035
1036 /// If present, a faucet is started using the chain provided by --faucet-chain, or
1037 /// `ChainId::root(1)` if not provided, as root 0 is usually the admin chain.
1038 #[arg(long, default_value = "false")]
1039 with_faucet: bool,
1040
1041 /// When using --with-faucet, this specifies the chain on which the faucet will be started.
1042 /// The chain is specified by its root number (0 for the admin chain, 1 for the first
1043 /// non-admin initial chain, etc).
1044 #[arg(long)]
1045 faucet_chain: Option<u32>,
1046
1047 /// The port on which to run the faucet server
1048 #[arg(long, default_value = "8080")]
1049 faucet_port: NonZeroU16,
1050
1051 /// The number of tokens to send to each new chain created by the faucet.
1052 #[arg(long, default_value = "1000")]
1053 faucet_amount: Amount,
1054
1055 /// The number of block exporters per validator in the local test network. Default is 0.
1056 #[arg(long, default_value = "0")]
1057 block_exporters: u32,
1058
1059 /// Use dual store (rocksdb and scylladb) instead of just scylladb. This is exclusive for
1060 /// kubernetes deployments.
1061 #[cfg(feature = "kubernetes")]
1062 #[arg(long, default_value = "false")]
1063 dual_store: bool,
1064 },
1065
1066 /// Print a bash helper script to make `linera net up` easier to use. The script is
1067 /// meant to be installed in `~/.bash_profile` or sourced when needed.
1068 Helper,
1069}
1070
1071#[derive(Clone, clap::Subcommand)]
1072pub enum WalletCommand {
1073 /// Show the contents of the wallet.
1074 Show {
1075 /// The chain to show the metadata.
1076 chain_id: Option<ChainId>,
1077 /// Only print a non-formatted list of the wallet's chain IDs.
1078 #[arg(long)]
1079 short: bool,
1080 /// Print only the chains that we have a key pair for.
1081 #[arg(long)]
1082 owned: bool,
1083 },
1084
1085 /// Change the wallet default chain.
1086 SetDefault { chain_id: ChainId },
1087
1088 /// Initialize a wallet from the genesis configuration.
1089 Init {
1090 /// The path to the genesis configuration for a Linera deployment. Either this or `--faucet`
1091 /// must be specified.
1092 #[arg(long = "genesis")]
1093 genesis_config_path: Option<PathBuf>,
1094
1095 /// The address of a faucet.
1096 #[arg(long = "faucet")]
1097 faucet: Option<String>,
1098
1099 /// Force this wallet to generate keys using a PRNG and a given seed. USE FOR
1100 /// TESTING ONLY.
1101 #[arg(long)]
1102 testing_prng_seed: Option<u64>,
1103 },
1104
1105 /// Request a new chain from a faucet and add it to the wallet.
1106 RequestChain {
1107 /// The address of a faucet.
1108 #[arg(long)]
1109 faucet: String,
1110
1111 /// Whether this chain should become the default chain.
1112 #[arg(long)]
1113 set_default: bool,
1114 },
1115
1116 /// Add a new followed chain (i.e. a chain without keypair) to the wallet.
1117 FollowChain {
1118 /// The chain ID.
1119 chain_id: ChainId,
1120 /// Synchronize the new chain and download all its blocks from the validators.
1121 #[arg(long)]
1122 sync: bool,
1123 },
1124
1125 /// Forgets the specified chain's keys. The chain will still be followed by the
1126 /// wallet.
1127 ForgetKeys { chain_id: ChainId },
1128
1129 /// Forgets the specified chain, including the associated key pair.
1130 ForgetChain { chain_id: ChainId },
1131}
1132
1133#[derive(Clone, clap::Parser)]
1134pub enum ProjectCommand {
1135 /// Create a new Linera project.
1136 New {
1137 /// The project name. A directory of the same name will be created in the current directory.
1138 name: String,
1139
1140 /// Use the given clone of the Linera repository instead of remote crates.
1141 #[arg(long)]
1142 linera_root: Option<PathBuf>,
1143 },
1144
1145 /// Test a Linera project.
1146 ///
1147 /// Equivalent to running `cargo test` with the appropriate test runner.
1148 Test { path: Option<PathBuf> },
1149
1150 /// Build and publish a Linera project.
1151 PublishAndCreate {
1152 /// The path of the root of the Linera project.
1153 /// Defaults to current working directory if unspecified.
1154 path: Option<PathBuf>,
1155
1156 /// Specify the name of the Linera project.
1157 /// This is used to locate the generated bytecode files. The generated bytecode files should
1158 /// be of the form `<name>_{contract,service}.wasm`.
1159 ///
1160 /// Defaults to the package name in Cargo.toml, with dashes replaced by
1161 /// underscores.
1162 name: Option<String>,
1163
1164 /// An optional chain ID to publish the module. The default chain of the wallet
1165 /// is used otherwise.
1166 publisher: Option<ChainId>,
1167
1168 /// The virtual machine runtime to use.
1169 #[arg(long, default_value = "wasm")]
1170 vm_runtime: VmRuntime,
1171
1172 /// The shared parameters as JSON string.
1173 #[arg(long)]
1174 json_parameters: Option<String>,
1175
1176 /// Path to a JSON file containing the shared parameters.
1177 #[arg(long)]
1178 json_parameters_path: Option<PathBuf>,
1179
1180 /// The instantiation argument as a JSON string.
1181 #[arg(long)]
1182 json_argument: Option<String>,
1183
1184 /// Path to a JSON file containing the instantiation argument.
1185 #[arg(long)]
1186 json_argument_path: Option<PathBuf>,
1187
1188 /// The list of required dependencies of application, if any.
1189 #[arg(long, num_args(0..))]
1190 required_application_ids: Option<Vec<ApplicationId>>,
1191 },
1192}