mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-03 00:31:50 +00:00
Anchor currently depends on `lighthouse_network` for a few types and utilities that live within. As we use our own libp2p behaviours, we actually do not use the core logic in that crate. This makes us transitively depend on a bunch of unneeded crates (even a whole separate libp2p if the versions mismatch!) Move things we require into it's own lightweight crate. Co-Authored-By: Daniel Knopik <daniel@dknopik.de>
159 lines
5.6 KiB
Rust
159 lines
5.6 KiB
Rust
//! The main bootnode server execution.
|
|
|
|
use super::BootNodeConfig;
|
|
use crate::config::BootNodeConfigSerialization;
|
|
use clap::ArgMatches;
|
|
use eth2_network_config::Eth2NetworkConfig;
|
|
use lighthouse_network::{
|
|
Eth2Enr,
|
|
discv5::{self, Discv5, enr::NodeId},
|
|
};
|
|
use network_utils::enr_ext::EnrExt;
|
|
use tracing::{info, warn};
|
|
use types::EthSpec;
|
|
|
|
pub async fn run<E: EthSpec>(
|
|
lh_matches: &ArgMatches,
|
|
bn_matches: &ArgMatches,
|
|
eth2_network_config: &Eth2NetworkConfig,
|
|
) -> Result<(), String> {
|
|
// parse the CLI args into a useable config
|
|
let config: BootNodeConfig<E> = BootNodeConfig::new(bn_matches, eth2_network_config).await?;
|
|
|
|
// Dump configs if `dump-config` or `dump-chain-config` flags are set
|
|
let config_sz = BootNodeConfigSerialization::from_config_ref(&config);
|
|
clap_utils::check_dump_configs::<_, E>(
|
|
lh_matches,
|
|
&config_sz,
|
|
ð2_network_config.chain_spec::<E>()?,
|
|
)?;
|
|
|
|
if lh_matches.get_flag("immediate-shutdown") {
|
|
return Ok(());
|
|
}
|
|
|
|
let BootNodeConfig {
|
|
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!(
|
|
listening_address = ?discv5_config.listen_config,
|
|
advertised_v4_address = ?pretty_v4_socket,
|
|
advertised_v6_address = ?pretty_v6_socket,
|
|
eth2 = eth2_field,
|
|
"Configuration parameters"
|
|
);
|
|
|
|
info!(peer_id = %local_enr.peer_id(), node_id = %local_enr.node_id(), "Identity established");
|
|
|
|
// build the contactable multiaddr list, adding the p2p protocol
|
|
info!(enr = local_enr.to_base64(), "Contact information");
|
|
info!(enr = ?local_enr, "Enr details");
|
|
info!(multiaddrs = ?local_enr.multiaddr_p2p(), "Contact information");
|
|
|
|
// construct the discv5 server
|
|
let mut discv5: 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!(
|
|
ipv4_address = ?enr.udp4_socket(),
|
|
ipv6_address = ?enr.udp6_socket(),
|
|
peer_id = ?enr.peer_id(),
|
|
node_id = ?enr.node_id(),
|
|
"Adding bootnode"
|
|
);
|
|
if enr != local_enr
|
|
&& let Err(e) = discv5.add_enr(enr)
|
|
{
|
|
warn!(error = ?e, "Failed adding ENR");
|
|
}
|
|
}
|
|
|
|
// start the server
|
|
if let Err(e) = discv5.start().await {
|
|
return Err(format!("Could not start discv5 server: {e:?}"));
|
|
}
|
|
|
|
// if there are peers in the local routing table, establish a session by running a query
|
|
if !discv5.table_entries_id().is_empty() {
|
|
info!("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) => {
|
|
return Err(format!("Failed to obtain event stream: {e:?}"));
|
|
}
|
|
};
|
|
|
|
// 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!(
|
|
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_only_nodes = ipv6_only_reachable,
|
|
dual_stack_nodes = ipv4_ipv6_reachable,
|
|
unreachable_nodes,
|
|
"Server metrics",
|
|
);
|
|
|
|
}
|
|
Some(event) = event_stream.recv() => {
|
|
match event {
|
|
discv5::Event::Discovered(_enr) => {
|
|
// An ENR has been obtained by the server
|
|
// Ignore these events here
|
|
}
|
|
discv5::Event::SocketUpdated(socket_addr) => {
|
|
info!(%socket_addr, "Advertised socket address updated");
|
|
}
|
|
_ => {} // Ignore
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|