mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-11 18:04:18 +00:00
Merge unstable 20230925 into deneb-free-blobs.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
//! Implementation of Lighthouse's peer management system.
|
||||
|
||||
use crate::discovery::enr_ext::EnrExt;
|
||||
use crate::rpc::{GoodbyeReason, MetaData, Protocol, RPCError, RPCResponseErrorCode};
|
||||
use crate::service::TARGET_SUBNET_PEERS;
|
||||
use crate::{error, metrics, Gossipsub};
|
||||
@@ -13,7 +14,6 @@ use peerdb::{client::ClientKind, BanOperation, BanResult, ScoreUpdateResult};
|
||||
use rand::seq::SliceRandom;
|
||||
use slog::{debug, error, trace, warn};
|
||||
use smallvec::SmallVec;
|
||||
use std::collections::BTreeMap;
|
||||
use std::{
|
||||
sync::Arc,
|
||||
time::{Duration, Instant},
|
||||
@@ -78,7 +78,7 @@ pub struct PeerManager<TSpec: EthSpec> {
|
||||
/// The target number of peers we would like to connect to.
|
||||
target_peers: usize,
|
||||
/// Peers queued to be dialed.
|
||||
peers_to_dial: BTreeMap<PeerId, Option<Enr>>,
|
||||
peers_to_dial: Vec<Enr>,
|
||||
/// The number of temporarily banned peers. This is used to prevent instantaneous
|
||||
/// reconnection.
|
||||
// NOTE: This just prevents re-connections. The state of the peer is otherwise unaffected. A
|
||||
@@ -312,16 +312,12 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
/// Peers that have been returned by discovery requests that are suitable for dialing are
|
||||
/// returned here.
|
||||
///
|
||||
/// NOTE: By dialing `PeerId`s and not multiaddrs, libp2p requests the multiaddr associated
|
||||
/// with a new `PeerId` which involves a discovery routing table lookup. We could dial the
|
||||
/// multiaddr here, however this could relate to duplicate PeerId's etc. If the lookup
|
||||
/// proves resource constraining, we should switch to multiaddr dialling here.
|
||||
/// This function decides whether or not to dial these peers.
|
||||
#[allow(clippy::mutable_key_type)]
|
||||
pub fn peers_discovered(&mut self, results: HashMap<PeerId, Option<Instant>>) -> Vec<PeerId> {
|
||||
let mut to_dial_peers = Vec::with_capacity(4);
|
||||
|
||||
pub fn peers_discovered(&mut self, results: HashMap<Enr, Option<Instant>>) {
|
||||
let mut to_dial_peers = 0;
|
||||
let connected_or_dialing = self.network_globals.connected_or_dialing_peers();
|
||||
for (peer_id, min_ttl) in results {
|
||||
for (enr, min_ttl) in results {
|
||||
// There are two conditions in deciding whether to dial this peer.
|
||||
// 1. If we are less than our max connections. Discovery queries are executed to reach
|
||||
// our target peers, so its fine to dial up to our max peers (which will get pruned
|
||||
@@ -330,10 +326,8 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
// considered a priority. We have pre-allocated some extra priority slots for these
|
||||
// peers as specified by PRIORITY_PEER_EXCESS. Therefore we dial these peers, even
|
||||
// if we are already at our max_peer limit.
|
||||
if (min_ttl.is_some()
|
||||
&& connected_or_dialing + to_dial_peers.len() < self.max_priority_peers()
|
||||
|| connected_or_dialing + to_dial_peers.len() < self.max_peers())
|
||||
&& self.network_globals.peers.read().should_dial(&peer_id)
|
||||
if min_ttl.is_some() && connected_or_dialing + to_dial_peers < self.max_priority_peers()
|
||||
|| connected_or_dialing + to_dial_peers < self.max_peers()
|
||||
{
|
||||
// This should be updated with the peer dialing. In fact created once the peer is
|
||||
// dialed
|
||||
@@ -341,16 +335,16 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
self.network_globals
|
||||
.peers
|
||||
.write()
|
||||
.update_min_ttl(&peer_id, min_ttl);
|
||||
.update_min_ttl(&enr.peer_id(), min_ttl);
|
||||
}
|
||||
to_dial_peers.push(peer_id);
|
||||
debug!(self.log, "Dialing discovered peer"; "peer_id" => %enr.peer_id());
|
||||
self.dial_peer(enr);
|
||||
to_dial_peers += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Queue another discovery if we need to
|
||||
self.maintain_peer_count(to_dial_peers.len());
|
||||
|
||||
to_dial_peers
|
||||
self.maintain_peer_count(to_dial_peers);
|
||||
}
|
||||
|
||||
/// A STATUS message has been received from a peer. This resets the status timer.
|
||||
@@ -406,9 +400,16 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
|
||||
/* Notifications from the Swarm */
|
||||
|
||||
// A peer is being dialed.
|
||||
pub fn dial_peer(&mut self, peer_id: &PeerId, enr: Option<Enr>) {
|
||||
self.peers_to_dial.insert(*peer_id, enr);
|
||||
/// A peer is being dialed.
|
||||
pub fn dial_peer(&mut self, peer: Enr) {
|
||||
if self
|
||||
.network_globals
|
||||
.peers
|
||||
.read()
|
||||
.should_dial(&peer.peer_id())
|
||||
{
|
||||
self.peers_to_dial.push(peer);
|
||||
}
|
||||
}
|
||||
|
||||
/// Reports if a peer is banned or not.
|
||||
@@ -2208,7 +2209,7 @@ mod tests {
|
||||
}
|
||||
|
||||
impl Arbitrary for PeerCondition {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
||||
fn arbitrary(g: &mut Gen) -> Self {
|
||||
let attestation_net_bitfield = {
|
||||
let len = <E as EthSpec>::SubnetBitfieldLength::to_usize();
|
||||
let mut bitfield = Vec::with_capacity(len);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use futures::StreamExt;
|
||||
use libp2p::core::ConnectedPoint;
|
||||
use libp2p::core::{multiaddr, ConnectedPoint};
|
||||
use libp2p::identity::PeerId;
|
||||
use libp2p::swarm::behaviour::{ConnectionClosed, ConnectionEstablished, DialFailure, FromSwarm};
|
||||
use libp2p::swarm::dial_opts::{DialOpts, PeerCondition};
|
||||
@@ -12,6 +12,7 @@ use libp2p::swarm::{ConnectionId, NetworkBehaviour, PollParameters, ToSwarm};
|
||||
use slog::{debug, error};
|
||||
use types::EthSpec;
|
||||
|
||||
use crate::discovery::enr_ext::EnrExt;
|
||||
use crate::rpc::GoodbyeReason;
|
||||
use crate::types::SyncState;
|
||||
use crate::{metrics, ClearDialError};
|
||||
@@ -95,11 +96,23 @@ impl<TSpec: EthSpec> NetworkBehaviour for PeerManager<TSpec> {
|
||||
self.events.shrink_to_fit();
|
||||
}
|
||||
|
||||
if let Some((peer_id, maybe_enr)) = self.peers_to_dial.pop_first() {
|
||||
self.inject_peer_connection(&peer_id, ConnectingType::Dialing, maybe_enr);
|
||||
if let Some(enr) = self.peers_to_dial.pop() {
|
||||
let peer_id = enr.peer_id();
|
||||
self.inject_peer_connection(&peer_id, ConnectingType::Dialing, Some(enr.clone()));
|
||||
let quic_multiaddrs = enr.multiaddr_quic();
|
||||
if !quic_multiaddrs.is_empty() {
|
||||
debug!(self.log, "Dialing QUIC supported peer"; "peer_id"=> %peer_id, "quic_multiaddrs" => ?quic_multiaddrs);
|
||||
}
|
||||
|
||||
// Prioritize Quic connections over Tcp ones.
|
||||
let multiaddrs = quic_multiaddrs
|
||||
.into_iter()
|
||||
.chain(enr.multiaddr_tcp())
|
||||
.collect();
|
||||
return Poll::Ready(ToSwarm::Dial {
|
||||
opts: DialOpts::peer_id(peer_id)
|
||||
.condition(PeerCondition::Disconnected)
|
||||
.addresses(multiaddrs)
|
||||
.build(),
|
||||
});
|
||||
}
|
||||
@@ -124,9 +137,11 @@ impl<TSpec: EthSpec> NetworkBehaviour for PeerManager<TSpec> {
|
||||
}
|
||||
FromSwarm::ConnectionClosed(ConnectionClosed {
|
||||
peer_id,
|
||||
endpoint,
|
||||
|
||||
remaining_established,
|
||||
..
|
||||
}) => self.on_connection_closed(peer_id, remaining_established),
|
||||
}) => self.on_connection_closed(peer_id, endpoint, remaining_established),
|
||||
FromSwarm::DialFailure(DialFailure {
|
||||
peer_id,
|
||||
error,
|
||||
@@ -184,7 +199,11 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
endpoint: &ConnectedPoint,
|
||||
other_established: usize,
|
||||
) {
|
||||
debug!(self.log, "Connection established"; "peer_id" => %peer_id, "connection" => ?endpoint.to_endpoint());
|
||||
debug!(self.log, "Connection established"; "peer_id" => %peer_id,
|
||||
"multiaddr" => %endpoint.get_remote_address(),
|
||||
"connection" => ?endpoint.to_endpoint()
|
||||
);
|
||||
|
||||
if other_established == 0 {
|
||||
self.events.push(PeerManagerEvent::MetaData(peer_id));
|
||||
}
|
||||
@@ -194,6 +213,34 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
metrics::check_nat();
|
||||
}
|
||||
|
||||
// increment prometheus metrics
|
||||
if self.metrics_enabled {
|
||||
let remote_addr = match endpoint {
|
||||
ConnectedPoint::Dialer { address, .. } => address,
|
||||
ConnectedPoint::Listener { send_back_addr, .. } => send_back_addr,
|
||||
};
|
||||
match remote_addr.iter().find(|proto| {
|
||||
matches!(
|
||||
proto,
|
||||
multiaddr::Protocol::QuicV1 | multiaddr::Protocol::Tcp(_)
|
||||
)
|
||||
}) {
|
||||
Some(multiaddr::Protocol::QuicV1) => {
|
||||
metrics::inc_gauge(&metrics::QUIC_PEERS_CONNECTED);
|
||||
}
|
||||
Some(multiaddr::Protocol::Tcp(_)) => {
|
||||
metrics::inc_gauge(&metrics::TCP_PEERS_CONNECTED);
|
||||
}
|
||||
Some(_) => unreachable!(),
|
||||
None => {
|
||||
error!(self.log, "Connection established via unknown transport"; "addr" => %remote_addr)
|
||||
}
|
||||
};
|
||||
|
||||
self.update_connected_peer_metrics();
|
||||
metrics::inc_counter(&metrics::PEER_CONNECT_EVENT_COUNT);
|
||||
}
|
||||
|
||||
// Check to make sure the peer is not supposed to be banned
|
||||
match self.ban_status(&peer_id) {
|
||||
// TODO: directly emit the ban event?
|
||||
@@ -245,14 +292,15 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
self.events
|
||||
.push(PeerManagerEvent::PeerConnectedOutgoing(peer_id));
|
||||
}
|
||||
}
|
||||
|
||||
// increment prometheus metrics
|
||||
self.update_connected_peer_metrics();
|
||||
metrics::inc_counter(&metrics::PEER_CONNECT_EVENT_COUNT);
|
||||
};
|
||||
}
|
||||
|
||||
fn on_connection_closed(&mut self, peer_id: PeerId, remaining_established: usize) {
|
||||
fn on_connection_closed(
|
||||
&mut self,
|
||||
peer_id: PeerId,
|
||||
endpoint: &ConnectedPoint,
|
||||
remaining_established: usize,
|
||||
) {
|
||||
if remaining_established > 0 {
|
||||
return;
|
||||
}
|
||||
@@ -278,9 +326,31 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
// reference so that peer manager can track this peer.
|
||||
self.inject_disconnect(&peer_id);
|
||||
|
||||
let remote_addr = match endpoint {
|
||||
ConnectedPoint::Listener { send_back_addr, .. } => send_back_addr,
|
||||
ConnectedPoint::Dialer { address, .. } => address,
|
||||
};
|
||||
|
||||
// Update the prometheus metrics
|
||||
self.update_connected_peer_metrics();
|
||||
metrics::inc_counter(&metrics::PEER_DISCONNECT_EVENT_COUNT);
|
||||
if self.metrics_enabled {
|
||||
match remote_addr.iter().find(|proto| {
|
||||
matches!(
|
||||
proto,
|
||||
multiaddr::Protocol::QuicV1 | multiaddr::Protocol::Tcp(_)
|
||||
)
|
||||
}) {
|
||||
Some(multiaddr::Protocol::QuicV1) => {
|
||||
metrics::dec_gauge(&metrics::QUIC_PEERS_CONNECTED);
|
||||
}
|
||||
Some(multiaddr::Protocol::Tcp(_)) => {
|
||||
metrics::dec_gauge(&metrics::TCP_PEERS_CONNECTED);
|
||||
}
|
||||
// If it's an unknown protocol we already logged when connection was established.
|
||||
_ => {}
|
||||
};
|
||||
self.update_connected_peer_metrics();
|
||||
metrics::inc_counter(&metrics::PEER_DISCONNECT_EVENT_COUNT);
|
||||
}
|
||||
}
|
||||
|
||||
/// A dial attempt has failed.
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
use crate::{
|
||||
metrics,
|
||||
multiaddr::{Multiaddr, Protocol},
|
||||
types::Subnet,
|
||||
Enr, Gossipsub, PeerId,
|
||||
};
|
||||
use crate::{metrics, multiaddr::Multiaddr, types::Subnet, Enr, Gossipsub, PeerId};
|
||||
use peer_info::{ConnectionDirection, PeerConnectionStatus, PeerInfo};
|
||||
use rand::seq::SliceRandom;
|
||||
use score::{PeerAction, ReportSource, Score, ScoreState};
|
||||
use slog::{crit, debug, error, trace, warn};
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::net::IpAddr;
|
||||
use std::time::Instant;
|
||||
use sync_status::SyncStatus;
|
||||
use types::EthSpec;
|
||||
@@ -764,28 +759,10 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
| PeerConnectionStatus::Dialing { .. } => {}
|
||||
}
|
||||
|
||||
// Add the seen ip address and port to the peer's info
|
||||
let socket_addr = match seen_address.iter().fold(
|
||||
(None, None),
|
||||
|(found_ip, found_port), protocol| match protocol {
|
||||
Protocol::Ip4(ip) => (Some(ip.into()), found_port),
|
||||
Protocol::Ip6(ip) => (Some(ip.into()), found_port),
|
||||
Protocol::Tcp(port) => (found_ip, Some(port)),
|
||||
_ => (found_ip, found_port),
|
||||
},
|
||||
) {
|
||||
(Some(ip), Some(port)) => Some(SocketAddr::new(ip, port)),
|
||||
(Some(_ip), None) => {
|
||||
crit!(self.log, "Connected peer has an IP but no TCP port"; "peer_id" => %peer_id);
|
||||
None
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
// Update the connection state
|
||||
match direction {
|
||||
ConnectionDirection::Incoming => info.connect_ingoing(socket_addr),
|
||||
ConnectionDirection::Outgoing => info.connect_outgoing(socket_addr),
|
||||
ConnectionDirection::Incoming => info.connect_ingoing(Some(seen_address)),
|
||||
ConnectionDirection::Outgoing => info.connect_outgoing(Some(seen_address)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1274,6 +1251,7 @@ impl BannedPeersCount {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use libp2p::core::multiaddr::Protocol;
|
||||
use libp2p::core::Multiaddr;
|
||||
use slog::{o, Drain};
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
|
||||
@@ -2,15 +2,15 @@ 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;
|
||||
use libp2p::core::multiaddr::{Multiaddr, Protocol};
|
||||
use serde::{
|
||||
ser::{SerializeStruct, Serializer},
|
||||
Serialize,
|
||||
};
|
||||
use std::collections::HashSet;
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::net::IpAddr;
|
||||
use std::time::Instant;
|
||||
use strum::AsRefStr;
|
||||
use types::EthSpec;
|
||||
@@ -29,9 +29,9 @@ pub struct PeerInfo<T: EthSpec> {
|
||||
/// The known listening addresses of this peer. This is given by identify and can be arbitrary
|
||||
/// (including local IPs).
|
||||
listening_addresses: Vec<Multiaddr>,
|
||||
/// This is addresses we have physically seen and this is what we use for banning/un-banning
|
||||
/// These are the multiaddrs we have physically seen and is what we use for banning/un-banning
|
||||
/// peers.
|
||||
seen_addresses: HashSet<SocketAddr>,
|
||||
seen_multiaddrs: HashSet<Multiaddr>,
|
||||
/// The current syncing state of the peer. The state may be determined after it's initial
|
||||
/// connection.
|
||||
sync_status: SyncStatus,
|
||||
@@ -60,7 +60,7 @@ impl<TSpec: EthSpec> Default for PeerInfo<TSpec> {
|
||||
client: Client::default(),
|
||||
connection_status: Default::default(),
|
||||
listening_addresses: Vec::new(),
|
||||
seen_addresses: HashSet::new(),
|
||||
seen_multiaddrs: HashSet::new(),
|
||||
subnets: HashSet::new(),
|
||||
sync_status: SyncStatus::Unknown,
|
||||
meta_data: None,
|
||||
@@ -227,15 +227,21 @@ impl<T: EthSpec> PeerInfo<T> {
|
||||
}
|
||||
|
||||
/// Returns the seen addresses of the peer.
|
||||
pub fn seen_addresses(&self) -> impl Iterator<Item = &SocketAddr> + '_ {
|
||||
self.seen_addresses.iter()
|
||||
pub fn seen_multiaddrs(&self) -> impl Iterator<Item = &Multiaddr> + '_ {
|
||||
self.seen_multiaddrs.iter()
|
||||
}
|
||||
|
||||
/// Returns a list of seen IP addresses for the peer.
|
||||
pub fn seen_ip_addresses(&self) -> impl Iterator<Item = IpAddr> + '_ {
|
||||
self.seen_addresses
|
||||
.iter()
|
||||
.map(|socket_addr| socket_addr.ip())
|
||||
self.seen_multiaddrs.iter().filter_map(|multiaddr| {
|
||||
multiaddr.iter().find_map(|protocol| {
|
||||
match protocol {
|
||||
Protocol::Ip4(ip) => Some(ip.into()),
|
||||
Protocol::Ip6(ip) => Some(ip.into()),
|
||||
_ => None, // Only care for IP addresses
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the connection status of the peer.
|
||||
@@ -415,7 +421,7 @@ impl<T: EthSpec> PeerInfo<T> {
|
||||
|
||||
/// Modifies the status to Connected and increases the number of ingoing
|
||||
/// connections by one
|
||||
pub(super) fn connect_ingoing(&mut self, seen_address: Option<SocketAddr>) {
|
||||
pub(super) fn connect_ingoing(&mut self, seen_multiaddr: Option<Multiaddr>) {
|
||||
match &mut self.connection_status {
|
||||
Connected { n_in, .. } => *n_in += 1,
|
||||
Disconnected { .. }
|
||||
@@ -428,14 +434,14 @@ impl<T: EthSpec> PeerInfo<T> {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(socket_addr) = seen_address {
|
||||
self.seen_addresses.insert(socket_addr);
|
||||
if let Some(multiaddr) = seen_multiaddr {
|
||||
self.seen_multiaddrs.insert(multiaddr);
|
||||
}
|
||||
}
|
||||
|
||||
/// Modifies the status to Connected and increases the number of outgoing
|
||||
/// connections by one
|
||||
pub(super) fn connect_outgoing(&mut self, seen_address: Option<SocketAddr>) {
|
||||
pub(super) fn connect_outgoing(&mut self, seen_multiaddr: Option<Multiaddr>) {
|
||||
match &mut self.connection_status {
|
||||
Connected { n_out, .. } => *n_out += 1,
|
||||
Disconnected { .. }
|
||||
@@ -447,8 +453,8 @@ impl<T: EthSpec> PeerInfo<T> {
|
||||
self.connection_direction = Some(ConnectionDirection::Outgoing);
|
||||
}
|
||||
}
|
||||
if let Some(ip_addr) = seen_address {
|
||||
self.seen_addresses.insert(ip_addr);
|
||||
if let Some(multiaddr) = seen_multiaddr {
|
||||
self.seen_multiaddrs.insert(multiaddr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user