mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-16 11:22:56 +00:00
Improved peer management (#2993)
## Issue Addressed I noticed in some logs some excess and unecessary discovery queries. What was happening was we were pruning our peers down to our outbound target and having some disconnect. When we are below this threshold we try to find more peers (even if we are at our peer limit). The request becomes futile because we have no more peer slots. This PR corrects this issue and advances the pruning mechanism to favour subnet peers. An overview the new logic added is: - We prune peers down to a target outbound peer count which is higher than the minimum outbound peer count. - We only search for more peers if there is room to do so, and we are below the minimum outbound peer count not the target. So this gives us some buffer for peers to disconnect. The buffer is currently 10% The modified pruning logic is documented in the code but for reference it should do the following: - Prune peers with bad scores first - If we need to prune more peers, then prune peers that are subscribed to a long-lived subnet - If we still need to prune peers, the prune peers that we have a higher density of on any given subnet which should drive for uniform peers across all subnets. This will need a bit of testing as it modifies some significant peer management behaviours in lighthouse.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use super::client::Client;
|
||||
use super::score::{PeerAction, Score, ScoreState};
|
||||
use super::sync_status::SyncStatus;
|
||||
use crate::discovery::Eth2Enr;
|
||||
use crate::Multiaddr;
|
||||
use crate::{rpc::MetaData, types::Subnet};
|
||||
use discv5::Enr;
|
||||
@@ -139,11 +140,92 @@ impl<T: EthSpec> PeerInfo<T> {
|
||||
self.enr.as_ref()
|
||||
}
|
||||
|
||||
/// An iterator over all the subnets this peer is subscribed to.
|
||||
pub fn subnets(&self) -> impl Iterator<Item = &Subnet> {
|
||||
self.subnets.iter()
|
||||
}
|
||||
|
||||
/// Returns the number of long lived subnets a peer is subscribed to.
|
||||
// NOTE: This currently excludes sync committee subnets
|
||||
pub fn long_lived_subnet_count(&self) -> usize {
|
||||
if let Some(meta_data) = self.meta_data.as_ref() {
|
||||
return meta_data.attnets().num_set_bits();
|
||||
} else if let Some(enr) = self.enr.as_ref() {
|
||||
if let Ok(attnets) = enr.attestation_bitfield::<T>() {
|
||||
return attnets.num_set_bits();
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
/// Returns an iterator over the long-lived subnets if it has any.
|
||||
pub fn long_lived_subnets(&self) -> Vec<Subnet> {
|
||||
let mut long_lived_subnets = Vec::new();
|
||||
// Check the meta_data
|
||||
if let Some(meta_data) = self.meta_data.as_ref() {
|
||||
for subnet in 0..=meta_data.attnets().highest_set_bit().unwrap_or(0) {
|
||||
if meta_data.attnets().get(subnet).unwrap_or(false) {
|
||||
long_lived_subnets.push(Subnet::Attestation((subnet as u64).into()));
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(syncnet) = meta_data.syncnets() {
|
||||
for subnet in 0..=syncnet.highest_set_bit().unwrap_or(0) {
|
||||
if syncnet.get(subnet).unwrap_or(false) {
|
||||
long_lived_subnets.push(Subnet::SyncCommittee((subnet as u64).into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let Some(enr) = self.enr.as_ref() {
|
||||
if let Ok(attnets) = enr.attestation_bitfield::<T>() {
|
||||
for subnet in 0..=attnets.highest_set_bit().unwrap_or(0) {
|
||||
if attnets.get(subnet).unwrap_or(false) {
|
||||
long_lived_subnets.push(Subnet::Attestation((subnet as u64).into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(syncnets) = enr.sync_committee_bitfield::<T>() {
|
||||
for subnet in 0..=syncnets.highest_set_bit().unwrap_or(0) {
|
||||
if syncnets.get(subnet).unwrap_or(false) {
|
||||
long_lived_subnets.push(Subnet::SyncCommittee((subnet as u64).into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
long_lived_subnets
|
||||
}
|
||||
|
||||
/// Returns if the peer is subscribed to a given `Subnet` from the gossipsub subscriptions.
|
||||
pub fn on_subnet_gossipsub(&self, subnet: &Subnet) -> bool {
|
||||
self.subnets.contains(subnet)
|
||||
}
|
||||
|
||||
/// Returns true if the peer is connected to a long-lived subnet.
|
||||
pub fn has_long_lived_subnet(&self) -> bool {
|
||||
// Check the meta_data
|
||||
if let Some(meta_data) = self.meta_data.as_ref() {
|
||||
if !meta_data.attnets().is_zero() && !self.subnets.is_empty() {
|
||||
return true;
|
||||
}
|
||||
if let Ok(sync) = meta_data.syncnets() {
|
||||
if !sync.is_zero() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We may not have the metadata but may have an ENR. Lets check that
|
||||
if let Some(enr) = self.enr.as_ref() {
|
||||
if let Ok(attnets) = enr.attestation_bitfield::<T>() {
|
||||
if !attnets.is_zero() && !self.subnets.is_empty() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns the seen addresses of the peer.
|
||||
pub fn seen_addresses(&self) -> impl Iterator<Item = &SocketAddr> + '_ {
|
||||
self.seen_addresses.iter()
|
||||
|
||||
Reference in New Issue
Block a user