-
Notifications
You must be signed in to change notification settings - Fork 857
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* port kad * feat: port kad bucket * feat: add discv4 * chore: rustfmt * cargo update * just reuse discv5 table * test: add rlp tests * message encoding * feat: impl codec roundtrip testing * more work in message handling * implement ping * feat: impl commands * cleanup * more cleanup * trim config * more docs * feat: implement recursive lookup * docs * cleanup config * feat: implement update stream * chore: config cleanup * docs: add crate docs * feat: more testing * fix deny * clarify ring * docs: more docs * use discv5 master * docs: address review and add comments * update readme * rustmft * chore(clippy): make clippy happy
- Loading branch information
Showing
11 changed files
with
3,231 additions
and
62 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
[package] | ||
name = "reth-discv4" | ||
version = "0.1.0" | ||
edition = "2021" | ||
license = "Apache-2.0" | ||
repository = "https://github.com/foundry-rs/reth" | ||
readme = "README.md" | ||
description = """ | ||
Ethereum network support | ||
""" | ||
|
||
[dependencies] | ||
# reth | ||
reth-primitives = { path = "../../primitives" } | ||
reth-rlp = { path = "../../common/rlp" } | ||
reth-rlp-derive = { path = "../../common/rlp-derive" } | ||
|
||
# ethereum | ||
discv5 = { git = "https://github.com/sigp/discv5" } | ||
secp256k1 = { version = "0.24", features = [ | ||
"global-context", | ||
"rand-std", | ||
"recovery", | ||
] } | ||
|
||
# async/futures | ||
tokio = { version = "1", features = ["io-util", "net", "time"] } | ||
tokio-stream = "0.1" | ||
|
||
# misc | ||
generic-array = "0.14" | ||
tracing = "0.1" | ||
bytes = "1.2" | ||
thiserror = "1.0" | ||
url = "2.3" | ||
hex = "0.4" | ||
public-ip = "0.2" | ||
|
||
[dev-dependencies] | ||
rand = "0.8" | ||
tokio = { version = "1", features = ["full"] } | ||
tracing-test = "0.2" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# <h1 align="center"> discv4 </h1> | ||
|
||
This is a rust implementation of | ||
the [Discovery v4](https://github.com/ethereum/devp2p/blob/40ab248bf7e017e83cc9812a4e048446709623e8/discv4.md) | ||
peer discovery protocol. | ||
|
||
For comparison to Discovery v5, | ||
see [discv5#comparison-with-node-discovery-v4](https://github.com/ethereum/devp2p/blob/40ab248bf7e017e83cc9812a4e048446709623e8/discv5/discv5.md#comparison-with-node-discovery-v4) | ||
|
||
This is inspired by the [discv5](https://github.com/sigp/discv5) crate and reuses its kademlia implementation. | ||
|
||
## Finding peers | ||
|
||
The discovery service continuously attempts to connect to other nodes on the network until it has found enough peers. | ||
If UPnP (Universal Plug and Play) is supported by the router the service is running on, it will also accept connections | ||
from external nodes. In the discovery protocol, nodes exchange information about where the node can be reached to | ||
eventually establish RLPx sessions. | ||
|
||
## Trouble Shooting | ||
|
||
The discv4 protocol depends on the local system clock. If the clock is not accurate it can cause connectivity issues | ||
because the expiration timestamps might be wrong. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
//! Various known bootstrap nodes for networks | ||
|
||
// <https://github.com/ledgerwatch/erigon/blob/610e648dc43ec8cd6563313e28f06f534a9091b3/params/bootnodes.go> | ||
|
||
use crate::node::NodeRecord; | ||
|
||
/// Ethereum Foundation Go Bootnodes | ||
pub static MAINNET_BOOTNODES : [&str; 8] = [ | ||
"enode://d860a01f9722d78051619d1e2351aba3f43f943f6f00718d1b9baa4101932a1f5011f16bb2b1bb35db20d6fe28fa0bf09636d26a87d31de9ec6203eeedb1f666@18.138.108.67:30303", // bootnode-aws-ap-southeast-1-001 | ||
"enode://22a8232c3abc76a16ae9d6c3b164f98775fe226f0917b0ca871128a74a8e9630b458460865bab457221f1d448dd9791d24c4e5d88786180ac185df813a68d4de@3.209.45.79:30303", // bootnode-aws-us-east-1-001 | ||
"enode://8499da03c47d637b20eee24eec3c356c9a2e6148d6fe25ca195c7949ab8ec2c03e3556126b0d7ed644675e78c4318b08691b7b57de10e5f0d40d05b09238fa0a@52.187.207.27:30303", // bootnode-azure-australiaeast-001 | ||
"enode://103858bdb88756c71f15e9b5e09b56dc1be52f0a5021d46301dbbfb7e130029cc9d0d6f73f693bc29b665770fff7da4d34f3c6379fe12721b5d7a0bcb5ca1fc1@191.234.162.198:30303", // bootnode-azure-brazilsouth-001 | ||
"enode://715171f50508aba88aecd1250af392a45a330af91d7b90701c436b618c86aaa1589c9184561907bebbb56439b8f8787bc01f49a7c77276c58c1b09822d75e8e8@52.231.165.108:30303", // bootnode-azure-koreasouth-001 | ||
"enode://5d6d7cd20d6da4bb83a1d28cadb5d409b64edf314c0335df658c1a54e32c7c4a7ab7823d57c39b6a757556e68ff1df17c748b698544a55cb488b52479a92b60f@104.42.217.25:30303", // bootnode-azure-westus-001 | ||
"enode://2b252ab6a1d0f971d9722cb839a42cb81db019ba44c08754628ab4a823487071b5695317c8ccd085219c3a03af063495b2f1da8d18218da2d6a82981b45e6ffc@65.108.70.101:30303", // bootnode-hetzner-hel | ||
"enode://4aeb4ab6c14b23e2c4cfdce879c04b0748a20d8e9b59e25ded2a08143e265c6c25936e74cbc8e641e3312ca288673d91f2f93f8e277de3cfa444ecdaaf982052@157.90.35.166:30303", // bootnode-hetzner-fsn | ||
]; | ||
|
||
/// SEPOLIA BOOTNODES | ||
pub static SEPOLIA_BOOTNODES : [&str; 2] = [ | ||
// geth | ||
"enode://9246d00bc8fd1742e5ad2428b80fc4dc45d786283e05ef6edbd9002cbc335d40998444732fbe921cb88e1d2c73d1b1de53bae6a2237996e9bfe14f871baf7066@18.168.182.86:30303", | ||
// besu | ||
"enode://ec66ddcf1a974950bd4c782789a7e04f8aa7110a72569b6e65fcd51e937e74eed303b1ea734e4d19cfaec9fbff9b6ee65bf31dcb50ba79acce9dd63a6aca61c7@52.14.151.177:30303", | ||
]; | ||
|
||
/// GOERLI bootnodes | ||
pub static GOERLI_BOOTNODES : [&str; 7] = [ | ||
// Upstream bootnodes | ||
"enode://011f758e6552d105183b1761c5e2dea0111bc20fd5f6422bc7f91e0fabbec9a6595caf6239b37feb773dddd3f87240d99d859431891e4a642cf2a0a9e6cbb98a@51.141.78.53:30303", | ||
"enode://176b9417f511d05b6b2cf3e34b756cf0a7096b3094572a8f6ef4cdcb9d1f9d00683bf0f83347eebdf3b81c3521c2332086d9592802230bf528eaf606a1d9677b@13.93.54.137:30303", | ||
"enode://46add44b9f13965f7b9875ac6b85f016f341012d84f975377573800a863526f4da19ae2c620ec73d11591fa9510e992ecc03ad0751f53cc02f7c7ed6d55c7291@94.237.54.114:30313", | ||
"enode://b5948a2d3e9d486c4d75bf32713221c2bd6cf86463302339299bd227dc2e276cd5a1c7ca4f43a0e9122fe9af884efed563bd2a1fd28661f3b5f5ad7bf1de5949@18.218.250.66:30303", | ||
|
||
// Ethereum Foundation bootnode | ||
"enode://a61215641fb8714a373c80edbfa0ea8878243193f57c96eeb44d0bc019ef295abd4e044fd619bfc4c59731a73fb79afe84e9ab6da0c743ceb479cbb6d263fa91@3.11.147.67:30303", | ||
|
||
// Goerli Initiative bootnodes | ||
"enode://d4f764a48ec2a8ecf883735776fdefe0a3949eb0ca476bd7bc8d0954a9defe8fea15ae5da7d40b5d2d59ce9524a99daedadf6da6283fca492cc80b53689fb3b3@46.4.99.122:32109", | ||
"enode://d2b720352e8216c9efc470091aa91ddafc53e222b32780f505c817ceef69e01d5b0b0797b69db254c586f493872352f5a022b4d8479a00fc92ec55f9ad46a27e@88.99.70.182:30303", | ||
]; | ||
|
||
/// Returns parsed mainnet nodes | ||
pub fn mainnet_nodes() -> Vec<NodeRecord> { | ||
parse_nodes(&MAINNET_BOOTNODES[..]) | ||
} | ||
|
||
/// Returns parsed goerli nodes | ||
pub fn goerli_nodes() -> Vec<NodeRecord> { | ||
parse_nodes(&GOERLI_BOOTNODES[..]) | ||
} | ||
|
||
/// Returns parsed sepolia nodes | ||
pub fn sepolia_nodes() -> Vec<NodeRecord> { | ||
parse_nodes(&SEPOLIA_BOOTNODES[..]) | ||
} | ||
|
||
/// Parses all the nodes | ||
pub fn parse_nodes(nodes: impl IntoIterator<Item = impl AsRef<str>>) -> Vec<NodeRecord> { | ||
nodes.into_iter().map(|s| s.as_ref().parse().unwrap()).collect() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
use crate::node::NodeRecord; | ||
use discv5::PermitBanList; | ||
///! A set of configuration parameters to tune the discovery protocol. | ||
// This basis of this file has been taken from the discv5 codebase: | ||
// https://github.com/sigp/discv5 | ||
use std::collections::HashSet; | ||
use std::time::Duration; | ||
|
||
/// Configuration parameters that define the performance of the discovery network. | ||
#[derive(Clone, Debug)] | ||
pub struct Discv4Config { | ||
/// Whether to enable the incoming packet filter. Default: false. | ||
pub enable_packet_filter: bool, | ||
/// The number of retries for each UDP request. Default: 1. | ||
pub request_retries: u8, | ||
/// The time between pings to ensure connectivity amongst connected nodes. Default: 300 | ||
/// seconds. | ||
pub ping_interval: Duration, | ||
/// The duration of we consider a ping timed out. | ||
pub ping_timeout: Duration, | ||
/// The rate at which lookups should be triggered. | ||
pub lookup_interval: Duration, | ||
/// The duration of we consider a FindNode request timed out. | ||
pub find_node_timeout: Duration, | ||
/// The duration we set for neighbours responses | ||
pub neighbours_timeout: Duration, | ||
/// A set of lists that permit or ban IP's or NodeIds from the server. See | ||
/// `crate::PermitBanList`. | ||
pub permit_ban_list: PermitBanList, | ||
/// Set the default duration for which nodes are banned for. This timeouts are checked every 5 | ||
/// minutes, so the precision will be to the nearest 5 minutes. If set to `None`, bans from | ||
/// the filter will last indefinitely. Default is 1 hour. | ||
pub ban_duration: Option<Duration>, | ||
/// Nodes to boot from. | ||
pub bootstrap_nodes: HashSet<NodeRecord>, | ||
} | ||
|
||
impl Discv4Config { | ||
/// Returns a new default builder instance | ||
pub fn builder() -> Discv4ConfigBuilder { | ||
Default::default() | ||
} | ||
} | ||
|
||
impl Default for Discv4Config { | ||
fn default() -> Self { | ||
Self { | ||
enable_packet_filter: false, | ||
request_retries: 1, | ||
ping_interval: Duration::from_secs(300), | ||
ping_timeout: Duration::from_secs(5), | ||
find_node_timeout: Duration::from_secs(2), | ||
neighbours_timeout: Duration::from_secs(30), | ||
lookup_interval: Duration::from_secs(20), | ||
permit_ban_list: PermitBanList::default(), | ||
ban_duration: Some(Duration::from_secs(3600)), // 1 hour | ||
bootstrap_nodes: Default::default(), | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug, Default)] | ||
pub struct Discv4ConfigBuilder { | ||
config: Discv4Config, | ||
} | ||
|
||
impl Discv4ConfigBuilder { | ||
/// Whether to enable the incoming packet filter. | ||
pub fn enable_packet_filter(&mut self) -> &mut Self { | ||
self.config.enable_packet_filter = true; | ||
self | ||
} | ||
|
||
/// The number of retries for each UDP request. | ||
pub fn request_retries(&mut self, retries: u8) -> &mut Self { | ||
self.config.request_retries = retries; | ||
self | ||
} | ||
|
||
/// The time between pings to ensure connectivity amongst connected nodes. | ||
pub fn ping_interval(&mut self, interval: Duration) -> &mut Self { | ||
self.config.ping_interval = interval; | ||
self | ||
} | ||
|
||
/// Sets the timeout for pings | ||
pub fn ping_timeout(&mut self, duration: Duration) -> &mut Self { | ||
self.config.ping_timeout = duration; | ||
self | ||
} | ||
|
||
/// A set of lists that permit or ban IP's or NodeIds from the server. See | ||
/// `crate::PermitBanList`. | ||
pub fn permit_ban_list(&mut self, list: PermitBanList) -> &mut Self { | ||
self.config.permit_ban_list = list; | ||
self | ||
} | ||
|
||
/// Sets the lookup interval duration. | ||
pub fn lookup_interval(&mut self, lookup_interval: Duration) -> &mut Self { | ||
self.config.lookup_interval = lookup_interval; | ||
self | ||
} | ||
|
||
/// Set the default duration for which nodes are banned for. This timeouts are checked every 5 | ||
/// minutes, so the precision will be to the nearest 5 minutes. If set to `None`, bans from | ||
/// the filter will last indefinitely. Default is 1 hour. | ||
pub fn ban_duration(&mut self, ban_duration: Option<Duration>) -> &mut Self { | ||
self.config.ban_duration = ban_duration; | ||
self | ||
} | ||
|
||
/// Adds a boot node | ||
pub fn add_boot_node(&mut self, node: NodeRecord) -> &mut Self { | ||
self.config.bootstrap_nodes.insert(node); | ||
self | ||
} | ||
|
||
/// Adds multiple boot nodes | ||
pub fn add_boot_nodes(&mut self, nodes: impl IntoIterator<Item = NodeRecord>) -> &mut Self { | ||
self.config.bootstrap_nodes.extend(nodes); | ||
self | ||
} | ||
|
||
pub fn build(&mut self) -> Discv4Config { | ||
self.config.clone() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
//! Error types that can occur in this crate. | ||
|
||
use tokio::sync::{mpsc::error::SendError, oneshot::error::RecvError}; | ||
|
||
/// Error thrown when decoding a UDP packet. | ||
#[derive(Debug, thiserror::Error)] | ||
#[allow(missing_docs)] | ||
pub enum DecodePacketError { | ||
#[error("Failed to rlp decode: {0:?}")] | ||
Rlp(#[from] reth_rlp::DecodeError), | ||
#[error("Received packet len too short.")] | ||
PacketTooShort, | ||
#[error("Hash of the header not equals to the hash of the data.")] | ||
HashMismatch, | ||
#[error("Message id {0} is not supported.")] | ||
UnknownMessage(u8), | ||
#[error("Failed to recover public key: {0:?}")] | ||
Secp256k1(#[from] secp256k1::Error), | ||
} | ||
|
||
/// High level errors that can occur when interacting with the discovery service | ||
#[derive(Debug, thiserror::Error)] | ||
pub enum Discv4Error { | ||
/// Failed to send a command over the channel | ||
#[error("Failed to send on a closed channel")] | ||
Send, | ||
/// Failed to receive a command response | ||
#[error(transparent)] | ||
Receive(#[from] RecvError), | ||
} | ||
|
||
impl<T> From<SendError<T>> for Discv4Error { | ||
fn from(_: SendError<T>) -> Self { | ||
Discv4Error::Send | ||
} | ||
} |
Oops, something went wrong.