mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-14 02:12:33 +00:00
Custom RPC request management for sync (#3029)
## Proposed Changes Make `lighthouse_network` generic over request ids, now usable by sync
This commit is contained in:
@@ -70,9 +70,16 @@ pub type PeerRequestId = (ConnectionId, SubstreamId);
|
||||
pub type SubscriptionFilter = MaxCountSubscriptionFilter<WhitelistSubscriptionFilter>;
|
||||
pub type Gossipsub = BaseGossipsub<SnappyTransform, SubscriptionFilter>;
|
||||
|
||||
/// Identifier of a request.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum RequestId<AppReqId> {
|
||||
Application(AppReqId),
|
||||
Behaviour,
|
||||
}
|
||||
|
||||
/// The types of events than can be obtained from polling the behaviour.
|
||||
#[derive(Debug)]
|
||||
pub enum BehaviourEvent<TSpec: EthSpec> {
|
||||
pub enum BehaviourEvent<AppReqId: ReqId, TSpec: EthSpec> {
|
||||
/// We have successfully dialed and connected to a peer.
|
||||
PeerConnectedOutgoing(PeerId),
|
||||
/// A peer has successfully dialed and connected to us.
|
||||
@@ -86,7 +93,7 @@ pub enum BehaviourEvent<TSpec: EthSpec> {
|
||||
/// An RPC Request that was sent failed.
|
||||
RPCFailed {
|
||||
/// The id of the failed request.
|
||||
id: RequestId,
|
||||
id: AppReqId,
|
||||
/// The peer to which this request was sent.
|
||||
peer_id: PeerId,
|
||||
},
|
||||
@@ -102,7 +109,7 @@ pub enum BehaviourEvent<TSpec: EthSpec> {
|
||||
/// Peer that sent the response.
|
||||
peer_id: PeerId,
|
||||
/// Id of the request to which the peer is responding.
|
||||
id: RequestId,
|
||||
id: AppReqId,
|
||||
/// Response the peer sent.
|
||||
response: Response<TSpec>,
|
||||
},
|
||||
@@ -134,16 +141,16 @@ enum InternalBehaviourMessage {
|
||||
/// behaviours.
|
||||
#[derive(NetworkBehaviour)]
|
||||
#[behaviour(
|
||||
out_event = "BehaviourEvent<TSpec>",
|
||||
out_event = "BehaviourEvent<AppReqId, TSpec>",
|
||||
poll_method = "poll",
|
||||
event_process = true
|
||||
)]
|
||||
pub struct Behaviour<TSpec: EthSpec> {
|
||||
pub struct Behaviour<AppReqId: ReqId, TSpec: EthSpec> {
|
||||
/* Sub-Behaviours */
|
||||
/// The routing pub-sub mechanism for eth2.
|
||||
gossipsub: Gossipsub,
|
||||
/// The Eth2 RPC specified in the wire-0 protocol.
|
||||
eth2_rpc: RPC<TSpec>,
|
||||
eth2_rpc: RPC<RequestId<AppReqId>, TSpec>,
|
||||
/// Discv5 Discovery protocol.
|
||||
discovery: Discovery<TSpec>,
|
||||
/// Keep regular connection to peers and disconnect if absent.
|
||||
@@ -156,7 +163,7 @@ pub struct Behaviour<TSpec: EthSpec> {
|
||||
/* Auxiliary Fields */
|
||||
/// The output events generated by this behaviour to be consumed in the swarm poll.
|
||||
#[behaviour(ignore)]
|
||||
events: VecDeque<BehaviourEvent<TSpec>>,
|
||||
events: VecDeque<BehaviourEvent<AppReqId, TSpec>>,
|
||||
/// Internal behaviour events, the NBAction type is composed of sub-behaviours, so we use a
|
||||
/// custom type here to avoid having to specify the concrete type.
|
||||
#[behaviour(ignore)]
|
||||
@@ -192,7 +199,7 @@ pub struct Behaviour<TSpec: EthSpec> {
|
||||
}
|
||||
|
||||
/// Implements the combined behaviour for the libp2p service.
|
||||
impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
impl<AppReqId: ReqId, TSpec: EthSpec> Behaviour<AppReqId, TSpec> {
|
||||
pub async fn new(
|
||||
local_key: &Keypair,
|
||||
ctx: ServiceContext<'_>,
|
||||
@@ -562,9 +569,9 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
/* Eth2 RPC behaviour functions */
|
||||
|
||||
/// Send a request to a peer over RPC.
|
||||
pub fn send_request(&mut self, peer_id: PeerId, request_id: RequestId, request: Request) {
|
||||
pub fn send_request(&mut self, peer_id: PeerId, request_id: AppReqId, request: Request) {
|
||||
self.eth2_rpc
|
||||
.send_request(peer_id, request_id, request.into())
|
||||
.send_request(peer_id, RequestId::Application(request_id), request.into())
|
||||
}
|
||||
|
||||
/// Send a successful response to a peer over RPC.
|
||||
@@ -718,12 +725,12 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
}
|
||||
|
||||
/// Sends a Ping request to the peer.
|
||||
fn ping(&mut self, id: RequestId, peer_id: PeerId) {
|
||||
fn ping(&mut self, peer_id: PeerId) {
|
||||
let ping = crate::rpc::Ping {
|
||||
data: *self.network_globals.local_metadata.read().seq_number(),
|
||||
};
|
||||
trace!(self.log, "Sending Ping"; "request_id" => id, "peer_id" => %peer_id);
|
||||
|
||||
trace!(self.log, "Sending Ping"; "peer_id" => %peer_id);
|
||||
let id = RequestId::Behaviour;
|
||||
self.eth2_rpc
|
||||
.send_request(peer_id, id, OutboundRequest::Ping(ping));
|
||||
}
|
||||
@@ -761,13 +768,19 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
|
||||
// RPC Propagation methods
|
||||
/// 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.add_event(BehaviourEvent::ResponseReceived {
|
||||
fn propagate_response(
|
||||
&mut self,
|
||||
id: RequestId<AppReqId>,
|
||||
peer_id: PeerId,
|
||||
response: Response<TSpec>,
|
||||
) {
|
||||
match id {
|
||||
RequestId::Application(id) => self.add_event(BehaviourEvent::ResponseReceived {
|
||||
peer_id,
|
||||
id,
|
||||
response,
|
||||
});
|
||||
}),
|
||||
RequestId::Behaviour => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -793,7 +806,7 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
}
|
||||
|
||||
/// Adds an event to the queue waking the current task to process it.
|
||||
fn add_event(&mut self, event: BehaviourEvent<TSpec>) {
|
||||
fn add_event(&mut self, event: BehaviourEvent<AppReqId, TSpec>) {
|
||||
self.events.push_back(event);
|
||||
if let Some(waker) = &self.waker {
|
||||
waker.wake_by_ref();
|
||||
@@ -869,7 +882,11 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
*/
|
||||
|
||||
// Gossipsub
|
||||
impl<TSpec: EthSpec> NetworkBehaviourEventProcess<GossipsubEvent> for Behaviour<TSpec> {
|
||||
impl<AppReqId, TSpec> NetworkBehaviourEventProcess<GossipsubEvent> for Behaviour<AppReqId, TSpec>
|
||||
where
|
||||
AppReqId: ReqId,
|
||||
TSpec: EthSpec,
|
||||
{
|
||||
fn inject_event(&mut self, event: GossipsubEvent) {
|
||||
match event {
|
||||
GossipsubEvent::Message {
|
||||
@@ -961,8 +978,13 @@ impl<TSpec: EthSpec> NetworkBehaviourEventProcess<GossipsubEvent> for Behaviour<
|
||||
}
|
||||
|
||||
// RPC
|
||||
impl<TSpec: EthSpec> NetworkBehaviourEventProcess<RPCMessage<TSpec>> for Behaviour<TSpec> {
|
||||
fn inject_event(&mut self, event: RPCMessage<TSpec>) {
|
||||
impl<AppReqId, TSpec> NetworkBehaviourEventProcess<RPCMessage<RequestId<AppReqId>, TSpec>>
|
||||
for Behaviour<AppReqId, TSpec>
|
||||
where
|
||||
AppReqId: ReqId,
|
||||
TSpec: EthSpec,
|
||||
{
|
||||
fn inject_event(&mut self, event: RPCMessage<RequestId<AppReqId>, TSpec>) {
|
||||
let peer_id = event.peer_id;
|
||||
|
||||
if !self.peer_manager.is_connected(&peer_id) {
|
||||
@@ -1006,7 +1028,7 @@ impl<TSpec: EthSpec> NetworkBehaviourEventProcess<RPCMessage<TSpec>> for Behavio
|
||||
ConnectionDirection::Outgoing,
|
||||
);
|
||||
// inform failures of requests comming outside the behaviour
|
||||
if !matches!(id, RequestId::Behaviour) {
|
||||
if let RequestId::Application(id) = id {
|
||||
self.add_event(BehaviourEvent::RPCFailed { peer_id, id });
|
||||
}
|
||||
}
|
||||
@@ -1090,7 +1112,11 @@ impl<TSpec: EthSpec> NetworkBehaviourEventProcess<RPCMessage<TSpec>> for Behavio
|
||||
}
|
||||
|
||||
// Discovery
|
||||
impl<TSpec: EthSpec> NetworkBehaviourEventProcess<DiscoveryEvent> for Behaviour<TSpec> {
|
||||
impl<AppReqId, TSpec> NetworkBehaviourEventProcess<DiscoveryEvent> for Behaviour<AppReqId, TSpec>
|
||||
where
|
||||
AppReqId: ReqId,
|
||||
TSpec: EthSpec,
|
||||
{
|
||||
fn inject_event(&mut self, event: DiscoveryEvent) {
|
||||
match event {
|
||||
DiscoveryEvent::SocketUpdated(socket_addr) => {
|
||||
@@ -1119,7 +1145,11 @@ impl<TSpec: EthSpec> NetworkBehaviourEventProcess<DiscoveryEvent> for Behaviour<
|
||||
}
|
||||
|
||||
// Identify
|
||||
impl<TSpec: EthSpec> NetworkBehaviourEventProcess<IdentifyEvent> for Behaviour<TSpec> {
|
||||
impl<AppReqId, TSpec> NetworkBehaviourEventProcess<IdentifyEvent> for Behaviour<AppReqId, TSpec>
|
||||
where
|
||||
TSpec: EthSpec,
|
||||
AppReqId: ReqId,
|
||||
{
|
||||
fn inject_event(&mut self, event: IdentifyEvent) {
|
||||
match event {
|
||||
IdentifyEvent::Received { peer_id, mut info } => {
|
||||
@@ -1140,15 +1170,20 @@ impl<TSpec: EthSpec> NetworkBehaviourEventProcess<IdentifyEvent> for Behaviour<T
|
||||
}
|
||||
}
|
||||
|
||||
impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
type BehaviourHandler<AppReqId, TSpec> =
|
||||
<Behaviour<AppReqId, TSpec> as NetworkBehaviour>::ConnectionHandler;
|
||||
|
||||
impl<AppReqId, TSpec> Behaviour<AppReqId, TSpec>
|
||||
where
|
||||
TSpec: EthSpec,
|
||||
AppReqId: ReqId,
|
||||
{
|
||||
/// Consumes the events list and drives the Lighthouse global NetworkBehaviour.
|
||||
fn poll(
|
||||
&mut self,
|
||||
cx: &mut Context,
|
||||
_: &mut impl PollParameters,
|
||||
) -> Poll<
|
||||
NBAction<BehaviourEvent<TSpec>, <Behaviour<TSpec> as NetworkBehaviour>::ConnectionHandler>,
|
||||
> {
|
||||
) -> Poll<NBAction<BehaviourEvent<AppReqId, TSpec>, BehaviourHandler<AppReqId, TSpec>>> {
|
||||
if let Some(waker) = &self.waker {
|
||||
if waker.will_wake(cx.waker()) {
|
||||
self.waker = Some(cx.waker().clone());
|
||||
@@ -1207,7 +1242,9 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<TSpec: EthSpec> NetworkBehaviourEventProcess<PeerManagerEvent> for Behaviour<TSpec> {
|
||||
impl<AppReqId: ReqId, TSpec: EthSpec> NetworkBehaviourEventProcess<PeerManagerEvent>
|
||||
for Behaviour<AppReqId, TSpec>
|
||||
{
|
||||
fn inject_event(&mut self, event: PeerManagerEvent) {
|
||||
match event {
|
||||
PeerManagerEvent::PeerConnectedIncoming(peer_id) => {
|
||||
@@ -1242,7 +1279,7 @@ impl<TSpec: EthSpec> NetworkBehaviourEventProcess<PeerManagerEvent> for Behaviou
|
||||
}
|
||||
PeerManagerEvent::Ping(peer_id) => {
|
||||
// send a ping request to this peer
|
||||
self.ping(RequestId::Behaviour, peer_id);
|
||||
self.ping(peer_id);
|
||||
}
|
||||
PeerManagerEvent::MetaData(peer_id) => {
|
||||
self.send_meta_data_request(peer_id);
|
||||
@@ -1251,7 +1288,8 @@ impl<TSpec: EthSpec> NetworkBehaviourEventProcess<PeerManagerEvent> for Behaviou
|
||||
debug!(self.log, "Peer Manager disconnecting peer";
|
||||
"peer_id" => %peer_id, "reason" => %reason);
|
||||
// send one goodbye
|
||||
self.eth2_rpc.shutdown(peer_id, reason);
|
||||
self.eth2_rpc
|
||||
.shutdown(peer_id, RequestId::Behaviour, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1335,3 +1373,19 @@ pub fn save_metadata_to_disk<E: EthSpec>(dir: &Path, metadata: MetaData<E>, log:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<AppReqId: std::fmt::Debug> slog::Value for RequestId<AppReqId> {
|
||||
fn serialize(
|
||||
&self,
|
||||
record: &slog::Record,
|
||||
key: slog::Key,
|
||||
serializer: &mut dyn slog::Serializer,
|
||||
) -> slog::Result {
|
||||
match self {
|
||||
RequestId::Behaviour => slog::Value::serialize("Behaviour", record, key, serializer),
|
||||
RequestId::Application(ref id) => {
|
||||
slog::Value::serialize(&format_args!("{:?}", id), record, key, serializer)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,9 +110,13 @@ impl<TSpec: EthSpec> NetworkBehaviour for PeerManager<TSpec> {
|
||||
_connection_id: &ConnectionId,
|
||||
endpoint: &ConnectedPoint,
|
||||
_failed_addresses: Option<&Vec<Multiaddr>>,
|
||||
_other_established: usize,
|
||||
other_established: usize,
|
||||
) {
|
||||
debug!(self.log, "Connection established"; "peer_id" => %peer_id, "connection" => ?endpoint.to_endpoint());
|
||||
if other_established == 0 {
|
||||
self.events.push(PeerManagerEvent::MetaData(*peer_id));
|
||||
}
|
||||
|
||||
// Check NAT if metrics are enabled
|
||||
if self.network_globals.local_enr.read().udp().is_some() {
|
||||
metrics::check_nat();
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
#![allow(clippy::type_complexity)]
|
||||
#![allow(clippy::cognitive_complexity)]
|
||||
|
||||
use super::methods::{
|
||||
GoodbyeReason, RPCCodedResponse, RPCResponseErrorCode, RequestId, ResponseTermination,
|
||||
};
|
||||
use super::methods::{GoodbyeReason, RPCCodedResponse, RPCResponseErrorCode, ResponseTermination};
|
||||
use super::outbound::OutboundRequestContainer;
|
||||
use super::protocol::{max_rpc_size, InboundRequest, Protocol, RPCError, RPCProtocol};
|
||||
use super::{RPCReceived, RPCSend};
|
||||
use super::{RPCReceived, RPCSend, ReqId};
|
||||
use crate::rpc::outbound::{OutboundFramed, OutboundRequest};
|
||||
use crate::rpc::protocol::InboundFramed;
|
||||
use fnv::FnvHashMap;
|
||||
@@ -49,11 +47,11 @@ pub struct SubstreamId(usize);
|
||||
type InboundSubstream<TSpec> = InboundFramed<NegotiatedSubstream, TSpec>;
|
||||
|
||||
/// Events the handler emits to the behaviour.
|
||||
type HandlerEvent<T> = Result<RPCReceived<T>, HandlerErr>;
|
||||
pub type HandlerEvent<Id, T> = Result<RPCReceived<Id, T>, HandlerErr<Id>>;
|
||||
|
||||
/// An error encountered by the handler.
|
||||
#[derive(Debug)]
|
||||
pub enum HandlerErr {
|
||||
pub enum HandlerErr<Id> {
|
||||
/// An error occurred for this peer's request. This can occur during protocol negotiation,
|
||||
/// message passing, or if the handler identifies that we are sending an error response to the peer.
|
||||
Inbound {
|
||||
@@ -69,7 +67,7 @@ pub enum HandlerErr {
|
||||
/// indicates an error.
|
||||
Outbound {
|
||||
/// Application-given Id of the request for which an error occurred.
|
||||
id: RequestId,
|
||||
id: Id,
|
||||
/// Information of the protocol.
|
||||
proto: Protocol,
|
||||
/// The error that occurred.
|
||||
@@ -78,7 +76,7 @@ pub enum HandlerErr {
|
||||
}
|
||||
|
||||
/// Implementation of `ConnectionHandler` for the RPC protocol.
|
||||
pub struct RPCHandler<TSpec>
|
||||
pub struct RPCHandler<Id, TSpec>
|
||||
where
|
||||
TSpec: EthSpec,
|
||||
{
|
||||
@@ -86,10 +84,10 @@ where
|
||||
listen_protocol: SubstreamProtocol<RPCProtocol<TSpec>, ()>,
|
||||
|
||||
/// Queue of events to produce in `poll()`.
|
||||
events_out: SmallVec<[HandlerEvent<TSpec>; 4]>,
|
||||
events_out: SmallVec<[HandlerEvent<Id, TSpec>; 4]>,
|
||||
|
||||
/// Queue of outbound substreams to open.
|
||||
dial_queue: SmallVec<[(RequestId, OutboundRequest<TSpec>); 4]>,
|
||||
dial_queue: SmallVec<[(Id, OutboundRequest<TSpec>); 4]>,
|
||||
|
||||
/// Current number of concurrent outbound substreams being opened.
|
||||
dial_negotiated: u32,
|
||||
@@ -101,7 +99,7 @@ where
|
||||
inbound_substreams_delay: DelayQueue<SubstreamId>,
|
||||
|
||||
/// Map of outbound substreams that need to be driven to completion.
|
||||
outbound_substreams: FnvHashMap<SubstreamId, OutboundInfo<TSpec>>,
|
||||
outbound_substreams: FnvHashMap<SubstreamId, OutboundInfo<Id, TSpec>>,
|
||||
|
||||
/// Inbound substream `DelayQueue` which keeps track of when an inbound substream will timeout.
|
||||
outbound_substreams_delay: DelayQueue<SubstreamId>,
|
||||
@@ -163,7 +161,7 @@ struct InboundInfo<TSpec: EthSpec> {
|
||||
}
|
||||
|
||||
/// Contains the information the handler keeps on established outbound substreams.
|
||||
struct OutboundInfo<TSpec: EthSpec> {
|
||||
struct OutboundInfo<Id, TSpec: EthSpec> {
|
||||
/// State of the substream.
|
||||
state: OutboundSubstreamState<TSpec>,
|
||||
/// Key to keep track of the substream's timeout via `self.outbound_substreams_delay`.
|
||||
@@ -172,8 +170,8 @@ struct OutboundInfo<TSpec: EthSpec> {
|
||||
proto: Protocol,
|
||||
/// Number of chunks to be seen from the peer's response.
|
||||
remaining_chunks: Option<u64>,
|
||||
/// `RequestId` as given by the application that sent the request.
|
||||
req_id: RequestId,
|
||||
/// `Id` as given by the application that sent the request.
|
||||
req_id: Id,
|
||||
}
|
||||
|
||||
/// State of an inbound substream connection.
|
||||
@@ -204,7 +202,7 @@ pub enum OutboundSubstreamState<TSpec: EthSpec> {
|
||||
Poisoned,
|
||||
}
|
||||
|
||||
impl<TSpec> RPCHandler<TSpec>
|
||||
impl<Id, TSpec> RPCHandler<Id, TSpec>
|
||||
where
|
||||
TSpec: EthSpec,
|
||||
{
|
||||
@@ -235,7 +233,7 @@ where
|
||||
|
||||
/// Initiates the handler's shutdown process, sending an optional Goodbye message to the
|
||||
/// peer.
|
||||
fn shutdown(&mut self, goodbye_reason: Option<GoodbyeReason>) {
|
||||
fn shutdown(&mut self, goodbye_reason: Option<(Id, GoodbyeReason)>) {
|
||||
if matches!(self.state, HandlerState::Active) {
|
||||
if !self.dial_queue.is_empty() {
|
||||
debug!(self.log, "Starting handler shutdown"; "unsent_queued_requests" => self.dial_queue.len());
|
||||
@@ -250,9 +248,8 @@ where
|
||||
}
|
||||
|
||||
// Queue our goodbye message.
|
||||
if let Some(reason) = goodbye_reason {
|
||||
self.dial_queue
|
||||
.push((RequestId::Router, OutboundRequest::Goodbye(reason)));
|
||||
if let Some((id, reason)) = goodbye_reason {
|
||||
self.dial_queue.push((id, OutboundRequest::Goodbye(reason)));
|
||||
}
|
||||
|
||||
self.state = HandlerState::ShuttingDown(Box::new(sleep_until(
|
||||
@@ -262,7 +259,7 @@ where
|
||||
}
|
||||
|
||||
/// Opens an outbound substream with a request.
|
||||
fn send_request(&mut self, id: RequestId, req: OutboundRequest<TSpec>) {
|
||||
fn send_request(&mut self, id: Id, req: OutboundRequest<TSpec>) {
|
||||
match self.state {
|
||||
HandlerState::Active => {
|
||||
self.dial_queue.push((id, req));
|
||||
@@ -310,16 +307,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<TSpec> ConnectionHandler for RPCHandler<TSpec>
|
||||
impl<Id, TSpec> ConnectionHandler for RPCHandler<Id, TSpec>
|
||||
where
|
||||
TSpec: EthSpec,
|
||||
Id: ReqId,
|
||||
{
|
||||
type InEvent = RPCSend<TSpec>;
|
||||
type OutEvent = HandlerEvent<TSpec>;
|
||||
type InEvent = RPCSend<Id, TSpec>;
|
||||
type OutEvent = HandlerEvent<Id, TSpec>;
|
||||
type Error = RPCError;
|
||||
type InboundProtocol = RPCProtocol<TSpec>;
|
||||
type OutboundProtocol = OutboundRequestContainer<TSpec>;
|
||||
type OutboundOpenInfo = (RequestId, OutboundRequest<TSpec>); // Keep track of the id and the request
|
||||
type OutboundOpenInfo = (Id, OutboundRequest<TSpec>); // Keep track of the id and the request
|
||||
type InboundOpenInfo = ();
|
||||
|
||||
fn listen_protocol(&self) -> SubstreamProtocol<Self::InboundProtocol, ()> {
|
||||
@@ -432,7 +430,7 @@ where
|
||||
match rpc_event {
|
||||
RPCSend::Request(id, req) => self.send_request(id, req),
|
||||
RPCSend::Response(inbound_id, response) => self.send_response(inbound_id, response),
|
||||
RPCSend::Shutdown(reason) => self.shutdown(Some(reason)),
|
||||
RPCSend::Shutdown(id, reason) => self.shutdown(Some((id, reason))),
|
||||
}
|
||||
// In any case, we need the handler to process the event.
|
||||
if let Some(waker) = &self.waker {
|
||||
|
||||
@@ -56,17 +56,6 @@ impl ToString for ErrorType {
|
||||
|
||||
/* Requests */
|
||||
|
||||
/// Identifier of a request.
|
||||
///
|
||||
// NOTE: The handler stores the `RequestId` to inform back of responses and errors, but it's execution
|
||||
// is independent of the contents on this type.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum RequestId {
|
||||
Router,
|
||||
Sync(usize),
|
||||
Behaviour,
|
||||
}
|
||||
|
||||
/// The STATUS request/response handshake message.
|
||||
#[derive(Encode, Decode, Clone, Debug, PartialEq)]
|
||||
pub struct StatusMessage {
|
||||
@@ -432,18 +421,3 @@ impl slog::KV for StatusMessage {
|
||||
slog::Result::Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl slog::Value for RequestId {
|
||||
fn serialize(
|
||||
&self,
|
||||
record: &slog::Record,
|
||||
key: slog::Key,
|
||||
serializer: &mut dyn slog::Serializer,
|
||||
) -> slog::Result {
|
||||
match self {
|
||||
RequestId::Behaviour => slog::Value::serialize("Behaviour", record, key, serializer),
|
||||
RequestId::Router => slog::Value::serialize("Router", record, key, serializer),
|
||||
RequestId::Sync(ref id) => slog::Value::serialize(id, record, key, serializer),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
//! syncing.
|
||||
|
||||
use futures::future::FutureExt;
|
||||
use handler::RPCHandler;
|
||||
use libp2p::core::{connection::ConnectionId, ConnectedPoint};
|
||||
use handler::{HandlerEvent, RPCHandler};
|
||||
use libp2p::core::connection::ConnectionId;
|
||||
use libp2p::swarm::{
|
||||
handler::ConnectionHandler, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler,
|
||||
PollParameters, SubstreamProtocol,
|
||||
};
|
||||
use libp2p::{Multiaddr, PeerId};
|
||||
use libp2p::PeerId;
|
||||
use rate_limiter::{RPCRateLimiter as RateLimiter, RPCRateLimiterBuilder, RateLimitedErr};
|
||||
use slog::{crit, debug, o};
|
||||
use std::marker::PhantomData;
|
||||
@@ -27,7 +27,7 @@ pub(crate) use protocol::{InboundRequest, RPCProtocol};
|
||||
pub use handler::SubstreamId;
|
||||
pub use methods::{
|
||||
BlocksByRangeRequest, BlocksByRootRequest, GoodbyeReason, MaxRequestBlocks,
|
||||
RPCResponseErrorCode, RequestId, ResponseTermination, StatusMessage, MAX_REQUEST_BLOCKS,
|
||||
RPCResponseErrorCode, ResponseTermination, StatusMessage, MAX_REQUEST_BLOCKS,
|
||||
};
|
||||
pub(crate) use outbound::OutboundRequest;
|
||||
pub use protocol::{max_rpc_size, Protocol, RPCError};
|
||||
@@ -39,14 +39,18 @@ mod outbound;
|
||||
mod protocol;
|
||||
mod rate_limiter;
|
||||
|
||||
/// Composite trait for a request id.
|
||||
pub trait ReqId: Send + 'static + std::fmt::Debug + Copy + Clone {}
|
||||
impl<T> ReqId for T where T: Send + 'static + std::fmt::Debug + Copy + Clone {}
|
||||
|
||||
/// RPC events sent from Lighthouse.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum RPCSend<TSpec: EthSpec> {
|
||||
pub enum RPCSend<Id, TSpec: EthSpec> {
|
||||
/// A request sent from Lighthouse.
|
||||
///
|
||||
/// The `RequestId` is given by the application making the request. These
|
||||
/// The `Id` is given by the application making the request. These
|
||||
/// go over *outbound* connections.
|
||||
Request(RequestId, OutboundRequest<TSpec>),
|
||||
Request(Id, OutboundRequest<TSpec>),
|
||||
/// A response sent from Lighthouse.
|
||||
///
|
||||
/// The `SubstreamId` must correspond to the RPC-given ID of the original request received from the
|
||||
@@ -54,12 +58,12 @@ pub enum RPCSend<TSpec: EthSpec> {
|
||||
/// connections.
|
||||
Response(SubstreamId, RPCCodedResponse<TSpec>),
|
||||
/// Lighthouse has requested to terminate the connection with a goodbye message.
|
||||
Shutdown(GoodbyeReason),
|
||||
Shutdown(Id, GoodbyeReason),
|
||||
}
|
||||
|
||||
/// RPC events received from outside Lighthouse.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum RPCReceived<T: EthSpec> {
|
||||
pub enum RPCReceived<Id, T: EthSpec> {
|
||||
/// A request received from the outside.
|
||||
///
|
||||
/// The `SubstreamId` is given by the `RPCHandler` as it identifies this request with the
|
||||
@@ -67,47 +71,47 @@ pub enum RPCReceived<T: EthSpec> {
|
||||
Request(SubstreamId, InboundRequest<T>),
|
||||
/// A response received from the outside.
|
||||
///
|
||||
/// The `RequestId` corresponds to the application given ID of the original request sent to the
|
||||
/// The `Id` corresponds to the application given ID of the original request sent to the
|
||||
/// peer. The second parameter is a single chunk of a response. These go over *outbound*
|
||||
/// connections.
|
||||
Response(RequestId, RPCResponse<T>),
|
||||
Response(Id, RPCResponse<T>),
|
||||
/// Marks a request as completed
|
||||
EndOfStream(RequestId, ResponseTermination),
|
||||
EndOfStream(Id, ResponseTermination),
|
||||
}
|
||||
|
||||
impl<T: EthSpec> std::fmt::Display for RPCSend<T> {
|
||||
impl<T: EthSpec, Id: std::fmt::Debug> std::fmt::Display for RPCSend<Id, T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
RPCSend::Request(id, req) => write!(f, "RPC Request(id: {:?}, {})", id, req),
|
||||
RPCSend::Response(id, res) => write!(f, "RPC Response(id: {:?}, {})", id, res),
|
||||
RPCSend::Shutdown(reason) => write!(f, "Sending Goodbye: {}", reason),
|
||||
RPCSend::Shutdown(_id, reason) => write!(f, "Sending Goodbye: {}", reason),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Messages sent to the user from the RPC protocol.
|
||||
pub struct RPCMessage<TSpec: EthSpec> {
|
||||
pub struct RPCMessage<Id, TSpec: EthSpec> {
|
||||
/// The peer that sent the message.
|
||||
pub peer_id: PeerId,
|
||||
/// Handler managing this message.
|
||||
pub conn_id: ConnectionId,
|
||||
/// The message that was sent.
|
||||
pub event: <RPCHandler<TSpec> as ConnectionHandler>::OutEvent,
|
||||
pub event: HandlerEvent<Id, TSpec>,
|
||||
}
|
||||
|
||||
/// Implements the libp2p `NetworkBehaviour` trait and therefore manages network-level
|
||||
/// logic.
|
||||
pub struct RPC<TSpec: EthSpec> {
|
||||
pub struct RPC<Id: ReqId, TSpec: EthSpec> {
|
||||
/// Rate limiter
|
||||
limiter: RateLimiter,
|
||||
/// Queue of events to be processed.
|
||||
events: Vec<NetworkBehaviourAction<RPCMessage<TSpec>, RPCHandler<TSpec>>>,
|
||||
events: Vec<NetworkBehaviourAction<RPCMessage<Id, TSpec>, RPCHandler<Id, TSpec>>>,
|
||||
fork_context: Arc<ForkContext>,
|
||||
/// Slog logger for RPC behaviour.
|
||||
log: slog::Logger,
|
||||
}
|
||||
|
||||
impl<TSpec: EthSpec> RPC<TSpec> {
|
||||
impl<Id: ReqId, TSpec: EthSpec> RPC<Id, TSpec> {
|
||||
pub fn new(fork_context: Arc<ForkContext>, log: slog::Logger) -> Self {
|
||||
let log = log.new(o!("service" => "libp2p_rpc"));
|
||||
let limiter = RPCRateLimiterBuilder::new()
|
||||
@@ -150,12 +154,7 @@ impl<TSpec: EthSpec> RPC<TSpec> {
|
||||
/// Submits an RPC request.
|
||||
///
|
||||
/// The peer must be connected for this to succeed.
|
||||
pub fn send_request(
|
||||
&mut self,
|
||||
peer_id: PeerId,
|
||||
request_id: RequestId,
|
||||
event: OutboundRequest<TSpec>,
|
||||
) {
|
||||
pub fn send_request(&mut self, peer_id: PeerId, request_id: Id, event: OutboundRequest<TSpec>) {
|
||||
self.events.push(NetworkBehaviourAction::NotifyHandler {
|
||||
peer_id,
|
||||
handler: NotifyHandler::Any,
|
||||
@@ -165,21 +164,22 @@ impl<TSpec: EthSpec> RPC<TSpec> {
|
||||
|
||||
/// Lighthouse wishes to disconnect from this peer by sending a Goodbye message. This
|
||||
/// gracefully terminates the RPC behaviour with a goodbye message.
|
||||
pub fn shutdown(&mut self, peer_id: PeerId, reason: GoodbyeReason) {
|
||||
pub fn shutdown(&mut self, peer_id: PeerId, id: Id, reason: GoodbyeReason) {
|
||||
self.events.push(NetworkBehaviourAction::NotifyHandler {
|
||||
peer_id,
|
||||
handler: NotifyHandler::Any,
|
||||
event: RPCSend::Shutdown(reason),
|
||||
event: RPCSend::Shutdown(id, reason),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<TSpec> NetworkBehaviour for RPC<TSpec>
|
||||
impl<Id, TSpec> NetworkBehaviour for RPC<Id, TSpec>
|
||||
where
|
||||
TSpec: EthSpec,
|
||||
Id: ReqId,
|
||||
{
|
||||
type ConnectionHandler = RPCHandler<TSpec>;
|
||||
type OutEvent = RPCMessage<TSpec>;
|
||||
type ConnectionHandler = RPCHandler<Id, TSpec>;
|
||||
type OutEvent = RPCMessage<Id, TSpec>;
|
||||
|
||||
fn new_handler(&mut self) -> Self::ConnectionHandler {
|
||||
RPCHandler::new(
|
||||
@@ -196,33 +196,6 @@ where
|
||||
)
|
||||
}
|
||||
|
||||
// handled by discovery
|
||||
fn addresses_of_peer(&mut self, _peer_id: &PeerId) -> Vec<Multiaddr> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
// Use connection established/closed instead of these currently
|
||||
fn inject_connection_established(
|
||||
&mut self,
|
||||
peer_id: &PeerId,
|
||||
_connection_id: &ConnectionId,
|
||||
_endpoint: &ConnectedPoint,
|
||||
_failed_addresses: Option<&Vec<Multiaddr>>,
|
||||
other_established: usize,
|
||||
) {
|
||||
if other_established == 0 {
|
||||
// find the peer's meta-data
|
||||
debug!(self.log, "Requesting new peer's metadata"; "peer_id" => %peer_id);
|
||||
let rpc_event =
|
||||
RPCSend::Request(RequestId::Behaviour, OutboundRequest::MetaData(PhantomData));
|
||||
self.events.push(NetworkBehaviourAction::NotifyHandler {
|
||||
peer_id: *peer_id,
|
||||
handler: NotifyHandler::Any,
|
||||
event: rpc_event,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn inject_event(
|
||||
&mut self,
|
||||
peer_id: PeerId,
|
||||
|
||||
@@ -4,9 +4,7 @@ use crate::behaviour::{
|
||||
use crate::config::NetworkLoad;
|
||||
use crate::discovery::enr;
|
||||
use crate::multiaddr::Protocol;
|
||||
use crate::rpc::{
|
||||
GoodbyeReason, MetaData, MetaDataV1, MetaDataV2, RPCResponseErrorCode, RequestId,
|
||||
};
|
||||
use crate::rpc::{GoodbyeReason, MetaData, MetaDataV1, MetaDataV2, RPCResponseErrorCode, ReqId};
|
||||
use crate::types::{error, EnrAttestationBitfield, EnrSyncCommitteeBitfield, GossipKind};
|
||||
use crate::EnrExt;
|
||||
use crate::{NetworkConfig, NetworkGlobals, PeerAction, ReportSource};
|
||||
@@ -42,9 +40,9 @@ pub const METADATA_FILENAME: &str = "metadata";
|
||||
///
|
||||
/// This is a subset of the events that a libp2p swarm emits.
|
||||
#[derive(Debug)]
|
||||
pub enum Libp2pEvent<TSpec: EthSpec> {
|
||||
pub enum Libp2pEvent<AppReqId: ReqId, TSpec: EthSpec> {
|
||||
/// A behaviour event
|
||||
Behaviour(BehaviourEvent<TSpec>),
|
||||
Behaviour(BehaviourEvent<AppReqId, TSpec>),
|
||||
/// A new listening address has been established.
|
||||
NewListenAddr(Multiaddr),
|
||||
/// We reached zero listening addresses.
|
||||
@@ -52,9 +50,9 @@ pub enum Libp2pEvent<TSpec: EthSpec> {
|
||||
}
|
||||
|
||||
/// The configuration and state of the libp2p components for the beacon node.
|
||||
pub struct Service<TSpec: EthSpec> {
|
||||
pub struct Service<AppReqId: ReqId, TSpec: EthSpec> {
|
||||
/// The libp2p Swarm handler.
|
||||
pub swarm: Swarm<Behaviour<TSpec>>,
|
||||
pub swarm: Swarm<Behaviour<AppReqId, TSpec>>,
|
||||
/// The bandwidth logger for the underlying libp2p transport.
|
||||
pub bandwidth: Arc<BandwidthSinks>,
|
||||
/// This node's PeerId.
|
||||
@@ -71,7 +69,7 @@ pub struct Context<'a> {
|
||||
pub gossipsub_registry: Option<&'a mut Registry>,
|
||||
}
|
||||
|
||||
impl<TSpec: EthSpec> Service<TSpec> {
|
||||
impl<AppReqId: ReqId, TSpec: EthSpec> Service<AppReqId, TSpec> {
|
||||
pub async fn new(
|
||||
executor: task_executor::TaskExecutor,
|
||||
ctx: Context<'_>,
|
||||
@@ -260,7 +258,7 @@ impl<TSpec: EthSpec> Service<TSpec> {
|
||||
}
|
||||
|
||||
/// Sends a request to a peer, with a given Id.
|
||||
pub fn send_request(&mut self, peer_id: PeerId, request_id: RequestId, request: Request) {
|
||||
pub fn send_request(&mut self, peer_id: PeerId, request_id: AppReqId, request: Request) {
|
||||
self.swarm
|
||||
.behaviour_mut()
|
||||
.send_request(peer_id, request_id, request);
|
||||
@@ -307,7 +305,7 @@ impl<TSpec: EthSpec> Service<TSpec> {
|
||||
.send_successful_response(peer_id, id, response);
|
||||
}
|
||||
|
||||
pub async fn next_event(&mut self) -> Libp2pEvent<TSpec> {
|
||||
pub async fn next_event(&mut self) -> Libp2pEvent<AppReqId, TSpec> {
|
||||
loop {
|
||||
match self.swarm.select_next_some().await {
|
||||
SwarmEvent::Behaviour(behaviour) => {
|
||||
|
||||
@@ -21,6 +21,8 @@ pub mod behaviour;
|
||||
pub mod swarm;
|
||||
|
||||
type E = MinimalEthSpec;
|
||||
type ReqId = usize;
|
||||
|
||||
use tempfile::Builder as TempBuilder;
|
||||
|
||||
/// Returns a dummy fork context
|
||||
@@ -33,10 +35,10 @@ pub fn fork_context() -> ForkContext {
|
||||
ForkContext::new::<E>(types::Slot::new(0), Hash256::zero(), &chain_spec)
|
||||
}
|
||||
|
||||
pub struct Libp2pInstance(LibP2PService<E>, exit_future::Signal);
|
||||
pub struct Libp2pInstance(LibP2PService<ReqId, E>, exit_future::Signal);
|
||||
|
||||
impl std::ops::Deref for Libp2pInstance {
|
||||
type Target = LibP2PService<E>;
|
||||
type Target = LibP2PService<ReqId, E>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
@@ -113,7 +115,7 @@ pub async fn build_libp2p_instance(
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_enr(node: &LibP2PService<E>) -> Enr {
|
||||
pub fn get_enr(node: &LibP2PService<ReqId, E>) -> Enr {
|
||||
node.swarm.behaviour().local_enr()
|
||||
}
|
||||
|
||||
|
||||
@@ -88,15 +88,14 @@ fn test_status_rpc() {
|
||||
Libp2pEvent::Behaviour(BehaviourEvent::PeerConnectedOutgoing(peer_id)) => {
|
||||
// Send a STATUS message
|
||||
debug!(log, "Sending RPC");
|
||||
sender.swarm.behaviour_mut().send_request(
|
||||
peer_id,
|
||||
RequestId::Sync(10),
|
||||
rpc_request.clone(),
|
||||
);
|
||||
sender
|
||||
.swarm
|
||||
.behaviour_mut()
|
||||
.send_request(peer_id, 10, rpc_request.clone());
|
||||
}
|
||||
Libp2pEvent::Behaviour(BehaviourEvent::ResponseReceived {
|
||||
peer_id: _,
|
||||
id: RequestId::Sync(10),
|
||||
id: 10,
|
||||
response,
|
||||
}) => {
|
||||
// Should receive the RPC response
|
||||
@@ -186,7 +185,7 @@ fn test_blocks_by_range_chunked_rpc() {
|
||||
|
||||
// keep count of the number of messages received
|
||||
let mut messages_received = 0;
|
||||
let request_id = RequestId::Sync(messages_to_send as usize);
|
||||
let request_id = messages_to_send as usize;
|
||||
// build the sender future
|
||||
let sender_future = async {
|
||||
loop {
|
||||
@@ -313,7 +312,7 @@ fn test_blocks_by_range_over_limit() {
|
||||
let signed_full_block = SignedBeaconBlock::from_block(full_block, Signature::empty());
|
||||
let rpc_response_merge_large = Response::BlocksByRange(Some(Box::new(signed_full_block)));
|
||||
|
||||
let request_id = RequestId::Sync(messages_to_send as usize);
|
||||
let request_id = messages_to_send as usize;
|
||||
// build the sender future
|
||||
let sender_future = async {
|
||||
loop {
|
||||
@@ -413,7 +412,7 @@ fn test_blocks_by_range_chunked_rpc_terminates_correctly() {
|
||||
|
||||
// keep count of the number of messages received
|
||||
let mut messages_received: u64 = 0;
|
||||
let request_id = RequestId::Sync(messages_to_send as usize);
|
||||
let request_id = messages_to_send as usize;
|
||||
// build the sender future
|
||||
let sender_future = async {
|
||||
loop {
|
||||
@@ -553,15 +552,14 @@ fn test_blocks_by_range_single_empty_rpc() {
|
||||
Libp2pEvent::Behaviour(BehaviourEvent::PeerConnectedOutgoing(peer_id)) => {
|
||||
// Send a STATUS message
|
||||
debug!(log, "Sending RPC");
|
||||
sender.swarm.behaviour_mut().send_request(
|
||||
peer_id,
|
||||
RequestId::Sync(10),
|
||||
rpc_request.clone(),
|
||||
);
|
||||
sender
|
||||
.swarm
|
||||
.behaviour_mut()
|
||||
.send_request(peer_id, 10, rpc_request.clone());
|
||||
}
|
||||
Libp2pEvent::Behaviour(BehaviourEvent::ResponseReceived {
|
||||
peer_id: _,
|
||||
id: RequestId::Sync(10),
|
||||
id: 10,
|
||||
response,
|
||||
}) => match response {
|
||||
Response::BlocksByRange(Some(_)) => {
|
||||
@@ -679,15 +677,14 @@ fn test_blocks_by_root_chunked_rpc() {
|
||||
Libp2pEvent::Behaviour(BehaviourEvent::PeerConnectedOutgoing(peer_id)) => {
|
||||
// Send a STATUS message
|
||||
debug!(log, "Sending RPC");
|
||||
sender.swarm.behaviour_mut().send_request(
|
||||
peer_id,
|
||||
RequestId::Sync(6),
|
||||
rpc_request.clone(),
|
||||
);
|
||||
sender
|
||||
.swarm
|
||||
.behaviour_mut()
|
||||
.send_request(peer_id, 6, rpc_request.clone());
|
||||
}
|
||||
Libp2pEvent::Behaviour(BehaviourEvent::ResponseReceived {
|
||||
peer_id: _,
|
||||
id: RequestId::Sync(6),
|
||||
id: 6,
|
||||
response,
|
||||
}) => match response {
|
||||
Response::BlocksByRoot(Some(_)) => {
|
||||
@@ -814,15 +811,14 @@ fn test_blocks_by_root_chunked_rpc_terminates_correctly() {
|
||||
Libp2pEvent::Behaviour(BehaviourEvent::PeerConnectedOutgoing(peer_id)) => {
|
||||
// Send a STATUS message
|
||||
debug!(log, "Sending RPC");
|
||||
sender.swarm.behaviour_mut().send_request(
|
||||
peer_id,
|
||||
RequestId::Sync(10),
|
||||
rpc_request.clone(),
|
||||
);
|
||||
sender
|
||||
.swarm
|
||||
.behaviour_mut()
|
||||
.send_request(peer_id, 10, rpc_request.clone());
|
||||
}
|
||||
Libp2pEvent::Behaviour(BehaviourEvent::ResponseReceived {
|
||||
peer_id: _,
|
||||
id: RequestId::Sync(10),
|
||||
id: 10,
|
||||
response,
|
||||
}) => {
|
||||
debug!(log, "Sender received a response");
|
||||
|
||||
Reference in New Issue
Block a user