diff --git a/crates/cli/src/commands/relay.rs b/crates/cli/src/commands/relay.rs index 1c92663a..2edd8d4a 100644 --- a/crates/cli/src/commands/relay.rs +++ b/crates/cli/src/commands/relay.rs @@ -403,11 +403,25 @@ mod tests { with_relay_server( |args| args.p2p.external_host = Some("www.google.com".into()), async |cfg| { - let response = relay_server_get(cfg, "/enr").await.unwrap(); - let body = response.text().await.unwrap(); - let enr = pluto_eth2util::enr::Record::try_from(body.as_str()).unwrap(); - - assert!(enr.ip().unwrap().is_loopback()); + // Resolution happens asynchronously on a tick, so poll until the + // ENR reflects a non-loopback IP (mirrors the Go test using + // `assert.Eventually`). + tokio::time::timeout(time::Duration::from_secs(10), async { + loop { + let response = relay_server_get(cfg.clone(), "/enr").await.unwrap(); + let body = response.text().await.unwrap(); + let enr = pluto_eth2util::enr::Record::try_from(body.as_str()).unwrap(); + let ip = enr.ip().unwrap(); + + if !ip.is_loopback() { + break; + } + + tokio::time::sleep(time::Duration::from_millis(200)).await; + } + }) + .await + .expect("external host never resolved to non-loopback ip"); }, ) .await diff --git a/crates/relay-server/src/web.rs b/crates/relay-server/src/web.rs index 97576a0a..20e5f24d 100644 --- a/crates/relay-server/src/web.rs +++ b/crates/relay-server/src/web.rs @@ -329,13 +329,22 @@ async fn resolve_external_host_periodically( /// Resolves the external host to an IP address. async fn resolve_external_host(state: Arc, external_host: &str) { - match tokio::net::lookup_host(external_host).await { - Ok(mut addrs) => { - if let Some(addr) = addrs.next() - && let IpAddr::V4(ipv4) = addr.ip() - { + // `tokio::net::lookup_host` requires a `host:port` input, but we only need + // the IP — use a dummy port of 0 so a bare hostname resolves correctly. + match tokio::net::lookup_host((external_host, 0)).await { + Ok(addrs) => { + let ipv4 = addrs + .filter_map(|a| match a.ip() { + IpAddr::V4(v4) => Some(v4), + IpAddr::V6(_) => None, + }) + .next(); + + if let Some(ipv4) = ipv4 { debug!("Resolved external host {external_host} to {ipv4}"); state.set_external_host_ip(Some(ipv4)).await; + } else { + warn!("External host {external_host} resolved with no IPv4 address"); } } Err(e) => {