diff --git a/crates/net/network-types/src/peers/config.rs b/crates/net/network-types/src/peers/config.rs index a28b9e602..97a8bb3ca 100644 --- a/crates/net/network-types/src/peers/config.rs +++ b/crates/net/network-types/src/peers/config.rs @@ -288,6 +288,7 @@ impl PeersConfig { Self { refill_slots_interval: Duration::from_millis(100), backoff_durations: PeerBackoffDurations::test(), + ban_duration: Duration::from_millis(200), ..Default::default() } } diff --git a/crates/net/network/src/peers.rs b/crates/net/network/src/peers.rs index 19b7910f6..b9196d29e 100644 --- a/crates/net/network/src/peers.rs +++ b/crates/net/network/src/peers.rs @@ -549,21 +549,26 @@ impl PeersManager { trace!(target: "net::peers", ?remote_addr, ?peer_id, %err, "fatal connection error"); // remove the peer to which we can't establish a connection due to protocol related // issues. - if let Some((peer_id, peer)) = self.peers.remove_entry(peer_id) { - self.connection_info.decr_state(peer.state); - self.queued_actions.push_back(PeerAction::PeerRemoved(peer_id)); + if let Entry::Occupied(mut entry) = self.peers.entry(*peer_id) { + self.connection_info.decr_state(entry.get().state); + // only remove if the peer is not trusted + if entry.get().is_trusted() { + entry.get_mut().state = PeerConnectionState::Idle; + } else { + entry.remove(); + self.queued_actions.push_back(PeerAction::PeerRemoved(*peer_id)); + // If the error is caused by a peer that should be banned from discovery + if err.merits_discovery_ban() { + self.queued_actions.push_back(PeerAction::DiscoveryBanPeerId { + peer_id: *peer_id, + ip_addr: remote_addr.ip(), + }) + } + } } // ban the peer self.ban_peer(*peer_id); - - // If the error is caused by a peer that should be banned from discovery - if err.merits_discovery_ban() { - self.queued_actions.push_back(PeerAction::DiscoveryBanPeerId { - peer_id: *peer_id, - ip_addr: remote_addr.ip(), - }) - } } else { let mut backoff_until = None; let mut remove_peer = false; @@ -1113,6 +1118,7 @@ mod tests { use super::PeersManager; use crate::{ + error::SessionError, peers::{ ConnectionInfo, InboundConnectionError, PeerAction, PeerAddr, PeerBackoffDurations, PeerConnectionState, @@ -1896,6 +1902,64 @@ mod tests { assert!(!peers.peers.contains_key(&peer)); } + #[tokio::test] + async fn test_fatal_outgoing_connection_error_trusted() { + let peer = PeerId::random(); + 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: peer, + }]) + .with_trusted_nodes_only(true); + let mut peers = PeersManager::new(config); + let socket_addr = peers.peers.get(&peer).unwrap().addr.tcp(); + + match event!(peers) { + PeerAction::Connect { peer_id, remote_addr } => { + assert_eq!(peer_id, peer); + assert_eq!(remote_addr, socket_addr); + } + _ => unreachable!(), + } + + let p = peers.peers.get(&peer).unwrap(); + assert_eq!(p.state, PeerConnectionState::PendingOut); + + assert_eq!(peers.num_outbound_connections(), 0); + + let err = PendingSessionHandshakeError::Eth(EthStreamError::EthHandshakeError( + EthHandshakeError::NonStatusMessageInHandshake, + )); + assert!(err.is_fatal_protocol_error()); + + peers.on_outgoing_pending_session_dropped(&socket_addr, &peer, &err); + assert_eq!(peers.num_outbound_connections(), 0); + + // try tmp ban peer + match event!(peers) { + PeerAction::BanPeer { peer_id } => { + assert_eq!(peer_id, peer); + } + err => unreachable!("{err:?}"), + } + + // ensure we still have trusted peer + assert!(peers.peers.contains_key(&peer)); + + // await for the ban to expire + tokio::time::sleep(peers.backoff_durations.medium).await; + + match event!(peers) { + PeerAction::Connect { peer_id, remote_addr } => { + assert_eq!(peer_id, peer); + assert_eq!(remote_addr, socket_addr); + } + err => unreachable!("{err:?}"), + } + } + #[tokio::test] async fn test_outgoing_connection_error() { let peer = PeerId::random();