keygen: add the ability to use derivation path for new & grind commands (#21614)

* keygen: add --use-derivation-path for new & grind

* keygen: add prompt:// uri scheme to new and grind

* fmt

* migrate to clap-v3-utils

* Revert "migrate to clap-v3-utils"

This reverts commit 77f33262ce6c4e95ac1cc62cca32749516f7f357.

* Revert "fmt"

This reverts commit 038cd4ce9628c57dec1f5a4716e2c5baacbe57b3.

* Revert "keygen: add prompt:// uri scheme to new and grind"

This reverts commit 029ea61409a1a16ba2c45483ade2c01f84f25fac.

* - remove `use` from arg
- fix issue from first commit with default value for derivation path
- refactor arg definition and acquiring
This commit is contained in:
DimAn 2022-09-07 20:31:40 +02:00 committed by GitHub
parent d6a1e7498f
commit 6899af26b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 4 deletions

View File

@ -14,10 +14,14 @@ use {
solana_cli_config::{Config, CONFIG_FILE}, solana_cli_config::{Config, CONFIG_FILE},
solana_remote_wallet::remote_wallet::RemoteWalletManager, solana_remote_wallet::remote_wallet::RemoteWalletManager,
solana_sdk::{ solana_sdk::{
derivation_path::DerivationPath,
instruction::{AccountMeta, Instruction}, instruction::{AccountMeta, Instruction},
message::Message, message::Message,
pubkey::{write_pubkey_file, Pubkey}, pubkey::{write_pubkey_file, Pubkey},
signature::{keypair_from_seed, write_keypair, write_keypair_file, Keypair, Signer}, signature::{
keypair_from_seed, keypair_from_seed_and_derivation_path, write_keypair,
write_keypair_file, Keypair, Signer,
},
}, },
std::{ std::{
collections::HashSet, collections::HashSet,
@ -34,6 +38,7 @@ use {
}; };
const NO_PASSPHRASE: &str = ""; const NO_PASSPHRASE: &str = "";
const DEFAULT_DERIVATION_PATH: &str = "m/44'/501'/0'/0'";
struct GrindMatch { struct GrindMatch {
starts: String, starts: String,
@ -325,6 +330,33 @@ fn grind_parse_args(
grind_matches grind_matches
} }
fn derivation_path_arg<'a>() -> Arg<'a> {
Arg::new("derivation_path")
.long("derivation-path")
.value_name("DERIVATION_PATH")
.takes_value(true)
.min_values(0)
.max_values(1)
.help("Derivation path. All indexes will be promoted to hardened. \
If arg is not presented then derivation path will not be used. \
If arg is presented with empty DERIVATION_PATH value then m/44'/501'/0'/0' will be used."
)
}
fn acquire_derivation_path(
matches: &ArgMatches,
) -> Result<Option<DerivationPath>, Box<dyn error::Error>> {
if matches.is_present("derivation_path") {
Ok(Some(DerivationPath::from_absolute_path_str(
matches
.value_of("derivation_path")
.unwrap_or(DEFAULT_DERIVATION_PATH),
)?))
} else {
Ok(None)
}
}
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 = Command::new(crate_name!()) let matches = Command::new(crate_name!())
@ -389,6 +421,9 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.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"),
) )
.arg(
derivation_path_arg()
)
.key_generation_common_args() .key_generation_common_args()
.arg(no_outfile_arg() .arg(no_outfile_arg()
.conflicts_with_all(&["outfile", "silent"]) .conflicts_with_all(&["outfile", "silent"])
@ -450,6 +485,10 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.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"),
) )
.arg(
derivation_path_arg()
.requires("use_mnemonic")
)
.key_generation_common_args() .key_generation_common_args()
.arg( .arg(
no_outfile_arg() no_outfile_arg()
@ -576,11 +615,17 @@ fn do_main(matches: &ArgMatches) -> Result<(), Box<dyn error::Error>> {
if !silent { if !silent {
println!("Generating a new keypair"); println!("Generating a new keypair");
} }
let derivation_path = acquire_derivation_path(matches)?;
let mnemonic = Mnemonic::new(mnemonic_type, language); let mnemonic = Mnemonic::new(mnemonic_type, language);
let (passphrase, passphrase_message) = acquire_passphrase_and_message(matches).unwrap(); let (passphrase, passphrase_message) = acquire_passphrase_and_message(matches).unwrap();
let seed = Seed::new(&mnemonic, &passphrase); let seed = Seed::new(&mnemonic, &passphrase);
let keypair = keypair_from_seed(seed.as_bytes())?; let keypair = match derivation_path {
Some(_) => keypair_from_seed_and_derivation_path(seed.as_bytes(), derivation_path),
None => keypair_from_seed(seed.as_bytes()),
}?;
if let Some(outfile) = outfile { if let Some(outfile) = outfile {
output_keypair(&keypair, outfile, "new") output_keypair(&keypair, outfile, "new")
@ -671,6 +716,8 @@ 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 derivation_path = acquire_derivation_path(matches)?;
let word_count: usize = matches.value_of_t(WORD_COUNT_ARG.name).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);
@ -696,6 +743,7 @@ fn do_main(matches: &ArgMatches) -> Result<(), Box<dyn error::Error>> {
let grind_matches_thread_safe = grind_matches_thread_safe.clone(); let grind_matches_thread_safe = grind_matches_thread_safe.clone();
let passphrase = passphrase.clone(); let passphrase = passphrase.clone();
let passphrase_message = passphrase_message.clone(); let passphrase_message = passphrase_message.clone();
let derivation_path = derivation_path.clone();
thread::spawn(move || loop { thread::spawn(move || loop {
if done.load(Ordering::Relaxed) { if done.load(Ordering::Relaxed) {
@ -713,7 +761,11 @@ fn do_main(matches: &ArgMatches) -> Result<(), Box<dyn error::Error>> {
let (keypair, phrase) = if use_mnemonic { let (keypair, phrase) = if use_mnemonic {
let mnemonic = Mnemonic::new(mnemonic_type, language); let mnemonic = Mnemonic::new(mnemonic_type, language);
let seed = Seed::new(&mnemonic, &passphrase); let seed = Seed::new(&mnemonic, &passphrase);
(keypair_from_seed(seed.as_bytes()).unwrap(), mnemonic.phrase().to_string()) let keypair = match derivation_path {
Some(_) => keypair_from_seed_and_derivation_path(seed.as_bytes(), derivation_path.clone()),
None => keypair_from_seed(seed.as_bytes()),
}.unwrap();
(keypair, mnemonic.phrase().to_string())
} else { } else {
(Keypair::new(), "".to_string()) (Keypair::new(), "".to_string())
}; };

View File

@ -79,7 +79,7 @@ impl DerivationPath {
Ok(Self::new_bip44_with_coin(coin, account, change)) Ok(Self::new_bip44_with_coin(coin, account, change))
} }
fn from_absolute_path_str(path: &str) -> Result<Self, DerivationPathError> { pub fn from_absolute_path_str(path: &str) -> Result<Self, DerivationPathError> {
let inner = DerivationPath::_from_absolute_path_insecure_str(path)? let inner = DerivationPath::_from_absolute_path_insecure_str(path)?
.into_iter() .into_iter()
.map(|c| ChildIndex::Hardened(c.to_u32())) .map(|c| ChildIndex::Hardened(c.to_u32()))