From 19a64f906e14e72f205e3c4d391446d4069aac9b Mon Sep 17 00:00:00 2001 From: Age Manning Date: Thu, 28 Feb 2019 10:24:27 +1100 Subject: [PATCH 01/62] Initial beacon node setup. - Add network crate. - Add sync crate. - Add version crate. - Add lighthouse configuration. - Add network configuration. --- Cargo.toml | 3 + beacon_node/Cargo.toml | 9 +- beacon_node/db/src/lib.rs | 7 ++ .../db/src/stores/beacon_block_store.rs | 2 +- beacon_node/network/Cargo.toml | 10 ++ beacon_node/network/src/lib.rs | 4 + .../network/src/network_configuration.rs | 39 ++++++ beacon_node/src/config.rs | 85 +++++++++++++ beacon_node/src/config/mod.rs | 30 ----- beacon_node/src/error.rs | 8 ++ beacon_node/src/main.rs | 119 +++--------------- beacon_node/src/run.rs | 54 ++++++++ beacon_node/sync/Cargo.toml | 8 ++ beacon_node/sync/src/lib.rs | 68 ++++++++++ beacon_node/version/Cargo.toml | 8 ++ beacon_node/version/src/lib.rs | 25 ++++ eth2/fork_choice/src/lib.rs | 1 + 17 files changed, 345 insertions(+), 135 deletions(-) create mode 100644 beacon_node/network/Cargo.toml create mode 100644 beacon_node/network/src/lib.rs create mode 100644 beacon_node/network/src/network_configuration.rs create mode 100644 beacon_node/src/config.rs delete mode 100644 beacon_node/src/config/mod.rs create mode 100644 beacon_node/src/error.rs create mode 100644 beacon_node/src/run.rs create mode 100644 beacon_node/sync/Cargo.toml create mode 100644 beacon_node/sync/src/lib.rs create mode 100644 beacon_node/version/Cargo.toml create mode 100644 beacon_node/version/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 42d69489b3..1090a9b6f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,9 @@ members = [ "eth2/utils/test_random_derive", "beacon_node", "beacon_node/db", + "beacon_node/network", + "beacon_node/sync", + "beacon_node/version", "beacon_node/beacon_chain", "beacon_node/beacon_chain/test_harness", "protos", diff --git a/beacon_node/Cargo.toml b/beacon_node/Cargo.toml index a4804e07e6..f909d51038 100644 --- a/beacon_node/Cargo.toml +++ b/beacon_node/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "beacon_node" version = "0.1.0" -authors = ["Paul Hauner "] +authors = ["Paul Hauner ", "Age Manning BeaconBlockStore { } } - /// Retuns an object implementing `BeaconBlockReader`, or `None` (if hash not known). + /// Returns an object implementing `BeaconBlockReader`, or `None` (if hash not known). /// /// Note: Presently, this function fully deserializes a `BeaconBlock` and returns that. In the /// future, it would be ideal to return an object capable of reading directly from serialized diff --git a/beacon_node/network/Cargo.toml b/beacon_node/network/Cargo.toml new file mode 100644 index 0000000000..57f75e2739 --- /dev/null +++ b/beacon_node/network/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "network" +version = "0.1.0" +authors = ["Age Manning "] +edition = "2018" + +[dependencies] +# SigP repository until PR is merged +libp2p = { git = "https://github.com/SigP/rust-libp2p", branch = "gossipsub" } +version = { path = "../version" } diff --git a/beacon_node/network/src/lib.rs b/beacon_node/network/src/lib.rs new file mode 100644 index 0000000000..1dc56ec4fb --- /dev/null +++ b/beacon_node/network/src/lib.rs @@ -0,0 +1,4 @@ +/// This crate provides the network server for Lighthouse. +mod network_configuration; + +pub use network_configuration::NetworkConfiguration; diff --git a/beacon_node/network/src/network_configuration.rs b/beacon_node/network/src/network_configuration.rs new file mode 100644 index 0000000000..64d763287b --- /dev/null +++ b/beacon_node/network/src/network_configuration.rs @@ -0,0 +1,39 @@ +use libp2p::gossipsub::{GossipsubConfig, GossipsubConfigBuilder}; +use std::net::IpAddr; +use version; + +#[derive(Debug, Clone)] +/// Network configuration for lighthouse. +pub struct NetworkConfiguration { + //TODO: stubbing networking initial params, change in the future + /// IP address to listen on. + pub listen_address: Option, + /// Listen port UDP/TCP. + pub listen_port: Option, + /// Gossipsub configuration parameters. + pub gs_config: GossipsubConfig, + /// List of nodes to initially connect to. + pub boot_nodes: Vec, + /// Client version + pub client_version: String, + //TODO: more to be added +} + +impl Default for NetworkConfiguration { + /// Generate a default network configuration. + fn default() -> Self { + NetworkConfiguration { + listen_address: None, + listen_port: None, + gs_config: GossipsubConfigBuilder::new().build(), + boot_nodes: Vec::new(), + client_version: version::version(), + } + } +} + +impl NetworkConfiguration { + pub fn new() -> Self { + NetworkConfiguration::default() + } +} diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs new file mode 100644 index 0000000000..c7fa579098 --- /dev/null +++ b/beacon_node/src/config.rs @@ -0,0 +1,85 @@ +use clap::ArgMatches; +use db::DBType; +use fork_choice::ForkChoiceAlgorithm; +use network::NetworkConfiguration; +use slog::error; +use std::fs; +use std::net::IpAddr; +use std::path::PathBuf; +use types::ChainSpec; + +/// Stores the core configuration for this Lighthouse instance. +/// This struct is general, other components may implement more +/// specialized configuration structs. +#[derive(Debug, Clone)] +pub struct Config { + pub data_dir: PathBuf, + pub spec: ChainSpec, + pub net_conf: network::NetworkConfiguration, + pub fork_choice: ForkChoiceAlgorithm, + pub db_type: DBType, + pub db_name: PathBuf, + //pub rpc_conf: + //pub ipc_conf: +} + +impl Default for Config { + /// Build a new lighthouse configuration from defaults. + fn default() -> Self { + let data_dir = { + let home = dirs::home_dir().expect("Unable to determine home dir."); + home.join(".lighthouse/") + }; + fs::create_dir_all(&data_dir) + .unwrap_or_else(|_| panic!("Unable to create {:?}", &data_dir)); + Self { + data_dir: data_dir.clone(), + // default to foundation for chain specs + spec: ChainSpec::foundation(), + net_conf: NetworkConfiguration::default(), + // default to bitwise LMD Ghost + fork_choice: ForkChoiceAlgorithm::BitwiseLMDGhost, + // default to memory db for now + db_type: DBType::Memory, + // default db name for disk-based dbs + db_name: data_dir.join("chain.db"), + } + } +} + +impl Config { + /// Parses the CLI arguments into a `Config` struct. + pub fn parse_args(args: ArgMatches, log: &slog::Logger) -> Result { + let mut config = Config::default(); + + // Network related args + + // Custom listening address ipv4/ipv6 + if let Some(listen_address_str) = args.value_of("listen_address") { + if let Ok(listen_address) = listen_address_str.parse::() { + config.net_conf.listen_address = Some(listen_address); + } else { + error!(log, "Invalid Ip Address"; "Address" => listen_address_str); + return Err("Invalid Ip Address"); + } + } + // Custom p2p listen port + if let Some(port_str) = args.value_of("port") { + if let Ok(port) = port_str.parse::() { + config.net_conf.listen_port = Some(port); + } else { + error!(log, "Invalid port"; "port" => port_str); + return Err("Invalid port"); + } + } + + // filesystem args + + // Custom datadir + if let Some(dir) = args.value_of("datadir") { + config.data_dir = PathBuf::from(dir.to_string()); + }; + + Ok(config) + } +} diff --git a/beacon_node/src/config/mod.rs b/beacon_node/src/config/mod.rs deleted file mode 100644 index 5c94e300c7..0000000000 --- a/beacon_node/src/config/mod.rs +++ /dev/null @@ -1,30 +0,0 @@ -use std::fs; -use std::path::PathBuf; - -/// Stores the core configuration for this Lighthouse instance. -/// This struct is general, other components may implement more -/// specialized config structs. -#[derive(Clone)] -pub struct LighthouseConfig { - pub data_dir: PathBuf, - pub p2p_listen_port: u16, -} - -const DEFAULT_LIGHTHOUSE_DIR: &str = ".lighthouse"; - -impl LighthouseConfig { - /// Build a new lighthouse configuration from defaults. - pub fn default() -> Self { - let data_dir = { - let home = dirs::home_dir().expect("Unable to determine home dir."); - home.join(DEFAULT_LIGHTHOUSE_DIR) - }; - fs::create_dir_all(&data_dir) - .unwrap_or_else(|_| panic!("Unable to create {:?}", &data_dir)); - let p2p_listen_port = 0; - Self { - data_dir, - p2p_listen_port, - } - } -} diff --git a/beacon_node/src/error.rs b/beacon_node/src/error.rs new file mode 100644 index 0000000000..163fe575d2 --- /dev/null +++ b/beacon_node/src/error.rs @@ -0,0 +1,8 @@ +// generates error types + +use error_chain::{ + error_chain, error_chain_processing, impl_error_chain_kind, impl_error_chain_processed, + impl_extract_backtrace, +}; + +error_chain! {} diff --git a/beacon_node/src/main.rs b/beacon_node/src/main.rs index b9ef2c8a7a..ed26a55fe2 100644 --- a/beacon_node/src/main.rs +++ b/beacon_node/src/main.rs @@ -1,34 +1,23 @@ extern crate slog; mod config; +mod error; mod rpc; +mod run; -use std::path::PathBuf; - -use crate::config::LighthouseConfig; -use crate::rpc::start_server; -use beacon_chain::BeaconChain; -use bls::create_proof_of_possession; use clap::{App, Arg}; -use db::{ - stores::{BeaconBlockStore, BeaconStateStore}, - MemoryDB, -}; -use fork_choice::BitwiseLMDGhost; -use slog::{error, info, o, Drain}; -use slot_clock::SystemTimeSlotClock; -use std::sync::Arc; -use types::{ChainSpec, Deposit, DepositData, DepositInput, Eth1Data, Hash256, Keypair}; +use config::Config; +use slog::{o, Drain}; fn main() { let decorator = slog_term::TermDecorator::new().build(); let drain = slog_term::CompactFormat::new(decorator).build().fuse(); let drain = slog_async::Async::new(drain).build().fuse(); - let log = slog::Logger::root(drain, o!()); + let logger = slog::Logger::root(drain, o!()); let matches = App::new("Lighthouse") - .version("0.0.1") - .author("Sigma Prime ") + .version(version::version().as_str()) + .author("Sigma Prime ") .about("Eth 2.0 Client") .arg( Arg::with_name("datadir") @@ -37,6 +26,13 @@ fn main() { .help("Data directory for keys and databases.") .takes_value(true), ) + .arg( + Arg::with_name("listen_address") + .long("listen_address") + .value_name("Listen Address") + .help("The Network address to listen for p2p connections.") + .takes_value(true), + ) .arg( Arg::with_name("port") .long("port") @@ -46,89 +42,8 @@ fn main() { ) .get_matches(); - let mut config = LighthouseConfig::default(); + // invalid arguments, panic + let config = Config::parse_args(matches, &logger).unwrap(); - // Custom datadir - if let Some(dir) = matches.value_of("datadir") { - config.data_dir = PathBuf::from(dir.to_string()); - } - - // Custom p2p listen port - if let Some(port_str) = matches.value_of("port") { - if let Ok(port) = port_str.parse::() { - config.p2p_listen_port = port; - } else { - error!(log, "Invalid port"; "port" => port_str); - return; - } - } - - // Log configuration - info!(log, ""; - "data_dir" => &config.data_dir.to_str(), - "port" => &config.p2p_listen_port); - - // Specification (presently fixed to foundation). - let spec = ChainSpec::foundation(); - - // Database (presently in-memory) - let db = Arc::new(MemoryDB::open()); - let block_store = Arc::new(BeaconBlockStore::new(db.clone())); - let state_store = Arc::new(BeaconStateStore::new(db.clone())); - - // Slot clock - let genesis_time = 1_549_935_547; // 12th Feb 2018 (arbitrary value in the past). - let slot_clock = SystemTimeSlotClock::new(genesis_time, spec.slot_duration) - .expect("Unable to load SystemTimeSlotClock"); - // Choose the fork choice - let fork_choice = BitwiseLMDGhost::new(block_store.clone(), state_store.clone()); - - /* - * Generate some random data to start a chain with. - * - * This is will need to be replace for production usage. - */ - let latest_eth1_data = Eth1Data { - deposit_root: Hash256::zero(), - block_hash: Hash256::zero(), - }; - let keypairs: Vec = (0..10) - .collect::>() - .iter() - .map(|_| Keypair::random()) - .collect(); - let initial_validator_deposits = keypairs - .iter() - .map(|keypair| Deposit { - branch: vec![], // branch verification is not specified. - index: 0, // index verification is not specified. - deposit_data: DepositData { - amount: 32_000_000_000, // 32 ETH (in Gwei) - timestamp: genesis_time - 1, - deposit_input: DepositInput { - pubkey: keypair.pk.clone(), - withdrawal_credentials: Hash256::zero(), // Withdrawal not possible. - proof_of_possession: create_proof_of_possession(&keypair), - }, - }, - }) - .collect(); - - // Genesis chain - let _chain_result = BeaconChain::genesis( - state_store.clone(), - block_store.clone(), - slot_clock, - genesis_time, - latest_eth1_data, - initial_validator_deposits, - spec, - fork_choice, - ); - - let _server = start_server(log.clone()); - - loop { - std::thread::sleep(std::time::Duration::from_secs(1)); - } + run::run_beacon_node(config, &logger); } diff --git a/beacon_node/src/run.rs b/beacon_node/src/run.rs new file mode 100644 index 0000000000..18c4c3fe05 --- /dev/null +++ b/beacon_node/src/run.rs @@ -0,0 +1,54 @@ +use crate::config::Config; +use crate::error; +use crate::rpc::start_server; +use beacon_chain::BeaconChain; +use bls::create_proof_of_possession; +use db::{ + stores::{BeaconBlockStore, BeaconStateStore}, + ClientDB, DBType, DiskDB, MemoryDB, +}; +use fork_choice::{BitwiseLMDGhost, ForkChoiceAlgorithm}; +use futures::sync::oneshot; +use network::NetworkConfiguration; +use slog::{error, info}; +use slot_clock::SystemTimeSlotClock; +use std::cell::RefCell; +use std::sync::Arc; +use tokio::runtime::{Builder, Runtime, TaskExecutor}; +use types::{ChainSpec, Deposit, DepositData, DepositInput, Eth1Data, Hash256, Keypair}; + +pub fn run_beacon_node(config: Config, log: &slog::Logger) -> error::Result<()> { + let mut runtime = Builder::new() + .name_prefix("main-") + .build() + .map_err(|e| format!("{:?}", e))?; + + // Log configuration + info!(log, ""; + "data_dir" => &config.data_dir.to_str(), + "port" => &config.net_conf.listen_port); + + // run service until ctrl-c + let (ctrlc_send, ctrlc) = oneshot::channel(); + let ctrlc_send_c = RefCell::new(Some(ctrlc_send)); + ctrlc::set_handler(move || { + if let Some(ctrlc_send) = ctrlc_send_c.try_borrow_mut().unwrap().take() { + ctrlc_send + .send(()) + .expect("Error sending termination message"); + } + }); + + let executor = runtime.executor(); + + start(config, log, executor); + + runtime.block_on(ctrlc); + + info!(log, "Shutting down."); + //TODO: handle shutdown of processes gracefully + + Ok(()) +} + +fn start(config: Config, log: &slog::Logger, executor: TaskExecutor) {} diff --git a/beacon_node/sync/Cargo.toml b/beacon_node/sync/Cargo.toml new file mode 100644 index 0000000000..347506bf06 --- /dev/null +++ b/beacon_node/sync/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "sync" +version = "0.1.0" +authors = ["Age Manning "] +edition = "2018" + +[dependencies] + diff --git a/beacon_node/sync/src/lib.rs b/beacon_node/sync/src/lib.rs new file mode 100644 index 0000000000..f520e9e094 --- /dev/null +++ b/beacon_node/sync/src/lib.rs @@ -0,0 +1,68 @@ +// /// Syncing for lighthouse. + +/* +// for initial testing and setup, to be replaced. +pub fn sync_server(config: Config) { + // Set up database + let db = match config.db_type { + _ => Arc::new(MemoryDB::open()), + //TODO: Box db + //DBType::Memory => Arc::new(Box::new(MemoryDB::open())), + //DBType::RocksDB => Arc::new(Box::new(DiskDB::open(&config.db_name, None))), + }; + + // build block + let block_store = Arc::new(BeaconBlockStore::new(db.clone())); + let state_store = Arc::new(BeaconStateStore::new(db.clone())); + + // Slot clock + let genesis_time = 1_549_935_547; // 12th Feb 2018 (arbitrary value in the past). + let slot_clock = SystemTimeSlotClock::new(genesis_time, spec.slot_duration) + .expect("Unable to load SystemTimeSlotClock"); + // Choose the fork choice + let fork_choice = BitwiseLMDGhost::new(block_store.clone(), state_store.clone()); + + /* + * Generate some random data to start a chain with. + * + * This is will need to be replace for production usage. + */ +let latest_eth1_data = Eth1Data { +deposit_root: Hash256::zero(), +block_hash: Hash256::zero(), +}; +let keypairs: Vec = (0..10) +.collect::>() +.iter() +.map(|_| Keypair::random()) +.collect(); +let initial_validator_deposits = keypairs +.iter() +.map(|keypair| Deposit { +branch: vec![], // branch verification is not specified. +index: 0, // index verification is not specified. +deposit_data: DepositData { +amount: 32_000_000_000, // 32 ETH (in Gwei) +timestamp: genesis_time - 1, +deposit_input: DepositInput { +pubkey: keypair.pk.clone(), +withdrawal_credentials: Hash256::zero(), // Withdrawal not possible. +proof_of_possession: create_proof_of_possession(&keypair), +}, +}, +}) +.collect(); + +// Genesis chain +let _chain_result = BeaconChain::genesis( +state_store.clone(), +block_store.clone(), +slot_clock, +genesis_time, +latest_eth1_data, +initial_validator_deposits, +spec, +fork_choice, +); +} +*/ diff --git a/beacon_node/version/Cargo.toml b/beacon_node/version/Cargo.toml new file mode 100644 index 0000000000..0497408f1b --- /dev/null +++ b/beacon_node/version/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "version" +version = "0.1.0" +authors = ["Age Manning "] +edition = "2018" + +[dependencies] +target_info = "0.1.0" diff --git a/beacon_node/version/src/lib.rs b/beacon_node/version/src/lib.rs new file mode 100644 index 0000000000..628186aa07 --- /dev/null +++ b/beacon_node/version/src/lib.rs @@ -0,0 +1,25 @@ +//TODO: Build the version and hash of the built lighthouse binary + +/// Version information for the Lighthouse beacon node. +// currently only supports unstable release +extern crate target_info; + +use target_info::Target; + +const TRACK: &'static str = "unstable"; + +/// Provides the current platform +pub fn platform() -> String { + format!("{}-{}", Target::arch(), Target::os()) +} + +/// Version of the beacon node. +// TODO: Find the sha3 hash, date and rust version used to build the beacon_node binary +pub fn version() -> String { + format!( + "Lighthouse/v{}-{}/{}", + env!("CARGO_PKG_VERSION"), + TRACK, + platform() + ) +} diff --git a/eth2/fork_choice/src/lib.rs b/eth2/fork_choice/src/lib.rs index 6062c19b15..318ac99a8a 100644 --- a/eth2/fork_choice/src/lib.rs +++ b/eth2/fork_choice/src/lib.rs @@ -94,6 +94,7 @@ impl From for ForkChoiceError { } /// Fork choice options that are currently implemented. +#[derive(Debug, Clone)] pub enum ForkChoiceAlgorithm { /// Chooses the longest chain becomes the head. Not for production. LongestChain, From 2e020a3efaac9361fed1dede756731e081156c33 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Fri, 1 Mar 2019 12:45:01 +1100 Subject: [PATCH 02/62] Implement the basic structure of the beacon node. --- Cargo.toml | 2 + beacon_node/Cargo.toml | 23 +++------ beacon_node/client/Cargo.toml | 22 ++++++++ .../config.rs => client/src/client_config.rs} | 12 ++--- beacon_node/client/src/client_types.rs | 25 ++++++++++ beacon_node/{ => client}/src/error.rs | 0 beacon_node/client/src/lib.rs | 50 +++++++++++++++++++ beacon_node/client/src/notifier.rs | 35 +++++++++++++ beacon_node/rpc/Cargo.toml | 23 +++++++++ .../{src/rpc => rpc/src}/beacon_block.rs | 0 .../{src/rpc/mod.rs => rpc/src/lib.rs} | 0 beacon_node/{src/rpc => rpc/src}/validator.rs | 0 beacon_node/src/main.rs | 9 ++-- beacon_node/src/run.rs | 43 +++++++--------- 14 files changed, 188 insertions(+), 56 deletions(-) create mode 100644 beacon_node/client/Cargo.toml rename beacon_node/{src/config.rs => client/src/client_config.rs} (90%) create mode 100644 beacon_node/client/src/client_types.rs rename beacon_node/{ => client}/src/error.rs (100%) create mode 100644 beacon_node/client/src/lib.rs create mode 100755 beacon_node/client/src/notifier.rs create mode 100644 beacon_node/rpc/Cargo.toml rename beacon_node/{src/rpc => rpc/src}/beacon_block.rs (100%) rename beacon_node/{src/rpc/mod.rs => rpc/src/lib.rs} (100%) rename beacon_node/{src/rpc => rpc/src}/validator.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 1090a9b6f5..6cd11c4380 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,9 @@ members = [ "eth2/utils/test_random_derive", "beacon_node", "beacon_node/db", + "beacon_node/client", "beacon_node/network", + "beacon_node/rpc", "beacon_node/sync", "beacon_node/version", "beacon_node/beacon_chain", diff --git a/beacon_node/Cargo.toml b/beacon_node/Cargo.toml index f909d51038..8b26417860 100644 --- a/beacon_node/Cargo.toml +++ b/beacon_node/Cargo.toml @@ -5,25 +5,14 @@ authors = ["Paul Hauner ", "Age Manning "] +edition = "2018" + +[dependencies] +beacon_chain = { path = "../beacon_chain" } +network = { path = "../network" } +sync = { path = "../sync" } +db = { path = "../db" } +fork_choice = { path = "../../eth2/fork_choice" } +types = { path = "../../eth2/types" } +slot_clock = { path = "../../eth2/utils/slot_clock" } + +error-chain = "0.12.0" +slog = "^2.2.3" +tokio = "0.1.15" +clap = "2.32.0" +dirs = "1.0.3" +exit-future = "0.1.3" +futures = "0.1.25" diff --git a/beacon_node/src/config.rs b/beacon_node/client/src/client_config.rs similarity index 90% rename from beacon_node/src/config.rs rename to beacon_node/client/src/client_config.rs index c7fa579098..c1580aa9fe 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/client/src/client_config.rs @@ -8,11 +8,9 @@ use std::net::IpAddr; use std::path::PathBuf; use types::ChainSpec; -/// Stores the core configuration for this Lighthouse instance. -/// This struct is general, other components may implement more -/// specialized configuration structs. +/// Stores the client configuration for this Lighthouse instance. #[derive(Debug, Clone)] -pub struct Config { +pub struct ClientConfig { pub data_dir: PathBuf, pub spec: ChainSpec, pub net_conf: network::NetworkConfiguration, @@ -23,7 +21,7 @@ pub struct Config { //pub ipc_conf: } -impl Default for Config { +impl Default for ClientConfig { /// Build a new lighthouse configuration from defaults. fn default() -> Self { let data_dir = { @@ -47,10 +45,10 @@ impl Default for Config { } } -impl Config { +impl ClientConfig { /// Parses the CLI arguments into a `Config` struct. pub fn parse_args(args: ArgMatches, log: &slog::Logger) -> Result { - let mut config = Config::default(); + let mut config = ClientConfig::default(); // Network related args diff --git a/beacon_node/client/src/client_types.rs b/beacon_node/client/src/client_types.rs new file mode 100644 index 0000000000..38ae1c8c38 --- /dev/null +++ b/beacon_node/client/src/client_types.rs @@ -0,0 +1,25 @@ +use db::{ClientDB, DiskDB, MemoryDB}; +use fork_choice::{BitwiseLMDGhost, ForkChoice}; +use slot_clock::{SlotClock, SystemTimeSlotClock, TestingSlotClock}; + +pub trait ClientTypes { + type ForkChoice: ForkChoice; + type DB: ClientDB; + type SlotClock: SlotClock; +} + +pub struct StandardClientType {} + +impl ClientTypes for StandardClientType { + type DB = DiskDB; + type ForkChoice = BitwiseLMDGhost; + type SlotClock = SystemTimeSlotClock; +} + +pub struct TestingClientType {} + +impl ClientTypes for TestingClientType { + type DB = MemoryDB; + type SlotClock = TestingSlotClock; + type ForkChoice = BitwiseLMDGhost; +} diff --git a/beacon_node/src/error.rs b/beacon_node/client/src/error.rs similarity index 100% rename from beacon_node/src/error.rs rename to beacon_node/client/src/error.rs diff --git a/beacon_node/client/src/lib.rs b/beacon_node/client/src/lib.rs new file mode 100644 index 0000000000..3bfde0e9de --- /dev/null +++ b/beacon_node/client/src/lib.rs @@ -0,0 +1,50 @@ +extern crate slog; + +mod client_config; + +pub mod client_types; +pub mod error; +pub mod notifier; + +pub use client_config::ClientConfig; +pub use client_types::ClientTypes; + +//use beacon_chain::BeaconChain; +use exit_future::{Exit, Signal}; +use std::marker::PhantomData; +//use std::sync::Arc; +use tokio::runtime::TaskExecutor; + +//use network::NetworkService; + +pub struct Client { + config: ClientConfig, + // beacon_chain: Arc>, + // network: Option>, + exit: exit_future::Exit, + exit_signal: Option, + log: slog::Logger, + phantom: PhantomData, +} + +impl Client { + pub fn new( + config: ClientConfig, + log: slog::Logger, + executor: TaskExecutor, + ) -> error::Result { + let (exit_signal, exit) = exit_future::signal(); + + Ok(Client { + config, + exit, + exit_signal: Some(exit_signal), + log, + phantom: PhantomData, + }) + } + + pub fn logger(&self) -> slog::Logger { + self.log.clone() + } +} diff --git a/beacon_node/client/src/notifier.rs b/beacon_node/client/src/notifier.rs new file mode 100755 index 0000000000..3edf93bf68 --- /dev/null +++ b/beacon_node/client/src/notifier.rs @@ -0,0 +1,35 @@ +use crate::Client; +use crate::ClientTypes; +use db::ClientDB; +use exit_future::Exit; +use fork_choice::ForkChoice; +use futures::{Future, Stream}; +use slog::{debug, info}; +use slot_clock::SlotClock; +use std::sync::Arc; +use std::time::{Duration, Instant}; +use tokio::runtime::TaskExecutor; +use tokio::timer::Interval; + +/// Thread that monitors the client and reports useful statistics to the user. + +pub fn run(client: &Client, executor: TaskExecutor, exit: Exit) { + // notification heartbeat + let interval = Interval::new(Instant::now(), Duration::from_secs(5)); + + let log = client.logger(); + + // build heartbeat logic here + let heartbeat = move |_| { + info!(log, "Temp heartbeat output"); + Ok(()) + }; + + // map error and spawn + let log = client.logger(); + let heartbeat_interval = interval + .map_err(move |e| debug!(log, "Timer error {}", e)) + .for_each(heartbeat); + + executor.spawn(exit.until(heartbeat_interval).map(|_| ())); +} diff --git a/beacon_node/rpc/Cargo.toml b/beacon_node/rpc/Cargo.toml new file mode 100644 index 0000000000..4c3333ee1d --- /dev/null +++ b/beacon_node/rpc/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "rpc" +version = "0.1.0" +authors = ["Age Manning "] +edition = "2018" + +[dependencies] +bls = { path = "../../eth2/utils/bls" } +beacon_chain = { path = "../beacon_chain" } + +protos = { path = "../../protos" } +grpcio = { version = "0.4", default-features = false, features = ["protobuf-codec"] } +protobuf = "2.0.2" +clap = "2.32.0" +db = { path = "../db" } +dirs = "1.0.3" +futures = "0.1.23" +slog = "^2.2.3" +slot_clock = { path = "../../eth2/utils/slot_clock" } +slog-term = "^2.4.0" +slog-async = "^2.3.0" +types = { path = "../../eth2/types" } +ssz = { path = "../../eth2/utils/ssz" } diff --git a/beacon_node/src/rpc/beacon_block.rs b/beacon_node/rpc/src/beacon_block.rs similarity index 100% rename from beacon_node/src/rpc/beacon_block.rs rename to beacon_node/rpc/src/beacon_block.rs diff --git a/beacon_node/src/rpc/mod.rs b/beacon_node/rpc/src/lib.rs similarity index 100% rename from beacon_node/src/rpc/mod.rs rename to beacon_node/rpc/src/lib.rs diff --git a/beacon_node/src/rpc/validator.rs b/beacon_node/rpc/src/validator.rs similarity index 100% rename from beacon_node/src/rpc/validator.rs rename to beacon_node/rpc/src/validator.rs diff --git a/beacon_node/src/main.rs b/beacon_node/src/main.rs index ed26a55fe2..09cac99b4b 100644 --- a/beacon_node/src/main.rs +++ b/beacon_node/src/main.rs @@ -1,12 +1,9 @@ extern crate slog; -mod config; -mod error; -mod rpc; mod run; use clap::{App, Arg}; -use config::Config; +use client::ClientConfig; use slog::{o, Drain}; fn main() { @@ -43,7 +40,7 @@ fn main() { .get_matches(); // invalid arguments, panic - let config = Config::parse_args(matches, &logger).unwrap(); + let config = ClientConfig::parse_args(matches, &logger).unwrap(); - run::run_beacon_node(config, &logger); + run::run_beacon_node(config, logger); } diff --git a/beacon_node/src/run.rs b/beacon_node/src/run.rs index 18c4c3fe05..3207ce43de 100644 --- a/beacon_node/src/run.rs +++ b/beacon_node/src/run.rs @@ -1,23 +1,13 @@ -use crate::config::Config; -use crate::error; -use crate::rpc::start_server; -use beacon_chain::BeaconChain; -use bls::create_proof_of_possession; -use db::{ - stores::{BeaconBlockStore, BeaconStateStore}, - ClientDB, DBType, DiskDB, MemoryDB, -}; -use fork_choice::{BitwiseLMDGhost, ForkChoiceAlgorithm}; +use client::client_types::{StandardClientType, TestingClientType}; +use client::error; +use client::{notifier, Client, ClientConfig}; use futures::sync::oneshot; -use network::NetworkConfiguration; -use slog::{error, info}; -use slot_clock::SystemTimeSlotClock; +use futures::Future; +use slog::info; use std::cell::RefCell; -use std::sync::Arc; -use tokio::runtime::{Builder, Runtime, TaskExecutor}; -use types::{ChainSpec, Deposit, DepositData, DepositInput, Eth1Data, Hash256, Keypair}; +use tokio::runtime::Builder; -pub fn run_beacon_node(config: Config, log: &slog::Logger) -> error::Result<()> { +pub fn run_beacon_node(config: ClientConfig, log: slog::Logger) -> error::Result<()> { let mut runtime = Builder::new() .name_prefix("main-") .build() @@ -33,22 +23,23 @@ pub fn run_beacon_node(config: Config, log: &slog::Logger) -> error::Result<()> let ctrlc_send_c = RefCell::new(Some(ctrlc_send)); ctrlc::set_handler(move || { if let Some(ctrlc_send) = ctrlc_send_c.try_borrow_mut().unwrap().take() { - ctrlc_send - .send(()) - .expect("Error sending termination message"); + ctrlc_send.send(()).expect("Error sending ctrl-c message"); } }); + let (exit_signal, exit) = exit_future::signal(); + let executor = runtime.executor(); - start(config, log, executor); + // currently testing - using TestingNode type + let client: Client = Client::new(config, log.clone(), executor.clone())?; + notifier::run(&client, executor, exit); runtime.block_on(ctrlc); - info!(log, "Shutting down."); - //TODO: handle shutdown of processes gracefully - + info!(log, "Shutting down.."); + exit_signal.fire(); + drop(client); + runtime.shutdown_on_idle().wait().unwrap(); Ok(()) } - -fn start(config: Config, log: &slog::Logger, executor: TaskExecutor) {} From 3b8f29a9141e337738937c2efe23c496621ed90b Mon Sep 17 00:00:00 2001 From: Age Manning Date: Mon, 4 Mar 2019 16:39:37 +1100 Subject: [PATCH 03/62] [Temp Commit] Implements more basic skeleton code. --- beacon_node/beacon_chain/Cargo.toml | 2 +- beacon_node/beacon_chain/src/initialize.rs | 56 +++++++++++++++ beacon_node/client/src/client_config.rs | 13 ++-- beacon_node/client/src/lib.rs | 21 ++++-- beacon_node/client/src/notifier.rs | 2 +- beacon_node/libp2p/Cargo.toml | 7 ++ beacon_node/libp2p/src/lib.rs | 11 +++ beacon_node/libp2p/src/service.rs | 0 beacon_node/network/Cargo.toml | 4 +- beacon_node/network/src/error.rs | 8 +++ beacon_node/network/src/lib.rs | 6 +- beacon_node/network/src/message_handler.rs | 18 +++++ beacon_node/network/src/messages.rs | 27 +++++++ ...ork_configuration.rs => network_config.rs} | 15 ++-- beacon_node/network/src/service.rs | 0 beacon_node/src/run.rs | 1 + beacon_node/sync/Cargo.toml | 3 +- beacon_node/sync/src/lib.rs | 72 ++----------------- beacon_node/sync/src/simple_syncer.rs | 22 ++++++ 19 files changed, 195 insertions(+), 93 deletions(-) create mode 100644 beacon_node/beacon_chain/src/initialize.rs mode change 100755 => 100644 beacon_node/client/src/notifier.rs create mode 100644 beacon_node/libp2p/Cargo.toml create mode 100644 beacon_node/libp2p/src/lib.rs create mode 100644 beacon_node/libp2p/src/service.rs create mode 100644 beacon_node/network/src/error.rs create mode 100644 beacon_node/network/src/message_handler.rs create mode 100644 beacon_node/network/src/messages.rs rename beacon_node/network/src/{network_configuration.rs => network_config.rs} (75%) create mode 100644 beacon_node/network/src/service.rs create mode 100644 beacon_node/sync/src/simple_syncer.rs diff --git a/beacon_node/beacon_chain/Cargo.toml b/beacon_node/beacon_chain/Cargo.toml index 4ce894477d..b5471be5fa 100644 --- a/beacon_node/beacon_chain/Cargo.toml +++ b/beacon_node/beacon_chain/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "beacon_chain" version = "0.1.0" -authors = ["Paul Hauner "] +authors = ["Paul Hauner ", "Age Manning "] edition = "2018" [dependencies] diff --git a/beacon_node/beacon_chain/src/initialize.rs b/beacon_node/beacon_chain/src/initialize.rs new file mode 100644 index 0000000000..14d0f81a67 --- /dev/null +++ b/beacon_node/beacon_chain/src/initialize.rs @@ -0,0 +1,56 @@ +// Initialisation functions to generate a new BeaconChain. + +pub fn initialise_test_chain( + config: &ClientConfig, +) -> Arc> { + let spec = config.spec; + // Slot clock + let genesis_time = 1_549_935_547; // 12th Feb 2018 (arbitrary value in the past). + let slot_clock = SystemTimeSlotClock::new(genesis_time, spec.slot_duration) + .expect("Unable to load SystemTimeSlotClock"); + // Choose the fork choice + let fork_choice = BitwiseLMDGhost::new(block_store.clone(), state_store.clone()); + + /* + * Generate some random data to start a chain with. + * + * This is will need to be replace for production usage. + */ + let latest_eth1_data = Eth1Data { + deposit_root: Hash256::zero(), + block_hash: Hash256::zero(), + }; + let keypairs: Vec = (0..10) + .collect::>() + .iter() + .map(|_| Keypair::random()) + .collect(); + let initial_validator_deposits = keypairs + .iter() + .map(|keypair| Deposit { + branch: vec![], // branch verification is not specified. + index: 0, // index verification is not specified. + deposit_data: DepositData { + amount: 32_000_000_000, // 32 ETH (in Gwei) + timestamp: genesis_time - 1, + deposit_input: DepositInput { + pubkey: keypair.pk.clone(), + withdrawal_credentials: Hash256::zero(), // Withdrawal not possible. + proof_of_possession: create_proof_of_possession(&keypair), + }, + }, + }) + .collect(); + + // Genesis chain + Arc::new(BeaconChain::genesis( + state_store.clone(), + block_store.clone(), + slot_clock, + genesis_time, + latest_eth1_data, + initial_validator_deposits, + spec, + fork_choice, + )); +} diff --git a/beacon_node/client/src/client_config.rs b/beacon_node/client/src/client_config.rs index c1580aa9fe..8943e783d0 100644 --- a/beacon_node/client/src/client_config.rs +++ b/beacon_node/client/src/client_config.rs @@ -1,7 +1,7 @@ use clap::ArgMatches; use db::DBType; use fork_choice::ForkChoiceAlgorithm; -use network::NetworkConfiguration; +use network::NetworkConfig; use slog::error; use std::fs; use std::net::IpAddr; @@ -13,7 +13,7 @@ use types::ChainSpec; pub struct ClientConfig { pub data_dir: PathBuf, pub spec: ChainSpec, - pub net_conf: network::NetworkConfiguration, + pub net_conf: network::NetworkConfig, pub fork_choice: ForkChoiceAlgorithm, pub db_type: DBType, pub db_name: PathBuf, @@ -34,7 +34,7 @@ impl Default for ClientConfig { data_dir: data_dir.clone(), // default to foundation for chain specs spec: ChainSpec::foundation(), - net_conf: NetworkConfiguration::default(), + net_conf: NetworkConfig::default(), // default to bitwise LMD Ghost fork_choice: ForkChoiceAlgorithm::BitwiseLMDGhost, // default to memory db for now @@ -53,12 +53,13 @@ impl ClientConfig { // Network related args // Custom listening address ipv4/ipv6 + // TODO: Handle list of addresses if let Some(listen_address_str) = args.value_of("listen_address") { if let Ok(listen_address) = listen_address_str.parse::() { - config.net_conf.listen_address = Some(listen_address); + config.net_conf.listen_address = Some(Vec::new(listen_address)); } else { - error!(log, "Invalid Ip Address"; "Address" => listen_address_str); - return Err("Invalid Ip Address"); + error!(log, "Invalid IP Address"; "Address" => listen_address_str); + return Err("Invalid IP Address"); } } // Custom p2p listen port diff --git a/beacon_node/client/src/lib.rs b/beacon_node/client/src/lib.rs index 3bfde0e9de..5ea6ba4a67 100644 --- a/beacon_node/client/src/lib.rs +++ b/beacon_node/client/src/lib.rs @@ -13,14 +13,15 @@ pub use client_types::ClientTypes; use exit_future::{Exit, Signal}; use std::marker::PhantomData; //use std::sync::Arc; +use network::NetworkService; use tokio::runtime::TaskExecutor; -//use network::NetworkService; - +/// Main beacon node client service. This provides the connection and initialisation of the clients +/// sub-services in multiple threads. pub struct Client { config: ClientConfig, // beacon_chain: Arc>, - // network: Option>, + network: Option>, exit: exit_future::Exit, exit_signal: Option, log: slog::Logger, @@ -28,6 +29,7 @@ pub struct Client { } impl Client { + /// Generate an instance of the client. Spawn and link all internal subprocesses. pub fn new( config: ClientConfig, log: slog::Logger, @@ -35,16 +37,21 @@ impl Client { ) -> error::Result { let (exit_signal, exit) = exit_future::signal(); + // TODO: generate a beacon_chain service. + + // start the network service, libp2p and syncing threads + // TODO: Add beacon_chain reference to network parameters + let network_config = config.net_config; + let network_logger = client.log.new(o!("Service" => "Network")); + let (network, network_send) = NetworkService::new(network_config, network_logger); + Ok(Client { config, exit, exit_signal: Some(exit_signal), log, + network: Some(network), phantom: PhantomData, }) } - - pub fn logger(&self) -> slog::Logger { - self.log.clone() - } } diff --git a/beacon_node/client/src/notifier.rs b/beacon_node/client/src/notifier.rs old mode 100755 new mode 100644 index 3edf93bf68..68d93e7358 --- a/beacon_node/client/src/notifier.rs +++ b/beacon_node/client/src/notifier.rs @@ -17,7 +17,7 @@ pub fn run(client: &Client, executor: TaskExecutor, exit: Exi // notification heartbeat let interval = Interval::new(Instant::now(), Duration::from_secs(5)); - let log = client.logger(); + let log = client.log.new(o!("Service" => "Notifier")); // build heartbeat logic here let heartbeat = move |_| { diff --git a/beacon_node/libp2p/Cargo.toml b/beacon_node/libp2p/Cargo.toml new file mode 100644 index 0000000000..f35ae4d430 --- /dev/null +++ b/beacon_node/libp2p/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "libp2p" +version = "0.1.0" +authors = ["Age Manning "] +edition = "2018" + +[dependencies] diff --git a/beacon_node/libp2p/src/lib.rs b/beacon_node/libp2p/src/lib.rs new file mode 100644 index 0000000000..e20eb055f8 --- /dev/null +++ b/beacon_node/libp2p/src/lib.rs @@ -0,0 +1,11 @@ +/// This crate contains the main link for lighthouse to rust-libp2p. It therefore re-exports +/// all required libp2p functionality. +/// +/// This crate builds and manages the libp2p services required by the beacon node. +extern crate libp2p; + +mod libp2p_service; + +pub use libp2p::{GossipsubConfig, PeerId}; + +pub use libp2p_service::LibP2PService; diff --git a/beacon_node/libp2p/src/service.rs b/beacon_node/libp2p/src/service.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/beacon_node/network/Cargo.toml b/beacon_node/network/Cargo.toml index 57f75e2739..31fc9eab6c 100644 --- a/beacon_node/network/Cargo.toml +++ b/beacon_node/network/Cargo.toml @@ -5,6 +5,6 @@ authors = ["Age Manning "] edition = "2018" [dependencies] -# SigP repository until PR is merged -libp2p = { git = "https://github.com/SigP/rust-libp2p", branch = "gossipsub" } +libp2p = { git = "../libp2p" } version = { path = "../version" } +types = { path = "../../eth2/types" } diff --git a/beacon_node/network/src/error.rs b/beacon_node/network/src/error.rs new file mode 100644 index 0000000000..163fe575d2 --- /dev/null +++ b/beacon_node/network/src/error.rs @@ -0,0 +1,8 @@ +// generates error types + +use error_chain::{ + error_chain, error_chain_processing, impl_error_chain_kind, impl_error_chain_processed, + impl_extract_backtrace, +}; + +error_chain! {} diff --git a/beacon_node/network/src/lib.rs b/beacon_node/network/src/lib.rs index 1dc56ec4fb..3bc555dd66 100644 --- a/beacon_node/network/src/lib.rs +++ b/beacon_node/network/src/lib.rs @@ -1,4 +1,6 @@ /// This crate provides the network server for Lighthouse. -mod network_configuration; +mod network_config; +mod service; -pub use network_configuration::NetworkConfiguration; +pub use network_config::NetworkConfig; +pub use service::NetworkService; diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs new file mode 100644 index 0000000000..66a7b58159 --- /dev/null +++ b/beacon_node/network/src/message_handler.rs @@ -0,0 +1,18 @@ +use crate::node_message::NodeMessage; + +/// Handles messages received from the network and client and organises syncing. +pub struct MessageHandler { + sync: Syncer, + //TODO: Implement beacon chain + //chain: BeaconChain +} + +/// Types of messages the handler can receive. +pub enum HandlerMessage { + /// Peer has connected. + PeerConnected(PeerId), + /// Peer has disconnected, + PeerDisconnected(PeerId), + /// A Node message has been received. + Message(Peer, NodeMessage), +} diff --git a/beacon_node/network/src/messages.rs b/beacon_node/network/src/messages.rs new file mode 100644 index 0000000000..5f9a666e06 --- /dev/null +++ b/beacon_node/network/src/messages.rs @@ -0,0 +1,27 @@ +use types::{H256,Slot} + +/// Messages between nodes across the network. +pub enum NodeMessage { + + Status(Status), + BlockRequest, +} + +pub struct Status { + /// Current node version. + version: u8 + /// Genesis Hash. + genesis_hash: H256 + /// Best known slot number. + best_slot: Slot + /// Best known slot hash. + best_slot_hash: H256 +} + +/// Types of messages that the network service can receive. +pub enum NetworkMessage { + /// Send a message to libp2p service. + //TODO: Define typing for messages accross the wire + Send(Node, Message), +} + diff --git a/beacon_node/network/src/network_configuration.rs b/beacon_node/network/src/network_config.rs similarity index 75% rename from beacon_node/network/src/network_configuration.rs rename to beacon_node/network/src/network_config.rs index 64d763287b..98347e122b 100644 --- a/beacon_node/network/src/network_configuration.rs +++ b/beacon_node/network/src/network_config.rs @@ -4,10 +4,10 @@ use version; #[derive(Debug, Clone)] /// Network configuration for lighthouse. -pub struct NetworkConfiguration { +pub struct NetworkConfig { //TODO: stubbing networking initial params, change in the future /// IP address to listen on. - pub listen_address: Option, + pub listen_addresses: Option>, /// Listen port UDP/TCP. pub listen_port: Option, /// Gossipsub configuration parameters. @@ -16,14 +16,13 @@ pub struct NetworkConfiguration { pub boot_nodes: Vec, /// Client version pub client_version: String, - //TODO: more to be added } -impl Default for NetworkConfiguration { +impl Default for NetworkConfig { /// Generate a default network configuration. fn default() -> Self { - NetworkConfiguration { - listen_address: None, + NetworkConfig { + listen_addresses: None, listen_port: None, gs_config: GossipsubConfigBuilder::new().build(), boot_nodes: Vec::new(), @@ -32,8 +31,8 @@ impl Default for NetworkConfiguration { } } -impl NetworkConfiguration { +impl NetworkConfig { pub fn new() -> Self { - NetworkConfiguration::default() + NetworkConfig::default() } } diff --git a/beacon_node/network/src/service.rs b/beacon_node/network/src/service.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/beacon_node/src/run.rs b/beacon_node/src/run.rs index 3207ce43de..f2a703cbcf 100644 --- a/beacon_node/src/run.rs +++ b/beacon_node/src/run.rs @@ -37,6 +37,7 @@ pub fn run_beacon_node(config: ClientConfig, log: slog::Logger) -> error::Result runtime.block_on(ctrlc); + // perform global shutdown operations. info!(log, "Shutting down.."); exit_signal.fire(); drop(client); diff --git a/beacon_node/sync/Cargo.toml b/beacon_node/sync/Cargo.toml index 347506bf06..4997cd094b 100644 --- a/beacon_node/sync/Cargo.toml +++ b/beacon_node/sync/Cargo.toml @@ -5,4 +5,5 @@ authors = ["Age Manning "] edition = "2018" [dependencies] - +types = { path = "../../eth2/types" } +libp2p = { git = "../libp2p/" } diff --git a/beacon_node/sync/src/lib.rs b/beacon_node/sync/src/lib.rs index f520e9e094..a901344f51 100644 --- a/beacon_node/sync/src/lib.rs +++ b/beacon_node/sync/src/lib.rs @@ -1,68 +1,10 @@ -// /// Syncing for lighthouse. +/// Syncing for lighthouse. +/// +/// Stores the various syncing methods for the beacon chain. +mod simple_sync; -/* -// for initial testing and setup, to be replaced. -pub fn sync_server(config: Config) { - // Set up database - let db = match config.db_type { - _ => Arc::new(MemoryDB::open()), - //TODO: Box db - //DBType::Memory => Arc::new(Box::new(MemoryDB::open())), - //DBType::RocksDB => Arc::new(Box::new(DiskDB::open(&config.db_name, None))), - }; +pub use crate::SimpleSync; - // build block - let block_store = Arc::new(BeaconBlockStore::new(db.clone())); - let state_store = Arc::new(BeaconStateStore::new(db.clone())); - - // Slot clock - let genesis_time = 1_549_935_547; // 12th Feb 2018 (arbitrary value in the past). - let slot_clock = SystemTimeSlotClock::new(genesis_time, spec.slot_duration) - .expect("Unable to load SystemTimeSlotClock"); - // Choose the fork choice - let fork_choice = BitwiseLMDGhost::new(block_store.clone(), state_store.clone()); - - /* - * Generate some random data to start a chain with. - * - * This is will need to be replace for production usage. - */ -let latest_eth1_data = Eth1Data { -deposit_root: Hash256::zero(), -block_hash: Hash256::zero(), -}; -let keypairs: Vec = (0..10) -.collect::>() -.iter() -.map(|_| Keypair::random()) -.collect(); -let initial_validator_deposits = keypairs -.iter() -.map(|keypair| Deposit { -branch: vec![], // branch verification is not specified. -index: 0, // index verification is not specified. -deposit_data: DepositData { -amount: 32_000_000_000, // 32 ETH (in Gwei) -timestamp: genesis_time - 1, -deposit_input: DepositInput { -pubkey: keypair.pk.clone(), -withdrawal_credentials: Hash256::zero(), // Withdrawal not possible. -proof_of_possession: create_proof_of_possession(&keypair), -}, -}, -}) -.collect(); - -// Genesis chain -let _chain_result = BeaconChain::genesis( -state_store.clone(), -block_store.clone(), -slot_clock, -genesis_time, -latest_eth1_data, -initial_validator_deposits, -spec, -fork_choice, -); +pub enum SyncMethod { + SimpleSync, } -*/ diff --git a/beacon_node/sync/src/simple_syncer.rs b/beacon_node/sync/src/simple_syncer.rs new file mode 100644 index 0000000000..f1d0a52195 --- /dev/null +++ b/beacon_node/sync/src/simple_syncer.rs @@ -0,0 +1,22 @@ +use std::collections::HashMap; +use types::{Slot, H256}; + +/// Keeps track of syncing information for known connected peers. +pub struct PeerSyncInfo { + best_slot: Slot, + best_slot_hash: H256, +} + +/// The current syncing state. +pub enum SyncState { + Idle, + Downloading, + Stopped, +} + +/// Simple Syncing protocol. +pub struct SimpleSync { + genesis_hash: H256, + known_peers: HashMap, + state: SyncState, +} From b68adc1ae3edfb537e49e866dd9a31fc4f329e97 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Mon, 4 Mar 2019 18:31:01 +1100 Subject: [PATCH 04/62] Implement skeleton network/sync framework. --- beacon_node/client/src/client_config.rs | 2 +- beacon_node/client/src/error.rs | 8 +++- beacon_node/client/src/lib.rs | 13 +++--- beacon_node/client/src/notifier.rs | 4 +- beacon_node/libp2p/Cargo.toml | 3 ++ beacon_node/libp2p/src/lib.rs | 11 ++--- beacon_node/libp2p/src/service.rs | 11 +++++ beacon_node/network/Cargo.toml | 7 +++- beacon_node/network/src/lib.rs | 5 ++- beacon_node/network/src/message_handler.rs | 32 +++++++++++++-- beacon_node/network/src/messages.rs | 25 ++++++----- beacon_node/network/src/network_config.rs | 2 +- beacon_node/network/src/service.rs | 41 +++++++++++++++++++ beacon_node/sync/Cargo.toml | 2 +- beacon_node/sync/src/lib.rs | 3 +- .../src/{simple_syncer.rs => simple_sync.rs} | 17 ++++++-- 16 files changed, 147 insertions(+), 39 deletions(-) rename beacon_node/sync/src/{simple_syncer.rs => simple_sync.rs} (54%) diff --git a/beacon_node/client/src/client_config.rs b/beacon_node/client/src/client_config.rs index 8943e783d0..ef7443839f 100644 --- a/beacon_node/client/src/client_config.rs +++ b/beacon_node/client/src/client_config.rs @@ -56,7 +56,7 @@ impl ClientConfig { // TODO: Handle list of addresses if let Some(listen_address_str) = args.value_of("listen_address") { if let Ok(listen_address) = listen_address_str.parse::() { - config.net_conf.listen_address = Some(Vec::new(listen_address)); + config.net_conf.listen_addresses = Some(vec![listen_address]); } else { error!(log, "Invalid IP Address"; "Address" => listen_address_str); return Err("Invalid IP Address"); diff --git a/beacon_node/client/src/error.rs b/beacon_node/client/src/error.rs index 163fe575d2..618813826b 100644 --- a/beacon_node/client/src/error.rs +++ b/beacon_node/client/src/error.rs @@ -1,8 +1,14 @@ // generates error types +use network; use error_chain::{ error_chain, error_chain_processing, impl_error_chain_kind, impl_error_chain_processed, impl_extract_backtrace, }; -error_chain! {} +error_chain! { + links { + Network(network::error::Error, network::error::ErrorKind); + } + +} diff --git a/beacon_node/client/src/lib.rs b/beacon_node/client/src/lib.rs index 5ea6ba4a67..d0b096416e 100644 --- a/beacon_node/client/src/lib.rs +++ b/beacon_node/client/src/lib.rs @@ -11,9 +11,10 @@ pub use client_types::ClientTypes; //use beacon_chain::BeaconChain; use exit_future::{Exit, Signal}; +use network::Service as NetworkService; +use slog::o; use std::marker::PhantomData; -//use std::sync::Arc; -use network::NetworkService; +use std::sync::Arc; use tokio::runtime::TaskExecutor; /// Main beacon node client service. This provides the connection and initialisation of the clients @@ -39,11 +40,11 @@ impl Client { // TODO: generate a beacon_chain service. - // start the network service, libp2p and syncing threads + // Start the network service, libp2p and syncing threads // TODO: Add beacon_chain reference to network parameters - let network_config = config.net_config; - let network_logger = client.log.new(o!("Service" => "Network")); - let (network, network_send) = NetworkService::new(network_config, network_logger); + let network_config = config.net_conf.clone(); + let network_logger = log.new(o!("Service" => "Network")); + let (network, network_send) = NetworkService::new(network_config, network_logger)?; Ok(Client { config, diff --git a/beacon_node/client/src/notifier.rs b/beacon_node/client/src/notifier.rs index 68d93e7358..dd38701c93 100644 --- a/beacon_node/client/src/notifier.rs +++ b/beacon_node/client/src/notifier.rs @@ -4,7 +4,7 @@ use db::ClientDB; use exit_future::Exit; use fork_choice::ForkChoice; use futures::{Future, Stream}; -use slog::{debug, info}; +use slog::{debug, info, o}; use slot_clock::SlotClock; use std::sync::Arc; use std::time::{Duration, Instant}; @@ -26,7 +26,7 @@ pub fn run(client: &Client, executor: TaskExecutor, exit: Exi }; // map error and spawn - let log = client.logger(); + let log = client.log.clone(); let heartbeat_interval = interval .map_err(move |e| debug!(log, "Timer error {}", e)) .for_each(heartbeat); diff --git a/beacon_node/libp2p/Cargo.toml b/beacon_node/libp2p/Cargo.toml index f35ae4d430..69f76369f8 100644 --- a/beacon_node/libp2p/Cargo.toml +++ b/beacon_node/libp2p/Cargo.toml @@ -5,3 +5,6 @@ authors = ["Age Manning "] edition = "2018" [dependencies] +# SigP repository until PR is merged +libp2p = { git = "https://github.com/SigP/rust-libp2p", branch = "gossipsub" } +slog = "2.4.1" diff --git a/beacon_node/libp2p/src/lib.rs b/beacon_node/libp2p/src/lib.rs index e20eb055f8..6f07b760f2 100644 --- a/beacon_node/libp2p/src/lib.rs +++ b/beacon_node/libp2p/src/lib.rs @@ -2,10 +2,11 @@ /// all required libp2p functionality. /// /// This crate builds and manages the libp2p services required by the beacon node. -extern crate libp2p; +mod service; -mod libp2p_service; +pub use libp2p::{ + gossipsub::{GossipsubConfig, GossipsubConfigBuilder}, + PeerId, +}; -pub use libp2p::{GossipsubConfig, PeerId}; - -pub use libp2p_service::LibP2PService; +pub use service::Service; diff --git a/beacon_node/libp2p/src/service.rs b/beacon_node/libp2p/src/service.rs index e69de29bb2..118f0d5288 100644 --- a/beacon_node/libp2p/src/service.rs +++ b/beacon_node/libp2p/src/service.rs @@ -0,0 +1,11 @@ +use slog::debug; + +/// The configuration and state of the libp2p components for the beacon node. +pub struct Service {} + +impl Service { + pub fn new(log: slog::Logger) -> Self { + debug!(log, "Service starting"); + Service {} + } +} diff --git a/beacon_node/network/Cargo.toml b/beacon_node/network/Cargo.toml index 31fc9eab6c..f32ee1f906 100644 --- a/beacon_node/network/Cargo.toml +++ b/beacon_node/network/Cargo.toml @@ -5,6 +5,11 @@ authors = ["Age Manning "] edition = "2018" [dependencies] -libp2p = { git = "../libp2p" } +libp2p = { path = "../libp2p" } version = { path = "../version" } types = { path = "../../eth2/types" } +sync = { path = "../sync" } +slog = "2.4.1" +futures = "0.1.25" +error-chain = "0.12.0" +crossbeam-channel = "0.3.8" diff --git a/beacon_node/network/src/lib.rs b/beacon_node/network/src/lib.rs index 3bc555dd66..8ffb90b93f 100644 --- a/beacon_node/network/src/lib.rs +++ b/beacon_node/network/src/lib.rs @@ -1,6 +1,9 @@ /// This crate provides the network server for Lighthouse. +pub mod error; +mod message_handler; +mod messages; mod network_config; mod service; pub use network_config::NetworkConfig; -pub use service::NetworkService; +pub use service::Service; diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index 66a7b58159..87935e8996 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -1,8 +1,14 @@ -use crate::node_message::NodeMessage; +use crate::error; +use crate::messages::NodeMessage; +use crossbeam_channel::{unbounded as channel, Sender}; +use libp2p::PeerId; +use slog::debug; +use sync::SimpleSync; +use types::Hash256; /// Handles messages received from the network and client and organises syncing. pub struct MessageHandler { - sync: Syncer, + sync: SimpleSync, //TODO: Implement beacon chain //chain: BeaconChain } @@ -14,5 +20,25 @@ pub enum HandlerMessage { /// Peer has disconnected, PeerDisconnected(PeerId), /// A Node message has been received. - Message(Peer, NodeMessage), + Message(PeerId, NodeMessage), +} + +impl MessageHandler { + /// Initializes and runs the MessageHandler. + pub fn new(log: slog::Logger) -> error::Result> { + debug!(log, "Service starting"); + + let (handler_send, handler_recv) = channel(); + + // Initialise sync and begin processing in thread + //TODO: Load genesis from BeaconChain + let temp_genesis = Hash256::zero(); + let sync = SimpleSync::new(temp_genesis); + + let handler = MessageHandler { sync }; + + // spawn handler thread + + Ok(handler_send) + } } diff --git a/beacon_node/network/src/messages.rs b/beacon_node/network/src/messages.rs index 5f9a666e06..05b899269b 100644 --- a/beacon_node/network/src/messages.rs +++ b/beacon_node/network/src/messages.rs @@ -1,27 +1,26 @@ -use types::{H256,Slot} +use libp2p::PeerId; +use types::{Hash256, Slot}; /// Messages between nodes across the network. pub enum NodeMessage { - Status(Status), BlockRequest, } pub struct Status { - /// Current node version. - version: u8 - /// Genesis Hash. - genesis_hash: H256 - /// Best known slot number. - best_slot: Slot - /// Best known slot hash. - best_slot_hash: H256 + /// Current node version. + version: u8, + /// Genesis Hash. + genesis_hash: Hash256, + /// Best known slot number. + best_slot: Slot, + /// Best known slot hash. + best_slot_hash: Hash256, } /// Types of messages that the network service can receive. pub enum NetworkMessage { /// Send a message to libp2p service. - //TODO: Define typing for messages accross the wire - Send(Node, Message), + //TODO: Define typing for messages across the wire + Send(PeerId, NodeMessage), } - diff --git a/beacon_node/network/src/network_config.rs b/beacon_node/network/src/network_config.rs index 98347e122b..5c513fcc6d 100644 --- a/beacon_node/network/src/network_config.rs +++ b/beacon_node/network/src/network_config.rs @@ -1,4 +1,4 @@ -use libp2p::gossipsub::{GossipsubConfig, GossipsubConfigBuilder}; +use libp2p::{GossipsubConfig, GossipsubConfigBuilder}; use std::net::IpAddr; use version; diff --git a/beacon_node/network/src/service.rs b/beacon_node/network/src/service.rs index e69de29bb2..9170628acb 100644 --- a/beacon_node/network/src/service.rs +++ b/beacon_node/network/src/service.rs @@ -0,0 +1,41 @@ +use crate::error; +use crate::message_handler::{HandlerMessage, MessageHandler}; +use crate::messages::{NetworkMessage, NodeMessage}; +use crate::NetworkConfig; +use crossbeam_channel::{unbounded as channel, Sender}; +use futures::sync::oneshot; +use libp2p::Service as LibP2PService; +use slog::{debug, info, o, trace, warn, Logger}; +use std::sync::{Arc, Mutex}; + +/// Service that handles communication between internal services and the libp2p network service. +pub struct Service { + //libp2p_service: Arc>, +//libp2p_thread: oneshot::Sender<()>, +//message_handler: MessageHandler, +//message_handler_send: Sender, +} + +impl Service { + pub fn new( + config: NetworkConfig, + log: slog::Logger, + ) -> error::Result<(Arc, Sender)> { + debug!(log, "Service starting"); + let (network_send, network_recv) = channel::(); + + // launch message handler thread + let message_handler_log = log.new(o!("Service" => "MessageHandler")); + let message_handler_send = MessageHandler::new(message_handler_log); + + // launch libp2p service + let libp2p_log = log.new(o!("Service" => "Libp2p")); + let libp2p_service = LibP2PService::new(libp2p_log); + + // TODO: Spawn thread to handle libp2p messages and pass to message handler thread. + + let network = Service {}; + + Ok((Arc::new(network), network_send)) + } +} diff --git a/beacon_node/sync/Cargo.toml b/beacon_node/sync/Cargo.toml index 4997cd094b..a4ebe3eede 100644 --- a/beacon_node/sync/Cargo.toml +++ b/beacon_node/sync/Cargo.toml @@ -6,4 +6,4 @@ edition = "2018" [dependencies] types = { path = "../../eth2/types" } -libp2p = { git = "../libp2p/" } +libp2p = { path = "../libp2p" } diff --git a/beacon_node/sync/src/lib.rs b/beacon_node/sync/src/lib.rs index a901344f51..8f5216b857 100644 --- a/beacon_node/sync/src/lib.rs +++ b/beacon_node/sync/src/lib.rs @@ -3,8 +3,9 @@ /// Stores the various syncing methods for the beacon chain. mod simple_sync; -pub use crate::SimpleSync; +pub use simple_sync::SimpleSync; +/// Currently implemented sync methods. pub enum SyncMethod { SimpleSync, } diff --git a/beacon_node/sync/src/simple_syncer.rs b/beacon_node/sync/src/simple_sync.rs similarity index 54% rename from beacon_node/sync/src/simple_syncer.rs rename to beacon_node/sync/src/simple_sync.rs index f1d0a52195..01a6a1adf4 100644 --- a/beacon_node/sync/src/simple_syncer.rs +++ b/beacon_node/sync/src/simple_sync.rs @@ -1,10 +1,11 @@ +use libp2p::PeerId; use std::collections::HashMap; -use types::{Slot, H256}; +use types::{Hash256, Slot}; /// Keeps track of syncing information for known connected peers. pub struct PeerSyncInfo { best_slot: Slot, - best_slot_hash: H256, + best_slot_hash: Hash256, } /// The current syncing state. @@ -16,7 +17,17 @@ pub enum SyncState { /// Simple Syncing protocol. pub struct SimpleSync { - genesis_hash: H256, + genesis_hash: Hash256, known_peers: HashMap, state: SyncState, } + +impl SimpleSync { + pub fn new(genesis_hash: Hash256) -> Self { + SimpleSync { + genesis_hash, + known_peers: HashMap::new(), + state: SyncState::Idle, + } + } +} From ac639c64274188eb9e2065af33d423cd69b47908 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 6 Mar 2019 23:31:08 +1100 Subject: [PATCH 05/62] Add libp2p transport - tcp/ws/secio and multiplexing. --- beacon_node/client/src/client_config.rs | 4 +- beacon_node/libp2p/Cargo.toml | 1 + beacon_node/libp2p/src/lib.rs | 3 +- beacon_node/libp2p/src/network_config.rs | 58 +++++++++++++++++++++++ beacon_node/libp2p/src/service.rs | 47 ++++++++++++++++-- beacon_node/network/src/lib.rs | 3 +- beacon_node/network/src/network_config.rs | 38 --------------- beacon_node/network/src/service.rs | 3 +- 8 files changed, 108 insertions(+), 49 deletions(-) create mode 100644 beacon_node/libp2p/src/network_config.rs delete mode 100644 beacon_node/network/src/network_config.rs diff --git a/beacon_node/client/src/client_config.rs b/beacon_node/client/src/client_config.rs index ef7443839f..3f5fbab2fd 100644 --- a/beacon_node/client/src/client_config.rs +++ b/beacon_node/client/src/client_config.rs @@ -56,7 +56,7 @@ impl ClientConfig { // TODO: Handle list of addresses if let Some(listen_address_str) = args.value_of("listen_address") { if let Ok(listen_address) = listen_address_str.parse::() { - config.net_conf.listen_addresses = Some(vec![listen_address]); + config.net_conf.listen_addresses = vec![listen_address]; } else { error!(log, "Invalid IP Address"; "Address" => listen_address_str); return Err("Invalid IP Address"); @@ -65,7 +65,7 @@ impl ClientConfig { // Custom p2p listen port if let Some(port_str) = args.value_of("port") { if let Ok(port) = port_str.parse::() { - config.net_conf.listen_port = Some(port); + config.net_conf.listen_port = port; } else { error!(log, "Invalid port"; "port" => port_str); return Err("Invalid port"); diff --git a/beacon_node/libp2p/Cargo.toml b/beacon_node/libp2p/Cargo.toml index 69f76369f8..b32eed1a63 100644 --- a/beacon_node/libp2p/Cargo.toml +++ b/beacon_node/libp2p/Cargo.toml @@ -8,3 +8,4 @@ edition = "2018" # SigP repository until PR is merged libp2p = { git = "https://github.com/SigP/rust-libp2p", branch = "gossipsub" } slog = "2.4.1" +version = { path = "../version" } diff --git a/beacon_node/libp2p/src/lib.rs b/beacon_node/libp2p/src/lib.rs index 6f07b760f2..7b45143371 100644 --- a/beacon_node/libp2p/src/lib.rs +++ b/beacon_node/libp2p/src/lib.rs @@ -2,11 +2,12 @@ /// all required libp2p functionality. /// /// This crate builds and manages the libp2p services required by the beacon node. +mod network_config; mod service; pub use libp2p::{ gossipsub::{GossipsubConfig, GossipsubConfigBuilder}, PeerId, }; - +pub use network_config::NetworkConfig; pub use service::Service; diff --git a/beacon_node/libp2p/src/network_config.rs b/beacon_node/libp2p/src/network_config.rs new file mode 100644 index 0000000000..7cb1cf6bb1 --- /dev/null +++ b/beacon_node/libp2p/src/network_config.rs @@ -0,0 +1,58 @@ +use libp2p::gossipsub::{GossipsubConfig, GossipsubConfigBuilder}; +use libp2p::secio; +use std::fmt; +use std::net::IpAddr; + +#[derive(Clone)] +/// Network configuration for lighthouse. +pub struct NetworkConfig { + //TODO: stubbing networking initial params, change in the future + /// IP address to listen on. + pub listen_addresses: Vec, + /// Listen port UDP/TCP. + pub listen_port: u16, + /// Gossipsub configuration parameters. + pub gs_config: GossipsubConfig, + /// List of nodes to initially connect to. + pub boot_nodes: Vec, + /// Peer key related to this nodes PeerId. + pub local_private_key: secio::SecioKeyPair, + /// Client version + pub client_version: String, +} + +impl Default for NetworkConfig { + /// Generate a default network configuration. + fn default() -> Self { + // hard-coded defaults + let bootnodes = ["127.0.0.1"]; + let default_port = 9000; + + // TODO: Currently using ed25519 key pairs. Wire protocol specifies RSA. Waiting for this + // PR to be merged to generate RSA keys: https://github.com/briansmith/ring/pull/733 + + NetworkConfig { + listen_addresses: vec!["127.0.0.1".parse().expect("correct IP address")], + listen_port: default_port, + gs_config: GossipsubConfigBuilder::new().build(), + boot_nodes: bootnodes + .iter() + .map(|s| s.parse().expect("Bootnodes must be IP addresses")) + .collect(), + local_private_key: secio::SecioKeyPair::ed25519_generated().unwrap(), + client_version: version::version(), + } + } +} + +impl NetworkConfig { + pub fn new() -> Self { + NetworkConfig::default() + } +} + +impl fmt::Debug for NetworkConfig { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "NetworkConfig: listen_addresses: {:?}, listen_port: {:?}, gs_config: {:?}, boot_nodes: {:?}, local_private_key: , client_version: {:?}", self.listen_addresses, self.listen_port, self.gs_config, self.boot_nodes, self.local_private_key.to_public_key(), self.client_version) + } +} diff --git a/beacon_node/libp2p/src/service.rs b/beacon_node/libp2p/src/service.rs index 118f0d5288..53c566187a 100644 --- a/beacon_node/libp2p/src/service.rs +++ b/beacon_node/libp2p/src/service.rs @@ -1,11 +1,50 @@ +use crate::NetworkConfig; +use libp2p::gossipsub::GossipsubEvent; +use libp2p::PeerId; +use libp2p::{build_tcp_ws_secio_mplex_yamux, core, secio, Transport}; use slog::debug; +use std::error; /// The configuration and state of the libp2p components for the beacon node. -pub struct Service {} +pub struct Service { + /// This node's PeerId. + peer_id: PeerId, +} impl Service { - pub fn new(log: slog::Logger) -> Self { - debug!(log, "Service starting"); - Service {} + pub fn new(config: NetworkConfig, log: slog::Logger) -> Self { + debug!(log, "Libp2p Service starting"); + + let local_private_key = config.local_private_key; + let peer_id = local_private_key.to_peer_id(); + debug!(log, "Local peer id: {:?}", peer_id); + + // Set up the transport + let transport = build_transport(local_private_key); + + //let transport = libp2p:: + + Service { peer_id } } } + +/// The implementation supports TCP/IP, WebSockets over TCP/IP, secio as the encryption layer, and +/// mplex or yamux as the multiplexing layer. +fn build_transport( + local_private_key: secio::SecioKeyPair, +) -> impl Transport< + Output = ( + PeerId, + impl core::muxing::StreamMuxer + + Send + + Sync, + ), + Error = impl error::Error + Send, + Listener = impl Send, + Dial = impl Send, + ListenerUpgrade = impl Send, +> + Clone { + // TODO: The Wire protocol currently doesn't specify encryption and this will need to be customised + // in the future. + build_tcp_ws_secio_mplex_yamux(local_private_key) +} diff --git a/beacon_node/network/src/lib.rs b/beacon_node/network/src/lib.rs index 8ffb90b93f..ae03d83678 100644 --- a/beacon_node/network/src/lib.rs +++ b/beacon_node/network/src/lib.rs @@ -2,8 +2,7 @@ pub mod error; mod message_handler; mod messages; -mod network_config; mod service; -pub use network_config::NetworkConfig; +pub use libp2p::NetworkConfig; pub use service::Service; diff --git a/beacon_node/network/src/network_config.rs b/beacon_node/network/src/network_config.rs deleted file mode 100644 index 5c513fcc6d..0000000000 --- a/beacon_node/network/src/network_config.rs +++ /dev/null @@ -1,38 +0,0 @@ -use libp2p::{GossipsubConfig, GossipsubConfigBuilder}; -use std::net::IpAddr; -use version; - -#[derive(Debug, Clone)] -/// Network configuration for lighthouse. -pub struct NetworkConfig { - //TODO: stubbing networking initial params, change in the future - /// IP address to listen on. - pub listen_addresses: Option>, - /// Listen port UDP/TCP. - pub listen_port: Option, - /// Gossipsub configuration parameters. - pub gs_config: GossipsubConfig, - /// List of nodes to initially connect to. - pub boot_nodes: Vec, - /// Client version - pub client_version: String, -} - -impl Default for NetworkConfig { - /// Generate a default network configuration. - fn default() -> Self { - NetworkConfig { - listen_addresses: None, - listen_port: None, - gs_config: GossipsubConfigBuilder::new().build(), - boot_nodes: Vec::new(), - client_version: version::version(), - } - } -} - -impl NetworkConfig { - pub fn new() -> Self { - NetworkConfig::default() - } -} diff --git a/beacon_node/network/src/service.rs b/beacon_node/network/src/service.rs index 9170628acb..ac8d9b442d 100644 --- a/beacon_node/network/src/service.rs +++ b/beacon_node/network/src/service.rs @@ -30,10 +30,9 @@ impl Service { // launch libp2p service let libp2p_log = log.new(o!("Service" => "Libp2p")); - let libp2p_service = LibP2PService::new(libp2p_log); + let libp2p_service = LibP2PService::new(config, libp2p_log); // TODO: Spawn thread to handle libp2p messages and pass to message handler thread. - let network = Service {}; Ok((Arc::new(network), network_send)) From e8e4c4ab9baaa1334c662bc9ef2a5a3b04e65095 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Thu, 7 Mar 2019 11:43:55 +1100 Subject: [PATCH 06/62] Adds basic structure for swarm behaviour and topology. --- beacon_node/libp2p/Cargo.toml | 1 + beacon_node/libp2p/src/service.rs | 33 ++++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/beacon_node/libp2p/Cargo.toml b/beacon_node/libp2p/Cargo.toml index b32eed1a63..fff7dc82d2 100644 --- a/beacon_node/libp2p/Cargo.toml +++ b/beacon_node/libp2p/Cargo.toml @@ -9,3 +9,4 @@ edition = "2018" libp2p = { git = "https://github.com/SigP/rust-libp2p", branch = "gossipsub" } slog = "2.4.1" version = { path = "../version" } +tokio = "0.1.16" diff --git a/beacon_node/libp2p/src/service.rs b/beacon_node/libp2p/src/service.rs index 53c566187a..528d24ce88 100644 --- a/beacon_node/libp2p/src/service.rs +++ b/beacon_node/libp2p/src/service.rs @@ -1,14 +1,17 @@ use crate::NetworkConfig; -use libp2p::gossipsub::GossipsubEvent; -use libp2p::PeerId; +use libp2p::core::{muxing::StreamMuxer, nodes::Substream}; +use libp2p::gossipsub::{Gossipsub, GossipsubConfig, GossipsubEvent}; use libp2p::{build_tcp_ws_secio_mplex_yamux, core, secio, Transport}; +use libp2p::{core::swarm::NetworkBehaviour, PeerId, Swarm}; use slog::debug; use std::error; /// The configuration and state of the libp2p components for the beacon node. pub struct Service { + /// The libp2p Swarm handler. + swarm: String, /// This node's PeerId. - peer_id: PeerId, + local_peer_id: PeerId, } impl Service { @@ -16,15 +19,22 @@ impl Service { debug!(log, "Libp2p Service starting"); let local_private_key = config.local_private_key; - let peer_id = local_private_key.to_peer_id(); - debug!(log, "Local peer id: {:?}", peer_id); + let local_peer_id = local_private_key.to_peer_id(); + debug!(log, "Local peer id: {:?}", local_peer_id); // Set up the transport let transport = build_transport(local_private_key); + // Set up gossipsub routing + let behaviour = build_behaviour(local_peer_id, config.gs_config); + // Set up Topology + let topology = local_peer_id; - //let transport = libp2p:: + let swarm = Swarm::new(transport, behaviour, topology); - Service { peer_id } + Service { + local_peer_id, + swarm, + } } } @@ -48,3 +58,12 @@ fn build_transport( // in the future. build_tcp_ws_secio_mplex_yamux(local_private_key) } + +/// Builds the network behaviour for the libp2p Swarm. +fn build_behaviour( + local_peer_id: PeerId, + config: GossipsubConfig, +) -> impl NetworkBehaviour { + // TODO: Add Kademlia/Peer discovery + Gossipsub::new(local_peer_id, config) +} From 9f13731d6d02feb3045a27471ae8061e0c5a77cc Mon Sep 17 00:00:00 2001 From: Age Manning Date: Thu, 7 Mar 2019 16:17:06 +1100 Subject: [PATCH 07/62] Implements a basic libp2p tcp,secio,mplex,gossipsub swarm. --- beacon_node/libp2p/Cargo.toml | 1 + beacon_node/libp2p/src/behaviour.rs | 46 +++++++++++++++++++ beacon_node/libp2p/src/lib.rs | 1 + beacon_node/libp2p/src/service.rs | 70 ++++++++++++++++++----------- 4 files changed, 91 insertions(+), 27 deletions(-) create mode 100644 beacon_node/libp2p/src/behaviour.rs diff --git a/beacon_node/libp2p/Cargo.toml b/beacon_node/libp2p/Cargo.toml index fff7dc82d2..9c4c6e7a52 100644 --- a/beacon_node/libp2p/Cargo.toml +++ b/beacon_node/libp2p/Cargo.toml @@ -10,3 +10,4 @@ libp2p = { git = "https://github.com/SigP/rust-libp2p", branch = "gossipsub" } slog = "2.4.1" version = { path = "../version" } tokio = "0.1.16" +futures = "0.1.25" diff --git a/beacon_node/libp2p/src/behaviour.rs b/beacon_node/libp2p/src/behaviour.rs new file mode 100644 index 0000000000..0c9aae16eb --- /dev/null +++ b/beacon_node/libp2p/src/behaviour.rs @@ -0,0 +1,46 @@ +use futures::prelude::*; +use libp2p::{ + core::swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess}, + gossipsub::{Gossipsub, GossipsubConfig, GossipsubEvent, GossipsubRpc}, + tokio_io::{AsyncRead, AsyncWrite}, + NetworkBehaviour, PeerId, +}; + +/// Builds the network behaviour for the libp2p Swarm. +/// Implements gossipsub message routing. +#[derive(NetworkBehaviour)] +pub struct Behaviour { + gossipsub: Gossipsub, + // TODO: Add Kademlia for peer discovery + /// The events generated by this behaviour to be consumed in the swarm poll. + // We use gossipsub events for now, generalise later. + #[behaviour(ignore)] + events: Vec, +} + +// Implement the NetworkBehaviourEventProcess trait so that we can derive NetworkBehaviour for Behaviour +impl NetworkBehaviourEventProcess + for Behaviour +{ + fn inject_event(&mut self, event: GossipsubEvent) { + self.events.push(event); + } +} + +impl Behaviour { + pub fn new(local_peer_id: PeerId, gs_config: GossipsubConfig) -> Self { + Behaviour { + gossipsub: Gossipsub::new(local_peer_id, gs_config), + events: Vec::new(), + } + } + + /// Consume the events list when polled. + fn poll(&mut self) -> Async> { + if !self.events.is_empty() { + return Async::Ready(NetworkBehaviourAction::GenerateEvent(self.events.remove(0))); + } + + Async::NotReady + } +} diff --git a/beacon_node/libp2p/src/lib.rs b/beacon_node/libp2p/src/lib.rs index 7b45143371..01dc420730 100644 --- a/beacon_node/libp2p/src/lib.rs +++ b/beacon_node/libp2p/src/lib.rs @@ -2,6 +2,7 @@ /// all required libp2p functionality. /// /// This crate builds and manages the libp2p services required by the beacon node. +mod behaviour; mod network_config; mod service; diff --git a/beacon_node/libp2p/src/service.rs b/beacon_node/libp2p/src/service.rs index 528d24ce88..7ed715bd68 100644 --- a/beacon_node/libp2p/src/service.rs +++ b/beacon_node/libp2p/src/service.rs @@ -1,18 +1,29 @@ +use crate::behaviour::Behaviour; use crate::NetworkConfig; -use libp2p::core::{muxing::StreamMuxer, nodes::Substream}; -use libp2p::gossipsub::{Gossipsub, GossipsubConfig, GossipsubEvent}; +use futures::prelude::*; +use libp2p::core::{ + muxing::StreamMuxerBox, + nodes::Substream, + transport::boxed::Boxed, + upgrade::{InboundUpgrade, InboundUpgradeExt, OutboundUpgrade, OutboundUpgradeExt}, +}; use libp2p::{build_tcp_ws_secio_mplex_yamux, core, secio, Transport}; -use libp2p::{core::swarm::NetworkBehaviour, PeerId, Swarm}; +use libp2p::{PeerId, Swarm}; use slog::debug; use std::error; +use std::io::{Error, ErrorKind}; +use std::time::Duration; /// The configuration and state of the libp2p components for the beacon node. pub struct Service { /// The libp2p Swarm handler. - swarm: String, + swarm: Swarm, Behaviour>>, /// This node's PeerId. local_peer_id: PeerId, } +//Swarm>>> + +//swarm: Swarm, Behaviour>>, impl Service { pub fn new(config: NetworkConfig, log: slog::Logger) -> Self { @@ -25,9 +36,9 @@ impl Service { // Set up the transport let transport = build_transport(local_private_key); // Set up gossipsub routing - let behaviour = build_behaviour(local_peer_id, config.gs_config); + let behaviour = Behaviour::new(local_peer_id.clone(), config.gs_config); // Set up Topology - let topology = local_peer_id; + let topology = local_peer_id.clone(); let swarm = Swarm::new(transport, behaviour, topology); @@ -42,28 +53,33 @@ impl Service { /// mplex or yamux as the multiplexing layer. fn build_transport( local_private_key: secio::SecioKeyPair, -) -> impl Transport< - Output = ( - PeerId, - impl core::muxing::StreamMuxer - + Send - + Sync, - ), - Error = impl error::Error + Send, - Listener = impl Send, - Dial = impl Send, - ListenerUpgrade = impl Send, -> + Clone { +) -> Boxed<(PeerId, StreamMuxerBox), Error> { // TODO: The Wire protocol currently doesn't specify encryption and this will need to be customised // in the future. - build_tcp_ws_secio_mplex_yamux(local_private_key) -} + let transport = libp2p::tcp::TcpConfig::new(); + let transport = libp2p::dns::DnsConfig::new(transport); + #[cfg(feature = "libp2p-websocket")] + let transport = { + let trans_clone = transport.clone(); + transport.or_transport(websocket::WsConfig::new(trans_clone)) + }; + transport + .with_upgrade(secio::SecioConfig::new(local_private_key)) + .and_then(move |out, endpoint| { + let peer_id = out.remote_key.into_peer_id(); + let peer_id2 = peer_id.clone(); + let upgrade = core::upgrade::SelectUpgrade::new( + libp2p::yamux::Config::default(), + libp2p::mplex::MplexConfig::new(), + ) + // TODO: use a single `.map` instead of two maps + .map_inbound(move |muxer| (peer_id, muxer)) + .map_outbound(move |muxer| (peer_id2, muxer)); -/// Builds the network behaviour for the libp2p Swarm. -fn build_behaviour( - local_peer_id: PeerId, - config: GossipsubConfig, -) -> impl NetworkBehaviour { - // TODO: Add Kademlia/Peer discovery - Gossipsub::new(local_peer_id, config) + core::upgrade::apply(out.stream, upgrade, endpoint) + .map(|(id, muxer)| (id, core::muxing::StreamMuxerBox::new(muxer))) + }) + .with_timeout(Duration::from_secs(20)) + .map_err(|err| Error::new(ErrorKind::Other, err)) + .boxed() } From 3c517694282614dc46e510380c79d2e57164eab4 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Fri, 8 Mar 2019 11:07:30 +1100 Subject: [PATCH 08/62] Node listens on default port and connects to bootnodes. --- beacon_node/client/Cargo.toml | 1 + beacon_node/client/src/client_config.rs | 25 +++++++----- beacon_node/libp2p/Cargo.toml | 1 + beacon_node/libp2p/src/lib.rs | 2 + beacon_node/libp2p/src/network_config.rs | 22 ++++------- beacon_node/libp2p/src/service.rs | 48 +++++++++++++++++------- 6 files changed, 61 insertions(+), 38 deletions(-) diff --git a/beacon_node/client/Cargo.toml b/beacon_node/client/Cargo.toml index 04f80e76bc..46394ac912 100644 --- a/beacon_node/client/Cargo.toml +++ b/beacon_node/client/Cargo.toml @@ -7,6 +7,7 @@ edition = "2018" [dependencies] beacon_chain = { path = "../beacon_chain" } network = { path = "../network" } +libp2p = { path = "../libp2p" } sync = { path = "../sync" } db = { path = "../db" } fork_choice = { path = "../../eth2/fork_choice" } diff --git a/beacon_node/client/src/client_config.rs b/beacon_node/client/src/client_config.rs index 3f5fbab2fd..18b39277a3 100644 --- a/beacon_node/client/src/client_config.rs +++ b/beacon_node/client/src/client_config.rs @@ -1,10 +1,12 @@ use clap::ArgMatches; use db::DBType; use fork_choice::ForkChoiceAlgorithm; +use libp2p::multiaddr::ToMultiaddr; use network::NetworkConfig; use slog::error; use std::fs; use std::net::IpAddr; +use std::net::SocketAddr; use std::path::PathBuf; use types::ChainSpec; @@ -52,16 +54,6 @@ impl ClientConfig { // Network related args - // Custom listening address ipv4/ipv6 - // TODO: Handle list of addresses - if let Some(listen_address_str) = args.value_of("listen_address") { - if let Ok(listen_address) = listen_address_str.parse::() { - config.net_conf.listen_addresses = vec![listen_address]; - } else { - error!(log, "Invalid IP Address"; "Address" => listen_address_str); - return Err("Invalid IP Address"); - } - } // Custom p2p listen port if let Some(port_str) = args.value_of("port") { if let Ok(port) = port_str.parse::() { @@ -71,6 +63,19 @@ impl ClientConfig { return Err("Invalid port"); } } + // Custom listening address ipv4/ipv6 + // TODO: Handle list of addresses + if let Some(listen_address_str) = args.value_of("listen_address") { + if let Ok(listen_address) = listen_address_str.parse::() { + let multiaddr = SocketAddr::new(listen_address, config.net_conf.listen_port) + .to_multiaddr() + .expect("Invalid listen address format"); + config.net_conf.listen_addresses = vec![multiaddr]; + } else { + error!(log, "Invalid IP Address"; "Address" => listen_address_str); + return Err("Invalid IP Address"); + } + } // filesystem args diff --git a/beacon_node/libp2p/Cargo.toml b/beacon_node/libp2p/Cargo.toml index 9c4c6e7a52..d78ddd882f 100644 --- a/beacon_node/libp2p/Cargo.toml +++ b/beacon_node/libp2p/Cargo.toml @@ -11,3 +11,4 @@ slog = "2.4.1" version = { path = "../version" } tokio = "0.1.16" futures = "0.1.25" +parity-multiaddr = "0.2.0" diff --git a/beacon_node/libp2p/src/lib.rs b/beacon_node/libp2p/src/lib.rs index 01dc420730..1a24165bac 100644 --- a/beacon_node/libp2p/src/lib.rs +++ b/beacon_node/libp2p/src/lib.rs @@ -6,6 +6,8 @@ mod behaviour; mod network_config; mod service; +pub use libp2p::multiaddr; +pub use libp2p::Multiaddr; pub use libp2p::{ gossipsub::{GossipsubConfig, GossipsubConfigBuilder}, PeerId, diff --git a/beacon_node/libp2p/src/network_config.rs b/beacon_node/libp2p/src/network_config.rs index 7cb1cf6bb1..8eeb338612 100644 --- a/beacon_node/libp2p/src/network_config.rs +++ b/beacon_node/libp2p/src/network_config.rs @@ -1,20 +1,20 @@ use libp2p::gossipsub::{GossipsubConfig, GossipsubConfigBuilder}; use libp2p::secio; +use libp2p::Multiaddr; use std::fmt; -use std::net::IpAddr; #[derive(Clone)] /// Network configuration for lighthouse. pub struct NetworkConfig { //TODO: stubbing networking initial params, change in the future /// IP address to listen on. - pub listen_addresses: Vec, + pub listen_addresses: Vec, /// Listen port UDP/TCP. pub listen_port: u16, /// Gossipsub configuration parameters. pub gs_config: GossipsubConfig, /// List of nodes to initially connect to. - pub boot_nodes: Vec, + pub boot_nodes: Vec, /// Peer key related to this nodes PeerId. pub local_private_key: secio::SecioKeyPair, /// Client version @@ -24,21 +24,15 @@ pub struct NetworkConfig { impl Default for NetworkConfig { /// Generate a default network configuration. fn default() -> Self { - // hard-coded defaults - let bootnodes = ["127.0.0.1"]; - let default_port = 9000; - // TODO: Currently using ed25519 key pairs. Wire protocol specifies RSA. Waiting for this // PR to be merged to generate RSA keys: https://github.com/briansmith/ring/pull/733 - NetworkConfig { - listen_addresses: vec!["127.0.0.1".parse().expect("correct IP address")], - listen_port: default_port, + listen_addresses: vec!["/ip4/127.0.0.1/tcp/9000" + .parse() + .expect("is a correct multi-address")], + listen_port: 9000, gs_config: GossipsubConfigBuilder::new().build(), - boot_nodes: bootnodes - .iter() - .map(|s| s.parse().expect("Bootnodes must be IP addresses")) - .collect(), + boot_nodes: Vec::new(), local_private_key: secio::SecioKeyPair::ed25519_generated().unwrap(), client_version: version::version(), } diff --git a/beacon_node/libp2p/src/service.rs b/beacon_node/libp2p/src/service.rs index 7ed715bd68..8e16707011 100644 --- a/beacon_node/libp2p/src/service.rs +++ b/beacon_node/libp2p/src/service.rs @@ -5,12 +5,12 @@ use libp2p::core::{ muxing::StreamMuxerBox, nodes::Substream, transport::boxed::Boxed, - upgrade::{InboundUpgrade, InboundUpgradeExt, OutboundUpgrade, OutboundUpgradeExt}, + upgrade::{InboundUpgradeExt, OutboundUpgradeExt}, }; -use libp2p::{build_tcp_ws_secio_mplex_yamux, core, secio, Transport}; +use libp2p::multiaddr::Protocol; +use libp2p::{core, secio, Transport}; use libp2p::{PeerId, Swarm}; -use slog::debug; -use std::error; +use slog::{debug, info, warn}; use std::io::{Error, ErrorKind}; use std::time::Duration; @@ -21,9 +21,6 @@ pub struct Service { /// This node's PeerId. local_peer_id: PeerId, } -//Swarm>>> - -//swarm: Swarm, Behaviour>>, impl Service { pub fn new(config: NetworkConfig, log: slog::Logger) -> Self { @@ -33,14 +30,37 @@ impl Service { let local_peer_id = local_private_key.to_peer_id(); debug!(log, "Local peer id: {:?}", local_peer_id); - // Set up the transport - let transport = build_transport(local_private_key); - // Set up gossipsub routing - let behaviour = Behaviour::new(local_peer_id.clone(), config.gs_config); - // Set up Topology - let topology = local_peer_id.clone(); + let mut swarm = { + // Set up the transport + let transport = build_transport(local_private_key); + // Set up gossipsub routing + let behaviour = Behaviour::new(local_peer_id.clone(), config.gs_config); + // Set up Topology + let topology = local_peer_id.clone(); + Swarm::new(transport, behaviour, topology) + }; - let swarm = Swarm::new(transport, behaviour, topology); + // listen on all addresses + for address in &config.listen_addresses { + match Swarm::listen_on(&mut swarm, address.clone()) { + Ok(mut listen_addr) => { + listen_addr.append(Protocol::P2p(local_peer_id.clone().into())); + info!(log, "Listening on: {}", listen_addr); + } + Err(err) => warn!(log, "Cannot listen on: {} : {:?}", address, err), + }; + } + // connect to boot nodes - these are currently stored as multiadders + // Once we have discovery, can set to peerId + for bootnode in config.boot_nodes { + match Swarm::dial_addr(&mut swarm, bootnode.clone()) { + Ok(()) => debug!(log, "Dialing bootnode: {}", bootnode), + Err(err) => debug!( + log, + "Could not connect to bootnode: {} error: {:?}", bootnode, err + ), + }; + } Service { local_peer_id, From 21032334ac272afb4b34d89cb35d0d077bd0c5e9 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Fri, 8 Mar 2019 12:15:57 +1100 Subject: [PATCH 09/62] Adds bootnodes to chainspec. Handles type correctly --- beacon_node/client/Cargo.toml | 2 -- beacon_node/client/src/client_config.rs | 10 +++++--- beacon_node/libp2p/Cargo.toml | 2 +- beacon_node/libp2p/src/lib.rs | 4 ++-- beacon_node/libp2p/src/network_config.rs | 9 ++++--- beacon_node/libp2p/src/service.rs | 2 +- eth2/types/Cargo.toml | 1 + eth2/types/src/chain_spec.rs | 30 +++++++++++++++++++++++- eth2/types/src/lib.rs | 2 ++ 9 files changed, 49 insertions(+), 13 deletions(-) diff --git a/beacon_node/client/Cargo.toml b/beacon_node/client/Cargo.toml index 46394ac912..8914a9e7e2 100644 --- a/beacon_node/client/Cargo.toml +++ b/beacon_node/client/Cargo.toml @@ -7,13 +7,11 @@ edition = "2018" [dependencies] beacon_chain = { path = "../beacon_chain" } network = { path = "../network" } -libp2p = { path = "../libp2p" } sync = { path = "../sync" } db = { path = "../db" } fork_choice = { path = "../../eth2/fork_choice" } types = { path = "../../eth2/types" } slot_clock = { path = "../../eth2/utils/slot_clock" } - error-chain = "0.12.0" slog = "^2.2.3" tokio = "0.1.15" diff --git a/beacon_node/client/src/client_config.rs b/beacon_node/client/src/client_config.rs index 18b39277a3..bc3a782796 100644 --- a/beacon_node/client/src/client_config.rs +++ b/beacon_node/client/src/client_config.rs @@ -1,13 +1,13 @@ use clap::ArgMatches; use db::DBType; use fork_choice::ForkChoiceAlgorithm; -use libp2p::multiaddr::ToMultiaddr; use network::NetworkConfig; use slog::error; use std::fs; use std::net::IpAddr; use std::net::SocketAddr; use std::path::PathBuf; +use types::multiaddr::ToMultiaddr; use types::ChainSpec; /// Stores the client configuration for this Lighthouse instance. @@ -32,11 +32,15 @@ impl Default for ClientConfig { }; fs::create_dir_all(&data_dir) .unwrap_or_else(|_| panic!("Unable to create {:?}", &data_dir)); + + let default_spec = ChainSpec::lighthouse_testnet(); + let default_net_conf = NetworkConfig::new(default_spec.boot_nodes.clone()); + Self { data_dir: data_dir.clone(), // default to foundation for chain specs - spec: ChainSpec::foundation(), - net_conf: NetworkConfig::default(), + spec: default_spec, + net_conf: default_net_conf, // default to bitwise LMD Ghost fork_choice: ForkChoiceAlgorithm::BitwiseLMDGhost, // default to memory db for now diff --git a/beacon_node/libp2p/Cargo.toml b/beacon_node/libp2p/Cargo.toml index d78ddd882f..496d302683 100644 --- a/beacon_node/libp2p/Cargo.toml +++ b/beacon_node/libp2p/Cargo.toml @@ -7,8 +7,8 @@ edition = "2018" [dependencies] # SigP repository until PR is merged libp2p = { git = "https://github.com/SigP/rust-libp2p", branch = "gossipsub" } +types = { path = "../../eth2/types" } slog = "2.4.1" version = { path = "../version" } tokio = "0.1.16" futures = "0.1.25" -parity-multiaddr = "0.2.0" diff --git a/beacon_node/libp2p/src/lib.rs b/beacon_node/libp2p/src/lib.rs index 1a24165bac..f72725e49d 100644 --- a/beacon_node/libp2p/src/lib.rs +++ b/beacon_node/libp2p/src/lib.rs @@ -6,11 +6,11 @@ mod behaviour; mod network_config; mod service; -pub use libp2p::multiaddr; -pub use libp2p::Multiaddr; pub use libp2p::{ gossipsub::{GossipsubConfig, GossipsubConfigBuilder}, PeerId, }; pub use network_config::NetworkConfig; pub use service::Service; +pub use types::multiaddr; +pub use types::Multiaddr; diff --git a/beacon_node/libp2p/src/network_config.rs b/beacon_node/libp2p/src/network_config.rs index 8eeb338612..7bab57ddef 100644 --- a/beacon_node/libp2p/src/network_config.rs +++ b/beacon_node/libp2p/src/network_config.rs @@ -1,6 +1,6 @@ +use crate::Multiaddr; use libp2p::gossipsub::{GossipsubConfig, GossipsubConfigBuilder}; use libp2p::secio; -use libp2p::Multiaddr; use std::fmt; #[derive(Clone)] @@ -40,8 +40,11 @@ impl Default for NetworkConfig { } impl NetworkConfig { - pub fn new() -> Self { - NetworkConfig::default() + pub fn new(boot_nodes: Vec) -> Self { + let mut conf = NetworkConfig::default(); + conf.boot_nodes = boot_nodes; + + conf } } diff --git a/beacon_node/libp2p/src/service.rs b/beacon_node/libp2p/src/service.rs index 8e16707011..ee36cefd57 100644 --- a/beacon_node/libp2p/src/service.rs +++ b/beacon_node/libp2p/src/service.rs @@ -1,4 +1,5 @@ use crate::behaviour::Behaviour; +use crate::multiaddr::Protocol; use crate::NetworkConfig; use futures::prelude::*; use libp2p::core::{ @@ -7,7 +8,6 @@ use libp2p::core::{ transport::boxed::Boxed, upgrade::{InboundUpgradeExt, OutboundUpgradeExt}, }; -use libp2p::multiaddr::Protocol; use libp2p::{core, secio, Transport}; use libp2p::{PeerId, Swarm}; use slog::{debug, info, warn}; diff --git a/eth2/types/Cargo.toml b/eth2/types/Cargo.toml index ea1343dbab..f8120d5206 100644 --- a/eth2/types/Cargo.toml +++ b/eth2/types/Cargo.toml @@ -22,6 +22,7 @@ ssz = { path = "../utils/ssz" } ssz_derive = { path = "../utils/ssz_derive" } swap_or_not_shuffle = { path = "../utils/swap_or_not_shuffle" } test_random_derive = { path = "../utils/test_random_derive" } +libp2p = { git = "https://github.com/SigP/rust-libp2p", branch = "gossipsub" } [dev-dependencies] env_logger = "0.6.0" diff --git a/eth2/types/src/chain_spec.rs b/eth2/types/src/chain_spec.rs index 789bb6c0cc..ef2c94d653 100644 --- a/eth2/types/src/chain_spec.rs +++ b/eth2/types/src/chain_spec.rs @@ -1,4 +1,4 @@ -use crate::{Address, Epoch, Fork, Hash256, Slot}; +use crate::{Address, Epoch, Fork, Hash256, Multiaddr, Slot}; use bls::Signature; const GWEI: u64 = 1_000_000_000; @@ -106,6 +106,12 @@ pub struct ChainSpec { domain_exit: u64, domain_randao: u64, domain_transfer: u64, + + /* + * Network specific parameters + * + */ + pub boot_nodes: Vec, } impl ChainSpec { @@ -232,9 +238,31 @@ impl ChainSpec { domain_exit: 3, domain_randao: 4, domain_transfer: 5, + + /* + * Boot nodes + */ + boot_nodes: vec![], } } + /// Returns a `ChainSpec` compatible with the Lighthouse testnet specification. + /// + /// Spec v0.4.0 + pub fn lighthouse_testnet() -> Self { + /* + * Lighthouse testnet bootnodes + */ + let boot_nodes = vec!["/ip4/127.0.0.1/tcp/9000" + .parse() + .expect("correct multiaddr")]; + + let mut standard_spec = ChainSpec::foundation(); + standard_spec.boot_nodes = boot_nodes; + + standard_spec + } + /// Returns a `ChainSpec` compatible with the specification suitable for 8 validators. /// /// Spec v0.4.0 diff --git a/eth2/types/src/lib.rs b/eth2/types/src/lib.rs index 9bf60f2c92..5555600900 100644 --- a/eth2/types/src/lib.rs +++ b/eth2/types/src/lib.rs @@ -73,3 +73,5 @@ pub type AttesterMap = HashMap<(u64, u64), Vec>; pub type ProposerMap = HashMap; pub use bls::{AggregatePublicKey, AggregateSignature, Keypair, PublicKey, Signature}; +pub use libp2p::multiaddr; +pub use libp2p::Multiaddr; From 5f51c6d60a4c0495e7b99024f00ecbfebbe73c5b Mon Sep 17 00:00:00 2001 From: Age Manning Date: Mon, 11 Mar 2019 15:09:57 +1100 Subject: [PATCH 10/62] Add editorconfig template --- .editorconfig | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..a14dd7a516 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true +[*] +indent_style=space +indent_size=4 +end_of_line=lf +charset=utf-8 +trim_trailing_whitespace=true +max_line_length=100 +insert_final_newline=false From ae983a9347d9a275ee90aeb044d0a6f2d4545ffa Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 12 Mar 2019 17:28:11 +1100 Subject: [PATCH 11/62] Basic networking service with channel --- beacon_node/client/src/lib.rs | 13 ++-- beacon_node/client/src/notifier.rs | 15 +++- beacon_node/libp2p/Cargo.toml | 1 + beacon_node/libp2p/src/behaviour.rs | 34 ++++++-- beacon_node/libp2p/src/error.rs | 8 ++ beacon_node/libp2p/src/lib.rs | 4 +- beacon_node/libp2p/src/service.rs | 46 +++++++++-- beacon_node/network/Cargo.toml | 1 + beacon_node/network/src/error.rs | 7 +- beacon_node/network/src/lib.rs | 1 + beacon_node/network/src/messages.rs | 5 ++ beacon_node/network/src/service.rs | 116 +++++++++++++++++++++++++--- beacon_node/src/run.rs | 2 + 13 files changed, 224 insertions(+), 29 deletions(-) create mode 100644 beacon_node/libp2p/src/error.rs diff --git a/beacon_node/client/src/lib.rs b/beacon_node/client/src/lib.rs index d0b096416e..6600c9e39b 100644 --- a/beacon_node/client/src/lib.rs +++ b/beacon_node/client/src/lib.rs @@ -22,9 +22,9 @@ use tokio::runtime::TaskExecutor; pub struct Client { config: ClientConfig, // beacon_chain: Arc>, - network: Option>, - exit: exit_future::Exit, - exit_signal: Option, + pub network: Arc, + pub exit: exit_future::Exit, + pub exit_signal: Signal, log: slog::Logger, phantom: PhantomData, } @@ -44,14 +44,15 @@ impl Client { // TODO: Add beacon_chain reference to network parameters let network_config = config.net_conf.clone(); let network_logger = log.new(o!("Service" => "Network")); - let (network, network_send) = NetworkService::new(network_config, network_logger)?; + let (network, network_send) = + NetworkService::new(network_config, executor, network_logger)?; Ok(Client { config, exit, - exit_signal: Some(exit_signal), + exit_signal: exit_signal, log, - network: Some(network), + network: network, phantom: PhantomData, }) } diff --git a/beacon_node/client/src/notifier.rs b/beacon_node/client/src/notifier.rs index dd38701c93..6b52e670a2 100644 --- a/beacon_node/client/src/notifier.rs +++ b/beacon_node/client/src/notifier.rs @@ -4,9 +4,10 @@ use db::ClientDB; use exit_future::Exit; use fork_choice::ForkChoice; use futures::{Future, Stream}; +use network::NodeMessage; use slog::{debug, info, o}; use slot_clock::SlotClock; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; use tokio::runtime::TaskExecutor; use tokio::timer::Interval; @@ -19,9 +20,21 @@ pub fn run(client: &Client, executor: TaskExecutor, exit: Exi let log = client.log.new(o!("Service" => "Notifier")); + // TODO: Debugging only + let counter = Arc::new(Mutex::new(0)); + let network = client.network.clone(); + // build heartbeat logic here let heartbeat = move |_| { info!(log, "Temp heartbeat output"); + let mut count = counter.lock().unwrap(); + *count += 1; + + if *count % 5 == 0 { + debug!(log, "Sending Message"); + network.send_message(String::from("Testing network channel")) + } + Ok(()) }; diff --git a/beacon_node/libp2p/Cargo.toml b/beacon_node/libp2p/Cargo.toml index 496d302683..ecd91e1701 100644 --- a/beacon_node/libp2p/Cargo.toml +++ b/beacon_node/libp2p/Cargo.toml @@ -12,3 +12,4 @@ slog = "2.4.1" version = { path = "../version" } tokio = "0.1.16" futures = "0.1.25" +error-chain = "0.12.0" diff --git a/beacon_node/libp2p/src/behaviour.rs b/beacon_node/libp2p/src/behaviour.rs index 0c9aae16eb..be12011dd7 100644 --- a/beacon_node/libp2p/src/behaviour.rs +++ b/beacon_node/libp2p/src/behaviour.rs @@ -1,7 +1,7 @@ use futures::prelude::*; use libp2p::{ core::swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess}, - gossipsub::{Gossipsub, GossipsubConfig, GossipsubEvent, GossipsubRpc}, + gossipsub::{Gossipsub, GossipsubConfig, GossipsubEvent}, tokio_io::{AsyncRead, AsyncWrite}, NetworkBehaviour, PeerId, }; @@ -9,13 +9,14 @@ use libp2p::{ /// Builds the network behaviour for the libp2p Swarm. /// Implements gossipsub message routing. #[derive(NetworkBehaviour)] +#[behaviour(out_event = "BehaviourEvent", poll_method = "poll")] pub struct Behaviour { gossipsub: Gossipsub, // TODO: Add Kademlia for peer discovery /// The events generated by this behaviour to be consumed in the swarm poll. // We use gossipsub events for now, generalise later. #[behaviour(ignore)] - events: Vec, + events: Vec, } // Implement the NetworkBehaviourEventProcess trait so that we can derive NetworkBehaviour for Behaviour @@ -23,7 +24,15 @@ impl NetworkBehaviourEventProcess { fn inject_event(&mut self, event: GossipsubEvent) { - self.events.push(event); + match event { + GossipsubEvent::Message(message) => { + let gs_message = String::from_utf8_lossy(&message.data); + // TODO: Remove this type - debug only + self.events + .push(BehaviourEvent::Message(gs_message.to_string())) + } + _ => {} + } } } @@ -35,8 +44,10 @@ impl Behaviour { } } - /// Consume the events list when polled. - fn poll(&mut self) -> Async> { + /// Consumes the events list when polled. + fn poll( + &mut self, + ) -> Async> { if !self.events.is_empty() { return Async::Ready(NetworkBehaviourAction::GenerateEvent(self.events.remove(0))); } @@ -44,3 +55,16 @@ impl Behaviour { Async::NotReady } } + +impl Behaviour { + pub fn send_message(&self, message: String) { + // TODO: Encode and send via gossipsub + + } +} + +/// The types of events than can be obtained from polling the behaviour. +pub enum BehaviourEvent { + // TODO: This is a stub at the moment + Message(String), +} diff --git a/beacon_node/libp2p/src/error.rs b/beacon_node/libp2p/src/error.rs new file mode 100644 index 0000000000..163fe575d2 --- /dev/null +++ b/beacon_node/libp2p/src/error.rs @@ -0,0 +1,8 @@ +// generates error types + +use error_chain::{ + error_chain, error_chain_processing, impl_error_chain_kind, impl_error_chain_processed, + impl_extract_backtrace, +}; + +error_chain! {} diff --git a/beacon_node/libp2p/src/lib.rs b/beacon_node/libp2p/src/lib.rs index f72725e49d..a1bf4402c6 100644 --- a/beacon_node/libp2p/src/lib.rs +++ b/beacon_node/libp2p/src/lib.rs @@ -2,7 +2,8 @@ /// all required libp2p functionality. /// /// This crate builds and manages the libp2p services required by the beacon node. -mod behaviour; +pub mod behaviour; +pub mod error; mod network_config; mod service; @@ -11,6 +12,7 @@ pub use libp2p::{ PeerId, }; pub use network_config::NetworkConfig; +pub use service::Libp2pEvent; pub use service::Service; pub use types::multiaddr; pub use types::Multiaddr; diff --git a/beacon_node/libp2p/src/service.rs b/beacon_node/libp2p/src/service.rs index ee36cefd57..dceb62511f 100644 --- a/beacon_node/libp2p/src/service.rs +++ b/beacon_node/libp2p/src/service.rs @@ -1,7 +1,9 @@ -use crate::behaviour::Behaviour; +use crate::behaviour::{Behaviour, BehaviourEvent}; +use crate::error; use crate::multiaddr::Protocol; use crate::NetworkConfig; use futures::prelude::*; +use futures::Stream; use libp2p::core::{ muxing::StreamMuxerBox, nodes::Substream, @@ -17,13 +19,16 @@ use std::time::Duration; /// The configuration and state of the libp2p components for the beacon node. pub struct Service { /// The libp2p Swarm handler. - swarm: Swarm, Behaviour>>, + //TODO: Make this private + pub swarm: Swarm, Behaviour>>, /// This node's PeerId. local_peer_id: PeerId, + /// The libp2p logger handle. + pub log: slog::Logger, } impl Service { - pub fn new(config: NetworkConfig, log: slog::Logger) -> Self { + pub fn new(config: NetworkConfig, log: slog::Logger) -> error::Result { debug!(log, "Libp2p Service starting"); let local_private_key = config.local_private_key; @@ -50,7 +55,7 @@ impl Service { Err(err) => warn!(log, "Cannot listen on: {} : {:?}", address, err), }; } - // connect to boot nodes - these are currently stored as multiadders + // connect to boot nodes - these are currently stored as multiaddrs // Once we have discovery, can set to peerId for bootnode in config.boot_nodes { match Swarm::dial_addr(&mut swarm, bootnode.clone()) { @@ -62,10 +67,36 @@ impl Service { }; } - Service { + Ok(Service { local_peer_id, swarm, + log, + }) + } +} + +impl Stream for Service { + type Item = Libp2pEvent; + type Error = crate::error::Error; + + fn poll(&mut self) -> Poll, Self::Error> { + loop { + // TODO: Currently only gossipsub events passed here. + // Build a type for more generic events + match self.swarm.poll() { + Ok(Async::Ready(Some(BehaviourEvent::Message(m)))) => { + // TODO: Stub here for debugging + debug!(self.log, "Message received: {}", m); + return Ok(Async::Ready(Some(Libp2pEvent::Message(m)))); + } + // TODO: Fill with all behaviour events + _ => break, + Ok(Async::Ready(None)) => unreachable!("Swarm stream shouldn't end"), + Ok(Async::NotReady) => break, + _ => break, + } } + Ok(Async::NotReady) } } @@ -103,3 +134,8 @@ fn build_transport( .map_err(|err| Error::new(ErrorKind::Other, err)) .boxed() } + +/// Events that can be obtained from polling the Libp2p Service. +pub enum Libp2pEvent { + Message(String), +} diff --git a/beacon_node/network/Cargo.toml b/beacon_node/network/Cargo.toml index f32ee1f906..19d3e82ad4 100644 --- a/beacon_node/network/Cargo.toml +++ b/beacon_node/network/Cargo.toml @@ -13,3 +13,4 @@ slog = "2.4.1" futures = "0.1.25" error-chain = "0.12.0" crossbeam-channel = "0.3.8" +tokio = "0.1.16" diff --git a/beacon_node/network/src/error.rs b/beacon_node/network/src/error.rs index 163fe575d2..2005f76ae9 100644 --- a/beacon_node/network/src/error.rs +++ b/beacon_node/network/src/error.rs @@ -1,8 +1,13 @@ // generates error types +use libp2p; use error_chain::{ error_chain, error_chain_processing, impl_error_chain_kind, impl_error_chain_processed, impl_extract_backtrace, }; -error_chain! {} +error_chain! { + links { + Libp2p(libp2p::error::Error, libp2p::error::ErrorKind); + } +} diff --git a/beacon_node/network/src/lib.rs b/beacon_node/network/src/lib.rs index ae03d83678..49b2abadd7 100644 --- a/beacon_node/network/src/lib.rs +++ b/beacon_node/network/src/lib.rs @@ -5,4 +5,5 @@ mod messages; mod service; pub use libp2p::NetworkConfig; +pub use messages::NodeMessage; pub use service::Service; diff --git a/beacon_node/network/src/messages.rs b/beacon_node/network/src/messages.rs index 05b899269b..d3a83fd5c8 100644 --- a/beacon_node/network/src/messages.rs +++ b/beacon_node/network/src/messages.rs @@ -2,11 +2,15 @@ use libp2p::PeerId; use types::{Hash256, Slot}; /// Messages between nodes across the network. +#[derive(Debug, Clone)] pub enum NodeMessage { Status(Status), BlockRequest, + // TODO: only for testing - remove + Message(String), } +#[derive(Debug, Clone)] pub struct Status { /// Current node version. version: u8, @@ -19,6 +23,7 @@ pub struct Status { } /// Types of messages that the network service can receive. +#[derive(Debug, Clone)] pub enum NetworkMessage { /// Send a message to libp2p service. //TODO: Define typing for messages across the wire diff --git a/beacon_node/network/src/service.rs b/beacon_node/network/src/service.rs index ac8d9b442d..e75b7e49a8 100644 --- a/beacon_node/network/src/service.rs +++ b/beacon_node/network/src/service.rs @@ -2,39 +2,135 @@ use crate::error; use crate::message_handler::{HandlerMessage, MessageHandler}; use crate::messages::{NetworkMessage, NodeMessage}; use crate::NetworkConfig; -use crossbeam_channel::{unbounded as channel, Sender}; +use crossbeam_channel::{unbounded as channel, Sender, TryRecvError}; +use futures::future::lazy; +use futures::future::poll_fn; +use futures::prelude::*; use futures::sync::oneshot; +use futures::Stream; +use libp2p::behaviour::BehaviourEvent; +use libp2p::error::Error as libp2pError; use libp2p::Service as LibP2PService; +use libp2p::{Libp2pEvent, PeerId}; use slog::{debug, info, o, trace, warn, Logger}; use std::sync::{Arc, Mutex}; +use tokio::runtime::TaskExecutor; /// Service that handles communication between internal services and the libp2p network service. pub struct Service { //libp2p_service: Arc>, -//libp2p_thread: oneshot::Sender<()>, -//message_handler: MessageHandler, -//message_handler_send: Sender, + libp2p_exit: oneshot::Sender<()>, + network_send: crossbeam_channel::Sender, + //message_handler: MessageHandler, + //message_handler_send: Sender, } impl Service { pub fn new( config: NetworkConfig, + executor: TaskExecutor, log: slog::Logger, ) -> error::Result<(Arc, Sender)> { - debug!(log, "Service starting"); - let (network_send, network_recv) = channel::(); - // launch message handler thread let message_handler_log = log.new(o!("Service" => "MessageHandler")); - let message_handler_send = MessageHandler::new(message_handler_log); + let message_handler_send = MessageHandler::new(message_handler_log)?; // launch libp2p service let libp2p_log = log.new(o!("Service" => "Libp2p")); - let libp2p_service = LibP2PService::new(config, libp2p_log); + let libp2p_service = LibP2PService::new(config, libp2p_log)?; // TODO: Spawn thread to handle libp2p messages and pass to message handler thread. - let network = Service {}; + let (network_send, libp2p_exit) = + spawn_service(libp2p_service, message_handler_send, executor, log)?; + let network = Service { + libp2p_exit, + network_send: network_send.clone(), + }; Ok((Arc::new(network), network_send)) } + + // TODO: Testing only + pub fn send_message(&self, message: String) { + let node_message = NodeMessage::Message(message); + self.network_send + .send(NetworkMessage::Send(PeerId::random(), node_message)); + } +} + +fn spawn_service( + libp2p_service: LibP2PService, + message_handler_send: crossbeam_channel::Sender, + executor: TaskExecutor, + log: slog::Logger, +) -> error::Result<( + crossbeam_channel::Sender, + oneshot::Sender<()>, +)> { + let (network_exit, exit_rx) = oneshot::channel(); + let (network_send, network_recv) = channel::(); + + // spawn on the current executor + executor.spawn( + network_service( + libp2p_service, + network_recv, + message_handler_send, + log.clone(), + ) + // allow for manual termination + .select(exit_rx.then(|_| Ok(()))) + .then(move |_| { + debug!(log.clone(), "Network service ended"); + Ok(()) + }), + ); + + Ok((network_send, network_exit)) +} + +fn network_service( + mut libp2p_service: LibP2PService, + network_recv: crossbeam_channel::Receiver, + message_handler_send: crossbeam_channel::Sender, + log: slog::Logger, +) -> impl futures::Future { + futures::future::poll_fn(move || -> Result<_, libp2p::error::Error> { + // poll the swarm + loop { + match libp2p_service.poll() { + Ok(Async::Ready(Some(Libp2pEvent::Message(m)))) => debug!( + libp2p_service.log, + "Network Service: Message received: {}", m + ), + _ => break, + } + } + // poll the network channel + // TODO: refactor - combine poll_fn's? + loop { + match network_recv.try_recv() { + // TODO: Testing message - remove + Ok(NetworkMessage::Send(_peer_id, node_message)) => { + match node_message { + NodeMessage::Message(m) => { + debug!(log, "Message received via network channel: {:?}", m); + //TODO: Make swarm private + //TODO: Implement correct peer id topic message handling + libp2p_service.swarm.send_message(m); + } + //TODO: Handle all NodeMessage types + _ => break, + }; + } + Err(TryRecvError::Empty) => break, + Err(TryRecvError::Disconnected) => { + return Err(libp2p::error::Error::from("Network channel disconnected")); + } + // TODO: Implement all NetworkMessage + _ => break, + } + } + Ok(Async::NotReady) + }) } diff --git a/beacon_node/src/run.rs b/beacon_node/src/run.rs index f2a703cbcf..cfae001a02 100644 --- a/beacon_node/src/run.rs +++ b/beacon_node/src/run.rs @@ -40,6 +40,8 @@ pub fn run_beacon_node(config: ClientConfig, log: slog::Logger) -> error::Result // perform global shutdown operations. info!(log, "Shutting down.."); exit_signal.fire(); + // shutdown the client + // client.exit_signal.fire(); drop(client); runtime.shutdown_on_idle().wait().unwrap(); Ok(()) From 8ee3523abd47b294d2ee41167dcf8d2e27bb76b1 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 13 Mar 2019 14:43:24 +1100 Subject: [PATCH 12/62] Transition to secp256k1 default peer id --- beacon_node/libp2p/src/network_config.rs | 6 ++++-- eth2/types/src/lib.rs | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/beacon_node/libp2p/src/network_config.rs b/beacon_node/libp2p/src/network_config.rs index 7bab57ddef..ecc36da338 100644 --- a/beacon_node/libp2p/src/network_config.rs +++ b/beacon_node/libp2p/src/network_config.rs @@ -2,6 +2,7 @@ use crate::Multiaddr; use libp2p::gossipsub::{GossipsubConfig, GossipsubConfigBuilder}; use libp2p::secio; use std::fmt; +use types::Topic; #[derive(Clone)] /// Network configuration for lighthouse. @@ -24,8 +25,9 @@ pub struct NetworkConfig { impl Default for NetworkConfig { /// Generate a default network configuration. fn default() -> Self { - // TODO: Currently using ed25519 key pairs. Wire protocol specifies RSA. Waiting for this + // TODO: Currently using secp256k1 key pairs. Wire protocol specifies RSA. Waiting for this // PR to be merged to generate RSA keys: https://github.com/briansmith/ring/pull/733 + NetworkConfig { listen_addresses: vec!["/ip4/127.0.0.1/tcp/9000" .parse() @@ -33,7 +35,7 @@ impl Default for NetworkConfig { listen_port: 9000, gs_config: GossipsubConfigBuilder::new().build(), boot_nodes: Vec::new(), - local_private_key: secio::SecioKeyPair::ed25519_generated().unwrap(), + local_private_key: secio::SecioKeyPair::secp256k1_generated().unwrap(), client_version: version::version(), } } diff --git a/eth2/types/src/lib.rs b/eth2/types/src/lib.rs index 5555600900..47235a15b0 100644 --- a/eth2/types/src/lib.rs +++ b/eth2/types/src/lib.rs @@ -73,5 +73,6 @@ pub type AttesterMap = HashMap<(u64, u64), Vec>; pub type ProposerMap = HashMap; pub use bls::{AggregatePublicKey, AggregateSignature, Keypair, PublicKey, Signature}; +pub use libp2p::floodsub::Topic; pub use libp2p::multiaddr; pub use libp2p::Multiaddr; From 23a8fbfc74b64e6f698dfe66d2ffdafec2f2cacd Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 13 Mar 2019 15:37:44 +1100 Subject: [PATCH 13/62] Add default topics and initial topic subscription --- beacon_node/libp2p/src/behaviour.rs | 5 +++++ beacon_node/libp2p/src/network_config.rs | 4 +++- beacon_node/libp2p/src/service.rs | 19 +++++++++++++++++-- eth2/types/src/lib.rs | 2 +- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/beacon_node/libp2p/src/behaviour.rs b/beacon_node/libp2p/src/behaviour.rs index be12011dd7..be49abb94e 100644 --- a/beacon_node/libp2p/src/behaviour.rs +++ b/beacon_node/libp2p/src/behaviour.rs @@ -5,6 +5,7 @@ use libp2p::{ tokio_io::{AsyncRead, AsyncWrite}, NetworkBehaviour, PeerId, }; +use types::Topic; /// Builds the network behaviour for the libp2p Swarm. /// Implements gossipsub message routing. @@ -57,6 +58,10 @@ impl Behaviour { } impl Behaviour { + pub fn subscribe(&mut self, topic: Topic) -> bool { + self.gossipsub.subscribe(topic) + } + pub fn send_message(&self, message: String) { // TODO: Encode and send via gossipsub diff --git a/beacon_node/libp2p/src/network_config.rs b/beacon_node/libp2p/src/network_config.rs index ecc36da338..176892bb02 100644 --- a/beacon_node/libp2p/src/network_config.rs +++ b/beacon_node/libp2p/src/network_config.rs @@ -2,7 +2,6 @@ use crate::Multiaddr; use libp2p::gossipsub::{GossipsubConfig, GossipsubConfigBuilder}; use libp2p::secio; use std::fmt; -use types::Topic; #[derive(Clone)] /// Network configuration for lighthouse. @@ -20,6 +19,8 @@ pub struct NetworkConfig { pub local_private_key: secio::SecioKeyPair, /// Client version pub client_version: String, + /// List of topics to subscribe to as strings + pub topics: Vec, } impl Default for NetworkConfig { @@ -37,6 +38,7 @@ impl Default for NetworkConfig { boot_nodes: Vec::new(), local_private_key: secio::SecioKeyPair::secp256k1_generated().unwrap(), client_version: version::version(), + topics: vec![String::from("beacon_chain")], } } } diff --git a/beacon_node/libp2p/src/service.rs b/beacon_node/libp2p/src/service.rs index dceb62511f..26154beb66 100644 --- a/beacon_node/libp2p/src/service.rs +++ b/beacon_node/libp2p/src/service.rs @@ -12,9 +12,10 @@ use libp2p::core::{ }; use libp2p::{core, secio, Transport}; use libp2p::{PeerId, Swarm}; -use slog::{debug, info, warn}; +use slog::{debug, info, trace, warn}; use std::io::{Error, ErrorKind}; use std::time::Duration; +use types::{Topic, TopicBuilder}; /// The configuration and state of the libp2p components for the beacon node. pub struct Service { @@ -33,7 +34,7 @@ impl Service { let local_private_key = config.local_private_key; let local_peer_id = local_private_key.to_peer_id(); - debug!(log, "Local peer id: {:?}", local_peer_id); + info!(log, "Local peer id: {:?}", local_peer_id); let mut swarm = { // Set up the transport @@ -67,6 +68,20 @@ impl Service { }; } + // subscribe to default gossipsub topics + let mut subscribed_topics = vec![]; + for topic in config.topics { + let t = TopicBuilder::new(topic.to_string()).build(); + match swarm.subscribe(t) { + true => { + trace!(log, "Subscribed to topic: {:?}", topic); + subscribed_topics.push(topic); + } + false => warn!(log, "Could not subscribe to topic: {:?}", topic), + }; + } + info!(log, "Subscribed to topics: {:?}", subscribed_topics); + Ok(Service { local_peer_id, swarm, diff --git a/eth2/types/src/lib.rs b/eth2/types/src/lib.rs index 47235a15b0..2cf61cfec9 100644 --- a/eth2/types/src/lib.rs +++ b/eth2/types/src/lib.rs @@ -73,6 +73,6 @@ pub type AttesterMap = HashMap<(u64, u64), Vec>; pub type ProposerMap = HashMap; pub use bls::{AggregatePublicKey, AggregateSignature, Keypair, PublicKey, Signature}; -pub use libp2p::floodsub::Topic; +pub use libp2p::floodsub::{Topic, TopicBuilder}; pub use libp2p::multiaddr; pub use libp2p::Multiaddr; From c06e8ffa5b497e238470caf985bf3fabca156fa0 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Fri, 15 Mar 2019 01:50:59 +1100 Subject: [PATCH 14/62] Initial Libp2p RPC implementation. --- beacon_node/Cargo.toml | 1 - beacon_node/libp2p/Cargo.toml | 2 + beacon_node/libp2p/src/lib.rs | 1 + beacon_node/libp2p/src/rpc/handler.rs | 0 beacon_node/libp2p/src/rpc/methods.rs | 38 ++++++ beacon_node/libp2p/src/rpc/mod.rs | 120 +++++++++++++++++ beacon_node/libp2p/src/rpc/protocol.rs | 179 +++++++++++++++++++++++++ beacon_node/libp2p/src/service.rs | 2 +- 8 files changed, 341 insertions(+), 2 deletions(-) create mode 100644 beacon_node/libp2p/src/rpc/handler.rs create mode 100644 beacon_node/libp2p/src/rpc/methods.rs create mode 100644 beacon_node/libp2p/src/rpc/mod.rs create mode 100644 beacon_node/libp2p/src/rpc/protocol.rs diff --git a/beacon_node/Cargo.toml b/beacon_node/Cargo.toml index 8b26417860..56f5c654e2 100644 --- a/beacon_node/Cargo.toml +++ b/beacon_node/Cargo.toml @@ -7,7 +7,6 @@ edition = "2018" [dependencies] client = { path = "client" } version = { path = "version" } - clap = "2.32.0" slog = "^2.2.3" slog-term = "^2.4.0" diff --git a/beacon_node/libp2p/Cargo.toml b/beacon_node/libp2p/Cargo.toml index ecd91e1701..dcbc04d0b9 100644 --- a/beacon_node/libp2p/Cargo.toml +++ b/beacon_node/libp2p/Cargo.toml @@ -8,6 +8,8 @@ edition = "2018" # SigP repository until PR is merged libp2p = { git = "https://github.com/SigP/rust-libp2p", branch = "gossipsub" } types = { path = "../../eth2/types" } +ssz = { path = "../../eth2/utils/ssz" } +ssz_derive = { path = "../../eth2/utils/ssz_derive" } slog = "2.4.1" version = { path = "../version" } tokio = "0.1.16" diff --git a/beacon_node/libp2p/src/lib.rs b/beacon_node/libp2p/src/lib.rs index a1bf4402c6..718b7fc222 100644 --- a/beacon_node/libp2p/src/lib.rs +++ b/beacon_node/libp2p/src/lib.rs @@ -5,6 +5,7 @@ pub mod behaviour; pub mod error; mod network_config; +mod rpc; mod service; pub use libp2p::{ diff --git a/beacon_node/libp2p/src/rpc/handler.rs b/beacon_node/libp2p/src/rpc/handler.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/beacon_node/libp2p/src/rpc/methods.rs b/beacon_node/libp2p/src/rpc/methods.rs new file mode 100644 index 0000000000..d299e9bb7a --- /dev/null +++ b/beacon_node/libp2p/src/rpc/methods.rs @@ -0,0 +1,38 @@ +/// Available RPC methods types and ids. +use ssz_derive::{Decode, Encode}; +use types::{Epoch, Hash256, Slot}; + +#[derive(Debug)] +pub enum RPCMethod { + Hello, + Unknown, +} + +impl From for RPCMethod { + fn from(method_id: u16) -> Self { + match method_id { + 0 => RPCMethod::Hello, + _ => RPCMethod::Unknown, + } + } +} + +#[derive(Debug, Clone)] +pub enum RPCRequest { + HelloRequest, +} + +#[derive(Debug, Clone)] +pub enum RPCResponse { + HelloResponse(HelloResponse), +} + +// request/response structs for RPC methods +#[derive(Encode, Decode, Clone, Debug)] +pub struct HelloResponse { + pub network_id: u8, + pub latest_finalized_root: Hash256, + pub latest_finalized_epoch: Epoch, + pub best_root: Hash256, + pub best_slot: Slot, +} diff --git a/beacon_node/libp2p/src/rpc/mod.rs b/beacon_node/libp2p/src/rpc/mod.rs new file mode 100644 index 0000000000..004f17d9e8 --- /dev/null +++ b/beacon_node/libp2p/src/rpc/mod.rs @@ -0,0 +1,120 @@ +mod handler; +mod methods; +/// RPC Protocol over libp2p. +/// +/// This is purpose built for Ethereum 2.0 serenity and the protocol listens on +/// `/eth/serenity/rpc/1.0.0` +mod protocol; + +use futures::prelude::*; +use libp2p::core::protocols_handler::{OneShotHandler, ProtocolsHandler}; +use libp2p::core::swarm::{ + ConnectedPoint, NetworkBehaviour, NetworkBehaviourAction, PollParameters, +}; +use libp2p::{Multiaddr, PeerId}; +use methods::RPCRequest; +use protocol::{RPCProtocol, RpcEvent}; +use std::marker::PhantomData; +use tokio::io::{AsyncRead, AsyncWrite}; + +/// The network behaviour handles RPC requests/responses as specified in the Eth 2.0 phase 0 +/// specification. + +pub struct Rpc { + /// Queue of events to processed. + events: Vec, + /// Pins the generic substream. + marker: PhantomData, +} + +impl Rpc { + pub fn new() -> Self { + Rpc { + events: Vec::new(), + marker: PhantomData, + } + } + + /// Submits and RPC request. + pub fn send_request(&mut self, id: u64, method_id: u16, body: RPCRequest) { + let request = RpcEvent::Request { + id, + method_id, + body, + }; + self.events.push(request); + } +} + +impl NetworkBehaviour for Rpc +where + TSubstream: AsyncRead + AsyncWrite, +{ + type ProtocolsHandler = OneShotHandler; + type OutEvent = RpcEvent; + + fn new_handler(&mut self) -> Self::ProtocolsHandler { + Default::default() + } + + fn addresses_of_peer(&mut self, _peer_id: &PeerId) -> Vec { + Vec::new() + } + + fn inject_connected(&mut self, _: PeerId, _: ConnectedPoint) {} + + fn inject_disconnected(&mut self, _: &PeerId, _: ConnectedPoint) {} + + fn inject_node_event( + &mut self, + source: PeerId, + event: ::OutEvent, + ) { + // ignore successful sends event + let event = match event { + OneShotEvent::Rx(event) => event, + OneShotEvent::Sent => return, + }; + + // send the event to the user + self.events.push(event); + } + + fn poll( + &mut self, + _: &mut PollParameters<'_>, + ) -> Async< + NetworkBehaviourAction< + ::InEvent, + Self::OutEvent, + >, + > { + if !self.events.is_empty() { + return Async::Ready(NetworkBehaviourAction::GenerateEvent(self.events.remove(0))); + } + Async::NotReady + } +} + +/// Transmission between the `OneShotHandler` and the `RpcEvent`. +#[derive(Debug)] +pub enum OneShotEvent { + /// We received an RPC from a remote. + Rx(RpcEvent), + /// We successfully sent an RPC request. + Sent, +} + +impl From for OneShotEvent { + #[inline] + fn from(rpc: RpcEvent) -> OneShotEvent { + OneShotEvent::Rx(rpc) + } +} + +impl From<()> for OneShotEvent { + #[inline] + fn from(_: ()) -> OneShotEvent { + OneShotEvent::Sent + } +} diff --git a/beacon_node/libp2p/src/rpc/protocol.rs b/beacon_node/libp2p/src/rpc/protocol.rs new file mode 100644 index 0000000000..e65927b03a --- /dev/null +++ b/beacon_node/libp2p/src/rpc/protocol.rs @@ -0,0 +1,179 @@ +use super::methods::HelloResponse; +use super::methods::{RPCMethod, RPCRequest, RPCResponse}; +//use crate::rpc_proto; +//use byteorder::{BigEndian, ByteOrder}; +//use bytes::BytesMut; +use futures::{future, stream, Future, Stream}; +use libp2p::core::{upgrade, InboundUpgrade, OutboundUpgrade, PeerId, UpgradeInfo}; +//use std::{io, iter}; +use ssz::{ssz_encode, Decodable, Encodable, SszStream}; +use std::io; +use std::iter; +use tokio::io::{AsyncRead, AsyncWrite}; + +/// The maximum bytes that can be sent across the RPC. +const MAX_READ_SIZE: usize = 2048; + +/// Implementation of the `ConnectionUpgrade` for the rpc protocol. + +#[derive(Debug, Clone)] +pub struct RPCProtocol; + +impl UpgradeInfo for RPCProtocol { + type Info = &'static [u8]; + type InfoIter = iter::Once; + + #[inline] + fn protocol_info(&self) -> Self::InfoIter { + iter::once(b"/eth/serenity/rpc/1.0.0") + } +} + +impl Default for RPCProtocol { + fn default() -> Self { + RPCProtocol + } +} + +/// The RPC types which are sent/received in this protocol. +#[derive(Debug, Clone)] +pub enum RpcEvent { + Request { + id: u64, + method_id: u16, + body: RPCRequest, + }, + Response { + id: u64, + method_id: u16, //TODO: Remove and process decoding upstream + result: RPCResponse, + }, +} + +impl UpgradeInfo for RpcEvent { + type Info = &'static [u8]; + type InfoIter = iter::Once; + + #[inline] + fn protocol_info(&self) -> Self::InfoIter { + iter::once(b"/eth/serenity/rpc/1.0.0") + } +} + +impl InboundUpgrade for RPCProtocol +where + TSocket: AsyncRead + AsyncWrite, +{ + type Output = RpcEvent; + type Error = DecodeError; + type Future = + upgrade::ReadOneThen, ()) -> Result>; + + fn upgrade_inbound(self, socket: TSocket, _: Self::Info) -> Self::Future { + upgrade::read_one_then(socket, MAX_READ_SIZE, (), |packet, ()| Ok(decode(packet)?)) + } +} + +fn decode(packet: Vec) -> Result { + // decode the header of the rpc + // request/response + let (request, index) = bool::ssz_decode(&packet, 0)?; + let (id, index) = u64::ssz_decode(&packet, index)?; + let (method_id, index) = u16::ssz_decode(&packet, index)?; + + if request { + let body = match RPCMethod::from(method_id) { + RPCMethod::Hello => RPCRequest::HelloRequest, + RPCMethod::Unknown => return Err(DecodeError::UnknownRPCMethod), + }; + + return Ok(RpcEvent::Request { + id, + method_id, + body, + }); + } + // we have received a response + else { + let result = match RPCMethod::from(method_id) { + RPCMethod::Hello => { + let (hello_response, _index) = HelloResponse::ssz_decode(&packet, index)?; + RPCResponse::HelloResponse(hello_response) + } + RPCMethod::Unknown => return Err(DecodeError::UnknownRPCMethod), + }; + return Ok(RpcEvent::Response { + id, + method_id, + result, + }); + } +} + +impl OutboundUpgrade for RpcEvent +where + TSocket: AsyncWrite, +{ + type Output = (); + type Error = io::Error; + type Future = upgrade::WriteOne; + + #[inline] + fn upgrade_outbound(self, socket: TSocket, _: Self::Info) -> Self::Future { + let bytes = ssz_encode(&self); + upgrade::write_one(socket, bytes) + } +} + +impl Encodable for RpcEvent { + fn ssz_append(&self, s: &mut SszStream) { + match self { + RpcEvent::Request { + id, + method_id, + body, + } => { + s.append(&true); + s.append(id); + s.append(method_id); + match body { + RPCRequest::HelloRequest => {} + } + } + RpcEvent::Response { + id, + method_id, + result, + } => { + s.append(&false); + s.append(id); + s.append(method_id); + match result { + RPCResponse::HelloResponse(response) => { + s.append(response); + } + } + } + } + } +} + +pub enum DecodeError { + ReadError(upgrade::ReadOneError), + SSZDecodeError(ssz::DecodeError), + UnknownRPCMethod, +} + +impl From for DecodeError { + #[inline] + fn from(err: upgrade::ReadOneError) -> Self { + DecodeError::ReadError(err) + } +} + +impl From for DecodeError { + #[inline] + fn from(err: ssz::DecodeError) -> Self { + DecodeError::SSZDecodeError(err) + } +} diff --git a/beacon_node/libp2p/src/service.rs b/beacon_node/libp2p/src/service.rs index 26154beb66..00c11101c3 100644 --- a/beacon_node/libp2p/src/service.rs +++ b/beacon_node/libp2p/src/service.rs @@ -15,7 +15,7 @@ use libp2p::{PeerId, Swarm}; use slog::{debug, info, trace, warn}; use std::io::{Error, ErrorKind}; use std::time::Duration; -use types::{Topic, TopicBuilder}; +use types::TopicBuilder; /// The configuration and state of the libp2p components for the beacon node. pub struct Service { From 24c7f180e2fa409c156260a2c911499a27d136cb Mon Sep 17 00:00:00 2001 From: Age Manning Date: Fri, 15 Mar 2019 02:13:16 +1100 Subject: [PATCH 15/62] Update rpc event handling. --- beacon_node/libp2p/src/rpc/mod.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/beacon_node/libp2p/src/rpc/mod.rs b/beacon_node/libp2p/src/rpc/mod.rs index 004f17d9e8..d5f7000582 100644 --- a/beacon_node/libp2p/src/rpc/mod.rs +++ b/beacon_node/libp2p/src/rpc/mod.rs @@ -22,7 +22,7 @@ use tokio::io::{AsyncRead, AsyncWrite}; pub struct Rpc { /// Queue of events to processed. - events: Vec, + events: Vec>, /// Pins the generic substream. marker: PhantomData, } @@ -36,13 +36,16 @@ impl Rpc { } /// Submits and RPC request. - pub fn send_request(&mut self, id: u64, method_id: u16, body: RPCRequest) { + pub fn send_request(&mut self, peer_id: PeerId, id: u64, method_id: u16, body: RPCRequest) { let request = RpcEvent::Request { id, method_id, body, }; - self.events.push(request); + self.events.push(NetworkBehaviourAction::SendEvent { + peer_id, + event: request, + }); } } @@ -67,17 +70,18 @@ where fn inject_node_event( &mut self, - source: PeerId, + _source: PeerId, event: ::OutEvent, ) { - // ignore successful sends event + // ignore successful send events let event = match event { OneShotEvent::Rx(event) => event, OneShotEvent::Sent => return, }; // send the event to the user - self.events.push(event); + self.events + .push(NetworkBehaviourAction::GenerateEvent(event)); } fn poll( @@ -90,7 +94,7 @@ where >, > { if !self.events.is_empty() { - return Async::Ready(NetworkBehaviourAction::GenerateEvent(self.events.remove(0))); + return Async::Ready(self.events.remove(0)); } Async::NotReady } From 7b6a653d05c43de741ee85865d12a5593dd9f0ed Mon Sep 17 00:00:00 2001 From: Age Manning Date: Fri, 15 Mar 2019 02:48:09 +1100 Subject: [PATCH 16/62] Add RPC protocol to lh network behaviour. --- beacon_node/libp2p/src/behaviour.rs | 36 +++++++++++++++++++++++++- beacon_node/libp2p/src/rpc/mod.rs | 8 +++--- beacon_node/libp2p/src/rpc/protocol.rs | 1 + 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/beacon_node/libp2p/src/behaviour.rs b/beacon_node/libp2p/src/behaviour.rs index be49abb94e..2c0371095f 100644 --- a/beacon_node/libp2p/src/behaviour.rs +++ b/beacon_node/libp2p/src/behaviour.rs @@ -1,3 +1,4 @@ +use crate::rpc::{RPCMethod, RPCRequest, RPCResponse, Rpc, RpcEvent}; use futures::prelude::*; use libp2p::{ core::swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess}, @@ -15,7 +16,7 @@ pub struct Behaviour { gossipsub: Gossipsub, // TODO: Add Kademlia for peer discovery /// The events generated by this behaviour to be consumed in the swarm poll. - // We use gossipsub events for now, generalise later. + serenity_rpc: Rpc, #[behaviour(ignore)] events: Vec, } @@ -37,10 +38,34 @@ impl NetworkBehaviourEventProcess NetworkBehaviourEventProcess + for Behaviour +{ + fn inject_event(&mut self, event: RpcEvent) { + match event { + RpcEvent::Request { + id, + method_id, + body, + } => self.events.push(BehaviourEvent::RPCRequest { + id, + method: RPCMethod::from(method_id), + body, + }), + RpcEvent::Response { + id, + method_id, + result, + } => self.events.push(BehaviourEvent::RPCResponse { id, result }), + } + } +} + impl Behaviour { pub fn new(local_peer_id: PeerId, gs_config: GossipsubConfig) -> Self { Behaviour { gossipsub: Gossipsub::new(local_peer_id, gs_config), + serenity_rpc: Rpc::new(), events: Vec::new(), } } @@ -70,6 +95,15 @@ impl Behaviour { /// The types of events than can be obtained from polling the behaviour. pub enum BehaviourEvent { + RPCRequest { + id: u64, + method: RPCMethod, + body: RPCRequest, + }, + RPCResponse { + id: u64, + result: RPCResponse, + }, // TODO: This is a stub at the moment Message(String), } diff --git a/beacon_node/libp2p/src/rpc/mod.rs b/beacon_node/libp2p/src/rpc/mod.rs index d5f7000582..f66f531eb9 100644 --- a/beacon_node/libp2p/src/rpc/mod.rs +++ b/beacon_node/libp2p/src/rpc/mod.rs @@ -1,9 +1,9 @@ -mod handler; -mod methods; /// RPC Protocol over libp2p. /// /// This is purpose built for Ethereum 2.0 serenity and the protocol listens on /// `/eth/serenity/rpc/1.0.0` +mod handler; +mod methods; mod protocol; use futures::prelude::*; @@ -12,8 +12,8 @@ use libp2p::core::swarm::{ ConnectedPoint, NetworkBehaviour, NetworkBehaviourAction, PollParameters, }; use libp2p::{Multiaddr, PeerId}; -use methods::RPCRequest; -use protocol::{RPCProtocol, RpcEvent}; +pub use methods::{RPCMethod, RPCRequest, RPCResponse}; +pub use protocol::{RPCProtocol, RpcEvent}; use std::marker::PhantomData; use tokio::io::{AsyncRead, AsyncWrite}; diff --git a/beacon_node/libp2p/src/rpc/protocol.rs b/beacon_node/libp2p/src/rpc/protocol.rs index e65927b03a..2c6b3caa09 100644 --- a/beacon_node/libp2p/src/rpc/protocol.rs +++ b/beacon_node/libp2p/src/rpc/protocol.rs @@ -158,6 +158,7 @@ impl Encodable for RpcEvent { } } +#[derive(Debug)] pub enum DecodeError { ReadError(upgrade::ReadOneError), SSZDecodeError(ssz::DecodeError), From 2871ad50558ad2f672cc0a6fb599267819cda7c1 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sun, 17 Mar 2019 14:25:47 +1100 Subject: [PATCH 17/62] Correct listening addresses and associated log --- beacon_node/Cargo.toml | 1 + beacon_node/client/src/client_config.rs | 6 ++++++ beacon_node/src/run.rs | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/beacon_node/Cargo.toml b/beacon_node/Cargo.toml index 56f5c654e2..6be030fd58 100644 --- a/beacon_node/Cargo.toml +++ b/beacon_node/Cargo.toml @@ -5,6 +5,7 @@ authors = ["Paul Hauner ", "Age Manning () { config.net_conf.listen_port = port; + // update the listening multiaddrs + for address in &mut config.net_conf.listen_addresses { + address.pop(); + address.append(Protocol::Tcp(port)); + } } else { error!(log, "Invalid port"; "port" => port_str); return Err("Invalid port"); diff --git a/beacon_node/src/run.rs b/beacon_node/src/run.rs index cfae001a02..12d761d84c 100644 --- a/beacon_node/src/run.rs +++ b/beacon_node/src/run.rs @@ -14,7 +14,7 @@ pub fn run_beacon_node(config: ClientConfig, log: slog::Logger) -> error::Result .map_err(|e| format!("{:?}", e))?; // Log configuration - info!(log, ""; + info!(log, "Listening on {:?}", &config.net_conf.listen_addresses; "data_dir" => &config.data_dir.to_str(), "port" => &config.net_conf.listen_port); From 7370306366d21abe8a52b549933d328aded2c5f9 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sun, 17 Mar 2019 14:38:20 +1100 Subject: [PATCH 18/62] Rename RPC reqeusts, correct RPC internals --- beacon_node/libp2p/src/rpc/handler.rs | 0 beacon_node/libp2p/src/rpc/methods.rs | 6 +++--- beacon_node/libp2p/src/rpc/mod.rs | 1 - beacon_node/libp2p/src/rpc/protocol.rs | 25 +++++++++++-------------- 4 files changed, 14 insertions(+), 18 deletions(-) delete mode 100644 beacon_node/libp2p/src/rpc/handler.rs diff --git a/beacon_node/libp2p/src/rpc/handler.rs b/beacon_node/libp2p/src/rpc/handler.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/beacon_node/libp2p/src/rpc/methods.rs b/beacon_node/libp2p/src/rpc/methods.rs index d299e9bb7a..b6563ba649 100644 --- a/beacon_node/libp2p/src/rpc/methods.rs +++ b/beacon_node/libp2p/src/rpc/methods.rs @@ -19,17 +19,17 @@ impl From for RPCMethod { #[derive(Debug, Clone)] pub enum RPCRequest { - HelloRequest, + Hello(HelloBody), } #[derive(Debug, Clone)] pub enum RPCResponse { - HelloResponse(HelloResponse), + Hello(HelloBody), } // request/response structs for RPC methods #[derive(Encode, Decode, Clone, Debug)] -pub struct HelloResponse { +pub struct HelloBody { pub network_id: u8, pub latest_finalized_root: Hash256, pub latest_finalized_epoch: Epoch, diff --git a/beacon_node/libp2p/src/rpc/mod.rs b/beacon_node/libp2p/src/rpc/mod.rs index f66f531eb9..4cebb1e396 100644 --- a/beacon_node/libp2p/src/rpc/mod.rs +++ b/beacon_node/libp2p/src/rpc/mod.rs @@ -2,7 +2,6 @@ /// /// This is purpose built for Ethereum 2.0 serenity and the protocol listens on /// `/eth/serenity/rpc/1.0.0` -mod handler; mod methods; mod protocol; diff --git a/beacon_node/libp2p/src/rpc/protocol.rs b/beacon_node/libp2p/src/rpc/protocol.rs index 2c6b3caa09..4b462bb77c 100644 --- a/beacon_node/libp2p/src/rpc/protocol.rs +++ b/beacon_node/libp2p/src/rpc/protocol.rs @@ -1,11 +1,5 @@ -use super::methods::HelloResponse; -use super::methods::{RPCMethod, RPCRequest, RPCResponse}; -//use crate::rpc_proto; -//use byteorder::{BigEndian, ByteOrder}; -//use bytes::BytesMut; -use futures::{future, stream, Future, Stream}; -use libp2p::core::{upgrade, InboundUpgrade, OutboundUpgrade, PeerId, UpgradeInfo}; -//use std::{io, iter}; +use super::methods::{HelloBody, RPCMethod, RPCRequest, RPCResponse}; +use libp2p::core::{upgrade, InboundUpgrade, OutboundUpgrade, UpgradeInfo}; use ssz::{ssz_encode, Decodable, Encodable, SszStream}; use std::io; use std::iter; @@ -83,7 +77,10 @@ fn decode(packet: Vec) -> Result { if request { let body = match RPCMethod::from(method_id) { - RPCMethod::Hello => RPCRequest::HelloRequest, + RPCMethod::Hello => { + let (hello_body, _index) = HelloBody::ssz_decode(&packet, index)?; + RPCRequest::Hello(hello_body) + } RPCMethod::Unknown => return Err(DecodeError::UnknownRPCMethod), }; @@ -97,8 +94,8 @@ fn decode(packet: Vec) -> Result { else { let result = match RPCMethod::from(method_id) { RPCMethod::Hello => { - let (hello_response, _index) = HelloResponse::ssz_decode(&packet, index)?; - RPCResponse::HelloResponse(hello_response) + let (body, _index) = HelloBody::ssz_decode(&packet, index)?; + RPCResponse::Hello(body) } RPCMethod::Unknown => return Err(DecodeError::UnknownRPCMethod), }; @@ -137,8 +134,8 @@ impl Encodable for RpcEvent { s.append(id); s.append(method_id); match body { - RPCRequest::HelloRequest => {} - } + RPCRequest::Hello(body) => s.append(body), + }; } RpcEvent::Response { id, @@ -149,7 +146,7 @@ impl Encodable for RpcEvent { s.append(id); s.append(method_id); match result { - RPCResponse::HelloResponse(response) => { + RPCResponse::Hello(response) => { s.append(response); } } From 9803ab30f291405ce19310d27679d4736648c1fe Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sun, 17 Mar 2019 21:49:56 +1100 Subject: [PATCH 19/62] Propagate RPC through network service. - Basic network message handler threading - Correct references --- beacon_node/client/src/lib.rs | 2 +- beacon_node/libp2p/src/behaviour.rs | 29 ++-------------- beacon_node/libp2p/src/lib.rs | 4 ++- beacon_node/libp2p/src/rpc/methods.rs | 6 ++-- beacon_node/libp2p/src/rpc/mod.rs | 2 +- beacon_node/libp2p/src/rpc/protocol.rs | 6 ++-- beacon_node/libp2p/src/service.rs | 8 +++-- beacon_node/network/src/message_handler.rs | 39 ++++++++++++++++++---- beacon_node/network/src/messages.rs | 15 ++------- beacon_node/network/src/service.rs | 15 +++++++-- beacon_node/src/run.rs | 2 +- 11 files changed, 68 insertions(+), 60 deletions(-) diff --git a/beacon_node/client/src/lib.rs b/beacon_node/client/src/lib.rs index 6600c9e39b..7312cc6c8c 100644 --- a/beacon_node/client/src/lib.rs +++ b/beacon_node/client/src/lib.rs @@ -34,7 +34,7 @@ impl Client { pub fn new( config: ClientConfig, log: slog::Logger, - executor: TaskExecutor, + executor: &TaskExecutor, ) -> error::Result { let (exit_signal, exit) = exit_future::signal(); diff --git a/beacon_node/libp2p/src/behaviour.rs b/beacon_node/libp2p/src/behaviour.rs index 2c0371095f..96355cf3fa 100644 --- a/beacon_node/libp2p/src/behaviour.rs +++ b/beacon_node/libp2p/src/behaviour.rs @@ -1,4 +1,4 @@ -use crate::rpc::{RPCMethod, RPCRequest, RPCResponse, Rpc, RpcEvent}; +use crate::rpc::{Rpc, RpcEvent}; use futures::prelude::*; use libp2p::{ core::swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess}, @@ -42,22 +42,7 @@ impl NetworkBehaviourEventProcess for Behaviour { fn inject_event(&mut self, event: RpcEvent) { - match event { - RpcEvent::Request { - id, - method_id, - body, - } => self.events.push(BehaviourEvent::RPCRequest { - id, - method: RPCMethod::from(method_id), - body, - }), - RpcEvent::Response { - id, - method_id, - result, - } => self.events.push(BehaviourEvent::RPCResponse { id, result }), - } + self.events.push(BehaviourEvent::RPC(event)); } } @@ -95,15 +80,7 @@ impl Behaviour { /// The types of events than can be obtained from polling the behaviour. pub enum BehaviourEvent { - RPCRequest { - id: u64, - method: RPCMethod, - body: RPCRequest, - }, - RPCResponse { - id: u64, - result: RPCResponse, - }, + RPC(RpcEvent), // TODO: This is a stub at the moment Message(String), } diff --git a/beacon_node/libp2p/src/lib.rs b/beacon_node/libp2p/src/lib.rs index 718b7fc222..69f6eb6508 100644 --- a/beacon_node/libp2p/src/lib.rs +++ b/beacon_node/libp2p/src/lib.rs @@ -5,7 +5,7 @@ pub mod behaviour; pub mod error; mod network_config; -mod rpc; +pub mod rpc; mod service; pub use libp2p::{ @@ -13,6 +13,8 @@ pub use libp2p::{ PeerId, }; pub use network_config::NetworkConfig; +pub use rpc::HelloMessage; +pub use rpc::RpcEvent; pub use service::Libp2pEvent; pub use service::Service; pub use types::multiaddr; diff --git a/beacon_node/libp2p/src/rpc/methods.rs b/beacon_node/libp2p/src/rpc/methods.rs index b6563ba649..ea9932806b 100644 --- a/beacon_node/libp2p/src/rpc/methods.rs +++ b/beacon_node/libp2p/src/rpc/methods.rs @@ -19,17 +19,17 @@ impl From for RPCMethod { #[derive(Debug, Clone)] pub enum RPCRequest { - Hello(HelloBody), + Hello(HelloMessage), } #[derive(Debug, Clone)] pub enum RPCResponse { - Hello(HelloBody), + Hello(HelloMessage), } // request/response structs for RPC methods #[derive(Encode, Decode, Clone, Debug)] -pub struct HelloBody { +pub struct HelloMessage { pub network_id: u8, pub latest_finalized_root: Hash256, pub latest_finalized_epoch: Epoch, diff --git a/beacon_node/libp2p/src/rpc/mod.rs b/beacon_node/libp2p/src/rpc/mod.rs index 4cebb1e396..3420217ce7 100644 --- a/beacon_node/libp2p/src/rpc/mod.rs +++ b/beacon_node/libp2p/src/rpc/mod.rs @@ -11,7 +11,7 @@ use libp2p::core::swarm::{ ConnectedPoint, NetworkBehaviour, NetworkBehaviourAction, PollParameters, }; use libp2p::{Multiaddr, PeerId}; -pub use methods::{RPCMethod, RPCRequest, RPCResponse}; +pub use methods::{HelloMessage, RPCMethod, RPCRequest, RPCResponse}; pub use protocol::{RPCProtocol, RpcEvent}; use std::marker::PhantomData; use tokio::io::{AsyncRead, AsyncWrite}; diff --git a/beacon_node/libp2p/src/rpc/protocol.rs b/beacon_node/libp2p/src/rpc/protocol.rs index 4b462bb77c..74b8322eb0 100644 --- a/beacon_node/libp2p/src/rpc/protocol.rs +++ b/beacon_node/libp2p/src/rpc/protocol.rs @@ -1,4 +1,4 @@ -use super::methods::{HelloBody, RPCMethod, RPCRequest, RPCResponse}; +use super::methods::{HelloMessage, RPCMethod, RPCRequest, RPCResponse}; use libp2p::core::{upgrade, InboundUpgrade, OutboundUpgrade, UpgradeInfo}; use ssz::{ssz_encode, Decodable, Encodable, SszStream}; use std::io; @@ -78,7 +78,7 @@ fn decode(packet: Vec) -> Result { if request { let body = match RPCMethod::from(method_id) { RPCMethod::Hello => { - let (hello_body, _index) = HelloBody::ssz_decode(&packet, index)?; + let (hello_body, _index) = HelloMessage::ssz_decode(&packet, index)?; RPCRequest::Hello(hello_body) } RPCMethod::Unknown => return Err(DecodeError::UnknownRPCMethod), @@ -94,7 +94,7 @@ fn decode(packet: Vec) -> Result { else { let result = match RPCMethod::from(method_id) { RPCMethod::Hello => { - let (body, _index) = HelloBody::ssz_decode(&packet, index)?; + let (body, _index) = HelloMessage::ssz_decode(&packet, index)?; RPCResponse::Hello(body) } RPCMethod::Unknown => return Err(DecodeError::UnknownRPCMethod), diff --git a/beacon_node/libp2p/src/service.rs b/beacon_node/libp2p/src/service.rs index 00c11101c3..a672e153b8 100644 --- a/beacon_node/libp2p/src/service.rs +++ b/beacon_node/libp2p/src/service.rs @@ -1,6 +1,7 @@ use crate::behaviour::{Behaviour, BehaviourEvent}; use crate::error; use crate::multiaddr::Protocol; +use crate::rpc::RpcEvent; use crate::NetworkConfig; use futures::prelude::*; use futures::Stream; @@ -104,8 +105,9 @@ impl Stream for Service { debug!(self.log, "Message received: {}", m); return Ok(Async::Ready(Some(Libp2pEvent::Message(m)))); } - // TODO: Fill with all behaviour events - _ => break, + Ok(Async::Ready(Some(BehaviourEvent::RPC(event)))) => { + return Ok(Async::Ready(Some(Libp2pEvent::RPC(event)))); + } Ok(Async::Ready(None)) => unreachable!("Swarm stream shouldn't end"), Ok(Async::NotReady) => break, _ => break, @@ -152,5 +154,7 @@ fn build_transport( /// Events that can be obtained from polling the Libp2p Service. pub enum Libp2pEvent { + // We have received an RPC event on the swarm + RPC(RpcEvent), Message(String), } diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index 87935e8996..fe9780ad52 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -1,7 +1,10 @@ use crate::error; use crate::messages::NodeMessage; -use crossbeam_channel::{unbounded as channel, Sender}; -use libp2p::PeerId; +use crossbeam_channel::{unbounded as channel, Sender, TryRecvError}; +use futures::future; +use futures::prelude::*; +use libp2p::rpc; +use libp2p::{PeerId, RpcEvent}; use slog::debug; use sync::SimpleSync; use types::Hash256; @@ -11,9 +14,11 @@ pub struct MessageHandler { sync: SimpleSync, //TODO: Implement beacon chain //chain: BeaconChain + log: slog::Logger, } /// Types of messages the handler can receive. +#[derive(Debug, Clone)] pub enum HandlerMessage { /// Peer has connected. PeerConnected(PeerId), @@ -21,11 +26,16 @@ pub enum HandlerMessage { PeerDisconnected(PeerId), /// A Node message has been received. Message(PeerId, NodeMessage), + /// An RPC response/request has been received. + RPC(RpcEvent), } impl MessageHandler { /// Initializes and runs the MessageHandler. - pub fn new(log: slog::Logger) -> error::Result> { + pub fn new( + executor: &tokio::runtime::TaskExecutor, + log: slog::Logger, + ) -> error::Result> { debug!(log, "Service starting"); let (handler_send, handler_recv) = channel(); @@ -33,12 +43,29 @@ impl MessageHandler { // Initialise sync and begin processing in thread //TODO: Load genesis from BeaconChain let temp_genesis = Hash256::zero(); + + // generate the Message handler let sync = SimpleSync::new(temp_genesis); + //TODO: Initialise beacon chain + let mut handler = MessageHandler { + sync, + log: log.clone(), + }; - let handler = MessageHandler { sync }; - - // spawn handler thread + // spawn handler task + // TODO: Handle manual termination of thread + executor.spawn(future::poll_fn(move || -> Result<_, _> { + loop { + handler.handle_message(handler_recv.recv().map_err(|_| { + debug!(log, "Handler channel closed. Handler terminating"); + })?); + } + })); Ok(handler_send) } + + fn handle_message(&mut self, message: HandlerMessage) { + debug!(self.log, "Message received {:?}", message); + } } diff --git a/beacon_node/network/src/messages.rs b/beacon_node/network/src/messages.rs index d3a83fd5c8..064424a87f 100644 --- a/beacon_node/network/src/messages.rs +++ b/beacon_node/network/src/messages.rs @@ -1,27 +1,16 @@ use libp2p::PeerId; +use libp2p::{HelloMessage, RpcEvent}; use types::{Hash256, Slot}; /// Messages between nodes across the network. #[derive(Debug, Clone)] pub enum NodeMessage { - Status(Status), + RPC(RpcEvent), BlockRequest, // TODO: only for testing - remove Message(String), } -#[derive(Debug, Clone)] -pub struct Status { - /// Current node version. - version: u8, - /// Genesis Hash. - genesis_hash: Hash256, - /// Best known slot number. - best_slot: Slot, - /// Best known slot hash. - best_slot_hash: Hash256, -} - /// Types of messages that the network service can receive. #[derive(Debug, Clone)] pub enum NetworkMessage { diff --git a/beacon_node/network/src/service.rs b/beacon_node/network/src/service.rs index e75b7e49a8..bd01027e96 100644 --- a/beacon_node/network/src/service.rs +++ b/beacon_node/network/src/service.rs @@ -28,12 +28,12 @@ pub struct Service { impl Service { pub fn new( config: NetworkConfig, - executor: TaskExecutor, + executor: &TaskExecutor, log: slog::Logger, ) -> error::Result<(Arc, Sender)> { // launch message handler thread let message_handler_log = log.new(o!("Service" => "MessageHandler")); - let message_handler_send = MessageHandler::new(message_handler_log)?; + let message_handler_send = MessageHandler::new(executor, message_handler_log)?; // launch libp2p service let libp2p_log = log.new(o!("Service" => "Libp2p")); @@ -61,7 +61,7 @@ impl Service { fn spawn_service( libp2p_service: LibP2PService, message_handler_send: crossbeam_channel::Sender, - executor: TaskExecutor, + executor: &TaskExecutor, log: slog::Logger, ) -> error::Result<( crossbeam_channel::Sender, @@ -99,6 +99,15 @@ fn network_service( // poll the swarm loop { match libp2p_service.poll() { + Ok(Async::Ready(Some(Libp2pEvent::RPC(rpc_event)))) => { + debug!( + libp2p_service.log, + "RPC Event: Rpc message received: {:?}", rpc_event + ); + message_handler_send + .send(HandlerMessage::RPC(rpc_event)) + .map_err(|_| "failed to send rpc to handler"); + } Ok(Async::Ready(Some(Libp2pEvent::Message(m)))) => debug!( libp2p_service.log, "Network Service: Message received: {}", m diff --git a/beacon_node/src/run.rs b/beacon_node/src/run.rs index 12d761d84c..810f2aeafd 100644 --- a/beacon_node/src/run.rs +++ b/beacon_node/src/run.rs @@ -32,7 +32,7 @@ pub fn run_beacon_node(config: ClientConfig, log: slog::Logger) -> error::Result let executor = runtime.executor(); // currently testing - using TestingNode type - let client: Client = Client::new(config, log.clone(), executor.clone())?; + let client: Client = Client::new(config, log.clone(), &executor)?; notifier::run(&client, executor, exit); runtime.block_on(ctrlc); From 2e0c8e2e479ea9e22a303681d697a74cf6ca98ee Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sun, 17 Mar 2019 23:14:28 +1100 Subject: [PATCH 20/62] Handle peer dials and propagate to message handler --- beacon_node/libp2p/src/behaviour.rs | 20 ++++++---- beacon_node/libp2p/src/lib.rs | 3 +- beacon_node/libp2p/src/rpc/mod.rs | 44 ++++++++++++++++------ beacon_node/libp2p/src/rpc/protocol.rs | 22 +++++------ beacon_node/libp2p/src/service.rs | 10 +++-- beacon_node/network/src/message_handler.rs | 16 ++++++-- beacon_node/network/src/messages.rs | 4 +- beacon_node/network/src/service.rs | 6 +++ 8 files changed, 84 insertions(+), 41 deletions(-) diff --git a/beacon_node/libp2p/src/behaviour.rs b/beacon_node/libp2p/src/behaviour.rs index 96355cf3fa..604b84c8f5 100644 --- a/beacon_node/libp2p/src/behaviour.rs +++ b/beacon_node/libp2p/src/behaviour.rs @@ -1,4 +1,4 @@ -use crate::rpc::{Rpc, RpcEvent}; +use crate::rpc::{RPCEvent, RPCMessage, Rpc}; use futures::prelude::*; use libp2p::{ core::swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess}, @@ -38,19 +38,24 @@ impl NetworkBehaviourEventProcess NetworkBehaviourEventProcess +impl NetworkBehaviourEventProcess for Behaviour { - fn inject_event(&mut self, event: RpcEvent) { - self.events.push(BehaviourEvent::RPC(event)); + fn inject_event(&mut self, event: RPCMessage) { + match event { + RPCMessage::PeerDialed(peer_id) => { + self.events.push(BehaviourEvent::PeerDialed(peer_id)) + } + RPCMessage::RPC(rpc_event) => self.events.push(BehaviourEvent::RPC(rpc_event)), + } } } impl Behaviour { - pub fn new(local_peer_id: PeerId, gs_config: GossipsubConfig) -> Self { + pub fn new(local_peer_id: PeerId, gs_config: GossipsubConfig, log: &slog::Logger) -> Self { Behaviour { gossipsub: Gossipsub::new(local_peer_id, gs_config), - serenity_rpc: Rpc::new(), + serenity_rpc: Rpc::new(log), events: Vec::new(), } } @@ -80,7 +85,8 @@ impl Behaviour { /// The types of events than can be obtained from polling the behaviour. pub enum BehaviourEvent { - RPC(RpcEvent), + RPC(RPCEvent), + PeerDialed(PeerId), // TODO: This is a stub at the moment Message(String), } diff --git a/beacon_node/libp2p/src/lib.rs b/beacon_node/libp2p/src/lib.rs index 69f6eb6508..f3e97355d7 100644 --- a/beacon_node/libp2p/src/lib.rs +++ b/beacon_node/libp2p/src/lib.rs @@ -13,8 +13,7 @@ pub use libp2p::{ PeerId, }; pub use network_config::NetworkConfig; -pub use rpc::HelloMessage; -pub use rpc::RpcEvent; +pub use rpc::{HelloMessage, RPCEvent}; pub use service::Libp2pEvent; pub use service::Service; pub use types::multiaddr; diff --git a/beacon_node/libp2p/src/rpc/mod.rs b/beacon_node/libp2p/src/rpc/mod.rs index 3420217ce7..d40e53935f 100644 --- a/beacon_node/libp2p/src/rpc/mod.rs +++ b/beacon_node/libp2p/src/rpc/mod.rs @@ -12,7 +12,8 @@ use libp2p::core::swarm::{ }; use libp2p::{Multiaddr, PeerId}; pub use methods::{HelloMessage, RPCMethod, RPCRequest, RPCResponse}; -pub use protocol::{RPCProtocol, RpcEvent}; +pub use protocol::{RPCEvent, RPCProtocol}; +use slog::{debug, o, Logger}; use std::marker::PhantomData; use tokio::io::{AsyncRead, AsyncWrite}; @@ -21,22 +22,26 @@ use tokio::io::{AsyncRead, AsyncWrite}; pub struct Rpc { /// Queue of events to processed. - events: Vec>, + events: Vec>, /// Pins the generic substream. marker: PhantomData, + /// Slog logger for RPC behaviour. + log: slog::Logger, } impl Rpc { - pub fn new() -> Self { + pub fn new(log: &slog::Logger) -> Self { + let log = log.new(o!("Service" => "Libp2p-RPC")); Rpc { events: Vec::new(), marker: PhantomData, + log, } } /// Submits and RPC request. pub fn send_request(&mut self, peer_id: PeerId, id: u64, method_id: u16, body: RPCRequest) { - let request = RpcEvent::Request { + let request = RPCEvent::Request { id, method_id, body, @@ -52,8 +57,8 @@ impl NetworkBehaviour for Rpc where TSubstream: AsyncRead + AsyncWrite, { - type ProtocolsHandler = OneShotHandler; - type OutEvent = RpcEvent; + type ProtocolsHandler = OneShotHandler; + type OutEvent = RPCMessage; fn new_handler(&mut self) -> Self::ProtocolsHandler { Default::default() @@ -63,7 +68,14 @@ where Vec::new() } - fn inject_connected(&mut self, _: PeerId, _: ConnectedPoint) {} + fn inject_connected(&mut self, peer_id: PeerId, connected_point: ConnectedPoint) { + // if initialised the connection, report this upwards to send the HELLO request + if let ConnectedPoint::Dialer { address } = connected_point { + self.events.push(NetworkBehaviourAction::GenerateEvent( + RPCMessage::PeerDialed(peer_id), + )); + } + } fn inject_disconnected(&mut self, _: &PeerId, _: ConnectedPoint) {} @@ -80,7 +92,9 @@ where // send the event to the user self.events - .push(NetworkBehaviourAction::GenerateEvent(event)); + .push(NetworkBehaviourAction::GenerateEvent(RPCMessage::RPC( + event, + ))); } fn poll( @@ -99,18 +113,24 @@ where } } -/// Transmission between the `OneShotHandler` and the `RpcEvent`. +/// Messages sent to the user from the RPC protocol. +pub enum RPCMessage { + RPC(RPCEvent), + PeerDialed(PeerId), +} + +/// Transmission between the `OneShotHandler` and the `RPCEvent`. #[derive(Debug)] pub enum OneShotEvent { /// We received an RPC from a remote. - Rx(RpcEvent), + Rx(RPCEvent), /// We successfully sent an RPC request. Sent, } -impl From for OneShotEvent { +impl From for OneShotEvent { #[inline] - fn from(rpc: RpcEvent) -> OneShotEvent { + fn from(rpc: RPCEvent) -> OneShotEvent { OneShotEvent::Rx(rpc) } } diff --git a/beacon_node/libp2p/src/rpc/protocol.rs b/beacon_node/libp2p/src/rpc/protocol.rs index 74b8322eb0..dce7144299 100644 --- a/beacon_node/libp2p/src/rpc/protocol.rs +++ b/beacon_node/libp2p/src/rpc/protocol.rs @@ -31,7 +31,7 @@ impl Default for RPCProtocol { /// The RPC types which are sent/received in this protocol. #[derive(Debug, Clone)] -pub enum RpcEvent { +pub enum RPCEvent { Request { id: u64, method_id: u16, @@ -44,7 +44,7 @@ pub enum RpcEvent { }, } -impl UpgradeInfo for RpcEvent { +impl UpgradeInfo for RPCEvent { type Info = &'static [u8]; type InfoIter = iter::Once; @@ -58,17 +58,17 @@ impl InboundUpgrade for RPCProtocol where TSocket: AsyncRead + AsyncWrite, { - type Output = RpcEvent; + type Output = RPCEvent; type Error = DecodeError; type Future = - upgrade::ReadOneThen, ()) -> Result>; + upgrade::ReadOneThen, ()) -> Result>; fn upgrade_inbound(self, socket: TSocket, _: Self::Info) -> Self::Future { upgrade::read_one_then(socket, MAX_READ_SIZE, (), |packet, ()| Ok(decode(packet)?)) } } -fn decode(packet: Vec) -> Result { +fn decode(packet: Vec) -> Result { // decode the header of the rpc // request/response let (request, index) = bool::ssz_decode(&packet, 0)?; @@ -84,7 +84,7 @@ fn decode(packet: Vec) -> Result { RPCMethod::Unknown => return Err(DecodeError::UnknownRPCMethod), }; - return Ok(RpcEvent::Request { + return Ok(RPCEvent::Request { id, method_id, body, @@ -99,7 +99,7 @@ fn decode(packet: Vec) -> Result { } RPCMethod::Unknown => return Err(DecodeError::UnknownRPCMethod), }; - return Ok(RpcEvent::Response { + return Ok(RPCEvent::Response { id, method_id, result, @@ -107,7 +107,7 @@ fn decode(packet: Vec) -> Result { } } -impl OutboundUpgrade for RpcEvent +impl OutboundUpgrade for RPCEvent where TSocket: AsyncWrite, { @@ -122,10 +122,10 @@ where } } -impl Encodable for RpcEvent { +impl Encodable for RPCEvent { fn ssz_append(&self, s: &mut SszStream) { match self { - RpcEvent::Request { + RPCEvent::Request { id, method_id, body, @@ -137,7 +137,7 @@ impl Encodable for RpcEvent { RPCRequest::Hello(body) => s.append(body), }; } - RpcEvent::Response { + RPCEvent::Response { id, method_id, result, diff --git a/beacon_node/libp2p/src/service.rs b/beacon_node/libp2p/src/service.rs index a672e153b8..dd6deabadb 100644 --- a/beacon_node/libp2p/src/service.rs +++ b/beacon_node/libp2p/src/service.rs @@ -1,7 +1,7 @@ use crate::behaviour::{Behaviour, BehaviourEvent}; use crate::error; use crate::multiaddr::Protocol; -use crate::rpc::RpcEvent; +use crate::rpc::RPCEvent; use crate::NetworkConfig; use futures::prelude::*; use futures::Stream; @@ -41,7 +41,7 @@ impl Service { // Set up the transport let transport = build_transport(local_private_key); // Set up gossipsub routing - let behaviour = Behaviour::new(local_peer_id.clone(), config.gs_config); + let behaviour = Behaviour::new(local_peer_id.clone(), config.gs_config, &log); // Set up Topology let topology = local_peer_id.clone(); Swarm::new(transport, behaviour, topology) @@ -108,6 +108,9 @@ impl Stream for Service { Ok(Async::Ready(Some(BehaviourEvent::RPC(event)))) => { return Ok(Async::Ready(Some(Libp2pEvent::RPC(event)))); } + Ok(Async::Ready(Some(BehaviourEvent::PeerDialed(peer_id)))) => { + return Ok(Async::Ready(Some(Libp2pEvent::PeerDialed(peer_id)))); + } Ok(Async::Ready(None)) => unreachable!("Swarm stream shouldn't end"), Ok(Async::NotReady) => break, _ => break, @@ -155,6 +158,7 @@ fn build_transport( /// Events that can be obtained from polling the Libp2p Service. pub enum Libp2pEvent { // We have received an RPC event on the swarm - RPC(RpcEvent), + RPC(RPCEvent), + PeerDialed(PeerId), Message(String), } diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index fe9780ad52..c059795ed4 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -4,30 +4,37 @@ use crossbeam_channel::{unbounded as channel, Sender, TryRecvError}; use futures::future; use futures::prelude::*; use libp2p::rpc; -use libp2p::{PeerId, RpcEvent}; +use libp2p::{PeerId, RPCEvent}; use slog::debug; +use std::collections::HashMap; +use std::time::{Duration, Instant}; use sync::SimpleSync; use types::Hash256; +/// Timeout for establishing a HELLO handshake. +const HELLO_TIMEOUT: Duration = Duration::from_secs(30); + /// Handles messages received from the network and client and organises syncing. pub struct MessageHandler { sync: SimpleSync, //TODO: Implement beacon chain //chain: BeaconChain + /// A mapping of peers we have sent a HELLO rpc request to + hello_requests: HashMap, log: slog::Logger, } /// Types of messages the handler can receive. #[derive(Debug, Clone)] pub enum HandlerMessage { - /// Peer has connected. - PeerConnected(PeerId), + /// We have initiated a connection to a new peer. + PeerDialed(PeerId), /// Peer has disconnected, PeerDisconnected(PeerId), /// A Node message has been received. Message(PeerId, NodeMessage), /// An RPC response/request has been received. - RPC(RpcEvent), + RPC(RPCEvent), } impl MessageHandler { @@ -49,6 +56,7 @@ impl MessageHandler { //TODO: Initialise beacon chain let mut handler = MessageHandler { sync, + hello_requests: HashMap::new(), log: log.clone(), }; diff --git a/beacon_node/network/src/messages.rs b/beacon_node/network/src/messages.rs index 064424a87f..930c90b3e4 100644 --- a/beacon_node/network/src/messages.rs +++ b/beacon_node/network/src/messages.rs @@ -1,11 +1,11 @@ use libp2p::PeerId; -use libp2p::{HelloMessage, RpcEvent}; +use libp2p::{HelloMessage, RPCEvent}; use types::{Hash256, Slot}; /// Messages between nodes across the network. #[derive(Debug, Clone)] pub enum NodeMessage { - RPC(RpcEvent), + RPC(RPCEvent), BlockRequest, // TODO: only for testing - remove Message(String), diff --git a/beacon_node/network/src/service.rs b/beacon_node/network/src/service.rs index bd01027e96..fc91cf53a2 100644 --- a/beacon_node/network/src/service.rs +++ b/beacon_node/network/src/service.rs @@ -108,6 +108,12 @@ fn network_service( .send(HandlerMessage::RPC(rpc_event)) .map_err(|_| "failed to send rpc to handler"); } + Ok(Async::Ready(Some(Libp2pEvent::PeerDialed(peer_id)))) => { + debug!(libp2p_service.log, "Peer Dialed: {:?}", peer_id); + message_handler_send + .send(HandlerMessage::PeerDialed(peer_id)) + .map_err(|_| "failed to send rpc to handler"); + } Ok(Async::Ready(Some(Libp2pEvent::Message(m)))) => debug!( libp2p_service.log, "Network Service: Message received: {}", m From bbad4bfa19854d63bbc3237d4d4e0dea45f70bdb Mon Sep 17 00:00:00 2001 From: Age Manning Date: Mon, 18 Mar 2019 16:16:54 +1100 Subject: [PATCH 21/62] Starts initialisation of beacon chain in the client --- beacon_node/beacon_chain/src/initialise.rs | 146 +++++++++++++++++++++ beacon_node/beacon_chain/src/initialize.rs | 56 -------- beacon_node/beacon_chain/src/lib.rs | 1 + beacon_node/client/src/client_types.rs | 18 ++- beacon_node/client/src/lib.rs | 17 ++- beacon_node/network/Cargo.toml | 1 + beacon_node/network/src/message_handler.rs | 27 +++- beacon_node/network/src/service.rs | 11 +- beacon_node/src/run.rs | 2 +- eth2/types/src/chain_spec.rs | 8 +- 10 files changed, 207 insertions(+), 80 deletions(-) create mode 100644 beacon_node/beacon_chain/src/initialise.rs delete mode 100644 beacon_node/beacon_chain/src/initialize.rs diff --git a/beacon_node/beacon_chain/src/initialise.rs b/beacon_node/beacon_chain/src/initialise.rs new file mode 100644 index 0000000000..131782470b --- /dev/null +++ b/beacon_node/beacon_chain/src/initialise.rs @@ -0,0 +1,146 @@ +// Initialisation functions to generate a new BeaconChain. +// Note: A new version of ClientTypes may need to be implemented for the lighthouse +// testnet. These are examples. Also. there is code duplication which can/should be cleaned up. + +use crate::BeaconChain; +use bls; +use db::stores::{BeaconBlockStore, BeaconStateStore}; +use db::{DiskDB, MemoryDB}; +use fork_choice::BitwiseLMDGhost; +use slot_clock::SystemTimeSlotClock; +use std::path::PathBuf; +use std::sync::Arc; +use types::{ChainSpec, Deposit, DepositData, DepositInput, Eth1Data, Hash256, Keypair}; + +//TODO: Correct this for prod +//TODO: Account for historical db +pub fn initialise_beacon_chain( + chain_spec: &ChainSpec, + db_name: Option<&PathBuf>, +) -> Arc>> { + // set up the db + let db = Arc::new(DiskDB::open( + db_name.expect("Database directory must be included"), + None, + )); + let block_store = Arc::new(BeaconBlockStore::new(db.clone())); + let state_store = Arc::new(BeaconStateStore::new(db.clone())); + + // Slot clock + let genesis_time = 1_549_935_547; // 12th Feb 2018 (arbitrary value in the past). + let slot_clock = SystemTimeSlotClock::new(genesis_time, chain_spec.seconds_per_slot) + .expect("Unable to load SystemTimeSlotClock"); + // Choose the fork choice + let fork_choice = BitwiseLMDGhost::new(block_store.clone(), state_store.clone()); + + /* + * Generate some random data to start a chain with. + * + * This is will need to be replace for production usage. + */ + let latest_eth1_data = Eth1Data { + deposit_root: Hash256::zero(), + block_hash: Hash256::zero(), + }; + let keypairs: Vec = (0..10) + .collect::>() + .iter() + .map(|_| Keypair::random()) + .collect(); + let initial_validator_deposits = keypairs + .iter() + .map(|keypair| Deposit { + branch: vec![], // branch verification is not chain_specified. + index: 0, // index verification is not chain_specified. + deposit_data: DepositData { + amount: 32_000_000_000, // 32 ETH (in Gwei) + timestamp: genesis_time - 1, + deposit_input: DepositInput { + pubkey: keypair.pk.clone(), + withdrawal_credentials: Hash256::zero(), // Withdrawal not possible. + proof_of_possession: bls::create_proof_of_possession(&keypair), + }, + }, + }) + .collect(); + + // Genesis chain + // TODO:Remove the expect here. Propagate errors and handle somewhat gracefully. + Arc::new( + BeaconChain::genesis( + state_store.clone(), + block_store.clone(), + slot_clock, + genesis_time, + latest_eth1_data, + initial_validator_deposits, + chain_spec.clone(), + fork_choice, + ) + .expect("Cannot initialise a beacon chain. Exiting"), + ) +} + +/// Initialisation of a test beacon chain, uses an in memory db with fixed genesis time. +pub fn initialise_test_beacon_chain( + chain_spec: &ChainSpec, + _db_name: Option<&PathBuf>, +) -> Arc>> { + let db = Arc::new(MemoryDB::open()); + let block_store = Arc::new(BeaconBlockStore::new(db.clone())); + let state_store = Arc::new(BeaconStateStore::new(db.clone())); + + // Slot clock + let genesis_time = 1_549_935_547; // 12th Feb 2018 (arbitrary value in the past). + let slot_clock = SystemTimeSlotClock::new(genesis_time, chain_spec.seconds_per_slot) + .expect("Unable to load SystemTimeSlotClock"); + // Choose the fork choice + let fork_choice = BitwiseLMDGhost::new(block_store.clone(), state_store.clone()); + + /* + * Generate some random data to start a chain with. + * + * This is will need to be replace for production usage. + */ + let latest_eth1_data = Eth1Data { + deposit_root: Hash256::zero(), + block_hash: Hash256::zero(), + }; + let keypairs: Vec = (0..10) + .collect::>() + .iter() + .map(|_| Keypair::random()) + .collect(); + let initial_validator_deposits = keypairs + .iter() + .map(|keypair| Deposit { + branch: vec![], // branch verification is not chain_specified. + index: 0, // index verification is not chain_specified. + deposit_data: DepositData { + amount: 32_000_000_000, // 32 ETH (in Gwei) + timestamp: genesis_time - 1, + deposit_input: DepositInput { + pubkey: keypair.pk.clone(), + withdrawal_credentials: Hash256::zero(), // Withdrawal not possible. + proof_of_possession: bls::create_proof_of_possession(&keypair), + }, + }, + }) + .collect(); + + // Genesis chain + // TODO: Handle error correctly + Arc::new( + BeaconChain::genesis( + state_store.clone(), + block_store.clone(), + slot_clock, + genesis_time, + latest_eth1_data, + initial_validator_deposits, + chain_spec.clone(), + fork_choice, + ) + .expect("Cannot generate beacon chain"), + ) +} diff --git a/beacon_node/beacon_chain/src/initialize.rs b/beacon_node/beacon_chain/src/initialize.rs deleted file mode 100644 index 14d0f81a67..0000000000 --- a/beacon_node/beacon_chain/src/initialize.rs +++ /dev/null @@ -1,56 +0,0 @@ -// Initialisation functions to generate a new BeaconChain. - -pub fn initialise_test_chain( - config: &ClientConfig, -) -> Arc> { - let spec = config.spec; - // Slot clock - let genesis_time = 1_549_935_547; // 12th Feb 2018 (arbitrary value in the past). - let slot_clock = SystemTimeSlotClock::new(genesis_time, spec.slot_duration) - .expect("Unable to load SystemTimeSlotClock"); - // Choose the fork choice - let fork_choice = BitwiseLMDGhost::new(block_store.clone(), state_store.clone()); - - /* - * Generate some random data to start a chain with. - * - * This is will need to be replace for production usage. - */ - let latest_eth1_data = Eth1Data { - deposit_root: Hash256::zero(), - block_hash: Hash256::zero(), - }; - let keypairs: Vec = (0..10) - .collect::>() - .iter() - .map(|_| Keypair::random()) - .collect(); - let initial_validator_deposits = keypairs - .iter() - .map(|keypair| Deposit { - branch: vec![], // branch verification is not specified. - index: 0, // index verification is not specified. - deposit_data: DepositData { - amount: 32_000_000_000, // 32 ETH (in Gwei) - timestamp: genesis_time - 1, - deposit_input: DepositInput { - pubkey: keypair.pk.clone(), - withdrawal_credentials: Hash256::zero(), // Withdrawal not possible. - proof_of_possession: create_proof_of_possession(&keypair), - }, - }, - }) - .collect(); - - // Genesis chain - Arc::new(BeaconChain::genesis( - state_store.clone(), - block_store.clone(), - slot_clock, - genesis_time, - latest_eth1_data, - initial_validator_deposits, - spec, - fork_choice, - )); -} diff --git a/beacon_node/beacon_chain/src/lib.rs b/beacon_node/beacon_chain/src/lib.rs index 0e879a4151..89ee2029c0 100644 --- a/beacon_node/beacon_chain/src/lib.rs +++ b/beacon_node/beacon_chain/src/lib.rs @@ -2,6 +2,7 @@ mod attestation_aggregator; mod beacon_chain; mod checkpoint; mod errors; +pub mod initialise; pub use self::beacon_chain::{BeaconChain, BlockProcessingOutcome, InvalidBlock, ValidBlock}; pub use self::checkpoint::CheckPoint; diff --git a/beacon_node/client/src/client_types.rs b/beacon_node/client/src/client_types.rs index 38ae1c8c38..744c9ab98b 100644 --- a/beacon_node/client/src/client_types.rs +++ b/beacon_node/client/src/client_types.rs @@ -1,25 +1,39 @@ use db::{ClientDB, DiskDB, MemoryDB}; use fork_choice::{BitwiseLMDGhost, ForkChoice}; use slot_clock::{SlotClock, SystemTimeSlotClock, TestingSlotClock}; +use beacon_chain::initialise; +use std::sync::Arc; +use crate::ClientConfig pub trait ClientTypes { type ForkChoice: ForkChoice; type DB: ClientDB; type SlotClock: SlotClock; + + pub fn initialise_beacon_chain(cchain_spec: &ClientConfig) -> Arc>); } -pub struct StandardClientType {} +pub struct StandardClientType impl ClientTypes for StandardClientType { type DB = DiskDB; type ForkChoice = BitwiseLMDGhost; type SlotClock = SystemTimeSlotClock; + + pub fn initialise_beacon_chain(config: &ClientConfig) -> Arc>) { + initialise::initialise_beacon_chain(config.chain_spec, config.db_name) + } + } -pub struct TestingClientType {} +pub struct TestingClientType impl ClientTypes for TestingClientType { type DB = MemoryDB; type SlotClock = TestingSlotClock; type ForkChoice = BitwiseLMDGhost; + + pub fn initialise_beacon_chain(config: &ClientConfig) -> Arc>) { + initialise::initialise_test_beacon_chain(config.chain_spec, None) + } } diff --git a/beacon_node/client/src/lib.rs b/beacon_node/client/src/lib.rs index 7312cc6c8c..46221c200b 100644 --- a/beacon_node/client/src/lib.rs +++ b/beacon_node/client/src/lib.rs @@ -21,31 +21,36 @@ use tokio::runtime::TaskExecutor; /// sub-services in multiple threads. pub struct Client { config: ClientConfig, - // beacon_chain: Arc>, + beacon_chain: Arc>, pub network: Arc, pub exit: exit_future::Exit, pub exit_signal: Signal, log: slog::Logger, - phantom: PhantomData, } impl Client { /// Generate an instance of the client. Spawn and link all internal subprocesses. pub fn new( config: ClientConfig, + client_type: T, log: slog::Logger, executor: &TaskExecutor, ) -> error::Result { let (exit_signal, exit) = exit_future::signal(); - // TODO: generate a beacon_chain service. + // generate a beacon chain + let beacon_chain = client_type.initialise_beacon_chain(&config); // Start the network service, libp2p and syncing threads // TODO: Add beacon_chain reference to network parameters - let network_config = config.net_conf.clone(); + let network_config = &config.net_conf; let network_logger = log.new(o!("Service" => "Network")); - let (network, network_send) = - NetworkService::new(network_config, executor, network_logger)?; + let (network, network_send) = NetworkService::new( + beacon_chain.clone(), + network_config, + executor, + network_logger, + )?; Ok(Client { config, diff --git a/beacon_node/network/Cargo.toml b/beacon_node/network/Cargo.toml index 19d3e82ad4..f1a7ed2589 100644 --- a/beacon_node/network/Cargo.toml +++ b/beacon_node/network/Cargo.toml @@ -5,6 +5,7 @@ authors = ["Age Manning "] edition = "2018" [dependencies] +beacon_chain = { path = "../beacon_chain" } libp2p = { path = "../libp2p" } version = { path = "../version" } types = { path = "../../eth2/types" } diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index c059795ed4..4ebedb89a3 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -1,5 +1,6 @@ use crate::error; use crate::messages::NodeMessage; +use beacon_chain::BeaconChain; use crossbeam_channel::{unbounded as channel, Sender, TryRecvError}; use futures::future; use futures::prelude::*; @@ -7,6 +8,7 @@ use libp2p::rpc; use libp2p::{PeerId, RPCEvent}; use slog::debug; use std::collections::HashMap; +use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; use sync::SimpleSync; use types::Hash256; @@ -15,12 +17,14 @@ use types::Hash256; const HELLO_TIMEOUT: Duration = Duration::from_secs(30); /// Handles messages received from the network and client and organises syncing. -pub struct MessageHandler { +pub struct MessageHandler { + /// Currently loaded and initialised beacon chain. + chain: BeaconChain, + /// The syncing framework. sync: SimpleSync, - //TODO: Implement beacon chain - //chain: BeaconChain - /// A mapping of peers we have sent a HELLO rpc request to + /// A mapping of peers we have sent a HELLO rpc request to. hello_requests: HashMap, + /// The `MessageHandler` logger. log: slog::Logger, } @@ -37,9 +41,10 @@ pub enum HandlerMessage { RPC(RPCEvent), } -impl MessageHandler { +impl MessageHandler { /// Initializes and runs the MessageHandler. pub fn new( + beacon_chain: Arc>, executor: &tokio::runtime::TaskExecutor, log: slog::Logger, ) -> error::Result> { @@ -49,12 +54,13 @@ impl MessageHandler { // Initialise sync and begin processing in thread //TODO: Load genesis from BeaconChain + //TODO: Initialise beacon chain let temp_genesis = Hash256::zero(); // generate the Message handler let sync = SimpleSync::new(temp_genesis); - //TODO: Initialise beacon chain let mut handler = MessageHandler { + chain: beacon_chain, sync, hello_requests: HashMap::new(), log: log.clone(), @@ -74,6 +80,13 @@ impl MessageHandler { } fn handle_message(&mut self, message: HandlerMessage) { - debug!(self.log, "Message received {:?}", message); + match message { + HandlerMessage::PeerDialed(peer_id) => self.send_hello(peer_id), + //TODO: Handle all messages + _ => {} + } } + + /// Sends a HELLO RPC request to a newly connected peer. + fn send_hello(&self, peer_id: PeerId) {} } diff --git a/beacon_node/network/src/service.rs b/beacon_node/network/src/service.rs index fc91cf53a2..6b9c0aff0a 100644 --- a/beacon_node/network/src/service.rs +++ b/beacon_node/network/src/service.rs @@ -15,25 +15,28 @@ use libp2p::{Libp2pEvent, PeerId}; use slog::{debug, info, o, trace, warn, Logger}; use std::sync::{Arc, Mutex}; use tokio::runtime::TaskExecutor; +use client::ClientTypes; /// Service that handles communication between internal services and the libp2p network service. -pub struct Service { +pub struct Service { //libp2p_service: Arc>, libp2p_exit: oneshot::Sender<()>, network_send: crossbeam_channel::Sender, //message_handler: MessageHandler, //message_handler_send: Sender, + PhantomData: T, } -impl Service { +impl Service { pub fn new( - config: NetworkConfig, + beacon_chain: Arc, + config: &NetworkConfig, executor: &TaskExecutor, log: slog::Logger, ) -> error::Result<(Arc, Sender)> { // launch message handler thread let message_handler_log = log.new(o!("Service" => "MessageHandler")); - let message_handler_send = MessageHandler::new(executor, message_handler_log)?; + let message_handler_send = MessageHandler::new(beacon_chain, executor, message_handler_log)?; // launch libp2p service let libp2p_log = log.new(o!("Service" => "Libp2p")); diff --git a/beacon_node/src/run.rs b/beacon_node/src/run.rs index 810f2aeafd..b7cbf5421c 100644 --- a/beacon_node/src/run.rs +++ b/beacon_node/src/run.rs @@ -31,7 +31,7 @@ pub fn run_beacon_node(config: ClientConfig, log: slog::Logger) -> error::Result let executor = runtime.executor(); - // currently testing - using TestingNode type + // currently testing - using TestingClientType let client: Client = Client::new(config, log.clone(), &executor)?; notifier::run(&client, executor, exit); diff --git a/eth2/types/src/chain_spec.rs b/eth2/types/src/chain_spec.rs index ef2c94d653..c6093231b4 100644 --- a/eth2/types/src/chain_spec.rs +++ b/eth2/types/src/chain_spec.rs @@ -257,10 +257,10 @@ impl ChainSpec { .parse() .expect("correct multiaddr")]; - let mut standard_spec = ChainSpec::foundation(); - standard_spec.boot_nodes = boot_nodes; - - standard_spec + Self { + boot_nodes, + ..ChainSpec::foundation() + } } /// Returns a `ChainSpec` compatible with the specification suitable for 8 validators. From 6b5debe654fce0cca60e5a14cbbc54d2983e5b65 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Mon, 18 Mar 2019 17:38:23 +1100 Subject: [PATCH 22/62] Organize beacon_chain typing - Implements ClientTypes - New network BeaconChain type for the networking service --- beacon_node/beacon_chain/src/initialise.rs | 2 +- beacon_node/beacon_chain/src/lib.rs | 5 ++- beacon_node/client/src/client_types.rs | 46 +++++++++++++--------- beacon_node/client/src/lib.rs | 19 +++++++-- beacon_node/network/src/beacon_chain.rs | 27 +++++++++++++ beacon_node/network/src/lib.rs | 1 + beacon_node/network/src/message_handler.rs | 16 ++++---- beacon_node/network/src/service.rs | 22 +++++------ 8 files changed, 93 insertions(+), 45 deletions(-) create mode 100644 beacon_node/network/src/beacon_chain.rs diff --git a/beacon_node/beacon_chain/src/initialise.rs b/beacon_node/beacon_chain/src/initialise.rs index 131782470b..a8289a062e 100644 --- a/beacon_node/beacon_chain/src/initialise.rs +++ b/beacon_node/beacon_chain/src/initialise.rs @@ -106,7 +106,7 @@ pub fn initialise_test_beacon_chain( deposit_root: Hash256::zero(), block_hash: Hash256::zero(), }; - let keypairs: Vec = (0..10) + let keypairs: Vec = (0..50) .collect::>() .iter() .map(|_| Keypair::random()) diff --git a/beacon_node/beacon_chain/src/lib.rs b/beacon_node/beacon_chain/src/lib.rs index 89ee2029c0..5acac6ff22 100644 --- a/beacon_node/beacon_chain/src/lib.rs +++ b/beacon_node/beacon_chain/src/lib.rs @@ -7,4 +7,7 @@ pub mod initialise; pub use self::beacon_chain::{BeaconChain, BlockProcessingOutcome, InvalidBlock, ValidBlock}; pub use self::checkpoint::CheckPoint; pub use self::errors::BeaconChainError; -pub use fork_choice::{ForkChoice, ForkChoiceAlgorithm, ForkChoiceError}; +pub use db; +pub use fork_choice; +pub use parking_lot; +pub use slot_clock; diff --git a/beacon_node/client/src/client_types.rs b/beacon_node/client/src/client_types.rs index 744c9ab98b..de0678fe78 100644 --- a/beacon_node/client/src/client_types.rs +++ b/beacon_node/client/src/client_types.rs @@ -1,39 +1,49 @@ -use db::{ClientDB, DiskDB, MemoryDB}; -use fork_choice::{BitwiseLMDGhost, ForkChoice}; -use slot_clock::{SlotClock, SystemTimeSlotClock, TestingSlotClock}; -use beacon_chain::initialise; +use crate::ClientConfig; +use beacon_chain::{ + db::{ClientDB, DiskDB, MemoryDB}, + fork_choice::BitwiseLMDGhost, + initialise, + slot_clock::{SlotClock, SystemTimeSlotClock, TestingSlotClock}, + BeaconChain, +}; +use fork_choice::ForkChoice; + use std::sync::Arc; -use crate::ClientConfig pub trait ClientTypes { - type ForkChoice: ForkChoice; - type DB: ClientDB; - type SlotClock: SlotClock; + type DB: ClientDB + 'static; + type SlotClock: SlotClock + 'static; + type ForkChoice: ForkChoice + 'static; - pub fn initialise_beacon_chain(cchain_spec: &ClientConfig) -> Arc>); + fn initialise_beacon_chain( + config: &ClientConfig, + ) -> Arc>; } -pub struct StandardClientType +pub struct StandardClientType; impl ClientTypes for StandardClientType { type DB = DiskDB; - type ForkChoice = BitwiseLMDGhost; type SlotClock = SystemTimeSlotClock; + type ForkChoice = BitwiseLMDGhost; - pub fn initialise_beacon_chain(config: &ClientConfig) -> Arc>) { - initialise::initialise_beacon_chain(config.chain_spec, config.db_name) + fn initialise_beacon_chain( + config: &ClientConfig, + ) -> Arc> { + initialise::initialise_beacon_chain(&config.spec, Some(&config.db_name)) } - } -pub struct TestingClientType +pub struct TestingClientType; impl ClientTypes for TestingClientType { type DB = MemoryDB; - type SlotClock = TestingSlotClock; + type SlotClock = SystemTimeSlotClock; type ForkChoice = BitwiseLMDGhost; - pub fn initialise_beacon_chain(config: &ClientConfig) -> Arc>) { - initialise::initialise_test_beacon_chain(config.chain_spec, None) + fn initialise_beacon_chain( + config: &ClientConfig, + ) -> Arc> { + initialise::initialise_test_beacon_chain(&config.spec, None) } } diff --git a/beacon_node/client/src/lib.rs b/beacon_node/client/src/lib.rs index 46221c200b..f3178eaa66 100644 --- a/beacon_node/client/src/lib.rs +++ b/beacon_node/client/src/lib.rs @@ -10,6 +10,7 @@ pub use client_config::ClientConfig; pub use client_types::ClientTypes; //use beacon_chain::BeaconChain; +use beacon_chain::BeaconChain; use exit_future::{Exit, Signal}; use network::Service as NetworkService; use slog::o; @@ -20,26 +21,35 @@ use tokio::runtime::TaskExecutor; /// Main beacon node client service. This provides the connection and initialisation of the clients /// sub-services in multiple threads. pub struct Client { + /// Configuration for the lighthouse client. config: ClientConfig, + /// The beacon chain for the running client. beacon_chain: Arc>, + /// Reference to the network service. pub network: Arc, + /// Future to stop and begin shutdown of the Client. + //TODO: Decide best way to handle shutdown pub exit: exit_future::Exit, + /// The sending future to call to terminate the Client. + //TODO: Decide best way to handle shutdown pub exit_signal: Signal, + /// The clients logger. log: slog::Logger, + /// Marker to pin the beacon chain generics. + phantom: PhantomData, } -impl Client { - /// Generate an instance of the client. Spawn and link all internal subprocesses. +impl Client { + /// Generate an instance of the client. Spawn and link all internal sub-processes. pub fn new( config: ClientConfig, - client_type: T, log: slog::Logger, executor: &TaskExecutor, ) -> error::Result { let (exit_signal, exit) = exit_future::signal(); // generate a beacon chain - let beacon_chain = client_type.initialise_beacon_chain(&config); + let beacon_chain = TClientType::initialise_beacon_chain(&config); // Start the network service, libp2p and syncing threads // TODO: Add beacon_chain reference to network parameters @@ -54,6 +64,7 @@ impl Client { Ok(Client { config, + beacon_chain, exit, exit_signal: exit_signal, log, diff --git a/beacon_node/network/src/beacon_chain.rs b/beacon_node/network/src/beacon_chain.rs new file mode 100644 index 0000000000..5e0857f47b --- /dev/null +++ b/beacon_node/network/src/beacon_chain.rs @@ -0,0 +1,27 @@ +use beacon_chain::BeaconChain as RawBeaconChain; +use beacon_chain::{ + db::ClientDB, fork_choice::ForkChoice, parking_lot::RwLockReadGuard, slot_clock::SlotClock, + CheckPoint, +}; + +/// The network's API to the beacon chain. +pub trait BeaconChain: Send + Sync { + fn head(&self) -> RwLockReadGuard; + + fn finalized_head(&self) -> RwLockReadGuard; +} + +impl BeaconChain for RawBeaconChain +where + T: ClientDB + Sized, + U: SlotClock, + F: ForkChoice, +{ + fn head(&self) -> RwLockReadGuard { + self.head() + } + + fn finalized_head(&self) -> RwLockReadGuard { + self.finalized_head() + } +} diff --git a/beacon_node/network/src/lib.rs b/beacon_node/network/src/lib.rs index 49b2abadd7..dca83bb773 100644 --- a/beacon_node/network/src/lib.rs +++ b/beacon_node/network/src/lib.rs @@ -1,4 +1,5 @@ /// This crate provides the network server for Lighthouse. +pub mod beacon_chain; pub mod error; mod message_handler; mod messages; diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index 4ebedb89a3..0471e8ce50 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -1,14 +1,14 @@ +use crate::beacon_chain::BeaconChain; use crate::error; use crate::messages::NodeMessage; -use beacon_chain::BeaconChain; -use crossbeam_channel::{unbounded as channel, Sender, TryRecvError}; +use crossbeam_channel::{unbounded as channel, Sender}; use futures::future; use futures::prelude::*; use libp2p::rpc; use libp2p::{PeerId, RPCEvent}; use slog::debug; use std::collections::HashMap; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use std::time::{Duration, Instant}; use sync::SimpleSync; use types::Hash256; @@ -17,9 +17,9 @@ use types::Hash256; const HELLO_TIMEOUT: Duration = Duration::from_secs(30); /// Handles messages received from the network and client and organises syncing. -pub struct MessageHandler { +pub struct MessageHandler { /// Currently loaded and initialised beacon chain. - chain: BeaconChain, + chain: Arc, /// The syncing framework. sync: SimpleSync, /// A mapping of peers we have sent a HELLO rpc request to. @@ -41,10 +41,10 @@ pub enum HandlerMessage { RPC(RPCEvent), } -impl MessageHandler { +impl MessageHandler { /// Initializes and runs the MessageHandler. pub fn new( - beacon_chain: Arc>, + beacon_chain: Arc, executor: &tokio::runtime::TaskExecutor, log: slog::Logger, ) -> error::Result> { @@ -60,7 +60,7 @@ impl MessageHandler { // generate the Message handler let sync = SimpleSync::new(temp_genesis); let mut handler = MessageHandler { - chain: beacon_chain, + chain: beacon_chain.clone(), sync, hello_requests: HashMap::new(), log: log.clone(), diff --git a/beacon_node/network/src/service.rs b/beacon_node/network/src/service.rs index 6b9c0aff0a..e42b391058 100644 --- a/beacon_node/network/src/service.rs +++ b/beacon_node/network/src/service.rs @@ -1,46 +1,42 @@ +use crate::beacon_chain::BeaconChain; use crate::error; use crate::message_handler::{HandlerMessage, MessageHandler}; use crate::messages::{NetworkMessage, NodeMessage}; use crate::NetworkConfig; use crossbeam_channel::{unbounded as channel, Sender, TryRecvError}; -use futures::future::lazy; -use futures::future::poll_fn; use futures::prelude::*; use futures::sync::oneshot; use futures::Stream; -use libp2p::behaviour::BehaviourEvent; -use libp2p::error::Error as libp2pError; use libp2p::Service as LibP2PService; use libp2p::{Libp2pEvent, PeerId}; -use slog::{debug, info, o, trace, warn, Logger}; -use std::sync::{Arc, Mutex}; +use slog::{debug, o}; +use std::sync::Arc; use tokio::runtime::TaskExecutor; -use client::ClientTypes; /// Service that handles communication between internal services and the libp2p network service. -pub struct Service { +pub struct Service { //libp2p_service: Arc>, libp2p_exit: oneshot::Sender<()>, network_send: crossbeam_channel::Sender, //message_handler: MessageHandler, //message_handler_send: Sender, - PhantomData: T, } -impl Service { +impl Service { pub fn new( - beacon_chain: Arc, + beacon_chain: Arc, config: &NetworkConfig, executor: &TaskExecutor, log: slog::Logger, ) -> error::Result<(Arc, Sender)> { // launch message handler thread let message_handler_log = log.new(o!("Service" => "MessageHandler")); - let message_handler_send = MessageHandler::new(beacon_chain, executor, message_handler_log)?; + let message_handler_send = + MessageHandler::new(beacon_chain, executor, message_handler_log)?; // launch libp2p service let libp2p_log = log.new(o!("Service" => "Libp2p")); - let libp2p_service = LibP2PService::new(config, libp2p_log)?; + let libp2p_service = LibP2PService::new(config.clone(), libp2p_log)?; // TODO: Spawn thread to handle libp2p messages and pass to message handler thread. let (network_send, libp2p_exit) = From 2d52d2954dce534cf12671e74a7ba8bdcd7c0f77 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Mon, 18 Mar 2019 17:45:40 +1100 Subject: [PATCH 23/62] Modify testnet spec to have few validators --- beacon_node/beacon_chain/src/initialise.rs | 2 +- eth2/types/src/chain_spec.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/beacon_node/beacon_chain/src/initialise.rs b/beacon_node/beacon_chain/src/initialise.rs index a8289a062e..21b145d429 100644 --- a/beacon_node/beacon_chain/src/initialise.rs +++ b/beacon_node/beacon_chain/src/initialise.rs @@ -106,7 +106,7 @@ pub fn initialise_test_beacon_chain( deposit_root: Hash256::zero(), block_hash: Hash256::zero(), }; - let keypairs: Vec = (0..50) + let keypairs: Vec = (0..8) .collect::>() .iter() .map(|_| Keypair::random()) diff --git a/eth2/types/src/chain_spec.rs b/eth2/types/src/chain_spec.rs index c6093231b4..089d40385e 100644 --- a/eth2/types/src/chain_spec.rs +++ b/eth2/types/src/chain_spec.rs @@ -259,7 +259,7 @@ impl ChainSpec { Self { boot_nodes, - ..ChainSpec::foundation() + ..ChainSpec::few_validators() } } From 6a89da43b71f94e1111fe601387f25f5362f5995 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Mon, 18 Mar 2019 18:22:01 +1100 Subject: [PATCH 24/62] Cleanup network shutdown messages --- beacon_node/network/src/message_handler.rs | 2 +- beacon_node/network/src/service.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index 0471e8ce50..b904993bba 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -71,7 +71,7 @@ impl MessageHandler { executor.spawn(future::poll_fn(move || -> Result<_, _> { loop { handler.handle_message(handler_recv.recv().map_err(|_| { - debug!(log, "Handler channel closed. Handler terminating"); + debug!(log, "Network message handler terminated."); })?); } })); diff --git a/beacon_node/network/src/service.rs b/beacon_node/network/src/service.rs index e42b391058..21f948a71c 100644 --- a/beacon_node/network/src/service.rs +++ b/beacon_node/network/src/service.rs @@ -9,7 +9,7 @@ use futures::sync::oneshot; use futures::Stream; use libp2p::Service as LibP2PService; use libp2p::{Libp2pEvent, PeerId}; -use slog::{debug, o}; +use slog::{debug, info, o}; use std::sync::Arc; use tokio::runtime::TaskExecutor; @@ -80,7 +80,7 @@ fn spawn_service( // allow for manual termination .select(exit_rx.then(|_| Ok(()))) .then(move |_| { - debug!(log.clone(), "Network service ended"); + info!(log.clone(), "Network service shutdown"); Ok(()) }), ); From be712f5b05d4171957e1554633ca6f4ee6719a16 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Mon, 18 Mar 2019 23:04:17 +1100 Subject: [PATCH 25/62] Add network id to chainspec --- eth2/types/src/chain_spec.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/eth2/types/src/chain_spec.rs b/eth2/types/src/chain_spec.rs index 1607b85aa5..0c6caaeeed 100644 --- a/eth2/types/src/chain_spec.rs +++ b/eth2/types/src/chain_spec.rs @@ -118,6 +118,7 @@ pub struct ChainSpec { * */ pub boot_nodes: Vec, + pub network_id: u8, } impl ChainSpec { @@ -254,6 +255,7 @@ impl ChainSpec { * Boot nodes */ boot_nodes: vec![], + network_id: 1, // foundation network id } } @@ -270,6 +272,7 @@ impl ChainSpec { Self { boot_nodes, + network_id: 2, // lighthouse testnet network id ..ChainSpec::few_validators() } } From 0625bb6b03ecaed807db54208d1c6749ceecc52d Mon Sep 17 00:00:00 2001 From: Age Manning Date: Mon, 18 Mar 2019 23:18:25 +1100 Subject: [PATCH 26/62] Add network channel into message handler --- beacon_node/network/src/message_handler.rs | 16 +++++++-- beacon_node/network/src/messages.rs | 11 ++----- beacon_node/network/src/service.rs | 38 +++++++++++++++------- 3 files changed, 44 insertions(+), 21 deletions(-) diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index b904993bba..02234f3267 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -1,6 +1,7 @@ use crate::beacon_chain::BeaconChain; use crate::error; use crate::messages::NodeMessage; +use crate::service::NetworkMessage; use crossbeam_channel::{unbounded as channel, Sender}; use futures::future; use futures::prelude::*; @@ -22,6 +23,8 @@ pub struct MessageHandler { chain: Arc, /// The syncing framework. sync: SimpleSync, + /// The network channel to relay messages to the Network service. + network_send: crossbeam_channel::Sender, /// A mapping of peers we have sent a HELLO rpc request to. hello_requests: HashMap, /// The `MessageHandler` logger. @@ -45,6 +48,7 @@ impl MessageHandler { /// Initializes and runs the MessageHandler. pub fn new( beacon_chain: Arc, + network_send: crossbeam_channel::Sender, executor: &tokio::runtime::TaskExecutor, log: slog::Logger, ) -> error::Result> { @@ -62,6 +66,7 @@ impl MessageHandler { let mut handler = MessageHandler { chain: beacon_chain.clone(), sync, + network_send, hello_requests: HashMap::new(), log: log.clone(), }; @@ -81,12 +86,19 @@ impl MessageHandler { fn handle_message(&mut self, message: HandlerMessage) { match message { - HandlerMessage::PeerDialed(peer_id) => self.send_hello(peer_id), + HandlerMessage::PeerDialed(peer_id) => { + // register RPC request + self.hello_requests.insert(peer_id.clone(), Instant::now()); + self.send_hello(peer_id); + } //TODO: Handle all messages _ => {} } } /// Sends a HELLO RPC request to a newly connected peer. - fn send_hello(&self, peer_id: PeerId) {} + fn send_hello(&self, peer_id: PeerId) { + // send the hello request to the network + //sync.hello() + } } diff --git a/beacon_node/network/src/messages.rs b/beacon_node/network/src/messages.rs index 930c90b3e4..6a69cbb874 100644 --- a/beacon_node/network/src/messages.rs +++ b/beacon_node/network/src/messages.rs @@ -2,7 +2,10 @@ use libp2p::PeerId; use libp2p::{HelloMessage, RPCEvent}; use types::{Hash256, Slot}; +//TODO: This module can be entirely replaced in the RPC rewrite + /// Messages between nodes across the network. +//TODO: Remove this in the RPC rewrite #[derive(Debug, Clone)] pub enum NodeMessage { RPC(RPCEvent), @@ -10,11 +13,3 @@ pub enum NodeMessage { // TODO: only for testing - remove Message(String), } - -/// Types of messages that the network service can receive. -#[derive(Debug, Clone)] -pub enum NetworkMessage { - /// Send a message to libp2p service. - //TODO: Define typing for messages across the wire - Send(PeerId, NodeMessage), -} diff --git a/beacon_node/network/src/service.rs b/beacon_node/network/src/service.rs index 21f948a71c..7ad3bdb3ec 100644 --- a/beacon_node/network/src/service.rs +++ b/beacon_node/network/src/service.rs @@ -1,7 +1,7 @@ use crate::beacon_chain::BeaconChain; use crate::error; use crate::message_handler::{HandlerMessage, MessageHandler}; -use crate::messages::{NetworkMessage, NodeMessage}; +use crate::messages::NodeMessage; use crate::NetworkConfig; use crossbeam_channel::{unbounded as channel, Sender, TryRecvError}; use futures::prelude::*; @@ -29,18 +29,29 @@ impl Service { executor: &TaskExecutor, log: slog::Logger, ) -> error::Result<(Arc, Sender)> { + // build the network channel + let (network_send, network_recv) = channel::(); // launch message handler thread let message_handler_log = log.new(o!("Service" => "MessageHandler")); - let message_handler_send = - MessageHandler::new(beacon_chain, executor, message_handler_log)?; + let message_handler_send = MessageHandler::new( + beacon_chain, + network_send.clone(), + executor, + message_handler_log, + )?; // launch libp2p service let libp2p_log = log.new(o!("Service" => "Libp2p")); let libp2p_service = LibP2PService::new(config.clone(), libp2p_log)?; // TODO: Spawn thread to handle libp2p messages and pass to message handler thread. - let (network_send, libp2p_exit) = - spawn_service(libp2p_service, message_handler_send, executor, log)?; + let libp2p_exit = spawn_service( + libp2p_service, + network_recv, + message_handler_send, + executor, + log, + )?; let network = Service { libp2p_exit, network_send: network_send.clone(), @@ -59,15 +70,12 @@ impl Service { fn spawn_service( libp2p_service: LibP2PService, + network_recv: crossbeam_channel::Receiver, message_handler_send: crossbeam_channel::Sender, executor: &TaskExecutor, log: slog::Logger, -) -> error::Result<( - crossbeam_channel::Sender, - oneshot::Sender<()>, -)> { +) -> error::Result> { let (network_exit, exit_rx) = oneshot::channel(); - let (network_send, network_recv) = channel::(); // spawn on the current executor executor.spawn( @@ -85,7 +93,7 @@ fn spawn_service( }), ); - Ok((network_send, network_exit)) + Ok(network_exit) } fn network_service( @@ -148,3 +156,11 @@ fn network_service( Ok(Async::NotReady) }) } + +/// Types of messages that the network service can receive. +#[derive(Debug, Clone)] +pub enum NetworkMessage { + /// Send a message to libp2p service. + //TODO: Define typing for messages across the wire + Send(PeerId, NodeMessage), +} From 8ec0688cb93c71cede5072cef007818aebc4df75 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Mon, 18 Mar 2019 23:34:44 +1100 Subject: [PATCH 27/62] Implements RPC call functionality --- beacon_node/libp2p/src/behaviour.rs | 8 +++--- beacon_node/libp2p/src/rpc/mod.rs | 11 +++----- beacon_node/network/src/service.rs | 41 ++++++++++++++++++----------- 3 files changed, 34 insertions(+), 26 deletions(-) diff --git a/beacon_node/libp2p/src/behaviour.rs b/beacon_node/libp2p/src/behaviour.rs index 604b84c8f5..f0a89027ba 100644 --- a/beacon_node/libp2p/src/behaviour.rs +++ b/beacon_node/libp2p/src/behaviour.rs @@ -72,14 +72,16 @@ impl Behaviour { } } +/// Implements the combined behaviour for the libp2p service. impl Behaviour { + /// Subscribes to a gossipsub topic. pub fn subscribe(&mut self, topic: Topic) -> bool { self.gossipsub.subscribe(topic) } - pub fn send_message(&self, message: String) { - // TODO: Encode and send via gossipsub - + /// Sends an RPC Request/Response via the RPC protocol. + pub fn send_rpc(&mut self, peer_id: PeerId, rpc_event: RPCEvent) { + self.serenity_rpc.send_rpc(peer_id, rpc_event); } } diff --git a/beacon_node/libp2p/src/rpc/mod.rs b/beacon_node/libp2p/src/rpc/mod.rs index d40e53935f..907e957632 100644 --- a/beacon_node/libp2p/src/rpc/mod.rs +++ b/beacon_node/libp2p/src/rpc/mod.rs @@ -13,7 +13,7 @@ use libp2p::core::swarm::{ use libp2p::{Multiaddr, PeerId}; pub use methods::{HelloMessage, RPCMethod, RPCRequest, RPCResponse}; pub use protocol::{RPCEvent, RPCProtocol}; -use slog::{debug, o, Logger}; +use slog::{debug, o}; use std::marker::PhantomData; use tokio::io::{AsyncRead, AsyncWrite}; @@ -40,15 +40,10 @@ impl Rpc { } /// Submits and RPC request. - pub fn send_request(&mut self, peer_id: PeerId, id: u64, method_id: u16, body: RPCRequest) { - let request = RPCEvent::Request { - id, - method_id, - body, - }; + pub fn send_rpc(&mut self, peer_id: PeerId, rpc_event: RPCEvent) { self.events.push(NetworkBehaviourAction::SendEvent { peer_id, - event: request, + event: rpc_event, }); } } diff --git a/beacon_node/network/src/service.rs b/beacon_node/network/src/service.rs index 7ad3bdb3ec..4cb1038d16 100644 --- a/beacon_node/network/src/service.rs +++ b/beacon_node/network/src/service.rs @@ -7,9 +7,10 @@ use crossbeam_channel::{unbounded as channel, Sender, TryRecvError}; use futures::prelude::*; use futures::sync::oneshot; use futures::Stream; +use libp2p::RPCEvent; use libp2p::Service as LibP2PService; use libp2p::{Libp2pEvent, PeerId}; -use slog::{debug, info, o}; +use slog::{debug, info, o, trace}; use std::sync::Arc; use tokio::runtime::TaskExecutor; @@ -63,8 +64,10 @@ impl Service { // TODO: Testing only pub fn send_message(&self, message: String) { let node_message = NodeMessage::Message(message); - self.network_send - .send(NetworkMessage::Send(PeerId::random(), node_message)); + self.network_send.send(NetworkMessage::Send( + PeerId::random(), + OutgoingMessage::NotifierTest, + )); } } @@ -113,13 +116,13 @@ fn network_service( ); message_handler_send .send(HandlerMessage::RPC(rpc_event)) - .map_err(|_| "failed to send rpc to handler"); + .map_err(|_| "failed to send rpc to handler")?; } Ok(Async::Ready(Some(Libp2pEvent::PeerDialed(peer_id)))) => { debug!(libp2p_service.log, "Peer Dialed: {:?}", peer_id); message_handler_send .send(HandlerMessage::PeerDialed(peer_id)) - .map_err(|_| "failed to send rpc to handler"); + .map_err(|_| "failed to send rpc to handler")?; } Ok(Async::Ready(Some(Libp2pEvent::Message(m)))) => debug!( libp2p_service.log, @@ -133,24 +136,23 @@ fn network_service( loop { match network_recv.try_recv() { // TODO: Testing message - remove - Ok(NetworkMessage::Send(_peer_id, node_message)) => { - match node_message { - NodeMessage::Message(m) => { - debug!(log, "Message received via network channel: {:?}", m); + Ok(NetworkMessage::Send(peer_id, outgoing_message)) => { + match outgoing_message { + OutgoingMessage::RPC(rpc_event) => { + trace!(log, "Sending RPC Event: {:?}", rpc_event); //TODO: Make swarm private //TODO: Implement correct peer id topic message handling - libp2p_service.swarm.send_message(m); + libp2p_service.swarm.send_rpc(peer_id, rpc_event); + } + OutgoingMessage::NotifierTest => { + debug!(log, "Received message from notifier"); } - //TODO: Handle all NodeMessage types - _ => break, }; } Err(TryRecvError::Empty) => break, Err(TryRecvError::Disconnected) => { return Err(libp2p::error::Error::from("Network channel disconnected")); } - // TODO: Implement all NetworkMessage - _ => break, } } Ok(Async::NotReady) @@ -162,5 +164,14 @@ fn network_service( pub enum NetworkMessage { /// Send a message to libp2p service. //TODO: Define typing for messages across the wire - Send(PeerId, NodeMessage), + Send(PeerId, OutgoingMessage), +} + +/// Type of outgoing messages that can be sent through the network service. +#[derive(Debug, Clone)] +pub enum OutgoingMessage { + /// Send an RPC request/response. + RPC(RPCEvent), + //TODO: Remove + NotifierTest, } From 41abdb7599168ba760d78e4c36b76ea8c991392b Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 19 Mar 2019 00:05:06 +1100 Subject: [PATCH 28/62] Remove sync crate, move into network crate --- Cargo.toml | 1 - beacon_node/beacon_chain/src/lib.rs | 1 + beacon_node/client/Cargo.toml | 1 - beacon_node/network/Cargo.toml | 1 - beacon_node/network/src/beacon_chain.rs | 8 +++++++- beacon_node/network/src/lib.rs | 1 + beacon_node/network/src/message_handler.rs | 11 ++++------- .../{sync/src/lib.rs => network/src/sync/mod.rs} | 0 .../src => network/src/sync}/simple_sync.rs | 16 +++++++++++----- beacon_node/sync/Cargo.toml | 9 --------- 10 files changed, 24 insertions(+), 25 deletions(-) rename beacon_node/{sync/src/lib.rs => network/src/sync/mod.rs} (100%) rename beacon_node/{sync/src => network/src/sync}/simple_sync.rs (54%) delete mode 100644 beacon_node/sync/Cargo.toml diff --git a/Cargo.toml b/Cargo.toml index 89158542e5..d34f6fd30e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,6 @@ members = [ "beacon_node/client", "beacon_node/network", "beacon_node/rpc", - "beacon_node/sync", "beacon_node/version", "beacon_node/beacon_chain", "beacon_node/beacon_chain/test_harness", diff --git a/beacon_node/beacon_chain/src/lib.rs b/beacon_node/beacon_chain/src/lib.rs index 5acac6ff22..2137c0edfd 100644 --- a/beacon_node/beacon_chain/src/lib.rs +++ b/beacon_node/beacon_chain/src/lib.rs @@ -11,3 +11,4 @@ pub use db; pub use fork_choice; pub use parking_lot; pub use slot_clock; +pub use types; diff --git a/beacon_node/client/Cargo.toml b/beacon_node/client/Cargo.toml index 8914a9e7e2..11453e4b81 100644 --- a/beacon_node/client/Cargo.toml +++ b/beacon_node/client/Cargo.toml @@ -7,7 +7,6 @@ edition = "2018" [dependencies] beacon_chain = { path = "../beacon_chain" } network = { path = "../network" } -sync = { path = "../sync" } db = { path = "../db" } fork_choice = { path = "../../eth2/fork_choice" } types = { path = "../../eth2/types" } diff --git a/beacon_node/network/Cargo.toml b/beacon_node/network/Cargo.toml index f1a7ed2589..8b87a9d502 100644 --- a/beacon_node/network/Cargo.toml +++ b/beacon_node/network/Cargo.toml @@ -9,7 +9,6 @@ beacon_chain = { path = "../beacon_chain" } libp2p = { path = "../libp2p" } version = { path = "../version" } types = { path = "../../eth2/types" } -sync = { path = "../sync" } slog = "2.4.1" futures = "0.1.25" error-chain = "0.12.0" diff --git a/beacon_node/network/src/beacon_chain.rs b/beacon_node/network/src/beacon_chain.rs index 5e0857f47b..5e9857c094 100644 --- a/beacon_node/network/src/beacon_chain.rs +++ b/beacon_node/network/src/beacon_chain.rs @@ -1,11 +1,13 @@ use beacon_chain::BeaconChain as RawBeaconChain; use beacon_chain::{ db::ClientDB, fork_choice::ForkChoice, parking_lot::RwLockReadGuard, slot_clock::SlotClock, - CheckPoint, + types::ChainSpec, CheckPoint, }; /// The network's API to the beacon chain. pub trait BeaconChain: Send + Sync { + fn get_spec(&self) -> &ChainSpec; + fn head(&self) -> RwLockReadGuard; fn finalized_head(&self) -> RwLockReadGuard; @@ -17,6 +19,10 @@ where U: SlotClock, F: ForkChoice, { + fn get_spec(&self) -> &ChainSpec { + &self.spec + } + fn head(&self) -> RwLockReadGuard { self.head() } diff --git a/beacon_node/network/src/lib.rs b/beacon_node/network/src/lib.rs index dca83bb773..c1840f5924 100644 --- a/beacon_node/network/src/lib.rs +++ b/beacon_node/network/src/lib.rs @@ -4,6 +4,7 @@ pub mod error; mod message_handler; mod messages; mod service; +pub mod sync; pub use libp2p::NetworkConfig; pub use messages::NodeMessage; diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index 02234f3267..7e5a74a102 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -2,16 +2,15 @@ use crate::beacon_chain::BeaconChain; use crate::error; use crate::messages::NodeMessage; use crate::service::NetworkMessage; +use crate::sync::SimpleSync; use crossbeam_channel::{unbounded as channel, Sender}; use futures::future; use futures::prelude::*; -use libp2p::rpc; use libp2p::{PeerId, RPCEvent}; use slog::debug; use std::collections::HashMap; use std::sync::Arc; use std::time::{Duration, Instant}; -use sync::SimpleSync; use types::Hash256; /// Timeout for establishing a HELLO handshake. @@ -57,13 +56,11 @@ impl MessageHandler { let (handler_send, handler_recv) = channel(); // Initialise sync and begin processing in thread - //TODO: Load genesis from BeaconChain - //TODO: Initialise beacon chain - let temp_genesis = Hash256::zero(); - // generate the Message handler - let sync = SimpleSync::new(temp_genesis); + let sync = SimpleSync::new(beacon_chain.clone()); + let mut handler = MessageHandler { + // TODO: The handler may not need a chain, perhaps only sync? chain: beacon_chain.clone(), sync, network_send, diff --git a/beacon_node/sync/src/lib.rs b/beacon_node/network/src/sync/mod.rs similarity index 100% rename from beacon_node/sync/src/lib.rs rename to beacon_node/network/src/sync/mod.rs diff --git a/beacon_node/sync/src/simple_sync.rs b/beacon_node/network/src/sync/simple_sync.rs similarity index 54% rename from beacon_node/sync/src/simple_sync.rs rename to beacon_node/network/src/sync/simple_sync.rs index 01a6a1adf4..4034c63c90 100644 --- a/beacon_node/sync/src/simple_sync.rs +++ b/beacon_node/network/src/sync/simple_sync.rs @@ -1,11 +1,15 @@ +use crate::beacon_chain::BeaconChain; use libp2p::PeerId; use std::collections::HashMap; -use types::{Hash256, Slot}; +use std::sync::Arc; +use types::{Epoch, Hash256, Slot}; /// Keeps track of syncing information for known connected peers. pub struct PeerSyncInfo { + latest_finalized_root: Hash256, + latest_finalized_epoch: Epoch, + best_root: Hash256, best_slot: Slot, - best_slot_hash: Hash256, } /// The current syncing state. @@ -16,18 +20,20 @@ pub enum SyncState { } /// Simple Syncing protocol. +//TODO: Decide for HELLO messages whether its better to keep current in RAM or build on the fly +//when asked. pub struct SimpleSync { - genesis_hash: Hash256, known_peers: HashMap, state: SyncState, + network_id: u8, } impl SimpleSync { - pub fn new(genesis_hash: Hash256) -> Self { + pub fn new(beacon_chain: Arc) -> Self { SimpleSync { - genesis_hash, known_peers: HashMap::new(), state: SyncState::Idle, + network_id: beacon_chain.get_spec().network_id, } } } diff --git a/beacon_node/sync/Cargo.toml b/beacon_node/sync/Cargo.toml deleted file mode 100644 index a4ebe3eede..0000000000 --- a/beacon_node/sync/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "sync" -version = "0.1.0" -authors = ["Age Manning "] -edition = "2018" - -[dependencies] -types = { path = "../../eth2/types" } -libp2p = { path = "../libp2p" } From dfdec78a7a32177e42c10255e8ba5d3efb1fa55d Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 19 Mar 2019 00:26:15 +1100 Subject: [PATCH 29/62] Implements hello generation in sync module --- beacon_node/network/src/beacon_chain.rs | 14 ++++++++++++-- beacon_node/network/src/sync/simple_sync.rs | 20 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/beacon_node/network/src/beacon_chain.rs b/beacon_node/network/src/beacon_chain.rs index 5e9857c094..91628cc7e9 100644 --- a/beacon_node/network/src/beacon_chain.rs +++ b/beacon_node/network/src/beacon_chain.rs @@ -1,13 +1,19 @@ use beacon_chain::BeaconChain as RawBeaconChain; use beacon_chain::{ - db::ClientDB, fork_choice::ForkChoice, parking_lot::RwLockReadGuard, slot_clock::SlotClock, - types::ChainSpec, CheckPoint, + db::ClientDB, + fork_choice::ForkChoice, + parking_lot::RwLockReadGuard, + slot_clock::SlotClock, + types::{BeaconState, ChainSpec}, + CheckPoint, }; /// The network's API to the beacon chain. pub trait BeaconChain: Send + Sync { fn get_spec(&self) -> &ChainSpec; + fn get_state(&self) -> RwLockReadGuard; + fn head(&self) -> RwLockReadGuard; fn finalized_head(&self) -> RwLockReadGuard; @@ -23,6 +29,10 @@ where &self.spec } + fn get_state(&self) -> RwLockReadGuard { + self.state.read() + } + fn head(&self) -> RwLockReadGuard { self.head() } diff --git a/beacon_node/network/src/sync/simple_sync.rs b/beacon_node/network/src/sync/simple_sync.rs index 4034c63c90..336f225b2a 100644 --- a/beacon_node/network/src/sync/simple_sync.rs +++ b/beacon_node/network/src/sync/simple_sync.rs @@ -1,4 +1,5 @@ use crate::beacon_chain::BeaconChain; +use libp2p::rpc::HelloMessage; use libp2p::PeerId; use std::collections::HashMap; use std::sync::Arc; @@ -23,8 +24,13 @@ pub enum SyncState { //TODO: Decide for HELLO messages whether its better to keep current in RAM or build on the fly //when asked. pub struct SimpleSync { + /// A reference to the underlying beacon chain. + chain: Arc, + /// A mapping of Peers to their respective PeerSyncInfo. known_peers: HashMap, + /// The current state of the syncing protocol. state: SyncState, + /// The network id, for quick HELLO RPC message lookup. network_id: u8, } @@ -34,6 +40,20 @@ impl SimpleSync { known_peers: HashMap::new(), state: SyncState::Idle, network_id: beacon_chain.get_spec().network_id, + chain: beacon_chain, + } + } + + /// Generates our current state in the form of a HELLO RPC message. + pub fn generate_hello(&self) -> HelloMessage { + let state = &self.chain.get_state(); + //TODO: Paul to verify the logic of these fields. + HelloMessage { + network_id: self.network_id, + latest_finalized_root: state.finalized_root.clone(), + latest_finalized_epoch: state.finalized_epoch, + best_root: state.latest_block_roots[0], // 0 or len of vec? + best_slot: state.slot, } } } From 495348f934895a2e0057e47889da1010ecd41ced Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 19 Mar 2019 11:25:42 +1100 Subject: [PATCH 30/62] Adds RPC request send framework in message handler --- beacon_node/network/src/message_handler.rs | 51 +++++++++++++++++----- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index 7e5a74a102..2d4d47b86b 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -6,15 +6,18 @@ use crate::sync::SimpleSync; use crossbeam_channel::{unbounded as channel, Sender}; use futures::future; use futures::prelude::*; -use libp2p::{PeerId, RPCEvent}; +use libp2p::{ + rpc::{RPCRequest, RPCResponse}, + PeerId, RPCEvent, +}; use slog::debug; use std::collections::HashMap; use std::sync::Arc; use std::time::{Duration, Instant}; use types::Hash256; -/// Timeout for establishing a HELLO handshake. -const HELLO_TIMEOUT: Duration = Duration::from_secs(30); +/// Timeout for RPC requests. +const REQUEST_TIMEOUT: Duration = Duration::from_secs(30); /// Handles messages received from the network and client and organises syncing. pub struct MessageHandler { @@ -24,12 +27,22 @@ pub struct MessageHandler { sync: SimpleSync, /// The network channel to relay messages to the Network service. network_send: crossbeam_channel::Sender, - /// A mapping of peers we have sent a HELLO rpc request to. - hello_requests: HashMap, + /// A mapping of peers we have sent an RPC request to. + requests: HashMap>, + /// A counter of request id for each peer. + request_ids: HashMap, /// The `MessageHandler` logger. log: slog::Logger, } +/// RPC request information +pub struct RPCRequestInfo { + /// The id of the request + id: u16, + /// The time the request was sent, to check ttl. + request_time: Instant, +} + /// Types of messages the handler can receive. #[derive(Debug, Clone)] pub enum HandlerMessage { @@ -64,7 +77,8 @@ impl MessageHandler { chain: beacon_chain.clone(), sync, network_send, - hello_requests: HashMap::new(), + requests: HashMap::new(), + request_ids: HashMap::new(), log: log.clone(), }; @@ -84,8 +98,6 @@ impl MessageHandler { fn handle_message(&mut self, message: HandlerMessage) { match message { HandlerMessage::PeerDialed(peer_id) => { - // register RPC request - self.hello_requests.insert(peer_id.clone(), Instant::now()); self.send_hello(peer_id); } //TODO: Handle all messages @@ -94,8 +106,27 @@ impl MessageHandler { } /// Sends a HELLO RPC request to a newly connected peer. - fn send_hello(&self, peer_id: PeerId) { + fn send_hello(&mut self, peer_id: PeerId) { + // generate a unique id for the peer + let id = { + let borrowed_id = self.request_ids.entry(peer_id.clone()).or_insert_with(|| 0); + let id = borrowed_id.clone(); + //increment the counter + *borrowed_id += 1; + id + }; + // register RPC request + { + let requests = self.requests.entry(peer_id).or_insert_with(|| vec![]); + requests.push(RPCRequestInfo { + id: id.clone(), + request_time: Instant::now(), + }); + } // send the hello request to the network - //sync.hello() + self.send_rpc_request(id, RPCResponse::Hello(self.sync.generate_hello())); } + + /// Sends and RPC response + fn send_rpc_request(&self, request_id: u16, response: RPCResponse) {} } From 31333e8f8eec5fa59240ebae93435d596e1320c9 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 19 Mar 2019 12:19:07 +1100 Subject: [PATCH 31/62] Add send rpc in message handler --- beacon_node/libp2p/src/rpc/methods.rs | 9 +++++ beacon_node/network/src/message_handler.rs | 42 +++++++++++++++++----- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/beacon_node/libp2p/src/rpc/methods.rs b/beacon_node/libp2p/src/rpc/methods.rs index ea9932806b..c99994b7ce 100644 --- a/beacon_node/libp2p/src/rpc/methods.rs +++ b/beacon_node/libp2p/src/rpc/methods.rs @@ -17,6 +17,15 @@ impl From for RPCMethod { } } +impl Into for RPCMethod { + fn into(self) -> u16 { + match self { + RPCMethod::Hello => 0, + _ => 0, + } + } +} + #[derive(Debug, Clone)] pub enum RPCRequest { Hello(HelloMessage), diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index 2d4d47b86b..dcc1452948 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -1,16 +1,17 @@ use crate::beacon_chain::BeaconChain; use crate::error; use crate::messages::NodeMessage; -use crate::service::NetworkMessage; +use crate::service::{NetworkMessage, OutgoingMessage}; use crate::sync::SimpleSync; use crossbeam_channel::{unbounded as channel, Sender}; use futures::future; use futures::prelude::*; use libp2p::{ - rpc::{RPCRequest, RPCResponse}, + rpc::{RPCMethod, RPCRequest, RPCResponse}, PeerId, RPCEvent, }; use slog::debug; +use slog::warn; use std::collections::HashMap; use std::sync::Arc; use std::time::{Duration, Instant}; @@ -30,7 +31,7 @@ pub struct MessageHandler { /// A mapping of peers we have sent an RPC request to. requests: HashMap>, /// A counter of request id for each peer. - request_ids: HashMap, + request_ids: HashMap, /// The `MessageHandler` logger. log: slog::Logger, } @@ -38,7 +39,7 @@ pub struct MessageHandler { /// RPC request information pub struct RPCRequestInfo { /// The id of the request - id: u16, + id: u64, /// The time the request was sent, to check ttl. request_time: Instant, } @@ -98,7 +99,7 @@ impl MessageHandler { fn handle_message(&mut self, message: HandlerMessage) { match message { HandlerMessage::PeerDialed(peer_id) => { - self.send_hello(peer_id); + self.send_hello_request(peer_id); } //TODO: Handle all messages _ => {} @@ -106,7 +107,7 @@ impl MessageHandler { } /// Sends a HELLO RPC request to a newly connected peer. - fn send_hello(&mut self, peer_id: PeerId) { + fn send_hello_request(&mut self, peer_id: PeerId) { // generate a unique id for the peer let id = { let borrowed_id = self.request_ids.entry(peer_id.clone()).or_insert_with(|| 0); @@ -117,16 +118,39 @@ impl MessageHandler { }; // register RPC request { - let requests = self.requests.entry(peer_id).or_insert_with(|| vec![]); + let requests = self + .requests + .entry(peer_id.clone()) + .or_insert_with(|| vec![]); requests.push(RPCRequestInfo { id: id.clone(), request_time: Instant::now(), }); } + + // build the rpc request + let rpc_event = RPCEvent::Request { + id, + method_id: RPCMethod::Hello.into(), + body: RPCRequest::Hello(self.sync.generate_hello()), + }; + // send the hello request to the network - self.send_rpc_request(id, RPCResponse::Hello(self.sync.generate_hello())); + self.send_rpc(peer_id, rpc_event); } /// Sends and RPC response - fn send_rpc_request(&self, request_id: u16, response: RPCResponse) {} + fn send_rpc(&self, peer_id: PeerId, rpc_event: RPCEvent) { + self.network_send + .send(NetworkMessage::Send( + peer_id, + OutgoingMessage::RPC(rpc_event), + )) + .unwrap_or_else(|_| { + warn!( + self.log, + "Could not send RPC message to the network service" + ) + }); + } } From 2657dc1465d7ac746c5c92394a68f0d76eef5a23 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 19 Mar 2019 12:47:36 +1100 Subject: [PATCH 32/62] Builds RPC infrastructure to handle RPC responses --- beacon_node/libp2p/src/behaviour.rs | 6 ++-- beacon_node/libp2p/src/rpc/mod.rs | 6 ++-- beacon_node/libp2p/src/service.rs | 6 ++-- beacon_node/network/src/message_handler.rs | 32 ++++++++++++++++++++-- beacon_node/network/src/service.rs | 6 ++-- 5 files changed, 42 insertions(+), 14 deletions(-) diff --git a/beacon_node/libp2p/src/behaviour.rs b/beacon_node/libp2p/src/behaviour.rs index f0a89027ba..78d0130025 100644 --- a/beacon_node/libp2p/src/behaviour.rs +++ b/beacon_node/libp2p/src/behaviour.rs @@ -46,7 +46,9 @@ impl NetworkBehaviourEventProcess { self.events.push(BehaviourEvent::PeerDialed(peer_id)) } - RPCMessage::RPC(rpc_event) => self.events.push(BehaviourEvent::RPC(rpc_event)), + RPCMessage::RPC(peer_id, rpc_event) => { + self.events.push(BehaviourEvent::RPC(peer_id, rpc_event)) + } } } } @@ -87,7 +89,7 @@ impl Behaviour { /// The types of events than can be obtained from polling the behaviour. pub enum BehaviourEvent { - RPC(RPCEvent), + RPC(PeerId, RPCEvent), PeerDialed(PeerId), // TODO: This is a stub at the moment Message(String), diff --git a/beacon_node/libp2p/src/rpc/mod.rs b/beacon_node/libp2p/src/rpc/mod.rs index 907e957632..e06f4effc5 100644 --- a/beacon_node/libp2p/src/rpc/mod.rs +++ b/beacon_node/libp2p/src/rpc/mod.rs @@ -76,7 +76,7 @@ where fn inject_node_event( &mut self, - _source: PeerId, + source: PeerId, event: ::OutEvent, ) { // ignore successful send events @@ -88,7 +88,7 @@ where // send the event to the user self.events .push(NetworkBehaviourAction::GenerateEvent(RPCMessage::RPC( - event, + source, event, ))); } @@ -110,7 +110,7 @@ where /// Messages sent to the user from the RPC protocol. pub enum RPCMessage { - RPC(RPCEvent), + RPC(PeerId, RPCEvent), PeerDialed(PeerId), } diff --git a/beacon_node/libp2p/src/service.rs b/beacon_node/libp2p/src/service.rs index dd6deabadb..92e6e88977 100644 --- a/beacon_node/libp2p/src/service.rs +++ b/beacon_node/libp2p/src/service.rs @@ -105,8 +105,8 @@ impl Stream for Service { debug!(self.log, "Message received: {}", m); return Ok(Async::Ready(Some(Libp2pEvent::Message(m)))); } - Ok(Async::Ready(Some(BehaviourEvent::RPC(event)))) => { - return Ok(Async::Ready(Some(Libp2pEvent::RPC(event)))); + Ok(Async::Ready(Some(BehaviourEvent::RPC(peer_id, event)))) => { + return Ok(Async::Ready(Some(Libp2pEvent::RPC(peer_id, event)))); } Ok(Async::Ready(Some(BehaviourEvent::PeerDialed(peer_id)))) => { return Ok(Async::Ready(Some(Libp2pEvent::PeerDialed(peer_id)))); @@ -158,7 +158,7 @@ fn build_transport( /// Events that can be obtained from polling the Libp2p Service. pub enum Libp2pEvent { // We have received an RPC event on the swarm - RPC(RPCEvent), + RPC(PeerId, RPCEvent), PeerDialed(PeerId), Message(String), } diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index dcc1452948..11ce3d4c02 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -10,8 +10,8 @@ use libp2p::{ rpc::{RPCMethod, RPCRequest, RPCResponse}, PeerId, RPCEvent, }; -use slog::debug; use slog::warn; +use slog::{debug, trace}; use std::collections::HashMap; use std::sync::Arc; use std::time::{Duration, Instant}; @@ -54,7 +54,7 @@ pub enum HandlerMessage { /// A Node message has been received. Message(PeerId, NodeMessage), /// An RPC response/request has been received. - RPC(RPCEvent), + RPC(PeerId, RPCEvent), } impl MessageHandler { @@ -98,14 +98,39 @@ impl MessageHandler { fn handle_message(&mut self, message: HandlerMessage) { match message { + // we have initiated a connection to a peer HandlerMessage::PeerDialed(peer_id) => { self.send_hello_request(peer_id); } + // we have received an RPC message request/response + HandlerMessage::RPC(peer_id, rpc_event) => { + self.handle_rpc_message(peer_id, rpc_event); + } //TODO: Handle all messages _ => {} } } + fn handle_rpc_message(&mut self, peer_id: PeerId, rpc_message: RPCEvent) { + match rpc_message { + RPCEvent::Request { + id, + method_id: _, + body, + } => self.handle_rpc_request(peer_id, id, body), + RPCEvent::Response { + id, + method_id: _, + result, + } => self.handle_rpc_response(peer_id, id, result), + } + } + + fn handle_rpc_request(&mut self, peer_id: PeerId, id: u64, request: RPCRequest) {} + + // we match on id and ignore responses past the timeout. + fn handle_rpc_response(&mut self, peer_id: PeerId, id: u64, response: RPCResponse) {} + /// Sends a HELLO RPC request to a newly connected peer. fn send_hello_request(&mut self, peer_id: PeerId) { // generate a unique id for the peer @@ -136,10 +161,11 @@ impl MessageHandler { }; // send the hello request to the network + trace!(self.log, "Sending HELLO message to peer {:?}", peer_id); self.send_rpc(peer_id, rpc_event); } - /// Sends and RPC response + /// Sends an RPC request/response to the network server. fn send_rpc(&self, peer_id: PeerId, rpc_event: RPCEvent) { self.network_send .send(NetworkMessage::Send( diff --git a/beacon_node/network/src/service.rs b/beacon_node/network/src/service.rs index 4cb1038d16..84e46e707c 100644 --- a/beacon_node/network/src/service.rs +++ b/beacon_node/network/src/service.rs @@ -109,13 +109,13 @@ fn network_service( // poll the swarm loop { match libp2p_service.poll() { - Ok(Async::Ready(Some(Libp2pEvent::RPC(rpc_event)))) => { + Ok(Async::Ready(Some(Libp2pEvent::RPC(peer_id, rpc_event)))) => { debug!( libp2p_service.log, - "RPC Event: Rpc message received: {:?}", rpc_event + "RPC Event: RPC message received: {:?}", rpc_event ); message_handler_send - .send(HandlerMessage::RPC(rpc_event)) + .send(HandlerMessage::RPC(peer_id, rpc_event)) .map_err(|_| "failed to send rpc to handler")?; } Ok(Async::Ready(Some(Libp2pEvent::PeerDialed(peer_id)))) => { From 67c09021f01cf9bba0b5e990c7a21405425e5a28 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 19 Mar 2019 13:03:12 +1100 Subject: [PATCH 33/62] Initial handling RPC responses --- beacon_node/network/src/message_handler.rs | 26 +++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index 11ce3d4c02..14be9acdc3 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -8,7 +8,7 @@ use futures::future; use futures::prelude::*; use libp2p::{ rpc::{RPCMethod, RPCRequest, RPCResponse}, - PeerId, RPCEvent, + HelloMessage, PeerId, RPCEvent, }; use slog::warn; use slog::{debug, trace}; @@ -115,7 +115,7 @@ impl MessageHandler { match rpc_message { RPCEvent::Request { id, - method_id: _, + method_id: _, // TODO: Clean up RPC Message types, have a cleaner type by this point. body, } => self.handle_rpc_request(peer_id, id, body), RPCEvent::Response { @@ -126,11 +126,31 @@ impl MessageHandler { } } - fn handle_rpc_request(&mut self, peer_id: PeerId, id: u64, request: RPCRequest) {} + /// A new RPC request has been received from the network. + fn handle_rpc_request(&mut self, peer_id: PeerId, id: u64, request: RPCRequest) { + match request { + RPCRequest::Hello(hello_message) => { + self.handle_hello_response(peer_id, id, hello_message) + } + } + } + /// An RPC response has been received from the network. // we match on id and ignore responses past the timeout. fn handle_rpc_response(&mut self, peer_id: PeerId, id: u64, response: RPCResponse) {} + fn handle_hello_response(&mut self, peer_id: PeerId, id: u64, response: HelloMessage) { + /* + // if response id is not in our list, ignore (likely RPC timeout) + match self.requests.get(peer_id) { + None => return; + Some(rpc_info) => { + if rpc_info.con + + */ + + } + /// Sends a HELLO RPC request to a newly connected peer. fn send_hello_request(&mut self, peer_id: PeerId) { // generate a unique id for the peer From 5ae8079b446791819d0ddc448554b52ebf8909e0 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 19 Mar 2019 13:25:25 +1100 Subject: [PATCH 34/62] Basic node handshake --- beacon_node/network/src/message_handler.rs | 50 +++++++++------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index 14be9acdc3..a685e33248 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -19,6 +19,8 @@ use types::Hash256; /// Timeout for RPC requests. const REQUEST_TIMEOUT: Duration = Duration::from_secs(30); +/// Timeout before banning a peer for non-identification. +const HELLO_TIMEOUT: Duration = Duration::from_secs(30); /// Handles messages received from the network and client and organises syncing. pub struct MessageHandler { @@ -28,22 +30,17 @@ pub struct MessageHandler { sync: SimpleSync, /// The network channel to relay messages to the Network service. network_send: crossbeam_channel::Sender, - /// A mapping of peers we have sent an RPC request to. - requests: HashMap>, + /// A mapping of peers and the RPC id we have sent an RPC request to. + requests: HashMap<(PeerId, u64), Instant>, + /// A mapping of HELLO requests we have sent. We drop/ban peers if they do not response + /// within the timeout + hello_requests: HashMap, /// A counter of request id for each peer. request_ids: HashMap, /// The `MessageHandler` logger. log: slog::Logger, } -/// RPC request information -pub struct RPCRequestInfo { - /// The id of the request - id: u64, - /// The time the request was sent, to check ttl. - request_time: Instant, -} - /// Types of messages the handler can receive. #[derive(Debug, Clone)] pub enum HandlerMessage { @@ -79,7 +76,9 @@ impl MessageHandler { sync, network_send, requests: HashMap::new(), + hello_requests: HashMap::new(), request_ids: HashMap::new(), + log: log.clone(), }; @@ -140,15 +139,13 @@ impl MessageHandler { fn handle_rpc_response(&mut self, peer_id: PeerId, id: u64, response: RPCResponse) {} fn handle_hello_response(&mut self, peer_id: PeerId, id: u64, response: HelloMessage) { - /* - // if response id is not in our list, ignore (likely RPC timeout) - match self.requests.get(peer_id) { - None => return; - Some(rpc_info) => { - if rpc_info.con - - */ + if self.hello_requests.remove(&peer_id).is_none() { + // if response id is not in our list, ignore (likely RPC timeout) + return; + } + debug!(self.log, "Hello response received from peer: {:?}", peer_id); + // validate peer - decide whether to drop/ban or add to sync } /// Sends a HELLO RPC request to a newly connected peer. @@ -161,17 +158,12 @@ impl MessageHandler { *borrowed_id += 1; id }; - // register RPC request - { - let requests = self - .requests - .entry(peer_id.clone()) - .or_insert_with(|| vec![]); - requests.push(RPCRequestInfo { - id: id.clone(), - request_time: Instant::now(), - }); - } + // register RPC Hello request + self.requests.insert((peer_id.clone(), id), Instant::now()); + debug!( + self.log, + "Hello request registered with peer: {:?}", peer_id + ); // build the rpc request let rpc_event = RPCEvent::Request { From 752c784534f83cbb6dbb8f6d29d0f50fe3fdf8f7 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 19 Mar 2019 14:40:08 +1100 Subject: [PATCH 35/62] Initial handling of RPC HELLO requests --- beacon_node/network/src/message_handler.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index a685e33248..f1a114db14 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -129,7 +129,7 @@ impl MessageHandler { fn handle_rpc_request(&mut self, peer_id: PeerId, id: u64, request: RPCRequest) { match request { RPCRequest::Hello(hello_message) => { - self.handle_hello_response(peer_id, id, hello_message) + // self.handle_hello_request(peer_id, id, hello_message) } } } @@ -146,6 +146,7 @@ impl MessageHandler { debug!(self.log, "Hello response received from peer: {:?}", peer_id); // validate peer - decide whether to drop/ban or add to sync + // TODO: Peer validation } /// Sends a HELLO RPC request to a newly connected peer. From d20fb93f0cd927526881dbaad439c3d827e2d644 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 19 Mar 2019 17:16:33 +1100 Subject: [PATCH 36/62] Update rewards processing to v0.5.0 --- .../src/per_epoch_processing.rs | 309 +++-------------- .../src/per_epoch_processing/apply_rewards.rs | 317 ++++++++++++++++++ .../src/per_epoch_processing/errors.rs | 1 + .../validator_statuses.rs | 41 ++- 4 files changed, 393 insertions(+), 275 deletions(-) create mode 100644 eth2/state_processing/src/per_epoch_processing/apply_rewards.rs diff --git a/eth2/state_processing/src/per_epoch_processing.rs b/eth2/state_processing/src/per_epoch_processing.rs index 8e03457d3e..24f4a1e1ff 100644 --- a/eth2/state_processing/src/per_epoch_processing.rs +++ b/eth2/state_processing/src/per_epoch_processing.rs @@ -1,16 +1,16 @@ +use apply_rewards::apply_rewards; use errors::EpochProcessingError as Error; -use integer_sqrt::IntegerSquareRoot; use process_ejections::process_ejections; use process_exit_queue::process_exit_queue; use process_slashings::process_slashings; use process_validator_registry::process_validator_registry; -use rayon::prelude::*; use ssz::TreeHash; use std::collections::HashMap; use types::*; use validator_statuses::{TotalBalances, ValidatorStatuses}; use winning_root::{winning_root, WinningRoot}; +pub mod apply_rewards; pub mod errors; pub mod get_attestation_participants; pub mod inclusion_distance; @@ -43,13 +43,13 @@ pub fn per_epoch_processing(state: &mut BeaconState, spec: &ChainSpec) -> Result process_eth1_data(state, spec); - process_justification(state, &statuses.total_balances, spec); + update_justification_and_finalization(state, &statuses.total_balances, spec)?; // Crosslinks let winning_root_for_shards = process_crosslinks(state, spec)?; // Rewards and Penalities - process_rewards_and_penalities(state, &mut statuses, &winning_root_for_shards, spec)?; + apply_rewards(state, &mut statuses, &winning_root_for_shards, spec)?; // Ejections process_ejections(state, spec)?; @@ -62,7 +62,7 @@ pub fn per_epoch_processing(state: &mut BeaconState, spec: &ChainSpec) -> Result // Final updates update_active_tree_index_roots(state, spec)?; update_latest_slashed_balances(state, spec)?; - clean_attestations(state); + state.previous_epoch_attestations = vec![]; // Rotate the epoch caches to suit the epoch transition. state.advance_caches(); @@ -113,83 +113,68 @@ pub fn process_eth1_data(state: &mut BeaconState, spec: &ChainSpec) { /// - `justified_epoch` /// - `previous_justified_epoch` /// -/// Spec v0.4.0 -pub fn process_justification( +/// Spec v0.5.0 +pub fn update_justification_and_finalization( state: &mut BeaconState, total_balances: &TotalBalances, spec: &ChainSpec, -) { +) -> Result<(), Error> { let previous_epoch = state.previous_epoch(spec); let current_epoch = state.current_epoch(spec); let mut new_justified_epoch = state.current_justified_epoch; + let mut new_finalized_epoch = state.finalized_epoch; + + // Rotate the justification bitfield up one epoch to make room for the current epoch. state.justification_bitfield <<= 1; - // If > 2/3 of the total balance attested to the previous epoch boundary - // - // - Set the 2nd bit of the bitfield. - // - Set the previous epoch to be justified. - if (3 * total_balances.previous_epoch_boundary_attesters) >= (2 * total_balances.previous_epoch) + // If the previous epoch gets justified, full the second last bit. + if (total_balances.previous_epoch_boundary_attesters * 3) >= (total_balances.previous_epoch * 2) { - state.justification_bitfield |= 2; new_justified_epoch = previous_epoch; + state.justification_bitfield |= 2; } - // If > 2/3 of the total balance attested to the previous epoch boundary - // - // - Set the 1st bit of the bitfield. - // - Set the current epoch to be justified. - if (3 * total_balances.current_epoch_boundary_attesters) >= (2 * total_balances.current_epoch) { - state.justification_bitfield |= 1; + // If the current epoch gets justified, fill the last bit. + if (total_balances.current_epoch_boundary_attesters * 3) >= (total_balances.current_epoch * 2) { new_justified_epoch = current_epoch; + state.justification_bitfield |= 1; } - // If: - // - // - All three epochs prior to this epoch have been justified. - // - The previous justified justified epoch was three epochs ago. - // - // Then, set the finalized epoch to be three epochs ago. - if ((state.justification_bitfield >> 1) % 8 == 0b111) - & (state.previous_justified_epoch == previous_epoch - 2) - { - state.finalized_epoch = state.previous_justified_epoch; + let bitfield = state.justification_bitfield; + + // The 2nd/3rd/4th most recent epochs are all justified, the 2nd using the 4th as source. + if ((bitfield >> 1) % 8 == 0b111) & (state.previous_justified_epoch == current_epoch - 3) { + new_finalized_epoch = state.previous_justified_epoch; } - // If: - // - // - Both two epochs prior to this epoch have been justified. - // - The previous justified epoch was two epochs ago. - // - // Then, set the finalized epoch to two epochs ago. - if ((state.justification_bitfield >> 1) % 4 == 0b11) - & (state.previous_justified_epoch == previous_epoch - 1) - { - state.finalized_epoch = state.previous_justified_epoch; + // The 2nd/3rd most recent epochs are both justified, the 2nd using the 3rd as source. + if ((bitfield >> 1) % 4 == 0b11) & (state.previous_justified_epoch == current_epoch - 2) { + new_finalized_epoch = state.previous_justified_epoch; } - // If: - // - // - This epoch and the two prior have been justified. - // - The presently justified epoch was two epochs ago. - // - // Then, set the finalized epoch to two epochs ago. - if (state.justification_bitfield % 8 == 0b111) - & (state.current_justified_epoch == previous_epoch - 1) - { - state.finalized_epoch = state.current_justified_epoch; + // The 1st/2nd/3rd most recent epochs are all justified, the 1st using the 2nd as source. + if (bitfield % 8 == 0b111) & (state.current_justified_epoch == current_epoch - 2) { + new_finalized_epoch = state.current_justified_epoch; } - // If: - // - // - This epoch and the epoch prior to it have been justified. - // - Set the previous epoch to be justified. - // - // Then, set the finalized epoch to be the previous epoch. - if (state.justification_bitfield % 4 == 0b11) - & (state.current_justified_epoch == previous_epoch) - { - state.finalized_epoch = state.current_justified_epoch; + // The 1st/2nd most recent epochs are both justified, the 1st using the 2nd as source. + if (bitfield % 4 == 0b11) & (state.current_justified_epoch == current_epoch - 1) { + new_finalized_epoch = state.current_justified_epoch; } state.previous_justified_epoch = state.current_justified_epoch; - state.current_justified_epoch = new_justified_epoch; + state.previous_justified_root = state.current_justified_root; + + if new_justified_epoch != state.current_justified_epoch { + state.current_justified_epoch = new_justified_epoch; + state.current_justified_root = + *state.get_block_root(new_justified_epoch.start_slot(spec.slots_per_epoch), spec)?; + } + + if new_finalized_epoch != state.finalized_epoch { + state.finalized_epoch = new_finalized_epoch; + state.finalized_root = + *state.get_block_root(new_finalized_epoch.start_slot(spec.slots_per_epoch), spec)?; + } + + Ok(()) } /// Updates the following fields on the `BeaconState`: @@ -239,201 +224,6 @@ pub fn process_crosslinks( Ok(winning_root_for_shards) } -/// Updates the following fields on the BeaconState: -/// -/// - `validator_balances` -/// -/// Spec v0.4.0 -pub fn process_rewards_and_penalities( - state: &mut BeaconState, - statuses: &mut ValidatorStatuses, - winning_root_for_shards: &WinningRootHashSet, - spec: &ChainSpec, -) -> Result<(), Error> { - let next_epoch = state.next_epoch(spec); - - statuses.process_winning_roots(state, winning_root_for_shards, spec)?; - - let total_balances = &statuses.total_balances; - - let base_reward_quotient = - total_balances.previous_epoch.integer_sqrt() / spec.base_reward_quotient; - - // Guard against a divide-by-zero during the validator balance update. - if base_reward_quotient == 0 { - return Err(Error::BaseRewardQuotientIsZero); - } - // Guard against a divide-by-zero during the validator balance update. - if total_balances.previous_epoch == 0 { - return Err(Error::PreviousTotalBalanceIsZero); - } - // Guard against an out-of-bounds during the validator balance update. - if statuses.statuses.len() != state.validator_balances.len() { - return Err(Error::ValidatorStatusesInconsistent); - } - - // Justification and finalization - - let epochs_since_finality = next_epoch - state.finalized_epoch; - - state.validator_balances = state - .validator_balances - .par_iter() - .enumerate() - .map(|(index, &balance)| { - let mut balance = balance; - let status = &statuses.statuses[index]; - let base_reward = get_base_reward(state, index, total_balances.previous_epoch, spec) - .expect( - "Cannot fail to access a validator balance when iterating validator balances.", - ); - - if epochs_since_finality <= 4 { - // Expected FFG source - if status.is_previous_epoch_attester { - safe_add_assign!( - balance, - base_reward * total_balances.previous_epoch_attesters - / total_balances.previous_epoch - ); - } else if status.is_active_in_previous_epoch { - safe_sub_assign!(balance, base_reward); - } - - // Expected FFG target - if status.is_previous_epoch_boundary_attester { - safe_add_assign!( - balance, - base_reward * total_balances.previous_epoch_boundary_attesters - / total_balances.previous_epoch - ); - } else if status.is_active_in_previous_epoch { - safe_sub_assign!(balance, base_reward); - } - - // Expected beacon chain head - if status.is_previous_epoch_head_attester { - safe_add_assign!( - balance, - base_reward * total_balances.previous_epoch_head_attesters - / total_balances.previous_epoch - ); - } else if status.is_active_in_previous_epoch { - safe_sub_assign!(balance, base_reward); - }; - } else { - let inactivity_penalty = get_inactivity_penalty( - state, - index, - epochs_since_finality.as_u64(), - total_balances.previous_epoch, - spec, - ) - .expect( - "Cannot fail to access a validator balance when iterating validator balances.", - ); - - if status.is_active_in_previous_epoch { - if !status.is_previous_epoch_attester { - safe_sub_assign!(balance, inactivity_penalty); - } - if !status.is_previous_epoch_boundary_attester { - safe_sub_assign!(balance, inactivity_penalty); - } - if !status.is_previous_epoch_head_attester { - safe_sub_assign!(balance, inactivity_penalty); - } - - if state.validator_registry[index].slashed { - let base_reward = - get_base_reward(state, index, total_balances.previous_epoch, spec).expect( - "Cannot fail to access a validator balance when iterating validator balances.", - ); - safe_sub_assign!(balance, 2 * inactivity_penalty + base_reward); - } - } - } - - // Crosslinks - - if let Some(ref info) = status.winning_root_info { - safe_add_assign!( - balance, - base_reward * info.total_attesting_balance / info.total_committee_balance - ); - } else { - safe_sub_assign!(balance, base_reward); - } - - balance - }) - .collect(); - - // Attestation inclusion - - // Guard against an out-of-bounds during the attester inclusion balance update. - if statuses.statuses.len() != state.validator_registry.len() { - return Err(Error::ValidatorStatusesInconsistent); - } - - for (index, _validator) in state.validator_registry.iter().enumerate() { - let status = &statuses.statuses[index]; - - if status.is_previous_epoch_attester { - let proposer_index = status.inclusion_info.proposer_index; - let inclusion_distance = status.inclusion_info.distance; - - let base_reward = - get_base_reward(state, proposer_index, total_balances.previous_epoch, spec).expect( - "Cannot fail to access a validator balance when iterating validator balances.", - ); - - if inclusion_distance > 0 && inclusion_distance < Slot::max_value() { - safe_add_assign!( - state.validator_balances[proposer_index], - base_reward * spec.min_attestation_inclusion_delay - / inclusion_distance.as_u64() - ) - } - } - } - - Ok(()) -} - -/// Returns the base reward for some validator. -/// -/// Spec v0.5.0 -pub fn get_base_reward( - state: &BeaconState, - index: usize, - previous_total_balance: u64, - spec: &ChainSpec, -) -> Result { - if previous_total_balance == 0 { - Ok(0) - } else { - let adjusted_quotient = previous_total_balance.integer_sqrt() / spec.base_reward_quotient; - Ok(state.get_effective_balance(index, spec)? / adjusted_quotient / 5) - } -} - -/// Returns the inactivity penalty for some validator. -/// -/// Spec v0.5.0 -pub fn get_inactivity_penalty( - state: &BeaconState, - index: usize, - epochs_since_finality: u64, - previous_total_balance: u64, - spec: &ChainSpec, -) -> Result { - Ok(get_base_reward(state, index, previous_total_balance, spec)? - + state.get_effective_balance(index, spec)? * epochs_since_finality - / spec.inactivity_penalty_quotient - / 2) -} - /// Updates the state's `latest_active_index_roots` field with a tree hash the active validator /// indices for the next epoch. /// @@ -472,10 +262,3 @@ pub fn update_latest_slashed_balances( Ok(()) } - -/// Removes all pending attestations from the previous epoch. -/// -/// Spec v0.4.0 -pub fn clean_attestations(state: &mut BeaconState) { - state.previous_epoch_attestations = vec![]; -} diff --git a/eth2/state_processing/src/per_epoch_processing/apply_rewards.rs b/eth2/state_processing/src/per_epoch_processing/apply_rewards.rs new file mode 100644 index 0000000000..5254e0710e --- /dev/null +++ b/eth2/state_processing/src/per_epoch_processing/apply_rewards.rs @@ -0,0 +1,317 @@ +use super::validator_statuses::{TotalBalances, ValidatorStatus, ValidatorStatuses}; +use super::{Error, WinningRootHashSet}; +use integer_sqrt::IntegerSquareRoot; +use types::*; + +#[derive(Default, Clone)] +pub struct Delta { + pub rewards: u64, + pub penalties: u64, +} + +impl std::ops::AddAssign for Delta { + /// Use wrapping addition as that is how it's defined in the spec. + fn add_assign(&mut self, other: Delta) { + self.rewards += other.rewards; + self.penalties += other.penalties; + } +} + +/// Apply attester and proposer rewards. +/// +/// Spec v0.5.0 +pub fn apply_rewards( + state: &mut BeaconState, + validator_statuses: &mut ValidatorStatuses, + winning_root_for_shards: &WinningRootHashSet, + spec: &ChainSpec, +) -> Result<(), Error> { + // Guard against an out-of-bounds during the validator balance update. + if validator_statuses.statuses.len() != state.validator_balances.len() { + return Err(Error::ValidatorStatusesInconsistent); + } + // Guard against an out-of-bounds during the attester inclusion balance update. + if validator_statuses.statuses.len() != state.validator_registry.len() { + return Err(Error::ValidatorStatusesInconsistent); + } + + let mut deltas = vec![Delta::default(); state.validator_balances.len()]; + + get_justification_and_finalization_deltas(&mut deltas, state, &validator_statuses, spec)?; + get_crosslink_deltas(&mut deltas, state, &validator_statuses, spec)?; + + // Apply the proposer deltas if we are finalizing normally. + // + // This is executed slightly differently to the spec because of the way our functions are + // structured. It should be functionally equivalent. + if epochs_since_finality(state, spec) <= 4 { + get_proposer_deltas( + &mut deltas, + state, + validator_statuses, + winning_root_for_shards, + spec, + )?; + } + + // Apply the deltas, over-flowing but not under-flowing (saturating at 0 instead). + for (i, delta) in deltas.iter().enumerate() { + state.validator_balances[i] += delta.rewards; + state.validator_balances[i] = state.validator_balances[i].saturating_sub(delta.penalties); + } + + Ok(()) +} + +/// Applies the attestation inclusion reward to each proposer for every validator who included an +/// attestation in the previous epoch. +/// +/// Spec v0.5.0 +fn get_proposer_deltas( + deltas: &mut Vec, + state: &mut BeaconState, + validator_statuses: &mut ValidatorStatuses, + winning_root_for_shards: &WinningRootHashSet, + spec: &ChainSpec, +) -> Result<(), Error> { + // Update statuses with the information from winning roots. + validator_statuses.process_winning_roots(state, winning_root_for_shards, spec)?; + + for (index, validator) in validator_statuses.statuses.iter().enumerate() { + let mut delta = Delta::default(); + + if validator.is_previous_epoch_attester { + let inclusion = validator + .inclusion_info + .expect("It is a logic error for an attester not to have an inclusion distance."); + + let base_reward = get_base_reward( + state, + inclusion.proposer_index, + validator_statuses.total_balances.previous_epoch, + spec, + )?; + + if inclusion.proposer_index >= deltas.len() { + return Err(Error::ValidatorStatusesInconsistent); + } + + delta.rewards += base_reward / spec.attestation_inclusion_reward_quotient; + } + + deltas[index] += delta; + } + + Ok(()) +} + +/// Apply rewards for participation in attestations during the previous epoch. +/// +/// Spec v0.5.0 +fn get_justification_and_finalization_deltas( + deltas: &mut Vec, + state: &BeaconState, + validator_statuses: &ValidatorStatuses, + spec: &ChainSpec, +) -> Result<(), Error> { + let epochs_since_finality = epochs_since_finality(state, spec); + + for (index, validator) in validator_statuses.statuses.iter().enumerate() { + let base_reward = get_base_reward( + state, + index, + validator_statuses.total_balances.previous_epoch, + spec, + )?; + let inactivity_penalty = get_inactivity_penalty( + state, + index, + epochs_since_finality.as_u64(), + validator_statuses.total_balances.previous_epoch, + spec, + )?; + + let delta = if epochs_since_finality <= 4 { + compute_normal_justification_and_finalization_delta( + &validator, + &validator_statuses.total_balances, + base_reward, + spec, + ) + } else { + compute_inactivity_leak_delta(&validator, base_reward, inactivity_penalty, spec) + }; + + deltas[index] += delta; + } + + Ok(()) +} + +/// Determine the delta for a single validator, if the chain is finalizing normally. +/// +/// Spec v0.5.0 +fn compute_normal_justification_and_finalization_delta( + validator: &ValidatorStatus, + total_balances: &TotalBalances, + base_reward: u64, + spec: &ChainSpec, +) -> Delta { + let mut delta = Delta::default(); + + let boundary_attesting_balance = total_balances.previous_epoch_boundary_attesters; + let total_balance = total_balances.previous_epoch; + let total_attesting_balance = total_balances.previous_epoch_attesters; + let matching_head_balance = total_balances.previous_epoch_boundary_attesters; + + // Expected FFG source. + if validator.is_previous_epoch_attester { + delta.rewards += base_reward * total_attesting_balance / total_balance; + // Inclusion speed bonus + let inclusion = validator + .inclusion_info + .expect("It is a logic error for an attester not to have an inclusion distance."); + delta.rewards += + base_reward * spec.min_attestation_inclusion_delay / inclusion.distance.as_u64(); + } else if validator.is_active_in_previous_epoch { + delta.penalties += base_reward; + } + + // Expected FFG target. + if validator.is_previous_epoch_boundary_attester { + delta.rewards += base_reward / boundary_attesting_balance / total_balance; + } else if validator.is_active_in_previous_epoch { + delta.penalties += base_reward; + } + + // Expected head. + if validator.is_previous_epoch_head_attester { + delta.rewards += base_reward * matching_head_balance / total_balance; + } else if validator.is_active_in_previous_epoch { + delta.penalties += base_reward; + }; + + // Proposer bonus is handled in `apply_proposer_deltas`. + // + // This function only computes the delta for a single validator, so it cannot also return a + // delta for a validator. + + delta +} + +/// Determine the delta for a single delta, assuming the chain is _not_ finalizing normally. +/// +/// Spec v0.5.0 +fn compute_inactivity_leak_delta( + validator: &ValidatorStatus, + base_reward: u64, + inactivity_penalty: u64, + spec: &ChainSpec, +) -> Delta { + let mut delta = Delta::default(); + + if validator.is_active_in_previous_epoch { + if !validator.is_previous_epoch_attester { + delta.penalties += inactivity_penalty; + } else { + // If a validator did attest, apply a small penalty for getting attestations included + // late. + let inclusion = validator + .inclusion_info + .expect("It is a logic error for an attester not to have an inclusion distance."); + delta.rewards += + base_reward * spec.min_attestation_inclusion_delay / inclusion.distance.as_u64(); + delta.penalties += base_reward; + } + + if !validator.is_previous_epoch_boundary_attester { + delta.penalties += inactivity_penalty; + } + + if !validator.is_previous_epoch_head_attester { + delta.penalties += inactivity_penalty; + } + } + + // Penalize slashed-but-inactive validators as though they were active but offline. + if !validator.is_active_in_previous_epoch + & validator.is_slashed + & !validator.is_withdrawable_in_current_epoch + { + delta.penalties += 2 * inactivity_penalty + base_reward; + } + + delta +} + +/// Calculate the deltas based upon the winning roots for attestations during the previous epoch. +/// +/// Spec v0.5.0 +fn get_crosslink_deltas( + deltas: &mut Vec, + state: &BeaconState, + validator_statuses: &ValidatorStatuses, + spec: &ChainSpec, +) -> Result<(), Error> { + for (index, validator) in validator_statuses.statuses.iter().enumerate() { + let mut delta = Delta::default(); + + let base_reward = get_base_reward( + state, + index, + validator_statuses.total_balances.previous_epoch, + spec, + )?; + + if let Some(ref winning_root) = validator.winning_root_info { + delta.rewards += base_reward * winning_root.total_attesting_balance + / winning_root.total_committee_balance + } else { + delta.penalties += base_reward; + } + + deltas[index] += delta; + } + + Ok(()) +} + +/// Returns the base reward for some validator. +/// +/// Spec v0.5.0 +fn get_base_reward( + state: &BeaconState, + index: usize, + previous_total_balance: u64, + spec: &ChainSpec, +) -> Result { + if previous_total_balance == 0 { + Ok(0) + } else { + let adjusted_quotient = previous_total_balance.integer_sqrt() / spec.base_reward_quotient; + Ok(state.get_effective_balance(index, spec)? / adjusted_quotient / 5) + } +} + +/// Returns the inactivity penalty for some validator. +/// +/// Spec v0.5.0 +fn get_inactivity_penalty( + state: &BeaconState, + index: usize, + epochs_since_finality: u64, + previous_total_balance: u64, + spec: &ChainSpec, +) -> Result { + Ok(get_base_reward(state, index, previous_total_balance, spec)? + + state.get_effective_balance(index, spec)? * epochs_since_finality + / spec.inactivity_penalty_quotient + / 2) +} + +/// Returns the epochs since the last finalized epoch. +/// +/// Spec v0.5.0 +fn epochs_since_finality(state: &BeaconState, spec: &ChainSpec) -> Epoch { + state.current_epoch(spec) + 1 - state.finalized_epoch +} diff --git a/eth2/state_processing/src/per_epoch_processing/errors.rs b/eth2/state_processing/src/per_epoch_processing/errors.rs index 94fc0cca5b..4632e83bb5 100644 --- a/eth2/state_processing/src/per_epoch_processing/errors.rs +++ b/eth2/state_processing/src/per_epoch_processing/errors.rs @@ -9,6 +9,7 @@ pub enum EpochProcessingError { PreviousTotalBalanceIsZero, InclusionDistanceZero, ValidatorStatusesInconsistent, + DeltasInconsistent, /// Unable to get the inclusion distance for a validator that should have an inclusion /// distance. This indicates an internal inconsistency. /// diff --git a/eth2/state_processing/src/per_epoch_processing/validator_statuses.rs b/eth2/state_processing/src/per_epoch_processing/validator_statuses.rs index bcbca82440..50f3ec3727 100644 --- a/eth2/state_processing/src/per_epoch_processing/validator_statuses.rs +++ b/eth2/state_processing/src/per_epoch_processing/validator_statuses.rs @@ -23,7 +23,7 @@ pub struct WinningRootInfo { } /// The information required to reward a block producer for including an attestation in a block. -#[derive(Clone)] +#[derive(Clone, Copy)] pub struct InclusionInfo { /// The earliest slot a validator had an attestation included in the previous epoch. pub slot: Slot, @@ -59,7 +59,11 @@ impl InclusionInfo { /// Information required to reward some validator during the current and previous epoch. #[derive(Default, Clone)] -pub struct AttesterStatus { +pub struct ValidatorStatus { + /// True if the validator has been slashed, ever. + pub is_slashed: bool, + /// True if the validator can withdraw in the current epoch. + pub is_withdrawable_in_current_epoch: bool, /// True if the validator was active in the state's _current_ epoch. pub is_active_in_current_epoch: bool, /// True if the validator was active in the state's _previous_ epoch. @@ -81,14 +85,14 @@ pub struct AttesterStatus { /// Information used to reward the block producer of this validators earliest-included /// attestation. - pub inclusion_info: InclusionInfo, + pub inclusion_info: Option, /// Information used to reward/penalize the validator if they voted in the super-majority for /// some shard block. pub winning_root_info: Option, } -impl AttesterStatus { - /// Accepts some `other` `AttesterStatus` and updates `self` if required. +impl ValidatorStatus { + /// Accepts some `other` `ValidatorStatus` and updates `self` if required. /// /// Will never set one of the `bool` fields to `false`, it will only set it to `true` if other /// contains a `true` field. @@ -97,6 +101,8 @@ impl AttesterStatus { pub fn update(&mut self, other: &Self) { // Update all the bool fields, only updating `self` if `other` is true (never setting // `self` to false). + set_self_if_other_is_true!(self, other, is_slashed); + set_self_if_other_is_true!(self, other, is_withdrawable_in_current_epoch); set_self_if_other_is_true!(self, other, is_active_in_current_epoch); set_self_if_other_is_true!(self, other, is_active_in_previous_epoch); set_self_if_other_is_true!(self, other, is_current_epoch_attester); @@ -105,7 +111,13 @@ impl AttesterStatus { set_self_if_other_is_true!(self, other, is_previous_epoch_boundary_attester); set_self_if_other_is_true!(self, other, is_previous_epoch_head_attester); - self.inclusion_info.update(&other.inclusion_info); + if let Some(other_info) = other.inclusion_info { + if let Some(self_info) = self.inclusion_info.as_mut() { + self_info.update(&other_info); + } else { + self.inclusion_info = other.inclusion_info; + } + } } } @@ -137,7 +149,7 @@ pub struct TotalBalances { #[derive(Clone)] pub struct ValidatorStatuses { /// Information about each individual validator from the state's validator registy. - pub statuses: Vec, + pub statuses: Vec, /// Summed balances for various sets of validators. pub total_balances: TotalBalances, } @@ -154,7 +166,12 @@ impl ValidatorStatuses { let mut total_balances = TotalBalances::default(); for (i, validator) in state.validator_registry.iter().enumerate() { - let mut status = AttesterStatus::default(); + let mut status = ValidatorStatus { + is_slashed: validator.slashed, + is_withdrawable_in_current_epoch: validator + .is_withdrawable_at(state.current_epoch(spec)), + ..ValidatorStatus::default() + }; if validator.is_active_at(state.current_epoch(spec)) { status.is_active_in_current_epoch = true; @@ -193,10 +210,10 @@ impl ValidatorStatuses { get_attestation_participants(state, &a.data, &a.aggregation_bitfield, spec)?; let attesting_balance = state.get_total_balance(&attesting_indices, spec)?; - let mut status = AttesterStatus::default(); + let mut status = ValidatorStatus::default(); // Profile this attestation, updating the total balances and generating an - // `AttesterStatus` object that applies to all participants in the attestation. + // `ValidatorStatus` object that applies to all participants in the attestation. if is_from_epoch(a, state.current_epoch(spec), spec) { self.total_balances.current_epoch_attesters += attesting_balance; status.is_current_epoch_attester = true; @@ -211,7 +228,7 @@ impl ValidatorStatuses { // The inclusion slot and distance are only required for previous epoch attesters. let relative_epoch = RelativeEpoch::from_slot(state.slot, a.data.slot, spec)?; - status.inclusion_info = InclusionInfo { + status.inclusion_info = Some(InclusionInfo { slot: a.inclusion_slot, distance: inclusion_distance(a), proposer_index: state.get_beacon_proposer_index( @@ -219,7 +236,7 @@ impl ValidatorStatuses { relative_epoch, spec, )?, - }; + }); if has_common_epoch_boundary_root(a, state, state.previous_epoch(spec), spec)? { self.total_balances.previous_epoch_boundary_attesters += attesting_balance; From 61f6fe25e7760ef60d1ee58207211a7493096a66 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 19 Mar 2019 17:26:20 +1100 Subject: [PATCH 37/62] Tidy reward processing --- .../src/per_epoch_processing/apply_rewards.rs | 59 ++++++++++++------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/eth2/state_processing/src/per_epoch_processing/apply_rewards.rs b/eth2/state_processing/src/per_epoch_processing/apply_rewards.rs index 5254e0710e..ce5fccb210 100644 --- a/eth2/state_processing/src/per_epoch_processing/apply_rewards.rs +++ b/eth2/state_processing/src/per_epoch_processing/apply_rewards.rs @@ -3,10 +3,23 @@ use super::{Error, WinningRootHashSet}; use integer_sqrt::IntegerSquareRoot; use types::*; +/// Use to track the changes to a validators balance. #[derive(Default, Clone)] pub struct Delta { - pub rewards: u64, - pub penalties: u64, + rewards: u64, + penalties: u64, +} + +impl Delta { + /// Reward the validator with the `reward`. + pub fn reward(&mut self, reward: u64) { + self.rewards += reward; + } + + /// Penalize the validator with the `penalty`. + pub fn penalize(&mut self, penalty: u64) { + self.penalties += penalty; + } } impl std::ops::AddAssign for Delta { @@ -96,7 +109,7 @@ fn get_proposer_deltas( return Err(Error::ValidatorStatusesInconsistent); } - delta.rewards += base_reward / spec.attestation_inclusion_reward_quotient; + delta.reward(base_reward / spec.attestation_inclusion_reward_quotient); } deltas[index] += delta; @@ -166,29 +179,30 @@ fn compute_normal_justification_and_finalization_delta( // Expected FFG source. if validator.is_previous_epoch_attester { - delta.rewards += base_reward * total_attesting_balance / total_balance; + delta.reward(base_reward * total_attesting_balance / total_balance); // Inclusion speed bonus let inclusion = validator .inclusion_info .expect("It is a logic error for an attester not to have an inclusion distance."); - delta.rewards += - base_reward * spec.min_attestation_inclusion_delay / inclusion.distance.as_u64(); + delta.reward( + base_reward * spec.min_attestation_inclusion_delay / inclusion.distance.as_u64(), + ); } else if validator.is_active_in_previous_epoch { - delta.penalties += base_reward; + delta.penalize(base_reward); } // Expected FFG target. if validator.is_previous_epoch_boundary_attester { - delta.rewards += base_reward / boundary_attesting_balance / total_balance; + delta.reward(base_reward / boundary_attesting_balance / total_balance); } else if validator.is_active_in_previous_epoch { - delta.penalties += base_reward; + delta.penalize(base_reward); } // Expected head. if validator.is_previous_epoch_head_attester { - delta.rewards += base_reward * matching_head_balance / total_balance; + delta.reward(base_reward * matching_head_balance / total_balance); } else if validator.is_active_in_previous_epoch { - delta.penalties += base_reward; + delta.penalize(base_reward); }; // Proposer bonus is handled in `apply_proposer_deltas`. @@ -212,24 +226,25 @@ fn compute_inactivity_leak_delta( if validator.is_active_in_previous_epoch { if !validator.is_previous_epoch_attester { - delta.penalties += inactivity_penalty; + delta.penalize(inactivity_penalty); } else { // If a validator did attest, apply a small penalty for getting attestations included // late. let inclusion = validator .inclusion_info .expect("It is a logic error for an attester not to have an inclusion distance."); - delta.rewards += - base_reward * spec.min_attestation_inclusion_delay / inclusion.distance.as_u64(); - delta.penalties += base_reward; + delta.reward( + base_reward * spec.min_attestation_inclusion_delay / inclusion.distance.as_u64(), + ); + delta.penalize(base_reward); } if !validator.is_previous_epoch_boundary_attester { - delta.penalties += inactivity_penalty; + delta.reward(inactivity_penalty); } if !validator.is_previous_epoch_head_attester { - delta.penalties += inactivity_penalty; + delta.penalize(inactivity_penalty); } } @@ -238,7 +253,7 @@ fn compute_inactivity_leak_delta( & validator.is_slashed & !validator.is_withdrawable_in_current_epoch { - delta.penalties += 2 * inactivity_penalty + base_reward; + delta.penalize(2 * inactivity_penalty + base_reward); } delta @@ -264,10 +279,12 @@ fn get_crosslink_deltas( )?; if let Some(ref winning_root) = validator.winning_root_info { - delta.rewards += base_reward * winning_root.total_attesting_balance - / winning_root.total_committee_balance + delta.reward( + base_reward * winning_root.total_attesting_balance + / winning_root.total_committee_balance, + ); } else { - delta.penalties += base_reward; + delta.penalize(base_reward); } deltas[index] += delta; From c0bc45f1f3f35ce66cfa6383745ffb322f7b615b Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 19 Mar 2019 18:28:42 +1100 Subject: [PATCH 38/62] Implement node connection validation structure --- beacon_node/network/src/message_handler.rs | 59 ++++++++++++++------- beacon_node/network/src/sync/simple_sync.rs | 42 +++++++++++++-- 2 files changed, 79 insertions(+), 22 deletions(-) diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index f1a114db14..17e74fda23 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -32,9 +32,6 @@ pub struct MessageHandler { network_send: crossbeam_channel::Sender, /// A mapping of peers and the RPC id we have sent an RPC request to. requests: HashMap<(PeerId, u64), Instant>, - /// A mapping of HELLO requests we have sent. We drop/ban peers if they do not response - /// within the timeout - hello_requests: HashMap, /// A counter of request id for each peer. request_ids: HashMap, /// The `MessageHandler` logger. @@ -76,7 +73,6 @@ impl MessageHandler { sync, network_send, requests: HashMap::new(), - hello_requests: HashMap::new(), request_ids: HashMap::new(), log: log.clone(), @@ -99,7 +95,8 @@ impl MessageHandler { match message { // we have initiated a connection to a peer HandlerMessage::PeerDialed(peer_id) => { - self.send_hello_request(peer_id); + let id = self.generate_request_id(&peer_id); + self.send_hello(peer_id, id, true); } // we have received an RPC message request/response HandlerMessage::RPC(peer_id, rpc_event) => { @@ -129,28 +126,41 @@ impl MessageHandler { fn handle_rpc_request(&mut self, peer_id: PeerId, id: u64, request: RPCRequest) { match request { RPCRequest::Hello(hello_message) => { - // self.handle_hello_request(peer_id, id, hello_message) + self.handle_hello_request(peer_id, id, hello_message) } } } /// An RPC response has been received from the network. // we match on id and ignore responses past the timeout. - fn handle_rpc_response(&mut self, peer_id: PeerId, id: u64, response: RPCResponse) {} - - fn handle_hello_response(&mut self, peer_id: PeerId, id: u64, response: HelloMessage) { - if self.hello_requests.remove(&peer_id).is_none() { - // if response id is not in our list, ignore (likely RPC timeout) + fn handle_rpc_response(&mut self, peer_id: PeerId, id: u64, response: RPCResponse) { + // if response id is related to a request, ignore (likely RPC timeout) + if self.requests.remove(&(peer_id, id)).is_none() { return; } + } + fn handle_hello_request(&mut self, peer_id: PeerId, id: u64, hello_message: HelloMessage) { + // send back a HELLO message + self.send_hello(peer_id.clone(), id, false); + // validate the peer + if !self.sync.validate_peer(peer_id.clone(), hello_message) { + debug!( + self.log, + "Peer dropped due to mismatching HELLO messages: {:?}", peer_id + ); + //TODO: block/ban the peer + } + } + + fn handle_hello_response(&mut self, peer_id: PeerId, id: u64, response: HelloMessage) { debug!(self.log, "Hello response received from peer: {:?}", peer_id); // validate peer - decide whether to drop/ban or add to sync // TODO: Peer validation } - /// Sends a HELLO RPC request to a newly connected peer. - fn send_hello_request(&mut self, peer_id: PeerId) { + /// Generates a new request id for a peer. + fn generate_request_id(&mut self, peer_id: &PeerId) -> u64 { // generate a unique id for the peer let id = { let borrowed_id = self.request_ids.entry(peer_id.clone()).or_insert_with(|| 0); @@ -159,18 +169,29 @@ impl MessageHandler { *borrowed_id += 1; id }; - // register RPC Hello request + // register RPC request self.requests.insert((peer_id.clone(), id), Instant::now()); debug!( self.log, "Hello request registered with peer: {:?}", peer_id ); + id + } - // build the rpc request - let rpc_event = RPCEvent::Request { - id, - method_id: RPCMethod::Hello.into(), - body: RPCRequest::Hello(self.sync.generate_hello()), + /// Sends a HELLO RPC request or response to a newly connected peer. + //TODO: The boolean determines if sending request/respond, will be cleaner in the RPC re-write + fn send_hello(&mut self, peer_id: PeerId, id: u64, request: bool) { + let rpc_event = match request { + true => RPCEvent::Request { + id, + method_id: RPCMethod::Hello.into(), + body: RPCRequest::Hello(self.sync.generate_hello()), + }, + false => RPCEvent::Response { + id, + method_id: RPCMethod::Hello.into(), + result: RPCResponse::Hello(self.sync.generate_hello()), + }, }; // send the hello request to the network diff --git a/beacon_node/network/src/sync/simple_sync.rs b/beacon_node/network/src/sync/simple_sync.rs index 336f225b2a..2a3cc70892 100644 --- a/beacon_node/network/src/sync/simple_sync.rs +++ b/beacon_node/network/src/sync/simple_sync.rs @@ -32,15 +32,22 @@ pub struct SimpleSync { state: SyncState, /// The network id, for quick HELLO RPC message lookup. network_id: u8, + /// The latest epoch of the syncing chain. + latest_finalized_epoch: Epoch, + /// The latest block of the syncing chain. + latest_block: Hash256, } impl SimpleSync { pub fn new(beacon_chain: Arc) -> Self { + let state = beacon_chain.get_state(); SimpleSync { + chain: beacon_chain.clone(), known_peers: HashMap::new(), state: SyncState::Idle, network_id: beacon_chain.get_spec().network_id, - chain: beacon_chain, + latest_finalized_epoch: state.finalized_epoch, + latest_block: state.finalized_root, //TODO: Build latest block function into Beacon chain and correct this } } @@ -52,8 +59,37 @@ impl SimpleSync { network_id: self.network_id, latest_finalized_root: state.finalized_root.clone(), latest_finalized_epoch: state.finalized_epoch, - best_root: state.latest_block_roots[0], // 0 or len of vec? - best_slot: state.slot, + best_root: state.latest_block_roots[0], //TODO: build correct value as a beacon chain function + best_slot: state.slot - 1, } } + + pub fn validate_peer(&mut self, peer_id: PeerId, hello_message: HelloMessage) -> bool { + // network id must match + if hello_message.network_id != self.network_id { + return false; + } + // compare latest epoch and finalized root to see if they exist in our chain + if hello_message.latest_finalized_epoch <= self.latest_finalized_epoch { + // ensure their finalized root is in our chain + // TODO: Get the finalized root at hello_message.latest_epoch and ensure they match + //if (hello_message.latest_finalized_root == self.chain.get_state() { + // return false; + // } + } + + // the client is valid, add it to our list of known_peers and request sync if required + // update peer list if peer already exists + let peer_info = PeerSyncInfo { + latest_finalized_root: hello_message.latest_finalized_root, + latest_finalized_epoch: hello_message.latest_finalized_epoch, + best_root: hello_message.best_root, + best_slot: hello_message.best_slot, + }; + + self.known_peers.insert(peer_id, peer_info); + //TODO: Start syncing + + true + } } From 35b90728c72dfc043ed4aacba8919014f01a4c08 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 19 Mar 2019 19:27:10 +1100 Subject: [PATCH 39/62] Push more epoch processing fns to 0.5.0 --- .../src/common/verify_bitfield.rs | 2 +- .../src/per_epoch_processing.rs | 122 +++++++------- .../process_validator_registry.rs | 70 -------- .../update_registry_and_shuffling_data.rs | 151 ++++++++++++++++++ .../update_validator_registry.rs | 52 ------ eth2/types/src/beacon_state.rs | 74 +++++---- 6 files changed, 252 insertions(+), 219 deletions(-) delete mode 100644 eth2/state_processing/src/per_epoch_processing/process_validator_registry.rs create mode 100644 eth2/state_processing/src/per_epoch_processing/update_registry_and_shuffling_data.rs delete mode 100644 eth2/state_processing/src/per_epoch_processing/update_validator_registry.rs diff --git a/eth2/state_processing/src/common/verify_bitfield.rs b/eth2/state_processing/src/common/verify_bitfield.rs index 8ff5c96ca3..03fcdbb671 100644 --- a/eth2/state_processing/src/common/verify_bitfield.rs +++ b/eth2/state_processing/src/common/verify_bitfield.rs @@ -4,7 +4,7 @@ use types::*; /// /// Is title `verify_bitfield` in spec. /// -/// Spec v0.4.0 +/// Spec v0.5.0 pub fn verify_bitfield_length(bitfield: &Bitfield, committee_size: usize) -> bool { if bitfield.num_bytes() != ((committee_size + 7) / 8) { return false; diff --git a/eth2/state_processing/src/per_epoch_processing.rs b/eth2/state_processing/src/per_epoch_processing.rs index 24f4a1e1ff..b917510f2e 100644 --- a/eth2/state_processing/src/per_epoch_processing.rs +++ b/eth2/state_processing/src/per_epoch_processing.rs @@ -3,10 +3,10 @@ use errors::EpochProcessingError as Error; use process_ejections::process_ejections; use process_exit_queue::process_exit_queue; use process_slashings::process_slashings; -use process_validator_registry::process_validator_registry; use ssz::TreeHash; use std::collections::HashMap; use types::*; +use update_registry_and_shuffling_data::update_registry_and_shuffling_data; use validator_statuses::{TotalBalances, ValidatorStatuses}; use winning_root::{winning_root, WinningRoot}; @@ -17,9 +17,8 @@ pub mod inclusion_distance; pub mod process_ejections; pub mod process_exit_queue; pub mod process_slashings; -pub mod process_validator_registry; pub mod tests; -pub mod update_validator_registry; +pub mod update_registry_and_shuffling_data; pub mod validator_statuses; pub mod winning_root; @@ -39,30 +38,34 @@ pub fn per_epoch_processing(state: &mut BeaconState, spec: &ChainSpec) -> Result state.build_epoch_cache(RelativeEpoch::Previous, spec)?; state.build_epoch_cache(RelativeEpoch::Current, spec)?; - let mut statuses = initialize_validator_statuses(&state, spec)?; + // Load the struct we use to assign validators into sets based on their participation. + // + // E.g., attestation in the previous epoch, attested to the head, etc. + let mut statuses = ValidatorStatuses::new(state, spec)?; + statuses.process_attestations(&state, spec)?; process_eth1_data(state, spec); update_justification_and_finalization(state, &statuses.total_balances, spec)?; - // Crosslinks + // Crosslinks. let winning_root_for_shards = process_crosslinks(state, spec)?; - // Rewards and Penalities + // Rewards and Penalities. apply_rewards(state, &mut statuses, &winning_root_for_shards, spec)?; - // Ejections + // Ejections. process_ejections(state, spec)?; - // Validator Registry - process_validator_registry(state, spec)?; + // Validator Registry. + update_registry_and_shuffling_data(state, statuses.total_balances.current_epoch, spec)?; + + // Slashings and exit queue. process_slashings(state, spec)?; process_exit_queue(state, spec); - // Final updates - update_active_tree_index_roots(state, spec)?; - update_latest_slashed_balances(state, spec)?; - state.previous_epoch_attestations = vec![]; + // Final updates. + finish_epoch_update(state, spec)?; // Rotate the epoch caches to suit the epoch transition. state.advance_caches(); @@ -70,25 +73,6 @@ pub fn per_epoch_processing(state: &mut BeaconState, spec: &ChainSpec) -> Result Ok(()) } -/// Calculates various sets of attesters, including: -/// -/// - current epoch attesters -/// - current epoch boundary attesters -/// - previous epoch attesters -/// - etc. -/// -/// Spec v0.5.0 -pub fn initialize_validator_statuses( - state: &BeaconState, - spec: &ChainSpec, -) -> Result { - let mut statuses = ValidatorStatuses::new(state, spec)?; - - statuses.process_attestations(&state, spec)?; - - Ok(statuses) -} - /// Maybe resets the eth1 period. /// /// Spec v0.5.0 @@ -224,41 +208,53 @@ pub fn process_crosslinks( Ok(winning_root_for_shards) } -/// Updates the state's `latest_active_index_roots` field with a tree hash the active validator -/// indices for the next epoch. +/// Finish up an epoch update. /// -/// Spec v0.4.0 -pub fn update_active_tree_index_roots( - state: &mut BeaconState, - spec: &ChainSpec, -) -> Result<(), Error> { - let next_epoch = state.next_epoch(spec); - - let active_tree_root = state - .get_active_validator_indices(next_epoch + Epoch::from(spec.activation_exit_delay)) - .to_vec() - .hash_tree_root(); - - state.set_active_index_root(next_epoch, Hash256::from_slice(&active_tree_root[..]), spec)?; - - Ok(()) -} - -/// Advances the state's `latest_slashed_balances` field. -/// -/// Spec v0.4.0 -pub fn update_latest_slashed_balances( - state: &mut BeaconState, - spec: &ChainSpec, -) -> Result<(), Error> { +/// Spec v0.5.0 +pub fn finish_epoch_update(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), Error> { let current_epoch = state.current_epoch(spec); let next_epoch = state.next_epoch(spec); - state.set_slashed_balance( - next_epoch, - state.get_slashed_balance(current_epoch, spec)?, - spec, - )?; + // This is a hack to allow us to update index roots and slashed balances for the next epoch. + // + // The indentation here is to make it obvious where the weird stuff happens. + { + state.slot += 1; + + // Set active index root + let active_index_root = Hash256::from_slice( + &state + .get_active_validator_indices(next_epoch + spec.activation_exit_delay) + .hash_tree_root()[..], + ); + state.set_active_index_root(next_epoch, active_index_root, spec)?; + + // Set total slashed balances + state.set_slashed_balance( + next_epoch, + state.get_slashed_balance(current_epoch, spec)?, + spec, + )?; + + // Set randao mix + state.set_randao_mix( + next_epoch, + *state.get_randao_mix(current_epoch, spec)?, + spec, + )?; + + state.slot -= 1; + } + + if next_epoch.as_u64() % (spec.slots_per_historical_root as u64 / spec.slots_per_epoch) == 0 { + let historical_batch: HistoricalBatch = state.historical_batch(); + state + .historical_roots + .push(Hash256::from_slice(&historical_batch.hash_tree_root()[..])); + } + + state.previous_epoch_attestations = state.current_epoch_attestations.clone(); + state.current_epoch_attestations = vec![]; Ok(()) } diff --git a/eth2/state_processing/src/per_epoch_processing/process_validator_registry.rs b/eth2/state_processing/src/per_epoch_processing/process_validator_registry.rs deleted file mode 100644 index 85d6c37f63..0000000000 --- a/eth2/state_processing/src/per_epoch_processing/process_validator_registry.rs +++ /dev/null @@ -1,70 +0,0 @@ -use super::update_validator_registry::update_validator_registry; -use super::Error; -use types::*; - -/// Peforms a validator registry update, if required. -/// -/// Spec v0.4.0 -pub fn process_validator_registry(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), Error> { - let current_epoch = state.current_epoch(spec); - let next_epoch = state.next_epoch(spec); - - state.previous_shuffling_epoch = state.current_shuffling_epoch; - state.previous_shuffling_start_shard = state.current_shuffling_start_shard; - - state.previous_shuffling_seed = state.current_shuffling_seed; - - if should_update_validator_registry(state, spec)? { - update_validator_registry(state, spec)?; - - state.current_shuffling_epoch = next_epoch; - state.current_shuffling_start_shard = (state.current_shuffling_start_shard - + spec.get_epoch_committee_count( - state - .get_cached_active_validator_indices(RelativeEpoch::Current, spec)? - .len(), - ) as u64) - % spec.shard_count; - state.current_shuffling_seed = state.generate_seed(state.current_shuffling_epoch, spec)? - } else { - let epochs_since_last_registry_update = - current_epoch - state.validator_registry_update_epoch; - if (epochs_since_last_registry_update > 1) - & epochs_since_last_registry_update.is_power_of_two() - { - state.current_shuffling_epoch = next_epoch; - state.current_shuffling_seed = - state.generate_seed(state.current_shuffling_epoch, spec)? - } - } - - Ok(()) -} - -/// Returns `true` if the validator registry should be updated during an epoch processing. -/// -/// Spec v0.5.0 -pub fn should_update_validator_registry( - state: &BeaconState, - spec: &ChainSpec, -) -> Result { - if state.finalized_epoch <= state.validator_registry_update_epoch { - return Ok(false); - } - - let num_active_validators = state - .get_cached_active_validator_indices(RelativeEpoch::Current, spec)? - .len(); - let current_epoch_committee_count = spec.get_epoch_committee_count(num_active_validators); - - for shard in (0..current_epoch_committee_count) - .into_iter() - .map(|i| (state.current_shuffling_start_shard + i as u64) % spec.shard_count) - { - if state.latest_crosslinks[shard as usize].epoch <= state.validator_registry_update_epoch { - return Ok(false); - } - } - - Ok(true) -} diff --git a/eth2/state_processing/src/per_epoch_processing/update_registry_and_shuffling_data.rs b/eth2/state_processing/src/per_epoch_processing/update_registry_and_shuffling_data.rs new file mode 100644 index 0000000000..286ad81408 --- /dev/null +++ b/eth2/state_processing/src/per_epoch_processing/update_registry_and_shuffling_data.rs @@ -0,0 +1,151 @@ +use super::super::common::exit_validator; +use super::Error; +use types::*; + +/// Peforms a validator registry update, if required. +/// +/// Spec v0.5.0 +pub fn update_registry_and_shuffling_data( + state: &mut BeaconState, + current_total_balance: u64, + spec: &ChainSpec, +) -> Result<(), Error> { + // First set previous shuffling data to current shuffling data. + state.previous_shuffling_epoch = state.current_shuffling_epoch; + state.previous_shuffling_start_shard = state.previous_shuffling_start_shard; + state.previous_shuffling_seed = state.previous_shuffling_seed; + + let current_epoch = state.current_epoch(spec); + let next_epoch = current_epoch + 1; + + // Check we should update, and if so, update. + if should_update_validator_registry(state, spec)? { + update_validator_registry(state, current_total_balance, spec)?; + + // If we update the registry, update the shuffling data and shards as well. + state.current_shuffling_epoch = next_epoch; + state.current_shuffling_start_shard = { + let active_validators = + state.get_cached_active_validator_indices(RelativeEpoch::Current, spec)?; + let epoch_committee_count = spec.get_epoch_committee_count(active_validators.len()); + + (state.current_shuffling_start_shard + epoch_committee_count) % spec.shard_count + }; + state.current_shuffling_seed = state.generate_seed(state.current_shuffling_epoch, spec)?; + } else { + // If processing at least on crosslink keeps failing, the reshuffle every power of two, but + // don't update the current_shuffling_start_shard. + let epochs_since_last_update = current_epoch - state.validator_registry_update_epoch; + + if epochs_since_last_update > 1 && epochs_since_last_update.is_power_of_two() { + state.current_shuffling_epoch = next_epoch; + state.current_shuffling_seed = + state.generate_seed(state.current_shuffling_epoch, spec)?; + } + } + + Ok(()) +} + +/// Returns `true` if the validator registry should be updated during an epoch processing. +/// +/// Spec v0.5.0 +pub fn should_update_validator_registry( + state: &BeaconState, + spec: &ChainSpec, +) -> Result { + if state.finalized_epoch <= state.validator_registry_update_epoch { + return Ok(false); + } + + let num_active_validators = state + .get_cached_active_validator_indices(RelativeEpoch::Current, spec)? + .len(); + let current_epoch_committee_count = spec.get_epoch_committee_count(num_active_validators); + + for shard in (0..current_epoch_committee_count) + .into_iter() + .map(|i| (state.current_shuffling_start_shard + i as u64) % spec.shard_count) + { + if state.latest_crosslinks[shard as usize].epoch <= state.validator_registry_update_epoch { + return Ok(false); + } + } + + Ok(true) +} + +/// Update validator registry, activating/exiting validators if possible. +/// +/// Note: Utilizes the cache and will fail if the appropriate cache is not initialized. +/// +/// Spec v0.5.0 +pub fn update_validator_registry( + state: &mut BeaconState, + current_total_balance: u64, + spec: &ChainSpec, +) -> Result<(), Error> { + let current_epoch = state.current_epoch(spec); + + let max_balance_churn = std::cmp::max( + spec.max_deposit_amount, + current_total_balance / (2 * spec.max_balance_churn_quotient), + ); + + // Activate validators within the allowable balance churn. + let mut balance_churn = 0; + for index in 0..state.validator_registry.len() { + let not_activated = + state.validator_registry[index].activation_epoch == spec.far_future_epoch; + let has_enough_balance = state.validator_balances[index] >= spec.max_deposit_amount; + + if not_activated && has_enough_balance { + // Check the balance churn would be within the allowance. + balance_churn += state.get_effective_balance(index, spec)?; + if balance_churn > max_balance_churn { + break; + } + + activate_validator(state, index, false, spec); + } + } + + // Exit validators within the allowable balance churn. + let mut balance_churn = 0; + for index in 0..state.validator_registry.len() { + let not_exited = state.validator_registry[index].exit_epoch == spec.far_future_epoch; + let has_initiated_exit = state.validator_registry[index].initiated_exit; + + if not_exited && has_initiated_exit { + // Check the balance churn would be within the allowance. + balance_churn += state.get_effective_balance(index, spec)?; + if balance_churn > max_balance_churn { + break; + } + + exit_validator(state, index, spec)?; + } + } + + state.validator_registry_update_epoch = current_epoch; + + Ok(()) +} + +/// Activate the validator of the given ``index``. +/// +/// Spec v0.5.0 +pub fn activate_validator( + state: &mut BeaconState, + validator_index: usize, + is_genesis: bool, + spec: &ChainSpec, +) { + let current_epoch = state.current_epoch(spec); + + state.validator_registry[validator_index].activation_epoch = if is_genesis { + spec.genesis_epoch + } else { + state.get_delayed_activation_exit_epoch(current_epoch, spec) + } +} diff --git a/eth2/state_processing/src/per_epoch_processing/update_validator_registry.rs b/eth2/state_processing/src/per_epoch_processing/update_validator_registry.rs deleted file mode 100644 index ecf05ce6f0..0000000000 --- a/eth2/state_processing/src/per_epoch_processing/update_validator_registry.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::common::exit_validator; -use types::{BeaconStateError as Error, *}; - -/// Update validator registry, activating/exiting validators if possible. -/// -/// Note: Utilizes the cache and will fail if the appropriate cache is not initialized. -/// -/// Spec v0.4.0 -pub fn update_validator_registry(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), Error> { - let current_epoch = state.current_epoch(spec); - let active_validator_indices = - state.get_cached_active_validator_indices(RelativeEpoch::Current, spec)?; - let total_balance = state.get_total_balance(&active_validator_indices[..], spec)?; - - let max_balance_churn = std::cmp::max( - spec.max_deposit_amount, - total_balance / (2 * spec.max_balance_churn_quotient), - ); - - let mut balance_churn = 0; - for index in 0..state.validator_registry.len() { - let validator = &state.validator_registry[index]; - - if (validator.activation_epoch == spec.far_future_epoch) - & (state.validator_balances[index] == spec.max_deposit_amount) - { - balance_churn += state.get_effective_balance(index, spec)?; - if balance_churn > max_balance_churn { - break; - } - state.activate_validator(index, false, spec); - } - } - - let mut balance_churn = 0; - for index in 0..state.validator_registry.len() { - let validator = &state.validator_registry[index]; - - if (validator.exit_epoch == spec.far_future_epoch) & (validator.initiated_exit) { - balance_churn += state.get_effective_balance(index, spec)?; - if balance_churn > max_balance_churn { - break; - } - - exit_validator(state, index, spec)?; - } - } - - state.validator_registry_update_epoch = current_epoch; - - Ok(()) -} diff --git a/eth2/types/src/beacon_state.rs b/eth2/types/src/beacon_state.rs index 22e7c6ecf0..1a165c9a9a 100644 --- a/eth2/types/src/beacon_state.rs +++ b/eth2/types/src/beacon_state.rs @@ -193,6 +193,13 @@ impl BeaconState { Hash256::from_slice(&self.hash_tree_root()[..]) } + pub fn historical_batch(&self) -> HistoricalBatch { + HistoricalBatch { + block_roots: self.latest_block_roots.clone(), + state_roots: self.latest_state_roots.clone(), + } + } + /// If a validator pubkey exists in the validator registry, returns `Some(i)`, otherwise /// returns `None`. /// @@ -382,6 +389,26 @@ impl BeaconState { Ok(self.latest_block_roots[i] = block_root) } + /// Safely obtains the index for `latest_randao_mixes` + /// + /// Spec v0.5.0 + fn get_randao_mix_index(&self, epoch: Epoch, spec: &ChainSpec) -> Result { + let current_epoch = self.current_epoch(spec); + + if (current_epoch - (spec.latest_randao_mixes_length as u64) < epoch) + & (epoch <= current_epoch) + { + let i = epoch.as_usize() % spec.latest_randao_mixes_length; + if i < self.latest_randao_mixes.len() { + Ok(i) + } else { + Err(Error::InsufficientRandaoMixes) + } + } else { + Err(Error::EpochOutOfBounds) + } + } + /// XOR-assigns the existing `epoch` randao mix with the hash of the `signature`. /// /// # Errors: @@ -406,24 +433,23 @@ impl BeaconState { /// Return the randao mix at a recent ``epoch``. /// - /// # Errors: - /// - `InsufficientRandaoMixes` if `self.latest_randao_mixes` is shorter than - /// `spec.latest_randao_mixes_length`. - /// - `EpochOutOfBounds` if the state no longer stores randao mixes for the given `epoch`. - /// /// Spec v0.5.0 pub fn get_randao_mix(&self, epoch: Epoch, spec: &ChainSpec) -> Result<&Hash256, Error> { - let current_epoch = self.current_epoch(spec); + let i = self.get_randao_mix_index(epoch, spec)?; + Ok(&self.latest_randao_mixes[i]) + } - if (current_epoch - (spec.latest_randao_mixes_length as u64) < epoch) - & (epoch <= current_epoch) - { - self.latest_randao_mixes - .get(epoch.as_usize() % spec.latest_randao_mixes_length) - .ok_or_else(|| Error::InsufficientRandaoMixes) - } else { - Err(Error::EpochOutOfBounds) - } + /// Set the randao mix at a recent ``epoch``. + /// + /// Spec v0.5.0 + pub fn set_randao_mix( + &mut self, + epoch: Epoch, + mix: Hash256, + spec: &ChainSpec, + ) -> Result<(), Error> { + let i = self.get_randao_mix_index(epoch, spec)?; + Ok(self.latest_randao_mixes[i] = mix) } /// Safely obtains the index for `latest_active_index_roots`, given some `epoch`. @@ -588,24 +614,6 @@ impl BeaconState { epoch + 1 + spec.activation_exit_delay } - /// Activate the validator of the given ``index``. - /// - /// Spec v0.5.0 - pub fn activate_validator( - &mut self, - validator_index: usize, - is_genesis: bool, - spec: &ChainSpec, - ) { - let current_epoch = self.current_epoch(spec); - - self.validator_registry[validator_index].activation_epoch = if is_genesis { - spec.genesis_epoch - } else { - self.get_delayed_activation_exit_epoch(current_epoch, spec) - } - } - /// Initiate an exit for the validator of the given `index`. /// /// Spec v0.5.0 From baca2c90abacfc8fafcaf3bfa590242a0ca8f084 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 19 Mar 2019 19:43:31 +1100 Subject: [PATCH 40/62] Add last of 0.5.0 upgrades. Woo! --- .../src/per_epoch_processing.rs | 31 ++++++++++------ .../process_exit_queue.rs | 4 +-- .../per_epoch_processing/process_slashings.rs | 36 +++++++++---------- 3 files changed, 40 insertions(+), 31 deletions(-) diff --git a/eth2/state_processing/src/per_epoch_processing.rs b/eth2/state_processing/src/per_epoch_processing.rs index b917510f2e..fcdc668f40 100644 --- a/eth2/state_processing/src/per_epoch_processing.rs +++ b/eth2/state_processing/src/per_epoch_processing.rs @@ -32,7 +32,7 @@ pub type WinningRootHashSet = HashMap; /// Mutates the given `BeaconState`, returning early if an error is encountered. If an error is /// returned, a state might be "half-processed" and therefore in an invalid state. /// -/// Spec v0.4.0 +/// Spec v0.5.0 pub fn per_epoch_processing(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), Error> { // Ensure the previous and next epoch caches are built. state.build_epoch_cache(RelativeEpoch::Previous, spec)?; @@ -41,27 +41,38 @@ pub fn per_epoch_processing(state: &mut BeaconState, spec: &ChainSpec) -> Result // Load the struct we use to assign validators into sets based on their participation. // // E.g., attestation in the previous epoch, attested to the head, etc. - let mut statuses = ValidatorStatuses::new(state, spec)?; - statuses.process_attestations(&state, spec)?; + let mut validator_statuses = ValidatorStatuses::new(state, spec)?; + validator_statuses.process_attestations(&state, spec)?; - process_eth1_data(state, spec); - - update_justification_and_finalization(state, &statuses.total_balances, spec)?; + // Justification. + update_justification_and_finalization(state, &validator_statuses.total_balances, spec)?; // Crosslinks. let winning_root_for_shards = process_crosslinks(state, spec)?; + // Eth1 data. + maybe_reset_eth1_period(state, spec); + // Rewards and Penalities. - apply_rewards(state, &mut statuses, &winning_root_for_shards, spec)?; + apply_rewards( + state, + &mut validator_statuses, + &winning_root_for_shards, + spec, + )?; // Ejections. process_ejections(state, spec)?; // Validator Registry. - update_registry_and_shuffling_data(state, statuses.total_balances.current_epoch, spec)?; + update_registry_and_shuffling_data( + state, + validator_statuses.total_balances.current_epoch, + spec, + )?; // Slashings and exit queue. - process_slashings(state, spec)?; + process_slashings(state, validator_statuses.total_balances.current_epoch, spec)?; process_exit_queue(state, spec); // Final updates. @@ -76,7 +87,7 @@ pub fn per_epoch_processing(state: &mut BeaconState, spec: &ChainSpec) -> Result /// Maybe resets the eth1 period. /// /// Spec v0.5.0 -pub fn process_eth1_data(state: &mut BeaconState, spec: &ChainSpec) { +pub fn maybe_reset_eth1_period(state: &mut BeaconState, spec: &ChainSpec) { let next_epoch = state.next_epoch(spec); let voting_period = spec.epochs_per_eth1_voting_period; diff --git a/eth2/state_processing/src/per_epoch_processing/process_exit_queue.rs b/eth2/state_processing/src/per_epoch_processing/process_exit_queue.rs index f672c97be3..074db1d08e 100644 --- a/eth2/state_processing/src/per_epoch_processing/process_exit_queue.rs +++ b/eth2/state_processing/src/per_epoch_processing/process_exit_queue.rs @@ -21,8 +21,8 @@ pub fn process_exit_queue(state: &mut BeaconState, spec: &ChainSpec) { .collect(); eligable_indices.sort_by_key(|i| state.validator_registry[*i].exit_epoch); - for (withdrawn_so_far, index) in eligable_indices.iter().enumerate() { - if withdrawn_so_far as u64 >= spec.max_exit_dequeues_per_epoch { + for (dequeues, index) in eligable_indices.iter().enumerate() { + if dequeues as u64 >= spec.max_exit_dequeues_per_epoch { break; } prepare_validator_for_withdrawal(state, *index, spec); diff --git a/eth2/state_processing/src/per_epoch_processing/process_slashings.rs b/eth2/state_processing/src/per_epoch_processing/process_slashings.rs index 19c1e519b3..88777472c3 100644 --- a/eth2/state_processing/src/per_epoch_processing/process_slashings.rs +++ b/eth2/state_processing/src/per_epoch_processing/process_slashings.rs @@ -2,34 +2,32 @@ use types::{BeaconStateError as Error, *}; /// Process slashings. /// -/// Note: Utilizes the cache and will fail if the appropriate cache is not initialized. -/// -/// Spec v0.4.0 -pub fn process_slashings(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), Error> { +/// Spec v0.5.0 +pub fn process_slashings( + state: &mut BeaconState, + current_total_balance: u64, + spec: &ChainSpec, +) -> Result<(), Error> { let current_epoch = state.current_epoch(spec); - let active_validator_indices = - state.get_cached_active_validator_indices(RelativeEpoch::Current, spec)?; - let total_balance = state.get_total_balance(&active_validator_indices[..], spec)?; + + let total_at_start = state.get_slashed_balance(current_epoch + 1, spec)?; + let total_at_end = state.get_slashed_balance(current_epoch, spec)?; + let total_penalities = total_at_end - total_at_start; for (index, validator) in state.validator_registry.iter().enumerate() { - if validator.slashed - && (current_epoch - == validator.withdrawable_epoch - Epoch::from(spec.latest_slashed_exit_length / 2)) - { - // TODO: check the following two lines are correct. - let total_at_start = state.get_slashed_balance(current_epoch + 1, spec)?; - let total_at_end = state.get_slashed_balance(current_epoch, spec)?; - - let total_penalities = total_at_end.saturating_sub(total_at_start); + let should_penalize = current_epoch.as_usize() + == validator.withdrawable_epoch.as_usize() - spec.latest_slashed_exit_length / 2; + if validator.slashed && should_penalize { let effective_balance = state.get_effective_balance(index, spec)?; + let penalty = std::cmp::max( - effective_balance * std::cmp::min(total_penalities * 3, total_balance) - / total_balance, + effective_balance * std::cmp::min(total_penalities * 3, current_total_balance) + / current_total_balance, effective_balance / spec.min_penalty_quotient, ); - safe_sub_assign!(state.validator_balances[index], penalty); + state.validator_balances[index] -= penalty; } } From 8f23aefb29f997e46de59ce8b571196b203c3ef6 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 19 Mar 2019 19:55:17 +1100 Subject: [PATCH 41/62] Adds comments to new epoch cache fns. --- eth2/types/src/beacon_state/epoch_cache.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/eth2/types/src/beacon_state/epoch_cache.rs b/eth2/types/src/beacon_state/epoch_cache.rs index ca8bcc70e9..6eebf1da3a 100644 --- a/eth2/types/src/beacon_state/epoch_cache.rs +++ b/eth2/types/src/beacon_state/epoch_cache.rs @@ -107,6 +107,7 @@ impl EpochCache { }) } + /// Return a vec of `CrosslinkCommittee` for a given slot. pub fn get_crosslink_committees_at_slot( &self, slot: Slot, @@ -116,6 +117,8 @@ impl EpochCache { .get_crosslink_committees_at_slot(slot, spec) } + /// Return `Some(CrosslinkCommittee)` if the given shard has a committee during the given + /// `epoch`. pub fn get_crosslink_committee_for_shard( &self, shard: Shard, @@ -131,6 +134,10 @@ impl EpochCache { } } +/// Returns a list of all `validator_registry` indices where the validator is active at the given +/// `epoch`. +/// +/// Spec v0.5.0 pub fn get_active_validator_indices(validators: &[Validator], epoch: Epoch) -> Vec { let mut active = Vec::with_capacity(validators.len()); @@ -145,13 +152,17 @@ pub fn get_active_validator_indices(validators: &[Validator], epoch: Epoch) -> V active } +/// Contains all `CrosslinkCommittees` for an epoch. #[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize)] pub struct EpochCrosslinkCommittees { + /// The epoch the committees are present in. epoch: Epoch, + /// Each commitee for each slot of the epoch. pub crosslink_committees: Vec>, } impl EpochCrosslinkCommittees { + /// Return a new instances where all slots have zero committees. fn new(epoch: Epoch, spec: &ChainSpec) -> Self { Self { epoch, @@ -159,6 +170,7 @@ impl EpochCrosslinkCommittees { } } + /// Return a vec of `CrosslinkCommittee` for a given slot. fn get_crosslink_committees_at_slot( &self, slot: Slot, @@ -176,6 +188,7 @@ impl EpochCrosslinkCommittees { } } +/// Builds an `EpochCrosslinkCommittees` object. pub struct EpochCrosslinkCommitteesBuilder { epoch: Epoch, shuffling_start_shard: Shard, @@ -185,6 +198,7 @@ pub struct EpochCrosslinkCommitteesBuilder { } impl EpochCrosslinkCommitteesBuilder { + /// Instantiates a builder that will build for the `state`'s previous epoch. pub fn for_previous_epoch( state: &BeaconState, active_validator_indices: Vec, @@ -199,6 +213,7 @@ impl EpochCrosslinkCommitteesBuilder { } } + /// Instantiates a builder that will build for the `state`'s next epoch. pub fn for_current_epoch( state: &BeaconState, active_validator_indices: Vec, @@ -213,6 +228,10 @@ impl EpochCrosslinkCommitteesBuilder { } } + /// Instantiates a builder that will build for the `state`'s next epoch. + /// + /// Note: there are two possible epoch builds for the next epoch, one where there is a registry + /// change and one where there is not. pub fn for_next_epoch( state: &BeaconState, active_validator_indices: Vec, @@ -257,6 +276,7 @@ impl EpochCrosslinkCommitteesBuilder { }) } + /// Consumes the builder, returning a fully-build `EpochCrosslinkCommittee`. pub fn build(self, spec: &ChainSpec) -> Result { // The shuffler fails on a empty list, so if there are no active validator indices, simply // return an empty list. From 6e10ce93d4e3a69cf61e6128f654a2b85ee28818 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 19 Mar 2019 21:44:52 +1100 Subject: [PATCH 42/62] Tidy message handler --- beacon_node/network/src/message_handler.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index 17e74fda23..3b95c1263d 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -91,6 +91,7 @@ impl MessageHandler { Ok(handler_send) } + /// Handle all messages incoming from the network service. fn handle_message(&mut self, message: HandlerMessage) { match message { // we have initiated a connection to a peer @@ -107,6 +108,9 @@ impl MessageHandler { } } + /* RPC - Related functionality */ + + /// Handle RPC messages fn handle_rpc_message(&mut self, peer_id: PeerId, rpc_message: RPCEvent) { match rpc_message { RPCEvent::Request { @@ -140,6 +144,7 @@ impl MessageHandler { } } + /// Handle a HELLO RPC request message. fn handle_hello_request(&mut self, peer_id: PeerId, id: u64, hello_message: HelloMessage) { // send back a HELLO message self.send_hello(peer_id.clone(), id, false); @@ -153,12 +158,15 @@ impl MessageHandler { } } + /// Handle a HELLO RPC response message. fn handle_hello_response(&mut self, peer_id: PeerId, id: u64, response: HelloMessage) { debug!(self.log, "Hello response received from peer: {:?}", peer_id); // validate peer - decide whether to drop/ban or add to sync // TODO: Peer validation } + /* General RPC helper functions */ + /// Generates a new request id for a peer. fn generate_request_id(&mut self, peer_id: &PeerId) -> u64 { // generate a unique id for the peer From b30d72501cfb57f4937b72ff4a8c1826a3e27a79 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 19 Mar 2019 21:55:57 +1100 Subject: [PATCH 43/62] Add logger to sync module --- beacon_node/network/src/message_handler.rs | 2 +- beacon_node/network/src/sync/simple_sync.rs | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index 3b95c1263d..bf0df1aa6a 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -65,7 +65,7 @@ impl MessageHandler { // Initialise sync and begin processing in thread // generate the Message handler - let sync = SimpleSync::new(beacon_chain.clone()); + let sync = SimpleSync::new(beacon_chain.clone(), &log); let mut handler = MessageHandler { // TODO: The handler may not need a chain, perhaps only sync? diff --git a/beacon_node/network/src/sync/simple_sync.rs b/beacon_node/network/src/sync/simple_sync.rs index 2a3cc70892..50f6f4a504 100644 --- a/beacon_node/network/src/sync/simple_sync.rs +++ b/beacon_node/network/src/sync/simple_sync.rs @@ -1,6 +1,7 @@ use crate::beacon_chain::BeaconChain; use libp2p::rpc::HelloMessage; use libp2p::PeerId; +use slog::{debug, o}; use std::collections::HashMap; use std::sync::Arc; use types::{Epoch, Hash256, Slot}; @@ -36,11 +37,14 @@ pub struct SimpleSync { latest_finalized_epoch: Epoch, /// The latest block of the syncing chain. latest_block: Hash256, + /// Sync logger. + log: slog::Logger, } impl SimpleSync { - pub fn new(beacon_chain: Arc) -> Self { + pub fn new(beacon_chain: Arc, log: &slog::Logger) -> Self { let state = beacon_chain.get_state(); + let sync_logger = log.new(o!("Service"=> "Sync")); SimpleSync { chain: beacon_chain.clone(), known_peers: HashMap::new(), @@ -48,6 +52,7 @@ impl SimpleSync { network_id: beacon_chain.get_spec().network_id, latest_finalized_epoch: state.finalized_epoch, latest_block: state.finalized_root, //TODO: Build latest block function into Beacon chain and correct this + log: sync_logger, } } @@ -87,7 +92,9 @@ impl SimpleSync { best_slot: hello_message.best_slot, }; + debug!(self.log, "Handshake successful. Peer: {:?}", peer_id); self.known_peers.insert(peer_id, peer_info); + //TODO: Start syncing true From 0a8b0069dc3ef7efad6dd542fd1b706305a45087 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 19 Mar 2019 22:18:01 +1100 Subject: [PATCH 44/62] Add peer validation and successful handshake --- beacon_node/network/src/message_handler.rs | 28 +++++++++++++++------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index bf0df1aa6a..1b9dc33691 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -139,9 +139,20 @@ impl MessageHandler { // we match on id and ignore responses past the timeout. fn handle_rpc_response(&mut self, peer_id: PeerId, id: u64, response: RPCResponse) { // if response id is related to a request, ignore (likely RPC timeout) - if self.requests.remove(&(peer_id, id)).is_none() { + if self + .requests + .remove(&(peer_id.clone(), id.clone())) + .is_none() + { + debug!(self.log, "Unrecognized response from peer: {:?}", peer_id); return; } + match response { + RPCResponse::Hello(hello_message) => { + debug!(self.log, "Hello response received from peer: {:?}", peer_id); + self.validate_hello(peer_id, hello_message); + } + } } /// Handle a HELLO RPC request message. @@ -149,7 +160,13 @@ impl MessageHandler { // send back a HELLO message self.send_hello(peer_id.clone(), id, false); // validate the peer - if !self.sync.validate_peer(peer_id.clone(), hello_message) { + self.validate_hello(peer_id, hello_message); + } + + /// Validate a HELLO RPC message. + fn validate_hello(&mut self, peer_id: PeerId, message: HelloMessage) { + // validate the peer + if !self.sync.validate_peer(peer_id.clone(), message) { debug!( self.log, "Peer dropped due to mismatching HELLO messages: {:?}", peer_id @@ -158,13 +175,6 @@ impl MessageHandler { } } - /// Handle a HELLO RPC response message. - fn handle_hello_response(&mut self, peer_id: PeerId, id: u64, response: HelloMessage) { - debug!(self.log, "Hello response received from peer: {:?}", peer_id); - // validate peer - decide whether to drop/ban or add to sync - // TODO: Peer validation - } - /* General RPC helper functions */ /// Generates a new request id for a peer. From dc014d07bc03953b5426bf3eb94809d1d4f0a1b4 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 19 Mar 2019 22:32:56 +1100 Subject: [PATCH 45/62] Enable syncing state when new peer connects --- beacon_node/network/src/service.rs | 5 +++-- beacon_node/network/src/sync/simple_sync.rs | 16 +++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/beacon_node/network/src/service.rs b/beacon_node/network/src/service.rs index 84e46e707c..a62408c0af 100644 --- a/beacon_node/network/src/service.rs +++ b/beacon_node/network/src/service.rs @@ -110,9 +110,10 @@ fn network_service( loop { match libp2p_service.poll() { Ok(Async::Ready(Some(Libp2pEvent::RPC(peer_id, rpc_event)))) => { - debug!( + trace!( libp2p_service.log, - "RPC Event: RPC message received: {:?}", rpc_event + "RPC Event: RPC message received: {:?}", + rpc_event ); message_handler_send .send(HandlerMessage::RPC(peer_id, rpc_event)) diff --git a/beacon_node/network/src/sync/simple_sync.rs b/beacon_node/network/src/sync/simple_sync.rs index 50f6f4a504..a3cd9044ce 100644 --- a/beacon_node/network/src/sync/simple_sync.rs +++ b/beacon_node/network/src/sync/simple_sync.rs @@ -6,6 +6,9 @@ use std::collections::HashMap; use std::sync::Arc; use types::{Epoch, Hash256, Slot}; +/// The number of slots that we can import blocks ahead of us, before going into full Sync mode. +const SLOT_IMPORT_TOLERANCE: u64 = 100; + /// Keeps track of syncing information for known connected peers. pub struct PeerSyncInfo { latest_finalized_root: Hash256, @@ -15,6 +18,7 @@ pub struct PeerSyncInfo { } /// The current syncing state. +#[derive(PartialEq)] pub enum SyncState { Idle, Downloading, @@ -36,7 +40,7 @@ pub struct SimpleSync { /// The latest epoch of the syncing chain. latest_finalized_epoch: Epoch, /// The latest block of the syncing chain. - latest_block: Hash256, + latest_slot: Slot, /// Sync logger. log: slog::Logger, } @@ -51,7 +55,7 @@ impl SimpleSync { state: SyncState::Idle, network_id: beacon_chain.get_spec().network_id, latest_finalized_epoch: state.finalized_epoch, - latest_block: state.finalized_root, //TODO: Build latest block function into Beacon chain and correct this + latest_slot: state.slot - 1, //TODO: Build latest block function into Beacon chain and correct this log: sync_logger, } } @@ -95,7 +99,13 @@ impl SimpleSync { debug!(self.log, "Handshake successful. Peer: {:?}", peer_id); self.known_peers.insert(peer_id, peer_info); - //TODO: Start syncing + // set state to sync + if self.state == SyncState::Idle + && hello_message.best_slot > self.latest_slot + SLOT_IMPORT_TOLERANCE + { + self.state = SyncState::Downloading; + //TODO: Start requesting blocks from known peers. Ideally in batches + } true } From e7f87112fb27b84f4850b4586686a9d492d73a7a Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 19 Mar 2019 22:53:51 +1100 Subject: [PATCH 46/62] Tidy networking crates --- beacon_node/client/src/client_types.rs | 2 +- beacon_node/client/src/lib.rs | 4 ++-- beacon_node/client/src/notifier.rs | 7 ++----- beacon_node/network/src/lib.rs | 2 -- beacon_node/network/src/message_handler.rs | 5 ----- beacon_node/network/src/messages.rs | 15 --------------- beacon_node/network/src/service.rs | 18 +++++++++--------- beacon_node/src/main.rs | 7 +++++-- beacon_node/src/run.rs | 11 +++++++---- 9 files changed, 26 insertions(+), 45 deletions(-) delete mode 100644 beacon_node/network/src/messages.rs diff --git a/beacon_node/client/src/client_types.rs b/beacon_node/client/src/client_types.rs index de0678fe78..f5abc77ced 100644 --- a/beacon_node/client/src/client_types.rs +++ b/beacon_node/client/src/client_types.rs @@ -3,7 +3,7 @@ use beacon_chain::{ db::{ClientDB, DiskDB, MemoryDB}, fork_choice::BitwiseLMDGhost, initialise, - slot_clock::{SlotClock, SystemTimeSlotClock, TestingSlotClock}, + slot_clock::{SlotClock, SystemTimeSlotClock}, BeaconChain, }; use fork_choice::ForkChoice; diff --git a/beacon_node/client/src/lib.rs b/beacon_node/client/src/lib.rs index f3178eaa66..327e433af3 100644 --- a/beacon_node/client/src/lib.rs +++ b/beacon_node/client/src/lib.rs @@ -11,7 +11,7 @@ pub use client_types::ClientTypes; //use beacon_chain::BeaconChain; use beacon_chain::BeaconChain; -use exit_future::{Exit, Signal}; +use exit_future::Signal; use network::Service as NetworkService; use slog::o; use std::marker::PhantomData; @@ -55,7 +55,7 @@ impl Client { // TODO: Add beacon_chain reference to network parameters let network_config = &config.net_conf; let network_logger = log.new(o!("Service" => "Network")); - let (network, network_send) = NetworkService::new( + let (network, _network_send) = NetworkService::new( beacon_chain.clone(), network_config, executor, diff --git a/beacon_node/client/src/notifier.rs b/beacon_node/client/src/notifier.rs index 6b52e670a2..335183c7de 100644 --- a/beacon_node/client/src/notifier.rs +++ b/beacon_node/client/src/notifier.rs @@ -1,12 +1,8 @@ use crate::Client; use crate::ClientTypes; -use db::ClientDB; use exit_future::Exit; -use fork_choice::ForkChoice; use futures::{Future, Stream}; -use network::NodeMessage; use slog::{debug, info, o}; -use slot_clock::SlotClock; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; use tokio::runtime::TaskExecutor; @@ -27,12 +23,13 @@ pub fn run(client: &Client, executor: TaskExecutor, exit: Exi // build heartbeat logic here let heartbeat = move |_| { info!(log, "Temp heartbeat output"); + //TODO: Remove this logic. Testing only let mut count = counter.lock().unwrap(); *count += 1; if *count % 5 == 0 { debug!(log, "Sending Message"); - network.send_message(String::from("Testing network channel")) + network.send_message(); } Ok(()) diff --git a/beacon_node/network/src/lib.rs b/beacon_node/network/src/lib.rs index c1840f5924..1e47b9a731 100644 --- a/beacon_node/network/src/lib.rs +++ b/beacon_node/network/src/lib.rs @@ -2,10 +2,8 @@ pub mod beacon_chain; pub mod error; mod message_handler; -mod messages; mod service; pub mod sync; pub use libp2p::NetworkConfig; -pub use messages::NodeMessage; pub use service::Service; diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index 1b9dc33691..bcea28ff83 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -1,11 +1,9 @@ use crate::beacon_chain::BeaconChain; use crate::error; -use crate::messages::NodeMessage; use crate::service::{NetworkMessage, OutgoingMessage}; use crate::sync::SimpleSync; use crossbeam_channel::{unbounded as channel, Sender}; use futures::future; -use futures::prelude::*; use libp2p::{ rpc::{RPCMethod, RPCRequest, RPCResponse}, HelloMessage, PeerId, RPCEvent, @@ -15,7 +13,6 @@ use slog::{debug, trace}; use std::collections::HashMap; use std::sync::Arc; use std::time::{Duration, Instant}; -use types::Hash256; /// Timeout for RPC requests. const REQUEST_TIMEOUT: Duration = Duration::from_secs(30); @@ -45,8 +42,6 @@ pub enum HandlerMessage { PeerDialed(PeerId), /// Peer has disconnected, PeerDisconnected(PeerId), - /// A Node message has been received. - Message(PeerId, NodeMessage), /// An RPC response/request has been received. RPC(PeerId, RPCEvent), } diff --git a/beacon_node/network/src/messages.rs b/beacon_node/network/src/messages.rs deleted file mode 100644 index 6a69cbb874..0000000000 --- a/beacon_node/network/src/messages.rs +++ /dev/null @@ -1,15 +0,0 @@ -use libp2p::PeerId; -use libp2p::{HelloMessage, RPCEvent}; -use types::{Hash256, Slot}; - -//TODO: This module can be entirely replaced in the RPC rewrite - -/// Messages between nodes across the network. -//TODO: Remove this in the RPC rewrite -#[derive(Debug, Clone)] -pub enum NodeMessage { - RPC(RPCEvent), - BlockRequest, - // TODO: only for testing - remove - Message(String), -} diff --git a/beacon_node/network/src/service.rs b/beacon_node/network/src/service.rs index a62408c0af..4e79a92fe5 100644 --- a/beacon_node/network/src/service.rs +++ b/beacon_node/network/src/service.rs @@ -1,7 +1,6 @@ use crate::beacon_chain::BeaconChain; use crate::error; use crate::message_handler::{HandlerMessage, MessageHandler}; -use crate::messages::NodeMessage; use crate::NetworkConfig; use crossbeam_channel::{unbounded as channel, Sender, TryRecvError}; use futures::prelude::*; @@ -53,21 +52,22 @@ impl Service { executor, log, )?; - let network = Service { + let network_service = Service { libp2p_exit, network_send: network_send.clone(), }; - Ok((Arc::new(network), network_send)) + Ok((Arc::new(network_service), network_send)) } // TODO: Testing only - pub fn send_message(&self, message: String) { - let node_message = NodeMessage::Message(message); - self.network_send.send(NetworkMessage::Send( - PeerId::random(), - OutgoingMessage::NotifierTest, - )); + pub fn send_message(&self) { + self.network_send + .send(NetworkMessage::Send( + PeerId::random(), + OutgoingMessage::NotifierTest, + )) + .unwrap(); } } diff --git a/beacon_node/src/main.rs b/beacon_node/src/main.rs index 09cac99b4b..9be6136c5c 100644 --- a/beacon_node/src/main.rs +++ b/beacon_node/src/main.rs @@ -4,7 +4,7 @@ mod run; use clap::{App, Arg}; use client::ClientConfig; -use slog::{o, Drain}; +use slog::{error, o, Drain}; fn main() { let decorator = slog_term::TermDecorator::new().build(); @@ -42,5 +42,8 @@ fn main() { // invalid arguments, panic let config = ClientConfig::parse_args(matches, &logger).unwrap(); - run::run_beacon_node(config, logger); + match run::run_beacon_node(config, &logger) { + Ok(_) => {} + Err(e) => error!(logger, "Beacon node failed because {:?}", e), + } } diff --git a/beacon_node/src/run.rs b/beacon_node/src/run.rs index b7cbf5421c..b3b2844526 100644 --- a/beacon_node/src/run.rs +++ b/beacon_node/src/run.rs @@ -1,4 +1,4 @@ -use client::client_types::{StandardClientType, TestingClientType}; +use client::client_types::TestingClientType; use client::error; use client::{notifier, Client, ClientConfig}; use futures::sync::oneshot; @@ -7,7 +7,7 @@ use slog::info; use std::cell::RefCell; use tokio::runtime::Builder; -pub fn run_beacon_node(config: ClientConfig, log: slog::Logger) -> error::Result<()> { +pub fn run_beacon_node(config: ClientConfig, log: &slog::Logger) -> error::Result<()> { let mut runtime = Builder::new() .name_prefix("main-") .build() @@ -25,7 +25,8 @@ pub fn run_beacon_node(config: ClientConfig, log: slog::Logger) -> error::Result if let Some(ctrlc_send) = ctrlc_send_c.try_borrow_mut().unwrap().take() { ctrlc_send.send(()).expect("Error sending ctrl-c message"); } - }); + }) + .map_err(|e| format!("Could not set ctrlc hander: {:?}", e))?; let (exit_signal, exit) = exit_future::signal(); @@ -35,7 +36,9 @@ pub fn run_beacon_node(config: ClientConfig, log: slog::Logger) -> error::Result let client: Client = Client::new(config, log.clone(), &executor)?; notifier::run(&client, executor, exit); - runtime.block_on(ctrlc); + runtime + .block_on(ctrlc) + .map_err(|e| format!("Ctrlc oneshot failed: {:?}", e))?; // perform global shutdown operations. info!(log, "Shutting down.."); From 4b57d32b60b6a3e3e4648e54bf8f57697c4dd737 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 19 Mar 2019 23:20:39 +1100 Subject: [PATCH 47/62] Apply clippy suggestions --- beacon_node/client/src/lib.rs | 4 +-- beacon_node/libp2p/src/rpc/mod.rs | 4 +-- beacon_node/libp2p/src/rpc/protocol.rs | 8 +++--- beacon_node/libp2p/src/service.rs | 13 ++++----- beacon_node/network/src/message_handler.rs | 32 +++++++-------------- beacon_node/network/src/service.rs | 2 +- beacon_node/network/src/sync/simple_sync.rs | 2 +- beacon_node/version/src/lib.rs | 2 +- eth2/fork_choice/src/slow_lmd_ghost.rs | 6 ++-- 9 files changed, 30 insertions(+), 43 deletions(-) diff --git a/beacon_node/client/src/lib.rs b/beacon_node/client/src/lib.rs index 327e433af3..beba6f4de3 100644 --- a/beacon_node/client/src/lib.rs +++ b/beacon_node/client/src/lib.rs @@ -66,9 +66,9 @@ impl Client { config, beacon_chain, exit, - exit_signal: exit_signal, + exit_signal, log, - network: network, + network, phantom: PhantomData, }) } diff --git a/beacon_node/libp2p/src/rpc/mod.rs b/beacon_node/libp2p/src/rpc/mod.rs index e06f4effc5..a1cfadafe6 100644 --- a/beacon_node/libp2p/src/rpc/mod.rs +++ b/beacon_node/libp2p/src/rpc/mod.rs @@ -13,7 +13,7 @@ use libp2p::core::swarm::{ use libp2p::{Multiaddr, PeerId}; pub use methods::{HelloMessage, RPCMethod, RPCRequest, RPCResponse}; pub use protocol::{RPCEvent, RPCProtocol}; -use slog::{debug, o}; +use slog::o; use std::marker::PhantomData; use tokio::io::{AsyncRead, AsyncWrite}; @@ -65,7 +65,7 @@ where fn inject_connected(&mut self, peer_id: PeerId, connected_point: ConnectedPoint) { // if initialised the connection, report this upwards to send the HELLO request - if let ConnectedPoint::Dialer { address } = connected_point { + if let ConnectedPoint::Dialer { address: _ } = connected_point { self.events.push(NetworkBehaviourAction::GenerateEvent( RPCMessage::PeerDialed(peer_id), )); diff --git a/beacon_node/libp2p/src/rpc/protocol.rs b/beacon_node/libp2p/src/rpc/protocol.rs index dce7144299..6cebb7fd2d 100644 --- a/beacon_node/libp2p/src/rpc/protocol.rs +++ b/beacon_node/libp2p/src/rpc/protocol.rs @@ -84,11 +84,11 @@ fn decode(packet: Vec) -> Result { RPCMethod::Unknown => return Err(DecodeError::UnknownRPCMethod), }; - return Ok(RPCEvent::Request { + Ok(RPCEvent::Request { id, method_id, body, - }); + }) } // we have received a response else { @@ -99,11 +99,11 @@ fn decode(packet: Vec) -> Result { } RPCMethod::Unknown => return Err(DecodeError::UnknownRPCMethod), }; - return Ok(RPCEvent::Response { + Ok(RPCEvent::Response { id, method_id, result, - }); + }) } } diff --git a/beacon_node/libp2p/src/service.rs b/beacon_node/libp2p/src/service.rs index 92e6e88977..e378cd634a 100644 --- a/beacon_node/libp2p/src/service.rs +++ b/beacon_node/libp2p/src/service.rs @@ -73,13 +73,12 @@ impl Service { let mut subscribed_topics = vec![]; for topic in config.topics { let t = TopicBuilder::new(topic.to_string()).build(); - match swarm.subscribe(t) { - true => { - trace!(log, "Subscribed to topic: {:?}", topic); - subscribed_topics.push(topic); - } - false => warn!(log, "Could not subscribe to topic: {:?}", topic), - }; + if swarm.subscribe(t) { + trace!(log, "Subscribed to topic: {:?}", topic); + subscribed_topics.push(topic); + } else { + warn!(log, "Could not subscribe to topic: {:?}", topic) + } } info!(log, "Subscribed to topics: {:?}", subscribed_topics); diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index bcea28ff83..2a3f38bc19 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -48,7 +48,7 @@ pub enum HandlerMessage { impl MessageHandler { /// Initializes and runs the MessageHandler. - pub fn new( + pub fn spawn( beacon_chain: Arc, network_send: crossbeam_channel::Sender, executor: &tokio::runtime::TaskExecutor, @@ -108,16 +108,9 @@ impl MessageHandler { /// Handle RPC messages fn handle_rpc_message(&mut self, peer_id: PeerId, rpc_message: RPCEvent) { match rpc_message { - RPCEvent::Request { - id, - method_id: _, // TODO: Clean up RPC Message types, have a cleaner type by this point. - body, + RPCEvent::Request { id, body, .. // TODO: Clean up RPC Message types, have a cleaner type by this point. } => self.handle_rpc_request(peer_id, id, body), - RPCEvent::Response { - id, - method_id: _, - result, - } => self.handle_rpc_response(peer_id, id, result), + RPCEvent::Response { id, result, .. } => self.handle_rpc_response(peer_id, id, result), } } @@ -134,11 +127,7 @@ impl MessageHandler { // we match on id and ignore responses past the timeout. fn handle_rpc_response(&mut self, peer_id: PeerId, id: u64, response: RPCResponse) { // if response id is related to a request, ignore (likely RPC timeout) - if self - .requests - .remove(&(peer_id.clone(), id.clone())) - .is_none() - { + if self.requests.remove(&(peer_id.clone(), id)).is_none() { debug!(self.log, "Unrecognized response from peer: {:?}", peer_id); return; } @@ -193,18 +182,19 @@ impl MessageHandler { /// Sends a HELLO RPC request or response to a newly connected peer. //TODO: The boolean determines if sending request/respond, will be cleaner in the RPC re-write - fn send_hello(&mut self, peer_id: PeerId, id: u64, request: bool) { - let rpc_event = match request { - true => RPCEvent::Request { + fn send_hello(&mut self, peer_id: PeerId, id: u64, is_request: bool) { + let rpc_event = if is_request { + RPCEvent::Request { id, method_id: RPCMethod::Hello.into(), body: RPCRequest::Hello(self.sync.generate_hello()), - }, - false => RPCEvent::Response { + } + } else { + RPCEvent::Response { id, method_id: RPCMethod::Hello.into(), result: RPCResponse::Hello(self.sync.generate_hello()), - }, + } }; // send the hello request to the network diff --git a/beacon_node/network/src/service.rs b/beacon_node/network/src/service.rs index 4e79a92fe5..c3045d280c 100644 --- a/beacon_node/network/src/service.rs +++ b/beacon_node/network/src/service.rs @@ -33,7 +33,7 @@ impl Service { let (network_send, network_recv) = channel::(); // launch message handler thread let message_handler_log = log.new(o!("Service" => "MessageHandler")); - let message_handler_send = MessageHandler::new( + let message_handler_send = MessageHandler::spawn( beacon_chain, network_send.clone(), executor, diff --git a/beacon_node/network/src/sync/simple_sync.rs b/beacon_node/network/src/sync/simple_sync.rs index a3cd9044ce..95c7092c3c 100644 --- a/beacon_node/network/src/sync/simple_sync.rs +++ b/beacon_node/network/src/sync/simple_sync.rs @@ -66,7 +66,7 @@ impl SimpleSync { //TODO: Paul to verify the logic of these fields. HelloMessage { network_id: self.network_id, - latest_finalized_root: state.finalized_root.clone(), + latest_finalized_root: state.finalized_root, latest_finalized_epoch: state.finalized_epoch, best_root: state.latest_block_roots[0], //TODO: build correct value as a beacon chain function best_slot: state.slot - 1, diff --git a/beacon_node/version/src/lib.rs b/beacon_node/version/src/lib.rs index 628186aa07..3dcd57beff 100644 --- a/beacon_node/version/src/lib.rs +++ b/beacon_node/version/src/lib.rs @@ -6,7 +6,7 @@ extern crate target_info; use target_info::Target; -const TRACK: &'static str = "unstable"; +const TRACK: &str = "unstable"; /// Provides the current platform pub fn platform() -> String { diff --git a/eth2/fork_choice/src/slow_lmd_ghost.rs b/eth2/fork_choice/src/slow_lmd_ghost.rs index af58aa7b83..0788ac171f 100644 --- a/eth2/fork_choice/src/slow_lmd_ghost.rs +++ b/eth2/fork_choice/src/slow_lmd_ghost.rs @@ -219,10 +219,8 @@ impl ForkChoice for SlowLMDGhost { head_vote_count = vote_count; } // resolve ties - choose smaller hash - else if vote_count == head_vote_count { - if *child_hash < head_hash { - head_hash = *child_hash; - } + else if vote_count == head_vote_count && *child_hash < head_hash { + head_hash = *child_hash; } } } From d2f12b7c1805c52b5e3850174638efc603a568b9 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 19 Mar 2019 23:47:58 +1100 Subject: [PATCH 48/62] Add standard RPC service --- beacon_node/client/Cargo.toml | 1 + beacon_node/client/src/client_config.rs | 3 ++- beacon_node/client/src/lib.rs | 7 ++++--- beacon_node/rpc/src/lib.rs | 12 +++++++----- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/beacon_node/client/Cargo.toml b/beacon_node/client/Cargo.toml index 11453e4b81..12c1b5c802 100644 --- a/beacon_node/client/Cargo.toml +++ b/beacon_node/client/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" beacon_chain = { path = "../beacon_chain" } network = { path = "../network" } db = { path = "../db" } +rpc = { path = "../rpc" } fork_choice = { path = "../../eth2/fork_choice" } types = { path = "../../eth2/types" } slot_clock = { path = "../../eth2/utils/slot_clock" } diff --git a/beacon_node/client/src/client_config.rs b/beacon_node/client/src/client_config.rs index 4fe390cb10..570bd30e49 100644 --- a/beacon_node/client/src/client_config.rs +++ b/beacon_node/client/src/client_config.rs @@ -20,7 +20,7 @@ pub struct ClientConfig { pub fork_choice: ForkChoiceAlgorithm, pub db_type: DBType, pub db_name: PathBuf, - //pub rpc_conf: + pub rpc_conf: rpc::RPCConfig, //pub ipc_conf: } @@ -48,6 +48,7 @@ impl Default for ClientConfig { db_type: DBType::Memory, // default db name for disk-based dbs db_name: data_dir.join("chain.db"), + rpc_conf: rpc::RPCConfig::default(), } } } diff --git a/beacon_node/client/src/lib.rs b/beacon_node/client/src/lib.rs index beba6f4de3..e6d08ac54f 100644 --- a/beacon_node/client/src/lib.rs +++ b/beacon_node/client/src/lib.rs @@ -6,11 +6,9 @@ pub mod client_types; pub mod error; pub mod notifier; +use beacon_chain::BeaconChain; pub use client_config::ClientConfig; pub use client_types::ClientTypes; - -//use beacon_chain::BeaconChain; -use beacon_chain::BeaconChain; use exit_future::Signal; use network::Service as NetworkService; use slog::o; @@ -62,6 +60,9 @@ impl Client { network_logger, )?; + // spawn the RPC server + rpc::start_server(&config.rpc_conf, &log); + Ok(Client { config, beacon_chain, diff --git a/beacon_node/rpc/src/lib.rs b/beacon_node/rpc/src/lib.rs index 6a18a4aa88..7f776d7d85 100644 --- a/beacon_node/rpc/src/lib.rs +++ b/beacon_node/rpc/src/lib.rs @@ -1,16 +1,18 @@ mod beacon_block; +pub mod config; mod validator; use self::beacon_block::BeaconBlockServiceInstance; use self::validator::ValidatorServiceInstance; +pub use config::Config as RPCConfig; use grpcio::{Environment, Server, ServerBuilder}; use protos::services_grpc::{create_beacon_block_service, create_validator_service}; use std::sync::Arc; -use slog::{info, Logger}; +use slog::{info, o}; -pub fn start_server(log: Logger) -> Server { - let log_clone = log.clone(); +pub fn start_server(config: &RPCConfig, log: &slog::Logger) -> Server { + let log = log.new(o!("Service"=>"RPC")); let env = Arc::new(Environment::new(1)); let beacon_block_service = { @@ -25,12 +27,12 @@ pub fn start_server(log: Logger) -> Server { let mut server = ServerBuilder::new(env) .register_service(beacon_block_service) .register_service(validator_service) - .bind("127.0.0.1", 50_051) + .bind(config.listen_address.to_string(), config.port) .build() .unwrap(); server.start(); for &(ref host, port) in server.bind_addrs() { - info!(log_clone, "gRPC listening on {}:{}", host, port); + info!(log, "gRPC listening on {}:{}", host, port); } server } From 037c3b830766d7bcb165b9311fd56829e3bf8048 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 20 Mar 2019 00:01:00 +1100 Subject: [PATCH 49/62] Update config and cli for rpc --- beacon_node/client/src/client_config.rs | 26 ++++++++++++++++++++++--- beacon_node/rpc/src/config.rs | 22 +++++++++++++++++++++ beacon_node/src/main.rs | 21 ++++++++++++++++++++ 3 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 beacon_node/rpc/src/config.rs diff --git a/beacon_node/client/src/client_config.rs b/beacon_node/client/src/client_config.rs index 570bd30e49..4a4774282c 100644 --- a/beacon_node/client/src/client_config.rs +++ b/beacon_node/client/src/client_config.rs @@ -4,8 +4,8 @@ use fork_choice::ForkChoiceAlgorithm; use network::NetworkConfig; use slog::error; use std::fs; -use std::net::IpAddr; use std::net::SocketAddr; +use std::net::{IpAddr, Ipv4Addr}; use std::path::PathBuf; use types::multiaddr::Protocol; use types::multiaddr::ToMultiaddr; @@ -58,7 +58,7 @@ impl ClientConfig { pub fn parse_args(args: ArgMatches, log: &slog::Logger) -> Result { let mut config = ClientConfig::default(); - // Network related args + /* Network related arguments */ // Custom p2p listen port if let Some(port_str) = args.value_of("port") { @@ -88,13 +88,33 @@ impl ClientConfig { } } - // filesystem args + /* Filesystem related arguments */ // Custom datadir if let Some(dir) = args.value_of("datadir") { config.data_dir = PathBuf::from(dir.to_string()); }; + /* RPC related arguments */ + + if let Some(rpc_address) = args.value_of("rpc-address") { + if let Ok(listen_address) = rpc_address.parse::() { + config.rpc_conf.listen_address = listen_address; + } else { + error!(log, "Invalid RPC listen address"; "Address" => rpc_address); + return Err("Invalid RPC listen address"); + } + } + + if let Some(rpc_port) = args.value_of("rpc-port") { + if let Ok(port) = rpc_port.parse::() { + config.rpc_conf.port = port; + } else { + error!(log, "Invalid RPC port"; "port" => rpc_port); + return Err("Invalid RPC port"); + } + } + Ok(config) } } diff --git a/beacon_node/rpc/src/config.rs b/beacon_node/rpc/src/config.rs new file mode 100644 index 0000000000..e21c2f7a89 --- /dev/null +++ b/beacon_node/rpc/src/config.rs @@ -0,0 +1,22 @@ +use std::net::Ipv4Addr; + +/// RPC Configuration +#[derive(Debug, Clone)] +pub struct Config { + /// Enable the RPC server. + pub enabled: bool, + /// The IPv4 address the RPC will listen on. + pub listen_address: Ipv4Addr, + /// The port the RPC will listen on. + pub port: u16, +} + +impl Default for Config { + fn default() -> Self { + Config { + enabled: false, // rpc disabled by default + listen_address: Ipv4Addr::new(127, 0, 0, 1), + port: 5051, + } + } +} diff --git a/beacon_node/src/main.rs b/beacon_node/src/main.rs index 9be6136c5c..130353d775 100644 --- a/beacon_node/src/main.rs +++ b/beacon_node/src/main.rs @@ -37,6 +37,27 @@ fn main() { .help("Network listen port for p2p connections.") .takes_value(true), ) + .arg( + Arg::with_name("rpc") + .long("Enable RPC") + .value_name("RPC") + .help("Enable the RPC server.") + .takes_value(false), + ) + .arg( + Arg::with_name("rpc-address") + .long("rpc address") + .value_name("RPCADDRESS") + .help("Listen address for RPC endpoint.") + .takes_value(true), + ) + .arg( + Arg::with_name("rpc-port") + .long("rpc port") + .value_name("RPCPORT") + .help("Listen port for RPC endpoint.") + .takes_value(true), + ) .get_matches(); // invalid arguments, panic From 4be2eeb7929ed48b31fc49e507f2c68cba796095 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 20 Mar 2019 09:58:31 +1100 Subject: [PATCH 50/62] Correct cli rpc parameters --- beacon_node/client/src/client_config.rs | 4 ++++ beacon_node/client/src/lib.rs | 5 +++-- beacon_node/src/main.rs | 8 ++++---- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/beacon_node/client/src/client_config.rs b/beacon_node/client/src/client_config.rs index 4a4774282c..cad287f2cc 100644 --- a/beacon_node/client/src/client_config.rs +++ b/beacon_node/client/src/client_config.rs @@ -97,6 +97,10 @@ impl ClientConfig { /* RPC related arguments */ + if args.is_present("rpc") { + config.rpc_conf.enabled = true; + } + if let Some(rpc_address) = args.value_of("rpc-address") { if let Ok(listen_address) = rpc_address.parse::() { config.rpc_conf.listen_address = listen_address; diff --git a/beacon_node/client/src/lib.rs b/beacon_node/client/src/lib.rs index e6d08ac54f..914e47fcf4 100644 --- a/beacon_node/client/src/lib.rs +++ b/beacon_node/client/src/lib.rs @@ -1,7 +1,6 @@ extern crate slog; mod client_config; - pub mod client_types; pub mod error; pub mod notifier; @@ -61,7 +60,9 @@ impl Client { )?; // spawn the RPC server - rpc::start_server(&config.rpc_conf, &log); + if config.rpc_conf.enabled { + rpc::start_server(&config.rpc_conf, &log); + } Ok(Client { config, diff --git a/beacon_node/src/main.rs b/beacon_node/src/main.rs index 130353d775..ea74c73766 100644 --- a/beacon_node/src/main.rs +++ b/beacon_node/src/main.rs @@ -25,7 +25,7 @@ fn main() { ) .arg( Arg::with_name("listen_address") - .long("listen_address") + .long("listen-address") .value_name("Listen Address") .help("The Network address to listen for p2p connections.") .takes_value(true), @@ -39,21 +39,21 @@ fn main() { ) .arg( Arg::with_name("rpc") - .long("Enable RPC") + .long("rpc") .value_name("RPC") .help("Enable the RPC server.") .takes_value(false), ) .arg( Arg::with_name("rpc-address") - .long("rpc address") + .long("rpc-address") .value_name("RPCADDRESS") .help("Listen address for RPC endpoint.") .takes_value(true), ) .arg( Arg::with_name("rpc-port") - .long("rpc port") + .long("rpc-port") .value_name("RPCPORT") .help("Listen port for RPC endpoint.") .takes_value(true), From d229bc9ccb890836b428f86bba1b91c203cade70 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 20 Mar 2019 10:02:26 +1100 Subject: [PATCH 51/62] Stub possible fields in HandlerMessage --- beacon_node/network/src/message_handler.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index 2a3f38bc19..a7d6e3d07f 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -44,6 +44,8 @@ pub enum HandlerMessage { PeerDisconnected(PeerId), /// An RPC response/request has been received. RPC(PeerId, RPCEvent), + /// A block has been imported. + BlockImported(), //TODO: This comes from pub-sub - decide its contents } impl MessageHandler { From 0e8b17477070678dd1f770039faab1232cca87d6 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 20 Mar 2019 10:05:17 +1100 Subject: [PATCH 52/62] Implement Goodbye libp2p rpc request --- beacon_node/libp2p/src/rpc/methods.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/beacon_node/libp2p/src/rpc/methods.rs b/beacon_node/libp2p/src/rpc/methods.rs index c99994b7ce..4ba19befdf 100644 --- a/beacon_node/libp2p/src/rpc/methods.rs +++ b/beacon_node/libp2p/src/rpc/methods.rs @@ -5,6 +5,7 @@ use types::{Epoch, Hash256, Slot}; #[derive(Debug)] pub enum RPCMethod { Hello, + Goodbye, Unknown, } @@ -12,6 +13,7 @@ impl From for RPCMethod { fn from(method_id: u16) -> Self { match method_id { 0 => RPCMethod::Hello, + 1 => RPCMethod::Goodbye, _ => RPCMethod::Unknown, } } @@ -21,6 +23,7 @@ impl Into for RPCMethod { fn into(self) -> u16 { match self { RPCMethod::Hello => 0, + RPCMethod::Goodbye => 1, _ => 0, } } @@ -29,6 +32,7 @@ impl Into for RPCMethod { #[derive(Debug, Clone)] pub enum RPCRequest { Hello(HelloMessage), + Goodbye(u64), } #[derive(Debug, Clone)] From 8acfb260d158ac24bfed0b3251618ee56ecc1328 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 20 Mar 2019 10:18:04 +1100 Subject: [PATCH 53/62] Implement RequestBeaconBlockRoots RPC method --- beacon_node/libp2p/src/rpc/methods.rs | 39 ++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/beacon_node/libp2p/src/rpc/methods.rs b/beacon_node/libp2p/src/rpc/methods.rs index 4ba19befdf..ddfbf80b54 100644 --- a/beacon_node/libp2p/src/rpc/methods.rs +++ b/beacon_node/libp2p/src/rpc/methods.rs @@ -6,6 +6,7 @@ use types::{Epoch, Hash256, Slot}; pub enum RPCMethod { Hello, Goodbye, + RequestBeaconBlockRoots, Unknown, } @@ -14,6 +15,7 @@ impl From for RPCMethod { match method_id { 0 => RPCMethod::Hello, 1 => RPCMethod::Goodbye, + 10 => RPCMethod::RequestBeaconBlockRoots, _ => RPCMethod::Unknown, } } @@ -24,6 +26,7 @@ impl Into for RPCMethod { match self { RPCMethod::Hello => 0, RPCMethod::Goodbye => 1, + RPCMethod::RequestBeaconBlockRoots => 10, _ => 0, } } @@ -33,19 +36,53 @@ impl Into for RPCMethod { pub enum RPCRequest { Hello(HelloMessage), Goodbye(u64), + RequestBeaconBlockRoots(BeaconBlockRootsRequest), } #[derive(Debug, Clone)] pub enum RPCResponse { Hello(HelloMessage), + RequestBeaconBlockRoots(BeaconBlockRootsResponse), } -// request/response structs for RPC methods +/* Request/Response data structures for RPC methods */ + +/// The HELLO request/response handshake message. #[derive(Encode, Decode, Clone, Debug)] pub struct HelloMessage { + /// The network ID of the peer. pub network_id: u8, + /// The peers last finalized root. pub latest_finalized_root: Hash256, + /// The peers last finalized epoch. pub latest_finalized_epoch: Epoch, + /// The peers last block root. pub best_root: Hash256, + /// The peers last slot. pub best_slot: Slot, } + +/// Request a number of beacon block roots from a peer. +#[derive(Encode, Decode, Clone, Debug)] +pub struct BeaconBlockRootsRequest { + /// The starting slot of the requested blocks. + start_slot: Slot, + /// The number of blocks from the start slot. + count: u64, // this must be less than 32768. //TODO: Enforce this in the lower layers +} + +/// Response a number of beacon block roots from a peer. +#[derive(Encode, Decode, Clone, Debug)] +pub struct BeaconBlockRootsResponse { + /// List of requested blocks and associated slots. + roots: Vec, +} + +/// Contains a block root and associated slot. +#[derive(Encode, Decode, Clone, Debug)] +pub struct BlockRootSlot { + /// The block root. + block_root: Hash256, + /// The block slot. + slot: Slot, +} From 450b2cfb81912c833488aab3cbd0fe8b22b98df1 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 20 Mar 2019 10:19:45 +1100 Subject: [PATCH 54/62] Rename RequestBeaconBlockRoots to BeaconBlockRoots for consistency --- beacon_node/libp2p/src/rpc/methods.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/beacon_node/libp2p/src/rpc/methods.rs b/beacon_node/libp2p/src/rpc/methods.rs index ddfbf80b54..1a35763ff2 100644 --- a/beacon_node/libp2p/src/rpc/methods.rs +++ b/beacon_node/libp2p/src/rpc/methods.rs @@ -6,7 +6,7 @@ use types::{Epoch, Hash256, Slot}; pub enum RPCMethod { Hello, Goodbye, - RequestBeaconBlockRoots, + BeaconBlockRoots, Unknown, } @@ -15,7 +15,7 @@ impl From for RPCMethod { match method_id { 0 => RPCMethod::Hello, 1 => RPCMethod::Goodbye, - 10 => RPCMethod::RequestBeaconBlockRoots, + 10 => RPCMethod::BeaconBlockRoots, _ => RPCMethod::Unknown, } } @@ -26,7 +26,7 @@ impl Into for RPCMethod { match self { RPCMethod::Hello => 0, RPCMethod::Goodbye => 1, - RPCMethod::RequestBeaconBlockRoots => 10, + RPCMethod::BeaconBlockRoots => 10, _ => 0, } } @@ -36,13 +36,13 @@ impl Into for RPCMethod { pub enum RPCRequest { Hello(HelloMessage), Goodbye(u64), - RequestBeaconBlockRoots(BeaconBlockRootsRequest), + BeaconBlockRoots(BeaconBlockRootsRequest), } #[derive(Debug, Clone)] pub enum RPCResponse { Hello(HelloMessage), - RequestBeaconBlockRoots(BeaconBlockRootsResponse), + BeaconBlockRoots(BeaconBlockRootsResponse), } /* Request/Response data structures for RPC methods */ From 8fa70f64ecc3a234b6f8733c377aab79bf90f1de Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 20 Mar 2019 10:28:05 +1100 Subject: [PATCH 55/62] Implement BeaconBlockHeaders RPC method --- beacon_node/libp2p/src/rpc/methods.rs | 29 +++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/beacon_node/libp2p/src/rpc/methods.rs b/beacon_node/libp2p/src/rpc/methods.rs index 1a35763ff2..4ee73761d5 100644 --- a/beacon_node/libp2p/src/rpc/methods.rs +++ b/beacon_node/libp2p/src/rpc/methods.rs @@ -1,12 +1,13 @@ /// Available RPC methods types and ids. use ssz_derive::{Decode, Encode}; -use types::{Epoch, Hash256, Slot}; +use types::{BeaconBlockHeader, Epoch, Hash256, Slot}; #[derive(Debug)] pub enum RPCMethod { Hello, Goodbye, BeaconBlockRoots, + BeaconBlockHeaders, Unknown, } @@ -16,6 +17,7 @@ impl From for RPCMethod { 0 => RPCMethod::Hello, 1 => RPCMethod::Goodbye, 10 => RPCMethod::BeaconBlockRoots, + 11 => RPCMethod::BeaconBlockHeaders, _ => RPCMethod::Unknown, } } @@ -27,6 +29,7 @@ impl Into for RPCMethod { RPCMethod::Hello => 0, RPCMethod::Goodbye => 1, RPCMethod::BeaconBlockRoots => 10, + RPCMethod::BeaconBlockHeaders => 11, _ => 0, } } @@ -37,12 +40,14 @@ pub enum RPCRequest { Hello(HelloMessage), Goodbye(u64), BeaconBlockRoots(BeaconBlockRootsRequest), + BeaconBlockHeaders(BeaconBlockHeadersRequest), } #[derive(Debug, Clone)] pub enum RPCResponse { Hello(HelloMessage), BeaconBlockRoots(BeaconBlockRootsResponse), + BeaconBlockHeaders(BeaconBlockHeadersResponse), } /* Request/Response data structures for RPC methods */ @@ -71,7 +76,7 @@ pub struct BeaconBlockRootsRequest { count: u64, // this must be less than 32768. //TODO: Enforce this in the lower layers } -/// Response a number of beacon block roots from a peer. +/// Response containing a number of beacon block roots from a peer. #[derive(Encode, Decode, Clone, Debug)] pub struct BeaconBlockRootsResponse { /// List of requested blocks and associated slots. @@ -86,3 +91,23 @@ pub struct BlockRootSlot { /// The block slot. slot: Slot, } + +/// Request a number of beacon block headers from a peer. +#[derive(Encode, Decode, Clone, Debug)] +pub struct BeaconBlockHeadersRequest { + /// The starting header hash of the requested headers. + start_root: Hash256, + /// The starting slot of the requested headers. + start_slot: Slot, + /// The maximum number of headers than can be returned. + max_headers: u64, + /// The maximum number of slots to skip between blocks. + skip_slots: u64, +} + +/// Response containing requested block headers. +#[derive(Encode, Decode, Clone, Debug)] +pub struct BeaconBlockHeadersResponse { + /// The list of requested beacon block headers. + headers: Vec, +} From fd04431d548002258e3da84053a8bcef6bad12fe Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 20 Mar 2019 10:36:37 +1100 Subject: [PATCH 56/62] Implement BeaconBlockBody RPC method --- beacon_node/libp2p/src/rpc/methods.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/beacon_node/libp2p/src/rpc/methods.rs b/beacon_node/libp2p/src/rpc/methods.rs index 4ee73761d5..7ae136eaf3 100644 --- a/beacon_node/libp2p/src/rpc/methods.rs +++ b/beacon_node/libp2p/src/rpc/methods.rs @@ -1,6 +1,6 @@ /// Available RPC methods types and ids. use ssz_derive::{Decode, Encode}; -use types::{BeaconBlockHeader, Epoch, Hash256, Slot}; +use types::{BeaconBlockBody, BeaconBlockHeader, Epoch, Hash256, Slot}; #[derive(Debug)] pub enum RPCMethod { @@ -8,6 +8,7 @@ pub enum RPCMethod { Goodbye, BeaconBlockRoots, BeaconBlockHeaders, + BeaconBlockBodies, Unknown, } @@ -18,6 +19,7 @@ impl From for RPCMethod { 1 => RPCMethod::Goodbye, 10 => RPCMethod::BeaconBlockRoots, 11 => RPCMethod::BeaconBlockHeaders, + 12 => RPCMethod::BeaconBlockBodies, _ => RPCMethod::Unknown, } } @@ -30,6 +32,7 @@ impl Into for RPCMethod { RPCMethod::Goodbye => 1, RPCMethod::BeaconBlockRoots => 10, RPCMethod::BeaconBlockHeaders => 11, + RPCMethod::BeaconBlockBodies => 12, _ => 0, } } @@ -41,6 +44,7 @@ pub enum RPCRequest { Goodbye(u64), BeaconBlockRoots(BeaconBlockRootsRequest), BeaconBlockHeaders(BeaconBlockHeadersRequest), + BeaconBlockBodies(BeaconBlockBodiesRequest), } #[derive(Debug, Clone)] @@ -48,6 +52,7 @@ pub enum RPCResponse { Hello(HelloMessage), BeaconBlockRoots(BeaconBlockRootsResponse), BeaconBlockHeaders(BeaconBlockHeadersResponse), + BeaconBlockBodies(BeaconBlockBodiesResponse), } /* Request/Response data structures for RPC methods */ @@ -111,3 +116,17 @@ pub struct BeaconBlockHeadersResponse { /// The list of requested beacon block headers. headers: Vec, } + +/// Request a number of beacon block bodies from a peer. +#[derive(Encode, Decode, Clone, Debug)] +pub struct BeaconBlockBodiesRequest { + /// The list of beacon block bodies being requested. + block_roots: Hash256, +} + +/// Response containing the list of requested beacon block bodies. +#[derive(Encode, Decode, Clone, Debug)] +pub struct BeaconBlockBodiesResponse { + /// The list of beacon block bodies being requested. + block_bodies: Vec, +} From ae1a7a2a25df50e5c7a5bf9d3a46049e8ff6503e Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 20 Mar 2019 10:43:40 +1100 Subject: [PATCH 57/62] Implement BeaconChainState RPC method --- beacon_node/libp2p/src/rpc/methods.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/beacon_node/libp2p/src/rpc/methods.rs b/beacon_node/libp2p/src/rpc/methods.rs index 7ae136eaf3..45e9f35abd 100644 --- a/beacon_node/libp2p/src/rpc/methods.rs +++ b/beacon_node/libp2p/src/rpc/methods.rs @@ -9,6 +9,7 @@ pub enum RPCMethod { BeaconBlockRoots, BeaconBlockHeaders, BeaconBlockBodies, + BeaconChainState, // Note: experimental, not complete. Unknown, } @@ -20,6 +21,8 @@ impl From for RPCMethod { 10 => RPCMethod::BeaconBlockRoots, 11 => RPCMethod::BeaconBlockHeaders, 12 => RPCMethod::BeaconBlockBodies, + 13 => RPCMethod::BeaconChainState, + _ => RPCMethod::Unknown, } } @@ -33,6 +36,7 @@ impl Into for RPCMethod { RPCMethod::BeaconBlockRoots => 10, RPCMethod::BeaconBlockHeaders => 11, RPCMethod::BeaconBlockBodies => 12, + RPCMethod::BeaconChainState => 13, _ => 0, } } @@ -45,6 +49,7 @@ pub enum RPCRequest { BeaconBlockRoots(BeaconBlockRootsRequest), BeaconBlockHeaders(BeaconBlockHeadersRequest), BeaconBlockBodies(BeaconBlockBodiesRequest), + BeaconChainState(BeaconChainStateRequest), } #[derive(Debug, Clone)] @@ -53,6 +58,7 @@ pub enum RPCResponse { BeaconBlockRoots(BeaconBlockRootsResponse), BeaconBlockHeaders(BeaconBlockHeadersResponse), BeaconBlockBodies(BeaconBlockBodiesResponse), + BeaconChainState(BeaconChainStateResponse), } /* Request/Response data structures for RPC methods */ @@ -130,3 +136,18 @@ pub struct BeaconBlockBodiesResponse { /// The list of beacon block bodies being requested. block_bodies: Vec, } + +/// Request values for tree hashes which yield a blocks `state_root`. +#[derive(Encode, Decode, Clone, Debug)] +pub struct BeaconChainStateRequest { + /// The tree hashes that a value is requested for. + hashes: Vec, +} + +/// Request values for tree hashes which yield a blocks `state_root`. +// Note: TBD +#[derive(Encode, Decode, Clone, Debug)] +pub struct BeaconChainStateResponse { + /// The values corresponding the to the requested tree hashes. + values: bool, //TBD - stubbed with encodeable bool +} From 9db36f15bf4dee0d92478a043f4ec4061def24a1 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 20 Mar 2019 10:47:05 +1100 Subject: [PATCH 58/62] Tidy RPC Methods --- beacon_node/libp2p/src/rpc/methods.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/beacon_node/libp2p/src/rpc/methods.rs b/beacon_node/libp2p/src/rpc/methods.rs index 45e9f35abd..3014afd0ff 100644 --- a/beacon_node/libp2p/src/rpc/methods.rs +++ b/beacon_node/libp2p/src/rpc/methods.rs @@ -3,13 +3,21 @@ use ssz_derive::{Decode, Encode}; use types::{BeaconBlockBody, BeaconBlockHeader, Epoch, Hash256, Slot}; #[derive(Debug)] +/// Available Serenity Libp2p RPC methods pub enum RPCMethod { + /// Initialise handshake between connecting peers. Hello, + /// Terminate a connection providing a reason. Goodbye, + /// Requests a number of beacon block roots. BeaconBlockRoots, + /// Requests a number of beacon block headers. BeaconBlockHeaders, + /// Requests a number of beacon block bodies. BeaconBlockBodies, + /// Requests values for a merkle proof for the current blocks state root. BeaconChainState, // Note: experimental, not complete. + /// Unknown method received. Unknown, } From 84f373fcc2ca1619dc0e3c708dbaa7a04bfa03b8 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Wed, 20 Mar 2019 10:51:53 +1100 Subject: [PATCH 59/62] Fix clippy lints --- beacon_node/beacon_chain/src/beacon_chain.rs | 8 ++--- eth2/fork_choice/src/slow_lmd_ghost.rs | 6 ++-- .../src/per_block_processing.rs | 4 +-- .../validate_attestation.rs | 34 ++++++------------- .../per_block_processing/verify_deposit.rs | 4 +-- .../get_attestation_participants.rs | 2 +- .../update_registry_and_shuffling_data.rs | 1 - eth2/types/src/beacon_block.rs | 6 ++-- eth2/types/src/beacon_state.rs | 17 ++++++---- eth2/types/src/beacon_state/epoch_cache.rs | 1 - eth2/types/src/relative_epoch.rs | 2 +- .../testing_beacon_state_builder.rs | 2 +- .../src/test_utils/testing_deposit_builder.rs | 2 +- 13 files changed, 38 insertions(+), 51 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 01787f95bc..816a570c0f 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -82,7 +82,7 @@ where let state_root = genesis_state.canonical_root(); state_store.put(&state_root, &ssz_encode(&genesis_state)[..])?; - let block_root = genesis_block.into_header().canonical_root(); + let block_root = genesis_block.block_header().canonical_root(); block_store.put(&block_root, &ssz_encode(&genesis_block)[..])?; let finalized_head = RwLock::new(CheckPoint::new( @@ -189,7 +189,7 @@ where pub fn advance_state(&self, slot: Slot) -> Result<(), SlotProcessingError> { let state_slot = self.state.read().slot; - let latest_block_header = self.head().beacon_block.into_header(); + let latest_block_header = self.head().beacon_block.block_header(); for _ in state_slot.as_u64()..slot.as_u64() { per_slot_processing(&mut *self.state.write(), &latest_block_header, &self.spec)?; @@ -561,7 +561,7 @@ where pub fn process_block(&self, block: BeaconBlock) -> Result { debug!("Processing block with slot {}...", block.slot); - let block_root = block.into_header().canonical_root(); + let block_root = block.block_header().canonical_root(); let present_slot = self.present_slot(); @@ -596,7 +596,7 @@ where // Transition the parent state to the present slot. let mut state = parent_state; - let previous_block_header = parent_block.into_header(); + let previous_block_header = parent_block.block_header(); for _ in state.slot.as_u64()..present_slot.as_u64() { if let Err(e) = per_slot_processing(&mut state, &previous_block_header, &self.spec) { return Ok(BlockProcessingOutcome::InvalidBlock( diff --git a/eth2/fork_choice/src/slow_lmd_ghost.rs b/eth2/fork_choice/src/slow_lmd_ghost.rs index 25d137089e..4b236cba45 100644 --- a/eth2/fork_choice/src/slow_lmd_ghost.rs +++ b/eth2/fork_choice/src/slow_lmd_ghost.rs @@ -215,10 +215,8 @@ impl ForkChoice for SlowLMDGhost { head_vote_count = vote_count; } // resolve ties - choose smaller hash - else if vote_count == head_vote_count { - if *child_hash < head_hash { - head_hash = *child_hash; - } + else if vote_count == head_vote_count && *child_hash < head_hash { + head_hash = *child_hash; } } } diff --git a/eth2/state_processing/src/per_block_processing.rs b/eth2/state_processing/src/per_block_processing.rs index 33f953b711..dc83abb3f3 100644 --- a/eth2/state_processing/src/per_block_processing.rs +++ b/eth2/state_processing/src/per_block_processing.rs @@ -109,7 +109,7 @@ pub fn process_block_header( Invalid::ParentBlockRootMismatch ); - state.latest_block_header = block.into_temporary_header(spec); + state.latest_block_header = block.temporary_block_header(spec); Ok(()) } @@ -388,7 +388,7 @@ pub fn process_deposits( // Create a new validator. let validator = Validator { pubkey: deposit_input.pubkey.clone(), - withdrawal_credentials: deposit_input.withdrawal_credentials.clone(), + withdrawal_credentials: deposit_input.withdrawal_credentials, activation_epoch: spec.far_future_epoch, exit_epoch: spec.far_future_epoch, withdrawable_epoch: spec.far_future_epoch, diff --git a/eth2/state_processing/src/per_block_processing/validate_attestation.rs b/eth2/state_processing/src/per_block_processing/validate_attestation.rs index 113dbc4ced..2143988a46 100644 --- a/eth2/state_processing/src/per_block_processing/validate_attestation.rs +++ b/eth2/state_processing/src/per_block_processing/validate_attestation.rs @@ -176,17 +176,7 @@ fn validate_attestation_signature_optional( ); if verify_signature { - let attestation_epoch = attestation.data.slot.epoch(spec.slots_per_epoch); - verify_attestation_signature( - state, - committee, - attestation_epoch, - &attestation.aggregation_bitfield, - &attestation.custody_bitfield, - &attestation.data, - &attestation.aggregate_signature, - spec, - )?; + verify_attestation_signature(state, committee, attestation, spec)?; } // Crosslink data root is zero (to be removed in phase 1). @@ -210,32 +200,29 @@ fn validate_attestation_signature_optional( fn verify_attestation_signature( state: &BeaconState, committee: &[usize], - attestation_epoch: Epoch, - aggregation_bitfield: &Bitfield, - custody_bitfield: &Bitfield, - attestation_data: &AttestationData, - aggregate_signature: &AggregateSignature, + a: &Attestation, spec: &ChainSpec, ) -> Result<(), Error> { let mut aggregate_pubs = vec![AggregatePublicKey::new(); 2]; let mut message_exists = vec![false; 2]; + let attestation_epoch = a.data.slot.epoch(spec.slots_per_epoch); for (i, v) in committee.iter().enumerate() { - let validator_signed = aggregation_bitfield.get(i).map_err(|_| { + let validator_signed = a.aggregation_bitfield.get(i).map_err(|_| { Error::Invalid(Invalid::BadAggregationBitfieldLength { committee_len: committee.len(), - bitfield_len: aggregation_bitfield.len(), + bitfield_len: a.aggregation_bitfield.len(), }) })?; if validator_signed { - let custody_bit: bool = match custody_bitfield.get(i) { + let custody_bit: bool = match a.custody_bitfield.get(i) { Ok(bit) => bit, // Invalidate signature if custody_bitfield.len() < committee Err(_) => { return Err(Error::Invalid(Invalid::BadCustodyBitfieldLength { committee_len: committee.len(), - bitfield_len: aggregation_bitfield.len(), + bitfield_len: a.aggregation_bitfield.len(), })); } }; @@ -254,14 +241,14 @@ fn verify_attestation_signature( // Message when custody bitfield is `false` let message_0 = AttestationDataAndCustodyBit { - data: attestation_data.clone(), + data: a.data.clone(), custody_bit: false, } .hash_tree_root(); // Message when custody bitfield is `true` let message_1 = AttestationDataAndCustodyBit { - data: attestation_data.clone(), + data: a.data.clone(), custody_bit: true, } .hash_tree_root(); @@ -283,7 +270,8 @@ fn verify_attestation_signature( let domain = spec.get_domain(attestation_epoch, Domain::Attestation, &state.fork); verify!( - aggregate_signature.verify_multiple(&messages[..], domain, &keys[..]), + a.aggregate_signature + .verify_multiple(&messages[..], domain, &keys[..]), Invalid::BadSignature ); diff --git a/eth2/state_processing/src/per_block_processing/verify_deposit.rs b/eth2/state_processing/src/per_block_processing/verify_deposit.rs index 80d8bc24fa..a3a0f5734c 100644 --- a/eth2/state_processing/src/per_block_processing/verify_deposit.rs +++ b/eth2/state_processing/src/per_block_processing/verify_deposit.rs @@ -71,9 +71,7 @@ pub fn get_existing_validator_index( ) -> Result, Error> { let deposit_input = &deposit.deposit_data.deposit_input; - let validator_index = state - .get_validator_index(&deposit_input.pubkey)? - .and_then(|i| Some(i)); + let validator_index = state.get_validator_index(&deposit_input.pubkey)?; match validator_index { None => Ok(None), diff --git a/eth2/state_processing/src/per_epoch_processing/get_attestation_participants.rs b/eth2/state_processing/src/per_epoch_processing/get_attestation_participants.rs index 3e52776b10..52ba0274b5 100644 --- a/eth2/state_processing/src/per_epoch_processing/get_attestation_participants.rs +++ b/eth2/state_processing/src/per_epoch_processing/get_attestation_participants.rs @@ -28,7 +28,7 @@ pub fn get_attestation_participants( let mut participants = Vec::with_capacity(committee.len()); for (i, validator_index) in committee.iter().enumerate() { match bitfield.get(i) { - Ok(bit) if bit == true => participants.push(*validator_index), + Ok(bit) if bit => participants.push(*validator_index), _ => {} } } diff --git a/eth2/state_processing/src/per_epoch_processing/update_registry_and_shuffling_data.rs b/eth2/state_processing/src/per_epoch_processing/update_registry_and_shuffling_data.rs index 286ad81408..0b18c25712 100644 --- a/eth2/state_processing/src/per_epoch_processing/update_registry_and_shuffling_data.rs +++ b/eth2/state_processing/src/per_epoch_processing/update_registry_and_shuffling_data.rs @@ -64,7 +64,6 @@ pub fn should_update_validator_registry( let current_epoch_committee_count = spec.get_epoch_committee_count(num_active_validators); for shard in (0..current_epoch_committee_count) - .into_iter() .map(|i| (state.current_shuffling_start_shard + i as u64) % spec.shard_count) { if state.latest_crosslinks[shard as usize].epoch <= state.validator_registry_update_epoch { diff --git a/eth2/types/src/beacon_block.rs b/eth2/types/src/beacon_block.rs index b966751ed8..6a3f1a354a 100644 --- a/eth2/types/src/beacon_block.rs +++ b/eth2/types/src/beacon_block.rs @@ -71,7 +71,7 @@ impl BeaconBlock { /// Note: performs a full tree-hash of `self.body`. /// /// Spec v0.5.0 - pub fn into_header(&self) -> BeaconBlockHeader { + pub fn block_header(&self) -> BeaconBlockHeader { BeaconBlockHeader { slot: self.slot, previous_block_root: self.previous_block_root, @@ -84,11 +84,11 @@ impl BeaconBlock { /// Returns a "temporary" header, where the `state_root` is `spec.zero_hash`. /// /// Spec v0.5.0 - pub fn into_temporary_header(&self, spec: &ChainSpec) -> BeaconBlockHeader { + pub fn temporary_block_header(&self, spec: &ChainSpec) -> BeaconBlockHeader { BeaconBlockHeader { state_root: spec.zero_hash, signature: spec.empty_signature.clone(), - ..self.into_header() + ..self.block_header() } } } diff --git a/eth2/types/src/beacon_state.rs b/eth2/types/src/beacon_state.rs index 1a165c9a9a..1e52781243 100644 --- a/eth2/types/src/beacon_state.rs +++ b/eth2/types/src/beacon_state.rs @@ -162,7 +162,7 @@ impl BeaconState { latest_state_roots: vec![spec.zero_hash; spec.slots_per_historical_root], latest_active_index_roots: vec![spec.zero_hash; spec.latest_active_index_roots_length], latest_slashed_balances: vec![0; spec.latest_slashed_exit_length], - latest_block_header: BeaconBlock::empty(spec).into_temporary_header(spec), + latest_block_header: BeaconBlock::empty(spec).temporary_block_header(spec), historical_roots: vec![], /* @@ -386,7 +386,8 @@ impl BeaconState { spec: &ChainSpec, ) -> Result<(), BeaconStateError> { let i = self.get_latest_block_roots_index(slot, spec)?; - Ok(self.latest_block_roots[i] = block_root) + self.latest_block_roots[i] = block_root; + Ok(()) } /// Safely obtains the index for `latest_randao_mixes` @@ -449,7 +450,8 @@ impl BeaconState { spec: &ChainSpec, ) -> Result<(), Error> { let i = self.get_randao_mix_index(epoch, spec)?; - Ok(self.latest_randao_mixes[i] = mix) + self.latest_randao_mixes[i] = mix; + Ok(()) } /// Safely obtains the index for `latest_active_index_roots`, given some `epoch`. @@ -492,7 +494,8 @@ impl BeaconState { spec: &ChainSpec, ) -> Result<(), Error> { let i = self.get_active_index_root_index(epoch, spec)?; - Ok(self.latest_active_index_roots[i] = index_root) + self.latest_active_index_roots[i] = index_root; + Ok(()) } /// Replace `active_index_roots` with clones of `index_root`. @@ -537,7 +540,8 @@ impl BeaconState { spec: &ChainSpec, ) -> Result<(), Error> { let i = self.get_latest_state_roots_index(slot, spec)?; - Ok(self.latest_state_roots[i] = state_root) + self.latest_state_roots[i] = state_root; + Ok(()) } /// Safely obtains the index for `latest_slashed_balances`, given some `epoch`. @@ -573,7 +577,8 @@ impl BeaconState { spec: &ChainSpec, ) -> Result<(), Error> { let i = self.get_slashed_balance_index(epoch, spec)?; - Ok(self.latest_slashed_balances[i] = balance) + self.latest_slashed_balances[i] = balance; + Ok(()) } /// Generate a seed for the given `epoch`. diff --git a/eth2/types/src/beacon_state/epoch_cache.rs b/eth2/types/src/beacon_state/epoch_cache.rs index 6eebf1da3a..32d9a643e9 100644 --- a/eth2/types/src/beacon_state/epoch_cache.rs +++ b/eth2/types/src/beacon_state/epoch_cache.rs @@ -304,7 +304,6 @@ impl EpochCrosslinkCommitteesBuilder { for (i, slot) in self.epoch.slot_iter(spec.slots_per_epoch).enumerate() { for j in (0..committees.len()) - .into_iter() .skip(i * committees_per_slot) .take(committees_per_slot) { diff --git a/eth2/types/src/relative_epoch.rs b/eth2/types/src/relative_epoch.rs index 6c135b1a6d..8f895e97a5 100644 --- a/eth2/types/src/relative_epoch.rs +++ b/eth2/types/src/relative_epoch.rs @@ -33,7 +33,7 @@ impl RelativeEpoch { /// Returns the `epoch` that `self` refers to, with respect to the `base` epoch. /// /// Spec v0.5.0 - pub fn into_epoch(&self, base: Epoch) -> Epoch { + pub fn into_epoch(self, base: Epoch) -> Epoch { match self { RelativeEpoch::Previous => base - 1, RelativeEpoch::Current => base, diff --git a/eth2/types/src/test_utils/testing_beacon_state_builder.rs b/eth2/types/src/test_utils/testing_beacon_state_builder.rs index e76a01e49b..6945769aa3 100644 --- a/eth2/types/src/test_utils/testing_beacon_state_builder.rs +++ b/eth2/types/src/test_utils/testing_beacon_state_builder.rs @@ -214,7 +214,7 @@ impl TestingBeaconStateBuilder { - spec.min_attestation_inclusion_delay; let last_slot = std::cmp::min(state.slot.as_u64(), last_slot); - for slot in first_slot..last_slot + 1 { + for slot in first_slot..=last_slot { let slot = Slot::from(slot); let committees = state diff --git a/eth2/types/src/test_utils/testing_deposit_builder.rs b/eth2/types/src/test_utils/testing_deposit_builder.rs index ee258e7fe7..326858c31a 100644 --- a/eth2/types/src/test_utils/testing_deposit_builder.rs +++ b/eth2/types/src/test_utils/testing_deposit_builder.rs @@ -47,7 +47,7 @@ impl TestingDepositBuilder { self.deposit .deposit_data .deposit_input - .withdrawal_credentials = withdrawal_credentials.clone(); + .withdrawal_credentials = withdrawal_credentials; self.deposit.deposit_data.deposit_input.proof_of_possession = self .deposit From 4105b869e1f239cb5fbbcc5a4dce17184c389e58 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 20 Mar 2019 10:54:19 +1100 Subject: [PATCH 60/62] Fix all matches relating to new RPC methods --- beacon_node/libp2p/src/rpc/protocol.rs | 12 ++++++++---- beacon_node/network/src/message_handler.rs | 4 ++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/beacon_node/libp2p/src/rpc/protocol.rs b/beacon_node/libp2p/src/rpc/protocol.rs index 6cebb7fd2d..c19aca8ffd 100644 --- a/beacon_node/libp2p/src/rpc/protocol.rs +++ b/beacon_node/libp2p/src/rpc/protocol.rs @@ -81,7 +81,7 @@ fn decode(packet: Vec) -> Result { let (hello_body, _index) = HelloMessage::ssz_decode(&packet, index)?; RPCRequest::Hello(hello_body) } - RPCMethod::Unknown => return Err(DecodeError::UnknownRPCMethod), + RPCMethod::Unknown | _ => return Err(DecodeError::UnknownRPCMethod), }; Ok(RPCEvent::Request { @@ -97,7 +97,7 @@ fn decode(packet: Vec) -> Result { let (body, _index) = HelloMessage::ssz_decode(&packet, index)?; RPCResponse::Hello(body) } - RPCMethod::Unknown => return Err(DecodeError::UnknownRPCMethod), + RPCMethod::Unknown | _ => return Err(DecodeError::UnknownRPCMethod), }; Ok(RPCEvent::Response { id, @@ -134,8 +134,11 @@ impl Encodable for RPCEvent { s.append(id); s.append(method_id); match body { - RPCRequest::Hello(body) => s.append(body), - }; + RPCRequest::Hello(body) => { + s.append(body); + } + _ => {} + } } RPCEvent::Response { id, @@ -149,6 +152,7 @@ impl Encodable for RPCEvent { RPCResponse::Hello(response) => { s.append(response); } + _ => {} } } } diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index a7d6e3d07f..4cd0ab951c 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -122,6 +122,8 @@ impl MessageHandler { RPCRequest::Hello(hello_message) => { self.handle_hello_request(peer_id, id, hello_message) } + // TODO: Handle all requests + _ => {} } } @@ -138,6 +140,8 @@ impl MessageHandler { debug!(self.log, "Hello response received from peer: {:?}", peer_id); self.validate_hello(peer_id, hello_message); } + // TODO: Handle all responses + _ => {} } } From 7c7f81d188ce29aac083f8ba1c9bd0762bfa1631 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 20 Mar 2019 14:36:09 +1100 Subject: [PATCH 61/62] Fix issue with merging v0.5.0 --- beacon_node/network/src/sync/simple_sync.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beacon_node/network/src/sync/simple_sync.rs b/beacon_node/network/src/sync/simple_sync.rs index 95c7092c3c..ea09f9c0ce 100644 --- a/beacon_node/network/src/sync/simple_sync.rs +++ b/beacon_node/network/src/sync/simple_sync.rs @@ -68,7 +68,7 @@ impl SimpleSync { network_id: self.network_id, latest_finalized_root: state.finalized_root, latest_finalized_epoch: state.finalized_epoch, - best_root: state.latest_block_roots[0], //TODO: build correct value as a beacon chain function + best_root: Hash256::zero(), //TODO: build correct value as a beacon chain function best_slot: state.slot - 1, } } From e080f6381128320df9cf3a475a5f971415df49df Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 20 Mar 2019 15:09:24 +1100 Subject: [PATCH 62/62] Rename libp2p to eth2-libp2p --- Cargo.toml | 1 + .../{libp2p => eth2-libp2p}/Cargo.toml | 2 +- .../{libp2p => eth2-libp2p}/src/behaviour.rs | 0 .../{libp2p => eth2-libp2p}/src/error.rs | 0 .../{libp2p => eth2-libp2p}/src/lib.rs | 0 .../src/network_config.rs | 0 .../src/rpc/methods.rs | 0 .../{libp2p => eth2-libp2p}/src/rpc/mod.rs | 0 .../src/rpc/protocol.rs | 0 .../{libp2p => eth2-libp2p}/src/service.rs | 0 beacon_node/network/Cargo.toml | 2 +- beacon_node/network/src/error.rs | 4 +- beacon_node/network/src/lib.rs | 2 +- beacon_node/network/src/message_handler.rs | 4 +- beacon_node/network/src/service.rs | 52 ++++++++++--------- beacon_node/network/src/sync/simple_sync.rs | 4 +- 16 files changed, 37 insertions(+), 34 deletions(-) rename beacon_node/{libp2p => eth2-libp2p}/Cargo.toml (95%) rename beacon_node/{libp2p => eth2-libp2p}/src/behaviour.rs (100%) rename beacon_node/{libp2p => eth2-libp2p}/src/error.rs (100%) rename beacon_node/{libp2p => eth2-libp2p}/src/lib.rs (100%) rename beacon_node/{libp2p => eth2-libp2p}/src/network_config.rs (100%) rename beacon_node/{libp2p => eth2-libp2p}/src/rpc/methods.rs (100%) rename beacon_node/{libp2p => eth2-libp2p}/src/rpc/mod.rs (100%) rename beacon_node/{libp2p => eth2-libp2p}/src/rpc/protocol.rs (100%) rename beacon_node/{libp2p => eth2-libp2p}/src/service.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index d34f6fd30e..cb070cc2da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ members = [ "beacon_node/db", "beacon_node/client", "beacon_node/network", + "beacon_node/eth2-libp2p", "beacon_node/rpc", "beacon_node/version", "beacon_node/beacon_chain", diff --git a/beacon_node/libp2p/Cargo.toml b/beacon_node/eth2-libp2p/Cargo.toml similarity index 95% rename from beacon_node/libp2p/Cargo.toml rename to beacon_node/eth2-libp2p/Cargo.toml index dcbc04d0b9..4dd2e9c7b4 100644 --- a/beacon_node/libp2p/Cargo.toml +++ b/beacon_node/eth2-libp2p/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "libp2p" +name = "eth2-libp2p" version = "0.1.0" authors = ["Age Manning "] edition = "2018" diff --git a/beacon_node/libp2p/src/behaviour.rs b/beacon_node/eth2-libp2p/src/behaviour.rs similarity index 100% rename from beacon_node/libp2p/src/behaviour.rs rename to beacon_node/eth2-libp2p/src/behaviour.rs diff --git a/beacon_node/libp2p/src/error.rs b/beacon_node/eth2-libp2p/src/error.rs similarity index 100% rename from beacon_node/libp2p/src/error.rs rename to beacon_node/eth2-libp2p/src/error.rs diff --git a/beacon_node/libp2p/src/lib.rs b/beacon_node/eth2-libp2p/src/lib.rs similarity index 100% rename from beacon_node/libp2p/src/lib.rs rename to beacon_node/eth2-libp2p/src/lib.rs diff --git a/beacon_node/libp2p/src/network_config.rs b/beacon_node/eth2-libp2p/src/network_config.rs similarity index 100% rename from beacon_node/libp2p/src/network_config.rs rename to beacon_node/eth2-libp2p/src/network_config.rs diff --git a/beacon_node/libp2p/src/rpc/methods.rs b/beacon_node/eth2-libp2p/src/rpc/methods.rs similarity index 100% rename from beacon_node/libp2p/src/rpc/methods.rs rename to beacon_node/eth2-libp2p/src/rpc/methods.rs diff --git a/beacon_node/libp2p/src/rpc/mod.rs b/beacon_node/eth2-libp2p/src/rpc/mod.rs similarity index 100% rename from beacon_node/libp2p/src/rpc/mod.rs rename to beacon_node/eth2-libp2p/src/rpc/mod.rs diff --git a/beacon_node/libp2p/src/rpc/protocol.rs b/beacon_node/eth2-libp2p/src/rpc/protocol.rs similarity index 100% rename from beacon_node/libp2p/src/rpc/protocol.rs rename to beacon_node/eth2-libp2p/src/rpc/protocol.rs diff --git a/beacon_node/libp2p/src/service.rs b/beacon_node/eth2-libp2p/src/service.rs similarity index 100% rename from beacon_node/libp2p/src/service.rs rename to beacon_node/eth2-libp2p/src/service.rs diff --git a/beacon_node/network/Cargo.toml b/beacon_node/network/Cargo.toml index 8b87a9d502..5275ed82fe 100644 --- a/beacon_node/network/Cargo.toml +++ b/beacon_node/network/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] beacon_chain = { path = "../beacon_chain" } -libp2p = { path = "../libp2p" } +eth2-libp2p = { path = "../eth2-libp2p" } version = { path = "../version" } types = { path = "../../eth2/types" } slog = "2.4.1" diff --git a/beacon_node/network/src/error.rs b/beacon_node/network/src/error.rs index 2005f76ae9..cdd6b62094 100644 --- a/beacon_node/network/src/error.rs +++ b/beacon_node/network/src/error.rs @@ -1,5 +1,5 @@ // generates error types -use libp2p; +use eth2_libp2p; use error_chain::{ error_chain, error_chain_processing, impl_error_chain_kind, impl_error_chain_processed, @@ -8,6 +8,6 @@ use error_chain::{ error_chain! { links { - Libp2p(libp2p::error::Error, libp2p::error::ErrorKind); + Libp2p(eth2_libp2p::error::Error, eth2_libp2p::error::ErrorKind); } } diff --git a/beacon_node/network/src/lib.rs b/beacon_node/network/src/lib.rs index 1e47b9a731..61a29ed356 100644 --- a/beacon_node/network/src/lib.rs +++ b/beacon_node/network/src/lib.rs @@ -5,5 +5,5 @@ mod message_handler; mod service; pub mod sync; -pub use libp2p::NetworkConfig; +pub use eth2_libp2p::NetworkConfig; pub use service::Service; diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index 4cd0ab951c..dbf8c7d9da 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -3,11 +3,11 @@ use crate::error; use crate::service::{NetworkMessage, OutgoingMessage}; use crate::sync::SimpleSync; use crossbeam_channel::{unbounded as channel, Sender}; -use futures::future; -use libp2p::{ +use eth2_libp2p::{ rpc::{RPCMethod, RPCRequest, RPCResponse}, HelloMessage, PeerId, RPCEvent, }; +use futures::future; use slog::warn; use slog::{debug, trace}; use std::collections::HashMap; diff --git a/beacon_node/network/src/service.rs b/beacon_node/network/src/service.rs index c3045d280c..14f994e4a5 100644 --- a/beacon_node/network/src/service.rs +++ b/beacon_node/network/src/service.rs @@ -3,20 +3,20 @@ use crate::error; use crate::message_handler::{HandlerMessage, MessageHandler}; use crate::NetworkConfig; use crossbeam_channel::{unbounded as channel, Sender, TryRecvError}; +use eth2_libp2p::RPCEvent; +use eth2_libp2p::Service as LibP2PService; +use eth2_libp2p::{Libp2pEvent, PeerId}; use futures::prelude::*; use futures::sync::oneshot; use futures::Stream; -use libp2p::RPCEvent; -use libp2p::Service as LibP2PService; -use libp2p::{Libp2pEvent, PeerId}; use slog::{debug, info, o, trace}; use std::sync::Arc; use tokio::runtime::TaskExecutor; -/// Service that handles communication between internal services and the libp2p network service. +/// Service that handles communication between internal services and the eth2_libp2p network service. pub struct Service { - //libp2p_service: Arc>, - libp2p_exit: oneshot::Sender<()>, + //eth2_libp2p_service: Arc>, + eth2_libp2p_exit: oneshot::Sender<()>, network_send: crossbeam_channel::Sender, //message_handler: MessageHandler, //message_handler_send: Sender, @@ -40,20 +40,20 @@ impl Service { message_handler_log, )?; - // launch libp2p service - let libp2p_log = log.new(o!("Service" => "Libp2p")); - let libp2p_service = LibP2PService::new(config.clone(), libp2p_log)?; + // launch eth2_libp2p service + let eth2_libp2p_log = log.new(o!("Service" => "Libp2p")); + let eth2_libp2p_service = LibP2PService::new(config.clone(), eth2_libp2p_log)?; - // TODO: Spawn thread to handle libp2p messages and pass to message handler thread. - let libp2p_exit = spawn_service( - libp2p_service, + // TODO: Spawn thread to handle eth2_libp2p messages and pass to message handler thread. + let eth2_libp2p_exit = spawn_service( + eth2_libp2p_service, network_recv, message_handler_send, executor, log, )?; let network_service = Service { - libp2p_exit, + eth2_libp2p_exit, network_send: network_send.clone(), }; @@ -72,7 +72,7 @@ impl Service { } fn spawn_service( - libp2p_service: LibP2PService, + eth2_libp2p_service: LibP2PService, network_recv: crossbeam_channel::Receiver, message_handler_send: crossbeam_channel::Sender, executor: &TaskExecutor, @@ -83,7 +83,7 @@ fn spawn_service( // spawn on the current executor executor.spawn( network_service( - libp2p_service, + eth2_libp2p_service, network_recv, message_handler_send, log.clone(), @@ -100,18 +100,18 @@ fn spawn_service( } fn network_service( - mut libp2p_service: LibP2PService, + mut eth2_libp2p_service: LibP2PService, network_recv: crossbeam_channel::Receiver, message_handler_send: crossbeam_channel::Sender, log: slog::Logger, -) -> impl futures::Future { - futures::future::poll_fn(move || -> Result<_, libp2p::error::Error> { +) -> impl futures::Future { + futures::future::poll_fn(move || -> Result<_, eth2_libp2p::error::Error> { // poll the swarm loop { - match libp2p_service.poll() { + match eth2_libp2p_service.poll() { Ok(Async::Ready(Some(Libp2pEvent::RPC(peer_id, rpc_event)))) => { trace!( - libp2p_service.log, + eth2_libp2p_service.log, "RPC Event: RPC message received: {:?}", rpc_event ); @@ -120,13 +120,13 @@ fn network_service( .map_err(|_| "failed to send rpc to handler")?; } Ok(Async::Ready(Some(Libp2pEvent::PeerDialed(peer_id)))) => { - debug!(libp2p_service.log, "Peer Dialed: {:?}", peer_id); + debug!(eth2_libp2p_service.log, "Peer Dialed: {:?}", peer_id); message_handler_send .send(HandlerMessage::PeerDialed(peer_id)) .map_err(|_| "failed to send rpc to handler")?; } Ok(Async::Ready(Some(Libp2pEvent::Message(m)))) => debug!( - libp2p_service.log, + eth2_libp2p_service.log, "Network Service: Message received: {}", m ), _ => break, @@ -143,7 +143,7 @@ fn network_service( trace!(log, "Sending RPC Event: {:?}", rpc_event); //TODO: Make swarm private //TODO: Implement correct peer id topic message handling - libp2p_service.swarm.send_rpc(peer_id, rpc_event); + eth2_libp2p_service.swarm.send_rpc(peer_id, rpc_event); } OutgoingMessage::NotifierTest => { debug!(log, "Received message from notifier"); @@ -152,7 +152,9 @@ fn network_service( } Err(TryRecvError::Empty) => break, Err(TryRecvError::Disconnected) => { - return Err(libp2p::error::Error::from("Network channel disconnected")); + return Err(eth2_libp2p::error::Error::from( + "Network channel disconnected", + )); } } } @@ -163,7 +165,7 @@ fn network_service( /// Types of messages that the network service can receive. #[derive(Debug, Clone)] pub enum NetworkMessage { - /// Send a message to libp2p service. + /// Send a message to eth2_libp2p service. //TODO: Define typing for messages across the wire Send(PeerId, OutgoingMessage), } diff --git a/beacon_node/network/src/sync/simple_sync.rs b/beacon_node/network/src/sync/simple_sync.rs index ea09f9c0ce..0f7de6ab97 100644 --- a/beacon_node/network/src/sync/simple_sync.rs +++ b/beacon_node/network/src/sync/simple_sync.rs @@ -1,6 +1,6 @@ use crate::beacon_chain::BeaconChain; -use libp2p::rpc::HelloMessage; -use libp2p::PeerId; +use eth2_libp2p::rpc::HelloMessage; +use eth2_libp2p::PeerId; use slog::{debug, o}; use std::collections::HashMap; use std::sync::Arc;