1use {
2 clap::{
3 crate_description, crate_name, App, AppSettings, Arg, ArgGroup, ArgMatches, SubCommand,
4 },
5 log::warn,
6 miraland_accounts_db::{
7 accounts_db::{
8 DEFAULT_ACCOUNTS_SHRINK_OPTIMIZE_TOTAL_SPACE, DEFAULT_ACCOUNTS_SHRINK_RATIO,
9 },
10 hardened_unpack::MAX_GENESIS_ARCHIVE_UNPACKED_SIZE,
11 },
12 miraland_clap_utils::{
13 hidden_unless_forced,
14 input_validators::{
15 is_keypair, is_keypair_or_ask_keyword, is_parsable, is_pow2, is_pubkey,
16 is_pubkey_or_keypair, is_slot, is_url_or_moniker, is_valid_percentage, is_within_range,
17 validate_maximum_full_snapshot_archives_to_retain,
18 validate_maximum_incremental_snapshot_archives_to_retain,
19 },
20 keypair::SKIP_SEED_PHRASE_VALIDATION_ARG,
21 },
22 miraland_core::{
23 banking_trace::{DirByteLimit, BANKING_TRACE_DIR_DEFAULT_BYTE_LIMIT},
24 validator::{BlockProductionMethod, BlockVerificationMethod},
25 },
26 miraland_faucet::faucet::{self, FAUCET_PORT},
27 miraland_ledger::use_snapshot_archives_at_startup,
28 miraland_net_utils::{MINIMUM_VALIDATOR_PORT_RANGE_WIDTH, VALIDATOR_PORT_RANGE},
29 miraland_rpc::{rpc::MAX_REQUEST_BODY_SIZE, rpc_pubsub_service::PubSubConfig},
30 miraland_rpc_client_api::request::MAX_MULTIPLE_ACCOUNTS,
31 miraland_send_transaction_service::send_transaction_service::{
32 self, MAX_BATCH_SEND_RATE_MS, MAX_TRANSACTION_BATCH_SIZE,
33 },
34 miraland_tpu_client::tpu_client::DEFAULT_TPU_CONNECTION_POOL_SIZE,
35 miraland_unified_scheduler_pool::DefaultSchedulerPool,
36 miraland_runtime::{
37 snapshot_bank_utils::{
38 DEFAULT_FULL_SNAPSHOT_ARCHIVE_INTERVAL_SLOTS,
39 DEFAULT_INCREMENTAL_SNAPSHOT_ARCHIVE_INTERVAL_SLOTS,
40 },
41 snapshot_utils::{
42 SnapshotVersion, DEFAULT_ARCHIVE_COMPRESSION,
43 DEFAULT_MAX_FULL_SNAPSHOT_ARCHIVES_TO_RETAIN,
44 DEFAULT_MAX_INCREMENTAL_SNAPSHOT_ARCHIVES_TO_RETAIN, SUPPORTED_ARCHIVE_COMPRESSION,
45 },
46 },
47 miraland_sdk::{
48 clock::Slot, epoch_schedule::MINIMUM_SLOTS_PER_EPOCH, hash::Hash, quic::QUIC_PORT_OFFSET,
49 rpc_port,
50 },
51 std::{path::PathBuf, str::FromStr},
52};
53
54const EXCLUDE_KEY: &str = "account-index-exclude-key";
55const INCLUDE_KEY: &str = "account-index-include-key";
56const DEFAULT_MIN_SNAPSHOT_DOWNLOAD_SPEED: u64 = 10485760;
58const MAX_SNAPSHOT_DOWNLOAD_ABORT: u32 = 5;
60const MINIMUM_TICKS_PER_SLOT: u64 = 2;
63
64pub fn app<'a>(version: &'a str, default_args: &'a DefaultArgs) -> App<'a, 'a> {
65 return App::new(crate_name!())
66 .about(crate_description!())
67 .version(version)
68 .setting(AppSettings::VersionlessSubcommands)
69 .setting(AppSettings::InferSubcommands)
70 .arg(
71 Arg::with_name(SKIP_SEED_PHRASE_VALIDATION_ARG.name)
72 .long(SKIP_SEED_PHRASE_VALIDATION_ARG.long)
73 .help(SKIP_SEED_PHRASE_VALIDATION_ARG.help),
74 )
75 .arg(
76 Arg::with_name("identity")
77 .short("i")
78 .long("identity")
79 .value_name("KEYPAIR")
80 .takes_value(true)
81 .validator(is_keypair_or_ask_keyword)
82 .help("Validator identity keypair"),
83 )
84 .arg(
85 Arg::with_name("authorized_voter_keypairs")
86 .long("authorized-voter")
87 .value_name("KEYPAIR")
88 .takes_value(true)
89 .validator(is_keypair_or_ask_keyword)
90 .requires("vote_account")
91 .multiple(true)
92 .help(
93 "Include an additional authorized voter keypair. May be specified multiple \
94 times. [default: the --identity keypair]",
95 ),
96 )
97 .arg(
98 Arg::with_name("vote_account")
99 .long("vote-account")
100 .value_name("ADDRESS")
101 .takes_value(true)
102 .validator(is_pubkey_or_keypair)
103 .requires("identity")
104 .help(
105 "Validator vote account public key. If unspecified, voting will be disabled. \
106 The authorized voter for the account must either be the --identity keypair \
107 or set by the --authorized-voter argument",
108 ),
109 )
110 .arg(
111 Arg::with_name("init_complete_file")
112 .long("init-complete-file")
113 .value_name("FILE")
114 .takes_value(true)
115 .help(
116 "Create this file if it doesn't already exist once validator initialization \
117 is complete",
118 ),
119 )
120 .arg(
121 Arg::with_name("ledger_path")
122 .short("l")
123 .long("ledger")
124 .value_name("DIR")
125 .takes_value(true)
126 .required(true)
127 .default_value(&default_args.ledger_path)
128 .help("Use DIR as ledger location"),
129 )
130 .arg(
131 Arg::with_name("entrypoint")
132 .short("n")
133 .long("entrypoint")
134 .value_name("HOST:PORT")
135 .takes_value(true)
136 .multiple(true)
137 .validator(miraland_net_utils::is_host_port)
138 .help("Rendezvous with the cluster at this gossip entrypoint"),
139 )
140 .arg(
141 Arg::with_name("no_snapshot_fetch")
142 .long("no-snapshot-fetch")
143 .takes_value(false)
144 .help(
145 "Do not attempt to fetch a snapshot from the cluster, start from a local \
146 snapshot if present",
147 ),
148 )
149 .arg(
150 Arg::with_name("no_genesis_fetch")
151 .long("no-genesis-fetch")
152 .takes_value(false)
153 .help("Do not fetch genesis from the cluster"),
154 )
155 .arg(
156 Arg::with_name("no_voting")
157 .long("no-voting")
158 .takes_value(false)
159 .help("Launch validator without voting"),
160 )
161 .arg(
162 Arg::with_name("check_vote_account")
163 .long("check-vote-account")
164 .takes_value(true)
165 .value_name("RPC_URL")
166 .requires("entrypoint")
167 .conflicts_with_all(&["no_check_vote_account", "no_voting"])
168 .help(
169 "Sanity check vote account state at startup. The JSON RPC endpoint at RPC_URL \
170 must expose `--full-rpc-api`",
171 ),
172 )
173 .arg(
174 Arg::with_name("restricted_repair_only_mode")
175 .long("restricted-repair-only-mode")
176 .takes_value(false)
177 .help(
178 "Do not publish the Gossip, TPU, TVU or Repair Service ports. Doing so causes \
179 the node to operate in a limited capacity that reduces its exposure to the \
180 rest of the cluster. The --no-voting flag is implicit when this flag is \
181 enabled",
182 ),
183 )
184 .arg(
185 Arg::with_name("dev_halt_at_slot")
186 .long("dev-halt-at-slot")
187 .value_name("SLOT")
188 .validator(is_slot)
189 .takes_value(true)
190 .help("Halt the validator when it reaches the given slot"),
191 )
192 .arg(
193 Arg::with_name("rpc_port")
194 .long("rpc-port")
195 .value_name("PORT")
196 .takes_value(true)
197 .validator(port_validator)
198 .help("Enable JSON RPC on this port, and the next port for the RPC websocket"),
199 )
200 .arg(
201 Arg::with_name("full_rpc_api")
202 .long("full-rpc-api")
203 .conflicts_with("minimal_rpc_api")
204 .takes_value(false)
205 .help("Expose RPC methods for querying chain state and transaction history"),
206 )
207 .arg(
208 Arg::with_name("obsolete_v1_7_rpc_api")
209 .long("enable-rpc-obsolete_v1_7")
210 .takes_value(false)
211 .help("Enable the obsolete RPC methods removed in v1.7"),
212 )
213 .arg(
214 Arg::with_name("private_rpc")
215 .long("private-rpc")
216 .takes_value(false)
217 .help("Do not publish the RPC port for use by others"),
218 )
219 .arg(
220 Arg::with_name("no_port_check")
221 .long("no-port-check")
222 .takes_value(false)
223 .hidden(hidden_unless_forced())
224 .help("Do not perform TCP/UDP reachable port checks at start-up"),
225 )
226 .arg(
227 Arg::with_name("enable_rpc_transaction_history")
228 .long("enable-rpc-transaction-history")
229 .takes_value(false)
230 .help(
231 "Enable historical transaction info over JSON RPC, including the \
232 'getConfirmedBlock' API. This will cause an increase in disk usage and IOPS",
233 ),
234 )
235 .arg(
236 Arg::with_name("enable_rpc_bigtable_ledger_storage")
237 .long("enable-rpc-bigtable-ledger-storage")
238 .requires("enable_rpc_transaction_history")
239 .takes_value(false)
240 .help(
241 "Fetch historical transaction info from a BigTable instance as a fallback to \
242 local ledger data",
243 ),
244 )
245 .arg(
246 Arg::with_name("enable_bigtable_ledger_upload")
247 .long("enable-bigtable-ledger-upload")
248 .requires("enable_rpc_transaction_history")
249 .takes_value(false)
250 .help("Upload new confirmed blocks into a BigTable instance"),
251 )
252 .arg(
253 Arg::with_name("enable_extended_tx_metadata_storage")
254 .long("enable-extended-tx-metadata-storage")
255 .requires("enable_rpc_transaction_history")
256 .takes_value(false)
257 .help(
258 "Include CPI inner instructions, logs, and return data in the historical \
259 transaction info stored",
260 ),
261 )
262 .arg(
263 Arg::with_name("rpc_max_multiple_accounts")
264 .long("rpc-max-multiple-accounts")
265 .value_name("MAX ACCOUNTS")
266 .takes_value(true)
267 .default_value(&default_args.rpc_max_multiple_accounts)
268 .help(
269 "Override the default maximum accounts accepted by the getMultipleAccounts \
270 JSON RPC method",
271 ),
272 )
273 .arg(
274 Arg::with_name("health_check_slot_distance")
275 .long("health-check-slot-distance")
276 .value_name("SLOT_DISTANCE")
277 .takes_value(true)
278 .default_value(&default_args.health_check_slot_distance)
279 .help(
280 "Report this validator as healthy if its latest replayed optimistically \
281 confirmed slot is within the specified number of slots from the cluster's \
282 latest optimistically confirmed slot",
283 ),
284 )
285 .arg(
286 Arg::with_name("rpc_faucet_addr")
287 .long("rpc-faucet-address")
288 .value_name("HOST:PORT")
289 .takes_value(true)
290 .validator(miraland_net_utils::is_host_port)
291 .help("Enable the JSON RPC 'requestAirdrop' API with this faucet address."),
292 )
293 .arg(
294 Arg::with_name("account_paths")
295 .long("accounts")
296 .value_name("PATHS")
297 .takes_value(true)
298 .multiple(true)
299 .help(
300 "Comma separated persistent accounts location. \
301 May be specified multiple times. \
302 [default: <LEDGER>/accounts]",
303 ),
304 )
305 .arg(
306 Arg::with_name("account_shrink_path")
307 .long("account-shrink-path")
308 .value_name("PATH")
309 .takes_value(true)
310 .multiple(true)
311 .help("Path to accounts shrink path which can hold a compacted account set."),
312 )
313 .arg(
314 Arg::with_name("accounts_hash_cache_path")
315 .long("accounts-hash-cache-path")
316 .value_name("PATH")
317 .takes_value(true)
318 .help(
319 "Use PATH as accounts hash cache location \
320 [default: <LEDGER>/accounts_hash_cache]",
321 ),
322 )
323 .arg(
324 Arg::with_name("snapshots")
325 .long("snapshots")
326 .value_name("DIR")
327 .takes_value(true)
328 .help("Use DIR as snapshot location [default: <LEDGER>/snapshots]"),
329 )
330 .arg(
331 Arg::with_name(use_snapshot_archives_at_startup::cli::NAME)
332 .long(use_snapshot_archives_at_startup::cli::LONG_ARG)
333 .takes_value(true)
334 .possible_values(use_snapshot_archives_at_startup::cli::POSSIBLE_VALUES)
335 .default_value(use_snapshot_archives_at_startup::cli::default_value())
336 .help(use_snapshot_archives_at_startup::cli::HELP)
337 .long_help(use_snapshot_archives_at_startup::cli::LONG_HELP),
338 )
339 .arg(
340 Arg::with_name("incremental_snapshot_archive_path")
341 .long("incremental-snapshot-archive-path")
342 .conflicts_with("no-incremental-snapshots")
343 .value_name("DIR")
344 .takes_value(true)
345 .help(
346 "Use DIR as separate location for incremental snapshot archives \
347 [default: --snapshots value]",
348 ),
349 )
350 .arg(
351 Arg::with_name("tower")
352 .long("tower")
353 .value_name("DIR")
354 .takes_value(true)
355 .help("Use DIR as file tower storage location [default: --ledger value]"),
356 )
357 .arg(
358 Arg::with_name("tower_storage")
359 .long("tower-storage")
360 .possible_values(&["file", "etcd"])
361 .default_value(&default_args.tower_storage)
362 .takes_value(true)
363 .help("Where to store the tower"),
364 )
365 .arg(
366 Arg::with_name("etcd_endpoint")
367 .long("etcd-endpoint")
368 .required_if("tower_storage", "etcd")
369 .value_name("HOST:PORT")
370 .takes_value(true)
371 .multiple(true)
372 .validator(miraland_net_utils::is_host_port)
373 .help("etcd gRPC endpoint to connect with"),
374 )
375 .arg(
376 Arg::with_name("etcd_domain_name")
377 .long("etcd-domain-name")
378 .required_if("tower_storage", "etcd")
379 .value_name("DOMAIN")
380 .default_value(&default_args.etcd_domain_name)
381 .takes_value(true)
382 .help("domain name against which to verify the etcd server’s TLS certificate"),
383 )
384 .arg(
385 Arg::with_name("etcd_cacert_file")
386 .long("etcd-cacert-file")
387 .required_if("tower_storage", "etcd")
388 .value_name("FILE")
389 .takes_value(true)
390 .help("verify the TLS certificate of the etcd endpoint using this CA bundle"),
391 )
392 .arg(
393 Arg::with_name("etcd_key_file")
394 .long("etcd-key-file")
395 .required_if("tower_storage", "etcd")
396 .value_name("FILE")
397 .takes_value(true)
398 .help("TLS key file to use when establishing a connection to the etcd endpoint"),
399 )
400 .arg(
401 Arg::with_name("etcd_cert_file")
402 .long("etcd-cert-file")
403 .required_if("tower_storage", "etcd")
404 .value_name("FILE")
405 .takes_value(true)
406 .help("TLS certificate to use when establishing a connection to the etcd endpoint"),
407 )
408 .arg(
409 Arg::with_name("gossip_port")
410 .long("gossip-port")
411 .value_name("PORT")
412 .takes_value(true)
413 .help("Gossip port number for the validator"),
414 )
415 .arg(
416 Arg::with_name("gossip_host")
417 .long("gossip-host")
418 .value_name("HOST")
419 .takes_value(true)
420 .validator(miraland_net_utils::is_host)
421 .help(
422 "Gossip DNS name or IP address for the validator to advertise in gossip \
423 [default: ask --entrypoint, or 127.0.0.1 when --entrypoint is not provided]",
424 ),
425 )
426 .arg(
427 Arg::with_name("public_tpu_addr")
428 .long("public-tpu-address")
429 .alias("tpu-host-addr")
430 .value_name("HOST:PORT")
431 .takes_value(true)
432 .validator(miraland_net_utils::is_host_port)
433 .help(
434 "Specify TPU address to advertise in gossip \
435 [default: ask --entrypoint or localhost when --entrypoint is not provided]",
436 ),
437 )
438 .arg(
439 Arg::with_name("public_tpu_forwards_addr")
440 .long("public-tpu-forwards-address")
441 .value_name("HOST:PORT")
442 .takes_value(true)
443 .validator(miraland_net_utils::is_host_port)
444 .help(
445 "Specify TPU Forwards address to advertise in gossip [default: ask \
446 --entrypoint or localhostwhen --entrypoint is not provided]",
447 ),
448 )
449 .arg(
450 Arg::with_name("public_rpc_addr")
451 .long("public-rpc-address")
452 .value_name("HOST:PORT")
453 .takes_value(true)
454 .conflicts_with("private_rpc")
455 .validator(miraland_net_utils::is_host_port)
456 .help(
457 "RPC address for the validator to advertise publicly in gossip. Useful for \
458 validators running behind a load balancer or proxy [default: use \
459 --rpc-bind-address / --rpc-port]",
460 ),
461 )
462 .arg(
463 Arg::with_name("dynamic_port_range")
464 .long("dynamic-port-range")
465 .value_name("MIN_PORT-MAX_PORT")
466 .takes_value(true)
467 .default_value(&default_args.dynamic_port_range)
468 .validator(port_range_validator)
469 .help("Range to use for dynamically assigned ports"),
470 )
471 .arg(
472 Arg::with_name("maximum_local_snapshot_age")
473 .long("maximum-local-snapshot-age")
474 .value_name("NUMBER_OF_SLOTS")
475 .takes_value(true)
476 .default_value(&default_args.maximum_local_snapshot_age)
477 .help(
478 "Reuse a local snapshot if it's less than this many slots behind the highest \
479 snapshot available for download from other validators",
480 ),
481 )
482 .arg(
483 Arg::with_name("no_incremental_snapshots")
484 .long("no-incremental-snapshots")
485 .takes_value(false)
486 .help("Disable incremental snapshots")
487 .long_help(
488 "Disable incremental snapshots by setting this flag. When enabled, \
489 --snapshot-interval-slots will set the incremental snapshot interval. To set \
490 the full snapshot interval, use --full-snapshot-interval-slots.",
491 ),
492 )
493 .arg(
494 Arg::with_name("incremental_snapshot_interval_slots")
495 .long("incremental-snapshot-interval-slots")
496 .alias("snapshot-interval-slots")
497 .value_name("NUMBER")
498 .takes_value(true)
499 .default_value(&default_args.incremental_snapshot_archive_interval_slots)
500 .help("Number of slots between generating snapshots, 0 to disable snapshots"),
501 )
502 .arg(
503 Arg::with_name("full_snapshot_interval_slots")
504 .long("full-snapshot-interval-slots")
505 .value_name("NUMBER")
506 .takes_value(true)
507 .default_value(&default_args.full_snapshot_archive_interval_slots)
508 .help(
509 "Number of slots between generating full snapshots. Must be a multiple of the \
510 incremental snapshot interval.",
511 ),
512 )
513 .arg(
514 Arg::with_name("maximum_full_snapshots_to_retain")
515 .long("maximum-full-snapshots-to-retain")
516 .alias("maximum-snapshots-to-retain")
517 .value_name("NUMBER")
518 .takes_value(true)
519 .default_value(&default_args.maximum_full_snapshot_archives_to_retain)
520 .validator(validate_maximum_full_snapshot_archives_to_retain)
521 .help(
522 "The maximum number of full snapshot archives to hold on to when purging \
523 older snapshots.",
524 ),
525 )
526 .arg(
527 Arg::with_name("maximum_incremental_snapshots_to_retain")
528 .long("maximum-incremental-snapshots-to-retain")
529 .value_name("NUMBER")
530 .takes_value(true)
531 .default_value(&default_args.maximum_incremental_snapshot_archives_to_retain)
532 .validator(validate_maximum_incremental_snapshot_archives_to_retain)
533 .help(
534 "The maximum number of incremental snapshot archives to hold on to when \
535 purging older snapshots.",
536 ),
537 )
538 .arg(
539 Arg::with_name("snapshot_packager_niceness_adj")
540 .long("snapshot-packager-niceness-adjustment")
541 .value_name("ADJUSTMENT")
542 .takes_value(true)
543 .validator(miraland_perf::thread::is_niceness_adjustment_valid)
544 .default_value(&default_args.snapshot_packager_niceness_adjustment)
545 .help(
546 "Add this value to niceness of snapshot packager thread. Negative value \
547 increases priority, positive value decreases priority.",
548 ),
549 )
550 .arg(
551 Arg::with_name("minimal_snapshot_download_speed")
552 .long("minimal-snapshot-download-speed")
553 .value_name("MINIMAL_SNAPSHOT_DOWNLOAD_SPEED")
554 .takes_value(true)
555 .default_value(&default_args.min_snapshot_download_speed)
556 .help(
557 "The minimal speed of snapshot downloads measured in bytes/second. If the \
558 initial download speed falls below this threshold, the system will retry the \
559 download against a different rpc node.",
560 ),
561 )
562 .arg(
563 Arg::with_name("maximum_snapshot_download_abort")
564 .long("maximum-snapshot-download-abort")
565 .value_name("MAXIMUM_SNAPSHOT_DOWNLOAD_ABORT")
566 .takes_value(true)
567 .default_value(&default_args.max_snapshot_download_abort)
568 .help(
569 "The maximum number of times to abort and retry when encountering a slow \
570 snapshot download.",
571 ),
572 )
573 .arg(
574 Arg::with_name("contact_debug_interval")
575 .long("contact-debug-interval")
576 .value_name("CONTACT_DEBUG_INTERVAL")
577 .takes_value(true)
578 .default_value(&default_args.contact_debug_interval)
579 .help("Milliseconds between printing contact debug from gossip."),
580 )
581 .arg(
582 Arg::with_name("no_poh_speed_test")
583 .long("no-poh-speed-test")
584 .hidden(hidden_unless_forced())
585 .help("Skip the check for PoH speed."),
586 )
587 .arg(
588 Arg::with_name("no_os_network_limits_test")
589 .hidden(hidden_unless_forced())
590 .long("no-os-network-limits-test")
591 .help("Skip checks for OS network limits."),
592 )
593 .arg(
594 Arg::with_name("no_os_memory_stats_reporting")
595 .long("no-os-memory-stats-reporting")
596 .hidden(hidden_unless_forced())
597 .help("Disable reporting of OS memory statistics."),
598 )
599 .arg(
600 Arg::with_name("no_os_network_stats_reporting")
601 .long("no-os-network-stats-reporting")
602 .hidden(hidden_unless_forced())
603 .help("Disable reporting of OS network statistics."),
604 )
605 .arg(
606 Arg::with_name("no_os_cpu_stats_reporting")
607 .long("no-os-cpu-stats-reporting")
608 .hidden(hidden_unless_forced())
609 .help("Disable reporting of OS CPU statistics."),
610 )
611 .arg(
612 Arg::with_name("no_os_disk_stats_reporting")
613 .long("no-os-disk-stats-reporting")
614 .hidden(hidden_unless_forced())
615 .help("Disable reporting of OS disk statistics."),
616 )
617 .arg(
618 Arg::with_name("snapshot_version")
619 .long("snapshot-version")
620 .value_name("SNAPSHOT_VERSION")
621 .validator(is_parsable::<SnapshotVersion>)
622 .takes_value(true)
623 .default_value(default_args.snapshot_version.into())
624 .help("Output snapshot version"),
625 )
626 .arg(
627 Arg::with_name("limit_ledger_size")
628 .long("limit-ledger-size")
629 .value_name("SHRED_COUNT")
630 .takes_value(true)
631 .min_values(0)
632 .max_values(1)
633 .help("Keep this amount of shreds in root slots."),
635 )
636 .arg(
637 Arg::with_name("rocksdb_shred_compaction")
638 .long("rocksdb-shred-compaction")
639 .value_name("ROCKSDB_COMPACTION_STYLE")
640 .takes_value(true)
641 .possible_values(&["level", "fifo"])
642 .default_value(&default_args.rocksdb_shred_compaction)
643 .help(
644 "Controls how RocksDB compacts shreds. *WARNING*: You will lose your \
645 Blockstore data when you switch between options. Possible values are: \
646 'level': stores shreds using RocksDB's default (level) compaction. \
647 'fifo': stores shreds under RocksDB's FIFO compaction. This option is more \
648 efficient on disk-write-bytes of the Blockstore.",
649 ),
650 )
651 .arg(
652 Arg::with_name("rocksdb_fifo_shred_storage_size")
653 .long("rocksdb-fifo-shred-storage-size")
654 .value_name("SHRED_STORAGE_SIZE_BYTES")
655 .takes_value(true)
656 .validator(is_parsable::<u64>)
657 .help(
658 "The shred storage size in bytes. The suggested value is at least 50% of your \
659 ledger storage size. If this argument is unspecified, we will assign a \
660 proper value based on --limit-ledger-size. If --limit-ledger-size is not \
661 presented, it means there is no limitation on the ledger size and thus \
662 rocksdb_fifo_shred_storage_size will also be unbounded.",
663 ),
664 )
665 .arg(
666 Arg::with_name("rocksdb_ledger_compression")
667 .hidden(hidden_unless_forced())
668 .long("rocksdb-ledger-compression")
669 .value_name("COMPRESSION_TYPE")
670 .takes_value(true)
671 .possible_values(&["none", "lz4", "snappy", "zlib"])
672 .default_value(&default_args.rocksdb_ledger_compression)
673 .help(
674 "The compression algorithm that is used to compress transaction status data. \
675 Turning on compression can save ~10% of the ledger size.",
676 ),
677 )
678 .arg(
679 Arg::with_name("rocksdb_perf_sample_interval")
680 .hidden(hidden_unless_forced())
681 .long("rocksdb-perf-sample-interval")
682 .value_name("ROCKS_PERF_SAMPLE_INTERVAL")
683 .takes_value(true)
684 .validator(is_parsable::<usize>)
685 .default_value(&default_args.rocksdb_perf_sample_interval)
686 .help(
687 "Controls how often RocksDB read/write performance samples are collected. \
688 Perf samples are collected in 1 / ROCKS_PERF_SAMPLE_INTERVAL sampling rate.",
689 ),
690 )
691 .arg(
692 Arg::with_name("skip_startup_ledger_verification")
693 .long("skip-startup-ledger-verification")
694 .takes_value(false)
695 .help("Skip ledger verification at validator bootup."),
696 )
697 .arg(
698 Arg::with_name("cuda")
699 .long("cuda")
700 .takes_value(false)
701 .help("Use CUDA"),
702 )
703 .arg(
704 clap::Arg::with_name("require_tower")
705 .long("require-tower")
706 .takes_value(false)
707 .help("Refuse to start if saved tower state is not found"),
708 )
709 .arg(
710 Arg::with_name("expected_genesis_hash")
711 .long("expected-genesis-hash")
712 .value_name("HASH")
713 .takes_value(true)
714 .validator(hash_validator)
715 .help("Require the genesis have this hash"),
716 )
717 .arg(
718 Arg::with_name("expected_bank_hash")
719 .long("expected-bank-hash")
720 .value_name("HASH")
721 .takes_value(true)
722 .validator(hash_validator)
723 .help("When wait-for-supermajority <x>, require the bank at <x> to have this hash"),
724 )
725 .arg(
726 Arg::with_name("expected_shred_version")
727 .long("expected-shred-version")
728 .value_name("VERSION")
729 .takes_value(true)
730 .validator(is_parsable::<u16>)
731 .help("Require the shred version be this value"),
732 )
733 .arg(
734 Arg::with_name("logfile")
735 .short("o")
736 .long("log")
737 .value_name("FILE")
738 .takes_value(true)
739 .help(
740 "Redirect logging to the specified file, '-' for standard error. Sending the \
741 SIGUSR1 signal to the validator process will cause it to re-open the log file",
742 ),
743 )
744 .arg(
745 Arg::with_name("wait_for_supermajority")
746 .long("wait-for-supermajority")
747 .requires("expected_bank_hash")
748 .value_name("SLOT")
749 .validator(is_slot)
750 .help(
751 "After processing the ledger and the next slot is SLOT, wait until a \
752 supermajority of stake is visible on gossip before starting PoH",
753 ),
754 )
755 .arg(
756 Arg::with_name("no_wait_for_vote_to_start_leader")
757 .hidden(hidden_unless_forced())
758 .long("no-wait-for-vote-to-start-leader")
759 .help(
760 "If the validator starts up with no ledger, it will wait to start block
761 production until it sees a vote land in a rooted slot. This prevents
762 double signing. Turn off to risk double signing a block.",
763 ),
764 )
765 .arg(
766 Arg::with_name("hard_forks")
767 .long("hard-fork")
768 .value_name("SLOT")
769 .validator(is_slot)
770 .multiple(true)
771 .takes_value(true)
772 .help("Add a hard fork at this slot"),
773 )
774 .arg(
775 Arg::with_name("known_validators")
776 .alias("trusted-validator")
777 .long("known-validator")
778 .validator(is_pubkey)
779 .value_name("VALIDATOR IDENTITY")
780 .multiple(true)
781 .takes_value(true)
782 .help(
783 "A snapshot hash must be published in gossip by this validator to be \
784 accepted. May be specified multiple times. If unspecified any snapshot hash \
785 will be accepted",
786 ),
787 )
788 .arg(
789 Arg::with_name("debug_key")
790 .long("debug-key")
791 .validator(is_pubkey)
792 .value_name("ADDRESS")
793 .multiple(true)
794 .takes_value(true)
795 .help("Log when transactions are processed which reference a given key."),
796 )
797 .arg(
798 Arg::with_name("only_known_rpc")
799 .alias("no-untrusted-rpc")
800 .long("only-known-rpc")
801 .takes_value(false)
802 .requires("known_validators")
803 .help("Use the RPC service of known validators only"),
804 )
805 .arg(
806 Arg::with_name("repair_validators")
807 .long("repair-validator")
808 .validator(is_pubkey)
809 .value_name("VALIDATOR IDENTITY")
810 .multiple(true)
811 .takes_value(true)
812 .help(
813 "A list of validators to request repairs from. If specified, repair will not \
814 request from validators outside this set [default: all validators]",
815 ),
816 )
817 .arg(
818 Arg::with_name("repair_whitelist")
819 .hidden(hidden_unless_forced())
820 .long("repair-whitelist")
821 .validator(is_pubkey)
822 .value_name("VALIDATOR IDENTITY")
823 .multiple(true)
824 .takes_value(true)
825 .help(
826 "A list of validators to prioritize repairs from. If specified, repair \
827 requests from validators in the list will be prioritized over requests from \
828 other validators. [default: all validators]",
829 ),
830 )
831 .arg(
832 Arg::with_name("gossip_validators")
833 .long("gossip-validator")
834 .validator(is_pubkey)
835 .value_name("VALIDATOR IDENTITY")
836 .multiple(true)
837 .takes_value(true)
838 .help(
839 "A list of validators to gossip with. If specified, gossip will not \
840 push/pull from from validators outside this set. [default: all validators]",
841 ),
842 )
843 .arg(
844 Arg::with_name("tpu_coalesce_ms")
845 .long("tpu-coalesce-ms")
846 .value_name("MILLISECS")
847 .takes_value(true)
848 .validator(is_parsable::<u64>)
849 .help("Milliseconds to wait in the TPU receiver for packet coalescing."),
850 )
851 .arg(
852 Arg::with_name("tpu_use_quic")
853 .long("tpu-use-quic")
854 .takes_value(false)
855 .hidden(hidden_unless_forced())
856 .conflicts_with("tpu_disable_quic")
857 .help("Use QUIC to send transactions."),
858 )
859 .arg(
860 Arg::with_name("tpu_disable_quic")
861 .long("tpu-disable-quic")
862 .takes_value(false)
863 .help("Do not use QUIC to send transactions."),
864 )
865 .arg(
866 Arg::with_name("tpu_enable_udp")
867 .long("tpu-enable-udp")
868 .takes_value(false)
869 .help("Enable UDP for receiving/sending transactions."),
870 )
871 .arg(
872 Arg::with_name("tpu_connection_pool_size")
873 .long("tpu-connection-pool-size")
874 .takes_value(true)
875 .default_value(&default_args.tpu_connection_pool_size)
876 .validator(is_parsable::<usize>)
877 .help("Controls the TPU connection pool size per remote address"),
878 )
879 .arg(
880 Arg::with_name("staked_nodes_overrides")
881 .long("staked-nodes-overrides")
882 .value_name("PATH")
883 .takes_value(true)
884 .help(
885 "Provide path to a yaml file with custom overrides for stakes of specific \
886 identities. Overriding the amount of stake this validator considers as valid \
887 for other peers in network. The stake amount is used for calculating the \
888 number of QUIC streams permitted from the peer and vote packet sender stage. \
889 Format of the file: `staked_map_id: {<pubkey>: <MLN stake amount>}",
890 ),
891 )
892 .arg(
893 Arg::with_name("bind_address")
894 .long("bind-address")
895 .value_name("HOST")
896 .takes_value(true)
897 .validator(miraland_net_utils::is_host)
898 .default_value(&default_args.bind_address)
899 .help("IP address to bind the validator ports"),
900 )
901 .arg(
902 Arg::with_name("rpc_bind_address")
903 .long("rpc-bind-address")
904 .value_name("HOST")
905 .takes_value(true)
906 .validator(miraland_net_utils::is_host)
907 .help(
908 "IP address to bind the RPC port [default: 127.0.0.1 if --private-rpc is \
909 present, otherwise use --bind-address]",
910 ),
911 )
912 .arg(
913 Arg::with_name("rpc_threads")
914 .long("rpc-threads")
915 .value_name("NUMBER")
916 .validator(is_parsable::<usize>)
917 .takes_value(true)
918 .default_value(&default_args.rpc_threads)
919 .help("Number of threads to use for servicing RPC requests"),
920 )
921 .arg(
922 Arg::with_name("rpc_niceness_adj")
923 .long("rpc-niceness-adjustment")
924 .value_name("ADJUSTMENT")
925 .takes_value(true)
926 .validator(miraland_perf::thread::is_niceness_adjustment_valid)
927 .default_value(&default_args.rpc_niceness_adjustment)
928 .help(
929 "Add this value to niceness of RPC threads. Negative value increases \
930 priority, positive value decreases priority.",
931 ),
932 )
933 .arg(
934 Arg::with_name("rpc_bigtable_timeout")
935 .long("rpc-bigtable-timeout")
936 .value_name("SECONDS")
937 .validator(is_parsable::<u64>)
938 .takes_value(true)
939 .default_value(&default_args.rpc_bigtable_timeout)
940 .help("Number of seconds before timing out RPC requests backed by BigTable"),
941 )
942 .arg(
943 Arg::with_name("rpc_bigtable_instance_name")
944 .long("rpc-bigtable-instance-name")
945 .takes_value(true)
946 .value_name("INSTANCE_NAME")
947 .default_value(&default_args.rpc_bigtable_instance_name)
948 .help("Name of the Bigtable instance to upload to"),
949 )
950 .arg(
951 Arg::with_name("rpc_bigtable_app_profile_id")
952 .long("rpc-bigtable-app-profile-id")
953 .takes_value(true)
954 .value_name("APP_PROFILE_ID")
955 .default_value(&default_args.rpc_bigtable_app_profile_id)
956 .help("Bigtable application profile id to use in requests"),
957 )
958 .arg(
959 Arg::with_name("rpc_bigtable_max_message_size")
960 .long("rpc-bigtable-max-message-size")
961 .value_name("BYTES")
962 .validator(is_parsable::<usize>)
963 .takes_value(true)
964 .default_value(&default_args.rpc_bigtable_max_message_size)
965 .help("Max encoding and decoding message size used in Bigtable Grpc client"),
966 )
967 .arg(
968 Arg::with_name("rpc_pubsub_worker_threads")
969 .long("rpc-pubsub-worker-threads")
970 .takes_value(true)
971 .value_name("NUMBER")
972 .validator(is_parsable::<usize>)
973 .default_value(&default_args.rpc_pubsub_worker_threads)
974 .help("PubSub worker threads"),
975 )
976 .arg(
977 Arg::with_name("rpc_pubsub_enable_block_subscription")
978 .long("rpc-pubsub-enable-block-subscription")
979 .requires("enable_rpc_transaction_history")
980 .takes_value(false)
981 .help("Enable the unstable RPC PubSub `blockSubscribe` subscription"),
982 )
983 .arg(
984 Arg::with_name("rpc_pubsub_enable_vote_subscription")
985 .long("rpc-pubsub-enable-vote-subscription")
986 .takes_value(false)
987 .help("Enable the unstable RPC PubSub `voteSubscribe` subscription"),
988 )
989 .arg(
990 Arg::with_name("rpc_pubsub_max_connections")
991 .long("rpc-pubsub-max-connections")
992 .value_name("NUMBER")
993 .takes_value(true)
994 .validator(is_parsable::<usize>)
995 .hidden(hidden_unless_forced())
996 .help(
997 "The maximum number of connections that RPC PubSub will support. This is a \
998 hard limit and no new connections beyond this limit can be made until an old \
999 connection is dropped. (Obsolete)",
1000 ),
1001 )
1002 .arg(
1003 Arg::with_name("rpc_pubsub_max_fragment_size")
1004 .long("rpc-pubsub-max-fragment-size")
1005 .value_name("BYTES")
1006 .takes_value(true)
1007 .validator(is_parsable::<usize>)
1008 .hidden(hidden_unless_forced())
1009 .help(
1010 "The maximum length in bytes of acceptable incoming frames. Messages longer \
1011 than this will be rejected. (Obsolete)",
1012 ),
1013 )
1014 .arg(
1015 Arg::with_name("rpc_pubsub_max_in_buffer_capacity")
1016 .long("rpc-pubsub-max-in-buffer-capacity")
1017 .value_name("BYTES")
1018 .takes_value(true)
1019 .validator(is_parsable::<usize>)
1020 .hidden(hidden_unless_forced())
1021 .help(
1022 "The maximum size in bytes to which the incoming websocket buffer can grow. \
1023 (Obsolete)",
1024 ),
1025 )
1026 .arg(
1027 Arg::with_name("rpc_pubsub_max_out_buffer_capacity")
1028 .long("rpc-pubsub-max-out-buffer-capacity")
1029 .value_name("BYTES")
1030 .takes_value(true)
1031 .validator(is_parsable::<usize>)
1032 .hidden(hidden_unless_forced())
1033 .help(
1034 "The maximum size in bytes to which the outgoing websocket buffer can grow. \
1035 (Obsolete)",
1036 ),
1037 )
1038 .arg(
1039 Arg::with_name("rpc_pubsub_max_active_subscriptions")
1040 .long("rpc-pubsub-max-active-subscriptions")
1041 .takes_value(true)
1042 .value_name("NUMBER")
1043 .validator(is_parsable::<usize>)
1044 .default_value(&default_args.rpc_pubsub_max_active_subscriptions)
1045 .help(
1046 "The maximum number of active subscriptions that RPC PubSub will accept \
1047 across all connections.",
1048 ),
1049 )
1050 .arg(
1051 Arg::with_name("rpc_pubsub_queue_capacity_items")
1052 .long("rpc-pubsub-queue-capacity-items")
1053 .takes_value(true)
1054 .value_name("NUMBER")
1055 .validator(is_parsable::<usize>)
1056 .default_value(&default_args.rpc_pubsub_queue_capacity_items)
1057 .help(
1058 "The maximum number of notifications that RPC PubSub will store across all \
1059 connections.",
1060 ),
1061 )
1062 .arg(
1063 Arg::with_name("rpc_pubsub_queue_capacity_bytes")
1064 .long("rpc-pubsub-queue-capacity-bytes")
1065 .takes_value(true)
1066 .value_name("BYTES")
1067 .validator(is_parsable::<usize>)
1068 .default_value(&default_args.rpc_pubsub_queue_capacity_bytes)
1069 .help(
1070 "The maximum total size of notifications that RPC PubSub will store across \
1071 all connections.",
1072 ),
1073 )
1074 .arg(
1075 Arg::with_name("rpc_pubsub_notification_threads")
1076 .long("rpc-pubsub-notification-threads")
1077 .requires("full_rpc_api")
1078 .takes_value(true)
1079 .value_name("NUM_THREADS")
1080 .validator(is_parsable::<usize>)
1081 .help(
1082 "The maximum number of threads that RPC PubSub will use for generating \
1083 notifications. 0 will disable RPC PubSub notifications",
1084 ),
1085 )
1086 .arg(
1087 Arg::with_name("rpc_send_transaction_retry_ms")
1088 .long("rpc-send-retry-ms")
1089 .value_name("MILLISECS")
1090 .takes_value(true)
1091 .validator(is_parsable::<u64>)
1092 .default_value(&default_args.rpc_send_transaction_retry_ms)
1093 .help("The rate at which transactions sent via rpc service are retried."),
1094 )
1095 .arg(
1096 Arg::with_name("rpc_send_transaction_batch_ms")
1097 .long("rpc-send-batch-ms")
1098 .value_name("MILLISECS")
1099 .hidden(hidden_unless_forced())
1100 .takes_value(true)
1101 .validator(|s| is_within_range(s, 1..=MAX_BATCH_SEND_RATE_MS))
1102 .default_value(&default_args.rpc_send_transaction_batch_ms)
1103 .help("The rate at which transactions sent via rpc service are sent in batch."),
1104 )
1105 .arg(
1106 Arg::with_name("rpc_send_transaction_leader_forward_count")
1107 .long("rpc-send-leader-count")
1108 .value_name("NUMBER")
1109 .takes_value(true)
1110 .validator(is_parsable::<u64>)
1111 .default_value(&default_args.rpc_send_transaction_leader_forward_count)
1112 .help(
1113 "The number of upcoming leaders to which to forward transactions sent via rpc \
1114 service.",
1115 ),
1116 )
1117 .arg(
1118 Arg::with_name("rpc_send_transaction_default_max_retries")
1119 .long("rpc-send-default-max-retries")
1120 .value_name("NUMBER")
1121 .takes_value(true)
1122 .validator(is_parsable::<usize>)
1123 .help(
1124 "The maximum number of transaction broadcast retries when unspecified by the \
1125 request, otherwise retried until expiration.",
1126 ),
1127 )
1128 .arg(
1129 Arg::with_name("rpc_send_transaction_service_max_retries")
1130 .long("rpc-send-service-max-retries")
1131 .value_name("NUMBER")
1132 .takes_value(true)
1133 .validator(is_parsable::<usize>)
1134 .default_value(&default_args.rpc_send_transaction_service_max_retries)
1135 .help(
1136 "The maximum number of transaction broadcast retries, regardless of requested \
1137 value.",
1138 ),
1139 )
1140 .arg(
1141 Arg::with_name("rpc_send_transaction_batch_size")
1142 .long("rpc-send-batch-size")
1143 .value_name("NUMBER")
1144 .hidden(hidden_unless_forced())
1145 .takes_value(true)
1146 .validator(|s| is_within_range(s, 1..=MAX_TRANSACTION_BATCH_SIZE))
1147 .default_value(&default_args.rpc_send_transaction_batch_size)
1148 .help("The size of transactions to be sent in batch."),
1149 )
1150 .arg(
1151 Arg::with_name("rpc_send_transaction_retry_pool_max_size")
1152 .long("rpc-send-transaction-retry-pool-max-size")
1153 .value_name("NUMBER")
1154 .takes_value(true)
1155 .validator(is_parsable::<usize>)
1156 .default_value(&default_args.rpc_send_transaction_retry_pool_max_size)
1157 .help("The maximum size of transactions retry pool."),
1158 )
1159 .arg(
1160 Arg::with_name("rpc_scan_and_fix_roots")
1161 .long("rpc-scan-and-fix-roots")
1162 .takes_value(false)
1163 .requires("enable_rpc_transaction_history")
1164 .help("Verifies blockstore roots on boot and fixes any gaps"),
1165 )
1166 .arg(
1167 Arg::with_name("rpc_max_request_body_size")
1168 .long("rpc-max-request-body-size")
1169 .value_name("BYTES")
1170 .takes_value(true)
1171 .validator(is_parsable::<usize>)
1172 .default_value(&default_args.rpc_max_request_body_size)
1173 .help("The maximum request body size accepted by rpc service"),
1174 )
1175 .arg(
1176 Arg::with_name("enable_accountsdb_repl")
1177 .long("enable-accountsdb-repl")
1178 .takes_value(false)
1179 .hidden(hidden_unless_forced())
1180 .help("Enable AccountsDb Replication"),
1181 )
1182 .arg(
1183 Arg::with_name("accountsdb_repl_bind_address")
1184 .long("accountsdb-repl-bind-address")
1185 .value_name("HOST")
1186 .takes_value(true)
1187 .validator(miraland_net_utils::is_host)
1188 .hidden(hidden_unless_forced())
1189 .help(
1190 "IP address to bind the AccountsDb Replication port [default: use \
1191 --bind-address]",
1192 ),
1193 )
1194 .arg(
1195 Arg::with_name("accountsdb_repl_port")
1196 .long("accountsdb-repl-port")
1197 .value_name("PORT")
1198 .takes_value(true)
1199 .validator(port_validator)
1200 .hidden(hidden_unless_forced())
1201 .help("Enable AccountsDb Replication Service on this port"),
1202 )
1203 .arg(
1204 Arg::with_name("accountsdb_repl_threads")
1205 .long("accountsdb-repl-threads")
1206 .value_name("NUMBER")
1207 .validator(is_parsable::<usize>)
1208 .takes_value(true)
1209 .default_value(&default_args.accountsdb_repl_threads)
1210 .hidden(hidden_unless_forced())
1211 .help("Number of threads to use for servicing AccountsDb Replication requests"),
1212 )
1213 .arg(
1214 Arg::with_name("geyser_plugin_config")
1215 .long("geyser-plugin-config")
1216 .alias("accountsdb-plugin-config")
1217 .value_name("FILE")
1218 .takes_value(true)
1219 .multiple(true)
1220 .help("Specify the configuration file for the Geyser plugin."),
1221 )
1222 .arg(
1223 Arg::with_name("snapshot_archive_format")
1224 .long("snapshot-archive-format")
1225 .alias("snapshot-compression") .possible_values(SUPPORTED_ARCHIVE_COMPRESSION)
1227 .default_value(&default_args.snapshot_archive_format)
1228 .value_name("ARCHIVE_TYPE")
1229 .takes_value(true)
1230 .help("Snapshot archive format to use."),
1231 )
1232 .arg(
1233 Arg::with_name("max_genesis_archive_unpacked_size")
1234 .long("max-genesis-archive-unpacked-size")
1235 .value_name("NUMBER")
1236 .takes_value(true)
1237 .default_value(&default_args.genesis_archive_unpacked_size)
1238 .help("maximum total uncompressed file size of downloaded genesis archive"),
1239 )
1240 .arg(
1241 Arg::with_name("wal_recovery_mode")
1242 .long("wal-recovery-mode")
1243 .value_name("MODE")
1244 .takes_value(true)
1245 .possible_values(&[
1246 "tolerate_corrupted_tail_records",
1247 "absolute_consistency",
1248 "point_in_time",
1249 "skip_any_corrupted_record",
1250 ])
1251 .help("Mode to recovery the ledger db write ahead log."),
1252 )
1253 .arg(
1254 Arg::with_name("poh_pinned_cpu_core")
1255 .hidden(hidden_unless_forced())
1256 .long("experimental-poh-pinned-cpu-core")
1257 .takes_value(true)
1258 .value_name("CPU_CORE_INDEX")
1259 .validator(|s| {
1260 let core_index = usize::from_str(&s).map_err(|e| e.to_string())?;
1261 let max_index = core_affinity::get_core_ids()
1262 .map(|cids| cids.len() - 1)
1263 .unwrap_or(0);
1264 if core_index > max_index {
1265 return Err(format!("core index must be in the range [0, {max_index}]"));
1266 }
1267 Ok(())
1268 })
1269 .help("EXPERIMENTAL: Specify which CPU core PoH is pinned to"),
1270 )
1271 .arg(
1272 Arg::with_name("poh_hashes_per_batch")
1273 .hidden(hidden_unless_forced())
1274 .long("poh-hashes-per-batch")
1275 .takes_value(true)
1276 .value_name("NUM")
1277 .help("Specify hashes per batch in PoH service"),
1278 )
1279 .arg(
1280 Arg::with_name("process_ledger_before_services")
1281 .long("process-ledger-before-services")
1282 .hidden(hidden_unless_forced())
1283 .help("Process the local ledger fully before starting networking services"),
1284 )
1285 .arg(
1286 Arg::with_name("account_indexes")
1287 .long("account-index")
1288 .takes_value(true)
1289 .multiple(true)
1290 .possible_values(&["program-id", "solarti-token-owner", "solarti-token-mint"])
1291 .value_name("INDEX")
1292 .help("Enable an accounts index, indexed by the selected account field"),
1293 )
1294 .arg(
1295 Arg::with_name("account_index_exclude_key")
1296 .long(EXCLUDE_KEY)
1297 .takes_value(true)
1298 .validator(is_pubkey)
1299 .multiple(true)
1300 .value_name("KEY")
1301 .help("When account indexes are enabled, exclude this key from the index."),
1302 )
1303 .arg(
1304 Arg::with_name("account_index_include_key")
1305 .long(INCLUDE_KEY)
1306 .takes_value(true)
1307 .validator(is_pubkey)
1308 .conflicts_with("account_index_exclude_key")
1309 .multiple(true)
1310 .value_name("KEY")
1311 .help(
1312 "When account indexes are enabled, only include specific keys in the index. \
1313 This overrides --account-index-exclude-key.",
1314 ),
1315 )
1316 .arg(
1317 Arg::with_name("accounts_db_verify_refcounts")
1318 .long("accounts-db-verify-refcounts")
1319 .help(
1320 "Debug option to scan all append vecs and verify account index refcounts \
1321 prior to clean",
1322 )
1323 .hidden(hidden_unless_forced()),
1324 )
1325 .arg(
1326 Arg::with_name("accounts_db_test_skip_rewrites")
1327 .long("accounts-db-test-skip-rewrites")
1328 .help(
1329 "Debug option to skip rewrites for rent-exempt accounts but still add them in \
1330 bank delta hash calculation",
1331 )
1332 .hidden(hidden_unless_forced()),
1333 )
1334 .arg(
1335 Arg::with_name("no_skip_initial_accounts_db_clean")
1336 .long("no-skip-initial-accounts-db-clean")
1337 .help("Do not skip the initial cleaning of accounts when verifying snapshot bank")
1338 .hidden(hidden_unless_forced())
1339 .conflicts_with("accounts_db_skip_shrink"),
1340 )
1341 .arg(
1342 Arg::with_name("accounts_db_create_ancient_storage_packed")
1343 .long("accounts-db-create-ancient-storage-packed")
1344 .help("Create ancient storages in one shot instead of appending.")
1345 .hidden(hidden_unless_forced()),
1346 )
1347 .arg(
1348 Arg::with_name("accounts_db_ancient_append_vecs")
1349 .long("accounts-db-ancient-append-vecs")
1350 .value_name("SLOT-OFFSET")
1351 .validator(is_parsable::<i64>)
1352 .takes_value(true)
1353 .help(
1354 "AppendVecs that are older than (slots_per_epoch - SLOT-OFFSET) are squashed \
1355 together.",
1356 )
1357 .hidden(hidden_unless_forced()),
1358 )
1359 .arg(
1360 Arg::with_name("accounts_db_cache_limit_mb")
1361 .long("accounts-db-cache-limit-mb")
1362 .value_name("MEGABYTES")
1363 .validator(is_parsable::<u64>)
1364 .takes_value(true)
1365 .help(
1366 "How large the write cache for account data can become. If this is exceeded, \
1367 the cache is flushed more aggressively.",
1368 ),
1369 )
1370 .arg(
1371 Arg::with_name("accounts_index_scan_results_limit_mb")
1372 .long("accounts-index-scan-results-limit-mb")
1373 .value_name("MEGABYTES")
1374 .validator(is_parsable::<usize>)
1375 .takes_value(true)
1376 .help(
1377 "How large accumulated results from an accounts index scan can become. If \
1378 this is exceeded, the scan aborts.",
1379 ),
1380 )
1381 .arg(
1382 Arg::with_name("accounts_index_memory_limit_mb")
1383 .long("accounts-index-memory-limit-mb")
1384 .value_name("MEGABYTES")
1385 .validator(is_parsable::<usize>)
1386 .takes_value(true)
1387 .help(
1388 "How much memory the accounts index can consume. If this is exceeded, some \
1389 account index entries will be stored on disk.",
1390 ),
1391 )
1392 .arg(
1393 Arg::with_name("accounts_index_bins")
1394 .long("accounts-index-bins")
1395 .value_name("BINS")
1396 .validator(is_pow2)
1397 .takes_value(true)
1398 .help("Number of bins to divide the accounts index into"),
1399 )
1400 .arg(
1401 Arg::with_name("partitioned_epoch_rewards_compare_calculation")
1402 .long("partitioned-epoch-rewards-compare-calculation")
1403 .takes_value(false)
1404 .help(
1405 "Do normal epoch rewards distribution, but also calculate rewards using the \
1406 partitioned rewards code path and compare the resulting vote and stake \
1407 accounts",
1408 )
1409 .hidden(hidden_unless_forced()),
1410 )
1411 .arg(
1412 Arg::with_name("partitioned_epoch_rewards_force_enable_single_slot")
1413 .long("partitioned-epoch-rewards-force-enable-single-slot")
1414 .takes_value(false)
1415 .help(
1416 "Force the partitioned rewards distribution, but distribute all rewards in \
1417 the first slot in the epoch. This should match consensus with the normal \
1418 rewards distribution.",
1419 )
1420 .conflicts_with("partitioned_epoch_rewards_compare_calculation")
1421 .hidden(hidden_unless_forced()),
1422 )
1423 .arg(
1424 Arg::with_name("accounts_index_path")
1425 .long("accounts-index-path")
1426 .value_name("PATH")
1427 .takes_value(true)
1428 .multiple(true)
1429 .help(
1430 "Persistent accounts-index location. \
1431 May be specified multiple times. \
1432 [default: <LEDGER>/accounts_index]",
1433 ),
1434 )
1435 .arg(
1436 Arg::with_name("accounts_db_test_hash_calculation")
1437 .long("accounts-db-test-hash-calculation")
1438 .help(
1439 "Enables testing of hash calculation using stores in AccountsHashVerifier. \
1440 This has a computational cost.",
1441 ),
1442 )
1443 .arg(
1444 Arg::with_name("accounts_shrink_optimize_total_space")
1445 .long("accounts-shrink-optimize-total-space")
1446 .takes_value(true)
1447 .value_name("BOOLEAN")
1448 .default_value(&default_args.accounts_shrink_optimize_total_space)
1449 .help(
1450 "When this is set to true, the system will shrink the most sparse accounts \
1451 and when the overall shrink ratio is above the specified \
1452 accounts-shrink-ratio, the shrink will stop and it will skip all other less \
1453 sparse accounts.",
1454 ),
1455 )
1456 .arg(
1457 Arg::with_name("accounts_shrink_ratio")
1458 .long("accounts-shrink-ratio")
1459 .takes_value(true)
1460 .value_name("RATIO")
1461 .default_value(&default_args.accounts_shrink_ratio)
1462 .help(
1463 "Specifies the shrink ratio for the accounts to be shrunk. The shrink ratio \
1464 is defined as the ratio of the bytes alive over the total bytes used. If \
1465 the account's shrink ratio is less than this ratio it becomes a candidate \
1466 for shrinking. The value must between 0. and 1.0 inclusive.",
1467 ),
1468 )
1469 .arg(
1470 Arg::with_name("allow_private_addr")
1471 .long("allow-private-addr")
1472 .takes_value(false)
1473 .help("Allow contacting private ip addresses")
1474 .hidden(hidden_unless_forced()),
1475 )
1476 .arg(
1477 Arg::with_name("log_messages_bytes_limit")
1478 .long("log-messages-bytes-limit")
1479 .takes_value(true)
1480 .validator(is_parsable::<usize>)
1481 .value_name("BYTES")
1482 .help("Maximum number of bytes written to the program log before truncation"),
1483 )
1484 .arg(
1485 Arg::with_name("replay_slots_concurrently")
1486 .long("replay-slots-concurrently")
1487 .help("Allow concurrent replay of slots on different forks"),
1488 )
1489 .arg(
1490 Arg::with_name("banking_trace_dir_byte_limit")
1491 .long("enable-banking-trace")
1494 .value_name("BYTES")
1495 .validator(is_parsable::<DirByteLimit>)
1496 .takes_value(true)
1497 .default_value(&default_args.banking_trace_dir_byte_limit)
1503 .help(
1504 "Enables the banking trace explicitly, which is enabled by default and writes \
1505 trace files for simulate-leader-blocks, retaining up to the default or \
1506 specified total bytes in the ledger. This flag can be used to override its \
1507 byte limit.",
1508 ),
1509 )
1510 .arg(
1511 Arg::with_name("disable_banking_trace")
1512 .long("disable-banking-trace")
1513 .conflicts_with("banking_trace_dir_byte_limit")
1514 .takes_value(false)
1515 .help("Disables the banking trace"),
1516 )
1517 .arg(
1518 Arg::with_name("block_verification_method")
1519 .long("block-verification-method")
1520 .hidden(hidden_unless_forced())
1521 .value_name("METHOD")
1522 .takes_value(true)
1523 .possible_values(BlockVerificationMethod::cli_names())
1524 .help(BlockVerificationMethod::cli_message()),
1525 )
1526 .arg(
1527 Arg::with_name("block_production_method")
1528 .long("block-production-method")
1529 .value_name("METHOD")
1530 .takes_value(true)
1531 .possible_values(BlockProductionMethod::cli_names())
1532 .help(BlockProductionMethod::cli_message()),
1533 )
1534 .arg(
1535 Arg::with_name("unified_scheduler_handler_threads")
1536 .long("unified-scheduler-handler-threads")
1537 .hidden(hidden_unless_forced())
1538 .value_name("COUNT")
1539 .takes_value(true)
1540 .validator(|s| is_within_range(s, 1..))
1541 .help(DefaultSchedulerPool::cli_message()),
1542 )
1543 .arg(
1544 Arg::with_name("wen_restart")
1545 .long("wen-restart")
1546 .hidden(hidden_unless_forced())
1547 .value_name("DIR")
1548 .takes_value(true)
1549 .required(false)
1550 .conflicts_with("wait_for_supermajority")
1551 .help(
1552 "When specified, the validator will enter Wen Restart mode which
1553 pauses normal activity. Validators in this mode will gossip their last
1554 vote to reach consensus on a safe restart slot and repair all blocks
1555 on the selected fork. The safe slot will be a descendant of the latest
1556 optimistically confirmed slot to ensure we do not roll back any
1557 optimistically confirmed slots.
1558
1559 The progress in this mode will be saved in the file location provided.
1560 If consensus is reached, the validator will automatically exit and then
1561 execute wait_for_supermajority logic so the cluster will resume execution.
1562 The progress file will be kept around for future debugging.
1563
1564 After the cluster resumes normal operation, the validator arguments can
1565 be adjusted to remove --wen_restart and update expected_shred_version to
1566 the new shred_version agreed on in the consensus.
1567
1568 If wen_restart fails, refer to the progress file (in proto3 format) for
1569 further debugging.
1570 ",
1571 ),
1572 )
1573 .args(&get_deprecated_arguments())
1574 .after_help("The default subcommand is run")
1575 .subcommand(
1576 SubCommand::with_name("exit")
1577 .about("Send an exit request to the validator")
1578 .arg(
1579 Arg::with_name("force")
1580 .short("f")
1581 .long("force")
1582 .takes_value(false)
1583 .help(
1584 "Request the validator exit immediately instead of waiting for a \
1585 restart window",
1586 ),
1587 )
1588 .arg(
1589 Arg::with_name("monitor")
1590 .short("m")
1591 .long("monitor")
1592 .takes_value(false)
1593 .help("Monitor the validator after sending the exit request"),
1594 )
1595 .arg(
1596 Arg::with_name("min_idle_time")
1597 .long("min-idle-time")
1598 .takes_value(true)
1599 .validator(is_parsable::<usize>)
1600 .value_name("MINUTES")
1601 .default_value(&default_args.exit_min_idle_time)
1602 .help(
1603 "Minimum time that the validator should not be leader before \
1604 restarting",
1605 ),
1606 )
1607 .arg(
1608 Arg::with_name("max_delinquent_stake")
1609 .long("max-delinquent-stake")
1610 .takes_value(true)
1611 .validator(is_valid_percentage)
1612 .default_value(&default_args.exit_max_delinquent_stake)
1613 .value_name("PERCENT")
1614 .help("The maximum delinquent stake % permitted for an exit"),
1615 )
1616 .arg(
1617 Arg::with_name("skip_new_snapshot_check")
1618 .long("skip-new-snapshot-check")
1619 .help("Skip check for a new snapshot"),
1620 )
1621 .arg(
1622 Arg::with_name("skip_health_check")
1623 .long("skip-health-check")
1624 .help("Skip health check"),
1625 ),
1626 )
1627 .subcommand(
1628 SubCommand::with_name("authorized-voter")
1629 .about("Adjust the validator authorized voters")
1630 .setting(AppSettings::SubcommandRequiredElseHelp)
1631 .setting(AppSettings::InferSubcommands)
1632 .subcommand(
1633 SubCommand::with_name("add")
1634 .about("Add an authorized voter")
1635 .arg(
1636 Arg::with_name("authorized_voter_keypair")
1637 .index(1)
1638 .value_name("KEYPAIR")
1639 .required(false)
1640 .takes_value(true)
1641 .validator(is_keypair)
1642 .help(
1643 "Path to keypair of the authorized voter to add [default: \
1644 read JSON keypair from stdin]",
1645 ),
1646 )
1647 .after_help(
1648 "Note: the new authorized voter only applies to the currently running \
1649 validator instance",
1650 ),
1651 )
1652 .subcommand(
1653 SubCommand::with_name("remove-all")
1654 .about("Remove all authorized voters")
1655 .after_help(
1656 "Note: the removal only applies to the currently running validator \
1657 instance",
1658 ),
1659 ),
1660 )
1661 .subcommand(
1662 SubCommand::with_name("contact-info")
1663 .about("Display the validator's contact info")
1664 .arg(
1665 Arg::with_name("output")
1666 .long("output")
1667 .takes_value(true)
1668 .value_name("MODE")
1669 .possible_values(&["json", "json-compact"])
1670 .help("Output display mode"),
1671 ),
1672 )
1673 .subcommand(
1674 SubCommand::with_name("repair-shred-from-peer")
1675 .about("Request a repair from the specified validator")
1676 .arg(
1677 Arg::with_name("pubkey")
1678 .long("pubkey")
1679 .value_name("PUBKEY")
1680 .required(false)
1681 .takes_value(true)
1682 .validator(is_pubkey)
1683 .help("Identity pubkey of the validator to repair from"),
1684 )
1685 .arg(
1686 Arg::with_name("slot")
1687 .long("slot")
1688 .value_name("SLOT")
1689 .takes_value(true)
1690 .validator(is_parsable::<u64>)
1691 .help("Slot to repair"),
1692 )
1693 .arg(
1694 Arg::with_name("shred")
1695 .long("shred")
1696 .value_name("SHRED")
1697 .takes_value(true)
1698 .validator(is_parsable::<u64>)
1699 .help("Shred to repair"),
1700 ),
1701 )
1702 .subcommand(
1703 SubCommand::with_name("repair-whitelist")
1704 .about("Manage the validator's repair protocol whitelist")
1705 .setting(AppSettings::SubcommandRequiredElseHelp)
1706 .setting(AppSettings::InferSubcommands)
1707 .subcommand(
1708 SubCommand::with_name("get")
1709 .about("Display the validator's repair protocol whitelist")
1710 .arg(
1711 Arg::with_name("output")
1712 .long("output")
1713 .takes_value(true)
1714 .value_name("MODE")
1715 .possible_values(&["json", "json-compact"])
1716 .help("Output display mode"),
1717 ),
1718 )
1719 .subcommand(
1720 SubCommand::with_name("set")
1721 .about("Set the validator's repair protocol whitelist")
1722 .setting(AppSettings::ArgRequiredElseHelp)
1723 .arg(
1724 Arg::with_name("whitelist")
1725 .long("whitelist")
1726 .validator(is_pubkey)
1727 .value_name("VALIDATOR IDENTITY")
1728 .multiple(true)
1729 .takes_value(true)
1730 .help("Set the validator's repair protocol whitelist"),
1731 )
1732 .after_help(
1733 "Note: repair protocol whitelist changes only apply to the currently \
1734 running validator instance",
1735 ),
1736 )
1737 .subcommand(
1738 SubCommand::with_name("remove-all")
1739 .about("Clear the validator's repair protocol whitelist")
1740 .after_help(
1741 "Note: repair protocol whitelist changes only apply to the currently \
1742 running validator instance",
1743 ),
1744 ),
1745 )
1746 .subcommand(
1747 SubCommand::with_name("init").about("Initialize the ledger directory then exit"),
1748 )
1749 .subcommand(SubCommand::with_name("monitor").about("Monitor the validator"))
1750 .subcommand(SubCommand::with_name("run").about("Run the validator"))
1751 .subcommand(
1752 SubCommand::with_name("plugin")
1753 .about("Manage and view geyser plugins")
1754 .setting(AppSettings::SubcommandRequiredElseHelp)
1755 .setting(AppSettings::InferSubcommands)
1756 .subcommand(
1757 SubCommand::with_name("list").about("List all current running gesyer plugins"),
1758 )
1759 .subcommand(
1760 SubCommand::with_name("unload")
1761 .about(
1762 "Unload a particular gesyer plugin. You must specify the gesyer \
1763 plugin name",
1764 )
1765 .arg(Arg::with_name("name").required(true).takes_value(true)),
1766 )
1767 .subcommand(
1768 SubCommand::with_name("reload")
1769 .about(
1770 "Reload a particular gesyer plugin. You must specify the gesyer \
1771 plugin name and the new config path",
1772 )
1773 .arg(Arg::with_name("name").required(true).takes_value(true))
1774 .arg(Arg::with_name("config").required(true).takes_value(true)),
1775 )
1776 .subcommand(
1777 SubCommand::with_name("load")
1778 .about(
1779 "Load a new gesyer plugin. You must specify the config path. Fails if \
1780 overwriting (use reload)",
1781 )
1782 .arg(Arg::with_name("config").required(true).takes_value(true)),
1783 ),
1784 )
1785 .subcommand(
1786 SubCommand::with_name("set-identity")
1787 .about("Set the validator identity")
1788 .arg(
1789 Arg::with_name("identity")
1790 .index(1)
1791 .value_name("KEYPAIR")
1792 .required(false)
1793 .takes_value(true)
1794 .validator(is_keypair)
1795 .help(
1796 "Path to validator identity keypair [default: read JSON keypair from \
1797 stdin]",
1798 ),
1799 )
1800 .arg(
1801 clap::Arg::with_name("require_tower")
1802 .long("require-tower")
1803 .takes_value(false)
1804 .help(
1805 "Refuse to set the validator identity if saved tower state is not \
1806 found",
1807 ),
1808 )
1809 .after_help(
1810 "Note: the new identity only applies to the currently running validator \
1811 instance",
1812 ),
1813 )
1814 .subcommand(
1815 SubCommand::with_name("set-log-filter")
1816 .about("Adjust the validator log filter")
1817 .arg(
1818 Arg::with_name("filter").takes_value(true).index(1).help(
1819 "New filter using the same format as the RUST_LOG environment variable",
1820 ),
1821 )
1822 .after_help(
1823 "Note: the new filter only applies to the currently running validator instance",
1824 ),
1825 )
1826 .subcommand(
1827 SubCommand::with_name("staked-nodes-overrides")
1828 .about("Overrides stakes of specific node identities.")
1829 .arg(
1830 Arg::with_name("path")
1831 .value_name("PATH")
1832 .takes_value(true)
1833 .required(true)
1834 .help(
1835 "Provide path to a file with custom overrides for stakes of specific \
1836 validator identities.",
1837 ),
1838 )
1839 .after_help(
1840 "Note: the new staked nodes overrides only applies to the currently running \
1841 validator instance",
1842 ),
1843 )
1844 .subcommand(
1845 SubCommand::with_name("wait-for-restart-window")
1846 .about("Monitor the validator for a good time to restart")
1847 .arg(
1848 Arg::with_name("min_idle_time")
1849 .long("min-idle-time")
1850 .takes_value(true)
1851 .validator(is_parsable::<usize>)
1852 .value_name("MINUTES")
1853 .default_value(&default_args.wait_for_restart_window_min_idle_time)
1854 .help(
1855 "Minimum time that the validator should not be leader before \
1856 restarting",
1857 ),
1858 )
1859 .arg(
1860 Arg::with_name("identity")
1861 .long("identity")
1862 .value_name("ADDRESS")
1863 .takes_value(true)
1864 .validator(is_pubkey_or_keypair)
1865 .help("Validator identity to monitor [default: your validator]"),
1866 )
1867 .arg(
1868 Arg::with_name("max_delinquent_stake")
1869 .long("max-delinquent-stake")
1870 .takes_value(true)
1871 .validator(is_valid_percentage)
1872 .default_value(&default_args.wait_for_restart_window_max_delinquent_stake)
1873 .value_name("PERCENT")
1874 .help("The maximum delinquent stake % permitted for a restart"),
1875 )
1876 .arg(
1877 Arg::with_name("skip_new_snapshot_check")
1878 .long("skip-new-snapshot-check")
1879 .help("Skip check for a new snapshot"),
1880 )
1881 .arg(
1882 Arg::with_name("skip_health_check")
1883 .long("skip-health-check")
1884 .help("Skip health check"),
1885 )
1886 .after_help(
1887 "Note: If this command exits with a non-zero status then this not a good time \
1888 for a restart",
1889 ),
1890 )
1891 .subcommand(
1892 SubCommand::with_name("set-public-address")
1893 .about("Specify addresses to advertise in gossip")
1894 .arg(
1895 Arg::with_name("tpu_addr")
1896 .long("tpu")
1897 .value_name("HOST:PORT")
1898 .takes_value(true)
1899 .validator(miraland_net_utils::is_host_port)
1900 .help("TPU address to advertise in gossip"),
1901 )
1902 .arg(
1903 Arg::with_name("tpu_forwards_addr")
1904 .long("tpu-forwards")
1905 .value_name("HOST:PORT")
1906 .takes_value(true)
1907 .validator(miraland_net_utils::is_host_port)
1908 .help("TPU Forwards address to advertise in gossip"),
1909 )
1910 .group(
1911 ArgGroup::with_name("set_public_address_details")
1912 .args(&["tpu_addr", "tpu_forwards_addr"])
1913 .required(true)
1914 .multiple(true),
1915 )
1916 .after_help("Note: At least one arg must be used. Using multiple is ok"),
1917 );
1918}
1919
1920struct DeprecatedArg {
1923 arg: Arg<'static, 'static>,
1928
1929 replaced_by: Option<&'static str>,
1933
1934 usage_warning: Option<&'static str>,
1938}
1939
1940fn deprecated_arguments() -> Vec<DeprecatedArg> {
1941 let mut res = vec![];
1942
1943 macro_rules! add_arg {
1945 (
1946 $arg:expr
1947 $( , replaced_by: $replaced_by:expr )?
1948 $( , usage_warning: $usage_warning:expr )?
1949 $(,)?
1950 ) => {
1951 let replaced_by = add_arg!(@into-option $( $replaced_by )?);
1952 let usage_warning = add_arg!(@into-option $( $usage_warning )?);
1953 res.push(DeprecatedArg {
1954 arg: $arg,
1955 replaced_by,
1956 usage_warning,
1957 });
1958 };
1959
1960 (@into-option) => { None };
1961 (@into-option $v:expr) => { Some($v) };
1962 }
1963
1964 add_arg!(Arg::with_name("accounts_db_caching_enabled").long("accounts-db-caching-enabled"));
1965 add_arg!(
1966 Arg::with_name("accounts_db_index_hashing")
1967 .long("accounts-db-index-hashing")
1968 .help(
1969 "Enables the use of the index in hash calculation in \
1970 AccountsHashVerifier/Accounts Background Service.",
1971 ),
1972 usage_warning: "The accounts hash is only calculated without using the index.",
1973 );
1974 add_arg!(
1975 Arg::with_name("accounts_db_skip_shrink")
1976 .long("accounts-db-skip-shrink")
1977 .help("Enables faster starting of validators by skipping startup clean and shrink."),
1978 usage_warning: "Enabled by default",
1979 );
1980 add_arg!(Arg::with_name("accounts_hash_interval_slots")
1981 .long("accounts-hash-interval-slots")
1982 .value_name("NUMBER")
1983 .takes_value(true)
1984 .help("Number of slots between verifying accounts hash.")
1985 .validator(|val| {
1986 if val.eq("0") {
1987 Err(String::from("Accounts hash interval cannot be zero"))
1988 } else {
1989 Ok(())
1990 }
1991 }));
1992 add_arg!(Arg::with_name("disable_accounts_disk_index")
1993 .long("disable-accounts-disk-index")
1994 .help("Disable the disk-based accounts index if it is enabled by default.")
1995 .conflicts_with("accounts_index_memory_limit_mb"));
1996 add_arg!(
1997 Arg::with_name("disable_quic_servers")
1998 .long("disable-quic-servers")
1999 .takes_value(false),
2000 usage_warning: "The quic server cannot be disabled.",
2001 );
2002 add_arg!(
2003 Arg::with_name("enable_cpi_and_log_storage")
2004 .long("enable-cpi-and-log-storage")
2005 .requires("enable_rpc_transaction_history")
2006 .takes_value(false)
2007 .help(
2008 "Include CPI inner instructions, logs and return data in the historical \
2009 transaction info stored",
2010 ),
2011 replaced_by: "enable-extended-tx-metadata-storage",
2012 );
2013 add_arg!(
2014 Arg::with_name("enable_quic_servers")
2015 .long("enable-quic-servers"),
2016 usage_warning: "The quic server is now enabled by default.",
2017 );
2018 add_arg!(
2019 Arg::with_name("halt_on_known_validators_accounts_hash_mismatch")
2020 .alias("halt-on-trusted-validators-accounts-hash-mismatch")
2021 .long("halt-on-known-validators-accounts-hash-mismatch")
2022 .requires("known_validators")
2023 .takes_value(false)
2024 .help(
2025 "Abort the validator if a bank hash mismatch is detected within known validator \
2026 set"
2027 ),
2028 );
2029 add_arg!(Arg::with_name("incremental_snapshots")
2030 .long("incremental-snapshots")
2031 .takes_value(false)
2032 .conflicts_with("no_incremental_snapshots")
2033 .help("Enable incremental snapshots")
2034 .long_help(
2035 "Enable incremental snapshots by setting this flag. When enabled, \
2036 --snapshot-interval-slots will set the incremental snapshot interval. To set the
2037 full snapshot interval, use --full-snapshot-interval-slots.",
2038 ));
2039 add_arg!(Arg::with_name("minimal_rpc_api")
2040 .long("minimal-rpc-api")
2041 .takes_value(false)
2042 .help("Only expose the RPC methods required to serve snapshots to other nodes"));
2043 add_arg!(
2044 Arg::with_name("no_accounts_db_index_hashing")
2045 .long("no-accounts-db-index-hashing")
2046 .help(
2047 "This is obsolete. See --accounts-db-index-hashing. \
2048 Disables the use of the index in hash calculation in \
2049 AccountsHashVerifier/Accounts Background Service.",
2050 ),
2051 usage_warning: "The accounts hash is only calculated without using the index.",
2052 );
2053 add_arg!(
2054 Arg::with_name("no_check_vote_account")
2055 .long("no-check-vote-account")
2056 .takes_value(false)
2057 .conflicts_with("no_voting")
2058 .requires("entrypoint")
2059 .help("Skip the RPC vote account sanity check"),
2060 usage_warning: "Vote account sanity checks are no longer performed by default.",
2061 );
2062 add_arg!(Arg::with_name("no_rocksdb_compaction")
2063 .long("no-rocksdb-compaction")
2064 .takes_value(false)
2065 .help("Disable manual compaction of the ledger database"));
2066 add_arg!(Arg::with_name("rocksdb_compaction_interval")
2067 .long("rocksdb-compaction-interval-slots")
2068 .value_name("ROCKSDB_COMPACTION_INTERVAL_SLOTS")
2069 .takes_value(true)
2070 .help("Number of slots between compacting ledger"));
2071 add_arg!(Arg::with_name("rocksdb_max_compaction_jitter")
2072 .long("rocksdb-max-compaction-jitter-slots")
2073 .value_name("ROCKSDB_MAX_COMPACTION_JITTER_SLOTS")
2074 .takes_value(true)
2075 .help("Introduce jitter into the compaction to offset compaction operation"));
2076 add_arg!(
2077 Arg::with_name("skip_poh_verify")
2078 .long("skip-poh-verify")
2079 .takes_value(false)
2080 .help("Skip ledger verification at validator bootup."),
2081 replaced_by: "skip-startup-ledger-verification",
2082 );
2083
2084 res
2085}
2086
2087fn get_deprecated_arguments() -> Vec<Arg<'static, 'static>> {
2090 deprecated_arguments()
2091 .into_iter()
2092 .map(|info| {
2093 let arg = info.arg;
2094 arg.hidden(hidden_unless_forced())
2096 })
2097 .collect()
2098}
2099
2100pub fn warn_for_deprecated_arguments(matches: &ArgMatches) {
2101 for DeprecatedArg {
2102 arg,
2103 replaced_by,
2104 usage_warning,
2105 } in deprecated_arguments().into_iter()
2106 {
2107 if matches.is_present(arg.b.name) {
2108 let mut msg = format!("--{} is deprecated", arg.b.name.replace('_', "-"));
2109 if let Some(replaced_by) = replaced_by {
2110 msg.push_str(&format!(", please use --{replaced_by}"));
2111 }
2112 msg.push('.');
2113 if let Some(usage_warning) = usage_warning {
2114 msg.push_str(&format!(" {usage_warning}"));
2115 if !msg.ends_with('.') {
2116 msg.push('.');
2117 }
2118 }
2119 warn!("{}", msg);
2120 }
2121 }
2122}
2123
2124pub struct DefaultArgs {
2125 pub bind_address: String,
2126 pub dynamic_port_range: String,
2127 pub ledger_path: String,
2128
2129 pub genesis_archive_unpacked_size: String,
2130 pub health_check_slot_distance: String,
2131 pub tower_storage: String,
2132 pub etcd_domain_name: String,
2133 pub send_transaction_service_config: send_transaction_service::Config,
2134
2135 pub rpc_max_multiple_accounts: String,
2136 pub rpc_pubsub_max_active_subscriptions: String,
2137 pub rpc_pubsub_queue_capacity_items: String,
2138 pub rpc_pubsub_queue_capacity_bytes: String,
2139 pub rpc_send_transaction_retry_ms: String,
2140 pub rpc_send_transaction_batch_ms: String,
2141 pub rpc_send_transaction_leader_forward_count: String,
2142 pub rpc_send_transaction_service_max_retries: String,
2143 pub rpc_send_transaction_batch_size: String,
2144 pub rpc_send_transaction_retry_pool_max_size: String,
2145 pub rpc_threads: String,
2146 pub rpc_niceness_adjustment: String,
2147 pub rpc_bigtable_timeout: String,
2148 pub rpc_bigtable_instance_name: String,
2149 pub rpc_bigtable_app_profile_id: String,
2150 pub rpc_bigtable_max_message_size: String,
2151 pub rpc_max_request_body_size: String,
2152 pub rpc_pubsub_worker_threads: String,
2153
2154 pub maximum_local_snapshot_age: String,
2155 pub maximum_full_snapshot_archives_to_retain: String,
2156 pub maximum_incremental_snapshot_archives_to_retain: String,
2157 pub snapshot_packager_niceness_adjustment: String,
2158 pub full_snapshot_archive_interval_slots: String,
2159 pub incremental_snapshot_archive_interval_slots: String,
2160 pub min_snapshot_download_speed: String,
2161 pub max_snapshot_download_abort: String,
2162
2163 pub contact_debug_interval: String,
2164
2165 pub accountsdb_repl_threads: String,
2166
2167 pub snapshot_version: SnapshotVersion,
2168 pub snapshot_archive_format: String,
2169
2170 pub rocksdb_shred_compaction: String,
2171 pub rocksdb_ledger_compression: String,
2172 pub rocksdb_perf_sample_interval: String,
2173
2174 pub accounts_shrink_optimize_total_space: String,
2175 pub accounts_shrink_ratio: String,
2176 pub tpu_connection_pool_size: String,
2177
2178 pub exit_min_idle_time: String,
2180 pub exit_max_delinquent_stake: String,
2181
2182 pub wait_for_restart_window_min_idle_time: String,
2184 pub wait_for_restart_window_max_delinquent_stake: String,
2185
2186 pub banking_trace_dir_byte_limit: String,
2187
2188 pub wen_restart_path: String,
2189}
2190
2191impl DefaultArgs {
2192 pub fn new() -> Self {
2193 let default_send_transaction_service_config = send_transaction_service::Config::default();
2194
2195 DefaultArgs {
2196 bind_address: "0.0.0.0".to_string(),
2197 ledger_path: "ledger".to_string(),
2198 dynamic_port_range: format!("{}-{}", VALIDATOR_PORT_RANGE.0, VALIDATOR_PORT_RANGE.1),
2199 maximum_local_snapshot_age: "2500".to_string(),
2200 genesis_archive_unpacked_size: MAX_GENESIS_ARCHIVE_UNPACKED_SIZE.to_string(),
2201 rpc_max_multiple_accounts: MAX_MULTIPLE_ACCOUNTS.to_string(),
2202 health_check_slot_distance: "150".to_string(),
2203 tower_storage: "file".to_string(),
2204 etcd_domain_name: "localhost".to_string(),
2205 rpc_pubsub_max_active_subscriptions: PubSubConfig::default()
2206 .max_active_subscriptions
2207 .to_string(),
2208 rpc_pubsub_queue_capacity_items: PubSubConfig::default()
2209 .queue_capacity_items
2210 .to_string(),
2211 rpc_pubsub_queue_capacity_bytes: PubSubConfig::default()
2212 .queue_capacity_bytes
2213 .to_string(),
2214 send_transaction_service_config: send_transaction_service::Config::default(),
2215 rpc_send_transaction_retry_ms: default_send_transaction_service_config
2216 .retry_rate_ms
2217 .to_string(),
2218 rpc_send_transaction_batch_ms: default_send_transaction_service_config
2219 .batch_send_rate_ms
2220 .to_string(),
2221 rpc_send_transaction_leader_forward_count: default_send_transaction_service_config
2222 .leader_forward_count
2223 .to_string(),
2224 rpc_send_transaction_service_max_retries: default_send_transaction_service_config
2225 .service_max_retries
2226 .to_string(),
2227 rpc_send_transaction_batch_size: default_send_transaction_service_config
2228 .batch_size
2229 .to_string(),
2230 rpc_send_transaction_retry_pool_max_size: default_send_transaction_service_config
2231 .retry_pool_max_size
2232 .to_string(),
2233 rpc_threads: num_cpus::get().to_string(),
2234 rpc_niceness_adjustment: "0".to_string(),
2235 rpc_bigtable_timeout: "30".to_string(),
2236 rpc_bigtable_instance_name: miraland_storage_bigtable::DEFAULT_INSTANCE_NAME.to_string(),
2237 rpc_bigtable_app_profile_id: miraland_storage_bigtable::DEFAULT_APP_PROFILE_ID
2238 .to_string(),
2239 rpc_bigtable_max_message_size: miraland_storage_bigtable::DEFAULT_MAX_MESSAGE_SIZE
2240 .to_string(),
2241 rpc_pubsub_worker_threads: "4".to_string(),
2242 accountsdb_repl_threads: num_cpus::get().to_string(),
2243 maximum_full_snapshot_archives_to_retain: DEFAULT_MAX_FULL_SNAPSHOT_ARCHIVES_TO_RETAIN
2244 .to_string(),
2245 maximum_incremental_snapshot_archives_to_retain:
2246 DEFAULT_MAX_INCREMENTAL_SNAPSHOT_ARCHIVES_TO_RETAIN.to_string(),
2247 snapshot_packager_niceness_adjustment: "0".to_string(),
2248 full_snapshot_archive_interval_slots: DEFAULT_FULL_SNAPSHOT_ARCHIVE_INTERVAL_SLOTS
2249 .to_string(),
2250 incremental_snapshot_archive_interval_slots:
2251 DEFAULT_INCREMENTAL_SNAPSHOT_ARCHIVE_INTERVAL_SLOTS.to_string(),
2252 min_snapshot_download_speed: DEFAULT_MIN_SNAPSHOT_DOWNLOAD_SPEED.to_string(),
2253 max_snapshot_download_abort: MAX_SNAPSHOT_DOWNLOAD_ABORT.to_string(),
2254 snapshot_archive_format: DEFAULT_ARCHIVE_COMPRESSION.to_string(),
2255 contact_debug_interval: "120000".to_string(),
2256 snapshot_version: SnapshotVersion::default(),
2257 rocksdb_shred_compaction: "level".to_string(),
2258 rocksdb_ledger_compression: "none".to_string(),
2259 rocksdb_perf_sample_interval: "0".to_string(),
2260 accounts_shrink_optimize_total_space: DEFAULT_ACCOUNTS_SHRINK_OPTIMIZE_TOTAL_SPACE
2261 .to_string(),
2262 accounts_shrink_ratio: DEFAULT_ACCOUNTS_SHRINK_RATIO.to_string(),
2263 tpu_connection_pool_size: DEFAULT_TPU_CONNECTION_POOL_SIZE.to_string(),
2264 rpc_max_request_body_size: MAX_REQUEST_BODY_SIZE.to_string(),
2265 exit_min_idle_time: "10".to_string(),
2266 exit_max_delinquent_stake: "5".to_string(),
2267 wait_for_restart_window_min_idle_time: "10".to_string(),
2268 wait_for_restart_window_max_delinquent_stake: "5".to_string(),
2269 banking_trace_dir_byte_limit: BANKING_TRACE_DIR_DEFAULT_BYTE_LIMIT.to_string(),
2270 wen_restart_path: "wen_restart_progress.proto".to_string(),
2271 }
2272 }
2273}
2274
2275impl Default for DefaultArgs {
2276 fn default() -> Self {
2277 Self::new()
2278 }
2279}
2280
2281pub fn port_validator(port: String) -> Result<(), String> {
2282 port.parse::<u16>()
2283 .map(|_| ())
2284 .map_err(|e| format!("{e:?}"))
2285}
2286
2287pub fn port_range_validator(port_range: String) -> Result<(), String> {
2288 if let Some((start, end)) = miraland_net_utils::parse_port_range(&port_range) {
2289 if end - start < MINIMUM_VALIDATOR_PORT_RANGE_WIDTH {
2290 Err(format!(
2291 "Port range is too small. Try --dynamic-port-range {}-{}",
2292 start,
2293 start + MINIMUM_VALIDATOR_PORT_RANGE_WIDTH
2294 ))
2295 } else if end.checked_add(QUIC_PORT_OFFSET).is_none() {
2296 Err("Invalid dynamic_port_range.".to_string())
2297 } else {
2298 Ok(())
2299 }
2300 } else {
2301 Err("Invalid port range".to_string())
2302 }
2303}
2304
2305fn hash_validator(hash: String) -> Result<(), String> {
2306 Hash::from_str(&hash)
2307 .map(|_| ())
2308 .map_err(|e| format!("{e:?}"))
2309}
2310
2311pub fn test_app<'a>(version: &'a str, default_args: &'a DefaultTestArgs) -> App<'a, 'a> {
2314 return App::new("miraland-test-validator")
2315 .about("Test Validator")
2316 .version(version)
2317 .arg({
2318 let arg = Arg::with_name("config_file")
2319 .short("C")
2320 .long("config")
2321 .value_name("PATH")
2322 .takes_value(true)
2323 .help("Configuration file to use");
2324 if let Some(ref config_file) = *miraland_cli_config::CONFIG_FILE {
2325 arg.default_value(config_file)
2326 } else {
2327 arg
2328 }
2329 })
2330 .arg(
2331 Arg::with_name("json_rpc_url")
2332 .short("u")
2333 .long("url")
2334 .value_name("URL_OR_MONIKER")
2335 .takes_value(true)
2336 .validator(is_url_or_moniker)
2337 .help(
2338 "URL for Miraland's JSON RPC or moniker (or their first letter): \
2339 [mainnet, testnet, devnet, localhost]",
2340 ),
2341 )
2342 .arg(
2343 Arg::with_name("mint_address")
2344 .long("mint")
2345 .value_name("PUBKEY")
2346 .validator(is_pubkey)
2347 .takes_value(true)
2348 .help(
2349 "Address of the mint account that will receive tokens created at genesis. If \
2350 the ledger already exists then this parameter is silently ignored \
2351 [default: client keypair]",
2352 ),
2353 )
2354 .arg(
2355 Arg::with_name("ledger_path")
2356 .short("l")
2357 .long("ledger")
2358 .value_name("DIR")
2359 .takes_value(true)
2360 .required(true)
2361 .default_value("test-ledger")
2362 .help("Use DIR as ledger location"),
2363 )
2364 .arg(
2365 Arg::with_name("reset")
2366 .short("r")
2367 .long("reset")
2368 .takes_value(false)
2369 .help(
2370 "Reset the ledger to genesis if it exists. By default the validator will \
2371 resume an existing ledger (if present)",
2372 ),
2373 )
2374 .arg(
2375 Arg::with_name("quiet")
2376 .short("q")
2377 .long("quiet")
2378 .takes_value(false)
2379 .conflicts_with("log")
2380 .help("Quiet mode: suppress normal output"),
2381 )
2382 .arg(
2383 Arg::with_name("log")
2384 .long("log")
2385 .takes_value(false)
2386 .conflicts_with("quiet")
2387 .help("Log mode: stream the validator log"),
2388 )
2389 .arg(
2390 Arg::with_name("account_indexes")
2391 .long("account-index")
2392 .takes_value(true)
2393 .multiple(true)
2394 .possible_values(&["program-id", "solarti-token-owner", "solarti-token-mint"])
2395 .value_name("INDEX")
2396 .help("Enable an accounts index, indexed by the selected account field"),
2397 )
2398 .arg(
2399 Arg::with_name("faucet_port")
2400 .long("faucet-port")
2401 .value_name("PORT")
2402 .takes_value(true)
2403 .default_value(&default_args.faucet_port)
2404 .validator(port_validator)
2405 .help("Enable the faucet on this port"),
2406 )
2407 .arg(
2408 Arg::with_name("rpc_port")
2409 .long("rpc-port")
2410 .value_name("PORT")
2411 .takes_value(true)
2412 .default_value(&default_args.rpc_port)
2413 .validator(port_validator)
2414 .help("Enable JSON RPC on this port, and the next port for the RPC websocket"),
2415 )
2416 .arg(
2417 Arg::with_name("enable_rpc_bigtable_ledger_storage")
2418 .long("enable-rpc-bigtable-ledger-storage")
2419 .takes_value(false)
2420 .hidden(hidden_unless_forced())
2421 .help(
2422 "Fetch historical transaction info from a BigTable instance as a fallback to \
2423 local ledger data",
2424 ),
2425 )
2426 .arg(
2427 Arg::with_name("rpc_bigtable_instance")
2428 .long("rpc-bigtable-instance")
2429 .value_name("INSTANCE_NAME")
2430 .takes_value(true)
2431 .hidden(hidden_unless_forced())
2432 .default_value("miraland-ledger")
2433 .help("Name of BigTable instance to target"),
2434 )
2435 .arg(
2436 Arg::with_name("rpc_bigtable_app_profile_id")
2437 .long("rpc-bigtable-app-profile-id")
2438 .value_name("APP_PROFILE_ID")
2439 .takes_value(true)
2440 .hidden(hidden_unless_forced())
2441 .default_value(miraland_storage_bigtable::DEFAULT_APP_PROFILE_ID)
2442 .help("Application profile id to use in Bigtable requests"),
2443 )
2444 .arg(
2445 Arg::with_name("rpc_pubsub_enable_vote_subscription")
2446 .long("rpc-pubsub-enable-vote-subscription")
2447 .takes_value(false)
2448 .help("Enable the unstable RPC PubSub `voteSubscribe` subscription"),
2449 )
2450 .arg(
2451 Arg::with_name("rpc_pubsub_enable_block_subscription")
2452 .long("rpc-pubsub-enable-block-subscription")
2453 .takes_value(false)
2454 .help("Enable the unstable RPC PubSub `blockSubscribe` subscription"),
2455 )
2456 .arg(
2457 Arg::with_name("bpf_program")
2458 .long("bpf-program")
2459 .value_names(&["ADDRESS_OR_KEYPAIR", "SBF_PROGRAM.SO"])
2460 .takes_value(true)
2461 .number_of_values(2)
2462 .multiple(true)
2463 .help(
2464 "Add a SBF program to the genesis configuration with upgrades disabled. If \
2465 the ledger already exists then this parameter is silently ignored. The first \
2466 argument can be a pubkey string or path to a keypair",
2467 ),
2468 )
2469 .arg(
2470 Arg::with_name("upgradeable_program")
2471 .long("upgradeable-program")
2472 .value_names(&["ADDRESS_OR_KEYPAIR", "SBF_PROGRAM.SO", "UPGRADE_AUTHORITY"])
2473 .takes_value(true)
2474 .number_of_values(3)
2475 .multiple(true)
2476 .help(
2477 "Add an upgradeable SBF program to the genesis configuration. If the ledger \
2478 already exists then this parameter is silently ignored. First and third \
2479 arguments can be a pubkey string or path to a keypair. Upgrade authority set \
2480 to \"none\" disables upgrades",
2481 ),
2482 )
2483 .arg(
2484 Arg::with_name("account")
2485 .long("account")
2486 .value_names(&["ADDRESS", "DUMP.JSON"])
2487 .takes_value(true)
2488 .number_of_values(2)
2489 .allow_hyphen_values(true)
2490 .multiple(true)
2491 .help(
2492 "Load an account from the provided JSON file (see `solana account --help` on \
2493 how to dump an account to file). Files are searched for relatively to CWD \
2494 and tests/fixtures. If ADDRESS is omitted via the `-` placeholder, the one \
2495 in the file will be used. If the ledger already exists then this parameter \
2496 is silently ignored",
2497 ),
2498 )
2499 .arg(
2500 Arg::with_name("account_dir")
2501 .long("account-dir")
2502 .value_name("DIRECTORY")
2503 .validator(|value| {
2504 value
2505 .parse::<PathBuf>()
2506 .map_err(|err| format!("error parsing '{value}': {err}"))
2507 .and_then(|path| {
2508 if path.exists() && path.is_dir() {
2509 Ok(())
2510 } else {
2511 Err(format!(
2512 "path does not exist or is not a directory: {value}"
2513 ))
2514 }
2515 })
2516 })
2517 .takes_value(true)
2518 .multiple(true)
2519 .help(
2520 "Load all the accounts from the JSON files found in the specified DIRECTORY \
2521 (see also the `--account` flag). If the ledger already exists then this \
2522 parameter is silently ignored",
2523 ),
2524 )
2525 .arg(
2526 Arg::with_name("ticks_per_slot")
2527 .long("ticks-per-slot")
2528 .value_name("TICKS")
2529 .validator(|value| {
2530 value
2531 .parse::<u64>()
2532 .map_err(|err| format!("error parsing '{value}': {err}"))
2533 .and_then(|ticks| {
2534 if ticks < MINIMUM_TICKS_PER_SLOT {
2535 Err(format!("value must be >= {MINIMUM_TICKS_PER_SLOT}"))
2536 } else {
2537 Ok(())
2538 }
2539 })
2540 })
2541 .takes_value(true)
2542 .help("The number of ticks in a slot"),
2543 )
2544 .arg(
2545 Arg::with_name("slots_per_epoch")
2546 .long("slots-per-epoch")
2547 .value_name("SLOTS")
2548 .validator(|value| {
2549 value
2550 .parse::<Slot>()
2551 .map_err(|err| format!("error parsing '{value}': {err}"))
2552 .and_then(|slot| {
2553 if slot < MINIMUM_SLOTS_PER_EPOCH {
2554 Err(format!("value must be >= {MINIMUM_SLOTS_PER_EPOCH}"))
2555 } else {
2556 Ok(())
2557 }
2558 })
2559 })
2560 .takes_value(true)
2561 .help(
2562 "Override the number of slots in an epoch. If the ledger already exists then \
2563 this parameter is silently ignored",
2564 ),
2565 )
2566 .arg(
2567 Arg::with_name("gossip_port")
2568 .long("gossip-port")
2569 .value_name("PORT")
2570 .takes_value(true)
2571 .help("Gossip port number for the validator"),
2572 )
2573 .arg(
2574 Arg::with_name("gossip_host")
2575 .long("gossip-host")
2576 .value_name("HOST")
2577 .takes_value(true)
2578 .validator(miraland_net_utils::is_host)
2579 .help(
2580 "Gossip DNS name or IP address for the validator to advertise in gossip \
2581 [default: 127.0.0.1]",
2582 ),
2583 )
2584 .arg(
2585 Arg::with_name("dynamic_port_range")
2586 .long("dynamic-port-range")
2587 .value_name("MIN_PORT-MAX_PORT")
2588 .takes_value(true)
2589 .validator(port_range_validator)
2590 .help("Range to use for dynamically assigned ports [default: 1024-65535]"),
2591 )
2592 .arg(
2593 Arg::with_name("bind_address")
2594 .long("bind-address")
2595 .value_name("HOST")
2596 .takes_value(true)
2597 .validator(miraland_net_utils::is_host)
2598 .default_value("0.0.0.0")
2599 .help("IP address to bind the validator ports [default: 0.0.0.0]"),
2600 )
2601 .arg(
2602 Arg::with_name("clone_account")
2603 .long("clone")
2604 .short("c")
2605 .value_name("ADDRESS")
2606 .takes_value(true)
2607 .validator(is_pubkey_or_keypair)
2608 .multiple(true)
2609 .requires("json_rpc_url")
2610 .help(
2611 "Copy an account from the cluster referenced by the --url argument the \
2612 genesis configuration. If the ledger already exists then this parameter is \
2613 silently ignored",
2614 ),
2615 )
2616 .arg(
2617 Arg::with_name("maybe_clone_account")
2618 .long("maybe-clone")
2619 .value_name("ADDRESS")
2620 .takes_value(true)
2621 .validator(is_pubkey_or_keypair)
2622 .multiple(true)
2623 .requires("json_rpc_url")
2624 .help(
2625 "Copy an account from the cluster referenced by the --url argument, skipping \
2626 it if it doesn't exist. If the ledger already exists then this parameter is \
2627 silently ignored",
2628 ),
2629 )
2630 .arg(
2631 Arg::with_name("clone_upgradeable_program")
2632 .long("clone-upgradeable-program")
2633 .value_name("ADDRESS")
2634 .takes_value(true)
2635 .validator(is_pubkey_or_keypair)
2636 .multiple(true)
2637 .requires("json_rpc_url")
2638 .help(
2639 "Copy an upgradeable program and its executable data from the cluster \
2640 referenced by the --url argument the genesis configuration. If the ledger \
2641 already exists then this parameter is silently ignored",
2642 ),
2643 )
2644 .arg(
2645 Arg::with_name("warp_slot")
2646 .required(false)
2647 .long("warp-slot")
2648 .short("w")
2649 .takes_value(true)
2650 .value_name("WARP_SLOT")
2651 .validator(is_slot)
2652 .min_values(0)
2653 .max_values(1)
2654 .help(
2655 "Warp the ledger to WARP_SLOT after starting the validator. If no slot is \
2656 provided then the current slot of the cluster referenced by the --url \
2657 argument will be used",
2658 ),
2659 )
2660 .arg(
2661 Arg::with_name("limit_ledger_size")
2662 .long("limit-ledger-size")
2663 .value_name("SHRED_COUNT")
2664 .takes_value(true)
2665 .default_value(default_args.limit_ledger_size.as_str())
2666 .help("Keep this amount of shreds in root slots."),
2667 )
2668 .arg(
2669 Arg::with_name("faucet_mln")
2670 .long("faucet-mln")
2671 .takes_value(true)
2672 .value_name("MLN")
2673 .default_value(default_args.faucet_mln.as_str())
2674 .help(
2675 "Give the faucet address this much MLN in genesis. If the ledger already \
2676 exists then this parameter is silently ignored",
2677 ),
2678 )
2679 .arg(
2680 Arg::with_name("faucet_time_slice_secs")
2681 .long("faucet-time-slice-secs")
2682 .takes_value(true)
2683 .value_name("SECS")
2684 .default_value(default_args.faucet_time_slice_secs.as_str())
2685 .help("Time slice (in secs) over which to limit faucet requests"),
2686 )
2687 .arg(
2688 Arg::with_name("faucet_per_time_mln_cap")
2689 .long("faucet-per-time-mln-cap")
2690 .takes_value(true)
2691 .value_name("MLN")
2692 .min_values(0)
2693 .max_values(1)
2694 .help("Per-time slice limit for faucet requests, in MLN"),
2695 )
2696 .arg(
2697 Arg::with_name("faucet_per_request_mln_cap")
2698 .long("faucet-per-request-mln-cap")
2699 .takes_value(true)
2700 .value_name("MLN")
2701 .min_values(0)
2702 .max_values(1)
2703 .help("Per-request limit for faucet requests, in MLN"),
2704 )
2705 .arg(
2706 Arg::with_name("geyser_plugin_config")
2707 .long("geyser-plugin-config")
2708 .alias("accountsdb-plugin-config")
2709 .value_name("FILE")
2710 .takes_value(true)
2711 .multiple(true)
2712 .help("Specify the configuration file for the Geyser plugin."),
2713 )
2714 .arg(
2715 Arg::with_name("deactivate_feature")
2716 .long("deactivate-feature")
2717 .takes_value(true)
2718 .value_name("FEATURE_PUBKEY")
2719 .validator(is_pubkey)
2720 .multiple(true)
2721 .help("deactivate this feature in genesis."),
2722 )
2723 .arg(
2724 Arg::with_name("compute_unit_limit")
2725 .long("compute-unit-limit")
2726 .alias("max-compute-units")
2727 .value_name("COMPUTE_UNITS")
2728 .validator(is_parsable::<u64>)
2729 .takes_value(true)
2730 .help("Override the runtime's compute unit limit per transaction"),
2731 )
2732 .arg(
2733 Arg::with_name("log_messages_bytes_limit")
2734 .long("log-messages-bytes-limit")
2735 .value_name("BYTES")
2736 .validator(is_parsable::<usize>)
2737 .takes_value(true)
2738 .help("Maximum number of bytes written to the program log before truncation"),
2739 )
2740 .arg(
2741 Arg::with_name("transaction_account_lock_limit")
2742 .long("transaction-account-lock-limit")
2743 .value_name("NUM_ACCOUNTS")
2744 .validator(is_parsable::<u64>)
2745 .takes_value(true)
2746 .help("Override the runtime's account lock limit per transaction"),
2747 );
2748}
2749
2750pub struct DefaultTestArgs {
2751 pub rpc_port: String,
2752 pub faucet_port: String,
2753 pub limit_ledger_size: String,
2754 pub faucet_mln: String,
2755 pub faucet_time_slice_secs: String,
2756}
2757
2758impl DefaultTestArgs {
2759 pub fn new() -> Self {
2760 DefaultTestArgs {
2761 rpc_port: rpc_port::DEFAULT_RPC_PORT.to_string(),
2762 faucet_port: FAUCET_PORT.to_string(),
2763 limit_ledger_size: 10_000.to_string(),
2768 faucet_mln: (1_000_000.).to_string(),
2769 faucet_time_slice_secs: (faucet::TIME_SLICE).to_string(),
2770 }
2771 }
2772}
2773
2774impl Default for DefaultTestArgs {
2775 fn default() -> Self {
2776 Self::new()
2777 }
2778}
2779
2780#[cfg(test)]
2781mod test {
2782 use super::*;
2783
2784 #[test]
2785 fn make_sure_deprecated_arguments_are_sorted_alphabetically() {
2786 let deprecated = deprecated_arguments();
2787
2788 for i in 0..deprecated.len().saturating_sub(1) {
2789 let curr_name = deprecated[i].arg.b.name;
2790 let next_name = deprecated[i + 1].arg.b.name;
2791
2792 assert!(
2793 curr_name != next_name,
2794 "Arguments in `deprecated_arguments()` should be distinct.\nArguments {} and {} \
2795 use the same name: {}",
2796 i,
2797 i + 1,
2798 curr_name,
2799 );
2800
2801 assert!(
2802 curr_name < next_name,
2803 "To generate better diffs and for readability purposes, `deprecated_arguments()` \
2804 should list arguments in alphabetical order.\nArguments {} and {} are \
2805 not.\nArgument {} name: {}\nArgument {} name: {}",
2806 i,
2807 i + 1,
2808 i,
2809 curr_name,
2810 i + 1,
2811 next_name,
2812 );
2813 }
2814 }
2815}