Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - Ipv6 bootnodes #3752

Closed
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions beacon_node/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use std::cmp::max;
use std::fmt::Debug;
use std::fmt::Write;
use std::fs;
use std::net::Ipv6Addr;
use std::net::{IpAddr, Ipv4Addr, ToSocketAddrs};
use std::path::{Path, PathBuf};
use std::str::FromStr;
Expand Down Expand Up @@ -837,9 +838,11 @@ pub fn set_network_config(
}

if cli_args.is_present("enr-match") {
// set the enr address to localhost if the address is 0.0.0.0
if config.listen_address == "0.0.0.0".parse::<IpAddr>().expect("valid ip addr") {
config.enr_address = Some("127.0.0.1".parse::<IpAddr>().expect("valid ip addr"));
// set the enr address to localhost if the address is unspecified
if config.listen_address == IpAddr::V4(Ipv4Addr::UNSPECIFIED) {
config.enr_address = Some(IpAddr::V4(Ipv4Addr::LOCALHOST));
} else if config.listen_address == IpAddr::V6(Ipv6Addr::UNSPECIFIED) {
config.enr_address = Some(IpAddr::V6(Ipv6Addr::LOCALHOST));
} else {
config.enr_address = Some(config.listen_address);
}
Expand Down
11 changes: 11 additions & 0 deletions boot_node/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use beacon_node::{get_data_dir, set_network_config};
use clap::ArgMatches;
use eth2_network_config::Eth2NetworkConfig;
use lighthouse_network::discv5::IpMode;
use lighthouse_network::discv5::{enr::CombinedKey, Discv5Config, Enr};
use lighthouse_network::{
discovery::{create_enr_builder_from_config, load_enr_from_disk, use_or_load_enr},
Expand Down Expand Up @@ -52,6 +53,10 @@ impl<T: EthSpec> BootNodeConfig<T> {
};

let mut network_config = NetworkConfig::default();
// create ipv6 sockets and enable ipv4 mapped addresses.
network_config.discv5_config.ip_mode = IpMode::Ip6 {
enable_mapped_addresses: true,
};

let logger = slog_scope::logger();

Expand Down Expand Up @@ -105,6 +110,12 @@ impl<T: EthSpec> BootNodeConfig<T> {

let mut local_enr = {
let mut builder = create_enr_builder_from_config(&network_config, false);
// Include the ipv6 ports too.
// NOTE: we do this explicitely to be able to upgrade the bootnodes to ipv6 without
divagant-martian marked this conversation as resolved.
Show resolved Hide resolved
// upgrading the beacon node yet.
if let Some(udp_port) = network_config.enr_udp_port {
builder.udp6(udp_port);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means that every bootnode will advertise a udp6 port? And even if we set an ipv4 address in the config, we still create an IPv6 socket right? (There's prob no harm in doing this, just double checking)

I was thinking that we were going to change the create_enr_builder_from_config() and if an ipv6 address is given, then we do dual stack and advertise both ips and ports.

I see that we want to take the cautious approach and not modify the beacon node in any way, but I think we use regular beacon nodes for bootnodes in the testnets.

What are your thoughts on extending this to include beacon nodes if an ipv6 address is given in the CLI config. We force everyone to use dual-stack initially I think if we went down that path?

Copy link
Collaborator Author

@divagant-martian divagant-martian Nov 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer if we update the boot nodes first tbh. This way we can gauge how ipv6 is working on live discv5 servers and continue from there


// If we know of the ENR field, add it to the initial construction
if let Some(enr_fork_bytes) = enr_fork {
Expand Down
85 changes: 59 additions & 26 deletions boot_node/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,53 +9,60 @@ use slog::info;
use types::EthSpec;

pub async fn run<T: EthSpec>(config: BootNodeConfig<T>, log: slog::Logger) {
let BootNodeConfig {
listen_socket,
boot_nodes,
local_enr,
local_key,
discv5_config,
..
} = config;

// Print out useful information about the generated ENR

let enr_socket = config
.local_enr
.udp4_socket()
.expect("Enr has a UDP socket");
let eth2_field = config
.local_enr
let enr_v4_socket = local_enr.udp4_socket().expect("Enr has a ipv4 UDP socket");
let enr_v6_socket = local_enr.udp6_socket().expect("Enr has a ipv6 UDP socket");
let eth2_field = 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, "Configuration parameters";
"listening_address" => %listen_socket,
"advertised_v4_address" => %enr_v4_socket,
"advertised_v6_address" => %enr_v6_socket,
"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());
info!(log, "Identity established"; "peer_id" => %local_enr.peer_id(), "node_id" => %local_enr.node_id());

// build the contactable multiaddr list, adding the p2p protocol
info!(log, "Contact information"; "enr" => config.local_enr.to_base64());
info!(log, "Contact information"; "multiaddrs" => format!("{:?}", config.local_enr.multiaddr_p2p()));
info!(log, "Contact information"; "enr" => local_enr.to_base64());
info!(log, "Contact information"; "multiaddrs" => ?local_enr.multiaddr_p2p());

// construct the discv5 server
let mut discv5 = Discv5::new(
config.local_enr.clone(),
config.local_key,
config.discv5_config,
)
.unwrap();
let mut discv5 = Discv5::new(local_enr.clone(), local_key, discv5_config).unwrap();

// If there are any bootnodes add them to the routing table
for enr in config.boot_nodes {
for enr in boot_nodes {
info!(
log,
"Adding bootnode";
"address" => ?enr.udp4_socket(),
"peer_id" => enr.peer_id().to_string(),
"node_id" => enr.node_id().to_string()
"peer_id" => ?enr.peer_id(),
"node_id" => ?enr.node_id()
);
if enr != config.local_enr {
if enr != local_enr {
if let Err(e) = discv5.add_enr(enr) {
slog::warn!(log, "Failed adding ENR"; "error" => e.to_string());
slog::warn!(log, "Failed adding ENR"; "error" => ?e);
}
}
}

// start the server
if let Err(e) = discv5.start(config.listen_socket).await {
slog::crit!(log, "Could not start discv5 server"; "error" => e.to_string());
if let Err(e) = discv5.start(listen_socket).await {
slog::crit!(log, "Could not start discv5 server"; "error" => %e);
return;
}

Expand All @@ -72,7 +79,7 @@ pub async fn run<T: EthSpec>(config: BootNodeConfig<T>, log: slog::Logger) {
let mut event_stream = match discv5.event_stream().await {
Ok(stream) => stream,
Err(e) => {
slog::crit!(log, "Failed to obtain event stream"; "error" => e.to_string());
slog::crit!(log, "Failed to obtain event stream"; "error" => %e);
return;
}
};
Expand All @@ -81,9 +88,35 @@ pub async fn run<T: EthSpec>(config: BootNodeConfig<T>, log: slog::Logger) {
loop {
tokio::select! {
_ = metric_interval.tick() => {
// Get some ipv4/ipv6 stats to add in the metrics.
let mut ipv4_only_reachable: usize = 0;
let mut ipv6_only_reachable: usize= 0;
let mut ipv4_ipv6_reachable: usize = 0;
let mut unreachable_nodes: usize = 0;
for enr in discv5.kbuckets().iter_ref().filter_map(|entry| entry.status.is_connected().then_some(entry.node.value)) {
let declares_ipv4 = enr.udp4_socket().is_some();
let declares_ipv6 = enr.udp6_socket().is_some();
match (declares_ipv4, declares_ipv6) {
(true, true) => ipv4_ipv6_reachable += 1,
(true, false) => ipv4_only_reachable += 1,
(false, true) => ipv6_only_reachable += 1,
(false, false) => unreachable_nodes += 1,
}
}

// display server metrics
let metrics = discv5.metrics();
info!(log, "Server metrics"; "connected_peers" => discv5.connected_peers(), "active_sessions" => metrics.active_sessions, "requests/s" => format!("{:.2}", metrics.unsolicited_requests_per_second));
info!(
log, "Server metrics";
"connected_peers" => discv5.connected_peers(),
"active_sessions" => metrics.active_sessions,
"requests/s" => format_args!("{:.2}", metrics.unsolicited_requests_per_second),
"ipv4_nodes" => ipv4_only_reachable,
"ipv6_nodes" => ipv6_only_reachable,
"ipv6_and_ipv4_nodes" => ipv4_ipv6_reachable,
"unreachable_nodes" => unreachable_nodes,
);

}
Some(event) = event_stream.recv() => {
match event {
Expand All @@ -95,7 +128,7 @@ pub async fn run<T: EthSpec>(config: BootNodeConfig<T>, log: slog::Logger) {
Discv5Event::TalkRequest(_) => {} // Ignore
Discv5Event::NodeInserted { .. } => {} // Ignore
Discv5Event::SocketUpdated(socket_addr) => {
info!(log, "External socket address updated"; "socket_addr" => format!("{:?}", socket_addr));
info!(log, "Advertised socket address updated"; "socket_addr" => %socket_addr);
}
Discv5Event::SessionEstablished{ .. } => {} // Ignore
}
Expand Down