feat(discv5): plug discv5 crate into network (#7446)

This commit is contained in:
Emilia Hane
2024-04-04 14:18:53 +02:00
committed by GitHub
parent 4a8d2f4abc
commit 633806ef3f
9 changed files with 265 additions and 94 deletions

View File

@ -1,7 +1,8 @@
//! Interface between node identification on protocol version 5 and 4. Specifically, between types
//! [`discv5::enr::NodeId`] and [`PeerId`].
use discv5::enr::{CombinedPublicKey, Enr, EnrPublicKey, NodeId};
use discv5::enr::{CombinedPublicKey, EnrPublicKey, NodeId};
use enr::Enr;
use reth_primitives::{id2pk, pk2id, PeerId};
use secp256k1::{PublicKey, SecretKey};

View File

@ -7,13 +7,13 @@ use discv5::IpMode;
pub enum Error {
/// Failure adding node to [`discv5::Discv5`].
#[error("failed adding node to discv5, {0}")]
AddNodeToDiscv5Failed(&'static str),
AddNodeFailed(&'static str),
/// Node record has incompatible key type.
#[error("incompatible key type (not secp256k1)")]
IncompatibleKeyType,
/// Missing key used to identify rlpx network.
#[error("fork missing on enr, 'eth' key missing")]
ForkMissing,
#[error("fork missing on enr, key missing")]
ForkMissing(&'static [u8]),
/// Failed to decode [`ForkId`](reth_primitives::ForkId) rlp value.
#[error("failed to decode fork id, 'eth': {0:?}")]
ForkIdDecodeError(#[from] alloy_rlp::Error),
@ -30,9 +30,6 @@ pub enum Error {
#[error("init failed, {0}")]
InitFailure(&'static str),
/// An error from underlying [`discv5::Discv5`] node.
#[error("{0}")]
#[error("sigp/discv5 error, {0}")]
Discv5Error(discv5::Error),
/// An error from underlying [`discv5::Discv5`] node.
#[error("{0}")]
Discv5ErrorStr(&'static str),
}

View File

@ -18,7 +18,6 @@ use std::{
use ::enr::Enr;
use alloy_rlp::Decodable;
use derive_more::Deref;
use discv5::ListenConfig;
use enr::{discv4_id_to_discv5_id, EnrCombinedKeyWrapper};
use futures::future::join_all;
@ -46,9 +45,8 @@ use metrics::Discv5Metrics;
const MAX_LOG2_DISTANCE: usize = 255;
/// Transparent wrapper around [`discv5::Discv5`].
#[derive(Deref, Clone)]
#[derive(Clone)]
pub struct Discv5 {
#[deref]
/// sigp/discv5 node.
discv5: Arc<discv5::Discv5>,
/// [`IpMode`] of the the node.
@ -67,9 +65,9 @@ impl Discv5 {
////////////////////////////////////////////////////////////////////////////////////////////////
/// Adds the node to the table, if it is not already present.
pub fn add_node_to_routing_table(&self, node_record: Enr<SecretKey>) -> Result<(), Error> {
pub fn add_node(&self, node_record: Enr<SecretKey>) -> Result<(), Error> {
let EnrCombinedKeyWrapper(enr) = node_record.into();
self.add_enr(enr).map_err(Error::AddNodeToDiscv5Failed)
self.discv5.add_enr(enr).map_err(Error::AddNodeFailed)
}
/// Sets the pair in the EIP-868 [`Enr`] of the node.
@ -85,7 +83,7 @@ impl Discv5 {
);
return
};
if let Err(err) = self.enr_insert(key_str, &rlp) {
if let Err(err) = self.discv5.enr_insert(key_str, &rlp) {
error!(target: "discv5",
%err,
"failed to update local enr"
@ -109,11 +107,11 @@ impl Discv5 {
/// Adds the peer and id to the ban list.
///
/// This will prevent any future inclusion in the table
pub fn ban_peer_by_ip_and_node_id(&self, peer_id: PeerId, ip: IpAddr) {
pub fn ban(&self, peer_id: PeerId, ip: IpAddr) {
match discv4_id_to_discv5_id(peer_id) {
Ok(node_id) => {
self.ban_node(&node_id, None);
self.ban_peer_by_ip(ip);
self.discv5.ban_node(&node_id, None);
self.ban_ip(ip);
}
Err(err) => error!(target: "discv5",
%err,
@ -125,15 +123,15 @@ impl Discv5 {
/// Adds the ip to the ban list.
///
/// This will prevent any future inclusion in the table
pub fn ban_peer_by_ip(&self, ip: IpAddr) {
self.ban_ip(ip, None);
pub fn ban_ip(&self, ip: IpAddr) {
self.discv5.ban_ip(ip, None);
}
/// Returns the [`NodeRecord`] of the local node.
///
/// This includes the currently tracked external IP address of the node.
pub fn node_record(&self) -> NodeRecord {
let enr: Enr<_> = EnrCombinedKeyWrapper(self.local_enr()).into();
let enr: Enr<_> = EnrCombinedKeyWrapper(self.discv5.local_enr()).into();
(&enr).try_into().unwrap()
}
@ -238,7 +236,7 @@ impl Discv5 {
//
// 4. add boot nodes
//
Self::bootstrap(bootstrap_nodes, &discv5)?;
Self::bootstrap(bootstrap_nodes, &discv5).await?;
let metrics = Discv5Metrics::default();
@ -255,7 +253,7 @@ impl Discv5 {
}
/// Bootstraps underlying [`discv5::Discv5`] node with configured peers.
fn bootstrap(
async fn bootstrap(
bootstrap_nodes: HashSet<BootNode>,
discv5: &Arc<discv5::Discv5>,
) -> Result<(), Error> {
@ -269,7 +267,7 @@ impl Discv5 {
match node {
BootNode::Enr(node) => {
if let Err(err) = discv5.add_enr(node) {
return Err(Error::Discv5ErrorStr(err))
return Err(Error::AddNodeFailed(err))
}
}
BootNode::Enode(enode) => {
@ -286,18 +284,8 @@ impl Discv5 {
}
}
}
_ = join_all(enr_requests);
debug!(target: "net::discv5",
nodes=format!("[{:#}]", discv5.with_kbuckets(|kbuckets| kbuckets
.write()
.iter()
.map(|peer| format!("enr: {:?}, status: {:?}", peer.node.value, peer.status)).collect::<Vec<_>>()
).into_iter().format(", ")),
"added boot nodes"
);
Ok(())
Ok(_ = join_all(enr_requests).await)
}
/// Backgrounds regular look up queries, in order to keep kbuckets populated.
@ -479,7 +467,8 @@ impl Discv5 {
&self,
enr: &discv5::enr::Enr<K>,
) -> Result<ForkId, Error> {
let mut fork_id_bytes = enr.get_raw_rlp(self.fork_id_key()).ok_or(Error::ForkMissing)?;
let key = self.fork_id_key;
let mut fork_id_bytes = enr.get_raw_rlp(key).ok_or(Error::ForkMissing(key))?;
Ok(ForkId::decode(&mut fork_id_bytes)?)
}
@ -491,9 +480,9 @@ impl Discv5 {
/// Exposes API of [`discv5::Discv5`].
pub fn with_discv5<F, R>(&self, f: F) -> R
where
F: FnOnce(&Self) -> R,
F: FnOnce(&discv5::Discv5) -> R,
{
f(self)
f(&self.discv5)
}
////////////////////////////////////////////////////////////////////////////////////////////////
@ -617,7 +606,7 @@ mod tests {
// add node_2 to discovery handle of node_1 (should add node to discv5 kbuckets)
let node_2_enr_reth_compatible_ty: Enr<SecretKey> =
EnrCombinedKeyWrapper(node_2_enr.clone()).into();
node_1.add_node_to_routing_table(node_2_enr_reth_compatible_ty).unwrap();
node_1.add_node(node_2_enr_reth_compatible_ty).unwrap();
// verify node_2 is in KBuckets of node_1:discv5
assert!(
@ -630,21 +619,21 @@ mod tests {
// verify node_1:discv5 is connected to node_2:discv5 and vv
let event_2_v5 = stream_2.recv().await.unwrap();
let event_1_v5 = stream_1.recv().await.unwrap();
matches!(
assert!(matches!(
event_1_v5,
discv5::Event::SessionEstablished(node, socket) if node == node_2_enr && socket == node_2_enr.udp4_socket().unwrap().into()
);
matches!(
));
assert!(matches!(
event_2_v5,
discv5::Event::SessionEstablished(node, socket) if node == node_1_enr && socket == node_1_enr.udp4_socket().unwrap().into()
);
));
// verify node_1 is in KBuckets of node_2:discv5
let event_2_v5 = stream_2.recv().await.unwrap();
matches!(
assert!(matches!(
event_2_v5,
discv5::Event::NodeInserted { node_id, replaced } if node_id == node_1_enr.node_id() && replaced.is_none()
);
));
}
#[test]