mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-23 00:21:08 +00:00
Generic request/response infrastructure for Polkadot (#2352)
* Move NetworkBridgeEvent to subsystem::messages. It is not protocol related at all, it is in fact only part of the subsystem communication as it gets wrapped into messages of each subsystem. * Request/response infrastructure is taking shape. WIP: Does not compile. * Multiplexer variant not supported by Rusts type system. * request_response::request type checks. * Cleanup. * Minor fixes for request_response. * Implement request sending + move multiplexer. Request multiplexer is moved to bridge, as there the implementation is more straight forward as we can specialize on `AllMessages` for the multiplexing target. Sending of requests is mostly complete, apart from a few `From` instances. Receiving is also almost done, initializtion needs to be fixed and the multiplexer needs to be invoked. * Remove obsolete multiplexer. * Initialize bridge with multiplexer. * Finish generic request sending/receiving. Subsystems are now able to receive and send requests and responses via the overseer. * Doc update. * Fixes. * Link issue for not yet implemented code. * Fixes suggested by @ordian - thanks! - start encoding at 0 - don't crash on zero protocols - don't panic on not yet implemented request handling * Update node/network/protocol/src/request_response/v1.rs Use index 0 instead of 1. Co-authored-by: Andronik Ordian <write@reusable.software> * Update node/network/protocol/src/request_response.rs Co-authored-by: Andronik Ordian <write@reusable.software> * Fix existing tests. * Better avoidance of division by zoro errors. * Doc fixes. * send_request -> start_request. * Fix missing renamings. * Update substrate. * Pass TryConnect instead of true. * Actually import `IfDisconnected`. * Fix wrong import. * Update node/network/bridge/src/lib.rs typo Co-authored-by: Pierre Krieger <pierre.krieger1708@gmail.com> * Update node/network/bridge/src/multiplexer.rs Remove redundant import. Co-authored-by: Pierre Krieger <pierre.krieger1708@gmail.com> * Stop doing tracing from within `From` instance. Thanks for the catch @tomaka! * Get rid of redundant import. * Formatting cleanup. * Fix tests. * Add link to issue. * Clarify comments some more. * Fix tests. * Formatting fix. * tabs * Fix link Co-authored-by: Bernhard Schuster <bernhard@ahoi.io> * Use map_err. Co-authored-by: Bernhard Schuster <bernhard@ahoi.io> * Improvements inspired by suggestions by @drahnr. - Channel size is now determined by function. - Explicitely scope NetworkService::start_request. Co-authored-by: Andronik Ordian <write@reusable.software> Co-authored-by: Pierre Krieger <pierre.krieger1708@gmail.com> Co-authored-by: Bernhard Schuster <bernhard@ahoi.io>
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
// 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;
|
||||
|
||||
use futures::channel::mpsc;
|
||||
use futures::stream::Stream;
|
||||
use futures::task::{Context, Poll};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use parity_scale_codec::{Decode, Error as DecodingError};
|
||||
|
||||
use sc_network::config as network;
|
||||
use sc_network::PeerId;
|
||||
|
||||
use polkadot_node_network_protocol::request_response::{
|
||||
request::IncomingRequest, v1, Protocol, RequestResponseConfig,
|
||||
};
|
||||
use polkadot_subsystem::messages::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.
|
||||
pub struct RequestMultiplexer {
|
||||
receivers: Vec<(Protocol, mpsc::Receiver<network::IncomingRequest>)>,
|
||||
next_poll: usize,
|
||||
}
|
||||
|
||||
/// Multiplexing can fail in case of invalid messages.
|
||||
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 (receivers, cfgs): (Vec<_>, Vec<_>) = Protocol::iter()
|
||||
.map(|p| {
|
||||
let (rx, cfg) = p.get_config();
|
||||
((p, rx), cfg)
|
||||
})
|
||||
.unzip();
|
||||
|
||||
(
|
||||
Self {
|
||||
receivers,
|
||||
next_poll: 0,
|
||||
},
|
||||
cfgs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
i += 1;
|
||||
count -= 1;
|
||||
match Pin::new(rx).poll_next(cx) {
|
||||
// If at least one stream is pending, then we are not done yet (No
|
||||
// Ready(None)).
|
||||
Poll::Pending => result = Poll::Pending,
|
||||
// Receiver is a fused stream, which allows for this simple handling of
|
||||
// exhausted ones.
|
||||
Poll::Ready(None) => {}
|
||||
Poll::Ready(Some(v)) => {
|
||||
result = Poll::Ready(Some(multiplex_single(*p, v)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.next_poll = i;
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
/// 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::AvailabilityFetching => From::from(IncomingRequest::new(
|
||||
peer,
|
||||
decode_with_peer::<v1::AvailabilityFetchingRequest>(peer, payload)?,
|
||||
pending_response,
|
||||
)),
|
||||
};
|
||||
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 })
|
||||
}
|
||||
Reference in New Issue
Block a user