mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
fix(op): discv5 ENR (#7991)
This commit is contained in:
@ -9,9 +9,9 @@ use std::{
|
||||
use derive_more::Display;
|
||||
use discv5::ListenConfig;
|
||||
use multiaddr::{Multiaddr, Protocol};
|
||||
use reth_primitives::{Bytes, EnrForkIdEntry, ForkId, NodeRecord, MAINNET};
|
||||
use reth_primitives::{Bytes, EnrForkIdEntry, ForkId, NodeRecord};
|
||||
|
||||
use crate::{enr::discv4_id_to_multiaddr_id, filter::MustNotIncludeKeys, network_key};
|
||||
use crate::{enr::discv4_id_to_multiaddr_id, filter::MustNotIncludeKeys, NetworkStackId};
|
||||
|
||||
/// Default interval in seconds at which to run a lookup up query.
|
||||
///
|
||||
@ -50,7 +50,7 @@ impl ConfigBuilder {
|
||||
let Config {
|
||||
discv5_config,
|
||||
bootstrap_nodes,
|
||||
fork: (network_key, fork_id),
|
||||
fork,
|
||||
tcp_port,
|
||||
other_enr_kv_pairs,
|
||||
lookup_interval,
|
||||
@ -60,7 +60,7 @@ impl ConfigBuilder {
|
||||
Self {
|
||||
discv5_config: Some(discv5_config),
|
||||
bootstrap_nodes,
|
||||
fork: Some((network_key, fork_id.fork_id)),
|
||||
fork: fork.map(|(key, fork_id)| (key, fork_id.fork_id)),
|
||||
tcp_port,
|
||||
other_enr_kv_pairs,
|
||||
lookup_interval: Some(lookup_interval),
|
||||
@ -117,8 +117,8 @@ impl ConfigBuilder {
|
||||
|
||||
/// Set fork ID kv-pair to set in local [`Enr`](discv5::enr::Enr). This lets peers on discovery
|
||||
/// network know which chain this node belongs to.
|
||||
pub fn fork(mut self, network_key: &'static [u8], fork_id: ForkId) -> Self {
|
||||
self.fork = Some((network_key, fork_id));
|
||||
pub fn fork(mut self, fork_key: &'static [u8], fork_id: ForkId) -> Self {
|
||||
self.fork = Some((fork_key, fork_id));
|
||||
self
|
||||
}
|
||||
|
||||
@ -160,13 +160,12 @@ impl ConfigBuilder {
|
||||
let discv5_config = discv5_config
|
||||
.unwrap_or_else(|| discv5::ConfigBuilder::new(ListenConfig::default()).build());
|
||||
|
||||
let (network_key, fork_id) = fork.unwrap_or((network_key::ETH, MAINNET.latest_fork_id()));
|
||||
let fork = (network_key, fork_id.into());
|
||||
let fork = fork.map(|(key, fork_id)| (key, fork_id.into()));
|
||||
|
||||
let lookup_interval = lookup_interval.unwrap_or(DEFAULT_SECONDS_LOOKUP_INTERVAL);
|
||||
|
||||
let discovered_peer_filter =
|
||||
discovered_peer_filter.unwrap_or_else(|| MustNotIncludeKeys::new(&[network_key::ETH2]));
|
||||
let discovered_peer_filter = discovered_peer_filter
|
||||
.unwrap_or_else(|| MustNotIncludeKeys::new(&[NetworkStackId::ETH2]));
|
||||
|
||||
Config {
|
||||
discv5_config,
|
||||
@ -190,7 +189,7 @@ pub struct Config {
|
||||
pub(super) bootstrap_nodes: HashSet<BootNode>,
|
||||
/// Fork kv-pair to set in local node record. Identifies which network/chain/fork the node
|
||||
/// belongs, e.g. `(b"opstack", ChainId)` or `(b"eth", [ForkId])`.
|
||||
pub(super) fork: (&'static [u8], EnrForkIdEntry),
|
||||
pub(super) fork: Option<(&'static [u8], EnrForkIdEntry)>,
|
||||
/// RLPx TCP port to advertise.
|
||||
pub(super) tcp_port: u16,
|
||||
/// Additional kv-pairs (besides tcp port, udp port and fork) that should be advertised to
|
||||
|
||||
@ -11,6 +11,9 @@ pub enum Error {
|
||||
/// Node record has incompatible key type.
|
||||
#[error("incompatible key type (not secp256k1)")]
|
||||
IncompatibleKeyType,
|
||||
/// No key used to identify rlpx network is configured.
|
||||
#[error("network stack identifier is not configured")]
|
||||
NetworkStackIdNotConfigured,
|
||||
/// Missing key used to identify rlpx network.
|
||||
#[error("fork missing on enr, key missing")]
|
||||
ForkMissing(&'static [u8]),
|
||||
|
||||
@ -96,7 +96,7 @@ mod tests {
|
||||
use alloy_rlp::Bytes;
|
||||
use discv5::enr::{CombinedKey, Enr};
|
||||
|
||||
use crate::network_key::{ETH, ETH2};
|
||||
use crate::NetworkStackId;
|
||||
|
||||
use super::*;
|
||||
|
||||
@ -104,16 +104,21 @@ mod tests {
|
||||
fn must_not_include_key_filter() {
|
||||
// rig test
|
||||
|
||||
let filter = MustNotIncludeKeys::new(&[ETH, ETH2]);
|
||||
let filter = MustNotIncludeKeys::new(&[NetworkStackId::ETH, NetworkStackId::ETH2]);
|
||||
|
||||
// enr_1 advertises a fork from one of the keys configured in filter
|
||||
let sk = CombinedKey::generate_secp256k1();
|
||||
let enr_1 =
|
||||
Enr::builder().add_value_rlp(ETH as &[u8], Bytes::from("cancun")).build(&sk).unwrap();
|
||||
let enr_1 = Enr::builder()
|
||||
.add_value_rlp(NetworkStackId::ETH as &[u8], Bytes::from("cancun"))
|
||||
.build(&sk)
|
||||
.unwrap();
|
||||
|
||||
// enr_2 advertises a fork from one the other key configured in filter
|
||||
let sk = CombinedKey::generate_secp256k1();
|
||||
let enr_2 = Enr::builder().add_value_rlp(ETH2, Bytes::from("deneb")).build(&sk).unwrap();
|
||||
let enr_2 = Enr::builder()
|
||||
.add_value_rlp(NetworkStackId::ETH2, Bytes::from("deneb"))
|
||||
.build(&sk)
|
||||
.unwrap();
|
||||
|
||||
// test
|
||||
|
||||
|
||||
@ -33,7 +33,7 @@ pub mod enr;
|
||||
pub mod error;
|
||||
pub mod filter;
|
||||
pub mod metrics;
|
||||
pub mod network_key;
|
||||
pub mod network_stack_id;
|
||||
|
||||
pub use discv5::{self, IpMode};
|
||||
|
||||
@ -41,6 +41,7 @@ pub use config::{BootNode, Config, ConfigBuilder};
|
||||
pub use enr::enr_to_discv4_id;
|
||||
pub use error::Error;
|
||||
pub use filter::{FilterOutcome, MustNotIncludeKeys};
|
||||
pub use network_stack_id::NetworkStackId;
|
||||
|
||||
use metrics::{DiscoveredPeersMetrics, Discv5Metrics};
|
||||
|
||||
@ -75,7 +76,7 @@ pub struct Discv5 {
|
||||
/// [`IpMode`] of the the node.
|
||||
ip_mode: IpMode,
|
||||
/// Key used in kv-pair to ID chain, e.g. 'opstack' or 'eth'.
|
||||
fork_key: &'static [u8],
|
||||
fork_key: Option<&'static [u8]>,
|
||||
/// Filter applied to a discovered peers before passing it up to app.
|
||||
discovered_peer_filter: MustNotIncludeKeys,
|
||||
/// Metrics for underlying [`discv5::Discv5`] node and filtered discovered peers.
|
||||
@ -217,7 +218,7 @@ impl Discv5 {
|
||||
fn build_local_enr(
|
||||
sk: &SecretKey,
|
||||
config: &Config,
|
||||
) -> (Enr<SecretKey>, NodeRecord, &'static [u8], IpMode) {
|
||||
) -> (Enr<SecretKey>, NodeRecord, Option<&'static [u8]>, IpMode) {
|
||||
let mut builder = discv5::enr::Enr::builder();
|
||||
|
||||
let Config { discv5_config, fork, tcp_port, other_enr_kv_pairs, .. } = config;
|
||||
@ -258,8 +259,10 @@ impl Discv5 {
|
||||
};
|
||||
|
||||
// identifies which network node is on
|
||||
let (network, fork_value) = fork;
|
||||
builder.add_value_rlp(network, alloy_rlp::encode(fork_value).into());
|
||||
let network_stack_id = fork.as_ref().map(|(network_stack_id, fork_value)| {
|
||||
builder.add_value_rlp(network_stack_id, alloy_rlp::encode(fork_value).into());
|
||||
*network_stack_id
|
||||
});
|
||||
|
||||
// add other data
|
||||
for (key, value) in other_enr_kv_pairs {
|
||||
@ -273,7 +276,7 @@ impl Discv5 {
|
||||
// backwards compatible enr
|
||||
let bc_enr = NodeRecord::from_secret_key(socket, sk);
|
||||
|
||||
(enr, bc_enr, network, ip_mode)
|
||||
(enr, bc_enr, network_stack_id, ip_mode)
|
||||
}
|
||||
|
||||
/// Bootstraps underlying [`discv5::Discv5`] node with configured peers.
|
||||
@ -438,8 +441,10 @@ impl Discv5 {
|
||||
return None
|
||||
}
|
||||
|
||||
let fork_id =
|
||||
(self.fork_key == network_key::ETH).then(|| self.get_fork_id(enr).ok()).flatten();
|
||||
// todo: extend for all network stacks in reth-network rlpx logic
|
||||
let fork_id = (self.fork_key == Some(NetworkStackId::ETH))
|
||||
.then(|| self.get_fork_id(enr).ok())
|
||||
.flatten();
|
||||
|
||||
trace!(target: "net::discovery::discv5",
|
||||
?fork_id,
|
||||
@ -483,12 +488,13 @@ impl Discv5 {
|
||||
self.discovered_peer_filter.filter(enr)
|
||||
}
|
||||
|
||||
/// Returns the [`ForkId`] of the given [`Enr`](discv5::Enr), if field is set.
|
||||
/// Returns the [`ForkId`] of the given [`Enr`](discv5::Enr) w.r.t. the local node's network
|
||||
/// stack, if field is set.
|
||||
fn get_fork_id<K: discv5::enr::EnrKey>(
|
||||
&self,
|
||||
enr: &discv5::enr::Enr<K>,
|
||||
) -> Result<ForkId, Error> {
|
||||
let key = self.fork_key;
|
||||
let Some(key) = self.fork_key else { return Err(Error::NetworkStackIdNotConfigured) };
|
||||
let fork_id = enr
|
||||
.get_decodable::<EnrForkIdEntry>(key)
|
||||
.ok_or(Error::ForkMissing(key))?
|
||||
@ -519,7 +525,7 @@ impl Discv5 {
|
||||
}
|
||||
|
||||
/// Returns the key to use to identify the [`ForkId`] kv-pair on the [`Enr`](discv5::Enr).
|
||||
pub fn fork_key(&self) -> &[u8] {
|
||||
pub fn fork_key(&self) -> Option<&[u8]> {
|
||||
self.fork_key
|
||||
}
|
||||
}
|
||||
@ -625,7 +631,7 @@ mod tests {
|
||||
.unwrap(),
|
||||
),
|
||||
ip_mode: IpMode::Ip4,
|
||||
fork_key: b"noop",
|
||||
fork_key: None,
|
||||
discovered_peer_filter: MustNotIncludeKeys::default(),
|
||||
metrics: Discv5Metrics::default(),
|
||||
}
|
||||
@ -831,13 +837,16 @@ mod tests {
|
||||
const TCP_PORT: u16 = 30303;
|
||||
let fork_id = MAINNET.latest_fork_id();
|
||||
|
||||
let config = Config::builder(TCP_PORT).fork(network_key::ETH, fork_id).build();
|
||||
let config = Config::builder(TCP_PORT).fork(NetworkStackId::ETH, fork_id).build();
|
||||
|
||||
let sk = SecretKey::new(&mut thread_rng());
|
||||
let (enr, _, _, _) = Discv5::build_local_enr(&sk, &config);
|
||||
|
||||
let decoded_fork_id =
|
||||
enr.get_decodable::<EnrForkIdEntry>(network_key::ETH).unwrap().map(Into::into).unwrap();
|
||||
let decoded_fork_id = enr
|
||||
.get_decodable::<EnrForkIdEntry>(NetworkStackId::ETH)
|
||||
.unwrap()
|
||||
.map(Into::into)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(fork_id, decoded_fork_id);
|
||||
assert_eq!(TCP_PORT, enr.tcp4().unwrap()); // listen config is defaulting to ip mode ipv4
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
use metrics::{Counter, Gauge};
|
||||
use reth_metrics::Metrics;
|
||||
|
||||
use crate::network_key::{ETH, ETH2, OPSTACK};
|
||||
use crate::NetworkStackId;
|
||||
|
||||
/// Information tracked by [`Discv5`](crate::Discv5).
|
||||
#[derive(Debug, Default, Clone)]
|
||||
@ -91,27 +91,34 @@ impl DiscoveredPeersMetrics {
|
||||
#[derive(Metrics, Clone)]
|
||||
#[metrics(scope = "discv5")]
|
||||
pub struct AdvertisedChainMetrics {
|
||||
/// Frequency of node records with a kv-pair with [`OPSTACK`](crate::network_key) as
|
||||
/// Frequency of node records with a kv-pair with [`OPEL`](NetworkStackId::OPEL) as
|
||||
/// key.
|
||||
opel: Counter,
|
||||
|
||||
/// Frequency of node records with a kv-pair with [`OPSTACK`](NetworkStackId::OPSTACK) as
|
||||
/// key.
|
||||
opstack: Counter,
|
||||
|
||||
/// Frequency of node records with a kv-pair with [`ETH`](crate::network_key) as key.
|
||||
/// Frequency of node records with a kv-pair with [`ETH`](NetworkStackId::ETH) as key.
|
||||
eth: Counter,
|
||||
|
||||
/// Frequency of node records with a kv-pair with [`ETH2`](crate::network_key) as key.
|
||||
/// Frequency of node records with a kv-pair with [`ETH2`](NetworkStackId::ETH2) as key.
|
||||
eth2: Counter,
|
||||
}
|
||||
|
||||
impl AdvertisedChainMetrics {
|
||||
/// Counts each recognised network type that is advertised on node record, once.
|
||||
/// Counts each recognised network stack type that is advertised on node record, once.
|
||||
pub fn increment_once_by_network_type(&self, enr: &discv5::Enr) {
|
||||
if enr.get_raw_rlp(OPSTACK).is_some() {
|
||||
if enr.get_raw_rlp(NetworkStackId::OPEL).is_some() {
|
||||
self.opel.increment(1u64)
|
||||
}
|
||||
if enr.get_raw_rlp(NetworkStackId::OPSTACK).is_some() {
|
||||
self.opstack.increment(1u64)
|
||||
}
|
||||
if enr.get_raw_rlp(ETH).is_some() {
|
||||
if enr.get_raw_rlp(NetworkStackId::ETH).is_some() {
|
||||
self.eth.increment(1u64)
|
||||
}
|
||||
if enr.get_raw_rlp(ETH2).is_some() {
|
||||
if enr.get_raw_rlp(NetworkStackId::ETH2).is_some() {
|
||||
self.eth2.increment(1u64)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
//! Keys of ENR [`ForkId`](reth_primitives::ForkId) kv-pair. Identifies which network a node
|
||||
//! belongs to.
|
||||
|
||||
/// ENR fork ID kv-pair key, for an Ethereum L1 EL node.
|
||||
pub const ETH: &[u8] = b"eth";
|
||||
|
||||
/// ENR fork ID kv-pair key, for an Ethereum L1 CL node.
|
||||
pub const ETH2: &[u8] = b"eth2";
|
||||
|
||||
/// ENR fork ID kv-pair key, for an Optimism CL node.
|
||||
pub const OPSTACK: &[u8] = b"opstack";
|
||||
33
crates/net/discv5/src/network_stack_id.rs
Normal file
33
crates/net/discv5/src/network_stack_id.rs
Normal file
@ -0,0 +1,33 @@
|
||||
//! Keys of ENR [`ForkId`](reth_primitives::ForkId) kv-pair. Identifies which network stack a node
|
||||
//! belongs to.
|
||||
|
||||
use reth_primitives::ChainSpec;
|
||||
|
||||
/// Identifies which Ethereum network stack a node belongs to, on the discovery network.
|
||||
#[derive(Debug)]
|
||||
pub struct NetworkStackId;
|
||||
|
||||
impl NetworkStackId {
|
||||
/// ENR fork ID kv-pair key, for an Ethereum L1 EL node.
|
||||
pub const ETH: &'static [u8] = b"eth";
|
||||
|
||||
/// ENR fork ID kv-pair key, for an Ethereum L1 CL node.
|
||||
pub const ETH2: &'static [u8] = b"eth2";
|
||||
|
||||
/// ENR fork ID kv-pair key, for an Optimism EL node.
|
||||
pub const OPEL: &'static [u8] = b"opel";
|
||||
|
||||
/// ENR fork ID kv-pair key, for an Optimism CL node.
|
||||
pub const OPSTACK: &'static [u8] = b"opstack";
|
||||
|
||||
/// Returns the [`NetworkStackId`] that matches the given [`ChainSpec`].
|
||||
pub fn id(chain: &ChainSpec) -> Option<&'static [u8]> {
|
||||
if chain.is_optimism() {
|
||||
return Some(Self::OPEL)
|
||||
} else if chain.is_eth() {
|
||||
return Some(Self::ETH)
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user