diff --git a/Cargo.lock b/Cargo.lock index 5f2af5faf..fb64faa0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6652,6 +6652,7 @@ version = "1.0.3" dependencies = [ "confy", "humantime-serde", + "reth-network-peers", "reth-network-types", "reth-prune-types", "reth-stages-types", @@ -7551,6 +7552,7 @@ dependencies = [ "tokio-stream", "tokio-util", "tracing", + "url", ] [[package]] @@ -7656,7 +7658,6 @@ name = "reth-node-builder" version = "1.0.3" dependencies = [ "aquamarine", - "backon", "confy", "eyre", "fdlimit", diff --git a/crates/cli/commands/src/p2p.rs b/crates/cli/commands/src/p2p.rs index 0fdefac8b..c7c2c414d 100644 --- a/crates/cli/commands/src/p2p.rs +++ b/crates/cli/commands/src/p2p.rs @@ -77,7 +77,7 @@ impl Command { let mut config: Config = confy::load_path(&config_path).unwrap_or_default(); - config.peers.trusted_nodes.extend(self.network.resolve_trusted_peers().await?); + config.peers.trusted_nodes.extend(self.network.trusted_peers.clone()); if config.peers.trusted_nodes.is_empty() && self.network.trusted_only { eyre::bail!("No trusted nodes. Set trusted peer with `--trusted-peer ` or set `--trusted-only` to `false`") diff --git a/crates/cli/commands/src/stage/run.rs b/crates/cli/commands/src/stage/run.rs index 5a02ec417..6949d8aa5 100644 --- a/crates/cli/commands/src/stage/run.rs +++ b/crates/cli/commands/src/stage/run.rs @@ -140,7 +140,7 @@ impl Command { let mut config = config; config.peers.trusted_nodes_only = self.network.trusted_only; - config.peers.trusted_nodes.extend(self.network.resolve_trusted_peers().await?); + config.peers.trusted_nodes.extend(self.network.trusted_peers.clone()); let network_secret_path = self .network diff --git a/crates/config/Cargo.toml b/crates/config/Cargo.toml index 91dcfc772..7a81bcb4d 100644 --- a/crates/config/Cargo.toml +++ b/crates/config/Cargo.toml @@ -26,3 +26,4 @@ confy.workspace = true [dev-dependencies] tempfile.workspace = true toml.workspace = true +reth-network-peers.workspace = true diff --git a/crates/config/src/config.rs b/crates/config/src/config.rs index f0a530734..6c36dd43f 100644 --- a/crates/config/src/config.rs +++ b/crates/config/src/config.rs @@ -383,7 +383,8 @@ where #[cfg(test)] mod tests { use super::{Config, EXTENSION}; - use std::time::Duration; + use reth_network_peers::TrustedPeer; + use std::{str::FromStr, time::Duration}; fn with_tempdir(filename: &str, proc: fn(&std::path::Path)) { let temp_dir = tempfile::tempdir().unwrap(); @@ -751,4 +752,28 @@ connect_trusted_nodes_only = true let conf: Config = toml::from_str(trusted_nodes_only).unwrap(); assert!(conf.peers.trusted_nodes_only); } + + #[test] + fn test_can_support_dns_in_trusted_nodes() { + let reth_toml = r#" + [peers] + trusted_nodes = [ + "enode://0401e494dbd0c84c5c0f72adac5985d2f2525e08b68d448958aae218f5ac8198a80d1498e0ebec2ce38b1b18d6750f6e61a56b4614c5a6c6cf0981c39aed47dc@34.159.32.127:30303", + "enode://e9675164b5e17b9d9edf0cc2bd79e6b6f487200c74d1331c220abb5b8ee80c2eefbf18213989585e9d0960683e819542e11d4eefb5f2b4019e1e49f9fd8fff18@berav2-bootnode.staketab.org:30303" + ] + "#; + + let conf: Config = toml::from_str(reth_toml).unwrap(); + assert_eq!(conf.peers.trusted_nodes.len(), 2); + + let expected_enodes = vec![ + "enode://0401e494dbd0c84c5c0f72adac5985d2f2525e08b68d448958aae218f5ac8198a80d1498e0ebec2ce38b1b18d6750f6e61a56b4614c5a6c6cf0981c39aed47dc@34.159.32.127:30303", + "enode://e9675164b5e17b9d9edf0cc2bd79e6b6f487200c74d1331c220abb5b8ee80c2eefbf18213989585e9d0960683e819542e11d4eefb5f2b4019e1e49f9fd8fff18@berav2-bootnode.staketab.org:30303", + ]; + + for enode in expected_enodes { + let node = TrustedPeer::from_str(enode).unwrap(); + assert!(conf.peers.trusted_nodes.contains(&node)); + } + } } diff --git a/crates/net/network-types/src/peers/config.rs b/crates/net/network-types/src/peers/config.rs index 5143c4c6f..fcd363357 100644 --- a/crates/net/network-types/src/peers/config.rs +++ b/crates/net/network-types/src/peers/config.rs @@ -2,7 +2,7 @@ use crate::{BackoffKind, ReputationChangeWeights}; use reth_net_banlist::BanList; -use reth_network_peers::NodeRecord; +use reth_network_peers::{NodeRecord, TrustedPeer}; use std::{ collections::HashSet, io::{self, ErrorKind}, @@ -122,7 +122,7 @@ pub struct PeersConfig { #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))] pub refill_slots_interval: Duration, /// Trusted nodes to connect to or accept from - pub trusted_nodes: HashSet, + pub trusted_nodes: Vec, /// Connect to or accept from trusted nodes only? #[cfg_attr(feature = "serde", serde(alias = "connect_trusted_nodes_only"))] pub trusted_nodes_only: bool, @@ -221,7 +221,7 @@ impl PeersConfig { } /// Nodes to always connect to. - pub fn with_trusted_nodes(mut self, nodes: HashSet) -> Self { + pub fn with_trusted_nodes(mut self, nodes: Vec) -> Self { self.trusted_nodes = nodes; self } diff --git a/crates/net/network/Cargo.toml b/crates/net/network/Cargo.toml index 61b887f04..5955f6cfe 100644 --- a/crates/net/network/Cargo.toml +++ b/crates/net/network/Cargo.toml @@ -91,6 +91,7 @@ alloy-provider= { workspace = true, features = ["admin-api"] } # misc serial_test.workspace = true tempfile.workspace = true +url.workspace = true ## Benchmarks pprof = { workspace = true, features = ["criterion", "flamegraph"] } diff --git a/crates/net/network/src/peers.rs b/crates/net/network/src/peers.rs index 306e0c55b..9ce2c6b5e 100644 --- a/crates/net/network/src/peers.rs +++ b/crates/net/network/src/peers.rs @@ -34,7 +34,7 @@ use tokio::{ time::{Instant, Interval}, }; use tokio_stream::wrappers::UnboundedReceiverStream; -use tracing::trace; +use tracing::{trace, warn}; /// A communication channel to the [`PeersManager`] to apply manual changes to the peer set. #[derive(Clone, Debug)] @@ -155,11 +155,18 @@ impl PeersManager { let mut peers = HashMap::with_capacity(trusted_nodes.len() + basic_nodes.len()); let mut trusted_peer_ids = HashSet::with_capacity(trusted_nodes.len()); - for NodeRecord { address, tcp_port, udp_port, id } in trusted_nodes { - trusted_peer_ids.insert(id); - peers.entry(id).or_insert_with(|| { - Peer::trusted(PeerAddr::new_with_ports(address, tcp_port, Some(udp_port))) - }); + for trusted_peer in trusted_nodes { + match trusted_peer.resolve_blocking() { + Ok(NodeRecord { address, tcp_port, udp_port, id }) => { + trusted_peer_ids.insert(id); + peers.entry(id).or_insert_with(|| { + Peer::trusted(PeerAddr::new_with_ports(address, tcp_port, Some(udp_port))) + }); + } + Err(err) => { + warn!(target: "net::peers", ?err, "Failed to resolve trusted peer"); + } + } } for NodeRecord { address, tcp_port, udp_port, id } in basic_nodes { @@ -1328,14 +1335,13 @@ mod tests { session::PendingSessionHandshakeError, PeersConfig, }; - use reth_discv4::NodeRecord; use reth_eth_wire::{ errors::{EthHandshakeError, EthStreamError, P2PHandshakeError, P2PStreamError}, DisconnectReason, }; use reth_net_banlist::BanList; use reth_network_api::{Direction, ReputationChangeKind}; - use reth_network_peers::PeerId; + use reth_network_peers::{PeerId, TrustedPeer}; use reth_network_types::{peers::reputation::DEFAULT_REPUTATION, BackoffKind}; use reth_primitives::B512; use std::{ @@ -1347,6 +1353,7 @@ mod tests { task::{Context, Poll}, time::Duration, }; + use url::Host; struct PeerActionFuture<'a> { peers: &'a mut PeersManager, @@ -2290,12 +2297,12 @@ mod tests { async fn test_trusted_peers_are_prioritized() { let trusted_peer = PeerId::random(); let trusted_sock = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), 8008); - let config = PeersConfig::test().with_trusted_nodes(HashSet::from([NodeRecord { - address: IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), + let config = PeersConfig::test().with_trusted_nodes(vec![TrustedPeer { + host: Host::Ipv4(Ipv4Addr::new(127, 0, 1, 2)), tcp_port: 8008, udp_port: 8008, id: trusted_peer, - }])); + }]); let mut peers = PeersManager::new(config); let basic_peer = PeerId::random(); @@ -2329,12 +2336,12 @@ mod tests { let trusted_peer = PeerId::random(); let trusted_sock = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), 8008); let config = PeersConfig::test() - .with_trusted_nodes(HashSet::from([NodeRecord { - address: IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), + .with_trusted_nodes(vec![TrustedPeer { + host: Host::Ipv4(Ipv4Addr::new(127, 0, 1, 2)), tcp_port: 8008, udp_port: 8008, id: trusted_peer, - }])) + }]) .with_trusted_nodes_only(true); let mut peers = PeersManager::new(config); @@ -2366,12 +2373,12 @@ mod tests { async fn test_incoming_with_trusted_nodes_only() { let trusted_peer = PeerId::random(); let config = PeersConfig::test() - .with_trusted_nodes(HashSet::from([NodeRecord { - address: IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), + .with_trusted_nodes(vec![TrustedPeer { + host: Host::Ipv4(Ipv4Addr::new(127, 0, 1, 2)), tcp_port: 8008, udp_port: 8008, id: trusted_peer, - }])) + }]) .with_trusted_nodes_only(true); let mut peers = PeersManager::new(config); @@ -2399,12 +2406,12 @@ mod tests { async fn test_incoming_without_trusted_nodes_only() { let trusted_peer = PeerId::random(); let config = PeersConfig::test() - .with_trusted_nodes(HashSet::from([NodeRecord { - address: IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), + .with_trusted_nodes(vec![TrustedPeer { + host: Host::Ipv4(Ipv4Addr::new(127, 0, 1, 2)), tcp_port: 8008, udp_port: 8008, id: trusted_peer, - }])) + }]) .with_trusted_nodes_only(false); let mut peers = PeersManager::new(config); diff --git a/crates/net/network/tests/it/connect.rs b/crates/net/network/tests/it/connect.rs index 88a0689b3..73dcd272e 100644 --- a/crates/net/network/tests/it/connect.rs +++ b/crates/net/network/tests/it/connect.rs @@ -15,12 +15,13 @@ use reth_network_p2p::{ headers::client::{HeadersClient, HeadersRequest}, sync::{NetworkSyncUpdater, SyncState}, }; -use reth_network_peers::{mainnet_nodes, NodeRecord}; +use reth_network_peers::{mainnet_nodes, NodeRecord, TrustedPeer}; use reth_provider::test_utils::NoopProvider; use reth_transaction_pool::test_utils::testing_pool; use secp256k1::SecretKey; use std::{collections::HashSet, net::SocketAddr, time::Duration}; use tokio::task; +use url::Host; #[tokio::test(flavor = "multi_thread")] async fn test_establish_connections() { @@ -594,13 +595,18 @@ async fn test_disconnect_incoming_when_exceeded_incoming_connections() { #[tokio::test(flavor = "multi_thread")] async fn test_always_accept_incoming_connections_from_trusted_peers() { reth_tracing::init_test_tracing(); - let peer1 = new_random_peer(10, HashSet::new()).await; - let peer2 = new_random_peer(0, HashSet::new()).await; + let peer1 = new_random_peer(10, vec![]).await; + let peer2 = new_random_peer(0, vec![]).await; // setup the peer with max_inbound = 1, and add other_peer_3 as trust nodes - let peer = - new_random_peer(0, HashSet::from([NodeRecord::new(peer2.local_addr(), *peer2.peer_id())])) - .await; + let trusted_peer2 = TrustedPeer { + host: Host::Ipv4(peer2.local_addr().ip().to_string().parse().unwrap()), + tcp_port: peer2.local_addr().port(), + udp_port: peer2.local_addr().port(), + id: *peer2.peer_id(), + }; + + let peer = new_random_peer(0, vec![trusted_peer2.clone()]).await; let handle = peer.handle().clone(); let peer1_handle = peer1.handle().clone(); @@ -634,11 +640,11 @@ async fn test_always_accept_incoming_connections_from_trusted_peers() { #[tokio::test(flavor = "multi_thread")] async fn test_rejected_by_already_connect() { reth_tracing::init_test_tracing(); - let other_peer1 = new_random_peer(10, HashSet::new()).await; - let other_peer2 = new_random_peer(10, HashSet::new()).await; + let other_peer1 = new_random_peer(10, vec![]).await; + let other_peer2 = new_random_peer(10, vec![]).await; // setup the peer with max_inbound = 2 - let peer = new_random_peer(2, HashSet::new()).await; + let peer = new_random_peer(2, vec![]).await; let handle = peer.handle().clone(); let other_peer_handle1 = other_peer1.handle().clone(); @@ -671,10 +677,7 @@ async fn test_rejected_by_already_connect() { assert_eq!(handle.num_connected_peers(), 2); } -async fn new_random_peer( - max_in_bound: usize, - trusted_nodes: HashSet, -) -> NetworkManager { +async fn new_random_peer(max_in_bound: usize, trusted_nodes: Vec) -> NetworkManager { let secret_key = SecretKey::new(&mut rand::thread_rng()); let peers_config = PeersConfig::default().with_max_inbound(max_in_bound).with_trusted_nodes(trusted_nodes); diff --git a/crates/node/builder/Cargo.toml b/crates/node/builder/Cargo.toml index bb77e419c..c10b15615 100644 --- a/crates/node/builder/Cargo.toml +++ b/crates/node/builder/Cargo.toml @@ -73,7 +73,6 @@ eyre.workspace = true fdlimit.workspace = true confy.workspace = true rayon.workspace = true -backon.workspace = true # tracing tracing.workspace = true diff --git a/crates/node/builder/src/launch/common.rs b/crates/node/builder/src/launch/common.rs index bdad79c92..e6093151a 100644 --- a/crates/node/builder/src/launch/common.rs +++ b/crates/node/builder/src/launch/common.rs @@ -5,7 +5,6 @@ use crate::{ hooks::OnComponentInitializedHook, BuilderContext, NodeAdapter, }; -use backon::{ConstantBuilder, Retryable}; use eyre::Context; use rayon::ThreadPoolBuilder; use reth_auto_seal_consensus::MiningMode; @@ -238,17 +237,11 @@ impl LaunchContextWith { if !self.attachment.config.network.trusted_peers.is_empty() { info!(target: "reth::cli", "Adding trusted nodes"); - // resolve trusted peers if they use a domain instead of dns - let resolved = futures::future::try_join_all( - self.attachment.config.network.trusted_peers.iter().map(|peer| async move { - let backoff = ConstantBuilder::default() - .with_max_times(self.attachment.config.network.dns_retries); - (move || { peer.resolve() }) - .retry(&backoff) - .notify(|err, _| warn!(target: "reth::cli", "Error resolving peer domain: {err}. Retrying...")) - .await - })).await?; - self.attachment.toml_config.peers.trusted_nodes.extend(resolved); + self.attachment + .toml_config + .peers + .trusted_nodes + .extend(self.attachment.config.network.trusted_peers.clone()); } Ok(self) }