Update discv5 to expand ipv6 support (#4319)

Done in different PRs so that they can reviewed independently, as it's likely this won't be merged before I leave

Includes resolution for #4080 
- [ ] #4299
- [ ] #4318
- [ ] #4320 

Co-authored-by: Diva M <divma@protonmail.com>
Co-authored-by: Age Manning <Age@AgeManning.com>
This commit is contained in:
Divma
2023-06-13 01:25:05 +00:00
parent 62a2413ade
commit 2639e67e90
12 changed files with 425 additions and 170 deletions

View File

@@ -5,7 +5,7 @@ authors = ["Sigma Prime <contact@sigmaprime.io>"]
edition = "2021"
[dependencies]
discv5 = { version = "0.2.2", features = ["libp2p"] }
discv5 = { version = "0.3.0", features = ["libp2p"]}
unsigned-varint = { version = "0.6.0", features = ["codec"] }
types = { path = "../../consensus/types" }
ssz_types = "0.5.0"
@@ -60,4 +60,4 @@ quickcheck = "0.9.2"
quickcheck_macros = "0.9.1"
[features]
libp2p-websocket = []
libp2p-websocket = []

View File

@@ -163,7 +163,7 @@ impl Config {
udp_port,
tcp_port,
});
self.discv5_config.ip_mode = discv5::IpMode::Ip4;
self.discv5_config.listen_config = discv5::ListenConfig::from_ip(addr.into(), udp_port);
self.discv5_config.table_filter = |enr| enr.ip4().as_ref().map_or(false, is_global_ipv4)
}
@@ -176,9 +176,8 @@ impl Config {
udp_port,
tcp_port,
});
self.discv5_config.ip_mode = discv5::IpMode::Ip6 {
enable_mapped_addresses: false,
};
self.discv5_config.listen_config = discv5::ListenConfig::from_ip(addr.into(), udp_port);
self.discv5_config.table_filter = |enr| enr.ip6().as_ref().map_or(false, is_global_ipv6)
}
@@ -206,10 +205,10 @@ impl Config {
tcp_port: tcp6_port,
},
);
self.discv5_config.listen_config = discv5::ListenConfig::default()
.with_ipv4(v4_addr, udp4_port)
.with_ipv6(v6_addr, udp6_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),
@@ -279,9 +278,17 @@ impl Default for Config {
.build()
.expect("The total rate limit has been specified"),
);
let listen_addresses = ListenAddress::V4(ListenAddr {
addr: Ipv4Addr::UNSPECIFIED,
udp_port: 9000,
tcp_port: 9000,
});
let discv5_listen_config =
discv5::ListenConfig::from_ip(Ipv4Addr::UNSPECIFIED.into(), 9000);
// discv5 configuration
let discv5_config = Discv5ConfigBuilder::new()
let discv5_config = Discv5ConfigBuilder::new(discv5_listen_config)
.enable_packet_filter()
.session_cache_capacity(5000)
.request_timeout(Duration::from_secs(1))
@@ -304,12 +311,9 @@ impl Default for Config {
// NOTE: Some of these get overridden by the corresponding CLI default values.
Config {
network_dir,
listen_addresses: ListenAddress::V4(ListenAddr {
addr: Ipv4Addr::UNSPECIFIED,
udp_port: 9000,
tcp_port: 9000,
}),
listen_addresses,
enr_address: (None, None),
enr_udp4_port: None,
enr_tcp4_port: None,
enr_udp6_port: None,

View File

@@ -198,7 +198,7 @@ impl CombinedKeyPublicExt for CombinedPublicKey {
fn as_peer_id(&self) -> PeerId {
match self {
Self::Secp256k1(pk) => {
let pk_bytes = pk.to_bytes();
let pk_bytes = pk.to_sec1_bytes();
let libp2p_pk = libp2p::core::PublicKey::Secp256k1(
libp2p::core::identity::secp256k1::PublicKey::decode(&pk_bytes)
.expect("valid public key"),
@@ -222,14 +222,16 @@ impl CombinedKeyExt for CombinedKey {
match key {
Keypair::Secp256k1(key) => {
let secret =
discv5::enr::k256::ecdsa::SigningKey::from_bytes(&key.secret().to_bytes())
discv5::enr::k256::ecdsa::SigningKey::from_slice(&key.secret().to_bytes())
.expect("libp2p key must be valid");
Ok(CombinedKey::Secp256k1(secret))
}
Keypair::Ed25519(key) => {
let ed_keypair =
discv5::enr::ed25519_dalek::SecretKey::from_bytes(&key.encode()[..32])
.expect("libp2p key must be valid");
let ed_keypair = discv5::enr::ed25519_dalek::SigningKey::from_bytes(
&(key.encode()[..32])
.try_into()
.expect("libp2p key must be valid"),
);
Ok(CombinedKey::from(ed_keypair))
}
Keypair::Ecdsa(_) => Err("Ecdsa keypairs not supported"),
@@ -281,7 +283,7 @@ mod tests {
fn test_secp256k1_peer_id_conversion() {
let sk_hex = "df94a73d528434ce2309abb19c16aedb535322797dbd59c157b1e04095900f48";
let sk_bytes = hex::decode(sk_hex).unwrap();
let secret_key = discv5::enr::k256::ecdsa::SigningKey::from_bytes(&sk_bytes).unwrap();
let secret_key = discv5::enr::k256::ecdsa::SigningKey::from_slice(&sk_bytes).unwrap();
let libp2p_sk = libp2p::identity::secp256k1::SecretKey::from_bytes(sk_bytes).unwrap();
let secp256k1_kp: libp2p::identity::secp256k1::Keypair = libp2p_sk.into();
@@ -300,16 +302,18 @@ mod tests {
fn test_ed25519_peer_conversion() {
let sk_hex = "4dea8a5072119927e9d243a7d953f2f4bc95b70f110978e2f9bc7a9000e4b261";
let sk_bytes = hex::decode(sk_hex).unwrap();
let secret = discv5::enr::ed25519_dalek::SecretKey::from_bytes(&sk_bytes).unwrap();
let public = discv5::enr::ed25519_dalek::PublicKey::from(&secret);
let keypair = discv5::enr::ed25519_dalek::Keypair { secret, public };
let secret_key = discv5::enr::ed25519_dalek::SigningKey::from_bytes(
&sk_bytes.clone().try_into().unwrap(),
);
let libp2p_sk = libp2p::identity::ed25519::SecretKey::from_bytes(sk_bytes).unwrap();
let ed25519_kp: libp2p::identity::ed25519::Keypair = libp2p_sk.into();
let libp2p_kp = Keypair::Ed25519(ed25519_kp);
let secp256k1_kp: libp2p::identity::ed25519::Keypair = libp2p_sk.into();
let libp2p_kp = Keypair::Ed25519(secp256k1_kp);
let peer_id = libp2p_kp.public().to_peer_id();
let enr = discv5::enr::EnrBuilder::new("v4").build(&keypair).unwrap();
let enr = discv5::enr::EnrBuilder::new("v4")
.build(&secret_key)
.unwrap();
let node_id = peer_id_to_node_id(&peer_id).unwrap();
assert_eq!(enr.node_id(), node_id);

View File

@@ -209,13 +209,6 @@ 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.tcp4(), "tcp6" => ?local_enr.tcp6(), "udp6" => ?local_enr.udp6()
);
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)?;
@@ -251,10 +244,7 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
// Start the discv5 service and obtain an event stream
let event_stream = if !config.disable_discovery {
discv5
.start(listen_socket)
.map_err(|e| e.to_string())
.await?;
discv5.start().map_err(|e| e.to_string()).await?;
debug!(log, "Discovery service started");
EventStream::Awaiting(Box::pin(discv5.event_stream()))
} else {
@@ -413,7 +403,7 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
/// If the external address needs to be modified, use `update_enr_udp_socket.
pub fn update_enr_tcp_port(&mut self, port: u16) -> Result<(), String> {
self.discv5
.enr_insert("tcp", &port.to_be_bytes())
.enr_insert("tcp", &port)
.map_err(|e| format!("{:?}", e))?;
// replace the global version
@@ -428,29 +418,12 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
/// This is with caution. Discovery should automatically maintain this. This should only be
/// used when automatic discovery is disabled.
pub fn update_enr_udp_socket(&mut self, socket_addr: SocketAddr) -> Result<(), String> {
match socket_addr {
SocketAddr::V4(socket) => {
self.discv5
.enr_insert("ip", &socket.ip().octets())
.map_err(|e| format!("{:?}", e))?;
self.discv5
.enr_insert("udp", &socket.port().to_be_bytes())
.map_err(|e| format!("{:?}", e))?;
}
SocketAddr::V6(socket) => {
self.discv5
.enr_insert("ip6", &socket.ip().octets())
.map_err(|e| format!("{:?}", e))?;
self.discv5
.enr_insert("udp6", &socket.port().to_be_bytes())
.map_err(|e| format!("{:?}", e))?;
}
const IS_TCP: bool = false;
if self.discv5.update_local_enr_socket(socket_addr, IS_TCP) {
// persist modified enr to disk
enr::save_enr_to_disk(Path::new(&self.enr_dir), &self.local_enr(), &self.log);
}
// replace the global version
*self.network_globals.local_enr.write() = self.discv5.local_enr();
// persist modified enr to disk
enr::save_enr_to_disk(Path::new(&self.enr_dir), &self.local_enr(), &self.log);
Ok(())
}