Allow secure keypair input for solana-validator cli (#7080)

* Allow secure keypair input for solana-validator cli

* feedback

* Add --skip-mnemonic-validation

* Update --identity to --identity-keypair

* Use struct instead of tuple

* Fix dependencies

* cargo fmt

* Add basic tests

* Use `seed phrase` instead of `mnemonic`

* Update passphrase prompt
This commit is contained in:
Justin Starry 2019-11-22 10:20:40 -05:00 committed by GitHub
parent c8166aed97
commit ce8d37984d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 252 additions and 94 deletions

5
Cargo.lock generated
View File

@ -3197,8 +3197,10 @@ name = "solana-clap-utils"
version = "0.21.0"
dependencies = [
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rpassword 4.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-sdk 0.21.0",
"tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -3859,12 +3861,14 @@ dependencies = [
"ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)",
"generic-array 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3874,6 +3878,7 @@ dependencies = [
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-crate-features 0.21.0",
"solana-logger 0.21.0",
"tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]

View File

@ -76,19 +76,19 @@ Then use one of the following commands, depending on your installation choice, t
If this is a `solana-install`-installation:
```bash
solana-validator --identity ~/validator-keypair.json --voting-keypair ~/validator-vote-keypair.json --ledger ~/validator-config --rpc-port 8899 --entrypoint testnet.solana.com:8001
solana-validator --identity-keypair ~/validator-keypair.json --voting-keypair ~/validator-vote-keypair.json --ledger ~/validator-config --rpc-port 8899 --entrypoint testnet.solana.com:8001
```
Alternatively, the `solana-install run` command can be used to run the validator node while periodically checking for and applying software updates:
```bash
solana-install run solana-validator -- --identity ~/validator-keypair.json --voting-keypair ~/validator-vote-keypair.json --ledger ~/validator-config --rpc-port 8899 --entrypoint testnet.solana.com:8001
solana-install run solana-validator -- --identity-keypair ~/validator-keypair.json --voting-keypair ~/validator-vote-keypair.json --ledger ~/validator-config --rpc-port 8899 --entrypoint testnet.solana.com:8001
```
If you built from source:
```bash
NDEBUG=1 USE_INSTALL=1 ./multinode-demo/validator.sh --identity ~/validator-keypair.json --voting-keypair ~/validator-vote-keypair.json --rpc-port 8899 --entrypoint testnet.solana.com:8001
NDEBUG=1 USE_INSTALL=1 ./multinode-demo/validator.sh --identity-keypair ~/validator-keypair.json --voting-keypair ~/validator-vote-keypair.json --rpc-port 8899 --entrypoint testnet.solana.com:8001
```
### Enabling CUDA

View File

@ -63,7 +63,7 @@ solana balance # Same result as command above
Solana-gossip and solana-validator commands already require an explicit `--entrypoint` argument. Simply replace testnet.solana.com in the examples with an alternate url to interact with a different testnet. For example:
```bash
solana-validator --identity ~/validator-keypair.json --voting-keypair ~/validator-vote-keypair.json --ledger ~/validator-config --rpc-port 8899 beta.testnet.solana.com
solana-validator --identity-keypair ~/validator-keypair.json --voting-keypair ~/validator-vote-keypair.json --ledger ~/validator-config --rpc-port 8899 beta.testnet.solana.com
```
You can also submit JSON-RPC requests to a different testnet, like:

View File

@ -10,8 +10,10 @@ edition = "2018"
[dependencies]
clap = "2.33.0"
rpassword = "4.0"
semver = "0.9.0"
solana-sdk = { path = "../sdk", version = "0.21.0" }
tiny-bip39 = "0.6.2"
url = "2.1.0"
[lib]

95
clap-utils/src/keypair.rs Normal file
View File

@ -0,0 +1,95 @@
use bip39::{Language, Mnemonic, Seed};
use clap::values_t;
use rpassword::prompt_password_stderr;
use solana_sdk::signature::{
keypair_from_seed, keypair_from_seed_phrase_and_passphrase, read_keypair_file, Keypair,
KeypairUtil,
};
use std::error;
pub const ASK_SEED_PHRASE_ARG: &str = "ask_seed_phrase";
pub const SKIP_SEED_PHRASE_VALIDATION_ARG: &str = "skip_seed_phrase_validation";
/// Reads user input from stdin to retrieve a seed phrase and passphrase for keypair derivation
pub fn keypair_from_seed_phrase(
keypair_name: &str,
skip_validation: bool,
) -> Result<Keypair, Box<dyn error::Error>> {
let seed_phrase = prompt_password_stderr(&format!("[{}] seed phrase: ", keypair_name))?;
let seed_phrase = seed_phrase.trim();
let passphrase_prompt = format!(
"[{}] If this seed phrase has an associated passphrase, enter it now. Otherwise, press ENTER to continue: ",
keypair_name,
);
if skip_validation {
let passphrase = prompt_password_stderr(&passphrase_prompt)?;
keypair_from_seed_phrase_and_passphrase(&seed_phrase, &passphrase)
} else {
let mnemonic = Mnemonic::from_phrase(seed_phrase, Language::English)?;
let passphrase = prompt_password_stderr(&passphrase_prompt)?;
let seed = Seed::new(&mnemonic, &passphrase);
keypair_from_seed(seed.as_bytes())
}
}
pub struct KeypairWithGenerated {
pub keypair: Keypair,
pub generated: bool,
}
impl KeypairWithGenerated {
fn new(keypair: Keypair, generated: bool) -> Self {
Self { keypair, generated }
}
}
/// 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<KeypairWithGenerated, Box<dyn error::Error>> {
let ask_seed_phrase_matches =
values_t!(matches.values_of(ASK_SEED_PHRASE_ARG), 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() {
let ask_seed_phrase_kebab = ASK_SEED_PHRASE_ARG.replace('_', "-");
clap::Error::with_description(
&format!(
"`--{} {}` cannot be used with `{} <PATH>`",
ask_seed_phrase_kebab, keypair_name, keypair_name
),
clap::ErrorKind::ArgumentConflict,
)
.exit();
}
let skip_validation = matches.is_present(SKIP_SEED_PHRASE_VALIDATION_ARG);
keypair_from_seed_phrase(keypair_name, skip_validation)
.map(|keypair| KeypairWithGenerated::new(keypair, false))
} else if let Some(keypair_file) = matches.value_of(keypair_match_name) {
read_keypair_file(keypair_file).map(|keypair| KeypairWithGenerated::new(keypair, false))
} else {
Ok(KeypairWithGenerated::new(Keypair::new(), true))
}
}
#[cfg(test)]
mod tests {
use super::*;
use clap::ArgMatches;
#[test]
fn test_keypair_input() {
let arg_matches = ArgMatches::default();
let KeypairWithGenerated { generated, .. } = keypair_input(&arg_matches, "").unwrap();
assert!(generated);
}
}

View File

@ -19,3 +19,4 @@ macro_rules! version {
pub mod input_parsers;
pub mod input_validators;
pub mod keypair;

View File

@ -76,10 +76,10 @@ ledger_dir="$SOLANA_CONFIG_DIR"/bootstrap-leader
args+=(
--accounts "$SOLANA_CONFIG_DIR"/bootstrap-leader/accounts
--enable-rpc-exit
--identity "$identity_keypair"
--ledger "$ledger_dir"
--rpc-port 8899
--snapshot-interval-slots 100
--identity-keypair "$identity_keypair"
--storage-keypair "$storage_keypair"
--voting-keypair "$vote_keypair"
--rpc-drone-address 127.0.0.1:9900

View File

@ -70,7 +70,7 @@ while [[ -n $1 ]]; do
elif [[ $1 = --expected-genesis-hash ]]; then
args+=("$1" "$2")
shift 2
elif [[ $1 = --identity ]]; then
elif [[ $1 = --identity-keypair ]]; then
identity_keypair_path=$2
args+=("$1" "$2")
shift 2
@ -170,7 +170,7 @@ fi
if [[ -n $REQUIRE_KEYPAIRS ]]; then
if [[ -z $identity_keypair_path ]]; then
usage "Error: --identity not specified"
usage "Error: --identity-keypair not specified"
fi
if [[ -z $voting_keypair_path ]]; then
usage "Error: --voting-keypair not specified"
@ -209,7 +209,7 @@ if ((airdrops_enabled)); then
default_arg --rpc-drone-address "$drone_address"
fi
default_arg --identity "$identity_keypair_path"
default_arg --identity-keypair "$identity_keypair_path"
default_arg --voting-keypair "$voting_keypair_path"
default_arg --storage-keypair "$storage_keypair_path"
default_arg --ledger "$ledger_dir"

View File

@ -304,7 +304,7 @@ EOF
if [[ ! -f config/validator-identity.json ]]; then
solana-keygen new -o config/validator-identity.json
fi
args+=(--identity config/validator-identity.json)
args+=(--identity-keypair config/validator-identity.json)
if [[ $airdropsEnabled != true ]]; then
args+=(--no-airdrop)

113
programs/bpf/Cargo.lock generated
View File

@ -375,6 +375,15 @@ dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crypto-mac"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
"subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ct-logs"
version = "0.6.0"
@ -681,6 +690,15 @@ name = "hex"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "hmac"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "http"
version = "0.1.18"
@ -1069,6 +1087,15 @@ dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pbkdf2"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "percent-encoding"
version = "1.0.1"
@ -1557,7 +1584,7 @@ version = "0.6.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "solana-bpf-loader-api"
name = "solana-bpf-loader-program"
version = "0.21.0"
dependencies = [
"bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1570,16 +1597,6 @@ dependencies = [
"solana_rbpf 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "solana-bpf-loader-program"
version = "0.21.0"
dependencies = [
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-bpf-loader-api 0.21.0",
"solana-logger 0.21.0",
"solana-sdk 0.21.0",
]
[[package]]
name = "solana-bpf-programs"
version = "0.21.0"
@ -1587,7 +1604,7 @@ dependencies = [
"bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"elf 0.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-bpf-loader-api 0.21.0",
"solana-bpf-loader-program 0.21.0",
"solana-logger 0.21.0",
"solana-runtime 0.21.0",
"solana-sdk 0.21.0",
@ -1704,13 +1721,14 @@ dependencies = [
]
[[package]]
name = "solana-config-api"
name = "solana-config-program"
version = "0.21.0"
dependencies = [
"bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-logger 0.21.0",
"solana-sdk 0.21.0",
]
@ -1793,17 +1811,14 @@ dependencies = [
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-bpf-loader-api 0.21.0",
"solana-bpf-loader-program 0.21.0",
"solana-logger 0.21.0",
"solana-measure 0.21.0",
"solana-metrics 0.21.0",
"solana-rayon-threadlimit 0.21.0",
"solana-sdk 0.21.0",
"solana-stake-api 0.21.0",
"solana-stake-program 0.21.0",
"solana-storage-api 0.21.0",
"solana-vote-api 0.21.0",
"solana-storage-program 0.21.0",
"solana-vote-program 0.21.0",
"sys-info 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1820,11 +1835,14 @@ dependencies = [
"ed25519-dalek 1.0.0-pre.2 (registry+https://github.com/rust-lang/crates.io-index)",
"generic-array 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1840,36 +1858,26 @@ dependencies = [
name = "solana-sdk-bpf-test"
version = "0.21.0"
[[package]]
name = "solana-stake-api"
version = "0.21.0"
dependencies = [
"bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-config-api 0.21.0",
"solana-logger 0.21.0",
"solana-metrics 0.21.0",
"solana-sdk 0.21.0",
"solana-vote-api 0.21.0",
]
[[package]]
name = "solana-stake-program"
version = "0.21.0"
dependencies = [
"bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-config-program 0.21.0",
"solana-logger 0.21.0",
"solana-metrics 0.21.0",
"solana-sdk 0.21.0",
"solana-stake-api 0.21.0",
"solana-vote-program 0.21.0",
]
[[package]]
name = "solana-storage-api"
name = "solana-storage-program"
version = "0.21.0"
dependencies = [
"bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1883,29 +1891,19 @@ dependencies = [
"solana-sdk 0.21.0",
]
[[package]]
name = "solana-vote-api"
version = "0.21.0"
dependencies = [
"bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-logger 0.21.0",
"solana-metrics 0.21.0",
"solana-sdk 0.21.0",
]
[[package]]
name = "solana-vote-program"
version = "0.21.0"
dependencies = [
"bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-logger 0.21.0",
"solana-metrics 0.21.0",
"solana-sdk 0.21.0",
"solana-vote-api 0.21.0",
]
[[package]]
@ -1951,6 +1949,11 @@ name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "subtle"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "subtle"
version = "2.1.1"
@ -2611,6 +2614,7 @@ dependencies = [
"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9"
"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b"
"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
"checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
"checksum ct-logs 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4d3686f5fa27dbc1d76c751300376e167c5a43387f44bb451fd1c24776e49113"
"checksum curve25519-dalek 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8b7dcd30ba50cdf88b55b033456138b7c0ac4afdc436d82e1b79f370f24cc66d"
"checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"
@ -2646,6 +2650,7 @@ dependencies = [
"checksum hash32 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "12d790435639c06a7b798af9e1e331ae245b7ef915b92f70a39b4cf8c00686af"
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
"checksum hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "023b39be39e3a2da62a94feb433e91e8bcd37676fbc8bea371daf52b7a769a3e"
"checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695"
"checksum http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "372bcb56f939e449117fb0869c2e8fd8753a8223d92a172c6e808cf123a5b6e4"
"checksum http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d"
"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9"
@ -2689,6 +2694,7 @@ dependencies = [
"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9"
"checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9"
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b"
@ -2750,6 +2756,7 @@ dependencies = [
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
"checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
"checksum subtle 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "01f40907d9ffc762709e4ff3eb4a6f6b41b650375a3f09ac92b641942b7fb082"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"

2
run.sh
View File

@ -99,7 +99,7 @@ solana-drone --keypair "$dataDir"/faucet-keypair.json &
drone=$!
args=(
--identity "$dataDir"/leader-keypair.json
--identity-keypair "$dataDir"/leader-keypair.json
--storage-keypair "$dataDir"/leader-storage-account-keypair.json
--voting-keypair "$dataDir"/leader-vote-account-keypair.json
--ledger "$ledgerDir"

View File

@ -31,12 +31,14 @@ bs58 = "0.3.0"
byteorder = { version = "1.3.2", optional = true }
generic-array = { version = "0.13.2", default-features = false, features = ["serde", "more_lengths"] }
hex = "0.4.0"
hmac = "0.7.0"
itertools = { version = "0.8.1" }
lazy_static = "1.4.0"
log = { version = "0.4.8" }
memmap = { version = "0.6.2", optional = true }
num-derive = { version = "0.3" }
num-traits = { version = "0.2" }
pbkdf2 = { version = "0.3.0", default-features = false }
rand = { version = "0.6.5", optional = true }
rand_chacha = { version = "0.1.1", optional = true }
serde = "1.0.102"
@ -47,3 +49,6 @@ sha2 = "0.8.0"
ed25519-dalek = { version = "1.0.0-pre.1", optional = true }
solana-logger = { path = "../logger", version = "0.21.0", optional = true }
solana-crate-features = { path = "../crate-features", version = "0.21.0", optional = true }
[dev-dependencies]
tiny-bip39 = "0.6.2"

View File

@ -4,6 +4,7 @@ use crate::pubkey::Pubkey;
use bs58;
use ed25519_dalek;
use generic_array::{typenum::U64, GenericArray};
use hmac::Hmac;
use rand::rngs::OsRng;
use serde_json;
use std::{
@ -186,9 +187,29 @@ pub fn keypair_from_seed(seed: &[u8]) -> Result<Keypair, Box<dyn error::Error>>
Ok(keypair)
}
pub fn keypair_from_seed_phrase_and_passphrase(
seed_phrase: &str,
passphrase: &str,
) -> Result<Keypair, Box<dyn error::Error>> {
const PBKDF2_ROUNDS: usize = 2048;
const PBKDF2_BYTES: usize = 64;
let salt = format!("mnemonic{}", passphrase);
let mut seed = vec![0u8; PBKDF2_BYTES];
pbkdf2::pbkdf2::<Hmac<sha2::Sha512>>(
seed_phrase.as_bytes(),
salt.as_bytes(),
PBKDF2_ROUNDS,
&mut seed,
);
keypair_from_seed(&seed[..])
}
#[cfg(test)]
mod tests {
use super::*;
use bip39::{Language, Mnemonic, MnemonicType, Seed};
use std::mem;
fn tmp_file_path(name: &str) -> String {
@ -300,4 +321,15 @@ mod tests {
Err(ParseSignatureError::Invalid)
);
}
#[test]
fn test_keypair_from_seed_phrase_and_passphrase() {
let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English);
let passphrase = "42";
let seed = Seed::new(&mnemonic, passphrase);
let expected_keypair = keypair_from_seed(seed.as_bytes()).unwrap();
let keypair =
keypair_from_seed_phrase_and_passphrase(mnemonic.phrase(), passphrase).unwrap();
assert_eq!(keypair.pubkey(), expected_keypair.pubkey());
}
}

View File

@ -30,8 +30,8 @@ solana-runtime = { path = "../runtime", version = "0.21.0" }
solana-sdk = { path = "../sdk", version = "0.21.0" }
solana-vote-program = { path = "../programs/vote", version = "0.21.0" }
solana-vote-signer = { path = "../vote-signer", version = "0.21.0" }
tempfile = "3.1.0"
tar = "0.4.26"
tempfile = "3.1.0"
[target."cfg(unix)".dependencies]
gag = "0.1.10"

View File

@ -6,6 +6,9 @@ use log::*;
use solana_clap_utils::{
input_parsers::pubkey_of,
input_validators::{is_keypair, is_pubkey_or_keypair},
keypair::{
keypair_input, KeypairWithGenerated, ASK_SEED_PHRASE_ARG, SKIP_SEED_PHRASE_VALIDATION_ARG,
},
};
use solana_client::rpc_client::RpcClient;
use solana_core::{
@ -21,7 +24,7 @@ use solana_sdk::{
clock::Slot,
hash::Hash,
pubkey::Pubkey,
signature::{read_keypair_file, Keypair, KeypairUtil},
signature::{Keypair, KeypairUtil},
};
use std::{
fs::{self, File},
@ -323,9 +326,24 @@ pub fn main() {
.help("Stream entries to this unix domain socket path")
)
.arg(
Arg::with_name("identity")
Arg::with_name(ASK_SEED_PHRASE_ARG)
.long("ask-seed-phrase")
.value_name("KEYPAIR NAME")
.multiple(true)
.takes_value(true)
.possible_values(&["identity-keypair", "storage-keypair", "voting-keypair"])
.help("Securely recover a keypair using a seed phrase and optional passphrase"),
)
.arg(
Arg::with_name(SKIP_SEED_PHRASE_VALIDATION_ARG)
.long("skip-seed-phrase-validation")
.requires(ASK_SEED_PHRASE_ARG)
.help("Skip validation of seed phrases. Use this if your phrase does not use the BIP39 official English word list"),
)
.arg(
Arg::with_name("identity_keypair")
.short("i")
.long("identity")
.long("identity-keypair")
.value_name("PATH")
.takes_value(true)
.validator(is_keypair)
@ -520,34 +538,27 @@ pub fn main() {
)
.get_matches();
let identity_keypair = if let Some(identity) = matches.value_of("identity") {
read_keypair_file(identity).unwrap_or_else(|err| {
error!("{}: Unable to open keypair file: {}", err, identity);
let identity_keypair = Arc::new(
keypair_input(&matches, "identity-keypair")
.unwrap_or_else(|err| {
eprintln!("Identity keypair input failed: {}", err);
exit(1);
})
.keypair,
);
let KeypairWithGenerated {
keypair: voting_keypair,
generated: ephemeral_voting_keypair,
} = keypair_input(&matches, "voting-keypair").unwrap_or_else(|err| {
eprintln!("Voting keypair input failed: {}", err);
exit(1);
});
let storage_keypair = keypair_input(&matches, "storage-keypair")
.unwrap_or_else(|err| {
eprintln!("Storage keypair input failed: {}", err);
exit(1);
})
} else {
Keypair::new()
};
let identity_keypair = Arc::new(identity_keypair);
let mut ephemeral_voting_keypair = false;
let voting_keypair = if let Some(identity) = matches.value_of("voting_keypair") {
read_keypair_file(identity).unwrap_or_else(|err| {
error!("{}: Unable to open keypair file: {}", err, identity);
exit(1);
})
} else {
ephemeral_voting_keypair = true;
Keypair::new()
};
let storage_keypair = if let Some(storage_keypair) = matches.value_of("storage_keypair") {
read_keypair_file(storage_keypair).unwrap_or_else(|err| {
error!("{}: Unable to open keypair file: {}", err, storage_keypair);
exit(1);
})
} else {
Keypair::new()
};
.keypair;
let ledger_path = PathBuf::from(matches.value_of("ledger_path").unwrap());
let entrypoint = matches.value_of("entrypoint");
@ -582,7 +593,7 @@ pub fn main() {
let snapshot_interval_slots = value_t_or_exit!(matches, "snapshot_interval_slots", usize);
let snapshot_path = ledger_path.clone().join("snapshot");
fs::create_dir_all(&snapshot_path).unwrap_or_else(|err| {
error!(
eprintln!(
"Failed to create snapshots directory {:?}: {}",
snapshot_path, err
);