fix: never ban trusted peers (#11254)

Co-authored-by: Emilia Hane <elsaemiliaevahane@gmail.com>
This commit is contained in:
Matthias Seitz
2024-10-01 09:35:59 +02:00
committed by GitHub
parent 6bbb07bbab
commit f51ac78d5a
2 changed files with 76 additions and 11 deletions

View File

@ -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()
}
}

View File

@ -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();