add a unique integer id to Rpc requests (#6444)

* add id to rpc requests

* rename rpc request and response types for more accurate meaning

* remove unrequired build_request function

* remove unirequired Request wrapper types and unify Outbound and Inbound Request

* add RequestId to NetworkMessage::SendResponse

,NetworkMessage::SendErrorResponse to be passed to Rpc::send_response
This commit is contained in:
João Oliveira
2024-10-01 02:36:17 +01:00
committed by GitHub
parent 5d1ff7c6f8
commit 82098e1ef7
20 changed files with 1327 additions and 1046 deletions

View File

@@ -6,16 +6,9 @@ use types::{
LightClientFinalityUpdate, LightClientOptimisticUpdate, SignedBeaconBlock,
};
use crate::rpc::methods::{
BlobsByRangeRequest, BlobsByRootRequest, DataColumnsByRangeRequest, DataColumnsByRootRequest,
};
use crate::rpc::{
methods::{
BlocksByRangeRequest, BlocksByRootRequest, LightClientBootstrapRequest,
OldBlocksByRangeRequest, OldBlocksByRangeRequestV1, OldBlocksByRangeRequestV2,
RPCCodedResponse, RPCResponse, ResponseTermination, StatusMessage,
},
OutboundRequest, SubstreamId,
methods::{ResponseTermination, RpcResponse, RpcSuccessResponse, StatusMessage},
SubstreamId,
};
/// Identifier of requests sent by a peer.
@@ -93,69 +86,6 @@ pub enum RequestId {
Internal,
}
/// 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 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 blocks by range request.
BlocksByRange(BlocksByRangeRequest),
/// A blobs by range request.
BlobsByRange(BlobsByRangeRequest),
/// A request blocks root request.
BlocksByRoot(BlocksByRootRequest),
// light client bootstrap request
LightClientBootstrap(LightClientBootstrapRequest),
// light client optimistic update request
LightClientOptimisticUpdate,
// light client finality update request
LightClientFinalityUpdate,
/// A request blobs root request.
BlobsByRoot(BlobsByRootRequest),
/// A request data columns root request.
DataColumnsByRoot(DataColumnsByRootRequest),
/// A request data columns by range request.
DataColumnsByRange(DataColumnsByRangeRequest),
}
impl<E: EthSpec> std::convert::From<Request> for OutboundRequest<E> {
fn from(req: Request) -> OutboundRequest<E> {
match req {
Request::BlocksByRoot(r) => OutboundRequest::BlocksByRoot(r),
Request::BlocksByRange(r) => match r {
BlocksByRangeRequest::V1(req) => OutboundRequest::BlocksByRange(
OldBlocksByRangeRequest::V1(OldBlocksByRangeRequestV1 {
start_slot: req.start_slot,
count: req.count,
step: 1,
}),
),
BlocksByRangeRequest::V2(req) => OutboundRequest::BlocksByRange(
OldBlocksByRangeRequest::V2(OldBlocksByRangeRequestV2 {
start_slot: req.start_slot,
count: req.count,
step: 1,
}),
),
},
Request::LightClientBootstrap(_)
| Request::LightClientOptimisticUpdate
| Request::LightClientFinalityUpdate => {
unreachable!("Lighthouse never makes an outbound light client request")
}
Request::BlobsByRange(r) => OutboundRequest::BlobsByRange(r),
Request::BlobsByRoot(r) => OutboundRequest::BlobsByRoot(r),
Request::DataColumnsByRoot(r) => OutboundRequest::DataColumnsByRoot(r),
Request::DataColumnsByRange(r) => OutboundRequest::DataColumnsByRange(r),
Request::Status(s) => OutboundRequest::Status(s),
}
}
}
/// The type of RPC responses the Behaviour informs it has received, and allows for sending.
///
// NOTE: This is an application-level wrapper over the lower network level responses that can be
@@ -186,44 +116,42 @@ pub enum Response<E: EthSpec> {
LightClientFinalityUpdate(Arc<LightClientFinalityUpdate<E>>),
}
impl<E: EthSpec> std::convert::From<Response<E>> for RPCCodedResponse<E> {
fn from(resp: Response<E>) -> RPCCodedResponse<E> {
impl<E: EthSpec> std::convert::From<Response<E>> for RpcResponse<E> {
fn from(resp: Response<E>) -> RpcResponse<E> {
match resp {
Response::BlocksByRoot(r) => match r {
Some(b) => RPCCodedResponse::Success(RPCResponse::BlocksByRoot(b)),
None => RPCCodedResponse::StreamTermination(ResponseTermination::BlocksByRoot),
Some(b) => RpcResponse::Success(RpcSuccessResponse::BlocksByRoot(b)),
None => RpcResponse::StreamTermination(ResponseTermination::BlocksByRoot),
},
Response::BlocksByRange(r) => match r {
Some(b) => RPCCodedResponse::Success(RPCResponse::BlocksByRange(b)),
None => RPCCodedResponse::StreamTermination(ResponseTermination::BlocksByRange),
Some(b) => RpcResponse::Success(RpcSuccessResponse::BlocksByRange(b)),
None => RpcResponse::StreamTermination(ResponseTermination::BlocksByRange),
},
Response::BlobsByRoot(r) => match r {
Some(b) => RPCCodedResponse::Success(RPCResponse::BlobsByRoot(b)),
None => RPCCodedResponse::StreamTermination(ResponseTermination::BlobsByRoot),
Some(b) => RpcResponse::Success(RpcSuccessResponse::BlobsByRoot(b)),
None => RpcResponse::StreamTermination(ResponseTermination::BlobsByRoot),
},
Response::BlobsByRange(r) => match r {
Some(b) => RPCCodedResponse::Success(RPCResponse::BlobsByRange(b)),
None => RPCCodedResponse::StreamTermination(ResponseTermination::BlobsByRange),
Some(b) => RpcResponse::Success(RpcSuccessResponse::BlobsByRange(b)),
None => RpcResponse::StreamTermination(ResponseTermination::BlobsByRange),
},
Response::DataColumnsByRoot(r) => match r {
Some(d) => RPCCodedResponse::Success(RPCResponse::DataColumnsByRoot(d)),
None => RPCCodedResponse::StreamTermination(ResponseTermination::DataColumnsByRoot),
Some(d) => RpcResponse::Success(RpcSuccessResponse::DataColumnsByRoot(d)),
None => RpcResponse::StreamTermination(ResponseTermination::DataColumnsByRoot),
},
Response::DataColumnsByRange(r) => match r {
Some(d) => RPCCodedResponse::Success(RPCResponse::DataColumnsByRange(d)),
None => {
RPCCodedResponse::StreamTermination(ResponseTermination::DataColumnsByRange)
}
Some(d) => RpcResponse::Success(RpcSuccessResponse::DataColumnsByRange(d)),
None => RpcResponse::StreamTermination(ResponseTermination::DataColumnsByRange),
},
Response::Status(s) => RPCCodedResponse::Success(RPCResponse::Status(s)),
Response::Status(s) => RpcResponse::Success(RpcSuccessResponse::Status(s)),
Response::LightClientBootstrap(b) => {
RPCCodedResponse::Success(RPCResponse::LightClientBootstrap(b))
RpcResponse::Success(RpcSuccessResponse::LightClientBootstrap(b))
}
Response::LightClientOptimisticUpdate(o) => {
RPCCodedResponse::Success(RPCResponse::LightClientOptimisticUpdate(o))
RpcResponse::Success(RpcSuccessResponse::LightClientOptimisticUpdate(o))
}
Response::LightClientFinalityUpdate(f) => {
RPCCodedResponse::Success(RPCResponse::LightClientFinalityUpdate(f))
RpcResponse::Success(RpcSuccessResponse::LightClientFinalityUpdate(f))
}
}
}

View File

@@ -11,9 +11,8 @@ use crate::peer_manager::{
use crate::peer_manager::{MIN_OUTBOUND_ONLY_FACTOR, PEER_EXCESS_FACTOR, PRIORITY_PEER_EXCESS};
use crate::rpc::methods::MetadataRequest;
use crate::rpc::{
methods, BlocksByRangeRequest, GoodbyeReason, HandlerErr, InboundRequest, NetworkParams,
OutboundRequest, Protocol, RPCCodedResponse, RPCError, RPCMessage, RPCReceived, RPCResponse,
RPCResponseErrorCode, ResponseTermination, RPC,
self, GoodbyeReason, HandlerErr, NetworkParams, Protocol, RPCError, RPCMessage, RPCReceived,
RequestType, ResponseTermination, RpcErrorResponse, RpcResponse, RpcSuccessResponse, RPC,
};
use crate::service::behaviour::BehaviourEvent;
pub use crate::service::behaviour::Gossipsub;
@@ -25,7 +24,7 @@ use crate::types::{
use crate::EnrExt;
use crate::Eth2Enr;
use crate::{error, metrics, Enr, NetworkGlobals, PubsubMessage, TopicHash};
use api_types::{AppRequestId, PeerRequestId, Request, RequestId, Response};
use api_types::{AppRequestId, PeerRequestId, RequestId, Response};
use futures::stream::StreamExt;
use gossipsub::{
IdentTopic as Topic, MessageAcceptance, MessageAuthenticity, MessageId, PublishError,
@@ -84,7 +83,7 @@ pub enum NetworkEvent<E: EthSpec> {
/// Identifier of the request. All responses to this request must use this id.
id: PeerRequestId,
/// Request the peer sent.
request: Request,
request: rpc::Request<E>,
},
ResponseReceived {
/// Peer that sent the response.
@@ -934,25 +933,28 @@ impl<E: EthSpec> Network<E> {
&mut self,
peer_id: PeerId,
request_id: AppRequestId,
request: Request,
request: RequestType<E>,
) -> Result<(), (AppRequestId, RPCError)> {
// Check if the peer is connected before sending an RPC request
if !self.swarm.is_connected(&peer_id) {
return Err((request_id, RPCError::Disconnected));
}
self.eth2_rpc_mut().send_request(
peer_id,
RequestId::Application(request_id),
request.into(),
);
self.eth2_rpc_mut()
.send_request(peer_id, RequestId::Application(request_id), request);
Ok(())
}
/// Send a successful response to a peer over RPC.
pub fn send_response(&mut self, peer_id: PeerId, id: PeerRequestId, response: Response<E>) {
pub fn send_response(
&mut self,
peer_id: PeerId,
id: PeerRequestId,
request_id: rpc::RequestId,
response: Response<E>,
) {
self.eth2_rpc_mut()
.send_response(peer_id, id, response.into())
.send_response(peer_id, id, request_id, response.into())
}
/// Inform the peer that their request produced an error.
@@ -960,13 +962,15 @@ impl<E: EthSpec> Network<E> {
&mut self,
peer_id: PeerId,
id: PeerRequestId,
error: RPCResponseErrorCode,
request_id: rpc::RequestId,
error: RpcErrorResponse,
reason: String,
) {
self.eth2_rpc_mut().send_response(
peer_id,
id,
RPCCodedResponse::Error(error, reason.into()),
request_id,
RpcResponse::Error(error, reason.into()),
)
}
@@ -1130,10 +1134,10 @@ impl<E: EthSpec> Network<E> {
let event = if self.fork_context.spec.is_peer_das_scheduled() {
// Nodes with higher custody will probably start advertising it
// before peerdas is activated
OutboundRequest::MetaData(MetadataRequest::new_v3())
RequestType::MetaData(MetadataRequest::new_v3())
} else {
// We always prefer sending V2 requests otherwise
OutboundRequest::MetaData(MetadataRequest::new_v2())
RequestType::MetaData(MetadataRequest::new_v2())
};
self.eth2_rpc_mut()
.send_request(peer_id, RequestId::Internal, event);
@@ -1144,12 +1148,14 @@ impl<E: EthSpec> Network<E> {
&mut self,
_req: MetadataRequest<E>,
id: PeerRequestId,
request_id: rpc::RequestId,
peer_id: PeerId,
) {
let metadata = self.network_globals.local_metadata.read().clone();
// The encoder is responsible for sending the negotiated version of the metadata
let event = RPCCodedResponse::Success(RPCResponse::MetaData(metadata));
self.eth2_rpc_mut().send_response(peer_id, id, event);
let event = RpcResponse::Success(RpcSuccessResponse::MetaData(metadata));
self.eth2_rpc_mut()
.send_response(peer_id, id, request_id, event);
}
// RPC Propagation methods
@@ -1171,56 +1177,6 @@ impl<E: EthSpec> Network<E> {
}
}
/// Convenience function to propagate a request.
#[must_use = "actually return the event"]
fn build_request(
&mut self,
id: PeerRequestId,
peer_id: PeerId,
request: Request,
) -> NetworkEvent<E> {
// Increment metrics
match &request {
Request::Status(_) => {
metrics::inc_counter_vec(&metrics::TOTAL_RPC_REQUESTS, &["status"])
}
Request::LightClientBootstrap(_) => {
metrics::inc_counter_vec(&metrics::TOTAL_RPC_REQUESTS, &["light_client_bootstrap"])
}
Request::LightClientOptimisticUpdate => metrics::inc_counter_vec(
&metrics::TOTAL_RPC_REQUESTS,
&["light_client_optimistic_update"],
),
Request::LightClientFinalityUpdate => metrics::inc_counter_vec(
&metrics::TOTAL_RPC_REQUESTS,
&["light_client_finality_update"],
),
Request::BlocksByRange { .. } => {
metrics::inc_counter_vec(&metrics::TOTAL_RPC_REQUESTS, &["blocks_by_range"])
}
Request::BlocksByRoot { .. } => {
metrics::inc_counter_vec(&metrics::TOTAL_RPC_REQUESTS, &["blocks_by_root"])
}
Request::BlobsByRange { .. } => {
metrics::inc_counter_vec(&metrics::TOTAL_RPC_REQUESTS, &["blobs_by_range"])
}
Request::BlobsByRoot { .. } => {
metrics::inc_counter_vec(&metrics::TOTAL_RPC_REQUESTS, &["blobs_by_root"])
}
Request::DataColumnsByRoot { .. } => {
metrics::inc_counter_vec(&metrics::TOTAL_RPC_REQUESTS, &["data_columns_by_root"])
}
Request::DataColumnsByRange { .. } => {
metrics::inc_counter_vec(&metrics::TOTAL_RPC_REQUESTS, &["data_columns_by_range"])
}
}
NetworkEvent::RequestReceived {
peer_id,
id,
request,
}
}
/// Dial cached Enrs in discovery service that are in the given `subnet_id` and aren't
/// in Connected, Dialing or Banned state.
fn dial_cached_enrs_in_subnet(&mut self, subnet: Subnet, spec: Arc<ChainSpec>) {
@@ -1406,7 +1362,7 @@ impl<E: EthSpec> Network<E> {
return None;
}
let handler_id = event.conn_id;
let connection_id = event.conn_id;
// The METADATA and PING RPC responses are handled within the behaviour and not propagated
match event.message {
Err(handler_err) => {
@@ -1444,21 +1400,25 @@ impl<E: EthSpec> Network<E> {
}
}
}
Ok(RPCReceived::Request(id, request)) => {
let peer_request_id = (handler_id, id);
match request {
Ok(RPCReceived::Request(request)) => {
match request.r#type {
/* Behaviour managed protocols: Ping and Metadata */
InboundRequest::Ping(ping) => {
RequestType::Ping(ping) => {
// inform the peer manager and send the response
self.peer_manager_mut().ping_request(&peer_id, ping.data);
None
}
InboundRequest::MetaData(req) => {
RequestType::MetaData(req) => {
// send the requested meta-data
self.send_meta_data_response(req, (handler_id, id), peer_id);
self.send_meta_data_response(
req,
(connection_id, request.substream_id),
request.id,
peer_id,
);
None
}
InboundRequest::Goodbye(reason) => {
RequestType::Goodbye(reason) => {
// queue for disconnection without a goodbye message
debug!(
self.log, "Peer sent Goodbye";
@@ -1473,17 +1433,19 @@ impl<E: EthSpec> Network<E> {
None
}
/* Protocols propagated to the Network */
InboundRequest::Status(msg) => {
RequestType::Status(_) => {
// inform the peer manager that we have received a status from a peer
self.peer_manager_mut().peer_statusd(&peer_id);
metrics::inc_counter_vec(&metrics::TOTAL_RPC_REQUESTS, &["status"]);
// propagate the STATUS message upwards
let event =
self.build_request(peer_request_id, peer_id, Request::Status(msg));
Some(event)
Some(NetworkEvent::RequestReceived {
peer_id,
id: (connection_id, request.substream_id),
request,
})
}
InboundRequest::BlocksByRange(req) => {
RequestType::BlocksByRange(ref req) => {
// Still disconnect the peer if the request is naughty.
let mut count = *req.count();
if *req.step() == 0 {
self.peer_manager_mut().handle_rpc_error(
&peer_id,
@@ -1495,131 +1457,144 @@ impl<E: EthSpec> Network<E> {
);
return None;
}
// return just one block in case the step parameter is used. https://github.com/ethereum/consensus-specs/pull/2856
if *req.step() > 1 {
count = 1;
}
let request = match req {
methods::OldBlocksByRangeRequest::V1(req) => Request::BlocksByRange(
BlocksByRangeRequest::new_v1(req.start_slot, count),
),
methods::OldBlocksByRangeRequest::V2(req) => Request::BlocksByRange(
BlocksByRangeRequest::new(req.start_slot, count),
),
};
let event = self.build_request(peer_request_id, peer_id, request);
Some(event)
}
InboundRequest::BlocksByRoot(req) => {
let event = self.build_request(
peer_request_id,
peer_id,
Request::BlocksByRoot(req),
metrics::inc_counter_vec(
&metrics::TOTAL_RPC_REQUESTS,
&["blocks_by_range"],
);
Some(event)
}
InboundRequest::BlobsByRange(req) => {
let event = self.build_request(
peer_request_id,
Some(NetworkEvent::RequestReceived {
peer_id,
Request::BlobsByRange(req),
);
Some(event)
id: (connection_id, request.substream_id),
request,
})
}
InboundRequest::BlobsByRoot(req) => {
let event =
self.build_request(peer_request_id, peer_id, Request::BlobsByRoot(req));
Some(event)
}
InboundRequest::DataColumnsByRoot(req) => {
let event = self.build_request(
peer_request_id,
RequestType::BlocksByRoot(_) => {
metrics::inc_counter_vec(&metrics::TOTAL_RPC_REQUESTS, &["blocks_by_root"]);
Some(NetworkEvent::RequestReceived {
peer_id,
Request::DataColumnsByRoot(req),
);
Some(event)
id: (connection_id, request.substream_id),
request,
})
}
InboundRequest::DataColumnsByRange(req) => {
let event = self.build_request(
peer_request_id,
RequestType::BlobsByRange(_) => {
metrics::inc_counter_vec(&metrics::TOTAL_RPC_REQUESTS, &["blobs_by_range"]);
Some(NetworkEvent::RequestReceived {
peer_id,
Request::DataColumnsByRange(req),
);
Some(event)
id: (connection_id, request.substream_id),
request,
})
}
InboundRequest::LightClientBootstrap(req) => {
let event = self.build_request(
peer_request_id,
RequestType::BlobsByRoot(_) => {
metrics::inc_counter_vec(&metrics::TOTAL_RPC_REQUESTS, &["blobs_by_root"]);
Some(NetworkEvent::RequestReceived {
peer_id,
Request::LightClientBootstrap(req),
);
Some(event)
id: (connection_id, request.substream_id),
request,
})
}
InboundRequest::LightClientOptimisticUpdate => {
let event = self.build_request(
peer_request_id,
peer_id,
Request::LightClientOptimisticUpdate,
RequestType::DataColumnsByRoot(_) => {
metrics::inc_counter_vec(
&metrics::TOTAL_RPC_REQUESTS,
&["data_columns_by_root"],
);
Some(event)
Some(NetworkEvent::RequestReceived {
peer_id,
id: (connection_id, request.substream_id),
request,
})
}
InboundRequest::LightClientFinalityUpdate => {
let event = self.build_request(
peer_request_id,
peer_id,
Request::LightClientFinalityUpdate,
RequestType::DataColumnsByRange(_) => {
metrics::inc_counter_vec(
&metrics::TOTAL_RPC_REQUESTS,
&["data_columns_by_range"],
);
Some(event)
Some(NetworkEvent::RequestReceived {
peer_id,
id: (connection_id, request.substream_id),
request,
})
}
RequestType::LightClientBootstrap(_) => {
metrics::inc_counter_vec(
&metrics::TOTAL_RPC_REQUESTS,
&["light_client_bootstrap"],
);
Some(NetworkEvent::RequestReceived {
peer_id,
id: (connection_id, request.substream_id),
request,
})
}
RequestType::LightClientOptimisticUpdate => {
metrics::inc_counter_vec(
&metrics::TOTAL_RPC_REQUESTS,
&["light_client_optimistic_update"],
);
Some(NetworkEvent::RequestReceived {
peer_id,
id: (connection_id, request.substream_id),
request,
})
}
RequestType::LightClientFinalityUpdate => {
metrics::inc_counter_vec(
&metrics::TOTAL_RPC_REQUESTS,
&["light_client_finality_update"],
);
Some(NetworkEvent::RequestReceived {
peer_id,
id: (connection_id, request.substream_id),
request,
})
}
}
}
Ok(RPCReceived::Response(id, resp)) => {
match resp {
/* Behaviour managed protocols */
RPCResponse::Pong(ping) => {
RpcSuccessResponse::Pong(ping) => {
self.peer_manager_mut().pong_response(&peer_id, ping.data);
None
}
RPCResponse::MetaData(meta_data) => {
RpcSuccessResponse::MetaData(meta_data) => {
self.peer_manager_mut()
.meta_data_response(&peer_id, meta_data);
None
}
/* Network propagated protocols */
RPCResponse::Status(msg) => {
RpcSuccessResponse::Status(msg) => {
// inform the peer manager that we have received a status from a peer
self.peer_manager_mut().peer_statusd(&peer_id);
// propagate the STATUS message upwards
self.build_response(id, peer_id, Response::Status(msg))
}
RPCResponse::BlocksByRange(resp) => {
RpcSuccessResponse::BlocksByRange(resp) => {
self.build_response(id, peer_id, Response::BlocksByRange(Some(resp)))
}
RPCResponse::BlobsByRange(resp) => {
RpcSuccessResponse::BlobsByRange(resp) => {
self.build_response(id, peer_id, Response::BlobsByRange(Some(resp)))
}
RPCResponse::BlocksByRoot(resp) => {
RpcSuccessResponse::BlocksByRoot(resp) => {
self.build_response(id, peer_id, Response::BlocksByRoot(Some(resp)))
}
RPCResponse::BlobsByRoot(resp) => {
RpcSuccessResponse::BlobsByRoot(resp) => {
self.build_response(id, peer_id, Response::BlobsByRoot(Some(resp)))
}
RPCResponse::DataColumnsByRoot(resp) => {
RpcSuccessResponse::DataColumnsByRoot(resp) => {
self.build_response(id, peer_id, Response::DataColumnsByRoot(Some(resp)))
}
RPCResponse::DataColumnsByRange(resp) => {
RpcSuccessResponse::DataColumnsByRange(resp) => {
self.build_response(id, peer_id, Response::DataColumnsByRange(Some(resp)))
}
// Should never be reached
RPCResponse::LightClientBootstrap(bootstrap) => {
RpcSuccessResponse::LightClientBootstrap(bootstrap) => {
self.build_response(id, peer_id, Response::LightClientBootstrap(bootstrap))
}
RPCResponse::LightClientOptimisticUpdate(update) => self.build_response(
RpcSuccessResponse::LightClientOptimisticUpdate(update) => self.build_response(
id,
peer_id,
Response::LightClientOptimisticUpdate(update),
),
RPCResponse::LightClientFinalityUpdate(update) => self.build_response(
RpcSuccessResponse::LightClientFinalityUpdate(update) => self.build_response(
id,
peer_id,
Response::LightClientFinalityUpdate(update),