Remove ask-seed-phrase arg from validator, archiver (#8697)
* Remove ask-seed-phrase from validator * Update paper-wallet docs * Remove ask-seed-phrase from archiver * Remove unused structs, methods
This commit is contained in:
@ -2,21 +2,20 @@ use clap::{crate_description, crate_name, App, Arg};
|
|||||||
use console::style;
|
use console::style;
|
||||||
use solana_archiver_lib::archiver::Archiver;
|
use solana_archiver_lib::archiver::Archiver;
|
||||||
use solana_clap_utils::{
|
use solana_clap_utils::{
|
||||||
input_validators::is_keypair,
|
input_parsers::keypair_of, input_validators::is_keypair_or_ask_keyword,
|
||||||
keypair::{
|
keypair::SKIP_SEED_PHRASE_VALIDATION_ARG,
|
||||||
self, keypair_input, KeypairWithSource, ASK_SEED_PHRASE_ARG,
|
|
||||||
SKIP_SEED_PHRASE_VALIDATION_ARG,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use solana_core::{
|
use solana_core::{
|
||||||
cluster_info::{Node, VALIDATOR_PORT_RANGE},
|
cluster_info::{Node, VALIDATOR_PORT_RANGE},
|
||||||
contact_info::ContactInfo,
|
contact_info::ContactInfo,
|
||||||
};
|
};
|
||||||
use solana_sdk::{commitment_config::CommitmentConfig, signature::Signer};
|
use solana_sdk::{
|
||||||
|
commitment_config::CommitmentConfig,
|
||||||
|
signature::{Keypair, Signer},
|
||||||
|
};
|
||||||
use std::{
|
use std::{
|
||||||
net::{IpAddr, Ipv4Addr, SocketAddr},
|
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
process::exit,
|
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -32,7 +31,7 @@ fn main() {
|
|||||||
.long("identity-keypair")
|
.long("identity-keypair")
|
||||||
.value_name("PATH")
|
.value_name("PATH")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.validator(is_keypair)
|
.validator(is_keypair_or_ask_keyword)
|
||||||
.help("File containing an identity (keypair)"),
|
.help("File containing an identity (keypair)"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
@ -60,48 +59,27 @@ fn main() {
|
|||||||
.long("storage-keypair")
|
.long("storage-keypair")
|
||||||
.value_name("PATH")
|
.value_name("PATH")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.validator(is_keypair)
|
.validator(is_keypair_or_ask_keyword)
|
||||||
.help("File containing the storage account keypair"),
|
.help("File containing the storage account keypair"),
|
||||||
)
|
)
|
||||||
.arg(
|
|
||||||
Arg::with_name(ASK_SEED_PHRASE_ARG.name)
|
|
||||||
.long(ASK_SEED_PHRASE_ARG.long)
|
|
||||||
.value_name("KEYPAIR NAME")
|
|
||||||
.multiple(true)
|
|
||||||
.takes_value(true)
|
|
||||||
.possible_values(&["identity-keypair", "storage-keypair"])
|
|
||||||
.help(ASK_SEED_PHRASE_ARG.help),
|
|
||||||
)
|
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(SKIP_SEED_PHRASE_VALIDATION_ARG.name)
|
Arg::with_name(SKIP_SEED_PHRASE_VALIDATION_ARG.name)
|
||||||
.long(SKIP_SEED_PHRASE_VALIDATION_ARG.long)
|
.long(SKIP_SEED_PHRASE_VALIDATION_ARG.long)
|
||||||
.requires(ASK_SEED_PHRASE_ARG.name)
|
|
||||||
.help(SKIP_SEED_PHRASE_VALIDATION_ARG.help),
|
.help(SKIP_SEED_PHRASE_VALIDATION_ARG.help),
|
||||||
)
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
let ledger_path = PathBuf::from(matches.value_of("ledger").unwrap());
|
let ledger_path = PathBuf::from(matches.value_of("ledger").unwrap());
|
||||||
|
|
||||||
let identity_keypair = keypair_input(&matches, "identity_keypair")
|
let identity_keypair = keypair_of(&matches, "identity_keypair").unwrap_or_else(Keypair::new);
|
||||||
.unwrap_or_else(|err| {
|
|
||||||
eprintln!("Identity keypair input failed: {}", err);
|
let storage_keypair = keypair_of(&matches, "storage_keypair").unwrap_or_else(|| {
|
||||||
exit(1);
|
|
||||||
})
|
|
||||||
.keypair;
|
|
||||||
let KeypairWithSource {
|
|
||||||
keypair: storage_keypair,
|
|
||||||
source: storage_keypair_source,
|
|
||||||
} = keypair_input(&matches, "storage_keypair").unwrap_or_else(|err| {
|
|
||||||
eprintln!("Storage keypair input failed: {}", err);
|
|
||||||
exit(1);
|
|
||||||
});
|
|
||||||
if storage_keypair_source == keypair::Source::Generated {
|
|
||||||
clap::Error::with_description(
|
clap::Error::with_description(
|
||||||
"The `storage-keypair` argument was not found",
|
"The `storage-keypair` argument was not found",
|
||||||
clap::ErrorKind::ArgumentNotFound,
|
clap::ErrorKind::ArgumentNotFound,
|
||||||
)
|
)
|
||||||
.exit();
|
.exit();
|
||||||
}
|
});
|
||||||
|
|
||||||
let entrypoint_addr = matches
|
let entrypoint_addr = matches
|
||||||
.value_of("entrypoint")
|
.value_of("entrypoint")
|
||||||
|
@ -4,7 +4,7 @@ use crate::{
|
|||||||
ArgConstant,
|
ArgConstant,
|
||||||
};
|
};
|
||||||
use bip39::{Language, Mnemonic, Seed};
|
use bip39::{Language, Mnemonic, Seed};
|
||||||
use clap::{values_t, ArgMatches, Error, ErrorKind};
|
use clap::{ArgMatches, Error, ErrorKind};
|
||||||
use rpassword::prompt_password_stderr;
|
use rpassword::prompt_password_stderr;
|
||||||
use solana_remote_wallet::{
|
use solana_remote_wallet::{
|
||||||
remote_keypair::generate_remote_keypair,
|
remote_keypair::generate_remote_keypair,
|
||||||
@ -113,36 +113,12 @@ pub fn signer_from_path(
|
|||||||
// Keyword used to indicate that the user should be asked for a keypair seed phrase
|
// Keyword used to indicate that the user should be asked for a keypair seed phrase
|
||||||
pub const ASK_KEYWORD: &str = "ASK";
|
pub const ASK_KEYWORD: &str = "ASK";
|
||||||
|
|
||||||
pub const ASK_SEED_PHRASE_ARG: ArgConstant<'static> = ArgConstant {
|
|
||||||
long: "ask-seed-phrase",
|
|
||||||
name: "ask_seed_phrase",
|
|
||||||
help: "Recover a keypair using a seed phrase and optional passphrase",
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const SKIP_SEED_PHRASE_VALIDATION_ARG: ArgConstant<'static> = ArgConstant {
|
pub const SKIP_SEED_PHRASE_VALIDATION_ARG: ArgConstant<'static> = ArgConstant {
|
||||||
long: "skip-seed-phrase-validation",
|
long: "skip-seed-phrase-validation",
|
||||||
name: "skip_seed_phrase_validation",
|
name: "skip_seed_phrase_validation",
|
||||||
help: "Skip validation of seed phrases. Use this if your phrase does not use the BIP39 official English word list",
|
help: "Skip validation of seed phrases. Use this if your phrase does not use the BIP39 official English word list",
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub enum Source {
|
|
||||||
Generated,
|
|
||||||
Path,
|
|
||||||
SeedPhrase,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct KeypairWithSource {
|
|
||||||
pub keypair: Keypair,
|
|
||||||
pub source: Source,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl KeypairWithSource {
|
|
||||||
fn new(keypair: Keypair, source: Source) -> Self {
|
|
||||||
Self { keypair, source }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Prompts user for a passphrase and then asks for confirmirmation to check for mistakes
|
/// Prompts user for a passphrase and then asks for confirmirmation to check for mistakes
|
||||||
pub fn prompt_passphrase(prompt: &str) -> Result<String, Box<dyn error::Error>> {
|
pub fn prompt_passphrase(prompt: &str) -> Result<String, Box<dyn error::Error>> {
|
||||||
let passphrase = prompt_password_stderr(&prompt)?;
|
let passphrase = prompt_password_stderr(&prompt)?;
|
||||||
@ -196,47 +172,6 @@ pub fn keypair_from_seed_phrase(
|
|||||||
Ok(keypair)
|
Ok(keypair)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks CLI arguments to determine whether a keypair should be:
|
|
||||||
/// - inputted securely via stdin,
|
|
||||||
/// - read in from a file,
|
|
||||||
/// - or newly generated
|
|
||||||
pub fn keypair_input(
|
|
||||||
matches: &clap::ArgMatches,
|
|
||||||
keypair_name: &str,
|
|
||||||
) -> Result<KeypairWithSource, Box<dyn error::Error>> {
|
|
||||||
let ask_seed_phrase_matches =
|
|
||||||
values_t!(matches.values_of(ASK_SEED_PHRASE_ARG.name), String).unwrap_or_default();
|
|
||||||
let keypair_match_name = keypair_name.replace('-', "_");
|
|
||||||
if ask_seed_phrase_matches
|
|
||||||
.iter()
|
|
||||||
.any(|s| s.as_str() == keypair_name)
|
|
||||||
{
|
|
||||||
if matches.value_of(keypair_match_name).is_some() {
|
|
||||||
clap::Error::with_description(
|
|
||||||
&format!(
|
|
||||||
"`--{} {}` cannot be used with `{} <PATH>`",
|
|
||||||
ASK_SEED_PHRASE_ARG.long, keypair_name, keypair_name
|
|
||||||
),
|
|
||||||
clap::ErrorKind::ArgumentConflict,
|
|
||||||
)
|
|
||||||
.exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
let skip_validation = matches.is_present(SKIP_SEED_PHRASE_VALIDATION_ARG.name);
|
|
||||||
keypair_from_seed_phrase(keypair_name, skip_validation, true)
|
|
||||||
.map(|keypair| KeypairWithSource::new(keypair, Source::SeedPhrase))
|
|
||||||
} else if let Some(keypair_file) = matches.value_of(keypair_match_name) {
|
|
||||||
if keypair_file.starts_with("usb://") {
|
|
||||||
Ok(KeypairWithSource::new(Keypair::new(), Source::Path))
|
|
||||||
} else {
|
|
||||||
read_keypair_file(keypair_file)
|
|
||||||
.map(|keypair| KeypairWithSource::new(keypair, Source::Path))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(KeypairWithSource::new(Keypair::new(), Source::Generated))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sanitize_seed_phrase(seed_phrase: &str) -> String {
|
fn sanitize_seed_phrase(seed_phrase: &str) -> String {
|
||||||
seed_phrase
|
seed_phrase
|
||||||
.split_whitespace()
|
.split_whitespace()
|
||||||
@ -247,14 +182,6 @@ fn sanitize_seed_phrase(seed_phrase: &str) -> String {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use clap::ArgMatches;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_keypair_input() {
|
|
||||||
let arg_matches = ArgMatches::default();
|
|
||||||
let KeypairWithSource { source, .. } = keypair_input(&arg_matches, "").unwrap();
|
|
||||||
assert_eq!(source, Source::Generated);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sanitize_seed_phrase() {
|
fn test_sanitize_seed_phrase() {
|
||||||
|
@ -233,21 +233,20 @@ done < public_keys.txt
|
|||||||
|
|
||||||
In order to run a validator, you will need to specify an "identity keypair"
|
In order to run a validator, you will need to specify an "identity keypair"
|
||||||
which will be used to fund all of the vote transactions signed by your validator.
|
which will be used to fund all of the vote transactions signed by your validator.
|
||||||
Rather than specifying a path with `--identity-keypair <PATH>` you can use the
|
Rather than specifying a path with `--identity-keypair <PATH>` you can pass
|
||||||
`--ask-seed-phrase` option.
|
`ASK` to securely input the funding keypair.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana-validator --ask-seed-phrase identity-keypair --ledger ...
|
solana-validator --identity-keypair ASK --ledger ...
|
||||||
|
|
||||||
[identity-keypair] seed phrase: 🔒
|
[identity-keypair] seed phrase: 🔒
|
||||||
[identity-keypair] If this seed phrase has an associated passphrase, enter it now. Otherwise, press ENTER to continue:
|
[identity-keypair] If this seed phrase has an associated passphrase, enter it now. Otherwise, press ENTER to continue:
|
||||||
```
|
```
|
||||||
|
|
||||||
The `--ask-seed-phrase` option accepts multiple keypairs. If you wish to use this
|
You can use this input method for your voting keypair as well:
|
||||||
input method for your voting keypair as well you can do the following:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana-validator --ask-seed-phrase identity-keypair voting-keypair --ledger ...
|
solana-validator --identity-keypair ASK --voting-keypair ASK --ledger ...
|
||||||
|
|
||||||
[identity-keypair] seed phrase: 🔒
|
[identity-keypair] seed phrase: 🔒
|
||||||
[identity-keypair] If this seed phrase has an associated passphrase, enter it now. Otherwise, press ENTER to continue:
|
[identity-keypair] If this seed phrase has an associated passphrase, enter it now. Otherwise, press ENTER to continue:
|
||||||
|
@ -7,12 +7,9 @@ use indicatif::{ProgressBar, ProgressStyle};
|
|||||||
use log::*;
|
use log::*;
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
use solana_clap_utils::{
|
use solana_clap_utils::{
|
||||||
input_parsers::pubkey_of,
|
input_parsers::{keypair_of, pubkey_of},
|
||||||
input_validators::{is_keypair, is_pubkey, is_pubkey_or_keypair, is_slot},
|
input_validators::{is_keypair_or_ask_keyword, is_pubkey, is_pubkey_or_keypair, is_slot},
|
||||||
keypair::{
|
keypair::SKIP_SEED_PHRASE_VALIDATION_ARG,
|
||||||
self, keypair_input, KeypairWithSource, ASK_SEED_PHRASE_ARG,
|
|
||||||
SKIP_SEED_PHRASE_VALIDATION_ARG,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use solana_client::rpc_client::RpcClient;
|
use solana_client::rpc_client::RpcClient;
|
||||||
use solana_core::ledger_cleanup_service::DEFAULT_MAX_LEDGER_SLOTS;
|
use solana_core::ledger_cleanup_service::DEFAULT_MAX_LEDGER_SLOTS;
|
||||||
@ -553,19 +550,9 @@ pub fn main() {
|
|||||||
.value_name("UNIX DOMAIN SOCKET")
|
.value_name("UNIX DOMAIN SOCKET")
|
||||||
.help("Stream entries to this unix domain socket path")
|
.help("Stream entries to this unix domain socket path")
|
||||||
)
|
)
|
||||||
.arg(
|
|
||||||
Arg::with_name(ASK_SEED_PHRASE_ARG.name)
|
|
||||||
.long(ASK_SEED_PHRASE_ARG.long)
|
|
||||||
.value_name("KEYPAIR NAME")
|
|
||||||
.multiple(true)
|
|
||||||
.takes_value(true)
|
|
||||||
.possible_values(&["identity-keypair", "storage-keypair", "voting-keypair"])
|
|
||||||
.help(ASK_SEED_PHRASE_ARG.help),
|
|
||||||
)
|
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(SKIP_SEED_PHRASE_VALIDATION_ARG.name)
|
Arg::with_name(SKIP_SEED_PHRASE_VALIDATION_ARG.name)
|
||||||
.long(SKIP_SEED_PHRASE_VALIDATION_ARG.long)
|
.long(SKIP_SEED_PHRASE_VALIDATION_ARG.long)
|
||||||
.requires(ASK_SEED_PHRASE_ARG.name)
|
|
||||||
.help(SKIP_SEED_PHRASE_VALIDATION_ARG.help),
|
.help(SKIP_SEED_PHRASE_VALIDATION_ARG.help),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
@ -574,7 +561,7 @@ pub fn main() {
|
|||||||
.long("identity-keypair")
|
.long("identity-keypair")
|
||||||
.value_name("PATH")
|
.value_name("PATH")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.validator(is_keypair)
|
.validator(is_keypair_or_ask_keyword)
|
||||||
.help("File containing the identity keypair for the validator"),
|
.help("File containing the identity keypair for the validator"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
@ -582,7 +569,7 @@ pub fn main() {
|
|||||||
.long("voting-keypair")
|
.long("voting-keypair")
|
||||||
.value_name("PATH")
|
.value_name("PATH")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.validator(is_keypair)
|
.validator(is_keypair_or_ask_keyword)
|
||||||
.help("File containing the authorized voting keypair. Default is an ephemeral keypair, which may disable voting without --vote-account."),
|
.help("File containing the authorized voting keypair. Default is an ephemeral keypair, which may disable voting without --vote-account."),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
@ -598,7 +585,7 @@ pub fn main() {
|
|||||||
.long("storage-keypair")
|
.long("storage-keypair")
|
||||||
.value_name("PATH")
|
.value_name("PATH")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.validator(is_keypair)
|
.validator(is_keypair_or_ask_keyword)
|
||||||
.help("File containing the storage account keypair. Default is an ephemeral keypair"),
|
.help("File containing the storage account keypair. Default is an ephemeral keypair"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
@ -854,28 +841,14 @@ pub fn main() {
|
|||||||
)
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
let identity_keypair = Arc::new(
|
let identity_keypair =
|
||||||
keypair_input(&matches, "identity-keypair")
|
Arc::new(keypair_of(&matches, "identity_keypair").unwrap_or_else(Keypair::new));
|
||||||
.unwrap_or_else(|err| {
|
|
||||||
eprintln!("Identity keypair input failed: {}", err);
|
let (voting_keypair, ephemeral_voting_keypair) = keypair_of(&matches, "voting_keypair")
|
||||||
exit(1);
|
.map(|keypair| (keypair, false))
|
||||||
})
|
.unwrap_or_else(|| (Keypair::new(), true));
|
||||||
.keypair,
|
|
||||||
);
|
let storage_keypair = keypair_of(&matches, "storage_keypair").unwrap_or_else(Keypair::new);
|
||||||
let KeypairWithSource {
|
|
||||||
keypair: voting_keypair,
|
|
||||||
source: voting_keypair_source,
|
|
||||||
} = keypair_input(&matches, "voting-keypair").unwrap_or_else(|err| {
|
|
||||||
eprintln!("Voting keypair input failed: {}", err);
|
|
||||||
exit(1);
|
|
||||||
});
|
|
||||||
let ephemeral_voting_keypair = voting_keypair_source == keypair::Source::Generated;
|
|
||||||
let storage_keypair = keypair_input(&matches, "storage-keypair")
|
|
||||||
.unwrap_or_else(|err| {
|
|
||||||
eprintln!("Storage keypair input failed: {}", err);
|
|
||||||
exit(1);
|
|
||||||
})
|
|
||||||
.keypair;
|
|
||||||
|
|
||||||
let ledger_path = PathBuf::from(matches.value_of("ledger_path").unwrap());
|
let ledger_path = PathBuf::from(matches.value_of("ledger_path").unwrap());
|
||||||
let entrypoint = matches.value_of("entrypoint");
|
let entrypoint = matches.value_of("entrypoint");
|
||||||
|
Reference in New Issue
Block a user