Clap v3 update: keygen (#24479)

* update clap to v3: keygen

* use clap-v3-utils

* update Cargo.lock

* address PR comments

* get rid of unnecessary generic for clap validator
This commit is contained in:
kirill lykov 2022-04-22 12:40:53 +02:00 committed by GitHub
parent 0d51596224
commit a22101489c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 90 additions and 90 deletions

4
Cargo.lock generated
View File

@ -5038,10 +5038,10 @@ name = "solana-keygen"
version = "1.11.0" version = "1.11.0"
dependencies = [ dependencies = [
"bs58", "bs58",
"clap 2.33.3", "clap 3.1.8",
"dirs-next", "dirs-next",
"num_cpus", "num_cpus",
"solana-clap-utils", "solana-clap-v3-utils",
"solana-cli-config", "solana-cli-config",
"solana-remote-wallet", "solana-remote-wallet",
"solana-sdk 1.11.0", "solana-sdk 1.11.0",

View File

@ -25,12 +25,12 @@ where
// Return an error if string cannot be parsed as type T. // Return an error if string cannot be parsed as type T.
// Takes a String to avoid second type parameter when used as a clap validator // Takes a String to avoid second type parameter when used as a clap validator
pub fn is_parsable<T>(string: String) -> Result<(), String> pub fn is_parsable<T>(string: &str) -> Result<(), String>
where where
T: FromStr, T: FromStr,
T::Err: Display, T::Err: Display,
{ {
is_parsable_generic::<T, String>(string) is_parsable_generic::<T, &str>(string)
} }
// Return an error if string cannot be parsed as numeric type T, and value not within specified // Return an error if string cannot be parsed as numeric type T, and value not within specified
@ -57,10 +57,7 @@ where
} }
// Return an error if a pubkey cannot be parsed. // Return an error if a pubkey cannot be parsed.
pub fn is_pubkey<T>(string: T) -> Result<(), String> pub fn is_pubkey(string: &str) -> Result<(), String> {
where
T: AsRef<str> + Display,
{
is_parsable_generic::<Pubkey, _>(string) is_parsable_generic::<Pubkey, _>(string)
} }
@ -96,14 +93,11 @@ where
} }
// Return an error if a `SignerSourceKind::Prompt` cannot be parsed // Return an error if a `SignerSourceKind::Prompt` cannot be parsed
pub fn is_prompt_signer_source<T>(string: T) -> Result<(), String> pub fn is_prompt_signer_source(string: &str) -> Result<(), String> {
where if string == ASK_KEYWORD {
T: AsRef<str> + Display,
{
if string.as_ref() == ASK_KEYWORD {
return Ok(()); return Ok(());
} }
match parse_signer_source(string.as_ref()) match parse_signer_source(string)
.map_err(|err| format!("{}", err))? .map_err(|err| format!("{}", err))?
.kind .kind
{ {

View File

@ -11,10 +11,10 @@ edition = "2021"
[dependencies] [dependencies]
bs58 = "0.4.0" bs58 = "0.4.0"
clap = "2.33" clap = { version = "3.1.5", features = ["cargo"] }
dirs-next = "2.0.0" dirs-next = "2.0.0"
num_cpus = "1.13.1" num_cpus = "1.13.1"
solana-clap-utils = { path = "../clap-utils", version = "=1.11.0" } solana-clap-v3-utils = { path = "../clap-v3-utils", version = "=1.11.0" }
solana-cli-config = { path = "../cli-config", version = "=1.11.0" } solana-cli-config = { path = "../cli-config", version = "=1.11.0" }
solana-remote-wallet = { path = "../remote-wallet", version = "=1.11.0" } solana-remote-wallet = { path = "../remote-wallet", version = "=1.11.0" }
solana-sdk = { path = "../sdk", version = "=1.11.0" } solana-sdk = { path = "../sdk", version = "=1.11.0" }

View File

@ -1,11 +1,8 @@
#![allow(clippy::integer_arithmetic)] #![allow(clippy::integer_arithmetic)]
use { use {
bip39::{Language, Mnemonic, MnemonicType, Seed}, bip39::{Language, Mnemonic, MnemonicType, Seed},
clap::{ clap::{crate_description, crate_name, Arg, ArgMatches, Command},
crate_description, crate_name, value_t, value_t_or_exit, values_t_or_exit, App, solana_clap_v3_utils::{
AppSettings, Arg, ArgMatches, SubCommand,
},
solana_clap_utils::{
input_parsers::STDOUT_OUTFILE_TOKEN, input_parsers::STDOUT_OUTFILE_TOKEN,
input_validators::{is_parsable, is_prompt_signer_source}, input_validators::{is_parsable, is_prompt_signer_source},
keypair::{ keypair::{
@ -68,8 +65,8 @@ const NO_OUTFILE_ARG: ArgConstant<'static> = ArgConstant {
help: "Only print a seed phrase and pubkey. Do not output a keypair file", help: "Only print a seed phrase and pubkey. Do not output a keypair file",
}; };
fn word_count_arg<'a, 'b>() -> Arg<'a, 'b> { fn word_count_arg<'a>() -> Arg<'a> {
Arg::with_name(WORD_COUNT_ARG.name) Arg::new(WORD_COUNT_ARG.name)
.long(WORD_COUNT_ARG.long) .long(WORD_COUNT_ARG.long)
.possible_values(&["12", "15", "18", "21", "24"]) .possible_values(&["12", "15", "18", "21", "24"])
.default_value("12") .default_value("12")
@ -78,8 +75,8 @@ fn word_count_arg<'a, 'b>() -> Arg<'a, 'b> {
.help(WORD_COUNT_ARG.help) .help(WORD_COUNT_ARG.help)
} }
fn language_arg<'a, 'b>() -> Arg<'a, 'b> { fn language_arg<'a>() -> Arg<'a> {
Arg::with_name(LANGUAGE_ARG.name) Arg::new(LANGUAGE_ARG.name)
.long(LANGUAGE_ARG.long) .long(LANGUAGE_ARG.long)
.possible_values(&[ .possible_values(&[
"english", "english",
@ -97,15 +94,15 @@ fn language_arg<'a, 'b>() -> Arg<'a, 'b> {
.help(LANGUAGE_ARG.help) .help(LANGUAGE_ARG.help)
} }
fn no_passphrase_arg<'a, 'b>() -> Arg<'a, 'b> { fn no_passphrase_arg<'a>() -> Arg<'a> {
Arg::with_name(NO_PASSPHRASE_ARG.name) Arg::new(NO_PASSPHRASE_ARG.name)
.long(NO_PASSPHRASE_ARG.long) .long(NO_PASSPHRASE_ARG.long)
.alias("no-passphrase") .alias("no-passphrase")
.help(NO_PASSPHRASE_ARG.help) .help(NO_PASSPHRASE_ARG.help)
} }
fn no_outfile_arg<'a, 'b>() -> Arg<'a, 'b> { fn no_outfile_arg<'a>() -> Arg<'a> {
Arg::with_name(NO_OUTFILE_ARG.name) Arg::new(NO_OUTFILE_ARG.name)
.long(NO_OUTFILE_ARG.long) .long(NO_OUTFILE_ARG.long)
.conflicts_with_all(&["outfile", "silent"]) .conflicts_with_all(&["outfile", "silent"])
.help(NO_OUTFILE_ARG.help) .help(NO_OUTFILE_ARG.help)
@ -115,7 +112,7 @@ trait KeyGenerationCommonArgs {
fn key_generation_common_args(self) -> Self; fn key_generation_common_args(self) -> Self;
} }
impl KeyGenerationCommonArgs for App<'_, '_> { impl KeyGenerationCommonArgs for Command<'_> {
fn key_generation_common_args(self) -> Self { fn key_generation_common_args(self) -> Self {
self.arg(word_count_arg()) self.arg(word_count_arg())
.arg(language_arg()) .arg(language_arg())
@ -163,7 +160,7 @@ fn output_keypair(
Ok(()) Ok(())
} }
fn grind_validator_starts_with(v: String) -> Result<(), String> { fn grind_validator_starts_with(v: &str) -> Result<(), String> {
if v.matches(':').count() != 1 || (v.starts_with(':') || v.ends_with(':')) { if v.matches(':').count() != 1 || (v.starts_with(':') || v.ends_with(':')) {
return Err(String::from("Expected : between PREFIX and COUNT")); return Err(String::from("Expected : between PREFIX and COUNT"));
} }
@ -178,7 +175,7 @@ fn grind_validator_starts_with(v: String) -> Result<(), String> {
Ok(()) Ok(())
} }
fn grind_validator_ends_with(v: String) -> Result<(), String> { fn grind_validator_ends_with(v: &str) -> Result<(), String> {
if v.matches(':').count() != 1 || (v.starts_with(':') || v.ends_with(':')) { if v.matches(':').count() != 1 || (v.starts_with(':') || v.ends_with(':')) {
return Err(String::from("Expected : between SUFFIX and COUNT")); return Err(String::from("Expected : between SUFFIX and COUNT"));
} }
@ -193,7 +190,7 @@ fn grind_validator_ends_with(v: String) -> Result<(), String> {
Ok(()) Ok(())
} }
fn grind_validator_starts_and_ends_with(v: String) -> Result<(), String> { fn grind_validator_starts_and_ends_with(v: &str) -> Result<(), String> {
if v.matches(':').count() != 2 || (v.starts_with(':') || v.ends_with(':')) { if v.matches(':').count() != 2 || (v.starts_with(':') || v.ends_with(':')) {
return Err(String::from( return Err(String::from(
"Expected : between PREFIX and SUFFIX and COUNT", "Expected : between PREFIX and SUFFIX and COUNT",
@ -213,7 +210,7 @@ fn grind_validator_starts_and_ends_with(v: String) -> Result<(), String> {
Ok(()) Ok(())
} }
fn acquire_language(matches: &ArgMatches<'_>) -> Language { fn acquire_language(matches: &ArgMatches) -> Language {
match matches.value_of(LANGUAGE_ARG.name).unwrap() { match matches.value_of(LANGUAGE_ARG.name).unwrap() {
"english" => Language::English, "english" => Language::English,
"chinese-simplified" => Language::ChineseSimplified, "chinese-simplified" => Language::ChineseSimplified,
@ -232,7 +229,7 @@ fn no_passphrase_and_message() -> (String, String) {
} }
fn acquire_passphrase_and_message( fn acquire_passphrase_and_message(
matches: &ArgMatches<'_>, matches: &ArgMatches,
) -> Result<(String, String), Box<dyn error::Error>> { ) -> Result<(String, String), Box<dyn error::Error>> {
if matches.is_present(NO_PASSPHRASE_ARG.name) { if matches.is_present(NO_PASSPHRASE_ARG.name) {
Ok(no_passphrase_and_message()) Ok(no_passphrase_and_message())
@ -331,13 +328,14 @@ fn grind_parse_args(
fn main() -> Result<(), Box<dyn error::Error>> { fn main() -> Result<(), Box<dyn error::Error>> {
let default_num_threads = num_cpus::get().to_string(); let default_num_threads = num_cpus::get().to_string();
let matches = App::new(crate_name!()) let matches = Command::new(crate_name!())
.about(crate_description!()) .about(crate_description!())
.version(solana_version::version!()) .version(solana_version::version!())
.setting(AppSettings::SubcommandRequiredElseHelp) .subcommand_required(true)
.arg_required_else_help(true)
.arg({ .arg({
let arg = Arg::with_name("config_file") let arg = Arg::new("config_file")
.short("C") .short('C')
.long("config") .long("config")
.value_name("FILEPATH") .value_name("FILEPATH")
.takes_value(true) .takes_value(true)
@ -350,10 +348,10 @@ fn main() -> Result<(), Box<dyn error::Error>> {
} }
}) })
.subcommand( .subcommand(
SubCommand::with_name("verify") Command::new("verify")
.about("Verify a keypair can sign and verify a message.") .about("Verify a keypair can sign and verify a message.")
.arg( .arg(
Arg::with_name("pubkey") Arg::new("pubkey")
.index(1) .index(1)
.value_name("PUBKEY") .value_name("PUBKEY")
.takes_value(true) .takes_value(true)
@ -361,7 +359,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.help("Public key"), .help("Public key"),
) )
.arg( .arg(
Arg::with_name("keypair") Arg::new("keypair")
.index(2) .index(2)
.value_name("KEYPAIR") .value_name("KEYPAIR")
.takes_value(true) .takes_value(true)
@ -369,26 +367,26 @@ fn main() -> Result<(), Box<dyn error::Error>> {
) )
) )
.subcommand( .subcommand(
SubCommand::with_name("new") Command::new("new")
.about("Generate new keypair file from a random seed phrase and optional BIP39 passphrase") .about("Generate new keypair file from a random seed phrase and optional BIP39 passphrase")
.setting(AppSettings::DisableVersion) .disable_version_flag(true)
.arg( .arg(
Arg::with_name("outfile") Arg::new("outfile")
.short("o") .short('o')
.long("outfile") .long("outfile")
.value_name("FILEPATH") .value_name("FILEPATH")
.takes_value(true) .takes_value(true)
.help("Path to generated file"), .help("Path to generated file"),
) )
.arg( .arg(
Arg::with_name("force") Arg::new("force")
.short("f") .short('f')
.long("force") .long("force")
.help("Overwrite the output file if it exists"), .help("Overwrite the output file if it exists"),
) )
.arg( .arg(
Arg::with_name("silent") Arg::new("silent")
.short("s") .short('s')
.long("silent") .long("silent")
.help("Do not display seed phrase. Useful when piping output to other programs that prompt for user input, like gpg"), .help("Do not display seed phrase. Useful when piping output to other programs that prompt for user input, like gpg"),
) )
@ -396,46 +394,49 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.arg(no_outfile_arg()) .arg(no_outfile_arg())
) )
.subcommand( .subcommand(
SubCommand::with_name("grind") Command::new("grind")
.about("Grind for vanity keypairs") .about("Grind for vanity keypairs")
.setting(AppSettings::DisableVersion) .disable_version_flag(true)
.arg( .arg(
Arg::with_name("ignore_case") Arg::new("ignore_case")
.long("ignore-case") .long("ignore-case")
.help("Performs case insensitive matches"), .help("Performs case insensitive matches"),
) )
.arg( .arg(
Arg::with_name("starts_with") Arg::new("starts_with")
.long("starts-with") .long("starts-with")
.value_name("PREFIX:COUNT") .value_name("PREFIX:COUNT")
.number_of_values(1) .number_of_values(1)
.takes_value(true) .takes_value(true)
.multiple(true) .multiple_occurrences(true)
.multiple_values(true)
.validator(grind_validator_starts_with) .validator(grind_validator_starts_with)
.help("Saves specified number of keypairs whos public key starts with the indicated prefix\nExample: --starts-with sol:4\nPREFIX type is Base58\nCOUNT type is u64"), .help("Saves specified number of keypairs whos public key starts with the indicated prefix\nExample: --starts-with sol:4\nPREFIX type is Base58\nCOUNT type is u64"),
) )
.arg( .arg(
Arg::with_name("ends_with") Arg::new("ends_with")
.long("ends-with") .long("ends-with")
.value_name("SUFFIX:COUNT") .value_name("SUFFIX:COUNT")
.number_of_values(1) .number_of_values(1)
.takes_value(true) .takes_value(true)
.multiple(true) .multiple_occurrences(true)
.multiple_values(true)
.validator(grind_validator_ends_with) .validator(grind_validator_ends_with)
.help("Saves specified number of keypairs whos public key ends with the indicated suffix\nExample: --ends-with ana:4\nSUFFIX type is Base58\nCOUNT type is u64"), .help("Saves specified number of keypairs whos public key ends with the indicated suffix\nExample: --ends-with ana:4\nSUFFIX type is Base58\nCOUNT type is u64"),
) )
.arg( .arg(
Arg::with_name("starts_and_ends_with") Arg::new("starts_and_ends_with")
.long("starts-and-ends-with") .long("starts-and-ends-with")
.value_name("PREFIX:SUFFIX:COUNT") .value_name("PREFIX:SUFFIX:COUNT")
.number_of_values(1) .number_of_values(1)
.takes_value(true) .takes_value(true)
.multiple(true) .multiple_occurrences(true)
.multiple_values(true)
.validator(grind_validator_starts_and_ends_with) .validator(grind_validator_starts_and_ends_with)
.help("Saves specified number of keypairs whos public key starts and ends with the indicated perfix and suffix\nExample: --starts-and-ends-with sol:ana:4\nPREFIX and SUFFIX type is Base58\nCOUNT type is u64"), .help("Saves specified number of keypairs whos public key starts and ends with the indicated perfix and suffix\nExample: --starts-and-ends-with sol:ana:4\nPREFIX and SUFFIX type is Base58\nCOUNT type is u64"),
) )
.arg( .arg(
Arg::with_name("num_threads") Arg::new("num_threads")
.long("num-threads") .long("num-threads")
.value_name("NUMBER") .value_name("NUMBER")
.takes_value(true) .takes_value(true)
@ -444,7 +445,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.help("Specify the number of grind threads"), .help("Specify the number of grind threads"),
) )
.arg( .arg(
Arg::with_name("use_mnemonic") Arg::new("use_mnemonic")
.long("use-mnemonic") .long("use-mnemonic")
.help("Generate using a mnemonic key phrase. Expect a significant slowdown in this mode"), .help("Generate using a mnemonic key phrase. Expect a significant slowdown in this mode"),
) )
@ -457,42 +458,42 @@ fn main() -> Result<(), Box<dyn error::Error>> {
) )
) )
.subcommand( .subcommand(
SubCommand::with_name("pubkey") Command::new("pubkey")
.about("Display the pubkey from a keypair file") .about("Display the pubkey from a keypair file")
.setting(AppSettings::DisableVersion) .disable_version_flag(true)
.arg( .arg(
Arg::with_name("keypair") Arg::new("keypair")
.index(1) .index(1)
.value_name("KEYPAIR") .value_name("KEYPAIR")
.takes_value(true) .takes_value(true)
.help("Filepath or URL to a keypair"), .help("Filepath or URL to a keypair"),
) )
.arg( .arg(
Arg::with_name(SKIP_SEED_PHRASE_VALIDATION_ARG.name) Arg::new(SKIP_SEED_PHRASE_VALIDATION_ARG.name)
.long(SKIP_SEED_PHRASE_VALIDATION_ARG.long) .long(SKIP_SEED_PHRASE_VALIDATION_ARG.long)
.help(SKIP_SEED_PHRASE_VALIDATION_ARG.help), .help(SKIP_SEED_PHRASE_VALIDATION_ARG.help),
) )
.arg( .arg(
Arg::with_name("outfile") Arg::new("outfile")
.short("o") .short('o')
.long("outfile") .long("outfile")
.value_name("FILEPATH") .value_name("FILEPATH")
.takes_value(true) .takes_value(true)
.help("Path to generated file"), .help("Path to generated file"),
) )
.arg( .arg(
Arg::with_name("force") Arg::new("force")
.short("f") .short('f')
.long("force") .long("force")
.help("Overwrite the output file if it exists"), .help("Overwrite the output file if it exists"),
) )
) )
.subcommand( .subcommand(
SubCommand::with_name("recover") Command::new("recover")
.about("Recover keypair from seed phrase and optional BIP39 passphrase") .about("Recover keypair from seed phrase and optional BIP39 passphrase")
.setting(AppSettings::DisableVersion) .disable_version_flag(true)
.arg( .arg(
Arg::with_name("prompt_signer") Arg::new("prompt_signer")
.index(1) .index(1)
.value_name("KEYPAIR") .value_name("KEYPAIR")
.takes_value(true) .takes_value(true)
@ -500,21 +501,21 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.help("`prompt:` URI scheme or `ASK` keyword"), .help("`prompt:` URI scheme or `ASK` keyword"),
) )
.arg( .arg(
Arg::with_name("outfile") Arg::new("outfile")
.short("o") .short('o')
.long("outfile") .long("outfile")
.value_name("FILEPATH") .value_name("FILEPATH")
.takes_value(true) .takes_value(true)
.help("Path to generated file"), .help("Path to generated file"),
) )
.arg( .arg(
Arg::with_name("force") Arg::new("force")
.short("f") .short('f')
.long("force") .long("force")
.help("Overwrite the output file if it exists"), .help("Overwrite the output file if it exists"),
) )
.arg( .arg(
Arg::with_name(SKIP_SEED_PHRASE_VALIDATION_ARG.name) Arg::new(SKIP_SEED_PHRASE_VALIDATION_ARG.name)
.long(SKIP_SEED_PHRASE_VALIDATION_ARG.long) .long(SKIP_SEED_PHRASE_VALIDATION_ARG.long)
.help(SKIP_SEED_PHRASE_VALIDATION_ARG.help), .help(SKIP_SEED_PHRASE_VALIDATION_ARG.help),
), ),
@ -525,7 +526,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
do_main(&matches).map_err(|err| DisplayError::new_as_boxed(err).into()) do_main(&matches).map_err(|err| DisplayError::new_as_boxed(err).into())
} }
fn do_main(matches: &ArgMatches<'_>) -> Result<(), Box<dyn error::Error>> { fn do_main(matches: &ArgMatches) -> Result<(), Box<dyn error::Error>> {
let config = if let Some(config_file) = matches.value_of("config_file") { let config = if let Some(config_file) = matches.value_of("config_file") {
Config::load(config_file).unwrap_or_default() Config::load(config_file).unwrap_or_default()
} else { } else {
@ -534,8 +535,10 @@ fn do_main(matches: &ArgMatches<'_>) -> Result<(), Box<dyn error::Error>> {
let mut wallet_manager = None; let mut wallet_manager = None;
match matches.subcommand() { let subcommand = matches.subcommand().unwrap();
("pubkey", Some(matches)) => {
match subcommand {
("pubkey", matches) => {
let pubkey = let pubkey =
get_keypair_from_matches(matches, config, &mut wallet_manager)?.try_pubkey()?; get_keypair_from_matches(matches, config, &mut wallet_manager)?.try_pubkey()?;
@ -547,7 +550,7 @@ fn do_main(matches: &ArgMatches<'_>) -> Result<(), Box<dyn error::Error>> {
println!("{}", pubkey); println!("{}", pubkey);
} }
} }
("new", Some(matches)) => { ("new", matches) => {
let mut path = dirs_next::home_dir().expect("home directory"); let mut path = dirs_next::home_dir().expect("home directory");
let outfile = if matches.is_present("outfile") { let outfile = if matches.is_present("outfile") {
matches.value_of("outfile") matches.value_of("outfile")
@ -564,7 +567,7 @@ fn do_main(matches: &ArgMatches<'_>) -> Result<(), Box<dyn error::Error>> {
None => (), None => (),
} }
let word_count = value_t!(matches.value_of(WORD_COUNT_ARG.name), usize).unwrap(); let word_count: usize = matches.value_of_t(WORD_COUNT_ARG.name).unwrap();
let mnemonic_type = MnemonicType::for_word_count(word_count)?; let mnemonic_type = MnemonicType::for_word_count(word_count)?;
let language = acquire_language(matches); let language = acquire_language(matches);
@ -592,7 +595,7 @@ fn do_main(matches: &ArgMatches<'_>) -> Result<(), Box<dyn error::Error>> {
); );
} }
} }
("recover", Some(matches)) => { ("recover", matches) => {
let mut path = dirs_next::home_dir().expect("home directory"); let mut path = dirs_next::home_dir().expect("home directory");
let outfile = if matches.is_present("outfile") { let outfile = if matches.is_present("outfile") {
matches.value_of("outfile").unwrap() matches.value_of("outfile").unwrap()
@ -614,11 +617,12 @@ fn do_main(matches: &ArgMatches<'_>) -> Result<(), Box<dyn error::Error>> {
}; };
output_keypair(&keypair, outfile, "recovered")?; output_keypair(&keypair, outfile, "recovered")?;
} }
("grind", Some(matches)) => { ("grind", matches) => {
let ignore_case = matches.is_present("ignore_case"); let ignore_case = matches.is_present("ignore_case");
let starts_with_args = if matches.is_present("starts_with") { let starts_with_args = if matches.is_present("starts_with") {
values_t_or_exit!(matches, "starts_with", String) matches
.values_of_t_or_exit::<String>("starts_with")
.into_iter() .into_iter()
.map(|s| if ignore_case { s.to_lowercase() } else { s }) .map(|s| if ignore_case { s.to_lowercase() } else { s })
.collect() .collect()
@ -626,7 +630,8 @@ fn do_main(matches: &ArgMatches<'_>) -> Result<(), Box<dyn error::Error>> {
HashSet::new() HashSet::new()
}; };
let ends_with_args = if matches.is_present("ends_with") { let ends_with_args = if matches.is_present("ends_with") {
values_t_or_exit!(matches, "ends_with", String) matches
.values_of_t_or_exit::<String>("ends_with")
.into_iter() .into_iter()
.map(|s| if ignore_case { s.to_lowercase() } else { s }) .map(|s| if ignore_case { s.to_lowercase() } else { s })
.collect() .collect()
@ -634,7 +639,8 @@ fn do_main(matches: &ArgMatches<'_>) -> Result<(), Box<dyn error::Error>> {
HashSet::new() HashSet::new()
}; };
let starts_and_ends_with_args = if matches.is_present("starts_and_ends_with") { let starts_and_ends_with_args = if matches.is_present("starts_and_ends_with") {
values_t_or_exit!(matches, "starts_and_ends_with", String) matches
.values_of_t_or_exit::<String>("starts_and_ends_with")
.into_iter() .into_iter()
.map(|s| if ignore_case { s.to_lowercase() } else { s }) .map(|s| if ignore_case { s.to_lowercase() } else { s })
.collect() .collect()
@ -652,7 +658,7 @@ fn do_main(matches: &ArgMatches<'_>) -> Result<(), Box<dyn error::Error>> {
exit(1); exit(1);
} }
let num_threads = value_t_or_exit!(matches.value_of("num_threads"), usize); let num_threads: usize = matches.value_of_t_or_exit("num_threads");
let grind_matches = grind_parse_args( let grind_matches = grind_parse_args(
ignore_case, ignore_case,
@ -664,7 +670,7 @@ fn do_main(matches: &ArgMatches<'_>) -> Result<(), Box<dyn error::Error>> {
let use_mnemonic = matches.is_present("use_mnemonic"); let use_mnemonic = matches.is_present("use_mnemonic");
let word_count = value_t!(matches.value_of(WORD_COUNT_ARG.name), usize).unwrap(); let word_count: usize = matches.value_of_t(WORD_COUNT_ARG.name).unwrap();
let mnemonic_type = MnemonicType::for_word_count(word_count)?; let mnemonic_type = MnemonicType::for_word_count(word_count)?;
let language = acquire_language(matches); let language = acquire_language(matches);
@ -766,7 +772,7 @@ fn do_main(matches: &ArgMatches<'_>) -> Result<(), Box<dyn error::Error>> {
thread_handle.join().unwrap(); thread_handle.join().unwrap();
} }
} }
("verify", Some(matches)) => { ("verify", matches) => {
let keypair = get_keypair_from_matches(matches, config, &mut wallet_manager)?; let keypair = get_keypair_from_matches(matches, config, &mut wallet_manager)?;
let simple_message = Message::new( let simple_message = Message::new(
&[Instruction::new_with_bincode( &[Instruction::new_with_bincode(