mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 22:41:06 +00:00
Remove request multiplexer (#3624)
* WIP: Get rid of request multiplexer. * WIP * Receiver for handling of incoming requests. * Get rid of useless `Fault` abstraction. The things the type system let us do are not worth getting abstracted in its own type. Instead error handling is going to be merely a pattern. * Make most things compile again. * Port availability distribution away from request multiplexer. * Formatting. * Port dispute distribution over. * Fixup statement distribution. * Handle request directly in collator protocol. + Only allow fatal errors at top level. * Use direct request channel for availability recovery. * Finally get rid of request multiplexer Fixes #2842 and paves the way for more back pressure possibilities. * Fix overseer and statement distribution tests. * Fix collator protocol and network bridge tests. * Fix tests in availability recovery. * Fix availability distribution tests. * Fix dispute distribution tests. * Add missing dependency * Typos. * Review remarks. * More remarks.
This commit is contained in:
@@ -22,7 +22,6 @@
|
||||
use futures::{prelude::*, stream::BoxStream};
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
use parking_lot::Mutex;
|
||||
use polkadot_subsystem::messages::DisputeDistributionMessage;
|
||||
use sc_network::Event as NetworkEvent;
|
||||
use sp_consensus::SyncOracle;
|
||||
|
||||
@@ -35,10 +34,7 @@ use polkadot_overseer::gen::{OverseerError, Subsystem};
|
||||
use polkadot_primitives::v1::{BlockNumber, Hash};
|
||||
use polkadot_subsystem::{
|
||||
errors::{SubsystemError, SubsystemResult},
|
||||
messages::{
|
||||
AllMessages, CollatorProtocolMessage, NetworkBridgeEvent, NetworkBridgeMessage,
|
||||
StatementDistributionMessage,
|
||||
},
|
||||
messages::{AllMessages, CollatorProtocolMessage, NetworkBridgeEvent, NetworkBridgeMessage},
|
||||
overseer, ActivatedLeaf, ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem,
|
||||
SubsystemContext, SubsystemSender,
|
||||
};
|
||||
@@ -61,10 +57,6 @@ mod validator_discovery;
|
||||
mod network;
|
||||
use network::{send_message, Network};
|
||||
|
||||
/// Request multiplexer for combining the multiple request sources into a single `Stream` of `AllMessages`.
|
||||
mod multiplexer;
|
||||
pub use multiplexer::RequestMultiplexer;
|
||||
|
||||
use crate::network::get_peer_id_by_authority_id;
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -276,7 +268,6 @@ pub struct NetworkBridge<N, AD> {
|
||||
/// `Network` trait implementing type.
|
||||
network_service: N,
|
||||
authority_discovery_service: AD,
|
||||
request_multiplexer: RequestMultiplexer,
|
||||
sync_oracle: Box<dyn SyncOracle + Send>,
|
||||
metrics: Metrics,
|
||||
}
|
||||
@@ -289,17 +280,10 @@ impl<N, AD> NetworkBridge<N, AD> {
|
||||
pub fn new(
|
||||
network_service: N,
|
||||
authority_discovery_service: AD,
|
||||
request_multiplexer: RequestMultiplexer,
|
||||
sync_oracle: Box<dyn SyncOracle + Send>,
|
||||
metrics: Metrics,
|
||||
) -> Self {
|
||||
NetworkBridge {
|
||||
network_service,
|
||||
authority_discovery_service,
|
||||
request_multiplexer,
|
||||
sync_oracle,
|
||||
metrics,
|
||||
}
|
||||
NetworkBridge { network_service, authority_discovery_service, sync_oracle, metrics }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,8 +319,6 @@ enum UnexpectedAbort {
|
||||
SubsystemError(SubsystemError),
|
||||
/// The stream of incoming events concluded.
|
||||
EventStreamConcluded,
|
||||
/// The stream of incoming requests concluded.
|
||||
RequestStreamConcluded,
|
||||
}
|
||||
|
||||
impl From<SubsystemError> for UnexpectedAbort {
|
||||
@@ -610,247 +592,226 @@ async fn handle_network_messages<AD: validator_discovery::AuthorityDiscovery>(
|
||||
mut network_service: impl Network,
|
||||
network_stream: BoxStream<'static, NetworkEvent>,
|
||||
mut authority_discovery_service: AD,
|
||||
mut request_multiplexer: RequestMultiplexer,
|
||||
metrics: Metrics,
|
||||
shared: Shared,
|
||||
) -> Result<(), UnexpectedAbort> {
|
||||
let mut network_stream = network_stream.fuse();
|
||||
loop {
|
||||
futures::select! {
|
||||
network_event = network_stream.next() => match network_event {
|
||||
None => return Err(UnexpectedAbort::EventStreamConcluded),
|
||||
Some(NetworkEvent::Dht(_))
|
||||
| Some(NetworkEvent::SyncConnected { .. })
|
||||
| Some(NetworkEvent::SyncDisconnected { .. }) => {}
|
||||
Some(NetworkEvent::NotificationStreamOpened { remote: peer, protocol, role, .. }) => {
|
||||
let role = ObservedRole::from(role);
|
||||
let peer_set = match PeerSet::try_from_protocol_name(&protocol) {
|
||||
None => continue,
|
||||
Some(peer_set) => peer_set,
|
||||
match network_stream.next().await {
|
||||
None => return Err(UnexpectedAbort::EventStreamConcluded),
|
||||
Some(NetworkEvent::Dht(_)) |
|
||||
Some(NetworkEvent::SyncConnected { .. }) |
|
||||
Some(NetworkEvent::SyncDisconnected { .. }) => {},
|
||||
Some(NetworkEvent::NotificationStreamOpened {
|
||||
remote: peer, protocol, role, ..
|
||||
}) => {
|
||||
let role = ObservedRole::from(role);
|
||||
let peer_set = match PeerSet::try_from_protocol_name(&protocol) {
|
||||
None => continue,
|
||||
Some(peer_set) => peer_set,
|
||||
};
|
||||
|
||||
tracing::debug!(
|
||||
target: LOG_TARGET,
|
||||
action = "PeerConnected",
|
||||
peer_set = ?peer_set,
|
||||
peer = ?peer,
|
||||
role = ?role
|
||||
);
|
||||
|
||||
let local_view = {
|
||||
let mut shared = shared.0.lock();
|
||||
let peer_map = match peer_set {
|
||||
PeerSet::Validation => &mut shared.validation_peers,
|
||||
PeerSet::Collation => &mut shared.collation_peers,
|
||||
};
|
||||
|
||||
tracing::debug!(
|
||||
target: LOG_TARGET,
|
||||
action = "PeerConnected",
|
||||
peer_set = ?peer_set,
|
||||
peer = ?peer,
|
||||
role = ?role
|
||||
);
|
||||
match peer_map.entry(peer.clone()) {
|
||||
hash_map::Entry::Occupied(_) => continue,
|
||||
hash_map::Entry::Vacant(vacant) => {
|
||||
vacant.insert(PeerData { view: View::default() });
|
||||
},
|
||||
}
|
||||
|
||||
let local_view = {
|
||||
let mut shared = shared.0.lock();
|
||||
let peer_map = match peer_set {
|
||||
PeerSet::Validation => &mut shared.validation_peers,
|
||||
PeerSet::Collation => &mut shared.collation_peers,
|
||||
};
|
||||
metrics.on_peer_connected(peer_set);
|
||||
metrics.note_peer_count(peer_set, peer_map.len());
|
||||
|
||||
match peer_map.entry(peer.clone()) {
|
||||
hash_map::Entry::Occupied(_) => continue,
|
||||
hash_map::Entry::Vacant(vacant) => {
|
||||
vacant.insert(PeerData { view: View::default() });
|
||||
}
|
||||
}
|
||||
shared.local_view.clone().unwrap_or(View::default())
|
||||
};
|
||||
|
||||
metrics.on_peer_connected(peer_set);
|
||||
metrics.note_peer_count(peer_set, peer_map.len());
|
||||
let maybe_authority =
|
||||
authority_discovery_service.get_authority_id_by_peer_id(peer).await;
|
||||
|
||||
shared.local_view.clone().unwrap_or(View::default())
|
||||
match peer_set {
|
||||
PeerSet::Validation => {
|
||||
dispatch_validation_events_to_all(
|
||||
vec![
|
||||
NetworkBridgeEvent::PeerConnected(
|
||||
peer.clone(),
|
||||
role,
|
||||
maybe_authority,
|
||||
),
|
||||
NetworkBridgeEvent::PeerViewChange(peer.clone(), View::default()),
|
||||
],
|
||||
&mut sender,
|
||||
)
|
||||
.await;
|
||||
|
||||
send_message(
|
||||
&mut network_service,
|
||||
vec![peer],
|
||||
PeerSet::Validation,
|
||||
WireMessage::<protocol_v1::ValidationProtocol>::ViewUpdate(local_view),
|
||||
&metrics,
|
||||
);
|
||||
},
|
||||
PeerSet::Collation => {
|
||||
dispatch_collation_events_to_all(
|
||||
vec![
|
||||
NetworkBridgeEvent::PeerConnected(
|
||||
peer.clone(),
|
||||
role,
|
||||
maybe_authority,
|
||||
),
|
||||
NetworkBridgeEvent::PeerViewChange(peer.clone(), View::default()),
|
||||
],
|
||||
&mut sender,
|
||||
)
|
||||
.await;
|
||||
|
||||
send_message(
|
||||
&mut network_service,
|
||||
vec![peer],
|
||||
PeerSet::Collation,
|
||||
WireMessage::<protocol_v1::CollationProtocol>::ViewUpdate(local_view),
|
||||
&metrics,
|
||||
);
|
||||
},
|
||||
}
|
||||
},
|
||||
Some(NetworkEvent::NotificationStreamClosed { remote: peer, protocol }) => {
|
||||
let peer_set = match PeerSet::try_from_protocol_name(&protocol) {
|
||||
None => continue,
|
||||
Some(peer_set) => peer_set,
|
||||
};
|
||||
|
||||
tracing::debug!(
|
||||
target: LOG_TARGET,
|
||||
action = "PeerDisconnected",
|
||||
peer_set = ?peer_set,
|
||||
peer = ?peer
|
||||
);
|
||||
|
||||
let was_connected = {
|
||||
let mut shared = shared.0.lock();
|
||||
let peer_map = match peer_set {
|
||||
PeerSet::Validation => &mut shared.validation_peers,
|
||||
PeerSet::Collation => &mut shared.collation_peers,
|
||||
};
|
||||
|
||||
let maybe_authority =
|
||||
authority_discovery_service
|
||||
.get_authority_id_by_peer_id(peer).await;
|
||||
let w = peer_map.remove(&peer).is_some();
|
||||
|
||||
metrics.on_peer_disconnected(peer_set);
|
||||
metrics.note_peer_count(peer_set, peer_map.len());
|
||||
|
||||
w
|
||||
};
|
||||
|
||||
if was_connected {
|
||||
match peer_set {
|
||||
PeerSet::Validation => {
|
||||
dispatch_validation_events_to_all(
|
||||
vec![
|
||||
NetworkBridgeEvent::PeerConnected(peer.clone(), role, maybe_authority),
|
||||
NetworkBridgeEvent::PeerViewChange(
|
||||
peer.clone(),
|
||||
View::default(),
|
||||
),
|
||||
],
|
||||
&mut sender,
|
||||
).await;
|
||||
|
||||
send_message(
|
||||
&mut network_service,
|
||||
vec![peer],
|
||||
PeerSet::Validation,
|
||||
WireMessage::<protocol_v1::ValidationProtocol>::ViewUpdate(
|
||||
local_view,
|
||||
),
|
||||
&metrics,
|
||||
);
|
||||
}
|
||||
PeerSet::Collation => {
|
||||
dispatch_collation_events_to_all(
|
||||
vec![
|
||||
NetworkBridgeEvent::PeerConnected(peer.clone(), role, maybe_authority),
|
||||
NetworkBridgeEvent::PeerViewChange(
|
||||
peer.clone(),
|
||||
View::default(),
|
||||
),
|
||||
],
|
||||
&mut sender,
|
||||
).await;
|
||||
|
||||
send_message(
|
||||
&mut network_service,
|
||||
vec![peer],
|
||||
PeerSet::Collation,
|
||||
WireMessage::<protocol_v1::CollationProtocol>::ViewUpdate(
|
||||
local_view,
|
||||
),
|
||||
&metrics,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(NetworkEvent::NotificationStreamClosed { remote: peer, protocol }) => {
|
||||
let peer_set = match PeerSet::try_from_protocol_name(&protocol) {
|
||||
None => continue,
|
||||
Some(peer_set) => peer_set,
|
||||
};
|
||||
|
||||
tracing::debug!(
|
||||
target: LOG_TARGET,
|
||||
action = "PeerDisconnected",
|
||||
peer_set = ?peer_set,
|
||||
peer = ?peer
|
||||
);
|
||||
|
||||
let was_connected = {
|
||||
let mut shared = shared.0.lock();
|
||||
let peer_map = match peer_set {
|
||||
PeerSet::Validation => &mut shared.validation_peers,
|
||||
PeerSet::Collation => &mut shared.collation_peers,
|
||||
};
|
||||
|
||||
let w = peer_map.remove(&peer).is_some();
|
||||
|
||||
metrics.on_peer_disconnected(peer_set);
|
||||
metrics.note_peer_count(peer_set, peer_map.len());
|
||||
|
||||
w
|
||||
};
|
||||
|
||||
if was_connected {
|
||||
match peer_set {
|
||||
PeerSet::Validation => dispatch_validation_event_to_all(
|
||||
PeerSet::Validation =>
|
||||
dispatch_validation_event_to_all(
|
||||
NetworkBridgeEvent::PeerDisconnected(peer),
|
||||
&mut sender,
|
||||
).await,
|
||||
PeerSet::Collation => dispatch_collation_event_to_all(
|
||||
)
|
||||
.await,
|
||||
PeerSet::Collation =>
|
||||
dispatch_collation_event_to_all(
|
||||
NetworkBridgeEvent::PeerDisconnected(peer),
|
||||
&mut sender,
|
||||
).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(NetworkEvent::NotificationsReceived { remote, messages }) => {
|
||||
let v_messages: Result<Vec<_>, _> = messages
|
||||
.iter()
|
||||
.filter(|(protocol, _)| {
|
||||
protocol == &PeerSet::Validation.into_protocol_name()
|
||||
})
|
||||
.map(|(_, msg_bytes)| {
|
||||
WireMessage::decode(&mut msg_bytes.as_ref())
|
||||
.map(|m| (m, msg_bytes.len()))
|
||||
})
|
||||
.collect();
|
||||
|
||||
let v_messages = match v_messages {
|
||||
Err(_) => {
|
||||
tracing::debug!(
|
||||
target: LOG_TARGET,
|
||||
action = "ReportPeer"
|
||||
);
|
||||
|
||||
network_service.report_peer(remote, MALFORMED_MESSAGE_COST);
|
||||
continue;
|
||||
}
|
||||
Ok(v) => v,
|
||||
};
|
||||
|
||||
let c_messages: Result<Vec<_>, _> = messages
|
||||
.iter()
|
||||
.filter(|(protocol, _)| {
|
||||
protocol == &PeerSet::Collation.into_protocol_name()
|
||||
})
|
||||
.map(|(_, msg_bytes)| {
|
||||
WireMessage::decode(&mut msg_bytes.as_ref())
|
||||
.map(|m| (m, msg_bytes.len()))
|
||||
})
|
||||
.collect();
|
||||
|
||||
match c_messages {
|
||||
Err(_) => {
|
||||
tracing::debug!(
|
||||
target: LOG_TARGET,
|
||||
action = "ReportPeer"
|
||||
);
|
||||
|
||||
network_service.report_peer(remote, MALFORMED_MESSAGE_COST);
|
||||
continue;
|
||||
}
|
||||
Ok(c_messages) => {
|
||||
if v_messages.is_empty() && c_messages.is_empty() {
|
||||
continue;
|
||||
} else {
|
||||
tracing::trace!(
|
||||
target: LOG_TARGET,
|
||||
action = "PeerMessages",
|
||||
peer = ?remote,
|
||||
num_validation_messages = %v_messages.len(),
|
||||
num_collation_messages = %c_messages.len()
|
||||
);
|
||||
|
||||
if !v_messages.is_empty() {
|
||||
let (events, reports) = handle_peer_messages(
|
||||
remote.clone(),
|
||||
PeerSet::Validation,
|
||||
&mut shared.0.lock().validation_peers,
|
||||
v_messages,
|
||||
&metrics,
|
||||
);
|
||||
|
||||
for report in reports {
|
||||
network_service.report_peer(remote.clone(), report);
|
||||
}
|
||||
|
||||
dispatch_validation_events_to_all(events, &mut sender).await;
|
||||
}
|
||||
|
||||
if !c_messages.is_empty() {
|
||||
let (events, reports) = handle_peer_messages(
|
||||
remote.clone(),
|
||||
PeerSet::Collation,
|
||||
&mut shared.0.lock().collation_peers,
|
||||
c_messages,
|
||||
&metrics,
|
||||
);
|
||||
|
||||
for report in reports {
|
||||
network_service.report_peer(remote.clone(), report);
|
||||
}
|
||||
|
||||
|
||||
dispatch_collation_events_to_all(events, &mut sender).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
.await,
|
||||
}
|
||||
}
|
||||
},
|
||||
req_res_event = request_multiplexer.next() => match req_res_event {
|
||||
None => return Err(UnexpectedAbort::RequestStreamConcluded),
|
||||
Some(Err(err)) => {
|
||||
network_service.report_peer(err.peer, MALFORMED_MESSAGE_COST);
|
||||
}
|
||||
Some(Ok(msg)) => {
|
||||
sender.send_message(msg).await;
|
||||
Some(NetworkEvent::NotificationsReceived { remote, messages }) => {
|
||||
let v_messages: Result<Vec<_>, _> = messages
|
||||
.iter()
|
||||
.filter(|(protocol, _)| protocol == &PeerSet::Validation.into_protocol_name())
|
||||
.map(|(_, msg_bytes)| {
|
||||
WireMessage::decode(&mut msg_bytes.as_ref()).map(|m| (m, msg_bytes.len()))
|
||||
})
|
||||
.collect();
|
||||
|
||||
let v_messages = match v_messages {
|
||||
Err(_) => {
|
||||
tracing::debug!(target: LOG_TARGET, action = "ReportPeer");
|
||||
|
||||
network_service.report_peer(remote, MALFORMED_MESSAGE_COST);
|
||||
continue
|
||||
},
|
||||
Ok(v) => v,
|
||||
};
|
||||
|
||||
let c_messages: Result<Vec<_>, _> = messages
|
||||
.iter()
|
||||
.filter(|(protocol, _)| protocol == &PeerSet::Collation.into_protocol_name())
|
||||
.map(|(_, msg_bytes)| {
|
||||
WireMessage::decode(&mut msg_bytes.as_ref()).map(|m| (m, msg_bytes.len()))
|
||||
})
|
||||
.collect();
|
||||
|
||||
match c_messages {
|
||||
Err(_) => {
|
||||
tracing::debug!(target: LOG_TARGET, action = "ReportPeer");
|
||||
|
||||
network_service.report_peer(remote, MALFORMED_MESSAGE_COST);
|
||||
continue
|
||||
},
|
||||
Ok(c_messages) =>
|
||||
if v_messages.is_empty() && c_messages.is_empty() {
|
||||
continue
|
||||
} else {
|
||||
tracing::trace!(
|
||||
target: LOG_TARGET,
|
||||
action = "PeerMessages",
|
||||
peer = ?remote,
|
||||
num_validation_messages = %v_messages.len(),
|
||||
num_collation_messages = %c_messages.len()
|
||||
);
|
||||
|
||||
if !v_messages.is_empty() {
|
||||
let (events, reports) = handle_peer_messages(
|
||||
remote.clone(),
|
||||
PeerSet::Validation,
|
||||
&mut shared.0.lock().validation_peers,
|
||||
v_messages,
|
||||
&metrics,
|
||||
);
|
||||
|
||||
for report in reports {
|
||||
network_service.report_peer(remote.clone(), report);
|
||||
}
|
||||
|
||||
dispatch_validation_events_to_all(events, &mut sender).await;
|
||||
}
|
||||
|
||||
if !c_messages.is_empty() {
|
||||
let (events, reports) = handle_peer_messages(
|
||||
remote.clone(),
|
||||
PeerSet::Collation,
|
||||
&mut shared.0.lock().collation_peers,
|
||||
c_messages,
|
||||
&metrics,
|
||||
);
|
||||
|
||||
for report in reports {
|
||||
network_service.report_peer(remote.clone(), report);
|
||||
}
|
||||
|
||||
dispatch_collation_events_to_all(events, &mut sender).await;
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -881,28 +842,14 @@ where
|
||||
{
|
||||
let shared = Shared::default();
|
||||
|
||||
let NetworkBridge {
|
||||
network_service,
|
||||
mut request_multiplexer,
|
||||
authority_discovery_service,
|
||||
metrics,
|
||||
sync_oracle,
|
||||
} = bridge;
|
||||
|
||||
let statement_receiver = request_multiplexer
|
||||
.get_statement_fetching()
|
||||
.expect("Gets initialized, must be `Some` on startup. qed.");
|
||||
|
||||
let dispute_receiver = request_multiplexer
|
||||
.get_dispute_sending()
|
||||
.expect("Gets initialized, must be `Some` on startup. qed.");
|
||||
let NetworkBridge { network_service, authority_discovery_service, metrics, sync_oracle } =
|
||||
bridge;
|
||||
|
||||
let (remote, network_event_handler) = handle_network_messages(
|
||||
ctx.sender().clone(),
|
||||
network_service.clone(),
|
||||
network_stream,
|
||||
authority_discovery_service.clone(),
|
||||
request_multiplexer,
|
||||
metrics.clone(),
|
||||
shared.clone(),
|
||||
)
|
||||
@@ -910,11 +857,6 @@ where
|
||||
|
||||
ctx.spawn("network-bridge-network-worker", Box::pin(remote))?;
|
||||
|
||||
ctx.send_message(DisputeDistributionMessage::DisputeSendingReceiver(dispute_receiver))
|
||||
.await;
|
||||
ctx.send_message(StatementDistributionMessage::StatementFetchingReceiver(statement_receiver))
|
||||
.await;
|
||||
|
||||
let subsystem_event_handler = handle_subsystem_messages(
|
||||
ctx,
|
||||
network_service,
|
||||
@@ -951,13 +893,6 @@ where
|
||||
);
|
||||
Err(SubsystemError::Context("Incoming network event stream concluded.".to_string()))
|
||||
},
|
||||
Err(UnexpectedAbort::RequestStreamConcluded) => {
|
||||
tracing::info!(
|
||||
target: LOG_TARGET,
|
||||
"Shutting down Network Bridge: underlying request stream concluded"
|
||||
);
|
||||
Err(SubsystemError::Context("Incoming network request stream concluded".to_string()))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,221 +0,0 @@
|
||||
// Copyright 2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Polkadot is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::{pin::Pin, unreachable};
|
||||
|
||||
use futures::{
|
||||
channel::mpsc,
|
||||
stream::{FusedStream, Stream},
|
||||
task::{Context, Poll},
|
||||
};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use parity_scale_codec::{Decode, Error as DecodingError};
|
||||
|
||||
use sc_network::{config as network, PeerId};
|
||||
|
||||
use polkadot_node_network_protocol::request_response::{
|
||||
request::IncomingRequest, v1, Protocol, RequestResponseConfig,
|
||||
};
|
||||
use polkadot_overseer::AllMessages;
|
||||
|
||||
/// Multiplex incoming network requests.
|
||||
///
|
||||
/// This multiplexer consumes all request streams and makes them a `Stream` of a single message
|
||||
/// type, useful for the network bridge to send them via the `Overseer` to other subsystems.
|
||||
///
|
||||
/// The resulting stream will end once any of its input ends.
|
||||
///
|
||||
// TODO: Get rid of this: <https://github.com/paritytech/polkadot/issues/2842>
|
||||
pub struct RequestMultiplexer {
|
||||
receivers: Vec<(Protocol, mpsc::Receiver<network::IncomingRequest>)>,
|
||||
statement_fetching: Option<mpsc::Receiver<network::IncomingRequest>>,
|
||||
dispute_sending: Option<mpsc::Receiver<network::IncomingRequest>>,
|
||||
next_poll: usize,
|
||||
}
|
||||
|
||||
/// Multiplexing can fail in case of invalid messages.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct RequestMultiplexError {
|
||||
/// The peer that sent the invalid message.
|
||||
pub peer: PeerId,
|
||||
/// The error that occurred.
|
||||
pub error: DecodingError,
|
||||
}
|
||||
|
||||
impl RequestMultiplexer {
|
||||
/// Create a new `RequestMultiplexer`.
|
||||
///
|
||||
/// This function uses `Protocol::get_config` for each available protocol and creates a
|
||||
/// `RequestMultiplexer` from it. The returned `RequestResponseConfig`s must be passed to the
|
||||
/// network implementation.
|
||||
pub fn new() -> (Self, Vec<RequestResponseConfig>) {
|
||||
let (mut receivers, cfgs): (Vec<_>, Vec<_>) = Protocol::iter()
|
||||
.map(|p| {
|
||||
let (rx, cfg) = p.get_config();
|
||||
((p, rx), cfg)
|
||||
})
|
||||
.unzip();
|
||||
|
||||
// Ok this code is ugly as hell, it is also a hack, see https://github.com/paritytech/polkadot/issues/2842.
|
||||
// But it works and is executed on startup so, if anything is wrong here it will be noticed immediately.
|
||||
let index = receivers
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find_map(
|
||||
|(i, (p, _))| if let Protocol::StatementFetching = p { Some(i) } else { None },
|
||||
)
|
||||
.expect("Statement fetching must be registered. qed.");
|
||||
let statement_fetching = Some(receivers.remove(index).1);
|
||||
|
||||
let index = receivers
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find_map(|(i, (p, _))| if let Protocol::DisputeSending = p { Some(i) } else { None })
|
||||
.expect("Dispute sending must be registered. qed.");
|
||||
let dispute_sending = Some(receivers.remove(index).1);
|
||||
|
||||
(Self { receivers, statement_fetching, dispute_sending, next_poll: 0 }, cfgs)
|
||||
}
|
||||
|
||||
/// Get the receiver for handling statement fetching requests.
|
||||
///
|
||||
/// This function will only return `Some` once.
|
||||
pub fn get_statement_fetching(&mut self) -> Option<mpsc::Receiver<network::IncomingRequest>> {
|
||||
std::mem::take(&mut self.statement_fetching)
|
||||
}
|
||||
|
||||
/// Get the receiver for handling dispute sending requests.
|
||||
///
|
||||
/// This function will only return `Some` once.
|
||||
pub fn get_dispute_sending(&mut self) -> Option<mpsc::Receiver<network::IncomingRequest>> {
|
||||
std::mem::take(&mut self.dispute_sending)
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for RequestMultiplexer {
|
||||
type Item = Result<AllMessages, RequestMultiplexError>;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
let len = self.receivers.len();
|
||||
let mut count = len;
|
||||
let mut i = self.next_poll;
|
||||
let mut result = Poll::Ready(None);
|
||||
// Poll streams in round robin fashion:
|
||||
while count > 0 {
|
||||
// % safe, because count initialized to len, loop would not be entered if 0, also
|
||||
// length of receivers is fixed.
|
||||
let (p, rx): &mut (_, _) = &mut self.receivers[i % len];
|
||||
// Avoid panic:
|
||||
if rx.is_terminated() {
|
||||
// Early return, we don't want to update next_poll.
|
||||
return Poll::Ready(None)
|
||||
}
|
||||
i += 1;
|
||||
count -= 1;
|
||||
match Pin::new(rx).poll_next(cx) {
|
||||
Poll::Pending => result = Poll::Pending,
|
||||
// We are done, once a single receiver is done.
|
||||
Poll::Ready(None) => return Poll::Ready(None),
|
||||
Poll::Ready(Some(v)) => {
|
||||
result = Poll::Ready(Some(multiplex_single(*p, v)));
|
||||
break
|
||||
},
|
||||
}
|
||||
}
|
||||
self.next_poll = i;
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl FusedStream for RequestMultiplexer {
|
||||
fn is_terminated(&self) -> bool {
|
||||
let len = self.receivers.len();
|
||||
if len == 0 {
|
||||
return true
|
||||
}
|
||||
let (_, rx) = &self.receivers[self.next_poll % len];
|
||||
rx.is_terminated()
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a single raw incoming request into a `MultiplexMessage`.
|
||||
fn multiplex_single(
|
||||
p: Protocol,
|
||||
network::IncomingRequest { payload, peer, pending_response }: network::IncomingRequest,
|
||||
) -> Result<AllMessages, RequestMultiplexError> {
|
||||
let r = match p {
|
||||
Protocol::ChunkFetching => AllMessages::from(IncomingRequest::new(
|
||||
peer,
|
||||
decode_with_peer::<v1::ChunkFetchingRequest>(peer, payload)?,
|
||||
pending_response,
|
||||
)),
|
||||
Protocol::CollationFetching => AllMessages::from(IncomingRequest::new(
|
||||
peer,
|
||||
decode_with_peer::<v1::CollationFetchingRequest>(peer, payload)?,
|
||||
pending_response,
|
||||
)),
|
||||
Protocol::PoVFetching => AllMessages::from(IncomingRequest::new(
|
||||
peer,
|
||||
decode_with_peer::<v1::PoVFetchingRequest>(peer, payload)?,
|
||||
pending_response,
|
||||
)),
|
||||
Protocol::AvailableDataFetching => AllMessages::from(IncomingRequest::new(
|
||||
peer,
|
||||
decode_with_peer::<v1::AvailableDataFetchingRequest>(peer, payload)?,
|
||||
pending_response,
|
||||
)),
|
||||
Protocol::StatementFetching => {
|
||||
unreachable!("Statement fetching requests are handled directly. qed.");
|
||||
},
|
||||
Protocol::DisputeSending => {
|
||||
unreachable!("Dispute sending request are handled directly. qed.");
|
||||
},
|
||||
};
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
fn decode_with_peer<Req: Decode>(
|
||||
peer: PeerId,
|
||||
payload: Vec<u8>,
|
||||
) -> Result<Req, RequestMultiplexError> {
|
||||
Req::decode(&mut payload.as_ref()).map_err(|error| RequestMultiplexError { peer, error })
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use futures::{prelude::*, stream::FusedStream};
|
||||
|
||||
use super::RequestMultiplexer;
|
||||
#[test]
|
||||
fn check_exhaustion_safety() {
|
||||
// Create and end streams:
|
||||
fn drop_configs() -> RequestMultiplexer {
|
||||
let (multiplexer, _) = RequestMultiplexer::new();
|
||||
multiplexer
|
||||
}
|
||||
let multiplexer = drop_configs();
|
||||
futures::executor::block_on(async move {
|
||||
let mut f = multiplexer;
|
||||
assert!(f.next().await.is_none());
|
||||
assert!(f.is_terminated());
|
||||
assert!(f.next().await.is_none());
|
||||
assert!(f.is_terminated());
|
||||
assert!(f.next().await.is_none());
|
||||
assert!(f.is_terminated());
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ use std::{
|
||||
|
||||
use sc_network::{Event as NetworkEvent, IfDisconnected};
|
||||
|
||||
use polkadot_node_network_protocol::{request_response::request::Requests, view, ObservedRole};
|
||||
use polkadot_node_network_protocol::{request_response::outgoing::Requests, view, ObservedRole};
|
||||
use polkadot_node_subsystem_test_helpers::{
|
||||
SingleItemSink, SingleItemStream, TestSubsystemContextHandle,
|
||||
};
|
||||
@@ -41,7 +41,7 @@ use polkadot_subsystem::{
|
||||
},
|
||||
ActiveLeavesUpdate, FromOverseer, LeafStatus, OverseerSignal,
|
||||
};
|
||||
use sc_network::{config::RequestResponseConfig, Multiaddr};
|
||||
use sc_network::Multiaddr;
|
||||
use sp_keyring::Sr25519Keyring;
|
||||
|
||||
use crate::{network::Network, validator_discovery::AuthorityDiscovery, Rep};
|
||||
@@ -61,7 +61,6 @@ pub enum NetworkAction {
|
||||
struct TestNetwork {
|
||||
net_events: Arc<Mutex<Option<SingleItemStream<NetworkEvent>>>>,
|
||||
action_tx: Arc<Mutex<metered::UnboundedMeteredSender<NetworkAction>>>,
|
||||
_req_configs: Vec<RequestResponseConfig>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -74,9 +73,7 @@ struct TestNetworkHandle {
|
||||
net_tx: SingleItemSink<NetworkEvent>,
|
||||
}
|
||||
|
||||
fn new_test_network(
|
||||
req_configs: Vec<RequestResponseConfig>,
|
||||
) -> (TestNetwork, TestNetworkHandle, TestAuthorityDiscovery) {
|
||||
fn new_test_network() -> (TestNetwork, TestNetworkHandle, TestAuthorityDiscovery) {
|
||||
let (net_tx, net_rx) = polkadot_node_subsystem_test_helpers::single_item_sink();
|
||||
let (action_tx, action_rx) = metered::unbounded();
|
||||
|
||||
@@ -84,7 +81,6 @@ fn new_test_network(
|
||||
TestNetwork {
|
||||
net_events: Arc::new(Mutex::new(Some(net_rx))),
|
||||
action_tx: Arc::new(Mutex::new(action_tx)),
|
||||
_req_configs: req_configs,
|
||||
},
|
||||
TestNetworkHandle { action_rx, net_tx },
|
||||
TestAuthorityDiscovery,
|
||||
@@ -285,8 +281,7 @@ fn test_harness<T: Future<Output = VirtualOverseer>>(
|
||||
test: impl FnOnce(TestHarness) -> T,
|
||||
) {
|
||||
let pool = sp_core::testing::TaskExecutor::new();
|
||||
let (request_multiplexer, req_configs) = RequestMultiplexer::new();
|
||||
let (mut network, network_handle, discovery) = new_test_network(req_configs);
|
||||
let (mut network, network_handle, discovery) = new_test_network();
|
||||
let (context, virtual_overseer) =
|
||||
polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
||||
let network_stream = network.event_stream();
|
||||
@@ -294,7 +289,6 @@ fn test_harness<T: Future<Output = VirtualOverseer>>(
|
||||
let bridge = NetworkBridge {
|
||||
network_service: network,
|
||||
authority_discovery_service: discovery,
|
||||
request_multiplexer,
|
||||
metrics: Metrics(None),
|
||||
sync_oracle,
|
||||
};
|
||||
@@ -642,17 +636,6 @@ fn peer_view_updates_sent_via_overseer() {
|
||||
|
||||
let view = view![Hash::repeat_byte(1)];
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::DisputeDistribution(DisputeDistributionMessage::DisputeSendingReceiver(_))
|
||||
);
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::StatementDistribution(
|
||||
StatementDistributionMessage::StatementFetchingReceiver(_)
|
||||
)
|
||||
);
|
||||
|
||||
// bridge will inform about all connected peers.
|
||||
{
|
||||
assert_sends_validation_event_to_all(
|
||||
@@ -696,17 +679,6 @@ fn peer_messages_sent_via_overseer() {
|
||||
.connect_peer(peer.clone(), PeerSet::Validation, ObservedRole::Full)
|
||||
.await;
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::DisputeDistribution(DisputeDistributionMessage::DisputeSendingReceiver(_))
|
||||
);
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::StatementDistribution(
|
||||
StatementDistributionMessage::StatementFetchingReceiver(_)
|
||||
)
|
||||
);
|
||||
|
||||
// bridge will inform about all connected peers.
|
||||
{
|
||||
assert_sends_validation_event_to_all(
|
||||
@@ -770,17 +742,6 @@ fn peer_disconnect_from_just_one_peerset() {
|
||||
|
||||
let peer = PeerId::random();
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::DisputeDistribution(DisputeDistributionMessage::DisputeSendingReceiver(_))
|
||||
);
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::StatementDistribution(
|
||||
StatementDistributionMessage::StatementFetchingReceiver(_)
|
||||
)
|
||||
);
|
||||
|
||||
network_handle
|
||||
.connect_peer(peer.clone(), PeerSet::Validation, ObservedRole::Full)
|
||||
.await;
|
||||
@@ -864,17 +825,6 @@ fn relays_collation_protocol_messages() {
|
||||
let peer_a = PeerId::random();
|
||||
let peer_b = PeerId::random();
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::DisputeDistribution(DisputeDistributionMessage::DisputeSendingReceiver(_))
|
||||
);
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::StatementDistribution(
|
||||
StatementDistributionMessage::StatementFetchingReceiver(_)
|
||||
)
|
||||
);
|
||||
|
||||
network_handle
|
||||
.connect_peer(peer_a.clone(), PeerSet::Validation, ObservedRole::Full)
|
||||
.await;
|
||||
@@ -975,17 +925,6 @@ fn different_views_on_different_peer_sets() {
|
||||
.connect_peer(peer.clone(), PeerSet::Collation, ObservedRole::Full)
|
||||
.await;
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::DisputeDistribution(DisputeDistributionMessage::DisputeSendingReceiver(_))
|
||||
);
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::StatementDistribution(
|
||||
StatementDistributionMessage::StatementFetchingReceiver(_)
|
||||
)
|
||||
);
|
||||
|
||||
// bridge will inform about all connected peers.
|
||||
{
|
||||
assert_sends_validation_event_to_all(
|
||||
@@ -1149,17 +1088,6 @@ fn send_messages_to_peers() {
|
||||
.connect_peer(peer.clone(), PeerSet::Collation, ObservedRole::Full)
|
||||
.await;
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::DisputeDistribution(DisputeDistributionMessage::DisputeSendingReceiver(_))
|
||||
);
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::StatementDistribution(
|
||||
StatementDistributionMessage::StatementFetchingReceiver(_)
|
||||
)
|
||||
);
|
||||
|
||||
// bridge will inform about all connected peers.
|
||||
{
|
||||
assert_sends_validation_event_to_all(
|
||||
@@ -1328,17 +1256,6 @@ fn our_view_updates_decreasing_order_and_limited_to_max() {
|
||||
.await;
|
||||
}
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::DisputeDistribution(DisputeDistributionMessage::DisputeSendingReceiver(_))
|
||||
);
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::StatementDistribution(
|
||||
StatementDistributionMessage::StatementFetchingReceiver(_)
|
||||
)
|
||||
);
|
||||
|
||||
let our_views = (1..=MAX_VIEW_HEADS).rev().map(|start| {
|
||||
OurView::new(
|
||||
(start..=MAX_VIEW_HEADS)
|
||||
|
||||
@@ -125,7 +125,7 @@ mod tests {
|
||||
|
||||
use async_trait::async_trait;
|
||||
use futures::stream::BoxStream;
|
||||
use polkadot_node_network_protocol::{request_response::request::Requests, PeerId};
|
||||
use polkadot_node_network_protocol::{request_response::outgoing::Requests, PeerId};
|
||||
use sc_network::{Event as NetworkEvent, IfDisconnected};
|
||||
use sp_keyring::Sr25519Keyring;
|
||||
use std::{borrow::Cow, collections::HashMap};
|
||||
|
||||
Reference in New Issue
Block a user