Update boot-node and discovery (#1682)

* Improve boot_node and upgrade discovery

* Clippy lints
This commit is contained in:
Age Manning 2020-09-29 18:28:29 +10:00 committed by GitHub
parent ae28773965
commit 13cb642f39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 119 additions and 27 deletions

9
Cargo.lock generated
View File

@ -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",

View File

@ -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"

View File

@ -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"

View File

@ -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<T: EthSpec> {
pub listen_socket: SocketAddr,
// TODO: Generalise to multiaddr
pub boot_nodes: Vec<Enr>,
pub local_enr: Enr,
pub local_key: CombinedKey,
pub auto_update: bool,
phantom: PhantomData<T>,
}
impl TryFrom<&ArgMatches<'_>> for BootNodeConfig {
impl<T: EthSpec> TryFrom<&ArgMatches<'_>> for BootNodeConfig<T> {
type Error = String;
fn try_from(matches: &ArgMatches<'_>) -> Result<Self, Self::Error> {
let data_dir = get_data_dir(matches);
// Try and grab testnet config from input CLI params
let eth2_testnet_config: Option<Eth2TestnetConfig<T>> = {
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::<Result<Vec<Enr>, _>>()?,
);
}
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::<Result<Vec<Enr>, _>>()?
// 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>(&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,
})
}
}

View File

@ -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::<types::MinimalEthSpec>(matches, log),
Some("mainnet") => main::<types::MainnetEthSpec>(matches, log),
Some("interop") => main::<types::InteropEthSpec>(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<T: EthSpec>(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<T> = BootNodeConfig::try_from(matches)?;
// Run the boot node
runtime.block_on(server::run(config, log));

View File

@ -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<T: EthSpec>(config: BootNodeConfig<T>, 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

View File

@ -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"] }