Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(discv5): open dns for discv5 #7328

Merged
merged 18 commits into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 16 additions & 10 deletions crates/net/dns/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ impl<R: Resolver> DnsDiscoveryService<R> {
}

fn on_resolved_enr(&mut self, enr: Enr<SecretKey>) {
if let Some(record) = convert_enr_node_record(&enr) {
if let Some(record) = convert_enr_node_record(enr.clone()) {
self.notify(record);
}
self.queued_events.push_back(DnsDiscoveryEvent::Enr(enr))
Expand Down Expand Up @@ -372,6 +372,8 @@ pub struct DnsNodeRecordUpdate {
pub node_record: NodeRecord,
/// The forkid of the node, if present in the ENR
pub fork_id: Option<ForkId>,
/// Original [`Enr`].
pub enr: Enr<SecretKey>,
}

/// Commands sent from [DnsDiscoveryHandle] to [DnsDiscoveryService]
Expand All @@ -389,21 +391,25 @@ pub enum DnsDiscoveryEvent {
}

/// Converts an [Enr] into a [NodeRecord]
fn convert_enr_node_record(enr: &Enr<SecretKey>) -> Option<DnsNodeRecordUpdate> {
fn convert_enr_node_record(enr: Enr<SecretKey>) -> Option<DnsNodeRecordUpdate> {
use alloy_rlp::Decodable;

let node_record = NodeRecord {
address: enr.ip4().map(IpAddr::from).or_else(|| enr.ip6().map(IpAddr::from))?,
tcp_port: enr.tcp4().or_else(|| enr.tcp6())?,
udp_port: enr.udp4().or_else(|| enr.udp6())?,
id: PeerId::from_slice(&enr.public_key().serialize_uncompressed()[1..]),
}
.into_ipv4_mapped();
let node_record = match NodeRecord::try_from(&enr) {
Ok(node_record) => node_record,
Err(err) => {
trace!(target: "disc::dns",
%err,
"can't convert enr to node_record"
);

return None
}
};

let mut maybe_fork_id = enr.get(b"eth")?;
let fork_id = ForkId::decode(&mut maybe_fork_id).ok();

Some(DnsNodeRecordUpdate { node_record, fork_id })
Some(DnsNodeRecordUpdate { node_record, fork_id, enr })
}

#[cfg(test)]
Expand Down
5 changes: 3 additions & 2 deletions crates/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,9 @@ pub use header::{Header, HeaderValidationError, HeadersDirection, SealedHeader};
pub use integer_list::IntegerList;
pub use log::{logs_bloom, Log};
pub use net::{
goerli_nodes, holesky_nodes, mainnet_nodes, parse_nodes, sepolia_nodes, NodeRecord,
GOERLI_BOOTNODES, HOLESKY_BOOTNODES, MAINNET_BOOTNODES, SEPOLIA_BOOTNODES,
goerli_nodes, holesky_nodes, mainnet_nodes, parse_nodes, pk_to_id, sepolia_nodes, NodeRecord,
NodeRecordParseError, GOERLI_BOOTNODES, HOLESKY_BOOTNODES, MAINNET_BOOTNODES,
SEPOLIA_BOOTNODES,
};
pub use peer::{AnyNode, PeerId, WithPeerId};
pub use prune::{
Expand Down
42 changes: 40 additions & 2 deletions crates/primitives/src/net.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub use reth_rpc_types::NodeRecord;
pub use reth_rpc_types::{pk_to_id, NodeRecord, NodeRecordParseError};

// <https://github.com/ledgerwatch/erigon/blob/610e648dc43ec8cd6563313e28f06f534a9091b3/params/bootnodes.go>
emhane marked this conversation as resolved.
Show resolved Hide resolved

Expand Down Expand Up @@ -73,10 +73,15 @@ mod tests {
str::FromStr,
};

use crate::MAINNET;

use super::*;
use alloy_rlp::Decodable;
use alloy_rlp::{Decodable, Encodable};
use enr::Enr;
use rand::{thread_rng, Rng, RngCore};
use reth_ethereum_forks::Hardfork;
use reth_rpc_types::PeerId;
use secp256k1::SecretKey;

#[test]
fn test_mapped_ipv6() {
Expand Down Expand Up @@ -197,4 +202,37 @@ mod tests {
id: PeerId::from_str("6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0").unwrap(),
})
}

#[test]
fn conversion_to_node_record_from_enr() {
const IP: &str = "::";
const TCP_PORT: u16 = 30303;
const UDP_PORT: u16 = 9000;

let mut rng = thread_rng();
let key = SecretKey::new(&mut rng);

let mut buf = Vec::new();
let fork_id = MAINNET.hardfork_fork_id(Hardfork::Frontier);
fork_id.unwrap().encode(&mut buf);

let enr = Enr::builder()
.ip6(IP.parse().unwrap())
.udp6(UDP_PORT)
.tcp6(TCP_PORT)
.build(&key)
.unwrap();

let node_record = NodeRecord::try_from(&enr).unwrap();

assert_eq!(
NodeRecord {
address: IP.parse().unwrap(),
tcp_port: TCP_PORT,
udp_port: UDP_PORT,
id: pk_to_id(&enr.public_key())
},
node_record
)
}
}
1 change: 1 addition & 0 deletions crates/rpc/rpc-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ alloy-rpc-engine-types = { workspace = true, features = ["jsonrpsee-types"] }
ethereum_ssz_derive = { version = "0.5", optional = true }
ethereum_ssz = { version = "0.5", optional = true }
alloy-genesis.workspace = true
enr = { workspace = true, features = ["serde", "rust-secp256k1"] }

# misc
thiserror.workspace = true
Expand Down
34 changes: 31 additions & 3 deletions crates/rpc/rpc-types/src/net.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::PeerId;
use crate::{pk_to_id, PeerId};
use alloy_rlp::{RlpDecodable, RlpEncodable};
use enr::Enr;
use secp256k1::{SecretKey, SECP256K1};
use serde_with::{DeserializeFromStr, SerializeDisplay};
use std::{
Expand All @@ -9,6 +10,7 @@ use std::{
num::ParseIntError,
str::FromStr,
};
use thiserror::Error;
use url::{Host, Url};

/// Represents a ENR in discovery.
Expand Down Expand Up @@ -114,8 +116,8 @@ impl fmt::Display for NodeRecord {
}
}

/// Possible error types when parsing a `NodeRecord`
#[derive(Debug, thiserror::Error)]
/// Possible error types when parsing a [`NodeRecord`]
#[derive(Debug, Error)]
pub enum NodeRecordParseError {
/// Invalid url
#[error("Failed to parse url: {0}")]
Expand All @@ -126,6 +128,9 @@ pub enum NodeRecordParseError {
/// Invalid discport
#[error("Failed to discport query: {0}")]
Discport(ParseIntError),
/// Conversion from type [`Enr<SecretKey>`] failed.
#[error("failed to convert enr into node record")]
ConversionFromEnrFailed,
}
emhane marked this conversation as resolved.
Show resolved Hide resolved

impl FromStr for NodeRecord {
Expand Down Expand Up @@ -165,6 +170,29 @@ impl FromStr for NodeRecord {
}
}

impl TryFrom<&Enr<SecretKey>> for NodeRecord {
type Error = NodeRecordParseError;

fn try_from(enr: &Enr<SecretKey>) -> Result<Self, Self::Error> {
let Some(address) = enr.ip4().map(IpAddr::from).or_else(|| enr.ip6().map(IpAddr::from))
else {
return Err(NodeRecordParseError::ConversionFromEnrFailed)
};

let Some(tcp_port) = enr.tcp4().or_else(|| enr.tcp6()) else {
return Err(NodeRecordParseError::ConversionFromEnrFailed)
};

let Some(udp_port) = enr.udp4().or_else(|| enr.udp6()) else {
return Err(NodeRecordParseError::ConversionFromEnrFailed)
};

let id = pk_to_id(&enr.public_key());

Ok(NodeRecord { address, tcp_port, udp_port, id }.into_ipv4_mapped())
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
5 changes: 5 additions & 0 deletions crates/rpc/rpc-types/src/peer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@ use alloy_primitives::B512;

/// Alias for a peer identifier
pub type PeerId = B512;

/// Converts a [`secp256k1::PublicKey`] to a [`PeerId`].
pub fn pk_to_id(pk: &secp256k1::PublicKey) -> PeerId {
PeerId::from_slice(&pk.serialize_uncompressed()[1..])
}
Loading