b4f4c0d253
## Issue Addressed our bootnodes as of now support only ipv4. this makes it so that they support ipv6 ## Proposed Changes - Adds code necessary to update the bootnodes to run on dual stack nodes and therefore contact and store ipv6 nodes. - Adds some metrics about connectivity type of stored peers. It might have been nice to see some metrics over the sessions but that feels out of scope right now. ## Additional Info - some code quality improvements sneaked in since the changes seemed small - I think it depends on the OS, but enabling mapped addresses on an ipv6 node without dual stack support enabled could fail silently, making these nodes effectively ipv6 only. In the future I'll probably change this to use two sockets, which should fail loudly
142 lines
5.3 KiB
Rust
142 lines
5.3 KiB
Rust
//! The main bootnode server execution.
|
|
|
|
use super::BootNodeConfig;
|
|
use lighthouse_network::{
|
|
discv5::{enr::NodeId, Discv5, Discv5Event},
|
|
EnrExt, Eth2Enr,
|
|
};
|
|
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_v4_socket = local_enr.udp4_socket();
|
|
let enr_v6_socket = local_enr.udp6_socket();
|
|
let eth2_field = local_enr
|
|
.eth2()
|
|
.map(|fork_id| hex::encode(fork_id.fork_digest))
|
|
.unwrap_or_default();
|
|
|
|
let pretty_v4_socket = enr_v4_socket.as_ref().map(|addr| addr.to_string());
|
|
let pretty_v6_socket = enr_v6_socket.as_ref().map(|addr| addr.to_string());
|
|
info!(
|
|
log, "Configuration parameters";
|
|
"listening_address" => %listen_socket,
|
|
"advertised_v4_address" => ?pretty_v4_socket,
|
|
"advertised_v6_address" => ?pretty_v6_socket,
|
|
"eth2" => eth2_field
|
|
);
|
|
|
|
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" => local_enr.to_base64());
|
|
info!(log, "Contact information"; "multiaddrs" => ?local_enr.multiaddr_p2p());
|
|
|
|
// construct the discv5 server
|
|
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 boot_nodes {
|
|
info!(
|
|
log,
|
|
"Adding bootnode";
|
|
"ipv4_address" => ?enr.udp4_socket(),
|
|
"ipv6_address" => ?enr.udp6_socket(),
|
|
"peer_id" => ?enr.peer_id(),
|
|
"node_id" => ?enr.node_id()
|
|
);
|
|
if enr != local_enr {
|
|
if let Err(e) = discv5.add_enr(enr) {
|
|
slog::warn!(log, "Failed adding ENR"; "error" => ?e);
|
|
}
|
|
}
|
|
}
|
|
|
|
// start the server
|
|
if let Err(e) = discv5.start(listen_socket).await {
|
|
slog::crit!(log, "Could not start discv5 server"; "error" => %e);
|
|
return;
|
|
}
|
|
|
|
// 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(NodeId::random()).await;
|
|
}
|
|
|
|
// respond with metrics every 10 seconds
|
|
let mut metric_interval = tokio::time::interval(tokio::time::Duration::from_secs(10));
|
|
|
|
// get an event stream
|
|
let mut event_stream = match discv5.event_stream().await {
|
|
Ok(stream) => stream,
|
|
Err(e) => {
|
|
slog::crit!(log, "Failed to obtain event stream"; "error" => %e);
|
|
return;
|
|
}
|
|
};
|
|
|
|
// listen for events
|
|
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_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 {
|
|
Discv5Event::Discovered(_enr) => {
|
|
// An ENR has bee obtained by the server
|
|
// Ignore these events here
|
|
}
|
|
Discv5Event::EnrAdded { .. } => {} // Ignore
|
|
Discv5Event::TalkRequest(_) => {} // Ignore
|
|
Discv5Event::NodeInserted { .. } => {} // Ignore
|
|
Discv5Event::SocketUpdated(socket_addr) => {
|
|
info!(log, "Advertised socket address updated"; "socket_addr" => %socket_addr);
|
|
}
|
|
Discv5Event::SessionEstablished{ .. } => {} // Ignore
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|