mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-11 18:04:18 +00:00
Activate peer scoring (#1284)
* Initial score structure * Peer manager update * Updates to dialing * Correct tests * Correct typos and remove unused function * Integrate scoring into the network crate * Clean warnings * Formatting * Shift core functionality into the behaviour * Temp commit * Shift disconnections into the behaviour * Temp commit * Update libp2p and gossipsub * Remove gossipsub lru cache * Correct merge conflicts * Modify handler and correct tests * Update enr network globals on socket update * Apply clippy lints * Add new prysm fingerprint * More clippy fixes
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
use crate::peer_manager::{PeerManager, PeerManagerEvent};
|
||||
use crate::peer_manager::{score::PeerAction, PeerManager, PeerManagerEvent};
|
||||
use crate::rpc::*;
|
||||
use crate::types::{GossipEncoding, GossipKind, GossipTopic};
|
||||
use crate::Eth2Enr;
|
||||
@@ -21,6 +21,7 @@ use libp2p::{
|
||||
};
|
||||
use slog::{crit, debug, o};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
marker::PhantomData,
|
||||
sync::Arc,
|
||||
task::{Context, Poll},
|
||||
@@ -46,10 +47,12 @@ pub struct Behaviour<TSpec: EthSpec> {
|
||||
identify: Identify,
|
||||
/// The peer manager that keeps track of peer's reputation and status.
|
||||
peer_manager: PeerManager<TSpec>,
|
||||
/// The events generated by this behaviour to be consumed in the swarm poll.
|
||||
events: Vec<BehaviourEvent<TSpec>>,
|
||||
/// The output events generated by this behaviour to be consumed in the swarm poll.
|
||||
events: VecDeque<BehaviourEvent<TSpec>>,
|
||||
/// Events generated in the global behaviour to be sent to the behaviour handler.
|
||||
handler_events: VecDeque<NBAction<BehaviourHandlerIn<TSpec>, BehaviourEvent<TSpec>>>,
|
||||
/// Queue of peers to disconnect.
|
||||
peers_to_dc: Vec<PeerId>,
|
||||
peers_to_dc: VecDeque<PeerId>,
|
||||
/// The current meta data of the node, so respond to pings and get metadata
|
||||
meta_data: MetaData<TSpec>,
|
||||
/// A collections of variables accessible outside the network service.
|
||||
@@ -58,173 +61,12 @@ pub struct Behaviour<TSpec: EthSpec> {
|
||||
// NOTE: This can be accessed via the network_globals ENR. However we keep it here for quick
|
||||
// lookups for every gossipsub message send.
|
||||
enr_fork_id: EnrForkId,
|
||||
/// The waker for the current thread.
|
||||
waker: Option<std::task::Waker>,
|
||||
/// Logger for behaviour actions.
|
||||
log: slog::Logger,
|
||||
}
|
||||
|
||||
/// Calls the given function with the given args on all sub behaviours.
|
||||
macro_rules! delegate_to_behaviours {
|
||||
($self: ident, $fn: ident, $($arg: ident), *) => {
|
||||
$self.gossipsub.$fn($($arg),*);
|
||||
$self.eth2_rpc.$fn($($arg),*);
|
||||
$self.identify.$fn($($arg),*);
|
||||
};
|
||||
}
|
||||
|
||||
impl<TSpec: EthSpec> NetworkBehaviour for Behaviour<TSpec> {
|
||||
type ProtocolsHandler = BehaviourHandler<TSpec>;
|
||||
type OutEvent = BehaviourEvent<TSpec>;
|
||||
|
||||
fn new_handler(&mut self) -> Self::ProtocolsHandler {
|
||||
BehaviourHandler::new(&mut self.gossipsub, &mut self.eth2_rpc, &mut self.identify)
|
||||
}
|
||||
|
||||
fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec<Multiaddr> {
|
||||
self.peer_manager.addresses_of_peer(peer_id)
|
||||
}
|
||||
|
||||
fn inject_connected(&mut self, peer_id: &PeerId) {
|
||||
delegate_to_behaviours!(self, inject_connected, peer_id);
|
||||
}
|
||||
|
||||
fn inject_disconnected(&mut self, peer_id: &PeerId) {
|
||||
delegate_to_behaviours!(self, inject_disconnected, peer_id);
|
||||
}
|
||||
|
||||
fn inject_connection_established(
|
||||
&mut self,
|
||||
peer_id: &PeerId,
|
||||
conn_id: &ConnectionId,
|
||||
endpoint: &ConnectedPoint,
|
||||
) {
|
||||
delegate_to_behaviours!(
|
||||
self,
|
||||
inject_connection_established,
|
||||
peer_id,
|
||||
conn_id,
|
||||
endpoint
|
||||
);
|
||||
}
|
||||
|
||||
fn inject_connection_closed(
|
||||
&mut self,
|
||||
peer_id: &PeerId,
|
||||
conn_id: &ConnectionId,
|
||||
endpoint: &ConnectedPoint,
|
||||
) {
|
||||
delegate_to_behaviours!(self, inject_connection_closed, peer_id, conn_id, endpoint);
|
||||
}
|
||||
|
||||
fn inject_addr_reach_failure(
|
||||
&mut self,
|
||||
peer_id: Option<&PeerId>,
|
||||
addr: &Multiaddr,
|
||||
error: &dyn std::error::Error,
|
||||
) {
|
||||
delegate_to_behaviours!(self, inject_addr_reach_failure, peer_id, addr, error);
|
||||
}
|
||||
|
||||
fn inject_dial_failure(&mut self, peer_id: &PeerId) {
|
||||
delegate_to_behaviours!(self, inject_dial_failure, peer_id);
|
||||
}
|
||||
|
||||
fn inject_new_listen_addr(&mut self, addr: &Multiaddr) {
|
||||
delegate_to_behaviours!(self, inject_new_listen_addr, addr);
|
||||
}
|
||||
|
||||
fn inject_expired_listen_addr(&mut self, addr: &Multiaddr) {
|
||||
delegate_to_behaviours!(self, inject_expired_listen_addr, addr);
|
||||
}
|
||||
|
||||
fn inject_new_external_addr(&mut self, addr: &Multiaddr) {
|
||||
delegate_to_behaviours!(self, inject_new_external_addr, addr);
|
||||
}
|
||||
|
||||
fn inject_listener_error(&mut self, id: ListenerId, err: &(dyn std::error::Error + 'static)) {
|
||||
delegate_to_behaviours!(self, inject_listener_error, id, err);
|
||||
}
|
||||
fn inject_listener_closed(&mut self, id: ListenerId, reason: Result<(), &std::io::Error>) {
|
||||
delegate_to_behaviours!(self, inject_listener_closed, id, reason);
|
||||
}
|
||||
|
||||
fn inject_event(
|
||||
&mut self,
|
||||
peer_id: PeerId,
|
||||
conn_id: ConnectionId,
|
||||
event: <Self::ProtocolsHandler as ProtocolsHandler>::OutEvent,
|
||||
) {
|
||||
match event {
|
||||
// Events comming from the handler, redirected to each behaviour
|
||||
BehaviourHandlerOut::Delegate(delegate) => match *delegate {
|
||||
DelegateOut::Gossipsub(ev) => self.gossipsub.inject_event(peer_id, conn_id, ev),
|
||||
DelegateOut::RPC(ev) => self.eth2_rpc.inject_event(peer_id, conn_id, ev),
|
||||
DelegateOut::Identify(ev) => self.identify.inject_event(peer_id, conn_id, *ev),
|
||||
},
|
||||
/* Custom events sent BY the handler */
|
||||
BehaviourHandlerOut::Custom => {
|
||||
// TODO: implement
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn poll(
|
||||
&mut self,
|
||||
cx: &mut Context,
|
||||
poll_params: &mut impl PollParameters,
|
||||
) -> Poll<NBAction<<Self::ProtocolsHandler as ProtocolsHandler>::InEvent, Self::OutEvent>> {
|
||||
// TODO: move where it's less distracting
|
||||
macro_rules! poll_behaviour {
|
||||
/* $behaviour: The sub-behaviour being polled.
|
||||
* $on_event_fn: Function to call if we get an event from the sub-behaviour.
|
||||
* $notify_handler_event_closure: Closure mapping the received event type to
|
||||
* the one that the handler should get.
|
||||
*/
|
||||
($behaviour: ident, $on_event_fn: ident, $notify_handler_event_closure: expr) => {
|
||||
loop {
|
||||
// poll the sub-behaviour
|
||||
match self.$behaviour.poll(cx, poll_params) {
|
||||
Poll::Ready(action) => match action {
|
||||
// call the designated function to handle the event from sub-behaviour
|
||||
NBAction::GenerateEvent(event) => self.$on_event_fn(event),
|
||||
NBAction::DialAddress { address } => {
|
||||
return Poll::Ready(NBAction::DialAddress { address })
|
||||
}
|
||||
NBAction::DialPeer { peer_id, condition } => {
|
||||
return Poll::Ready(NBAction::DialPeer { peer_id, condition })
|
||||
}
|
||||
NBAction::NotifyHandler {
|
||||
peer_id,
|
||||
handler,
|
||||
event,
|
||||
} => {
|
||||
return Poll::Ready(NBAction::NotifyHandler {
|
||||
peer_id,
|
||||
handler,
|
||||
// call the closure mapping the received event to the needed one
|
||||
// in order to notify the handler
|
||||
event: BehaviourHandlerIn::Delegate(
|
||||
$notify_handler_event_closure(event),
|
||||
),
|
||||
});
|
||||
}
|
||||
NBAction::ReportObservedAddr { address } => {
|
||||
return Poll::Ready(NBAction::ReportObservedAddr { address })
|
||||
}
|
||||
},
|
||||
Poll::Pending => break,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
poll_behaviour!(gossipsub, on_gossip_event, DelegateIn::Gossipsub);
|
||||
poll_behaviour!(eth2_rpc, on_rpc_event, DelegateIn::RPC);
|
||||
poll_behaviour!(identify, on_identify_event, DelegateIn::Identify);
|
||||
|
||||
self.custom_poll(cx)
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements the combined behaviour for the libp2p service.
|
||||
impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
pub fn new(
|
||||
@@ -264,15 +106,27 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
),
|
||||
identify,
|
||||
peer_manager: PeerManager::new(local_key, net_conf, network_globals.clone(), log)?,
|
||||
events: Vec::new(),
|
||||
peers_to_dc: Vec::new(),
|
||||
events: VecDeque::new(),
|
||||
handler_events: VecDeque::new(),
|
||||
peers_to_dc: VecDeque::new(),
|
||||
meta_data,
|
||||
network_globals,
|
||||
enr_fork_id,
|
||||
waker: None,
|
||||
log: behaviour_log,
|
||||
})
|
||||
}
|
||||
|
||||
/// Attempts to connect to a libp2p peer.
|
||||
///
|
||||
/// This MUST be used over Swarm::dial() as this keeps track of the peer in the peer manager.
|
||||
///
|
||||
/// All external dials, dial a multiaddr. This is currently unused but kept here in case any
|
||||
/// part of lighthouse needs to connect to a peer_id in the future.
|
||||
pub fn _dial(&mut self, peer_id: &PeerId) {
|
||||
self.peer_manager.dial_peer(peer_id);
|
||||
}
|
||||
|
||||
/// Returns the local ENR of the node.
|
||||
pub fn local_enr(&self) -> Enr {
|
||||
self.network_globals.local_enr()
|
||||
@@ -409,13 +263,18 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
|
||||
/* Peer management functions */
|
||||
|
||||
/// Notify discovery that the peer has been banned.
|
||||
// TODO: Remove this and integrate all disconnection/banning logic inside the peer manager.
|
||||
pub fn peer_banned(&mut self, _peer_id: PeerId) {}
|
||||
/// Report a peer's action.
|
||||
pub fn report_peer(&mut self, peer_id: &PeerId, action: PeerAction) {
|
||||
self.peer_manager.report_peer(peer_id, action)
|
||||
}
|
||||
|
||||
/// Notify discovery that the peer has been unbanned.
|
||||
// TODO: Remove this and integrate all disconnection/banning logic inside the peer manager.
|
||||
pub fn peer_unbanned(&mut self, _peer_id: &PeerId) {}
|
||||
/// Disconnects from a peer providing a reason.
|
||||
///
|
||||
/// This will send a goodbye, disconnect and then ban the peer.
|
||||
/// This is fatal for a peer, and should be used in unrecoverable circumstances.
|
||||
pub fn goodbye_peer(&mut self, peer_id: &PeerId, reason: GoodbyeReason) {
|
||||
self.peer_manager.goodbye_peer(peer_id, reason);
|
||||
}
|
||||
|
||||
/// Returns an iterator over all enr entries in the DHT.
|
||||
pub fn enr_entries(&mut self) -> Vec<Enr> {
|
||||
@@ -531,40 +390,6 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
&mut self.peer_manager
|
||||
}
|
||||
|
||||
/* Address in the new behaviour. Connections are now maintained at the swarm level.
|
||||
/// Notifies the behaviour that a peer has connected.
|
||||
pub fn notify_peer_connect(&mut self, peer_id: PeerId, endpoint: ConnectedPoint) {
|
||||
match endpoint {
|
||||
ConnectedPoint::Dialer { .. } => self.peer_manager.connect_outgoing(&peer_id),
|
||||
ConnectedPoint::Listener { .. } => self.peer_manager.connect_ingoing(&peer_id),
|
||||
};
|
||||
|
||||
// Find ENR info about a peer if possible.
|
||||
if let Some(enr) = self.discovery.enr_of_peer(&peer_id) {
|
||||
let bitfield = match enr.bitfield::<TSpec>() {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
warn!(self.log, "Peer has invalid ENR bitfield";
|
||||
"peer_id" => format!("{}", peer_id),
|
||||
"error" => format!("{:?}", e));
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// use this as a baseline, until we get the actual meta-data
|
||||
let meta_data = MetaData {
|
||||
seq_number: 0,
|
||||
attnets: bitfield,
|
||||
};
|
||||
// TODO: Shift to the peer manager
|
||||
self.network_globals
|
||||
.peers
|
||||
.write()
|
||||
.add_metadata(&peer_id, meta_data);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
fn on_gossip_event(&mut self, event: GossipsubEvent) {
|
||||
match event {
|
||||
GossipsubEvent::Message(propagation_source, id, gs_msg) => {
|
||||
@@ -576,7 +401,7 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
}
|
||||
Ok(msg) => {
|
||||
// if this message isn't a duplicate, notify the network
|
||||
self.events.push(BehaviourEvent::PubsubMessage {
|
||||
self.add_event(BehaviourEvent::PubsubMessage {
|
||||
id,
|
||||
source: propagation_source,
|
||||
topics: gs_msg.topics,
|
||||
@@ -586,8 +411,7 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
}
|
||||
}
|
||||
GossipsubEvent::Subscribed { peer_id, topic } => {
|
||||
self.events
|
||||
.push(BehaviourEvent::PeerSubscribed(peer_id, topic));
|
||||
self.add_event(BehaviourEvent::PeerSubscribed(peer_id, topic));
|
||||
}
|
||||
GossipsubEvent::Unsubscribed { .. } => {}
|
||||
}
|
||||
@@ -596,7 +420,7 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
/// Queues the response to be sent upwards as long at it was requested outside the Behaviour.
|
||||
fn propagate_response(&mut self, id: RequestId, peer_id: PeerId, response: Response<TSpec>) {
|
||||
if !matches!(id, RequestId::Behaviour) {
|
||||
self.events.push(BehaviourEvent::ResponseReceived {
|
||||
self.add_event(BehaviourEvent::ResponseReceived {
|
||||
peer_id,
|
||||
id,
|
||||
response,
|
||||
@@ -606,7 +430,7 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
|
||||
/// Convenience function to propagate a request.
|
||||
fn propagate_request(&mut self, id: PeerRequestId, peer_id: PeerId, request: Request) {
|
||||
self.events.push(BehaviourEvent::RequestReceived {
|
||||
self.add_event(BehaviourEvent::RequestReceived {
|
||||
peer_id,
|
||||
id,
|
||||
request,
|
||||
@@ -639,8 +463,7 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
self.peer_manager.handle_rpc_error(&peer_id, proto, &error);
|
||||
// inform failures of requests comming outside the behaviour
|
||||
if !matches!(id, RequestId::Behaviour) {
|
||||
self.events
|
||||
.push(BehaviourEvent::RPCFailed { peer_id, id, error });
|
||||
self.add_event(BehaviourEvent::RPCFailed { peer_id, id, error });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -664,11 +487,18 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
// let the peer manager know this peer is in the process of disconnecting
|
||||
self.peer_manager._disconnecting_peer(&peer_id);
|
||||
// queue for disconnection without a goodbye message
|
||||
debug!(self.log, "Received a Goodbye, queueing for disconnection";
|
||||
"peer_id" => peer_id.to_string());
|
||||
self.peers_to_dc.push(peer_id.clone());
|
||||
// TODO: do not propagate
|
||||
self.propagate_request(peer_request_id, peer_id, Request::Goodbye(reason));
|
||||
debug!(
|
||||
self.log, "Peer sent Goodbye";
|
||||
"peer_id" => peer_id.to_string(),
|
||||
"reason" => reason.to_string(),
|
||||
"client" => self.network_globals.client(&peer_id).to_string(),
|
||||
);
|
||||
self.peers_to_dc.push_back(peer_id);
|
||||
// NOTE: We currently do not inform the application that we are
|
||||
// disconnecting here.
|
||||
// The actual disconnection event will be relayed to the application. Ideally
|
||||
// this time difference is short, but we may need to introduce a message to
|
||||
// inform the application layer early.
|
||||
}
|
||||
/* Protocols propagated to the Network */
|
||||
RPCRequest::Status(msg) => {
|
||||
@@ -724,10 +554,15 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
&mut self,
|
||||
cx: &mut Context,
|
||||
) -> Poll<NBAction<BehaviourHandlerIn<TSpec>, BehaviourEvent<TSpec>>> {
|
||||
// if there are any handler_events process them
|
||||
if let Some(event) = self.handler_events.pop_front() {
|
||||
return Poll::Ready(event);
|
||||
}
|
||||
|
||||
// handle pending disconnections to perform
|
||||
if !self.peers_to_dc.is_empty() {
|
||||
if let Some(peer_id) = self.peers_to_dc.pop_front() {
|
||||
return Poll::Ready(NBAction::NotifyHandler {
|
||||
peer_id: self.peers_to_dc.remove(0),
|
||||
peer_id,
|
||||
handler: NotifyHandler::All,
|
||||
event: BehaviourHandlerIn::Shutdown(None),
|
||||
});
|
||||
@@ -760,18 +595,18 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
PeerManagerEvent::MetaData(peer_id) => {
|
||||
self.send_meta_data_request(peer_id);
|
||||
}
|
||||
PeerManagerEvent::DisconnectPeer(peer_id) => {
|
||||
PeerManagerEvent::DisconnectPeer(peer_id, reason) => {
|
||||
debug!(self.log, "PeerManager requested to disconnect a peer";
|
||||
"peer_id" => peer_id.to_string());
|
||||
// queue for disabling
|
||||
self.peers_to_dc.push(peer_id.clone());
|
||||
self.peers_to_dc.push_back(peer_id.clone());
|
||||
// send one goodbye
|
||||
return Poll::Ready(NBAction::NotifyHandler {
|
||||
peer_id,
|
||||
handler: NotifyHandler::Any,
|
||||
event: BehaviourHandlerIn::Shutdown(Some((
|
||||
RequestId::Behaviour,
|
||||
RPCRequest::Goodbye(GoodbyeReason::Fault),
|
||||
RPCRequest::Goodbye(reason),
|
||||
))),
|
||||
});
|
||||
}
|
||||
@@ -781,8 +616,8 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
}
|
||||
}
|
||||
|
||||
if !self.events.is_empty() {
|
||||
return Poll::Ready(NBAction::GenerateEvent(self.events.remove(0)));
|
||||
if let Some(event) = self.events.pop_front() {
|
||||
return Poll::Ready(NBAction::GenerateEvent(event));
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
@@ -817,21 +652,244 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
IdentifyEvent::Error { .. } => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds an event to the queue waking the current thread to process it.
|
||||
fn add_event(&mut self, event: BehaviourEvent<TSpec>) {
|
||||
self.events.push_back(event);
|
||||
if let Some(waker) = &self.waker {
|
||||
waker.wake_by_ref();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Calls the given function with the given args on all sub behaviours.
|
||||
macro_rules! delegate_to_behaviours {
|
||||
($self: ident, $fn: ident, $($arg: ident), *) => {
|
||||
$self.gossipsub.$fn($($arg),*);
|
||||
$self.eth2_rpc.$fn($($arg),*);
|
||||
$self.identify.$fn($($arg),*);
|
||||
};
|
||||
}
|
||||
|
||||
impl<TSpec: EthSpec> NetworkBehaviour for Behaviour<TSpec> {
|
||||
type ProtocolsHandler = BehaviourHandler<TSpec>;
|
||||
type OutEvent = BehaviourEvent<TSpec>;
|
||||
|
||||
fn new_handler(&mut self) -> Self::ProtocolsHandler {
|
||||
BehaviourHandler::new(&mut self.gossipsub, &mut self.eth2_rpc, &mut self.identify)
|
||||
}
|
||||
|
||||
fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec<Multiaddr> {
|
||||
self.peer_manager.addresses_of_peer(peer_id)
|
||||
}
|
||||
|
||||
// This gets called every time a connection is closed.
|
||||
fn inject_connection_closed(
|
||||
&mut self,
|
||||
peer_id: &PeerId,
|
||||
conn_id: &ConnectionId,
|
||||
endpoint: &ConnectedPoint,
|
||||
) {
|
||||
delegate_to_behaviours!(self, inject_connection_closed, peer_id, conn_id, endpoint);
|
||||
}
|
||||
|
||||
// This gets called once there are no more active connections.
|
||||
fn inject_disconnected(&mut self, peer_id: &PeerId) {
|
||||
// Inform the peer manager.
|
||||
self.peer_manager.notify_disconnect(&peer_id);
|
||||
// Inform the application.
|
||||
self.add_event(BehaviourEvent::PeerDisconnected(peer_id.clone()));
|
||||
delegate_to_behaviours!(self, inject_disconnected, peer_id);
|
||||
}
|
||||
|
||||
// This gets called every time a connection is established.
|
||||
fn inject_connection_established(
|
||||
&mut self,
|
||||
peer_id: &PeerId,
|
||||
conn_id: &ConnectionId,
|
||||
endpoint: &ConnectedPoint,
|
||||
) {
|
||||
// If the peer is banned, send a goodbye and disconnect.
|
||||
if self.peer_manager.is_banned(peer_id) {
|
||||
self.peers_to_dc.push_back(peer_id.clone());
|
||||
// send a goodbye on all possible handlers for this peer
|
||||
self.handler_events.push_back(NBAction::NotifyHandler {
|
||||
peer_id: peer_id.clone(),
|
||||
handler: NotifyHandler::All,
|
||||
event: BehaviourHandlerIn::Shutdown(Some((
|
||||
RequestId::Behaviour,
|
||||
RPCRequest::Goodbye(GoodbyeReason::Banned),
|
||||
))),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// notify the peer manager of a successful connection
|
||||
match endpoint {
|
||||
ConnectedPoint::Listener { .. } => {
|
||||
self.peer_manager.connect_ingoing(&peer_id);
|
||||
self.add_event(BehaviourEvent::PeerConnected(peer_id.clone()));
|
||||
debug!(self.log, "Connection established"; "peer_id" => peer_id.to_string(), "connection" => "Incoming");
|
||||
}
|
||||
ConnectedPoint::Dialer { .. } => {
|
||||
self.peer_manager.connect_outgoing(&peer_id);
|
||||
self.add_event(BehaviourEvent::PeerDialed(peer_id.clone()));
|
||||
debug!(self.log, "Connection established"; "peer_id" => peer_id.to_string(), "connection" => "Dialed");
|
||||
}
|
||||
}
|
||||
// report the event to the application
|
||||
|
||||
delegate_to_behaviours!(
|
||||
self,
|
||||
inject_connection_established,
|
||||
peer_id,
|
||||
conn_id,
|
||||
endpoint
|
||||
);
|
||||
}
|
||||
|
||||
// This gets called on the initial connection establishment.
|
||||
fn inject_connected(&mut self, peer_id: &PeerId) {
|
||||
// Drop any connection from a banned peer. The goodbye and disconnects are handled in
|
||||
// `inject_connection_established()`, which gets called first.
|
||||
if self.peer_manager.is_banned(peer_id) {
|
||||
return;
|
||||
}
|
||||
delegate_to_behaviours!(self, inject_connected, peer_id);
|
||||
}
|
||||
|
||||
fn inject_addr_reach_failure(
|
||||
&mut self,
|
||||
peer_id: Option<&PeerId>,
|
||||
addr: &Multiaddr,
|
||||
error: &dyn std::error::Error,
|
||||
) {
|
||||
delegate_to_behaviours!(self, inject_addr_reach_failure, peer_id, addr, error);
|
||||
}
|
||||
|
||||
fn inject_dial_failure(&mut self, peer_id: &PeerId) {
|
||||
// Could not dial the peer, inform the peer manager.
|
||||
self.peer_manager.notify_dial_failure(&peer_id);
|
||||
delegate_to_behaviours!(self, inject_dial_failure, peer_id);
|
||||
}
|
||||
|
||||
fn inject_new_listen_addr(&mut self, addr: &Multiaddr) {
|
||||
delegate_to_behaviours!(self, inject_new_listen_addr, addr);
|
||||
}
|
||||
|
||||
fn inject_expired_listen_addr(&mut self, addr: &Multiaddr) {
|
||||
delegate_to_behaviours!(self, inject_expired_listen_addr, addr);
|
||||
}
|
||||
|
||||
fn inject_new_external_addr(&mut self, addr: &Multiaddr) {
|
||||
delegate_to_behaviours!(self, inject_new_external_addr, addr);
|
||||
}
|
||||
|
||||
fn inject_listener_error(&mut self, id: ListenerId, err: &(dyn std::error::Error + 'static)) {
|
||||
delegate_to_behaviours!(self, inject_listener_error, id, err);
|
||||
}
|
||||
fn inject_listener_closed(&mut self, id: ListenerId, reason: Result<(), &std::io::Error>) {
|
||||
delegate_to_behaviours!(self, inject_listener_closed, id, reason);
|
||||
}
|
||||
|
||||
fn inject_event(
|
||||
&mut self,
|
||||
peer_id: PeerId,
|
||||
conn_id: ConnectionId,
|
||||
event: <Self::ProtocolsHandler as ProtocolsHandler>::OutEvent,
|
||||
) {
|
||||
match event {
|
||||
// Events comming from the handler, redirected to each behaviour
|
||||
BehaviourHandlerOut::Delegate(delegate) => match *delegate {
|
||||
DelegateOut::Gossipsub(ev) => self.gossipsub.inject_event(peer_id, conn_id, ev),
|
||||
DelegateOut::RPC(ev) => self.eth2_rpc.inject_event(peer_id, conn_id, ev),
|
||||
DelegateOut::Identify(ev) => self.identify.inject_event(peer_id, conn_id, *ev),
|
||||
},
|
||||
/* Custom events sent BY the handler */
|
||||
BehaviourHandlerOut::Custom => {
|
||||
// TODO: implement
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn poll(
|
||||
&mut self,
|
||||
cx: &mut Context,
|
||||
poll_params: &mut impl PollParameters,
|
||||
) -> Poll<NBAction<<Self::ProtocolsHandler as ProtocolsHandler>::InEvent, Self::OutEvent>> {
|
||||
// update the waker if needed
|
||||
if let Some(waker) = &self.waker {
|
||||
if waker.will_wake(cx.waker()) {
|
||||
self.waker = Some(cx.waker().clone());
|
||||
}
|
||||
} else {
|
||||
self.waker = Some(cx.waker().clone());
|
||||
}
|
||||
|
||||
// TODO: move where it's less distracting
|
||||
macro_rules! poll_behaviour {
|
||||
/* $behaviour: The sub-behaviour being polled.
|
||||
* $on_event_fn: Function to call if we get an event from the sub-behaviour.
|
||||
* $notify_handler_event_closure: Closure mapping the received event type to
|
||||
* the one that the handler should get.
|
||||
*/
|
||||
($behaviour: ident, $on_event_fn: ident, $notify_handler_event_closure: expr) => {
|
||||
loop {
|
||||
// poll the sub-behaviour
|
||||
match self.$behaviour.poll(cx, poll_params) {
|
||||
Poll::Ready(action) => match action {
|
||||
// call the designated function to handle the event from sub-behaviour
|
||||
NBAction::GenerateEvent(event) => self.$on_event_fn(event),
|
||||
NBAction::DialAddress { address } => {
|
||||
return Poll::Ready(NBAction::DialAddress { address })
|
||||
}
|
||||
NBAction::DialPeer { peer_id, condition } => {
|
||||
return Poll::Ready(NBAction::DialPeer { peer_id, condition })
|
||||
}
|
||||
NBAction::NotifyHandler {
|
||||
peer_id,
|
||||
handler,
|
||||
event,
|
||||
} => {
|
||||
return Poll::Ready(NBAction::NotifyHandler {
|
||||
peer_id,
|
||||
handler,
|
||||
// call the closure mapping the received event to the needed one
|
||||
// in order to notify the handler
|
||||
event: BehaviourHandlerIn::Delegate(
|
||||
$notify_handler_event_closure(event),
|
||||
),
|
||||
});
|
||||
}
|
||||
NBAction::ReportObservedAddr { address } => {
|
||||
return Poll::Ready(NBAction::ReportObservedAddr { address })
|
||||
}
|
||||
},
|
||||
Poll::Pending => break,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
poll_behaviour!(gossipsub, on_gossip_event, DelegateIn::Gossipsub);
|
||||
poll_behaviour!(eth2_rpc, on_rpc_event, DelegateIn::RPC);
|
||||
poll_behaviour!(identify, on_identify_event, DelegateIn::Identify);
|
||||
|
||||
self.custom_poll(cx)
|
||||
}
|
||||
}
|
||||
|
||||
/* Public API types */
|
||||
|
||||
/// The type of RPC requests the Behaviour informs it has received and allows for sending.
|
||||
///
|
||||
// NOTE: This is an application-level wrapper over the lower network leve requests that can be
|
||||
// sent. The main difference is the absense of the Ping and Metadata protocols, which don't
|
||||
// NOTE: This is an application-level wrapper over the lower network level requests that can be
|
||||
// sent. The main difference is the absence of the Ping, Metadata and Goodbye protocols, which don't
|
||||
// leave the Behaviour. For all protocols managed by RPC see `RPCRequest`.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Request {
|
||||
/// A Status message.
|
||||
Status(StatusMessage),
|
||||
/// A Goobye message.
|
||||
Goodbye(GoodbyeReason),
|
||||
/// A blocks by range request.
|
||||
BlocksByRange(BlocksByRangeRequest),
|
||||
/// A request blocks root request.
|
||||
@@ -843,7 +901,6 @@ impl<TSpec: EthSpec> std::convert::From<Request> for RPCRequest<TSpec> {
|
||||
match req {
|
||||
Request::BlocksByRoot(r) => RPCRequest::BlocksByRoot(r),
|
||||
Request::BlocksByRange(r) => RPCRequest::BlocksByRange(r),
|
||||
Request::Goodbye(r) => RPCRequest::Goodbye(r),
|
||||
Request::Status(s) => RPCRequest::Status(s),
|
||||
}
|
||||
}
|
||||
@@ -887,6 +944,12 @@ pub type PeerRequestId = (ConnectionId, SubstreamId);
|
||||
/// The types of events than can be obtained from polling the behaviour.
|
||||
#[derive(Debug)]
|
||||
pub enum BehaviourEvent<TSpec: EthSpec> {
|
||||
/// We have successfully dialed and connected to a peer.
|
||||
PeerDialed(PeerId),
|
||||
/// A peer has successfully dialed and connected to us.
|
||||
PeerConnected(PeerId),
|
||||
/// A peer has disconnected.
|
||||
PeerDisconnected(PeerId),
|
||||
/// An RPC Request that was sent failed.
|
||||
RPCFailed {
|
||||
/// The id of the failed request.
|
||||
|
||||
Reference in New Issue
Block a user