diff --git a/Cargo.lock b/Cargo.lock index 7bb666e08..0ee0e35f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -538,9 +538,11 @@ version = "0.2.12" dependencies = [ "beacon_node", "clap", - "discv5", "eth2_libp2p", + "eth2_ssz", + "eth2_testnet_config", "futures 0.3.5", + "hex 0.4.2", "log 0.4.11", "logging", "slog", @@ -550,6 +552,7 @@ dependencies = [ "slog-term", "sloggers", "tokio 0.2.22", + "types", ] [[package]] @@ -1242,9 +1245,9 @@ checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" [[package]] name = "discv5" -version = "0.1.0-alpha.11" +version = "0.1.0-alpha.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68cb1b942aadd3bb3a13620c4d831c0aa49eda988cf8bcccfdfdc7ef69504a7" +checksum = "65a5e4a22a4c1d7142f54ac068b8c6252610ed0ebf00264f39eccee7f88fe4b9" dependencies = [ "aes-gcm", "arrayvec", diff --git a/beacon_node/eth2_libp2p/Cargo.toml b/beacon_node/eth2_libp2p/Cargo.toml index 49e6dc92e..2df5123b5 100644 --- a/beacon_node/eth2_libp2p/Cargo.toml +++ b/beacon_node/eth2_libp2p/Cargo.toml @@ -32,7 +32,7 @@ snap = "1.0.0" void = "1.0.2" tokio-io-timeout = "0.4.0" tokio-util = { version = "0.3.1", features = ["codec", "compat"] } -discv5 = { version = "0.1.0-alpha.10", features = ["libp2p"] } +discv5 = { version = "0.1.0-alpha.12", features = ["libp2p"] } tiny-keccak = "2.0.2" environment = { path = "../../lighthouse/environment" } rand = "0.7.3" diff --git a/boot_node/Cargo.toml b/boot_node/Cargo.toml index ea3a2acba..73306261c 100644 --- a/boot_node/Cargo.toml +++ b/boot_node/Cargo.toml @@ -8,6 +8,9 @@ edition = "2018" beacon_node = { path = "../beacon_node" } clap = "2.33.0" eth2_libp2p = { path = "../beacon_node/eth2_libp2p" } +types = { path = "../consensus/types" } +eth2_testnet_config = { path = "../common/eth2_testnet_config" } +eth2_ssz = { path = "../consensus/ssz" } slog = "2.5.2" sloggers = "1.0.1" tokio = "0.2.21" @@ -18,4 +21,4 @@ slog-async = "2.5.0" slog-scope = "4.3.0" slog-stdlog = "4.0.0" futures = "0.3.5" -discv5 = "0.1.0-alpha.5" +hex = "0.4.2" diff --git a/boot_node/src/config.rs b/boot_node/src/config.rs index a08aed00c..2a4bba51d 100644 --- a/boot_node/src/config.rs +++ b/boot_node/src/config.rs @@ -1,34 +1,81 @@ -use beacon_node::{get_data_dir, set_network_config}; +use beacon_node::{get_data_dir, get_eth2_testnet_config, set_network_config}; use clap::ArgMatches; -use discv5::{enr::CombinedKey, Enr}; +use eth2_libp2p::discv5::{enr::CombinedKey, Enr}; use eth2_libp2p::{ discovery::{create_enr_builder_from_config, use_or_load_enr}, load_private_key, CombinedKeyExt, NetworkConfig, }; +use eth2_testnet_config::Eth2TestnetConfig; +use ssz::Encode; use std::convert::TryFrom; +use std::marker::PhantomData; use std::net::SocketAddr; +use types::EthSpec; /// A set of configuration parameters for the bootnode, established from CLI arguments. -pub struct BootNodeConfig { +pub struct BootNodeConfig { pub listen_socket: SocketAddr, // TODO: Generalise to multiaddr pub boot_nodes: Vec, pub local_enr: Enr, pub local_key: CombinedKey, pub auto_update: bool, + phantom: PhantomData, } -impl TryFrom<&ArgMatches<'_>> for BootNodeConfig { +impl TryFrom<&ArgMatches<'_>> for BootNodeConfig { type Error = String; fn try_from(matches: &ArgMatches<'_>) -> Result { let data_dir = get_data_dir(matches); + // Try and grab testnet config from input CLI params + let eth2_testnet_config: Option> = { + if matches.is_present("testnet") { + Some(get_eth2_testnet_config(&matches)?) + } else { + None + } + }; + + // Try and obtain bootnodes + + let boot_nodes = { + let mut boot_nodes = Vec::new(); + + if let Some(testnet_config) = eth2_testnet_config.as_ref() { + if let Some(enr) = &testnet_config.boot_enr { + boot_nodes.extend_from_slice(enr); + } + } + + if let Some(nodes) = matches.value_of("boot-nodes") { + boot_nodes.extend_from_slice( + &nodes + .split(',') + .map(|enr| enr.parse().map_err(|_| format!("Invalid ENR: {}", enr))) + .collect::, _>>()?, + ); + } + + boot_nodes + }; + let mut network_config = NetworkConfig::default(); let logger = slog_scope::logger(); set_network_config(&mut network_config, matches, &data_dir, &logger, true)?; + // default to the standard port + if !matches.is_present("enr-udp-port") { + network_config.enr_udp_port = Some( + matches + .value_of("port") + .expect("Value required") + .parse() + .map_err(|_| "Invalid port number")?, + ); + } let private_key = load_private_key(&network_config, &logger); let local_key = CombinedKey::from_libp2p(&private_key)?; @@ -39,16 +86,38 @@ impl TryFrom<&ArgMatches<'_>> for BootNodeConfig { use_or_load_enr(&local_key, &mut local_enr, &network_config, &logger)?; - let boot_nodes = { - if let Some(boot_nodes) = matches.value_of("boot-nodes") { - boot_nodes - .split(',') - .map(|enr| enr.parse().map_err(|_| format!("Invalid ENR: {}", enr))) - .collect::, _>>()? + // build the enr_fork_id and add it to the local_enr if it exists + if let Some(config) = eth2_testnet_config.as_ref() { + let spec = config + .yaml_config + .as_ref() + .ok_or_else(|| "The testnet directory must contain a spec config".to_string())? + .apply_to_chain_spec::(&T::default_spec()) + .ok_or_else(|| "The loaded config is not compatible with the current spec")?; + + if let Some(genesis_state) = config.genesis_state.as_ref() { + slog::info!(logger, "Genesis state found"; "root" => genesis_state.canonical_root().to_string()); + let enr_fork = spec.enr_fork_id( + types::Slot::from(0u64), + genesis_state.genesis_validators_root, + ); + + // add to the local_enr + if let Err(e) = local_enr.insert("eth2", enr_fork.as_ssz_bytes(), &local_key) { + slog::warn!(logger, "Could not update eth2 field"; "error" => ?e); + } } else { - Vec::new() + slog::warn!( + logger, + "No genesis state provided. No Eth2 field added to the ENR" + ); } - }; + } else { + slog::warn!( + logger, + "No testnet config provided. Not setting an eth2 field" + ); + } let auto_update = matches.is_present("enable-enr_auto_update"); @@ -62,6 +131,7 @@ impl TryFrom<&ArgMatches<'_>> for BootNodeConfig { local_enr, local_key, auto_update, + phantom: PhantomData, }) } } diff --git a/boot_node/src/lib.rs b/boot_node/src/lib.rs index 2a5546663..3b6b6f391 100644 --- a/boot_node/src/lib.rs +++ b/boot_node/src/lib.rs @@ -8,6 +8,7 @@ mod config; mod server; pub use cli::cli_app; use config::BootNodeConfig; +use types::EthSpec; const LOG_CHANNEL_SIZE: usize = 2048; @@ -45,13 +46,19 @@ pub fn run(matches: &ArgMatches<'_>, debug_level: String) { let _scope_guard = slog_scope::set_global_logger(logger); let _log_guard = slog_stdlog::init_with_level(debug_level).unwrap(); + let log = slog_scope::logger(); // Run the main function emitting any errors - if let Err(e) = main(matches, slog_scope::logger()) { + if let Err(e) = match matches.value_of("spec") { + Some("minimal") => main::(matches, log), + Some("mainnet") => main::(matches, log), + Some("interop") => main::(matches, log), + spec => unreachable!("Unknown spec configuration: {:?}", spec), + } { slog::crit!(slog_scope::logger(), "{}", e); } } -fn main(matches: &ArgMatches<'_>, log: slog::Logger) -> Result<(), String> { +fn main(matches: &ArgMatches<'_>, log: slog::Logger) -> Result<(), String> { // Builds a custom executor for the bootnode let mut runtime = tokio::runtime::Builder::new() .threaded_scheduler() @@ -60,7 +67,7 @@ fn main(matches: &ArgMatches<'_>, log: slog::Logger) -> Result<(), String> { .map_err(|e| format!("Failed to build runtime: {}", e))?; // parse the CLI args into a useable config - let config = BootNodeConfig::try_from(matches)?; + let config: BootNodeConfig = BootNodeConfig::try_from(matches)?; // Run the boot node runtime.block_on(server::run(config, log)); diff --git a/boot_node/src/server.rs b/boot_node/src/server.rs index 415e44eec..367948a4b 100644 --- a/boot_node/src/server.rs +++ b/boot_node/src/server.rs @@ -1,16 +1,25 @@ //! The main bootnode server execution. use super::BootNodeConfig; -use discv5::{Discv5, Discv5ConfigBuilder, Discv5Event}; -use eth2_libp2p::EnrExt; +use eth2_libp2p::{ + discv5::{enr::NodeId, Discv5, Discv5ConfigBuilder, Discv5Event}, + EnrExt, Eth2Enr, +}; use futures::prelude::*; use slog::info; +use types::EthSpec; -pub async fn run(config: BootNodeConfig, log: slog::Logger) { +pub async fn run(config: BootNodeConfig, log: slog::Logger) { // Print out useful information about the generated ENR let enr_socket = config.local_enr.udp_socket().expect("Enr has a UDP socket"); - info!(log, "Configuration parameters"; "listening_address" => format!("{}:{}", config.listen_socket.ip(), config.listen_socket.port()), "broadcast_address" => format!("{}:{}",enr_socket.ip(), enr_socket.port())); + let eth2_field = config + .local_enr + .eth2() + .map(|fork_id| hex::encode(fork_id.fork_digest)) + .unwrap_or_default(); + + info!(log, "Configuration parameters"; "listening_address" => format!("{}:{}", config.listen_socket.ip(), config.listen_socket.port()), "broadcast_address" => format!("{}:{}",enr_socket.ip(), enr_socket.port()), "eth2" => eth2_field); info!(log, "Identity established"; "peer_id" => config.local_enr.peer_id().to_string(), "node_id" => config.local_enr.node_id().to_string()); @@ -51,7 +60,7 @@ pub async fn run(config: BootNodeConfig, log: slog::Logger) { // if there are peers in the local routing table, establish a session by running a query if !discv5.table_entries_id().is_empty() { info!(log, "Executing bootstrap query..."); - let _ = discv5.find_node(discv5::enr::NodeId::random()).await; + let _ = discv5.find_node(NodeId::random()).await; } // respond with metrics every 10 seconds diff --git a/common/eth2_testnet_config/Cargo.toml b/common/eth2_testnet_config/Cargo.toml index e8b7bd842..f5351875c 100644 --- a/common/eth2_testnet_config/Cargo.toml +++ b/common/eth2_testnet_config/Cargo.toml @@ -19,4 +19,4 @@ serde_yaml = "0.8.11" types = { path = "../../consensus/types"} enr = { version = "0.1.0", features = ["libsecp256k1", "ed25519"] } eth2_ssz = "0.1.2" -eth2_config = { path = "../eth2_config"} \ No newline at end of file +eth2_config = { path = "../eth2_config"} diff --git a/lighthouse/environment/Cargo.toml b/lighthouse/environment/Cargo.toml index ec05faaed..ee191f38d 100644 --- a/lighthouse/environment/Cargo.toml +++ b/lighthouse/environment/Cargo.toml @@ -21,4 +21,4 @@ slog-json = "2.3.0" exit-future = "0.2.0" lazy_static = "1.4.0" lighthouse_metrics = { path = "../../common/lighthouse_metrics" } -discv5 = { version = "0.1.0-alpha.10", features = ["libp2p"] } +discv5 = { version = "0.1.0-alpha.12", features = ["libp2p"] }