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