From 96cb91b3b368cc14c8d3a0990fe310cfe0f3f7f4 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Thu, 12 Jul 2018 15:42:01 -0600 Subject: [PATCH 01/11] 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 d95aa080786a6d..4c1c554f8191b9 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 047aa7633311a2..ecd5b0c164e57e 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 5b764349d83b41..c5e86659410294 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 7c0e268994ff9f..52bea2068c9afc 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 a9299f4a521d87..df52ddbb3894ea 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 4db1c6ab22a196..30959c1a0c93cb 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 2a7c88922e18a2..5e7ad3e309435c 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 bdbee0d04f4283..506b3e8e66415a 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 6931e7df069b3a..4937b69555d2e7 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 b4b558276e2afa..9dea5d42cce93b 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::*; From ddb0ce926a9c00f0f9a6d2701bed75d80a760b8d Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Thu, 12 Jul 2018 16:02:14 -0600 Subject: [PATCH 02/11] More keygen --- src/bin/client-demo.rs | 24 ++---------------------- src/bin/drone.rs | 29 ++++++++--------------------- src/bin/mint.rs | 29 ----------------------------- src/bin/wallet.rs | 39 +++++++++++++-------------------------- 4 files changed, 23 insertions(+), 98 deletions(-) delete mode 100644 src/bin/mint.rs diff --git a/src/bin/client-demo.rs b/src/bin/client-demo.rs index 5e7ad3e309435c..62e1f4d8a2a15d 100644 --- a/src/bin/client-demo.rs +++ b/src/bin/client-demo.rs @@ -12,7 +12,6 @@ use solana::crdt::{Crdt, NodeInfo}; use solana::drone::DroneRequest; use solana::fullnode::Config; use solana::hash::Hash; -use solana::mint::Mint; use solana::nat::{udp_public_bind, udp_random_bind}; use solana::ncp::Ncp; use solana::service::Service; @@ -163,20 +162,13 @@ fn main() { .takes_value(true) .help("/path/to/leader.json"), ) - .arg( - Arg::with_name("mint") - .short("m") - .long("mint") - .value_name("PATH") - .takes_value(true) - .help("/path/to/mint.json"), - ) .arg( Arg::with_name("keypair") .short("k") .long("keypair") .value_name("PATH") .takes_value(true) + .default_value("~/.config/solana/id.json") .help("/path/to/id.json"), ) .arg( @@ -213,13 +205,7 @@ fn main() { leader = NodeInfo::new_leader(&server_addr); }; - 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 { - read_keypair("~/.config/solana/id.json").expect("default keypair") - }; + let id = read_keypair(matches.value_of("keypair").unwrap()).expect("client keypair"); if let Some(t) = matches.value_of("threads") { threads = t.to_string().parse().expect("integer"); @@ -441,12 +427,6 @@ fn read_leader(path: &str) -> Config { serde_json::from_reader(file).unwrap_or_else(|_| panic!("failed to parse {}", path)) } -fn read_mint(path: &str) -> Result> { - let file = File::open(path.to_string())?; - let mint = serde_json::from_reader(file)?; - Ok(mint) -} - fn request_airdrop( drone_addr: &SocketAddr, id: &KeyPair, diff --git a/src/bin/drone.rs b/src/bin/drone.rs index f19f7a802a10e2..a09605d03187df 100644 --- a/src/bin/drone.rs +++ b/src/bin/drone.rs @@ -12,11 +12,9 @@ use clap::{App, Arg}; use solana::crdt::NodeInfo; use solana::drone::{Drone, DroneRequest}; use solana::fullnode::Config; -use solana::mint::Mint; -use std::error; +use solana::signature::read_keypair; use std::fs::File; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; -use std::process::exit; use std::sync::{Arc, Mutex}; use std::thread; use tokio::net::TcpListener; @@ -35,11 +33,12 @@ fn main() { .help("/path/to/leader.json"), ) .arg( - Arg::with_name("mint") - .short("m") - .long("mint") + Arg::with_name("keypair") + .short("k") + .long("keypair") .value_name("PATH") .takes_value(true) + .required(true) .help("/path/to/mint.json"), ) .arg( @@ -68,13 +67,9 @@ fn main() { leader = NodeInfo::new_leader(&server_addr); }; - let mint: Mint; - if let Some(m) = matches.value_of("mint") { - mint = read_mint(m).expect("client mint"); - } else { - eprintln!("No mint found!"); - exit(1); - }; + let mint_keypair = + read_keypair(matches.value_of("keypair").expect("keypair")).expect("client keypair"); + let time_slice: Option; if let Some(t) = matches.value_of("time") { time_slice = Some(t.to_string().parse().expect("integer")); @@ -88,8 +83,6 @@ fn main() { request_cap = None; } - let mint_keypair = mint.keypair(); - let drone_addr: SocketAddr = "0.0.0.0:9900".parse().unwrap(); let drone = Arc::new(Mutex::new(Drone::new( @@ -152,9 +145,3 @@ fn read_leader(path: &str) -> Config { let file = File::open(path).unwrap_or_else(|_| panic!("file not found: {}", path)); serde_json::from_reader(file).unwrap_or_else(|_| panic!("failed to parse {}", path)) } - -fn read_mint(path: &str) -> Result> { - let file = File::open(path.to_string())?; - let mint = serde_json::from_reader(file)?; - Ok(mint) -} diff --git a/src/bin/mint.rs b/src/bin/mint.rs deleted file mode 100644 index e62ce1c73b90dc..00000000000000 --- a/src/bin/mint.rs +++ /dev/null @@ -1,29 +0,0 @@ -extern crate atty; -extern crate serde_json; -extern crate solana; - -use atty::{is, Stream}; -use solana::mint::Mint; -use std::io; -use std::process::exit; - -fn main() { - let mut input_text = String::new(); - if is(Stream::Stdin) { - eprintln!("nothing found on stdin, expected a token number"); - exit(1); - } - - io::stdin().read_line(&mut input_text).unwrap(); - let trimmed = input_text.trim(); - let tokens = trimmed.parse::().unwrap_or_else(|e| { - eprintln!("{}", e); - exit(1); - }); - let mint = Mint::new(tokens); - let serialized = serde_json::to_string(&mint).unwrap_or_else(|e| { - eprintln!("failed to serialize: {}", e); - exit(1); - }); - println!("{}", serialized); -} diff --git a/src/bin/wallet.rs b/src/bin/wallet.rs index 9864696421d73e..d5d6636e681f04 100644 --- a/src/bin/wallet.rs +++ b/src/bin/wallet.rs @@ -11,8 +11,7 @@ use clap::{App, Arg, SubCommand}; use solana::crdt::NodeInfo; use solana::drone::DroneRequest; use solana::fullnode::Config; -use solana::mint::Mint; -use solana::signature::{PublicKey, Signature}; +use solana::signature::{read_keypair, KeyPair, KeyPairUtil, PublicKey, Signature}; use solana::thin_client::ThinClient; use std::error; use std::fmt; @@ -20,7 +19,6 @@ use std::fs::File; use std::io; use std::io::prelude::*; use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream, UdpSocket}; -use std::process::exit; use std::thread::sleep; use std::time::Duration; @@ -57,7 +55,7 @@ impl error::Error for WalletError { struct WalletConfig { leader: NodeInfo, - id: Mint, + id: KeyPair, drone_addr: SocketAddr, command: WalletCommand, } @@ -67,7 +65,7 @@ impl Default for WalletConfig { let default_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8000); WalletConfig { leader: NodeInfo::new_leader(&default_addr), - id: Mint::new(0), + id: KeyPair::new(), drone_addr: default_addr, command: WalletCommand::Balance, } @@ -85,12 +83,13 @@ fn parse_args() -> Result> { .help("/path/to/leader.json"), ) .arg( - Arg::with_name("mint") - .short("m") - .long("mint") + Arg::with_name("keypair") + .short("k") + .long("keypair") .value_name("PATH") .takes_value(true) - .help("/path/to/mint.json"), + .default_value("~/.config/solana/id.json") + .help("/path/to/id.json"), ) .subcommand( SubCommand::with_name("airdrop") @@ -149,13 +148,7 @@ fn parse_args() -> Result> { leader = NodeInfo::new_leader(&server_addr); }; - let id: Mint; - if let Some(m) = matches.value_of("mint") { - id = read_mint(m)?; - } else { - eprintln!("No mint found!"); - exit(1); - }; + let id = read_keypair(matches.value_of("keypair").unwrap()).expect("client keypair"); let mut drone_addr = leader.contact_info.tpu; drone_addr.set_port(9900); @@ -165,7 +158,7 @@ fn parse_args() -> Result> { let tokens = if airdrop_matches.is_present("tokens") { airdrop_matches.value_of("tokens").unwrap().parse()? } else { - id.tokens + 100 }; Ok(WalletCommand::AirDrop(tokens)) } @@ -187,7 +180,7 @@ fn parse_args() -> Result> { let tokens = if pay_matches.is_present("tokens") { pay_matches.value_of("tokens").unwrap().parse()? } else { - id.tokens + 10 }; Ok(WalletCommand::Pay(tokens, to)) @@ -264,7 +257,7 @@ fn process_command( // If client has positive balance, spend tokens in {balance} number of transactions WalletCommand::Pay(tokens, to) => { let last_id = client.get_last_id(); - let sig = client.transfer(tokens, &config.id.keypair(), to, &last_id)?; + let sig = client.transfer(tokens, &config.id, to, &last_id)?; println!("{}", bs58::encode(sig).into_string()); } // Confirm the last client transaction by signature @@ -295,12 +288,6 @@ fn read_leader(path: &str) -> Config { serde_json::from_reader(file).unwrap_or_else(|_| panic!("failed to parse {}", path)) } -fn read_mint(path: &str) -> Result> { - let file = File::open(path.to_string())?; - let mint = serde_json::from_reader(file)?; - Ok(mint) -} - fn mk_client(r: &NodeInfo) -> io::Result { let requests_socket = UdpSocket::bind("0.0.0.0:0").unwrap(); let transactions_socket = UdpSocket::bind("0.0.0.0:0").unwrap(); @@ -318,7 +305,7 @@ fn mk_client(r: &NodeInfo) -> io::Result { fn request_airdrop( drone_addr: &SocketAddr, - id: &Mint, + id: &KeyPair, tokens: u64, ) -> Result<(), Box> { let mut stream = TcpStream::connect(drone_addr)?; From 814457b35d177dc3ff963bf90f0cf795cc425b33 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Thu, 12 Jul 2018 16:29:49 -0600 Subject: [PATCH 03/11] Add --outfile option to solana-keygen --- multinode-demo/client.sh | 2 +- multinode-demo/setup.sh | 2 +- multinode-demo/wallet.sh | 2 +- src/bin/genesis.rs | 1 - src/bin/keygen.rs | 31 ++++++++++++++++++++++++++++++- 5 files changed, 33 insertions(+), 5 deletions(-) diff --git a/multinode-demo/client.sh b/multinode-demo/client.sh index ecd5b0c164e57e..6d09fd4b74618e 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_keygen > "$client_json" + $solana_keygen -o "$client_json" fi # shellcheck disable=SC2086 # $solana_client_demo should not be quoted diff --git a/multinode-demo/setup.sh b/multinode-demo/setup.sh index 52bea2068c9afc..ba5b06855f27ef 100755 --- a/multinode-demo/setup.sh +++ b/multinode-demo/setup.sh @@ -84,7 +84,7 @@ if $node_type_leader; then mkdir -p "$SOLANA_CONFIG_PRIVATE_DIR" echo "Creating $SOLANA_CONFIG_DIR/mint.json with $num_tokens tokens" - $solana_keygen > "$SOLANA_CONFIG_PRIVATE_DIR"/mint.json + $solana_keygen -o "$SOLANA_CONFIG_PRIVATE_DIR"/mint.json echo "Creating $SOLANA_CONFIG_DIR/genesis.log" $solana_genesis --tokens="$num_tokens" < "$SOLANA_CONFIG_PRIVATE_DIR"/mint.json > "$SOLANA_CONFIG_DIR"/genesis.log diff --git a/multinode-demo/wallet.sh b/multinode-demo/wallet.sh index df52ddbb3894ea..658c79df14c941 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_keygen > "$client_json" + $solana_keygen -o "$client_json" fi set -x diff --git a/src/bin/genesis.rs b/src/bin/genesis.rs index 506b3e8e66415a..8db6fe81a26647 100644 --- a/src/bin/genesis.rs +++ b/src/bin/genesis.rs @@ -23,7 +23,6 @@ fn main() -> Result<(), Box> { .value_name("NUMBER") .takes_value(true) .required(true) - .default_value("0") .help("Number of tokens with which to initialize mint"), ) .get_matches(); diff --git a/src/bin/keygen.rs b/src/bin/keygen.rs index dba63fb26e76c6..8b172428ddcd87 100644 --- a/src/bin/keygen.rs +++ b/src/bin/keygen.rs @@ -1,14 +1,43 @@ +extern crate clap; extern crate ring; extern crate serde_json; +use clap::{App, Arg}; use ring::rand::SystemRandom; use ring::signature::Ed25519KeyPair; use std::error; +use std::fs::{self, File}; +use std::io::Write; +use std::path::Path; fn main() -> Result<(), Box> { + let matches = App::new("solana-genesis") + .arg( + Arg::with_name("outfile") + .short("o") + .long("outfile") + .value_name("PATH") + .takes_value(true) + .default_value("~/.config/solana/id.json") + .help("Number of tokens with which to initialize mint"), + ) + .get_matches(); + let rnd = SystemRandom::new(); let pkcs8_bytes = Ed25519KeyPair::generate_pkcs8(&rnd)?; let serialized = serde_json::to_string(&pkcs8_bytes.to_vec())?; - println!("{}", serialized); + + let outfile = matches.value_of("outfile").unwrap(); + + if outfile == "-" { + println!("{}", serialized); + } else { + if let Some(outdir) = Path::new(outfile).parent() { + fs::create_dir_all(outdir)?; + } + let mut f = File::create(outfile)?; + f.write_all(&serialized.into_bytes())?; + } + Ok(()) } From 080819b6705174b0512281c2146c642b7a4c4d87 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Thu, 12 Jul 2018 16:32:53 -0600 Subject: [PATCH 04/11] In Wallet, make --tokens required and --to optional --- src/bin/wallet.rs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/bin/wallet.rs b/src/bin/wallet.rs index d5d6636e681f04..fc167848a714fc 100644 --- a/src/bin/wallet.rs +++ b/src/bin/wallet.rs @@ -100,6 +100,7 @@ fn parse_args() -> Result> { .long("tokens") .value_name("NUMBER") .takes_value(true) + .required(true) .help("The number of tokens to request"), ), ) @@ -121,7 +122,6 @@ fn parse_args() -> Result> { .long("to") .value_name("PUBKEY") .takes_value(true) - .required(true) .help("The pubkey of recipient"), ), ) @@ -155,11 +155,7 @@ fn parse_args() -> Result> { let command = match matches.subcommand() { ("airdrop", Some(airdrop_matches)) => { - let tokens = if airdrop_matches.is_present("tokens") { - airdrop_matches.value_of("tokens").unwrap().parse()? - } else { - 100 - }; + let tokens = airdrop_matches.value_of("tokens").unwrap().parse()?; Ok(WalletCommand::AirDrop(tokens)) } ("pay", Some(pay_matches)) => { @@ -177,11 +173,7 @@ fn parse_args() -> Result> { id.pubkey() }; - let tokens = if pay_matches.is_present("tokens") { - pay_matches.value_of("tokens").unwrap().parse()? - } else { - 10 - }; + let tokens = pay_matches.value_of("tokens").unwrap().parse()?; Ok(WalletCommand::Pay(tokens, to)) } From 56bf9e67d8d0932b3b59dcd64ef2f4ad195057b7 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Thu, 12 Jul 2018 17:04:42 -0600 Subject: [PATCH 05/11] Fix default keypair paths --- src/bin/keygen.rs | 10 ++++++++-- src/bin/wallet.rs | 11 +++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/bin/keygen.rs b/src/bin/keygen.rs index 8b172428ddcd87..9b65c0d8814f4c 100644 --- a/src/bin/keygen.rs +++ b/src/bin/keygen.rs @@ -5,6 +5,7 @@ extern crate serde_json; use clap::{App, Arg}; use ring::rand::SystemRandom; use ring::signature::Ed25519KeyPair; +use std::env; use std::error; use std::fs::{self, File}; use std::io::Write; @@ -18,7 +19,6 @@ fn main() -> Result<(), Box> { .long("outfile") .value_name("PATH") .takes_value(true) - .default_value("~/.config/solana/id.json") .help("Number of tokens with which to initialize mint"), ) .get_matches(); @@ -27,7 +27,13 @@ fn main() -> Result<(), Box> { let pkcs8_bytes = Ed25519KeyPair::generate_pkcs8(&rnd)?; let serialized = serde_json::to_string(&pkcs8_bytes.to_vec())?; - let outfile = matches.value_of("outfile").unwrap(); + let mut path = env::home_dir().expect("home directory"); + let outfile = if matches.is_present("outfile") { + matches.value_of("outfile").unwrap() + } else { + path.extend(&[".config", "solana", "id.json"]); + path.to_str().unwrap() + }; if outfile == "-" { println!("{}", serialized); diff --git a/src/bin/wallet.rs b/src/bin/wallet.rs index fc167848a714fc..0b320fd8a25edf 100644 --- a/src/bin/wallet.rs +++ b/src/bin/wallet.rs @@ -13,6 +13,7 @@ use solana::drone::DroneRequest; use solana::fullnode::Config; use solana::signature::{read_keypair, KeyPair, KeyPairUtil, PublicKey, Signature}; use solana::thin_client::ThinClient; +use std::env; use std::error; use std::fmt; use std::fs::File; @@ -88,7 +89,6 @@ fn parse_args() -> Result> { .long("keypair") .value_name("PATH") .takes_value(true) - .default_value("~/.config/solana/id.json") .help("/path/to/id.json"), ) .subcommand( @@ -148,7 +148,14 @@ fn parse_args() -> Result> { leader = NodeInfo::new_leader(&server_addr); }; - let id = read_keypair(matches.value_of("keypair").unwrap()).expect("client keypair"); + let mut path = env::home_dir().expect("home directory"); + let id_path = if matches.is_present("keypair") { + matches.value_of("keypair").unwrap() + } else { + path.extend(&[".config", "solana", "id.json"]); + path.to_str().unwrap() + }; + let id = read_keypair(id_path).expect("client keypair"); let mut drone_addr = leader.contact_info.tpu; drone_addr.set_port(9900); From 4407fa02a92ef3d91a11698460d284f6ef2fc62f Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Thu, 12 Jul 2018 17:26:56 -0600 Subject: [PATCH 06/11] Pass the owner's keypair to fullnode-config --- multinode-demo/setup.sh | 12 +++++++----- src/bin/fullnode-config.rs | 21 ++++++++++++++++++++- src/fullnode.rs | 7 +------ src/signature.rs | 7 ++++++- 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/multinode-demo/setup.sh b/multinode-demo/setup.sh index ba5b06855f27ef..9041d5175afa52 100755 --- a/multinode-demo/setup.sh +++ b/multinode-demo/setup.sh @@ -71,6 +71,7 @@ done leader_address_args=("$ip_address_arg") validator_address_args=("$ip_address_arg" -b 9000) +keypair_arg=(--keypair="$SOLANA_CONFIG_PRIVATE_DIR/id.json") set -e @@ -78,11 +79,12 @@ echo "Cleaning $SOLANA_CONFIG_DIR" rm -rvf "$SOLANA_CONFIG_DIR" mkdir -p "$SOLANA_CONFIG_DIR" +rm -rvf "$SOLANA_CONFIG_PRIVATE_DIR" +mkdir -p "$SOLANA_CONFIG_PRIVATE_DIR" -if $node_type_leader; then - rm -rvf "$SOLANA_CONFIG_PRIVATE_DIR" - mkdir -p "$SOLANA_CONFIG_PRIVATE_DIR" +$solana_keygen -o "$SOLANA_CONFIG_PRIVATE_DIR"/id.json +if $node_type_leader; then echo "Creating $SOLANA_CONFIG_DIR/mint.json with $num_tokens tokens" $solana_keygen -o "$SOLANA_CONFIG_PRIVATE_DIR"/mint.json @@ -90,13 +92,13 @@ if $node_type_leader; then $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 + $solana_fullnode_config "${keypair_arg}" "${leader_address_args[@]}" > "$SOLANA_CONFIG_DIR"/leader.json fi if $node_type_validator; then echo "Creating $SOLANA_CONFIG_DIR/validator.json" - $solana_fullnode_config "${validator_address_args[@]}" > "$SOLANA_CONFIG_DIR"/validator.json + $solana_fullnode_config "${keypair_arg}" "${validator_address_args[@]}" > "$SOLANA_CONFIG_DIR"/validator.json fi ls -lh "$SOLANA_CONFIG_DIR"/ diff --git a/src/bin/fullnode-config.rs b/src/bin/fullnode-config.rs index 7b9760294694ff..5d9bc238729a77 100644 --- a/src/bin/fullnode-config.rs +++ b/src/bin/fullnode-config.rs @@ -6,6 +6,8 @@ use clap::{App, Arg}; use solana::crdt::{get_ip_addr, parse_port_or_addr}; use solana::fullnode::Config; use solana::nat::get_public_ip_addr; +use solana::signature::read_pkcs8; +use std::env; use std::io; use std::net::SocketAddr; @@ -18,6 +20,14 @@ fn main() { .takes_value(false) .help("detect network address from local machine configuration"), ) + .arg( + Arg::with_name("keypair") + .short("k") + .long("keypair") + .value_name("PATH") + .takes_value(true) + .help("/path/to/id.json"), + ) .arg( Arg::with_name("public") .short("p") @@ -54,9 +64,18 @@ fn main() { bind_addr }; + let mut path = env::home_dir().expect("home directory"); + let id_path = if matches.is_present("keypair") { + matches.value_of("keypair").unwrap() + } else { + path.extend(&[".config", "solana", "id.json"]); + path.to_str().unwrap() + }; + let pkcs8 = read_pkcs8(id_path).expect("client keypair"); + // we need all the receiving sockets to be bound within the expected // port range that we open on aws - let config = Config::new(&bind_addr); + let config = Config::new(&bind_addr, pkcs8); let stdout = io::stdout(); serde_json::to_writer(stdout, &config).expect("serialize"); } diff --git a/src/fullnode.rs b/src/fullnode.rs index ab896202ca19b3..09fda99ded407e 100644 --- a/src/fullnode.rs +++ b/src/fullnode.rs @@ -7,7 +7,6 @@ use entry_writer; use ledger::Block; use ncp::Ncp; use packet::BlobRecycler; -use ring::rand::SystemRandom; use rpu::Rpu; use service::Service; use signature::{KeyPair, KeyPairUtil}; @@ -50,11 +49,7 @@ pub struct Config { /// Structure to be replicated by the network impl Config { - pub fn new(bind_addr: &SocketAddr) -> Self { - let rnd = SystemRandom::new(); - let pkcs8 = KeyPair::generate_pkcs8(&rnd) - .expect("generate_pkcs8 in mint pub fn new") - .to_vec(); + pub fn new(bind_addr: &SocketAddr, pkcs8: Vec) -> Self { let keypair = KeyPair::from_pkcs8(Input::from(&pkcs8)).expect("from_pkcs8 in fullnode::Config new"); let pubkey = keypair.pubkey(); diff --git a/src/signature.rs b/src/signature.rs index 9dea5d42cce93b..431f0d95402cd8 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -92,9 +92,14 @@ impl SecureRandom for GenKeys { } } -pub fn read_keypair(path: &str) -> Result> { +pub fn read_pkcs8(path: &str) -> Result, Box> { let file = File::open(path.to_string())?; let pkcs8: Vec = serde_json::from_reader(file)?; + Ok(pkcs8) +} + +pub fn read_keypair(path: &str) -> Result> { + let pkcs8 = read_pkcs8(path)?; let keypair = Ed25519KeyPair::from_pkcs8(Input::from(&pkcs8))?; Ok(keypair) } From fdae0d34525fba7ff74147ba84cc5d5672e1e12b Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Thu, 12 Jul 2018 17:29:10 -0600 Subject: [PATCH 07/11] Fix keygen docs Thanks @rob-solana --- src/bin/keygen.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/keygen.rs b/src/bin/keygen.rs index 9b65c0d8814f4c..e77614d78ab3dc 100644 --- a/src/bin/keygen.rs +++ b/src/bin/keygen.rs @@ -12,14 +12,14 @@ use std::io::Write; use std::path::Path; fn main() -> Result<(), Box> { - let matches = App::new("solana-genesis") + let matches = App::new("solana-keygen") .arg( Arg::with_name("outfile") .short("o") .long("outfile") .value_name("PATH") .takes_value(true) - .help("Number of tokens with which to initialize mint"), + .help("path to generated file"), ) .get_matches(); From 3cc10b6c1cfb978f648f4ccd661dcaabd1b1c3ba Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Thu, 12 Jul 2018 17:37:19 -0600 Subject: [PATCH 08/11] Cleanup setup.sh --- multinode-demo/setup.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/multinode-demo/setup.sh b/multinode-demo/setup.sh index 9041d5175afa52..31d380f07c818b 100755 --- a/multinode-demo/setup.sh +++ b/multinode-demo/setup.sh @@ -71,7 +71,8 @@ done leader_address_args=("$ip_address_arg") validator_address_args=("$ip_address_arg" -b 9000) -keypair_arg=(--keypair="$SOLANA_CONFIG_PRIVATE_DIR/id.json") +id_path=("$SOLANA_CONFIG_PRIVATE_DIR"/id.json) +mint_path=("$SOLANA_CONFIG_PRIVATE_DIR"/mint.json) set -e @@ -82,17 +83,17 @@ mkdir -p "$SOLANA_CONFIG_DIR" rm -rvf "$SOLANA_CONFIG_PRIVATE_DIR" mkdir -p "$SOLANA_CONFIG_PRIVATE_DIR" -$solana_keygen -o "$SOLANA_CONFIG_PRIVATE_DIR"/id.json +$solana_keygen -o "$id_path" if $node_type_leader; then echo "Creating $SOLANA_CONFIG_DIR/mint.json with $num_tokens tokens" - $solana_keygen -o "$SOLANA_CONFIG_PRIVATE_DIR"/mint.json + $solana_keygen -o "$mint_path" echo "Creating $SOLANA_CONFIG_DIR/genesis.log" - $solana_genesis --tokens="$num_tokens" < "$SOLANA_CONFIG_PRIVATE_DIR"/mint.json > "$SOLANA_CONFIG_DIR"/genesis.log + $solana_genesis --tokens="$num_tokens" < "$mint_path" > "$SOLANA_CONFIG_DIR"/genesis.log echo "Creating $SOLANA_CONFIG_DIR/leader.json" - $solana_fullnode_config "${keypair_arg}" "${leader_address_args[@]}" > "$SOLANA_CONFIG_DIR"/leader.json + $solana_fullnode_config --keypair="$id_path" "${leader_address_args[@]}" > "$SOLANA_CONFIG_DIR"/leader.json fi From 383b0d313c37b36056a2ceb76411c30dea394092 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Thu, 12 Jul 2018 17:40:38 -0600 Subject: [PATCH 09/11] Battle shellcheck --- multinode-demo/setup.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/multinode-demo/setup.sh b/multinode-demo/setup.sh index 31d380f07c818b..da50e2e27e42ac 100755 --- a/multinode-demo/setup.sh +++ b/multinode-demo/setup.sh @@ -71,8 +71,8 @@ done leader_address_args=("$ip_address_arg") validator_address_args=("$ip_address_arg" -b 9000) -id_path=("$SOLANA_CONFIG_PRIVATE_DIR"/id.json) -mint_path=("$SOLANA_CONFIG_PRIVATE_DIR"/mint.json) +id_path="$SOLANA_CONFIG_PRIVATE_DIR"/id.json +mint_path="$SOLANA_CONFIG_PRIVATE_DIR"/mint.json set -e @@ -99,7 +99,7 @@ fi if $node_type_validator; then echo "Creating $SOLANA_CONFIG_DIR/validator.json" - $solana_fullnode_config "${keypair_arg}" "${validator_address_args[@]}" > "$SOLANA_CONFIG_DIR"/validator.json + $solana_fullnode_config --keypair="$id_path" "${validator_address_args[@]}" > "$SOLANA_CONFIG_DIR"/validator.json fi ls -lh "$SOLANA_CONFIG_DIR"/ From ffc843a676bafaf88b41b9cd2943ac40db69fac6 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Thu, 12 Jul 2018 18:16:30 -0600 Subject: [PATCH 10/11] Fix nightly --- Cargo.toml | 1 + src/bin/fullnode-config.rs | 4 ++-- src/bin/keygen.rs | 4 ++-- src/bin/wallet.rs | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4c1c554f8191b9..bdbc17801b6ef7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,6 +81,7 @@ futures = "0.1.21" clap = "2.31" reqwest = "0.8.6" influx_db_client = "0.3.4" +dirs = "1.0.2" [dev-dependencies] criterion = "0.2" diff --git a/src/bin/fullnode-config.rs b/src/bin/fullnode-config.rs index 5d9bc238729a77..2e8235c1bff0e8 100644 --- a/src/bin/fullnode-config.rs +++ b/src/bin/fullnode-config.rs @@ -1,4 +1,5 @@ extern crate clap; +extern crate dirs; extern crate serde_json; extern crate solana; @@ -7,7 +8,6 @@ use solana::crdt::{get_ip_addr, parse_port_or_addr}; use solana::fullnode::Config; use solana::nat::get_public_ip_addr; use solana::signature::read_pkcs8; -use std::env; use std::io; use std::net::SocketAddr; @@ -64,7 +64,7 @@ fn main() { bind_addr }; - let mut path = env::home_dir().expect("home directory"); + let mut path = dirs::home_dir().expect("home directory"); let id_path = if matches.is_present("keypair") { matches.value_of("keypair").unwrap() } else { diff --git a/src/bin/keygen.rs b/src/bin/keygen.rs index e77614d78ab3dc..6974ced7b42024 100644 --- a/src/bin/keygen.rs +++ b/src/bin/keygen.rs @@ -1,11 +1,11 @@ extern crate clap; +extern crate dirs; extern crate ring; extern crate serde_json; use clap::{App, Arg}; use ring::rand::SystemRandom; use ring::signature::Ed25519KeyPair; -use std::env; use std::error; use std::fs::{self, File}; use std::io::Write; @@ -27,7 +27,7 @@ fn main() -> Result<(), Box> { let pkcs8_bytes = Ed25519KeyPair::generate_pkcs8(&rnd)?; let serialized = serde_json::to_string(&pkcs8_bytes.to_vec())?; - let mut path = env::home_dir().expect("home directory"); + let mut path = dirs::home_dir().expect("home directory"); let outfile = if matches.is_present("outfile") { matches.value_of("outfile").unwrap() } else { diff --git a/src/bin/wallet.rs b/src/bin/wallet.rs index 0b320fd8a25edf..cb48d32751a40a 100644 --- a/src/bin/wallet.rs +++ b/src/bin/wallet.rs @@ -2,6 +2,7 @@ extern crate atty; extern crate bincode; extern crate bs58; extern crate clap; +extern crate dirs; extern crate env_logger; extern crate serde_json; extern crate solana; @@ -13,7 +14,6 @@ use solana::drone::DroneRequest; use solana::fullnode::Config; use solana::signature::{read_keypair, KeyPair, KeyPairUtil, PublicKey, Signature}; use solana::thin_client::ThinClient; -use std::env; use std::error; use std::fmt; use std::fs::File; @@ -148,7 +148,7 @@ fn parse_args() -> Result> { leader = NodeInfo::new_leader(&server_addr); }; - let mut path = env::home_dir().expect("home directory"); + let mut path = dirs::home_dir().expect("home directory"); let id_path = if matches.is_present("keypair") { matches.value_of("keypair").unwrap() } else { From 7476b8a8403cf4ada62dd1dcd4ab15b99cdccc1d Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Thu, 12 Jul 2018 19:47:56 -0600 Subject: [PATCH 11/11] Fix keypair option in scripts Thanks @CriesofCarrots! --- multinode-demo/client.sh | 2 +- multinode-demo/drone.sh | 2 +- multinode-demo/wallet.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/multinode-demo/client.sh b/multinode-demo/client.sh index 6d09fd4b74618e..5e11b455aabbae 100755 --- a/multinode-demo/client.sh +++ b/multinode-demo/client.sh @@ -28,4 +28,4 @@ fi # shellcheck disable=SC2086 # $solana_client_demo should not be quoted exec $solana_client_demo \ - -n "$count" -l "$SOLANA_CONFIG_CLIENT_DIR"/leader.json -m "$SOLANA_CONFIG_CLIENT_DIR"/client.json + -n "$count" -l "$SOLANA_CONFIG_CLIENT_DIR"/leader.json -k "$SOLANA_CONFIG_CLIENT_DIR"/client.json diff --git a/multinode-demo/drone.sh b/multinode-demo/drone.sh index 1c9d255f41bb22..e29ccd1f0dc50e 100755 --- a/multinode-demo/drone.sh +++ b/multinode-demo/drone.sh @@ -38,4 +38,4 @@ $rsync -vPz "$rsync_leader_url"/config/leader.json "$SOLANA_CONFIG_DIR"/ # shellcheck disable=SC2086 # $solana_drone should not be quoted exec $solana_drone \ - -l "$SOLANA_CONFIG_DIR"/leader.json -m "$SOLANA_CONFIG_PRIVATE_DIR"/mint.json + -l "$SOLANA_CONFIG_DIR"/leader.json -k "$SOLANA_CONFIG_PRIVATE_DIR"/mint.json diff --git a/multinode-demo/wallet.sh b/multinode-demo/wallet.sh index 658c79df14c941..e3189b5171ee11 100755 --- a/multinode-demo/wallet.sh +++ b/multinode-demo/wallet.sh @@ -44,4 +44,4 @@ fi set -x # shellcheck disable=SC2086 # $solana_wallet should not be quoted exec $solana_wallet \ - -l "$SOLANA_CONFIG_CLIENT_DIR"/leader.json -m "$client_json" "$@" + -l "$SOLANA_CONFIG_CLIENT_DIR"/leader.json -k "$client_json" "$@"