mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-16 19:32:55 +00:00
Add DC/Shutdown capabilities to the behaviour handler (#1233)
* Remove ban event from the PM * Fix dispatching of responses to peer's requests * Disconnection logic
This commit is contained in:
@@ -15,7 +15,8 @@ use libp2p::{
|
||||
gossipsub::{Gossipsub, GossipsubEvent, MessageId},
|
||||
identify::{Identify, IdentifyEvent},
|
||||
swarm::{
|
||||
NetworkBehaviour, NetworkBehaviourAction as NBAction, PollParameters, ProtocolsHandler,
|
||||
NetworkBehaviour, NetworkBehaviourAction as NBAction, NotifyHandler, PollParameters,
|
||||
ProtocolsHandler,
|
||||
},
|
||||
PeerId,
|
||||
};
|
||||
@@ -51,7 +52,8 @@ pub struct Behaviour<TSpec: EthSpec> {
|
||||
peer_manager: PeerManager<TSpec>,
|
||||
/// The events generated by this behaviour to be consumed in the swarm poll.
|
||||
events: Vec<BehaviourEvent<TSpec>>,
|
||||
// TODO: add events to send to the handler
|
||||
/// Queue of peers to disconnect.
|
||||
peers_to_dc: Vec<PeerId>,
|
||||
/// The current meta data of the node, so respond to pings and get metadata
|
||||
meta_data: MetaData<TSpec>,
|
||||
/// A cache of recently seen gossip messages. This is used to filter out any possible
|
||||
@@ -285,6 +287,7 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
identify,
|
||||
peer_manager: PeerManager::new(network_globals.clone(), log),
|
||||
events: Vec::new(),
|
||||
peers_to_dc: Vec::new(),
|
||||
seen_gossip_messages: LruCache::new(100_000),
|
||||
meta_data,
|
||||
network_globals,
|
||||
@@ -396,36 +399,34 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
|
||||
/// Send a request to a peer over RPC.
|
||||
pub fn send_request(&mut self, peer_id: PeerId, request_id: RequestId, request: Request) {
|
||||
self.send_rpc(peer_id, RPCSend::Request(request_id, request.into()))
|
||||
self.eth2_rpc
|
||||
.send_request(peer_id, request_id, request.into())
|
||||
}
|
||||
|
||||
/// Send a successful response to a peer over RPC.
|
||||
pub fn send_successful_response(
|
||||
&mut self,
|
||||
peer_id: PeerId,
|
||||
stream_id: SubstreamId,
|
||||
id: PeerRequestId,
|
||||
response: Response<TSpec>,
|
||||
) {
|
||||
self.send_rpc(peer_id, RPCSend::Response(stream_id, response.into()))
|
||||
self.eth2_rpc.send_response(peer_id, id, response.into())
|
||||
}
|
||||
|
||||
/// Inform the peer that their request produced an error.
|
||||
pub fn _send_error_reponse(
|
||||
&mut self,
|
||||
peer_id: PeerId,
|
||||
stream_id: SubstreamId,
|
||||
id: PeerRequestId,
|
||||
error: RPCResponseErrorCode,
|
||||
reason: String,
|
||||
) {
|
||||
self.send_rpc(
|
||||
self.eth2_rpc.send_response(
|
||||
peer_id,
|
||||
RPCSend::Response(stream_id, RPCCodedResponse::from_error_code(error, reason)),
|
||||
id,
|
||||
RPCCodedResponse::from_error_code(error, reason),
|
||||
)
|
||||
}
|
||||
/// Sends an RPC Request/Response via the RPC protocol.
|
||||
fn send_rpc(&mut self, peer_id: PeerId, rpc_event: RPCSend<TSpec>) {
|
||||
self.eth2_rpc.send_rpc(peer_id, rpc_event);
|
||||
}
|
||||
|
||||
/* Discovery / Peer management functions */
|
||||
|
||||
@@ -512,36 +513,32 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
data: self.meta_data.seq_number,
|
||||
};
|
||||
debug!(self.log, "Sending Ping"; "request_id" => id, "peer_id" => peer_id.to_string());
|
||||
let event = RPCSend::Request(id, RPCRequest::Ping(ping));
|
||||
|
||||
self.send_rpc(peer_id, event);
|
||||
self.eth2_rpc
|
||||
.send_request(peer_id, id, RPCRequest::Ping(ping));
|
||||
}
|
||||
|
||||
/// Sends a Pong response to the peer.
|
||||
fn pong(&mut self, id: SubstreamId, peer_id: PeerId) {
|
||||
fn pong(&mut self, id: PeerRequestId, peer_id: PeerId) {
|
||||
let ping = crate::rpc::Ping {
|
||||
data: self.meta_data.seq_number,
|
||||
};
|
||||
debug!(self.log, "Sending Pong"; "request_id" => id, "peer_id" => peer_id.to_string());
|
||||
let event = RPCSend::Response(id, RPCCodedResponse::Success(RPCResponse::Pong(ping)));
|
||||
|
||||
self.send_rpc(peer_id, event);
|
||||
debug!(self.log, "Sending Pong"; "request_id" => id.1, "peer_id" => peer_id.to_string());
|
||||
let event = RPCCodedResponse::Success(RPCResponse::Pong(ping));
|
||||
self.eth2_rpc.send_response(peer_id, id, event);
|
||||
}
|
||||
|
||||
/// Sends a METADATA request to a peer.
|
||||
fn send_meta_data_request(&mut self, peer_id: PeerId) {
|
||||
let metadata_request =
|
||||
RPCSend::Request(RequestId::Behaviour, RPCRequest::MetaData(PhantomData));
|
||||
self.send_rpc(peer_id, metadata_request);
|
||||
let event = RPCRequest::MetaData(PhantomData);
|
||||
self.eth2_rpc
|
||||
.send_request(peer_id, RequestId::Behaviour, event);
|
||||
}
|
||||
|
||||
/// Sends a METADATA response to a peer.
|
||||
fn send_meta_data_response(&mut self, id: SubstreamId, peer_id: PeerId) {
|
||||
let metadata_response = RPCSend::Response(
|
||||
id,
|
||||
RPCCodedResponse::Success(RPCResponse::MetaData(self.meta_data.clone())),
|
||||
);
|
||||
self.send_rpc(peer_id, metadata_response);
|
||||
fn send_meta_data_response(&mut self, id: PeerRequestId, peer_id: PeerId) {
|
||||
let event = RPCCodedResponse::Success(RPCResponse::MetaData(self.meta_data.clone()));
|
||||
self.eth2_rpc.send_response(peer_id, id, event);
|
||||
}
|
||||
|
||||
/// Returns a reference to the peer manager to allow the swarm to notify the manager of peer
|
||||
@@ -635,7 +632,7 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
}
|
||||
|
||||
/// Convenience function to propagate a request.
|
||||
fn propagate_request(&mut self, id: SubstreamId, peer_id: PeerId, request: Request) {
|
||||
fn propagate_request(&mut self, id: PeerRequestId, peer_id: PeerId, request: Request) {
|
||||
self.events.push(BehaviourEvent::RequestReceived {
|
||||
peer_id,
|
||||
id,
|
||||
@@ -645,6 +642,7 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
|
||||
fn on_rpc_event(&mut self, message: RPCMessage<TSpec>) {
|
||||
let peer_id = message.peer_id;
|
||||
let handler_id = message.conn_id;
|
||||
// The METADATA and PING RPC responses are handled within the behaviour and not propagated
|
||||
match message.event {
|
||||
Err(handler_err) => {
|
||||
@@ -654,6 +652,10 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
proto,
|
||||
error,
|
||||
} => {
|
||||
if matches!(error, RPCError::HandlerRejected) {
|
||||
// this peer's request got canceled
|
||||
// TODO: cancel processing for this request
|
||||
}
|
||||
// Inform the peer manager of the error.
|
||||
// An inbound error here means we sent an error to the peer, or the stream
|
||||
// timed out.
|
||||
@@ -670,37 +672,48 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(RPCReceived::Request(id, request)) => match request {
|
||||
/* Behaviour managed protocols: Ping and Metadata */
|
||||
RPCRequest::Ping(ping) => {
|
||||
// inform the peer manager and send the response
|
||||
self.peer_manager.ping_request(&peer_id, ping.data);
|
||||
// send a ping response
|
||||
self.pong(id, peer_id);
|
||||
Ok(RPCReceived::Request(id, request)) => {
|
||||
let peer_request_id = (handler_id, id);
|
||||
match request {
|
||||
/* Behaviour managed protocols: Ping and Metadata */
|
||||
RPCRequest::Ping(ping) => {
|
||||
// inform the peer manager and send the response
|
||||
self.peer_manager.ping_request(&peer_id, ping.data);
|
||||
// send a ping response
|
||||
self.pong(peer_request_id, peer_id);
|
||||
}
|
||||
RPCRequest::MetaData(_) => {
|
||||
// send the requested meta-data
|
||||
self.send_meta_data_response((handler_id, id), peer_id);
|
||||
// TODO: inform the peer manager?
|
||||
}
|
||||
RPCRequest::Goodbye(reason) => {
|
||||
// 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));
|
||||
}
|
||||
/* Protocols propagated to the Network */
|
||||
RPCRequest::Status(msg) => {
|
||||
// inform the peer manager that we have received a status from a peer
|
||||
self.peer_manager.peer_statusd(&peer_id);
|
||||
// propagate the STATUS message upwards
|
||||
self.propagate_request(peer_request_id, peer_id, Request::Status(msg))
|
||||
}
|
||||
RPCRequest::BlocksByRange(req) => self.propagate_request(
|
||||
peer_request_id,
|
||||
peer_id,
|
||||
Request::BlocksByRange(req),
|
||||
),
|
||||
RPCRequest::BlocksByRoot(req) => {
|
||||
self.propagate_request(peer_request_id, peer_id, Request::BlocksByRoot(req))
|
||||
}
|
||||
}
|
||||
RPCRequest::MetaData(_) => {
|
||||
// send the requested meta-data
|
||||
self.send_meta_data_response(id, peer_id);
|
||||
// TODO: inform the peer manager?
|
||||
}
|
||||
/* Protocols propagated to the Network */
|
||||
RPCRequest::Status(msg) => {
|
||||
// inform the peer manager that we have received a status from a peer
|
||||
self.peer_manager.peer_statusd(&peer_id);
|
||||
// propagate the STATUS message upwards
|
||||
self.propagate_request(id, peer_id, Request::Status(msg))
|
||||
}
|
||||
RPCRequest::BlocksByRange(req) => {
|
||||
self.propagate_request(id, peer_id, Request::BlocksByRange(req))
|
||||
}
|
||||
RPCRequest::BlocksByRoot(req) => {
|
||||
self.propagate_request(id, peer_id, Request::BlocksByRoot(req))
|
||||
}
|
||||
RPCRequest::Goodbye(reason) => {
|
||||
// TODO: do not propagate
|
||||
self.propagate_request(id, peer_id, Request::Goodbye(reason));
|
||||
}
|
||||
},
|
||||
}
|
||||
Ok(RPCReceived::Response(id, resp)) => {
|
||||
match resp {
|
||||
/* Behaviour managed protocols */
|
||||
@@ -734,10 +747,19 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
}
|
||||
|
||||
/// Consumes the events list when polled.
|
||||
fn custom_poll<TBehaviourIn>(
|
||||
fn custom_poll(
|
||||
&mut self,
|
||||
cx: &mut Context,
|
||||
) -> Poll<NBAction<TBehaviourIn, BehaviourEvent<TSpec>>> {
|
||||
) -> Poll<NBAction<BehaviourHandlerIn<TSpec>, BehaviourEvent<TSpec>>> {
|
||||
// handle pending disconnections to perform
|
||||
if !self.peers_to_dc.is_empty() {
|
||||
return Poll::Ready(NBAction::NotifyHandler {
|
||||
peer_id: self.peers_to_dc.remove(0),
|
||||
handler: NotifyHandler::All,
|
||||
event: BehaviourHandlerIn::Shutdown(None),
|
||||
});
|
||||
}
|
||||
|
||||
// check the peer manager for events
|
||||
loop {
|
||||
match self.peer_manager.poll_next_unpin(cx) {
|
||||
@@ -756,11 +778,20 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
PeerManagerEvent::MetaData(peer_id) => {
|
||||
self.send_meta_data_request(peer_id);
|
||||
}
|
||||
PeerManagerEvent::_DisconnectPeer(_peer_id) => {
|
||||
//TODO: Implement
|
||||
}
|
||||
PeerManagerEvent::_BanPeer(_peer_id) => {
|
||||
//TODO: Implement
|
||||
PeerManagerEvent::DisconnectPeer(peer_id) => {
|
||||
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());
|
||||
// send one goodbye
|
||||
return Poll::Ready(NBAction::NotifyHandler {
|
||||
peer_id,
|
||||
handler: NotifyHandler::Any,
|
||||
event: BehaviourHandlerIn::Shutdown(Some((
|
||||
RequestId::Behaviour,
|
||||
RPCRequest::Goodbye(GoodbyeReason::Fault),
|
||||
))),
|
||||
});
|
||||
}
|
||||
},
|
||||
Poll::Pending => break,
|
||||
@@ -872,6 +903,9 @@ impl<TSpec: EthSpec> std::convert::From<Response<TSpec>> for RPCCodedResponse<TS
|
||||
}
|
||||
}
|
||||
|
||||
/// Identifier of requests sent by a peer.
|
||||
pub type PeerRequestId = (ConnectionId, SubstreamId);
|
||||
|
||||
/// The types of events than can be obtained from polling the behaviour.
|
||||
#[derive(Debug)]
|
||||
pub enum BehaviourEvent<TSpec: EthSpec> {
|
||||
@@ -888,7 +922,7 @@ pub enum BehaviourEvent<TSpec: EthSpec> {
|
||||
/// The peer that sent the request.
|
||||
peer_id: PeerId,
|
||||
/// Identifier of the request. All responses to this request must use this id.
|
||||
id: SubstreamId,
|
||||
id: PeerRequestId,
|
||||
/// Request the peer sent.
|
||||
request: Request,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user