feat(net): integrate external public ip auto discovery (#632)

* feat(net): integrate external public ip auto discovery

* Update crates/net/discv4/src/config.rs

Co-authored-by: Georgios Konstantopoulos <me@gakonst.com>

* rename var

Co-authored-by: Georgios Konstantopoulos <me@gakonst.com>
This commit is contained in:
Matthias Seitz
2022-12-28 16:14:07 +01:00
committed by GitHub
parent c3432bc284
commit 525f28a67d
7 changed files with 141 additions and 9 deletions

View File

@ -6,7 +6,7 @@ license = "Apache-2.0"
repository = "https://github.com/paradigmxyz/reth"
readme = "README.md"
description = """
Ethereum network support
Ethereum network discovery
"""
[dependencies]
@ -15,6 +15,7 @@ reth-primitives = { path = "../../primitives" }
reth-rlp = { path = "../../common/rlp", features = ["enr"] }
reth-rlp-derive = { path = "../../common/rlp-derive" }
reth-net-common = { path = "../common" }
reth-net-nat = { path = "../nat" }
# ethereum
discv5 = { git = "https://github.com/sigp/discv5" }
@ -34,7 +35,6 @@ bytes = "1.2"
tracing = "0.1"
thiserror = "1.0"
hex = "0.4"
public-ip = "0.2"
rand = { version = "0.8", optional = true }
generic-array = "0.14"

View File

@ -5,6 +5,7 @@
use bytes::{Bytes, BytesMut};
use reth_net_common::ban_list::BanList;
use reth_net_nat::{NatResolver, ResolveNatInterval};
use reth_primitives::NodeRecord;
use reth_rlp::Encodable;
use std::{
@ -54,6 +55,11 @@ pub struct Discv4Config {
pub enable_eip868: bool,
/// Additional pairs to include in The [`Enr`](enr::Enr) if EIP-868 extension is enabled <https://eips.ethereum.org/EIPS/eip-868>
pub additional_eip868_rlp_pairs: HashMap<Vec<u8>, Bytes>,
/// If configured, try to resolve public ip
pub external_ip_resolver: Option<NatResolver>,
/// If configured and a `external_ip_resolver` is configured, try to resolve the external ip
/// using this interval.
pub resolve_external_ip_interval: Option<Duration>,
}
impl Discv4Config {
@ -85,6 +91,14 @@ impl Discv4Config {
}
self
}
/// Returns the corresponding [`ResolveNatInterval`], if a [NatResolver] and an interval was
/// configured
pub fn resolve_external_ip_interval(&self) -> Option<ResolveNatInterval> {
let resolver = self.external_ip_resolver?;
let interval = self.resolve_external_ip_interval?;
Some(ResolveNatInterval::interval(resolver, interval))
}
}
impl Default for Discv4Config {
@ -113,6 +127,9 @@ impl Default for Discv4Config {
enable_lookup: true,
enable_eip868: true,
additional_eip868_rlp_pairs: Default::default(),
external_ip_resolver: Some(Default::default()),
/// By default retry public IP using a 5min interval
resolve_external_ip_interval: Some(Duration::from_secs(60 * 5)),
}
}
}
@ -247,6 +264,21 @@ impl Discv4ConfigBuilder {
self
}
/// Configures if and how the external IP of the node should be resolved.
pub fn external_ip_resolver(&mut self, external_ip_resolver: Option<NatResolver>) -> &mut Self {
self.config.external_ip_resolver = external_ip_resolver;
self
}
/// Sets the interval at which the external IP is to be resolved.
pub fn resolve_external_ip_interval(
&mut self,
resolve_external_ip_interval: Option<Duration>,
) -> &mut Self {
self.config.resolve_external_ip_interval = resolve_external_ip_interval;
self
}
/// Returns the configured [`Discv4Config`]
pub fn build(&self) -> Discv4Config {
self.config.clone()

View File

@ -49,7 +49,7 @@ use tokio::{
time::Interval,
};
use tokio_stream::{wrappers::ReceiverStream, Stream, StreamExt};
use tracing::{debug, trace, warn};
use tracing::{debug, info, trace, warn};
pub mod bootnodes;
pub mod error;
@ -67,8 +67,9 @@ pub use reth_primitives::NodeRecord;
#[cfg(any(test, feature = "mock"))]
pub mod mock;
use reth_net_nat::ResolveNatInterval;
/// reexport to get public ip.
pub use public_ip;
pub use reth_net_nat::{external_ip, NatResolver};
/// The default port for discv4 via UDP
///
@ -361,6 +362,8 @@ pub struct Discv4Service {
evict_expired_requests_interval: Interval,
/// Interval when to resend pings.
ping_interval: Interval,
/// The interval at which to attempt resolving external IP again.
resolve_external_ip_interval: Option<ResolveNatInterval>,
/// How this services is configured
config: Discv4Config,
}
@ -453,8 +456,9 @@ impl Discv4Service {
lookup_interval: self_lookup_interval,
ping_interval,
evict_expired_requests_interval,
config,
lookup_rotator,
resolve_external_ip_interval: config.resolve_external_ip_interval(),
config,
}
}
@ -467,6 +471,16 @@ impl Discv4Service {
}
}
/// Sets the given ip address as the node's external IP in the node record announced in
/// discovery
pub fn set_external_ip_addr(&mut self, external_ip: IpAddr) {
if self.local_node_record.address != external_ip {
info!(target : "discv4", ?external_ip, "Updating external ip");
self.local_node_record.address = external_ip;
let _ = self.local_eip_868_enr.set_ip(external_ip, &self.secret_key);
}
}
/// Returns the address of the UDP socket
pub fn local_addr(&self) -> SocketAddr {
self.local_address
@ -1251,6 +1265,12 @@ impl Discv4Service {
self.re_ping_oldest();
}
if let Some(Poll::Ready(Some(ip))) =
self.resolve_external_ip_interval.as_mut().map(|r| r.poll_tick(cx))
{
self.set_external_ip_addr(ip);
}
// process all incoming commands
if let Some(mut rx) = self.commands_rx.take() {
let mut is_done = false;

View File

@ -216,7 +216,7 @@ pub async fn create_discv4_with_config(config: Discv4Config) -> (Discv4, Discv4S
let socket = SocketAddr::from_str("0.0.0.0:0").unwrap();
let (secret_key, pk) = SECP256K1.generate_keypair(&mut rng);
let id = PeerId::from_slice(&pk.serialize_uncompressed()[1..]);
let external_addr = public_ip::addr().await.unwrap_or_else(|| socket.ip());
let external_addr = reth_net_nat::external_ip().await.unwrap_or_else(|| socket.ip());
let local_enr =
NodeRecord { address: external_addr, tcp_port: socket.port(), udp_port: socket.port(), id };
Discv4::bind(socket, local_enr, secret_key, config).await.unwrap()