client/network: Use request response for block requests (#7478)

* client/network: Add scaffolding for finality req to use req resp
	#sc

* client/network/src/finality_requests: Remove

* client/network/src/behaviour: Pass request id down to sync

* client/network: Use request response for block requests

* client/network: Move handler logic into *_*_handler.rs

* client/network: Track ongoing finality requests in protocol.rs

* client/network: Remove commented out finalization initialization

* client/network: Add docs for request handlers

* client/network/finality_request_handler: Log errors

* client/network/block_request_handler: Log errors

* client/network: Format

* client/network: Handle block request failure

* protocols/network: Fix tests

* client/network/src/behaviour: Handle request sending errors

* client/network: Move response handling into custom method

* client/network/protocol: Handle block response errors

* client/network/protocol: Remove tracking of obsolete requests

* client/network/protocol: Remove block request start time tracking

This will be handled generically via request-responses.

* client/network/protocol: Refactor on_*_request_started

* client/network: Pass protocol config instead of protocol name

* client/network: Pass protocol config in tests

* client/network/config: Document request response configs

* client/network/src/_request_handler: Document protocol config gen

* client/network/src/protocol: Document Peer request values

* client/network: Rework request response to always use oneshot

* client/network: Unified metric reporting for all request protocols

* client/network: Move protobuf parsing into protocol.rs

* client/network/src/protocol: Return pending events after poll

* client/network: Improve error handling and documentation

* client/network/behaviour: Remove outdated error types

* Update client/network/src/block_request_handler.rs

Co-authored-by: Ashley <ashley.ruglys@gmail.com>

* Update client/network/src/finality_request_handler.rs

Co-authored-by: Ashley <ashley.ruglys@gmail.com>

* client/network/protocol: Reduce reputation on timeout

* client/network/protocol: Refine reputation changes

* client/network/block_request_handler: Set and explain queue length

* client/service: Deny block requests when light client

* client/service: Fix role matching

* client: Enforce line width

* client/network/request_responses: Fix unit tests

* client/network: Expose time to build response via metrics

* client/network/request_responses: Fix early connection closed error

* client/network/protocol: Fix line length

* client/network/protocol: Disconnect on most request failures

* client/network/protocol: Disconnect peer when oneshot is canceled

* client/network/protocol: Disconnect peer even when connection closed

* client/network/protocol: Remove debugging log line

* client/network/request_response: Use Clone::clone for error

* client/network/request_response: Remove outdated comment

With libp2p v0.33.0 libp2p-request-response properly sends inbound
failures on connections being closed.

Co-authored-by: Addie Wagenknecht <addie@nortd.com>
Co-authored-by: Ashley <ashley.ruglys@gmail.com>
This commit is contained in:
Max Inden
2021-01-05 19:20:54 +01:00
committed by GitHub
parent 92f596829d
commit 3f629f743b
17 changed files with 780 additions and 1299 deletions
+35 -84
View File
@@ -38,7 +38,7 @@ use crate::{
NetworkState, NotConnectedPeer as NetworkStateNotConnectedPeer, Peer as NetworkStatePeer,
},
on_demand_layer::AlwaysBadChecker,
light_client_handler, block_requests,
light_client_handler,
protocol::{
self,
NotifsHandlerError,
@@ -94,7 +94,6 @@ use std::{
},
task::Poll,
};
use wasm_timer::Instant;
pub use behaviour::{ResponseFailure, InboundFailure, RequestFailure, OutboundFailure};
@@ -287,10 +286,6 @@ impl<B: BlockT + 'static, H: ExHashT> NetworkWorker<B, H> {
params.network_config.client_version,
params.network_config.node_name
);
let block_requests = {
let config = block_requests::Config::new(&params.protocol_id);
block_requests::BlockRequests::new(config, params.chain.clone())
};
let light_client_handler = {
let config = light_client_handler::Config::new(&params.protocol_id);
light_client_handler::LightClientHandler::new(
@@ -329,9 +324,9 @@ impl<B: BlockT + 'static, H: ExHashT> NetworkWorker<B, H> {
params.role,
user_agent,
local_public,
block_requests,
light_client_handler,
discovery_config,
params.block_request_protocol_config,
params.network_config.request_response_protocols,
);
@@ -430,7 +425,6 @@ impl<B: BlockT + 'static, H: ExHashT> NetworkWorker<B, H> {
peers_notifications_sinks,
metrics,
boot_node_ids,
pending_requests: HashMap::with_capacity(128),
})
}
@@ -1231,13 +1225,6 @@ pub struct NetworkWorker<B: BlockT + 'static, H: ExHashT> {
metrics: Option<Metrics>,
/// The `PeerId`'s of all boot nodes.
boot_node_ids: Arc<HashSet<PeerId>>,
/// Requests started using [`NetworkService::request`]. Includes the channel to send back the
/// response, when the request has started, and the name of the protocol for diagnostic
/// purposes.
pending_requests: HashMap<
behaviour::RequestId,
(oneshot::Sender<Result<Vec<u8>, RequestFailure>>, Instant, String)
>,
/// For each peer and protocol combination, an object that allows sending notifications to
/// that peer. Shared with the [`NetworkService`].
peers_notifications_sinks: Arc<Mutex<HashMap<(PeerId, Cow<'static, str>), NotificationsSink>>>,
@@ -1310,29 +1297,7 @@ impl<B: BlockT + 'static, H: ExHashT> Future for NetworkWorker<B, H> {
ServiceToWorkerMsg::EventStream(sender) =>
this.event_streams.push(sender),
ServiceToWorkerMsg::Request { target, protocol, request, pending_response } => {
// Calling `send_request` can fail immediately in some circumstances.
// This is handled by sending back an error on the channel.
match this.network_service.send_request(&target, &protocol, request) {
Ok(request_id) => {
if let Some(metrics) = this.metrics.as_ref() {
metrics.requests_out_started_total
.with_label_values(&[&protocol])
.inc();
}
this.pending_requests.insert(
request_id,
(pending_response, Instant::now(), protocol.to_string())
);
},
Err(behaviour::SendRequestError::NotConnected) => {
let err = RequestFailure::Network(OutboundFailure::ConnectionClosed);
let _ = pending_response.send(Err(err));
},
Err(behaviour::SendRequestError::UnknownProtocol) => {
let err = RequestFailure::Network(OutboundFailure::UnsupportedProtocols);
let _ = pending_response.send(Err(err));
},
}
this.network_service.send_request(&target, &protocol, request, pending_response);
},
ServiceToWorkerMsg::DisconnectPeer(who) =>
this.network_service.user_protocol_mut().disconnect_peer(&who),
@@ -1396,51 +1361,37 @@ impl<B: BlockT + 'static, H: ExHashT> Future for NetworkWorker<B, H> {
}
}
},
Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::RequestFinished { request_id, result })) => {
if let Some((send_back, started, protocol)) = this.pending_requests.remove(&request_id) {
if let Some(metrics) = this.metrics.as_ref() {
match &result {
Ok(_) => {
metrics.requests_out_success_total
.with_label_values(&[&protocol])
.observe(started.elapsed().as_secs_f64());
}
Err(err) => {
let reason = match err {
RequestFailure::Refused => "refused",
RequestFailure::Network(OutboundFailure::DialFailure) =>
"dial-failure",
RequestFailure::Network(OutboundFailure::Timeout) =>
"timeout",
RequestFailure::Network(OutboundFailure::ConnectionClosed) =>
"connection-closed",
RequestFailure::Network(OutboundFailure::UnsupportedProtocols) =>
"unsupported",
};
Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::RequestFinished {
protocol, duration, result, ..
})) => {
if let Some(metrics) = this.metrics.as_ref() {
match result {
Ok(_) => {
metrics.requests_out_success_total
.with_label_values(&[&protocol])
.observe(duration.as_secs_f64());
}
Err(err) => {
let reason = match err {
RequestFailure::NotConnected => "not-connected",
RequestFailure::UnknownProtocol => "unknown-protocol",
RequestFailure::Refused => "refused",
RequestFailure::Obsolete => "obsolete",
RequestFailure::Network(OutboundFailure::DialFailure) =>
"dial-failure",
RequestFailure::Network(OutboundFailure::Timeout) =>
"timeout",
RequestFailure::Network(OutboundFailure::ConnectionClosed) =>
"connection-closed",
RequestFailure::Network(OutboundFailure::UnsupportedProtocols) =>
"unsupported",
};
metrics.requests_out_failure_total
.with_label_values(&[&protocol, reason])
.inc();
}
metrics.requests_out_failure_total
.with_label_values(&[&protocol, reason])
.inc();
}
}
let _ = send_back.send(result);
} else {
error!("Request not in pending_requests");
}
},
Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::OpaqueRequestStarted { protocol, .. })) => {
if let Some(metrics) = this.metrics.as_ref() {
metrics.requests_out_started_total
.with_label_values(&[&protocol])
.inc();
}
},
Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::OpaqueRequestFinished { protocol, request_duration, .. })) => {
if let Some(metrics) = this.metrics.as_ref() {
metrics.requests_out_success_total
.with_label_values(&[&protocol])
.observe(request_duration.as_secs_f64());
}
},
Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::RandomKademliaStarted(protocol))) => {
@@ -1567,11 +1518,11 @@ impl<B: BlockT + 'static, H: ExHashT> Future for NetworkWorker<B, H> {
let reason = match cause {
Some(ConnectionError::IO(_)) => "transport-error",
Some(ConnectionError::Handler(NodeHandlerWrapperError::Handler(EitherError::A(EitherError::A(
EitherError::A(EitherError::A(EitherError::B(
EitherError::A(PingFailure::Timeout))))))))) => "ping-timeout",
EitherError::A(EitherError::B(EitherError::A(
PingFailure::Timeout)))))))) => "ping-timeout",
Some(ConnectionError::Handler(NodeHandlerWrapperError::Handler(EitherError::A(EitherError::A(
EitherError::A(EitherError::A(EitherError::A(
NotifsHandlerError::SyncNotificationsClogged)))))))) => "sync-notifications-clogged",
EitherError::A(EitherError::A(
NotifsHandlerError::SyncNotificationsClogged))))))) => "sync-notifications-clogged",
Some(ConnectionError::Handler(NodeHandlerWrapperError::Handler(_))) => "protocol-error",
Some(ConnectionError::Handler(NodeHandlerWrapperError::KeepAliveTimeout)) => "keep-alive-timeout",
None => "actively-closed",