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

@@ -6,6 +6,7 @@ use super::enr_ext::CombinedKeyExt;
use super::ENR_FILENAME;
use crate::types::{Enr, EnrBitfield};
use crate::NetworkConfig;
use discv5::enr::EnrKey;
use libp2p::core::identity::Keypair;
use slog::{debug, warn};
use ssz::{Decode, Encode};
@@ -48,6 +49,56 @@ impl Eth2Enr for Enr {
}
}
/// Either use the given ENR or load an ENR from file if it exists and matches the current NodeId
/// and sequence number.
/// If an ENR exists, with the same NodeId, this function checks to see if the loaded ENR from
/// disk is suitable to use, otherwise we increment the given ENR's sequence number.
pub fn use_or_load_enr(
enr_key: &CombinedKey,
local_enr: &mut Enr,
config: &NetworkConfig,
log: &slog::Logger,
) -> Result<(), String> {
let enr_f = config.network_dir.join(ENR_FILENAME);
if let Ok(mut enr_file) = File::open(enr_f.clone()) {
let mut enr_string = String::new();
match enr_file.read_to_string(&mut enr_string) {
Err(_) => debug!(log, "Could not read ENR from file"),
Ok(_) => {
match Enr::from_str(&enr_string) {
Ok(disk_enr) => {
// if the same node id, then we may need to update our sequence number
if local_enr.node_id() == disk_enr.node_id() {
if compare_enr(&local_enr, &disk_enr) {
debug!(log, "ENR loaded from disk"; "file" => format!("{:?}", enr_f));
// the stored ENR has the same configuration, use it
*local_enr = disk_enr;
return Ok(());
}
// same node id, different configuration - update the sequence number
// Note: local_enr is generated with default(0) attnets value,
// so a non default value in persisted enr will also update sequence number.
let new_seq_no = disk_enr.seq().checked_add(1).ok_or_else(|| "ENR sequence number on file is too large. Remove it to generate a new NodeId")?;
local_enr.set_seq(new_seq_no, enr_key).map_err(|e| {
format!("Could not update ENR sequence number: {:?}", e)
})?;
debug!(log, "ENR sequence number increased"; "seq" => new_seq_no);
}
}
Err(e) => {
warn!(log, "ENR from file could not be decoded"; "error" => format!("{:?}", e));
}
}
}
}
}
save_enr_to_disk(&config.network_dir, &local_enr, log);
Ok(())
}
/// Loads an ENR from file if it exists and matches the current NodeId and sequence number. If none
/// exists, generates a new one.
///
@@ -65,51 +116,11 @@ pub fn build_or_load_enr<T: EthSpec>(
let enr_key = CombinedKey::from_libp2p(&local_key)?;
let mut local_enr = build_enr::<T>(&enr_key, config, enr_fork_id)?;
let enr_f = config.network_dir.join(ENR_FILENAME);
if let Ok(mut enr_file) = File::open(enr_f.clone()) {
let mut enr_string = String::new();
match enr_file.read_to_string(&mut enr_string) {
Err(_) => debug!(log, "Could not read ENR from file"),
Ok(_) => {
match Enr::from_str(&enr_string) {
Ok(disk_enr) => {
// if the same node id, then we may need to update our sequence number
if local_enr.node_id() == disk_enr.node_id() {
if compare_enr(&local_enr, &disk_enr) {
debug!(log, "ENR loaded from disk"; "file" => format!("{:?}", enr_f));
// the stored ENR has the same configuration, use it
return Ok(disk_enr);
}
// same node id, different configuration - update the sequence number
// Note: local_enr is generated with default(0) attnets value,
// so a non default value in persisted enr will also update sequence number.
let new_seq_no = disk_enr.seq().checked_add(1).ok_or_else(|| "ENR sequence number on file is too large. Remove it to generate a new NodeId")?;
local_enr.set_seq(new_seq_no, &enr_key).map_err(|e| {
format!("Could not update ENR sequence number: {:?}", e)
})?;
debug!(log, "ENR sequence number increased"; "seq" => new_seq_no);
}
}
Err(e) => {
warn!(log, "ENR from file could not be decoded"; "error" => format!("{:?}", e));
}
}
}
}
}
save_enr_to_disk(&config.network_dir, &local_enr, log);
use_or_load_enr(&enr_key, &mut local_enr, config, log)?;
Ok(local_enr)
}
/// Builds a lighthouse ENR given a `NetworkConfig`.
pub fn build_enr<T: EthSpec>(
enr_key: &CombinedKey,
config: &NetworkConfig,
enr_fork_id: EnrForkId,
) -> Result<Enr, String> {
pub fn create_enr_builder_from_config<T: EnrKey>(config: &NetworkConfig) -> EnrBuilder<T> {
let mut builder = EnrBuilder::new("v4");
if let Some(enr_address) = config.enr_address {
builder.ip(enr_address);
@@ -120,7 +131,17 @@ pub fn build_enr<T: EthSpec>(
// we always give it our listening tcp port
// TODO: Add uPnP support to map udp and tcp ports
let tcp_port = config.enr_tcp_port.unwrap_or_else(|| config.libp2p_port);
builder.tcp(tcp_port);
builder.tcp(tcp_port).tcp(config.libp2p_port);
builder
}
/// Builds a lighthouse ENR given a `NetworkConfig`.
pub fn build_enr<T: EthSpec>(
enr_key: &CombinedKey,
config: &NetworkConfig,
enr_fork_id: EnrForkId,
) -> Result<Enr, String> {
let mut builder = create_enr_builder_from_config(config);
// set the `eth2` field on our ENR
builder.add_value(ETH2_ENR_KEY.into(), enr_fork_id.as_ssz_bytes());
@@ -131,7 +152,6 @@ pub fn build_enr<T: EthSpec>(
builder.add_value(BITFIELD_ENR_KEY.into(), bitfield.as_ssz_bytes());
builder
.tcp(config.libp2p_port)
.build(enr_key)
.map_err(|e| format!("Could not build Local ENR: {:?}", e))
}

View File

@@ -3,7 +3,7 @@ pub(crate) mod enr;
pub mod enr_ext;
// Allow external use of the lighthouse ENR builder
pub use enr::{build_enr, CombinedKey, Eth2Enr};
pub use enr::{build_enr, create_enr_builder_from_config, use_or_load_enr, CombinedKey, Eth2Enr};
pub use enr_ext::{CombinedKeyExt, EnrExt};
pub use libp2p::core::identity::Keypair;

View File

@@ -26,4 +26,4 @@ pub use metrics::scrape_discovery_metrics;
pub use peer_manager::{
client::Client, score::PeerAction, PeerDB, PeerInfo, PeerSyncStatus, SyncInfo,
};
pub use service::{Libp2pEvent, Service, NETWORK_KEY_FILENAME};
pub use service::{load_private_key, Libp2pEvent, Service, NETWORK_KEY_FILENAME};

View File

@@ -357,7 +357,7 @@ fn keypair_from_bytes(mut bytes: Vec<u8>) -> error::Result<Keypair> {
/// generated and is then saved to disk.
///
/// Currently only secp256k1 keys are allowed, as these are the only keys supported by discv5.
fn load_private_key(config: &NetworkConfig, log: &slog::Logger) -> Keypair {
pub fn load_private_key(config: &NetworkConfig, log: &slog::Logger) -> Keypair {
// check for key from disk
let network_key_f = config.network_dir.join(NETWORK_KEY_FILENAME);
if let Ok(mut network_key_file) = File::open(network_key_f.clone()) {