reuse beacon_node methods for initializing network configs in boot_node (#1520)

## Issue Addressed

#1378

## Proposed Changes

Boot node reuses code from beacon_node to initialize network config. This also enables using the network directory to store/load the enr and the private key.

## Additional Info

Note that before this PR the port cli arguments were off (the argument was named `enr-port` but used as `boot-node-enr-port`).
Therefore as port always the cli port argument was used (for both enr and listening). Now the enr-port argument can be used to overwrite the listening port as the public port others should connect to.

Last but not least note, that this restructuring reuses `ethlibp2p::NetworkConfig` that has many more options than the ones used in the boot node. For example the network config has an own `discv5_config` field that gets never used in the boot node and instead another `Discv5Config` gets created later in the boot node process.

Co-authored-by: Age Manning <Age@AgeManning.com>
This commit is contained in:
blacktemplar
2020-08-21 12:00:01 +00:00
parent 3cfd70d7fd
commit 2bc9115a94
10 changed files with 296 additions and 274 deletions

View File

@@ -5,6 +5,7 @@ authors = ["Sigma Prime <contact@sigmaprime.io>"]
edition = "2018"
[dependencies]
beacon_node = { path = "../beacon_node" }
clap = "2.33.0"
eth2_libp2p = { path = "../beacon_node/eth2_libp2p" }
slog = "2.5.2"

View File

@@ -12,7 +12,7 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
surface compared to a full beacon node.")
.settings(&[clap::AppSettings::ColoredHelp])
.arg(
Arg::with_name("boot-node-enr-address")
Arg::with_name("enr-address")
.value_name("IP-ADDRESS")
.help("The external IP address/ DNS address to broadcast to other peers on how to reach this node. \
If a DNS address is provided, the enr-address is set to the IP address it resolves to and \
@@ -44,7 +44,7 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
.takes_value(true),
)
.arg(
Arg::with_name("enr-port")
Arg::with_name("enr-udp-port")
.long("enr-port")
.value_name("PORT")
.help("The UDP port of the boot node's ENR. This is the port that external peers will dial to reach this boot node. Set this only if the external port differs from the listening port.")

View File

@@ -1,7 +1,12 @@
use beacon_node::{get_data_dir, set_network_config};
use clap::ArgMatches;
use discv5::{enr::CombinedKey, Enr};
use eth2_libp2p::{
discovery::{create_enr_builder_from_config, use_or_load_enr},
load_private_key, CombinedKeyExt, NetworkConfig,
};
use std::convert::TryFrom;
use std::net::{IpAddr, SocketAddr, ToSocketAddrs};
use std::net::SocketAddr;
/// A set of configuration parameters for the bootnode, established from CLI arguments.
pub struct BootNodeConfig {
@@ -17,17 +22,22 @@ impl TryFrom<&ArgMatches<'_>> for BootNodeConfig {
type Error = String;
fn try_from(matches: &ArgMatches<'_>) -> Result<Self, Self::Error> {
let listen_address = matches
.value_of("listen-address")
.expect("required parameter")
.parse::<IpAddr>()
.map_err(|_| "Invalid listening address".to_string())?;
let data_dir = get_data_dir(matches);
let listen_port = matches
.value_of("port")
.expect("required parameter")
.parse::<u16>()
.map_err(|_| "Invalid listening port".to_string())?;
let mut network_config = NetworkConfig::default();
let logger = slog_scope::logger();
set_network_config(&mut network_config, matches, &data_dir, &logger, true)?;
let private_key = load_private_key(&network_config, &logger);
let local_key = CombinedKey::from_libp2p(&private_key)?;
let mut local_enr = create_enr_builder_from_config(&network_config)
.build(&local_key)
.map_err(|e| format!("Failed to build ENR: {:?}", e))?;
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") {
@@ -40,34 +50,11 @@ impl TryFrom<&ArgMatches<'_>> for BootNodeConfig {
}
};
let enr_port = {
if let Some(port) = matches.value_of("boot-node-enr-port") {
port.parse::<u16>()
.map_err(|_| "Invalid ENR port".to_string())?
} else {
listen_port
}
};
let enr_address = {
let address_string = matches
.value_of("boot-node-enr-address")
.expect("required parameter");
resolve_address(address_string.into(), enr_port)?
};
let auto_update = matches.is_present("enable-enr_auto_update");
// the address to listen on
let listen_socket = SocketAddr::new(listen_address, enr_port);
// Generate a new key and build a new ENR
let local_key = CombinedKey::generate_secp256k1();
let local_enr = discv5::enr::EnrBuilder::new("v4")
.ip(enr_address)
.udp(enr_port)
.build(&local_key)
.map_err(|e| format!("Failed to build ENR: {:?}", e))?;
let listen_socket =
SocketAddr::new(network_config.listen_address, network_config.discovery_port);
Ok(BootNodeConfig {
listen_socket,
@@ -78,25 +65,3 @@ impl TryFrom<&ArgMatches<'_>> for BootNodeConfig {
})
}
}
/// Resolves an IP/DNS string to an IpAddr.
fn resolve_address(address_string: String, port: u16) -> Result<IpAddr, String> {
match address_string.parse::<IpAddr>() {
Ok(addr) => Ok(addr), // valid IpAddr
Err(_) => {
let mut addr = address_string.clone();
// Appending enr-port to the dns hostname to appease `to_socket_addrs()` parsing.
addr.push_str(&format!(":{}", port.to_string()));
// `to_socket_addr()` does the dns resolution
// Note: `to_socket_addrs()` is a blocking call
addr.to_socket_addrs()
.map(|mut resolved_addrs|
// Pick the first ip from the list of resolved addresses
resolved_addrs
.next()
.map(|a| a.ip())
.ok_or_else(|| "Resolved dns addr contains no entries".to_string()))
.map_err(|_| format!("Failed to parse enr-address: {}", address_string))?
}
}
}