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:
divma
2020-06-17 20:53:08 -05:00
committed by GitHub
parent 9db0c28051
commit 065251b701
12 changed files with 544 additions and 358 deletions

View File

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