Support for Ipv6 (#4046)

## Issue Addressed
Add support for ipv6 and dual stack in lighthouse. 

## Proposed Changes
From an user perspective, now setting an ipv6 address, optionally configuring the ports should feel exactly the same as using an ipv4 address. If listening over both ipv4 and ipv6 then the user needs to:
- use the `--listen-address` two times (ipv4 and ipv6 addresses)
- `--port6` becomes then required
- `--discovery-port6` can now be used to additionally configure the ipv6 udp port

### Rough list of code changes
- Discovery:
  - Table filter and ip mode set to match the listening config. 
  - Ipv6 address, tcp port and udp port set in the ENR builder
  - Reported addresses now check which tcp port to give to libp2p
- LH Network Service:
  - Can listen over Ipv6, Ipv4, or both. This uses two sockets. Using mapped addresses is disabled from libp2p and it's the most compatible option.
- NetworkGlobals:
  - No longer stores udp port since was not used at all. Instead, stores the Ipv4 and Ipv6 TCP ports.
- NetworkConfig:
  - Update names to make it clear that previous udp and tcp ports in ENR were Ipv4
  - Add fields to configure Ipv6 udp and tcp ports in the ENR
  - Include advertised enr Ipv6 address.
  - Add type to model Listening address that's either Ipv4, Ipv6 or both. A listening address includes the ip, udp port and tcp port.
- UPnP:
  - Kept only for ipv4
- Cli flags:
  - `--listen-addresses` now can take up to two values
  - `--port` will apply to ipv4 or ipv6 if only one listening address is given. If two listening addresses are given it will apply only to Ipv4.
  - `--port6` New flag required when listening over ipv4 and ipv6 that applies exclusively to Ipv6.
  - `--discovery-port` will now apply to ipv4 and ipv6 if only one listening address is given.
  - `--discovery-port6` New flag to configure the individual udp port of ipv6 if listening over both ipv4 and ipv6.
  - `--enr-udp-port` Updated docs to specify that it only applies to ipv4. This is an old behaviour.
  - `--enr-udp6-port` Added to configure the enr udp6 field.
  - `--enr-tcp-port` Updated docs to specify that it only applies to ipv4. This is an old behaviour.
  - `--enr-tcp6-port` Added to configure the enr tcp6 field.
  - `--enr-addresses` now can take two values.
  - `--enr-match` updated behaviour.
- Common:
  - rename `unused_port` functions to specify that they are over ipv4.
  - add functions to get unused ports over ipv6.
- Testing binaries
  - Updated code to reflect network config changes and unused_port changes.

## Additional Info

TODOs:
- use two sockets in discovery. I'll get back to this and it's on https://github.com/sigp/discv5/pull/160
- lcli allow listening over two sockets in generate_bootnodes_enr
- add at least one smoke flag for ipv6 (I have tested this and works for me)
- update the book
This commit is contained in:
Divma
2023-03-14 01:13:34 +00:00
parent 06af31a66a
commit e190ebb8a0
33 changed files with 1194 additions and 361 deletions

View File

@@ -1,3 +1,4 @@
use crate::listen_addr::{ListenAddr, ListenAddress};
use crate::rpc::config::OutboundRateLimiterConfig;
use crate::types::GossipKind;
use crate::{Enr, PeerIdSerialized};
@@ -12,6 +13,7 @@ use libp2p::gossipsub::{
use libp2p::Multiaddr;
use serde_derive::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::net::{Ipv4Addr, Ipv6Addr};
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
@@ -57,24 +59,24 @@ pub struct Config {
/// Data directory where node's keyfile is stored
pub network_dir: PathBuf,
/// IP address to listen on.
pub listen_address: std::net::IpAddr,
/// The TCP port that libp2p listens on.
pub libp2p_port: u16,
/// UDP port that discovery listens on.
pub discovery_port: u16,
/// IP addresses to listen on.
listen_addresses: ListenAddress,
/// The address to broadcast to peers about which address we are listening on. None indicates
/// that no discovery address has been set in the CLI args.
pub enr_address: Option<std::net::IpAddr>,
pub enr_address: (Option<Ipv4Addr>, Option<Ipv6Addr>),
/// The udp port to broadcast to peers in order to reach back for discovery.
pub enr_udp_port: Option<u16>,
/// The udp4 port to broadcast to peers in order to reach back for discovery.
pub enr_udp4_port: Option<u16>,
/// The tcp port to broadcast to peers in order to reach back for libp2p services.
pub enr_tcp_port: Option<u16>,
/// The tcp4 port to broadcast to peers in order to reach back for libp2p services.
pub enr_tcp4_port: Option<u16>,
/// The udp6 port to broadcast to peers in order to reach back for discovery.
pub enr_udp6_port: Option<u16>,
/// The tcp6 port to broadcast to peers in order to reach back for libp2p services.
pub enr_tcp6_port: Option<u16>,
/// Target number of connected peers.
pub target_peers: usize,
@@ -139,6 +141,105 @@ pub struct Config {
pub outbound_rate_limiter_config: Option<OutboundRateLimiterConfig>,
}
impl Config {
/// Sets the listening address to use an ipv4 address. The discv5 ip_mode and table filter are
/// adjusted accordingly to ensure addresses that are present in the enr are globally
/// reachable.
pub fn set_ipv4_listening_address(&mut self, addr: Ipv4Addr, tcp_port: u16, udp_port: u16) {
self.listen_addresses = ListenAddress::V4(ListenAddr {
addr,
udp_port,
tcp_port,
});
self.discv5_config.ip_mode = discv5::IpMode::Ip4;
self.discv5_config.table_filter = |enr| enr.ip4().as_ref().map_or(false, is_global_ipv4)
}
/// Sets the listening address to use an ipv6 address. The discv5 ip_mode and table filter is
/// adjusted accordingly to ensure addresses that are present in the enr are globally
/// reachable.
pub fn set_ipv6_listening_address(&mut self, addr: Ipv6Addr, tcp_port: u16, udp_port: u16) {
self.listen_addresses = ListenAddress::V6(ListenAddr {
addr,
udp_port,
tcp_port,
});
self.discv5_config.ip_mode = discv5::IpMode::Ip6 {
enable_mapped_addresses: false,
};
self.discv5_config.table_filter = |enr| enr.ip6().as_ref().map_or(false, is_global_ipv6)
}
/// Sets the listening address to use both an ipv4 and ipv6 address. The discv5 ip_mode and
/// table filter is adjusted accordingly to ensure addresses that are present in the enr are
/// globally reachable.
pub fn set_ipv4_ipv6_listening_addresses(
&mut self,
v4_addr: Ipv4Addr,
tcp4_port: u16,
udp4_port: u16,
v6_addr: Ipv6Addr,
tcp6_port: u16,
udp6_port: u16,
) {
self.listen_addresses = ListenAddress::DualStack(
ListenAddr {
addr: v4_addr,
udp_port: udp4_port,
tcp_port: tcp4_port,
},
ListenAddr {
addr: v6_addr,
udp_port: udp6_port,
tcp_port: tcp6_port,
},
);
self.discv5_config.ip_mode = discv5::IpMode::Ip6 {
enable_mapped_addresses: true,
};
self.discv5_config.table_filter = |enr| match (&enr.ip4(), &enr.ip6()) {
(None, None) => false,
(None, Some(ip6)) => is_global_ipv6(ip6),
(Some(ip4), None) => is_global_ipv4(ip4),
(Some(ip4), Some(ip6)) => is_global_ipv4(ip4) && is_global_ipv6(ip6),
};
}
pub fn set_listening_addr(&mut self, listen_addr: ListenAddress) {
match listen_addr {
ListenAddress::V4(ListenAddr {
addr,
udp_port,
tcp_port,
}) => self.set_ipv4_listening_address(addr, tcp_port, udp_port),
ListenAddress::V6(ListenAddr {
addr,
udp_port,
tcp_port,
}) => self.set_ipv6_listening_address(addr, tcp_port, udp_port),
ListenAddress::DualStack(
ListenAddr {
addr: ip4addr,
udp_port: udp4_port,
tcp_port: tcp4_port,
},
ListenAddr {
addr: ip6addr,
udp_port: udp6_port,
tcp_port: tcp6_port,
},
) => self.set_ipv4_ipv6_listening_addresses(
ip4addr, tcp4_port, udp4_port, ip6addr, tcp6_port, udp6_port,
),
}
}
pub fn listen_addrs(&self) -> &ListenAddress {
&self.listen_addresses
}
}
impl Default for Config {
/// Generate a default network configuration.
fn default() -> Self {
@@ -183,7 +284,7 @@ impl Default for Config {
.filter_rate_limiter(filter_rate_limiter)
.filter_max_bans_per_ip(Some(5))
.filter_max_nodes_per_ip(Some(10))
.table_filter(|enr| enr.ip4().map_or(false, |ip| is_global(&ip))) // Filter non-global IPs
.table_filter(|enr| enr.ip4().map_or(false, |ip| is_global_ipv4(&ip))) // Filter non-global IPs
.ban_duration(Some(Duration::from_secs(3600)))
.ping_interval(Duration::from_secs(300))
.build();
@@ -191,12 +292,16 @@ impl Default for Config {
// NOTE: Some of these get overridden by the corresponding CLI default values.
Config {
network_dir,
listen_address: "0.0.0.0".parse().expect("valid ip address"),
libp2p_port: 9000,
discovery_port: 9000,
enr_address: None,
enr_udp_port: None,
enr_tcp_port: None,
listen_addresses: ListenAddress::V4(ListenAddr {
addr: Ipv4Addr::UNSPECIFIED,
udp_port: 9000,
tcp_port: 9000,
}),
enr_address: (None, None),
enr_udp4_port: None,
enr_tcp4_port: None,
enr_udp6_port: None,
enr_tcp6_port: None,
target_peers: 50,
gs_config,
discv5_config,
@@ -361,7 +466,7 @@ pub fn gossipsub_config(network_load: u8, fork_context: Arc<ForkContext>) -> Gos
/// Helper function to determine if the IpAddr is a global address or not. The `is_global()`
/// function is not yet stable on IpAddr.
#[allow(clippy::nonminimal_bool)]
fn is_global(addr: &std::net::Ipv4Addr) -> bool {
fn is_global_ipv4(addr: &Ipv4Addr) -> bool {
// check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two
// globally routable addresses in the 192.0.0.0/24 range.
if u32::from_be_bytes(addr.octets()) == 0xc0000009
@@ -382,3 +487,60 @@ fn is_global(addr: &std::net::Ipv4Addr) -> bool {
// Make sure the address is not in 0.0.0.0/8
&& addr.octets()[0] != 0
}
/// NOTE: Docs taken from https://doc.rust-lang.org/stable/std/net/struct.Ipv6Addr.html#method.is_global
///
/// Returns true if the address appears to be globally reachable as specified by the IANA IPv6
/// Special-Purpose Address Registry. Whether or not an address is practically reachable will
/// depend on your network configuration.
///
/// Most IPv6 addresses are globally reachable; unless they are specifically defined as not
/// globally reachable.
///
/// Non-exhaustive list of notable addresses that are not globally reachable:
///
/// - The unspecified address (is_unspecified)
/// - The loopback address (is_loopback)
/// - IPv4-mapped addresses
/// - Addresses reserved for benchmarking
/// - Addresses reserved for documentation (is_documentation)
/// - Unique local addresses (is_unique_local)
/// - Unicast addresses with link-local scope (is_unicast_link_local)
// TODO: replace with [`Ipv6Addr::is_global`] once
// [Ip](https://github.com/rust-lang/rust/issues/27709) is stable.
pub const fn is_global_ipv6(addr: &Ipv6Addr) -> bool {
const fn is_documentation(addr: &Ipv6Addr) -> bool {
(addr.segments()[0] == 0x2001) && (addr.segments()[1] == 0xdb8)
}
const fn is_unique_local(addr: &Ipv6Addr) -> bool {
(addr.segments()[0] & 0xfe00) == 0xfc00
}
const fn is_unicast_link_local(addr: &Ipv6Addr) -> bool {
(addr.segments()[0] & 0xffc0) == 0xfe80
}
!(addr.is_unspecified()
|| addr.is_loopback()
// IPv4-mapped Address (`::ffff:0:0/96`)
|| matches!(addr.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
// IPv4-IPv6 Translat. (`64:ff9b:1::/48`)
|| matches!(addr.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
// Discard-Only Address Block (`100::/64`)
|| matches!(addr.segments(), [0x100, 0, 0, 0, _, _, _, _])
// IETF Protocol Assignments (`2001::/23`)
|| (matches!(addr.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
&& !(
// Port Control Protocol Anycast (`2001:1::1`)
u128::from_be_bytes(addr.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
// Traversal Using Relays around NAT Anycast (`2001:1::2`)
|| u128::from_be_bytes(addr.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
// AMT (`2001:3::/32`)
|| matches!(addr.segments(), [0x2001, 3, _, _, _, _, _, _])
// AS112-v6 (`2001:4:112::/48`)
|| matches!(addr.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
// ORCHIDv2 (`2001:20::/28`)
|| matches!(addr.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F)
))
|| is_documentation(addr)
|| is_unique_local(addr)
|| is_unicast_link_local(addr))
}

View File

@@ -145,16 +145,39 @@ pub fn create_enr_builder_from_config<T: EnrKey>(
enable_tcp: bool,
) -> EnrBuilder<T> {
let mut builder = EnrBuilder::new("v4");
if let Some(enr_address) = config.enr_address {
builder.ip(enr_address);
let (maybe_ipv4_address, maybe_ipv6_address) = &config.enr_address;
if let Some(ip) = maybe_ipv4_address {
builder.ip4(*ip);
}
if let Some(udp_port) = config.enr_udp_port {
builder.udp4(udp_port);
if let Some(ip) = maybe_ipv6_address {
builder.ip6(*ip);
}
// we always give it our listening tcp port
if let Some(udp4_port) = config.enr_udp4_port {
builder.udp4(udp4_port);
}
if let Some(udp6_port) = config.enr_udp6_port {
builder.udp6(udp6_port);
}
if enable_tcp {
let tcp_port = config.enr_tcp_port.unwrap_or(config.libp2p_port);
builder.tcp4(tcp_port);
// If the ENR port is not set, and we are listening over that ip version, use the listening port instead.
let tcp4_port = config
.enr_tcp4_port
.or_else(|| config.listen_addrs().v4().map(|v4_addr| v4_addr.tcp_port));
if let Some(tcp4_port) = tcp4_port {
builder.tcp4(tcp4_port);
}
let tcp6_port = config
.enr_tcp6_port
.or_else(|| config.listen_addrs().v6().map(|v6_addr| v6_addr.tcp_port));
if let Some(tcp6_port) = tcp6_port {
builder.tcp6(tcp6_port);
}
}
builder
}

View File

@@ -201,8 +201,13 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
info!(log, "ENR Initialised"; "enr" => local_enr.to_base64(), "seq" => local_enr.seq(), "id"=> %local_enr.node_id(),
"ip4" => ?local_enr.ip4(), "udp4"=> ?local_enr.udp4(), "tcp4" => ?local_enr.tcp6()
);
let listen_socket = SocketAddr::new(config.listen_address, config.discovery_port);
let listen_socket = match config.listen_addrs() {
crate::listen_addr::ListenAddress::V4(v4_addr) => v4_addr.udp_socket_addr(),
crate::listen_addr::ListenAddress::V6(v6_addr) => v6_addr.udp_socket_addr(),
crate::listen_addr::ListenAddress::DualStack(_v4_addr, v6_addr) => {
v6_addr.udp_socket_addr()
}
};
// convert the keypair into an ENR key
let enr_key: CombinedKey = CombinedKey::from_libp2p(local_key)?;
@@ -1015,14 +1020,27 @@ impl<TSpec: EthSpec> NetworkBehaviour for Discovery<TSpec> {
*self.network_globals.local_enr.write() = enr;
// A new UDP socket has been detected.
// Build a multiaddr to report to libp2p
let mut address = Multiaddr::from(socket_addr.ip());
// NOTE: This doesn't actually track the external TCP port. More sophisticated NAT handling
// should handle this.
address.push(Protocol::Tcp(self.network_globals.listen_port_tcp()));
return Poll::Ready(NBAction::ReportObservedAddr {
address,
score: AddressScore::Finite(1),
});
let addr = match socket_addr.ip() {
IpAddr::V4(v4_addr) => {
self.network_globals.listen_port_tcp4().map(|tcp4_port| {
Multiaddr::from(v4_addr).with(Protocol::Tcp(tcp4_port))
})
}
IpAddr::V6(v6_addr) => {
self.network_globals.listen_port_tcp6().map(|tcp6_port| {
Multiaddr::from(v6_addr).with(Protocol::Tcp(tcp6_port))
})
}
};
if let Some(address) = addr {
// NOTE: This doesn't actually track the external TCP port. More sophisticated NAT handling
// should handle this.
return Poll::Ready(NBAction::ReportObservedAddr {
address,
score: AddressScore::Finite(1),
});
}
}
Discv5Event::EnrAdded { .. }
| Discv5Event::TalkRequest(_)
@@ -1087,7 +1105,6 @@ mod tests {
use enr::EnrBuilder;
use slog::{o, Drain};
use types::{BitVector, MinimalEthSpec, SubnetId};
use unused_port::unused_udp_port;
type E = MinimalEthSpec;
@@ -1105,17 +1122,15 @@ mod tests {
async fn build_discovery() -> Discovery<E> {
let keypair = libp2p::identity::Keypair::generate_secp256k1();
let config = NetworkConfig {
discovery_port: unused_udp_port().unwrap(),
..Default::default()
};
let mut config = NetworkConfig::default();
config.set_listening_addr(crate::ListenAddress::unused_v4_ports());
let enr_key: CombinedKey = CombinedKey::from_libp2p(&keypair).unwrap();
let enr: Enr = build_enr::<E>(&enr_key, &config, &EnrForkId::default()).unwrap();
let log = build_log(slog::Level::Debug, false);
let globals = NetworkGlobals::new(
enr,
9000,
9000,
Some(9000),
None,
MetaData::V2(MetaDataV2 {
seq_number: 0,
attnets: Default::default(),

View File

@@ -10,12 +10,14 @@ pub mod service;
#[allow(clippy::mutable_key_type)] // PeerId in hashmaps are no longer permitted by clippy
pub mod discovery;
pub mod listen_addr;
pub mod metrics;
pub mod peer_manager;
pub mod rpc;
pub mod types;
pub use config::gossip_max_size;
pub use listen_addr::*;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use std::str::FromStr;

View File

@@ -0,0 +1,97 @@
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use libp2p::{multiaddr::Protocol, Multiaddr};
use serde::{Deserialize, Serialize};
/// A listening address composed by an Ip, an UDP port and a TCP port.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ListenAddr<Ip> {
pub addr: Ip,
pub udp_port: u16,
pub tcp_port: u16,
}
impl<Ip: Into<IpAddr> + Clone> ListenAddr<Ip> {
pub fn udp_socket_addr(&self) -> SocketAddr {
(self.addr.clone().into(), self.udp_port).into()
}
pub fn tcp_socket_addr(&self) -> SocketAddr {
(self.addr.clone().into(), self.tcp_port).into()
}
}
/// Types of listening addresses Lighthouse can accept.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum ListenAddress {
V4(ListenAddr<Ipv4Addr>),
V6(ListenAddr<Ipv6Addr>),
DualStack(ListenAddr<Ipv4Addr>, ListenAddr<Ipv6Addr>),
}
impl ListenAddress {
/// Return the listening address over IpV4 if any.
pub fn v4(&self) -> Option<&ListenAddr<Ipv4Addr>> {
match self {
ListenAddress::V4(v4_addr) | ListenAddress::DualStack(v4_addr, _) => Some(v4_addr),
ListenAddress::V6(_) => None,
}
}
/// Return the listening address over IpV6 if any.
pub fn v6(&self) -> Option<&ListenAddr<Ipv6Addr>> {
match self {
ListenAddress::V6(v6_addr) | ListenAddress::DualStack(_, v6_addr) => Some(v6_addr),
ListenAddress::V4(_) => None,
}
}
/// Returns the TCP addresses.
pub fn tcp_addresses(&self) -> impl Iterator<Item = Multiaddr> + '_ {
let v4_multiaddr = self
.v4()
.map(|v4_addr| Multiaddr::from(v4_addr.addr).with(Protocol::Tcp(v4_addr.tcp_port)));
let v6_multiaddr = self
.v6()
.map(|v6_addr| Multiaddr::from(v6_addr.addr).with(Protocol::Tcp(v6_addr.tcp_port)));
v4_multiaddr.into_iter().chain(v6_multiaddr)
}
#[cfg(test)]
pub fn unused_v4_ports() -> Self {
ListenAddress::V4(ListenAddr {
addr: Ipv4Addr::UNSPECIFIED,
udp_port: unused_port::unused_udp4_port().unwrap(),
tcp_port: unused_port::unused_tcp4_port().unwrap(),
})
}
#[cfg(test)]
pub fn unused_v6_ports() -> Self {
ListenAddress::V6(ListenAddr {
addr: Ipv6Addr::UNSPECIFIED,
udp_port: unused_port::unused_udp6_port().unwrap(),
tcp_port: unused_port::unused_tcp6_port().unwrap(),
})
}
}
impl slog::KV for ListenAddress {
fn serialize(
&self,
_record: &slog::Record,
serializer: &mut dyn slog::Serializer,
) -> slog::Result {
if let Some(v4_addr) = self.v4() {
serializer.emit_arguments("ip4_address", &format_args!("{}", v4_addr.addr))?;
serializer.emit_u16("udp4_port", v4_addr.udp_port)?;
serializer.emit_u16("tcp4_port", v4_addr.tcp_port)?;
}
if let Some(v6_addr) = self.v6() {
serializer.emit_arguments("ip6_address", &format_args!("{}", v6_addr.addr))?;
serializer.emit_u16("udp6_port", v6_addr.udp_port)?;
serializer.emit_u16("tcp6_port", v6_addr.tcp_port)?;
}
slog::Result::Ok(())
}
}

View File

@@ -163,8 +163,8 @@ impl<AppReqId: ReqId, TSpec: EthSpec> Network<AppReqId, TSpec> {
let meta_data = utils::load_or_build_metadata(&config.network_dir, &log);
let globals = NetworkGlobals::new(
enr,
config.libp2p_port,
config.discovery_port,
config.listen_addrs().v4().map(|v4_addr| v4_addr.tcp_port),
config.listen_addrs().v6().map(|v6_addr| v6_addr.tcp_port),
meta_data,
config
.trusted_peers
@@ -388,36 +388,26 @@ impl<AppReqId: ReqId, TSpec: EthSpec> Network<AppReqId, TSpec> {
async fn start(&mut self, config: &crate::NetworkConfig) -> error::Result<()> {
let enr = self.network_globals.local_enr();
info!(self.log, "Libp2p Starting"; "peer_id" => %enr.peer_id(), "bandwidth_config" => format!("{}-{}", config.network_load, NetworkLoad::from(config.network_load).name));
let discovery_string = if config.disable_discovery {
"None".into()
} else {
config.discovery_port.to_string()
};
debug!(self.log, "Attempting to open listening ports"; config.listen_addrs(), "discovery_enabled" => !config.disable_discovery);
debug!(self.log, "Attempting to open listening ports"; "address" => ?config.listen_address, "tcp_port" => config.libp2p_port, "udp_port" => discovery_string);
let listen_multiaddr = {
let mut m = Multiaddr::from(config.listen_address);
m.push(MProtocol::Tcp(config.libp2p_port));
m
};
match self.swarm.listen_on(listen_multiaddr.clone()) {
Ok(_) => {
let mut log_address = listen_multiaddr;
log_address.push(MProtocol::P2p(enr.peer_id().into()));
info!(self.log, "Listening established"; "address" => %log_address);
}
Err(err) => {
crit!(
self.log,
"Unable to listen on libp2p address";
"error" => ?err,
"listen_multiaddr" => %listen_multiaddr,
);
return Err("Libp2p was unable to listen on the given listen address.".into());
}
};
for listen_multiaddr in config.listen_addrs().tcp_addresses() {
match self.swarm.listen_on(listen_multiaddr.clone()) {
Ok(_) => {
let mut log_address = listen_multiaddr;
log_address.push(MProtocol::P2p(enr.peer_id().into()));
info!(self.log, "Listening established"; "address" => %log_address);
}
Err(err) => {
crit!(
self.log,
"Unable to listen on libp2p address";
"error" => ?err,
"listen_multiaddr" => %listen_multiaddr,
);
return Err("Libp2p was unable to listen on the given listen address.".into());
}
};
}
// helper closure for dialing peers
let mut dial = |mut multiaddr: Multiaddr| {

View File

@@ -7,7 +7,6 @@ use crate::EnrExt;
use crate::{Enr, GossipTopic, Multiaddr, PeerId};
use parking_lot::RwLock;
use std::collections::HashSet;
use std::sync::atomic::{AtomicU16, Ordering};
use types::EthSpec;
pub struct NetworkGlobals<TSpec: EthSpec> {
@@ -17,10 +16,10 @@ pub struct NetworkGlobals<TSpec: EthSpec> {
pub peer_id: RwLock<PeerId>,
/// Listening multiaddrs.
pub listen_multiaddrs: RwLock<Vec<Multiaddr>>,
/// The TCP port that the libp2p service is listening on
pub listen_port_tcp: AtomicU16,
/// The UDP port that the discovery service is listening on
pub listen_port_udp: AtomicU16,
/// The TCP port that the libp2p service is listening on over Ipv4.
listen_port_tcp4: Option<u16>,
/// The TCP port that the libp2p service is listening on over Ipv6.
listen_port_tcp6: Option<u16>,
/// The collection of known peers.
pub peers: RwLock<PeerDB<TSpec>>,
// The local meta data of our node.
@@ -36,8 +35,8 @@ pub struct NetworkGlobals<TSpec: EthSpec> {
impl<TSpec: EthSpec> NetworkGlobals<TSpec> {
pub fn new(
enr: Enr,
tcp_port: u16,
udp_port: u16,
listen_port_tcp4: Option<u16>,
listen_port_tcp6: Option<u16>,
local_metadata: MetaData<TSpec>,
trusted_peers: Vec<PeerId>,
log: &slog::Logger,
@@ -46,8 +45,8 @@ impl<TSpec: EthSpec> NetworkGlobals<TSpec> {
local_enr: RwLock::new(enr.clone()),
peer_id: RwLock::new(enr.peer_id()),
listen_multiaddrs: RwLock::new(Vec::new()),
listen_port_tcp: AtomicU16::new(tcp_port),
listen_port_udp: AtomicU16::new(udp_port),
listen_port_tcp4,
listen_port_tcp6,
local_metadata: RwLock::new(local_metadata),
peers: RwLock::new(PeerDB::new(trusted_peers, log)),
gossipsub_subscriptions: RwLock::new(HashSet::new()),
@@ -73,13 +72,13 @@ impl<TSpec: EthSpec> NetworkGlobals<TSpec> {
}
/// Returns the libp2p TCP port that this node has been configured to listen on.
pub fn listen_port_tcp(&self) -> u16 {
self.listen_port_tcp.load(Ordering::Relaxed)
pub fn listen_port_tcp4(&self) -> Option<u16> {
self.listen_port_tcp4
}
/// Returns the UDP discovery port that this node has been configured to listen on.
pub fn listen_port_udp(&self) -> u16 {
self.listen_port_udp.load(Ordering::Relaxed)
pub fn listen_port_tcp6(&self) -> Option<u16> {
self.listen_port_tcp6
}
/// Returns the number of libp2p connected peers.
@@ -137,8 +136,8 @@ impl<TSpec: EthSpec> NetworkGlobals<TSpec> {
let enr = discv5::enr::EnrBuilder::new("v4").build(&enr_key).unwrap();
NetworkGlobals::new(
enr,
9000,
9000,
Some(9000),
None,
MetaData::V2(MetaDataV2 {
seq_number: 0,
attnets: Default::default(),