Merge unstable 20230925 into deneb-free-blobs.

This commit is contained in:
Jimmy Chen
2023-09-26 10:32:18 +10:00
164 changed files with 3844 additions and 3057 deletions

View File

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

View File

@@ -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.

View File

@@ -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};

View File

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