fix(net): use external ip for discv5 config (#19784)

This commit is contained in:
Matthias Seitz
2025-11-17 22:26:19 +01:00
committed by GitHub
parent 23eb96c209
commit 940be8a092
11 changed files with 225 additions and 19 deletions

View File

@@ -75,6 +75,11 @@ pub struct Discv5 {
discovered_peer_filter: MustNotIncludeKeys,
/// Metrics for underlying [`discv5::Discv5`] node and filtered discovered peers.
metrics: Discv5Metrics,
/// Returns the _local_ [`NodeRecord`] this service was started with.
// Note: we must track this separately because the `discv5::Discv5` does not necessarily
// provide this via it's [`local_enr`](discv5::Discv5::local_ner()) This is intended for
// obtaining the port this service was launched at
local_node_record: NodeRecord,
}
impl Discv5 {
@@ -155,22 +160,29 @@ impl Discv5 {
enr.try_into().ok()
}
/// Returns the local [`Enr`] of the service.
pub fn local_enr(&self) -> Enr<discv5::enr::CombinedKey> {
self.discv5.local_enr()
}
/// The port the discv5 service is listening on.
pub const fn local_port(&self) -> u16 {
self.local_node_record.udp_port
}
/// Spawns [`discv5::Discv5`]. Returns [`discv5::Discv5`] handle in reth compatible wrapper type
/// [`Discv5`], a receiver of [`discv5::Event`]s from the underlying node, and the local
/// [`Enr`](discv5::Enr) converted into the reth compatible [`NodeRecord`] type.
pub async fn start(
sk: &SecretKey,
discv5_config: Config,
) -> Result<(Self, mpsc::Receiver<discv5::Event>, NodeRecord), Error> {
) -> Result<(Self, mpsc::Receiver<discv5::Event>), Error> {
//
// 1. make local enr from listen config
//
let (enr, bc_enr, fork_key, rlpx_ip_mode) = build_local_enr(sk, &discv5_config);
let (enr, local_node_record, fork_key, rlpx_ip_mode) = build_local_enr(sk, &discv5_config);
trace!(target: "net::discv5",
?enr,
"local ENR"
);
trace!(target: "net::discv5", ?enr, "local ENR");
//
// 2. start discv5
@@ -217,9 +229,15 @@ impl Discv5 {
);
Ok((
Self { discv5, rlpx_ip_mode, fork_key, discovered_peer_filter, metrics },
Self {
discv5,
rlpx_ip_mode,
fork_key,
discovered_peer_filter,
metrics,
local_node_record,
},
discv5_updates,
bc_enr,
))
}
@@ -699,12 +717,14 @@ mod test {
fork_key: None,
discovered_peer_filter: MustNotIncludeKeys::default(),
metrics: Discv5Metrics::default(),
local_node_record: NodeRecord::new(
(Ipv4Addr::LOCALHOST, 30303).into(),
PeerId::random(),
),
}
}
async fn start_discovery_node(
udp_port_discv5: u16,
) -> (Discv5, mpsc::Receiver<discv5::Event>, NodeRecord) {
async fn start_discovery_node(udp_port_discv5: u16) -> (Discv5, mpsc::Receiver<discv5::Event>) {
let secret_key = SecretKey::new(&mut thread_rng());
let discv5_addr: SocketAddr = format!("127.0.0.1:{udp_port_discv5}").parse().unwrap();
@@ -725,11 +745,11 @@ mod test {
// rig test
// rig node_1
let (node_1, mut stream_1, _) = start_discovery_node(30344).await;
let (node_1, mut stream_1) = start_discovery_node(30344).await;
let node_1_enr = node_1.with_discv5(|discv5| discv5.local_enr());
// rig node_2
let (node_2, mut stream_2, _) = start_discovery_node(30355).await;
let (node_2, mut stream_2) = start_discovery_node(30355).await;
let node_2_enr = node_2.with_discv5(|discv5| discv5.local_enr());
trace!(target: "net::discv5::test",

View File

@@ -25,7 +25,7 @@ use std::{
};
use tokio::{sync::mpsc, task::JoinHandle};
use tokio_stream::{wrappers::ReceiverStream, Stream};
use tracing::trace;
use tracing::{debug, trace};
/// Default max capacity for cache of discovered peers.
///
@@ -95,12 +95,15 @@ impl Discovery {
// spawn the service
let discv4_service = discv4_service.spawn();
debug!(target:"net", ?discovery_v4_addr, "started discovery v4");
Ok((Some(discv4), Some(discv4_updates), Some(discv4_service)))
};
let discv5_future = async {
let Some(config) = discv5_config else { return Ok::<_, NetworkError>((None, None)) };
let (discv5, discv5_updates, _local_enr_discv5) = Discv5::start(&sk, config).await?;
let (discv5, discv5_updates) = Discv5::start(&sk, config).await?;
debug!(target:"net", discovery_v5_enr=? discv5.local_enr(), "started discovery v5");
Ok((Some(discv5), Some(discv5_updates.into())))
};

View File

@@ -175,6 +175,7 @@ pub use reth_network_p2p as p2p;
/// re-export types crates
pub mod types {
pub use reth_discv4::NatResolver;
pub use reth_eth_wire_types::*;
pub use reth_network_types::*;
}

View File

@@ -232,9 +232,25 @@ impl<N: NetworkPrimitives> PeersInfo for NetworkHandle<N> {
fn local_node_record(&self) -> NodeRecord {
if let Some(discv4) = &self.inner.discv4 {
// Note: the discv4 services uses the same `nat` so we can directly return the node
// record here
discv4.node_record()
} else if let Some(record) = self.inner.discv5.as_ref().and_then(|d| d.node_record()) {
record
} else if let Some(discv5) = self.inner.discv5.as_ref() {
// for disv5 we must check if we have an external ip configured
if let Some(external) = self.inner.nat.and_then(|nat| nat.as_external_ip()) {
NodeRecord::new((external, discv5.local_port()).into(), *self.peer_id())
} else {
// use the node record that discv5 tracks or use localhost
self.inner.discv5.as_ref().and_then(|d| d.node_record()).unwrap_or_else(|| {
NodeRecord::new(
(std::net::IpAddr::V4(std::net::Ipv4Addr::LOCALHOST), discv5.local_port())
.into(),
*self.peer_id(),
)
})
}
// also use the tcp port
.with_tcp_port(self.inner.listener_address.lock().port())
} else {
let external_ip = self.inner.nat.and_then(|nat| nat.as_external_ip());