mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-29 11:27:24 +00:00
305375e1e4
* Wip * Increase proposer timeout. * WIP. * Better timeout values now that we are going to be connected to all nodes. (#2778) * Better timeout values. * Fix typo. * Fix validator bandwidth. * Fix compilation. * Better and more consistent sizes. Most importantly code size is now 5 Meg, which is the limit we currently want to support in statement distribution. * Introduce statement fetching request. * WIP * Statement cache retrieval logic. * Review remarks by @rphmeier * Fixes. * Better requester logic. * WIP: Handle requester messages. * Missing dep. * Fix request launching logic. * Finish fetching logic. * Sending logic. * Redo code size calculations. Now that max code size is compressed size. * Update Cargo.lock (new dep) * Get request receiver to statement distribution. * Expose new functionality for responding to requests. * Cleanup. * Responder logic. * Fixes + Cleanup. * Cargo.lock * Whitespace. * Add lost copyright. * Launch responder task. * Typo. * info -> warn * Typo. * Fix. * Fix. * Update comment. * Doc fix. * Better large statement heuristics. * Fix tests. * Fix network bridge tests. * Add test for size estimate. * Very simple tests that checks we get LargeStatement. * Basic check, that fetching of large candidates is performed. * More tests. * Basic metrics for responder. * More metrics. * Use Encode::encoded_size(). * Some useful spans. * Get rid of redundant metrics. * Don't add peer on duplicate. * Properly check hash instead of relying on signatures alone. * Preserve ordering + better flood protection. * Get rid of redundant clone. * Don't shutdown responder on failed query. And add test for this. * Smaller fixes. * Quotes. * Better queue size calculation. * A bit saner response sizes. * Fixes.
213 lines
6.1 KiB
Rust
213 lines
6.1 KiB
Rust
// 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::{FusedStream, 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.
|
|
///
|
|
/// 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>>,
|
|
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();
|
|
|
|
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);
|
|
|
|
(
|
|
Self {
|
|
receivers,
|
|
statement_fetching,
|
|
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)
|
|
}
|
|
}
|
|
|
|
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 => From::from(IncomingRequest::new(
|
|
peer,
|
|
decode_with_peer::<v1::ChunkFetchingRequest>(peer, payload)?,
|
|
pending_response,
|
|
)),
|
|
Protocol::CollationFetching => From::from(IncomingRequest::new(
|
|
peer,
|
|
decode_with_peer::<v1::CollationFetchingRequest>(peer, payload)?,
|
|
pending_response,
|
|
)),
|
|
Protocol::PoVFetching => From::from(IncomingRequest::new(
|
|
peer,
|
|
decode_with_peer::<v1::PoVFetchingRequest>(peer, payload)?,
|
|
pending_response,
|
|
)),
|
|
Protocol::AvailableDataFetching => From::from(IncomingRequest::new(
|
|
peer,
|
|
decode_with_peer::<v1::AvailableDataFetchingRequest>(peer, payload)?,
|
|
pending_response,
|
|
)),
|
|
Protocol::StatementFetching => {
|
|
panic!("Statement fetching requests 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::*;
|
|
use futures::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());
|
|
});
|
|
}
|
|
}
|