mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-06 18:21:45 +00:00
Unban peers at the swarm level when purged (#2855)
## Issue Addressed #2840
This commit is contained in:
@@ -638,7 +638,7 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
///
|
||||
/// This is also called when dialing a peer fails.
|
||||
fn inject_disconnect(&mut self, peer_id: &PeerId) {
|
||||
let ban_operation = self
|
||||
let (ban_operation, purged_peers) = self
|
||||
.network_globals
|
||||
.peers
|
||||
.write()
|
||||
@@ -653,6 +653,11 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
self.inbound_ping_peers.remove(peer_id);
|
||||
self.outbound_ping_peers.remove(peer_id);
|
||||
self.status_peers.remove(peer_id);
|
||||
self.events.extend(
|
||||
purged_peers
|
||||
.into_iter()
|
||||
.map(|(peer_id, unbanned_ips)| PeerManagerEvent::UnBanned(peer_id, unbanned_ips)),
|
||||
);
|
||||
}
|
||||
|
||||
/// Registers a peer as connected. The `ingoing` parameter determines if the peer is being
|
||||
@@ -855,9 +860,6 @@ enum ConnectingType {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::discovery::enr_ext::CombinedKeyExt;
|
||||
use crate::rpc::methods::{MetaData, MetaDataV2};
|
||||
use discv5::enr::CombinedKey;
|
||||
use slog::{o, Drain};
|
||||
use types::MinimalEthSpec as E;
|
||||
|
||||
@@ -880,23 +882,7 @@ mod tests {
|
||||
..Default::default()
|
||||
};
|
||||
let log = build_log(slog::Level::Debug, false);
|
||||
let globals = {
|
||||
let keypair = libp2p::identity::Keypair::generate_secp256k1();
|
||||
let enr_key: CombinedKey = CombinedKey::from_libp2p(&keypair).unwrap();
|
||||
let enr = discv5::enr::EnrBuilder::new("v4").build(&enr_key).unwrap();
|
||||
NetworkGlobals::new(
|
||||
enr,
|
||||
9000,
|
||||
9000,
|
||||
MetaData::V2(MetaDataV2 {
|
||||
seq_number: 0,
|
||||
attnets: Default::default(),
|
||||
syncnets: Default::default(),
|
||||
}),
|
||||
vec![],
|
||||
&log,
|
||||
)
|
||||
};
|
||||
let globals = NetworkGlobals::new_test_globals(&log);
|
||||
PeerManager::new(config, Arc::new(globals), &log)
|
||||
.await
|
||||
.unwrap()
|
||||
|
||||
@@ -23,7 +23,7 @@ pub mod sync_status;
|
||||
/// Max number of disconnected nodes to remember.
|
||||
const MAX_DC_PEERS: usize = 500;
|
||||
/// The maximum number of banned nodes to remember.
|
||||
const MAX_BANNED_PEERS: usize = 1000;
|
||||
pub const MAX_BANNED_PEERS: usize = 1000;
|
||||
/// We ban an IP if there are more than `BANNED_PEERS_PER_IP_THRESHOLD` banned peers with this IP.
|
||||
const BANNED_PEERS_PER_IP_THRESHOLD: usize = 5;
|
||||
/// Relative factor of peers that are allowed to have a negative gossipsub score without penalizing
|
||||
@@ -709,6 +709,7 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
}
|
||||
PeerConnectionStatus::Banned { .. } => {
|
||||
error!(self.log, "Accepted a connection from a banned peer"; "peer_id" => %peer_id);
|
||||
// TODO: check if this happens and report the unban back
|
||||
self.banned_peers_count
|
||||
.remove_banned_peer(info.seen_ip_addresses());
|
||||
}
|
||||
@@ -765,7 +766,6 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
.seen_ip_addresses()
|
||||
.filter(|ip| known_banned_ips.contains(ip))
|
||||
.collect::<Vec<_>>();
|
||||
self.shrink_to_fit();
|
||||
return Some(BanOperation::ReadyToBan(banned_ips));
|
||||
}
|
||||
PeerConnectionStatus::Disconnecting { .. }
|
||||
@@ -776,7 +776,6 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
info.set_connection_status(PeerConnectionStatus::Disconnected {
|
||||
since: Instant::now(),
|
||||
});
|
||||
self.shrink_to_fit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -818,7 +817,6 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
.seen_ip_addresses()
|
||||
.filter(|ip| known_banned_ips.contains(ip))
|
||||
.collect::<Vec<_>>();
|
||||
self.shrink_to_fit();
|
||||
return Some(BanOperation::ReadyToBan(banned_ips));
|
||||
}
|
||||
(PeerConnectionStatus::Disconnecting { .. }, NewConnectionState::Banned) => {
|
||||
@@ -859,7 +857,6 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
.seen_ip_addresses()
|
||||
.filter(|ip| known_banned_ips.contains(ip))
|
||||
.collect::<Vec<_>>();
|
||||
self.shrink_to_fit();
|
||||
return Some(BanOperation::ReadyToBan(banned_ips));
|
||||
}
|
||||
|
||||
@@ -885,7 +882,6 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
.remove_banned_peer(info.seen_ip_addresses());
|
||||
self.disconnected_peers =
|
||||
self.disconnected_peers().count().saturating_add(1);
|
||||
self.shrink_to_fit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -896,8 +892,14 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
/// Sets the peer as disconnected. A banned peer remains banned. If the node has become banned,
|
||||
/// this returns true, otherwise this is false.
|
||||
// VISIBILITY: Only the peer manager can adjust the connection state.
|
||||
pub(super) fn inject_disconnect(&mut self, peer_id: &PeerId) -> Option<BanOperation> {
|
||||
self.update_connection_state(peer_id, NewConnectionState::Disconnected)
|
||||
pub(super) fn inject_disconnect(
|
||||
&mut self,
|
||||
peer_id: &PeerId,
|
||||
) -> (Option<BanOperation>, Vec<(PeerId, Vec<IpAddr>)>) {
|
||||
// A peer can be banned for disconnecting. Thus another peer could be purged
|
||||
let maybe_ban_op = self.update_connection_state(peer_id, NewConnectionState::Disconnected);
|
||||
let purged_peers = self.shrink_to_fit();
|
||||
(maybe_ban_op, purged_peers)
|
||||
}
|
||||
|
||||
/// The peer manager has notified us that the peer is undergoing a normal disconnect. Optionally tag
|
||||
@@ -908,12 +910,19 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
}
|
||||
|
||||
/// Removes banned and disconnected peers from the DB if we have reached any of our limits.
|
||||
/// Drops the peers with the lowest reputation so that the number of
|
||||
/// disconnected peers is less than MAX_DC_PEERS
|
||||
fn shrink_to_fit(&mut self) {
|
||||
/// Drops the peers with the lowest reputation so that the number of disconnected peers is less
|
||||
/// than MAX_DC_PEERS
|
||||
#[must_use = "Unbanned peers need to be reported to libp2p."]
|
||||
fn shrink_to_fit(&mut self) -> Vec<(PeerId, Vec<IpAddr>)> {
|
||||
let excess_peers = self
|
||||
.banned_peers_count
|
||||
.banned_peers()
|
||||
.saturating_sub(MAX_BANNED_PEERS);
|
||||
let mut unbanned_peers = Vec::with_capacity(excess_peers);
|
||||
|
||||
// Remove excess banned peers
|
||||
while self.banned_peers_count.banned_peers() > MAX_BANNED_PEERS {
|
||||
if let Some(to_drop) = if let Some((id, info, _)) = self
|
||||
if let Some((to_drop, unbanned_ips)) = if let Some((id, info, _)) = self
|
||||
.peers
|
||||
.iter()
|
||||
.filter_map(|(id, info)| match info.connection_status() {
|
||||
@@ -924,7 +933,12 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
{
|
||||
self.banned_peers_count
|
||||
.remove_banned_peer(info.seen_ip_addresses());
|
||||
Some(*id)
|
||||
let unbanned_ips = info
|
||||
.seen_ip_addresses()
|
||||
.filter(|ip| !self.is_ip_banned(ip))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Some((*id, unbanned_ips))
|
||||
} else {
|
||||
// If there is no minimum, this is a coding error.
|
||||
crit!(
|
||||
@@ -937,6 +951,7 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
} {
|
||||
debug!(self.log, "Removing old banned peer"; "peer_id" => %to_drop);
|
||||
self.peers.remove(&to_drop);
|
||||
unbanned_peers.push((to_drop, unbanned_ips))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -960,6 +975,8 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
// the count to avoid a potential infinite loop.
|
||||
self.disconnected_peers = self.disconnected_peers.saturating_sub(1);
|
||||
}
|
||||
|
||||
unbanned_peers
|
||||
}
|
||||
|
||||
/// This handles score transitions between states. It transitions peers states from
|
||||
@@ -1721,6 +1738,7 @@ mod tests {
|
||||
//peers[0] gets unbanned
|
||||
reset_score(&mut pdb, &peers[0]);
|
||||
pdb.update_connection_state(&peers[0], NewConnectionState::Unbanned);
|
||||
let _ = pdb.shrink_to_fit();
|
||||
|
||||
//nothing changed
|
||||
assert!(pdb.ban_status(&p1).is_banned());
|
||||
@@ -1732,6 +1750,7 @@ mod tests {
|
||||
//peers[1] gets unbanned
|
||||
reset_score(&mut pdb, &peers[1]);
|
||||
pdb.update_connection_state(&peers[1], NewConnectionState::Unbanned);
|
||||
let _ = pdb.shrink_to_fit();
|
||||
|
||||
//all ips are unbanned
|
||||
assert!(!pdb.ban_status(&p1).is_banned());
|
||||
@@ -1769,6 +1788,7 @@ mod tests {
|
||||
// unban a peer
|
||||
reset_score(&mut pdb, &peers[0]);
|
||||
pdb.update_connection_state(&peers[0], NewConnectionState::Unbanned);
|
||||
let _ = pdb.shrink_to_fit();
|
||||
|
||||
// check not banned anymore
|
||||
assert!(!pdb.ban_status(&p1).is_banned());
|
||||
@@ -1778,6 +1798,7 @@ mod tests {
|
||||
for p in &peers {
|
||||
reset_score(&mut pdb, p);
|
||||
pdb.update_connection_state(p, NewConnectionState::Unbanned);
|
||||
let _ = pdb.shrink_to_fit();
|
||||
}
|
||||
|
||||
// add ip2 to all peers and ban them.
|
||||
@@ -1797,6 +1818,7 @@ mod tests {
|
||||
for p in &peers {
|
||||
reset_score(&mut pdb, p);
|
||||
pdb.update_connection_state(p, NewConnectionState::Unbanned);
|
||||
let _ = pdb.shrink_to_fit();
|
||||
}
|
||||
|
||||
// reban every peer except one
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! A collection of variables that are accessible outside of the network thread itself.
|
||||
use crate::peer_manager::peerdb::PeerDB;
|
||||
use crate::rpc::MetaData;
|
||||
use crate::rpc::{MetaData, MetaDataV2};
|
||||
use crate::types::{BackFillState, SyncState};
|
||||
use crate::Client;
|
||||
use crate::EnrExt;
|
||||
@@ -127,4 +127,25 @@ impl<TSpec: EthSpec> NetworkGlobals<TSpec> {
|
||||
pub fn set_sync_state(&self, new_state: SyncState) -> SyncState {
|
||||
std::mem::replace(&mut *self.sync_state.write(), new_state)
|
||||
}
|
||||
|
||||
/// TESTING ONLY. Build a dummy NetworkGlobals instance.
|
||||
pub fn new_test_globals(log: &slog::Logger) -> NetworkGlobals<TSpec> {
|
||||
use crate::CombinedKeyExt;
|
||||
let keypair = libp2p::identity::Keypair::generate_secp256k1();
|
||||
let enr_key: discv5::enr::CombinedKey =
|
||||
discv5::enr::CombinedKey::from_libp2p(&keypair).unwrap();
|
||||
let enr = discv5::enr::EnrBuilder::new("v4").build(&enr_key).unwrap();
|
||||
NetworkGlobals::new(
|
||||
enr,
|
||||
9000,
|
||||
9000,
|
||||
MetaData::V2(MetaDataV2 {
|
||||
seq_number: 0,
|
||||
attnets: Default::default(),
|
||||
syncnets: Default::default(),
|
||||
}),
|
||||
vec![],
|
||||
log,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user