Port availability recovery to use req/res (#2694)

* add AvailableDataFetchingRequest

* rename AvailabilityFetchingRequest to ChunkFetchingRequest

* rename AvailabilityFetchingResponse to Chunk_

* add AvailableDataFetching request

* add available data fetching request to availability recovery message

* remove availability recovery message

* fix

* update network bridge

* port availability recovery to request/response

* use validators.len(), not shuffling

* fix availability recovery tests

* update guide

* Update node/network/availability-recovery/src/lib.rs

Co-authored-by: Bernhard Schuster <bernhard@ahoi.io>

* Update node/network/availability-recovery/src/lib.rs

Co-authored-by: Arkadiy Paronyan <arkady.paronyan@gmail.com>

* remove println

Co-authored-by: Bernhard Schuster <bernhard@ahoi.io>
Co-authored-by: Arkadiy Paronyan <arkady.paronyan@gmail.com>
This commit is contained in:
Robert Habermeier
2021-03-25 15:34:24 +01:00
committed by GitHub
parent 349879df6b
commit 8a396c678f
19 changed files with 379 additions and 1067 deletions
@@ -56,10 +56,12 @@ pub mod v1;
/// within protocols.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, EnumIter)]
pub enum Protocol {
/// Protocol for availability fetching, used by availability distribution.
AvailabilityFetching,
/// Protocol for chunk fetching, used by availability distribution and availability recovery.
ChunkFetching,
/// Protocol for fetching collations from collators.
CollationFetching,
/// Protocol for fetching available data.
AvailableDataFetching,
}
/// Default request timeout in seconds.
@@ -67,7 +69,7 @@ pub enum Protocol {
/// When decreasing this value, take into account that the very first request might need to open a
/// connection, which can be slow. If this causes problems, we should ensure connectivity via peer
/// sets.
const DEFAULT_REQUEST_TIMEOUT: Duration = Duration::from_secs(3);
const DEFAULT_REQUEST_TIMEOUT: Duration = Duration::from_secs(3);
/// Request timeout where we can assume the connection is already open (e.g. we have peers in a
/// peer set as well).
@@ -90,7 +92,7 @@ impl Protocol {
let p_name = self.into_protocol_name();
let (tx, rx) = mpsc::channel(self.get_channel_size());
let cfg = match self {
Protocol::AvailabilityFetching => RequestResponseConfig {
Protocol::ChunkFetching => RequestResponseConfig {
name: p_name,
max_request_size: 10_000,
max_response_size: 10_000_000,
@@ -105,6 +107,14 @@ impl Protocol {
request_timeout: DEFAULT_REQUEST_TIMEOUT_CONNECTED,
inbound_queue: Some(tx),
},
Protocol::AvailableDataFetching => RequestResponseConfig {
name: p_name,
max_request_size: 1_000,
// Available data size is dominated by the PoV size.
max_response_size: 30_000_000,
request_timeout: DEFAULT_REQUEST_TIMEOUT,
inbound_queue: Some(tx),
},
};
(rx, cfg)
}
@@ -117,9 +127,12 @@ impl Protocol {
// times (due to network delays), 100 seems big enough to accomodate for "bursts",
// assuming we can service requests relatively quickly, which would need to be measured
// as well.
Protocol::AvailabilityFetching => 100,
Protocol::ChunkFetching => 100,
// 10 seems reasonable, considering group sizes of max 10 validators.
Protocol::CollationFetching => 10,
// Validators are constantly self-selecting to request available data which may lead
// to constant load and occasional burstiness.
Protocol::AvailableDataFetching => 100,
}
}
@@ -131,8 +144,9 @@ impl Protocol {
/// Get the protocol name associated with each peer set as static str.
pub const fn get_protocol_name_static(self) -> &'static str {
match self {
Protocol::AvailabilityFetching => "/polkadot/req_availability/1",
Protocol::ChunkFetching => "/polkadot/req_chunk/1",
Protocol::CollationFetching => "/polkadot/req_collation/1",
Protocol::AvailableDataFetching => "/polkadot/req_available_data/1",
}
}
}
@@ -39,17 +39,20 @@ pub trait IsRequest {
#[derive(Debug)]
pub enum Requests {
/// Request an availability chunk from a node.
AvailabilityFetching(OutgoingRequest<v1::AvailabilityFetchingRequest>),
ChunkFetching(OutgoingRequest<v1::ChunkFetchingRequest>),
/// Fetch a collation from a collator which previously announced it.
CollationFetching(OutgoingRequest<v1::CollationFetchingRequest>),
/// Request full available data from a node.
AvailableDataFetching(OutgoingRequest<v1::AvailableDataFetchingRequest>),
}
impl Requests {
/// Get the protocol this request conforms to.
pub fn get_protocol(&self) -> Protocol {
match self {
Self::AvailabilityFetching(_) => Protocol::AvailabilityFetching,
Self::ChunkFetching(_) => Protocol::ChunkFetching,
Self::CollationFetching(_) => Protocol::CollationFetching,
Self::AvailableDataFetching(_) => Protocol::AvailableDataFetching,
}
}
@@ -62,8 +65,9 @@ impl Requests {
/// contained in the enum.
pub fn encode_request(self) -> (Protocol, OutgoingRequest<Vec<u8>>) {
match self {
Self::AvailabilityFetching(r) => r.encode_request(),
Self::ChunkFetching(r) => r.encode_request(),
Self::CollationFetching(r) => r.encode_request(),
Self::AvailableDataFetching(r) => r.encode_request(),
}
}
}
@@ -92,6 +96,7 @@ pub struct OutgoingRequest<Req> {
}
/// Any error that can occur when sending a request.
#[derive(Debug)]
pub enum RequestError {
/// Response could not be decoded.
InvalidResponse(DecodingError),
@@ -18,7 +18,10 @@
use parity_scale_codec::{Decode, Encode};
use polkadot_primitives::v1::{CandidateHash, CandidateReceipt, ErasureChunk, ValidatorIndex, CompressedPoV, Hash};
use polkadot_primitives::v1::{
AvailableData, CandidateHash, CandidateReceipt, ErasureChunk, ValidatorIndex,
CompressedPoV, Hash,
};
use polkadot_primitives::v1::Id as ParaId;
use super::request::IsRequest;
@@ -26,16 +29,16 @@ use super::Protocol;
/// Request an availability chunk.
#[derive(Debug, Copy, Clone, Encode, Decode)]
pub struct AvailabilityFetchingRequest {
pub struct ChunkFetchingRequest {
/// Hash of candidate we want a chunk for.
pub candidate_hash: CandidateHash,
/// The index of the chunk to fetch.
pub index: ValidatorIndex,
}
/// Receive a rqeuested erasure chunk.
/// Receive a requested erasure chunk.
#[derive(Debug, Clone, Encode, Decode)]
pub enum AvailabilityFetchingResponse {
pub enum ChunkFetchingResponse {
/// The requested chunk data.
#[codec(index = 0)]
Chunk(ChunkResponse),
@@ -44,10 +47,19 @@ pub enum AvailabilityFetchingResponse {
NoSuchChunk,
}
impl From<Option<ChunkResponse>> for ChunkFetchingResponse {
fn from(x: Option<ChunkResponse>) -> Self {
match x {
Some(c) => ChunkFetchingResponse::Chunk(c),
None => ChunkFetchingResponse::NoSuchChunk,
}
}
}
/// Skimmed down variant of `ErasureChunk`.
///
/// Instead of transmitting a full `ErasureChunk` we transmit `ChunkResponse` in
/// `AvailabilityFetchingResponse`, which omits the chunk's index. The index is already known by
/// `ChunkFetchingResponse`, which omits the chunk's index. The index is already known by
/// the requester and by not transmitting it, we ensure the requester is going to use his index
/// value for validating the response, thus making sure he got what he requested.
#[derive(Debug, Clone, Encode, Decode)]
@@ -66,7 +78,7 @@ impl From<ErasureChunk> for ChunkResponse {
impl ChunkResponse {
/// Re-build an `ErasureChunk` from response and request.
pub fn recombine_into_chunk(self, req: &AvailabilityFetchingRequest) -> ErasureChunk {
pub fn recombine_into_chunk(self, req: &ChunkFetchingRequest) -> ErasureChunk {
ErasureChunk {
chunk: self.chunk,
proof: self.proof,
@@ -75,9 +87,9 @@ impl ChunkResponse {
}
}
impl IsRequest for AvailabilityFetchingRequest {
type Response = AvailabilityFetchingResponse;
const PROTOCOL: Protocol = Protocol::AvailabilityFetching;
impl IsRequest for ChunkFetchingRequest {
type Response = ChunkFetchingResponse;
const PROTOCOL: Protocol = Protocol::ChunkFetching;
}
/// Request the advertised collation at that relay-parent.
@@ -101,3 +113,35 @@ impl IsRequest for CollationFetchingRequest {
type Response = CollationFetchingResponse;
const PROTOCOL: Protocol = Protocol::CollationFetching;
}
/// Request the entire available data for a candidate.
#[derive(Debug, Clone, Encode, Decode)]
pub struct AvailableDataFetchingRequest {
/// The candidate hash to get the available data for.
pub candidate_hash: CandidateHash,
}
/// Receive a requested available data.
#[derive(Debug, Clone, Encode, Decode)]
pub enum AvailableDataFetchingResponse {
/// The requested data.
#[codec(index = 0)]
AvailableData(AvailableData),
/// Node was not in possession of the requested data.
#[codec(index = 1)]
NoSuchData,
}
impl From<Option<AvailableData>> for AvailableDataFetchingResponse {
fn from(x: Option<AvailableData>) -> Self {
match x {
Some(data) => AvailableDataFetchingResponse::AvailableData(data),
None => AvailableDataFetchingResponse::NoSuchData,
}
}
}
impl IsRequest for AvailableDataFetchingRequest {
type Response = AvailableDataFetchingResponse;
const PROTOCOL: Protocol = Protocol::AvailableDataFetching;
}