From b5006b8f2b13274914417d639b2c7552be3010c4 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Thu, 12 Jul 2018 15:42:01 -0600 Subject: [PATCH] Migrate to solana-keygen Most of #593 --- Cargo.toml | 4 ---- multinode-demo/client.sh | 2 +- multinode-demo/common.sh | 2 +- multinode-demo/setup.sh | 4 ++-- multinode-demo/wallet.sh | 2 +- snap/snapcraft.yaml | 4 ++-- src/bin/client-demo.rs | 28 ++++++++++++++++++---------- src/bin/genesis.rs | 22 +++++++++++++++++++++- src/mint.rs | 15 ++++++++++----- src/signature.rs | 26 +++++++++++++++++--------- 10 files changed, 73 insertions(+), 36 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d95aa0807..4c1c554f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,10 +37,6 @@ path = "src/bin/fullnode-config.rs" name = "solana-genesis" path = "src/bin/genesis.rs" -[[bin]] -name = "solana-mint" -path = "src/bin/mint.rs" - [[bin]] name = "solana-drone" path = "src/bin/drone.rs" diff --git a/multinode-demo/client.sh b/multinode-demo/client.sh index 047aa7633..ecd5b0c16 100755 --- a/multinode-demo/client.sh +++ b/multinode-demo/client.sh @@ -23,7 +23,7 @@ fi client_json="$SOLANA_CONFIG_CLIENT_DIR"/client.json if [[ ! -r $client_json ]]; then - $solana_mint <<<0 > "$client_json" + $solana_keygen > "$client_json" fi # shellcheck disable=SC2086 # $solana_client_demo should not be quoted diff --git a/multinode-demo/common.sh b/multinode-demo/common.sh index 5b764349d..c5e866594 100644 --- a/multinode-demo/common.sh +++ b/multinode-demo/common.sh @@ -53,7 +53,7 @@ solana_fullnode=$(solana_program fullnode) solana_fullnode_config=$(solana_program fullnode-config) solana_fullnode_cuda=$(solana_program fullnode-cuda) solana_genesis=$(solana_program genesis) -solana_mint=$(solana_program mint) +solana_keygen=$(solana_program keygen) export RUST_LOG=${RUST_LOG:-solana=info} # if RUST_LOG is unset, default to info export RUST_BACKTRACE=1 diff --git a/multinode-demo/setup.sh b/multinode-demo/setup.sh index 7c0e26899..52bea2068 100755 --- a/multinode-demo/setup.sh +++ b/multinode-demo/setup.sh @@ -84,10 +84,10 @@ if $node_type_leader; then mkdir -p "$SOLANA_CONFIG_PRIVATE_DIR" echo "Creating $SOLANA_CONFIG_DIR/mint.json with $num_tokens tokens" - $solana_mint <<<"$num_tokens" > "$SOLANA_CONFIG_PRIVATE_DIR"/mint.json + $solana_keygen > "$SOLANA_CONFIG_PRIVATE_DIR"/mint.json echo "Creating $SOLANA_CONFIG_DIR/genesis.log" - $solana_genesis < "$SOLANA_CONFIG_PRIVATE_DIR"/mint.json > "$SOLANA_CONFIG_DIR"/genesis.log + $solana_genesis --tokens="$num_tokens" < "$SOLANA_CONFIG_PRIVATE_DIR"/mint.json > "$SOLANA_CONFIG_DIR"/genesis.log echo "Creating $SOLANA_CONFIG_DIR/leader.json" $solana_fullnode_config "${leader_address_args[@]}" > "$SOLANA_CONFIG_DIR"/leader.json diff --git a/multinode-demo/wallet.sh b/multinode-demo/wallet.sh index a9299f4a5..df52ddbb3 100755 --- a/multinode-demo/wallet.sh +++ b/multinode-demo/wallet.sh @@ -38,7 +38,7 @@ fi client_json="$SOLANA_CONFIG_CLIENT_DIR"/client.json if [[ ! -r $client_json ]]; then - $solana_mint <<<0 > "$client_json" + $solana_keygen > "$client_json" fi set -x diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 4db1c6ab2..30959c1a0 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -39,8 +39,8 @@ apps: - network-bind genesis: command: solana-genesis - mint: - command: solana-mint + keygen: + command: solana-keygen client-demo: command: solana-client-demo wallet: diff --git a/src/bin/client-demo.rs b/src/bin/client-demo.rs index 2a7c88922..5e7ad3e30 100644 --- a/src/bin/client-demo.rs +++ b/src/bin/client-demo.rs @@ -16,7 +16,7 @@ use solana::mint::Mint; use solana::nat::{udp_public_bind, udp_random_bind}; use solana::ncp::Ncp; use solana::service::Service; -use solana::signature::{GenKeys, KeyPair, KeyPairUtil}; +use solana::signature::{read_keypair, GenKeys, KeyPair, KeyPairUtil}; use solana::streamer::default_window; use solana::thin_client::ThinClient; use solana::timing::{duration_as_ms, duration_as_s}; @@ -77,7 +77,7 @@ fn sample_tx_count( fn generate_and_send_txs( client: &mut ThinClient, tx_clients: &[ThinClient], - id: &Mint, + id: &KeyPair, keypairs: &[KeyPair], leader: &NodeInfo, txs: i64, @@ -91,7 +91,7 @@ fn generate_and_send_txs( let transactions: Vec<_> = if !reclaim { keypairs .par_iter() - .map(|keypair| Transaction::new(&id.keypair(), keypair.pubkey(), 1, *last_id)) + .map(|keypair| Transaction::new(&id, keypair.pubkey(), 1, *last_id)) .collect() } else { keypairs @@ -171,6 +171,14 @@ fn main() { .takes_value(true) .help("/path/to/mint.json"), ) + .arg( + Arg::with_name("keypair") + .short("k") + .long("keypair") + .value_name("PATH") + .takes_value(true) + .help("/path/to/id.json"), + ) .arg( Arg::with_name("num_nodes") .short("n") @@ -205,12 +213,12 @@ fn main() { leader = NodeInfo::new_leader(&server_addr); }; - let id: Mint; - if let Some(m) = matches.value_of("mint") { - id = read_mint(m).expect("client mint"); + let id = if let Some(m) = matches.value_of("keypair") { + read_keypair(m).expect("client keypair") + } else if let Some(m) = matches.value_of("mint") { + read_mint(m).expect("client mint").keypair() } else { - eprintln!("No mint found!"); - exit(1); + read_keypair("~/.config/solana/id.json").expect("default keypair") }; if let Some(t) = matches.value_of("threads") { @@ -259,7 +267,7 @@ fn main() { println!("Got last ID {:?}", last_id); let mut seed = [0u8; 32]; - seed.copy_from_slice(&id.keypair().public_key_bytes()[..32]); + seed.copy_from_slice(&id.public_key_bytes()[..32]); let rnd = GenKeys::new(seed); println!("Creating keypairs..."); @@ -441,7 +449,7 @@ fn read_mint(path: &str) -> Result> { fn request_airdrop( drone_addr: &SocketAddr, - id: &Mint, + id: &KeyPair, tokens: u64, ) -> Result<(), Box> { let mut stream = TcpStream::connect(drone_addr)?; diff --git a/src/bin/genesis.rs b/src/bin/genesis.rs index bdbee0d04..506b3e8e6 100644 --- a/src/bin/genesis.rs +++ b/src/bin/genesis.rs @@ -1,10 +1,13 @@ //! A command-line executable for generating the chain's genesis block. extern crate atty; +#[macro_use] +extern crate clap; extern crate serde_json; extern crate solana; use atty::{is, Stream}; +use clap::{App, Arg}; use solana::entry_writer::EntryWriter; use solana::mint::Mint; use std::error; @@ -12,6 +15,21 @@ use std::io::{stdin, stdout, Read}; use std::process::exit; fn main() -> Result<(), Box> { + let matches = App::new("solana-genesis") + .arg( + Arg::with_name("tokens") + .short("t") + .long("tokens") + .value_name("NUMBER") + .takes_value(true) + .required(true) + .default_value("0") + .help("Number of tokens with which to initialize mint"), + ) + .get_matches(); + + let tokens = value_t_or_exit!(matches, "tokens", i64); + if is(Stream::Stdin) { eprintln!("nothing found on stdin, expected a json file"); exit(1); @@ -24,7 +42,9 @@ fn main() -> Result<(), Box> { exit(1); } - let mint: Mint = serde_json::from_str(&buffer)?; + let pkcs8: Vec = serde_json::from_str(&buffer)?; + let mint = Mint::new_with_pkcs8(tokens, pkcs8); + let mut writer = stdout(); EntryWriter::write_entries(&mut writer, mint.create_entries())?; Ok(()) diff --git a/src/mint.rs b/src/mint.rs index 6931e7df0..4937b6955 100644 --- a/src/mint.rs +++ b/src/mint.rs @@ -15,11 +15,7 @@ pub struct Mint { } impl Mint { - pub fn new(tokens: i64) -> Self { - let rnd = SystemRandom::new(); - let pkcs8 = KeyPair::generate_pkcs8(&rnd) - .expect("generate_pkcs8 in mint pub fn new") - .to_vec(); + pub fn new_with_pkcs8(tokens: i64, pkcs8: Vec) -> Self { let keypair = KeyPair::from_pkcs8(Input::from(&pkcs8)).expect("from_pkcs8 in mint pub fn new"); let pubkey = keypair.pubkey(); @@ -29,6 +25,15 @@ impl Mint { tokens, } } + + pub fn new(tokens: i64) -> Self { + let rnd = SystemRandom::new(); + let pkcs8 = KeyPair::generate_pkcs8(&rnd) + .expect("generate_pkcs8 in mint pub fn new") + .to_vec(); + Self::new_with_pkcs8(tokens, pkcs8) + } + pub fn seed(&self) -> Hash { hash(&self.pkcs8) } diff --git a/src/signature.rs b/src/signature.rs index b4b558276..9dea5d42c 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -8,8 +8,11 @@ use ring::error::Unspecified; use ring::rand::SecureRandom; use ring::signature::Ed25519KeyPair; use ring::{rand, signature}; +use serde_json; use std::cell::RefCell; -use untrusted; +use std::error; +use std::fs::File; +use untrusted::Input; pub type KeyPair = Ed25519KeyPair; pub type PublicKey = GenericArray; @@ -24,10 +27,8 @@ impl KeyPairUtil for Ed25519KeyPair { /// Return a new ED25519 keypair fn new() -> Self { let rng = rand::SystemRandom::new(); - let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(&rng) - .expect("generate_pkcs8 in signature pb fn new"); - signature::Ed25519KeyPair::from_pkcs8(untrusted::Input::from(&pkcs8_bytes)) - .expect("from_pcks8 in signature pb fn new") + let pkcs8_bytes = Ed25519KeyPair::generate_pkcs8(&rng).expect("generate_pkcs8"); + Ed25519KeyPair::from_pkcs8(Input::from(&pkcs8_bytes)).expect("from_pcks8") } /// Return the public key for the given keypair @@ -42,9 +43,9 @@ pub trait SignatureUtil { impl SignatureUtil for GenericArray { fn verify(&self, peer_public_key_bytes: &[u8], msg_bytes: &[u8]) -> bool { - let peer_public_key = untrusted::Input::from(peer_public_key_bytes); - let msg = untrusted::Input::from(msg_bytes); - let sig = untrusted::Input::from(self); + let peer_public_key = Input::from(peer_public_key_bytes); + let msg = Input::from(msg_bytes); + let sig = Input::from(self); signature::verify(&signature::ED25519, peer_public_key, msg, sig).is_ok() } } @@ -77,7 +78,7 @@ impl GenKeys { .into_par_iter() .map(|seed| { let pkcs8 = GenKeys::new(seed).new_key(); - KeyPair::from_pkcs8(untrusted::Input::from(&pkcs8)).unwrap() + KeyPair::from_pkcs8(Input::from(&pkcs8)).unwrap() }) .collect() } @@ -91,6 +92,13 @@ impl SecureRandom for GenKeys { } } +pub fn read_keypair(path: &str) -> Result> { + let file = File::open(path.to_string())?; + let pkcs8: Vec = serde_json::from_reader(file)?; + let keypair = Ed25519KeyPair::from_pkcs8(Input::from(&pkcs8))?; + Ok(keypair) +} + #[cfg(test)] mod tests { use super::*;