From ba38cef25eef826e2f477358d4c203613a1c1dc3 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Wed, 1 Aug 2018 10:27:05 +1000 Subject: [PATCH] Introduce NetworkConfig and NetworkState --- Cargo.toml | 3 +- src/main.rs | 17 +++++++-- src/p2p/config.rs | 15 +++++++- src/p2p/floodsub.rs | 1 - src/p2p/keys.rs | 14 +++---- src/p2p/mod.rs | 3 +- src/p2p/state.rs | 91 ++++++++++++++++++++++++++++++++++++--------- 7 files changed, 109 insertions(+), 35 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2be246a9c..0207b3d1b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,6 @@ clap = "2.32.0" eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" } ethereum-types = "" futures = "0.1.23" -hex = "0.3.2" libp2p-peerstore = { git = "https://github.com/tomaka/libp2p-rs", branch ="zksummit" } libp2p-core = { git = "https://github.com/tomaka/libp2p-rs", branch ="zksummit" } libp2p-mplex = { git = "https://github.com/tomaka/libp2p-rs", branch ="zksummit" } @@ -21,6 +20,8 @@ libp2p-tcp-transport = { git = "https://github.com/tomaka/libp2p-rs", branch ="z libp2p-floodsub = { git = "https://github.com/tomaka/libp2p-rs", branch ="zksummit" } libp2p-identify = { git = "https://github.com/tomaka/libp2p-rs", branch ="zksummit" } libp2p-kad = { git = "https://github.com/tomaka/libp2p-rs", branch ="zksummit" } +# TODO: Bring pem module internal; too risky to have as external dep. +pem = "0.5.0" rand = "0.3" rlp = { git = "https://github.com/paritytech/parity-common" } slog = "^2.2.3" diff --git a/src/main.rs b/src/main.rs index f84ee672b..66a5f9923 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,8 +10,10 @@ pub mod pubkeystore; pub mod state; pub mod utils; +use std::path::PathBuf; + use slog::Drain; -use clap::{ App, SubCommand}; +use clap::{ Arg, App, SubCommand}; use p2p::config::NetworkConfig; use p2p::floodsub; use p2p::state::NetworkState; @@ -24,17 +26,24 @@ fn main() { let matches = App::new("Lighthouse") .version("0.0.1") - .author("Paul H. ") + .author("Sigma Prime ") .about("Eth 2.0 Client") + .arg(Arg::with_name("datadir") + .value_name("DIR") + .help("Data directory for keys and databases.")) .subcommand(SubCommand::with_name("generate-keys")) .about("Generates a new set of random keys for p2p dev.") .get_matches(); - let config = NetworkConfig::default(); + let mut config = NetworkConfig::default(); + if let Some(dir) = matches.value_of("datadir") { + config.data_dir = PathBuf::from(dir.to_string()); + } + info!(log, ""; "data_dir" => &config.data_dir.to_str()); if let Some(_) = matches.subcommand_matches("generate-keys") { // keys::generate_keys(&log).expect("Failed to generate keys"); } else { - let state = NetworkState::new(&config).expect("setup failed"); + let state = NetworkState::new(config, &log).expect("setup failed"); floodsub::listen(state, &log); } info!(log, "Exiting."); diff --git a/src/p2p/config.rs b/src/p2p/config.rs index 5f1556f2f..0e47c3a3c 100644 --- a/src/p2p/config.rs +++ b/src/p2p/config.rs @@ -1,14 +1,25 @@ +use std::env; +use std::path::PathBuf; + use super::libp2p_core::Multiaddr; +#[derive(Clone)] pub struct NetworkConfig { - pub config_dir: String, + pub data_dir: PathBuf, pub listen_multiaddr: Multiaddr, } +const DEFAULT_LIGHTHOUSE_DIR: &str = ".lighthouse"; + impl NetworkConfig { pub fn default() -> Self{ + let data_dir = { + let home = env::home_dir() + .expect("Unable to determine home dir."); + home.join(DEFAULT_LIGHTHOUSE_DIR) + }; Self { - config_dir: ".lighthouse".to_string(), + data_dir, listen_multiaddr: "/ip4/0.0.0.0/tcp/0" .parse::().unwrap() diff --git a/src/p2p/floodsub.rs b/src/p2p/floodsub.rs index f48f2cfa5..9f3d6a630 100644 --- a/src/p2p/floodsub.rs +++ b/src/p2p/floodsub.rs @@ -1,7 +1,6 @@ extern crate bigint; extern crate bytes; extern crate futures; -extern crate hex; extern crate libp2p_peerstore; extern crate libp2p_identify; extern crate libp2p_core; diff --git a/src/p2p/keys.rs b/src/p2p/keys.rs index 61d7f524a..8d006e80e 100644 --- a/src/p2p/keys.rs +++ b/src/p2p/keys.rs @@ -18,26 +18,22 @@ const LOCAL_PK_FILE: &str = "local.pk"; const LOCAL_SK_FILE: &str = "local.sk"; const BOOTSTRAP_PK_FILE: &str = "bootstrap.pk"; -fn get_curve() -> secp256k1::Secp256k1 { secp256k1::Secp256k1::new() } - /// Generates a new public and secret key pair and writes them to /// individual files. +/// +/// This function should only be present during +/// early development states and should be removed. pub fn generate_keys(config: NetworkConfig, log: &Logger) -> Result<(), IoError> { + // TODO: remove this method and import pem files instead info!(log, "Generating keys..."); let mut rng = rand::thread_rng(); - let curve = get_curve(); + let curve = secp256k1::Secp256k1::new(); let s = SecretKey::new(&curve, &mut rng); - let p = PublicKey::from_secret_key(&curve, &s).unwrap(); - let p_vec = p.serialize_vec(&curve, false); let s_vec = &s[..]; - let p_string = hex::encode(p_vec); let s_string = hex::encode(s_vec); - let mut p_file = File::create(LOCAL_PK_FILE)?; let mut s_file = File::create(LOCAL_SK_FILE)?; - info!(log, "Writing public key..."); - p_file.write(p_string.as_bytes())?; info!(log, "Writing secret key..."); s_file.write(s_string.as_bytes())?; Ok(()) diff --git a/src/p2p/mod.rs b/src/p2p/mod.rs index f483b87a1..9ba21ff35 100644 --- a/src/p2p/mod.rs +++ b/src/p2p/mod.rs @@ -1,7 +1,8 @@ -extern crate hex; extern crate libp2p_core; extern crate libp2p_peerstore; +extern crate pem; extern crate secp256k1; +extern crate slog; pub mod floodsub; pub mod state; diff --git a/src/p2p/state.rs b/src/p2p/state.rs index 787bac396..9094edd84 100644 --- a/src/p2p/state.rs +++ b/src/p2p/state.rs @@ -1,22 +1,26 @@ -use std::io::Read; +extern crate rand; + +use std::io::{ Read, Write }; use std::error::Error; -use std::path::Path; use std::fs::File; use std::sync::Arc; +use std::time::Duration; -use super::hex; +use super::config::NetworkConfig; +use super::libp2p_core::Multiaddr; +use super::libp2p_peerstore::{ Peerstore, PeerAccess, PeerId }; +use super::libp2p_peerstore::json_peerstore::JsonPeerstore; +use super::pem; use super::secp256k1::Secp256k1; use super::secp256k1::key::{ SecretKey, PublicKey }; -use super::libp2p_core::Multiaddr; -use super::libp2p_peerstore::PeerId; -use super::libp2p_peerstore::json_peerstore::JsonPeerstore; -use super::config::NetworkConfig; +use super::slog::Logger; const PEERS_FILE: &str = "peerstore.json"; -const LOCAL_SK_FILE: &str = "local.sk"; +const LOCAL_PEM_FILE: &str = "local_peer_id.pem"; pub struct NetworkState { + pub config: NetworkConfig, pub pubkey: PublicKey, pub seckey: SecretKey, pub peer_id: PeerId, @@ -25,26 +29,26 @@ pub struct NetworkState { } impl NetworkState { - pub fn new(config: &NetworkConfig) -> Result > { + pub fn new(config: NetworkConfig, log: &Logger) -> Result > { let curve = Secp256k1::new(); - let seckey = { - let path = Path::new(&config.config_dir).join(LOCAL_SK_FILE); - let mut contents = String::new(); - let mut file = File::open(path)?; - file.read_to_string(&mut contents)?; - let vec = hex::decode(contents)?; - SecretKey::from_slice(&curve, &vec)? + let seckey = match + NetworkState::load_secret_key_from_pem_file(&config, &curve) + { + Ok(k) => k, + _ => NetworkState::generate_new_secret_key(&config, &curve)? }; let pubkey = PublicKey::from_secret_key(&curve, &seckey)?; let peer_id = PeerId::from_public_key( &pubkey.serialize_vec(&curve, false)); + info!(log, "Loaded keys"; "peer_id" => &peer_id.to_base58()); let peer_store = { - let path = Path::new(&config.config_dir).join(PEERS_FILE); + let path = config.data_dir.join(PEERS_FILE); let base = JsonPeerstore::new(path)?; Arc::new(base) }; let listen_multiaddr = "/ip4/0.0.0.0/tcp/0".parse::()?; Ok(Self { + config: config, seckey, pubkey, peer_id, @@ -52,4 +56,57 @@ impl NetworkState { peer_store, }) } + + pub fn add_peer(&mut self, + peer_id: PeerId, + multiaddr: Multiaddr, + duration_secs: u64) { + self.peer_store.peer_or_create(&peer_id) + .add_addr(multiaddr, Duration::from_secs(duration_secs)); + } + + // TODO: this shouldn't be hard-coded; distribute with peers json. + pub fn add_sigp_peer(&mut self) { + let peer_id = { + let b58 = "Qmajfeei87f8V5N7SQwPw3wr57M1dNcGNwhTqf72v73E7U"; + b58.parse::().unwrap() + }; + let multiaddr = { + let string = "/dns/lh.sigp.io/tcp/10101"; + string.parse::().unwrap() + }; + self.add_peer(peer_id, multiaddr, 3600 * 24 * 356); + } + + /// Instantiate a SecretKey from a .pem file on disk. + pub fn load_secret_key_from_pem_file(config: &NetworkConfig, curve: &Secp256k1) + -> Result> + { + let path = config.data_dir.join(LOCAL_PEM_FILE); + let mut contents = String::new(); + let mut file = File::open(path)?; + file.read_to_string(&mut contents)?; + let pem_key = pem::parse(contents)?; + let key = SecretKey::from_slice(curve, &pem_key.contents)?; + Ok(key) + } + + /// Generate a new SecretKey and store it on disk as a .pem file. + pub fn generate_new_secret_key( + config: &NetworkConfig, + curve: &Secp256k1) + -> Result> + { + let mut rng = rand::thread_rng(); + let sk = SecretKey::new(&curve, &mut rng); + let pem_key = pem::Pem { + tag: String::from("EC PRIVATE KEY"), + contents: sk[..].to_vec() + }; + let s_string = pem::encode(&pem_key); + let path = config.data_dir.join(LOCAL_PEM_FILE); + let mut s_file = File::create(path)?; + s_file.write(s_string.as_bytes())?; + Ok(sk) + } }