Erasure encoding availability (#345)

* Erasure encoding availability initial commit

 * Modifications to availability store to keep chunks as well as
   reconstructed blocks and extrinsics.
 * Gossip messages containig signed erasure chunks.
 * Requesting eraure chunks with polkadot-specific messages.
 * Validation of erasure chunk messages.

* Apply suggestions from code review

Co-Authored-By: Luke Schoen <ltfschoen@users.noreply.github.com>

* Fix build after a merge

* Gossip erasure chunk messages under their own topic

* erasure_chunks should use the appropriate topic

* Updates Cargo.lock

* Fixes after merge

* Removes a couple of leftover pieces of code

* Fixes simple stuff from review

* Updates erasure and storage for more flexible logic

* Changes validation and candidate receipt production.

* Adds add_erasure_chunks method

* Fixes most of the nits

* Better validate_collation and validate_receipt functions

* Fixes the tests

* Apply suggestions from code review

Co-Authored-By: Robert Habermeier <rphmeier@gmail.com>

* Removes unwrap() calls

* Removes ErasureChunks primitive

* Removes redundant fields from ErasureChunk struct

* AvailabilityStore should store CandidateReceipt

* Changes the way chunk messages are imported and validated.

 * Availability store now stores a validator_index and n_validators for
 each relay_parent.
 * Availability store now also stores candidate receipts.
 * Removes importing chunks in the table and moves it into network
 gossip validation.
 * Validation of erasure messages id done against receipts that are
 stored in the availability store.

* Correctly compute topics for erasure messages

* Removes an unused parameter

* Refactors availability db querying into a helper

* Adds the apis described in the writeup

* Adds a runtime api to extract erasure roots form raw extrinsics.

* Adds a barebone BlockImport impl for avalability store

* Adds the implementation of the availability worker

* Fix build after the merge with master.

* Make availability store API async

* Bring back the default wasmtime feature

* Lines width

* Bump runtime version

* Formatting and dead code elimination

* some style nits (#1)

* More nits and api cleanup

* Disable wasm CI for availability-store

* Another nit

* Formatting
This commit is contained in:
Fedor Sakharov
2019-12-03 17:49:07 +03:00
committed by Robert Habermeier
parent ec54d5b1e4
commit 99d164b5e7
29 changed files with 2957 additions and 572 deletions
+7 -5
View File
@@ -184,7 +184,7 @@ impl CollatorPool {
/// The collation should have been checked for integrity of signature before passing to this function.
pub fn on_collation(&mut self, collator_id: CollatorId, relay_parent: Hash, collation: Collation) {
if let Some((para_id, _)) = self.collators.get(&collator_id) {
debug_assert_eq!(para_id, &collation.receipt.parachain_index);
debug_assert_eq!(para_id, &collation.info.parachain_index);
// TODO: punish if not primary? (https://github.com/paritytech/polkadot/issues/213)
@@ -279,7 +279,7 @@ mod tests {
pool.await_collation(relay_parent, para_id, tx1);
pool.await_collation(relay_parent, para_id, tx2);
pool.on_collation(primary.clone(), relay_parent, Collation {
receipt: CandidateReceipt {
info: CandidateReceipt {
parachain_index: para_id,
collator: primary.clone().into(),
signature: Default::default(),
@@ -288,7 +288,8 @@ mod tests {
fees: 0,
block_data_hash: [3; 32].into(),
upward_messages: Vec::new(),
},
erasure_root: [1u8; 32].into(),
}.into(),
pov: make_pov(vec![4, 5, 6]),
});
@@ -307,7 +308,7 @@ mod tests {
assert_eq!(pool.on_new_collator(primary.clone(), para_id.clone(), PeerId::random()), Role::Primary);
pool.on_collation(primary.clone(), relay_parent, Collation {
receipt: CandidateReceipt {
info: CandidateReceipt {
parachain_index: para_id,
collator: primary,
signature: Default::default(),
@@ -316,7 +317,8 @@ mod tests {
fees: 0,
block_data_hash: [3; 32].into(),
upward_messages: Vec::new(),
},
erasure_root: [1u8; 32].into(),
}.into(),
pov: make_pov(vec![4, 5, 6]),
});
+90 -4
View File
@@ -49,16 +49,19 @@
//! Peers who send information which was not allowed under a recent neighbor packet
//! will be noted as non-beneficial to Substrate's peer-set management utility.
use sp_runtime::{generic::BlockId, traits::ProvideRuntimeApi};
use sp_runtime::{generic::BlockId, traits::{ProvideRuntimeApi, BlakeTwo256, Hash as HashT}};
use sp_blockchain::Error as ClientError;
use sc_network::{config::Roles, PeerId, ReputationChange};
use sc_network::consensus_gossip::{
self as network_gossip, ValidationResult as GossipValidationResult,
ValidatorContext, MessageIntent, ConsensusMessage,
};
use polkadot_validation::SignedStatement;
use polkadot_validation::{SignedStatement};
use polkadot_primitives::{Block, Hash};
use polkadot_primitives::parachain::{ParachainHost, ValidatorId, Message as ParachainMessage};
use polkadot_primitives::parachain::{
ParachainHost, ValidatorId, Message as ParachainMessage, ErasureChunk as PrimitiveChunk
};
use polkadot_erasure_coding::{self as erasure};
use codec::{Decode, Encode};
use std::collections::HashMap;
@@ -92,6 +95,8 @@ mod benefit {
pub const NEW_CANDIDATE: Rep = Rep::new(100, "Polkadot: New candidate");
/// When a peer sends us a previously-unknown attestation.
pub const NEW_ATTESTATION: Rep = Rep::new(50, "Polkadot: New attestation");
/// When a peer sends us a previously-unknown erasure chunk.
pub const NEW_ERASURE_CHUNK: Rep = Rep::new(10, "Polkadot: New erasure chunk");
/// When a peer sends us a previously-unknown message packet.
pub const NEW_ICMP_MESSAGES: Rep = Rep::new(50, "Polkadot: New ICMP messages");
}
@@ -114,6 +119,10 @@ mod cost {
pub const BAD_NEIGHBOR_PACKET: Rep = Rep::new(-300, "Polkadot: Bad neighbor");
/// A peer sent us an ICMP queue we haven't advertised a need for.
pub const UNNEEDED_ICMP_MESSAGES: Rep = Rep::new(-100, "Polkadot: Unexpected ICMP message");
/// A peer sent us an erasure chunk referring to a candidate that we are not aware of.
pub const ORPHANED_ERASURE_CHUNK: Rep = Rep::new(-10, "An erasure chunk from unknown candidate");
/// A peer sent us an erasure chunk that does not match candidate's erasure root.
pub const ERASURE_CHUNK_WRONG_ROOT: Rep = Rep::new(-100, "Chunk doesn't match encoding root");
/// A peer sent us an ICMP queue with a bad root.
pub fn icmp_messages_root_mismatch(n_messages: usize) -> Rep {
@@ -137,7 +146,9 @@ pub enum GossipMessage {
#[codec(index = "3")]
ParachainMessages(GossipParachainMessages),
// TODO: https://github.com/paritytech/polkadot/issues/253
// erasure-coded chunks.
/// A packet containing one of the erasure-coding chunks of one candidate.
#[codec(index = "4")]
ErasureChunk(ErasureChunkMessage),
}
impl GossipMessage {
@@ -187,6 +198,24 @@ impl GossipStatement {
}
}
/// A gossip message containing one erasure chunk of a candidate block.
/// For each chunk of block erasure encoding one of this messages is constructed.
#[derive(Encode, Decode, Clone, Debug)]
pub struct ErasureChunkMessage {
/// The chunk itself.
pub chunk: PrimitiveChunk,
/// The relay parent of the block this chunk belongs to.
pub relay_parent: Hash,
/// The hash of the candidate receipt of the block this chunk belongs to.
pub candidate_hash: Hash,
}
impl From<ErasureChunkMessage> for GossipMessage {
fn from(chk: ErasureChunkMessage) -> Self {
GossipMessage::ErasureChunk(chk)
}
}
/// A packet of messages from one parachain to another.
///
/// These are all the messages posted from one parachain to another during the
@@ -303,6 +332,7 @@ pub fn register_validator<C: ChainContext + 'static>(
peers: HashMap::new(),
attestation_view: Default::default(),
message_routing_view: Default::default(),
availability_store: None,
chain,
})
});
@@ -368,6 +398,10 @@ impl RegisteredMessageValidator {
RegisteredMessageValidator { inner: validator as _ }
}
pub fn register_availability_store(&mut self, availability_store: av_store::Store) {
self.inner.inner.write().availability_store = Some(availability_store);
}
/// Note that we perceive a new leaf of the block-DAG. We will notify our neighbors that
/// we now accept parachain candidate attestations and incoming message queues
/// relevant to this leaf.
@@ -475,6 +509,7 @@ struct Inner<C: ?Sized> {
peers: HashMap<PeerId, PeerData>,
attestation_view: AttestationView,
message_routing_view: MessageRoutingView,
availability_store: Option<av_store::Store>,
chain: C,
}
@@ -504,6 +539,52 @@ impl<C: ?Sized + ChainContext> Inner<C> {
}
}
fn validate_erasure_chunk_packet(&mut self, msg: ErasureChunkMessage)
-> (GossipValidationResult<Hash>, ReputationChange)
{
if let Some(store) = &self.availability_store {
if let Some(receipt) = store.get_candidate(&msg.candidate_hash) {
let chunk_hash = erasure::branch_hash(
&receipt.erasure_root,
&msg.chunk.proof,
msg.chunk.index as usize
);
if chunk_hash != Ok(BlakeTwo256::hash(&msg.chunk.chunk)) {
(
GossipValidationResult::Discard,
cost::ERASURE_CHUNK_WRONG_ROOT
)
} else {
if let Some(awaited_chunks) = store.awaited_chunks() {
if awaited_chunks.contains(&(
msg.relay_parent,
receipt.erasure_root,
receipt.hash(),
msg.chunk.index,
)) {
let topic = av_store::erasure_coding_topic(
msg.relay_parent,
receipt.erasure_root,
msg.chunk.index,
);
return (
GossipValidationResult::ProcessAndKeep(topic),
benefit::NEW_ERASURE_CHUNK,
);
}
}
(GossipValidationResult::Discard, cost::NONE)
}
} else {
(GossipValidationResult::Discard, cost::ORPHANED_ERASURE_CHUNK)
}
} else {
(GossipValidationResult::Discard, cost::NONE)
}
}
fn multicast_neighbor_packet<F: FnMut(&PeerId, ConsensusMessage)>(
&self,
mut send_neighbor_packet: F,
@@ -536,6 +617,7 @@ impl<C: ChainContext + ?Sized> MessageValidator<C> {
peers: HashMap::new(),
attestation_view: Default::default(),
message_routing_view: Default::default(),
availability_store: None,
chain,
}),
}
@@ -594,6 +676,9 @@ impl<C: ChainContext + ?Sized> network_gossip::Validator<Block> for MessageValid
}
(res, cb)
}
Ok(GossipMessage::ErasureChunk(chunk)) => {
self.inner.write().validate_erasure_chunk_packet(chunk)
}
};
self.report(sender, cost_benefit);
@@ -775,6 +860,7 @@ mod tests {
fees: 1_000_000,
block_data_hash: [20u8; 32].into(),
upward_messages: Vec::new(),
erasure_root: [1u8; 32].into(),
};
let statement = GossipMessage::Statement(GossipStatement {
+89 -44
View File
@@ -27,12 +27,13 @@ pub mod gossip;
use codec::{Decode, Encode};
use futures::sync::oneshot;
use futures::future::Either;
use futures::prelude::*;
use futures03::{channel::mpsc, compat::Compat, StreamExt};
use futures03::{channel::mpsc, compat::{Compat, Stream01CompatExt}, FutureExt, StreamExt, TryFutureExt};
use polkadot_primitives::{Block, Hash, Header};
use polkadot_primitives::parachain::{
Id as ParaId, BlockData, CollatorId, CandidateReceipt, Collation, PoVBlock,
StructuredUnroutedIngress, ValidatorId, OutgoingMessages,
Id as ParaId, CollatorId, CandidateReceipt, Collation, PoVBlock,
StructuredUnroutedIngress, ValidatorId, OutgoingMessages, ErasureChunk,
};
use sc_network::{
PeerId, RequestId, Context, StatusMessage as GenericFullStatus,
@@ -48,7 +49,7 @@ use log::{trace, debug, warn};
use std::collections::{HashMap, HashSet};
use crate::gossip::{POLKADOT_ENGINE_ID, GossipMessage};
use crate::gossip::{POLKADOT_ENGINE_ID, GossipMessage, ErasureChunkMessage};
#[cfg(test)]
mod tests;
@@ -98,6 +99,63 @@ pub trait NetworkService: Send + Sync + 'static {
where F: FnOnce(&mut PolkadotProtocol, &mut dyn Context<Block>);
}
/// This is a newtype that implements a [`ProvideGossipMessages`] shim trait.
///
/// For any wrapped [`NetworkService`] type it implements a [`ProvideGossipMessages`].
/// For more details see documentation of [`ProvideGossipMessages`].
///
/// [`NetworkService`]: ./trait.NetworkService.html
/// [`ProvideGossipMessages`]: ../polkadot_availability_store/trait.ProvideGossipMessages.html
pub struct AvailabilityNetworkShim<T>(pub std::sync::Arc<T>);
impl<T> av_store::ProvideGossipMessages for AvailabilityNetworkShim<T>
where T: NetworkService
{
fn gossip_messages_for(&self, topic: Hash)
-> Box<dyn futures03::Stream<Item = (Hash, Hash, ErasureChunk)> + Unpin + Send>
{
Box::new(self.0.gossip_messages_for(topic)
.compat()
.filter_map(|msg| async move {
match msg {
Ok(msg) => match msg.0 {
GossipMessage::ErasureChunk(chunk) => {
Some((chunk.relay_parent, chunk.candidate_hash, chunk.chunk))
},
_ => None,
}
_ => None,
}
})
.boxed()
)
}
fn gossip_erasure_chunk(
&self,
relay_parent: Hash,
candidate_hash: Hash,
erasure_root: Hash,
chunk: ErasureChunk
) {
let topic = av_store::erasure_coding_topic(relay_parent, erasure_root, chunk.index);
self.0.gossip_message(
topic,
GossipMessage::ErasureChunk(ErasureChunkMessage {
chunk,
relay_parent,
candidate_hash,
})
)
}
}
impl<T> Clone for AvailabilityNetworkShim<T> {
fn clone(&self) -> Self {
AvailabilityNetworkShim(self.0.clone())
}
}
impl NetworkService for PolkadotNetworkService {
fn gossip_messages_for(&self, topic: Hash) -> GossipMessageStream {
let (tx, rx) = std::sync::mpsc::channel();
@@ -280,10 +338,6 @@ pub enum Message {
RequestPovBlock(RequestId, Hash, Hash),
/// Provide requested proof-of-validation block data by candidate hash or nothing if unknown.
PovBlock(RequestId, Option<PoVBlock>),
/// Request block data (relay_parent, candidate_hash)
RequestBlockData(RequestId, Hash, Hash),
/// Provide requested block data by candidate hash or nothing.
BlockData(RequestId, Option<BlockData>),
/// Tell a collator their role.
CollatorRole(Role),
/// A collation provided by a peer. Relay parent and collation.
@@ -444,24 +498,7 @@ impl PolkadotProtocol {
send_polkadot_message(ctx, who, Message::PovBlock(req_id, pov_block));
}
Message::RequestBlockData(req_id, relay_parent, candidate_hash) => {
let block_data = self.live_validation_leaves
.with_pov_block(
&relay_parent,
&candidate_hash,
|res| res.ok().map(|b| b.block_data.clone()),
)
.or_else(|| self.availability_store.as_ref()
.and_then(|s| s.block_data(relay_parent, candidate_hash))
);
send_polkadot_message(ctx, who, Message::BlockData(req_id, block_data));
}
Message::PovBlock(req_id, data) => self.on_pov_block(ctx, who, req_id, data),
Message::BlockData(_req_id, _data) => {
// current block data is never requested bare by the node.
ctx.report_peer(who, cost::UNEXPECTED_MESSAGE);
}
Message::Collation(relay_parent, collation) => self.on_collation(ctx, who, relay_parent, collation),
Message::CollatorRole(role) => self.on_new_role(ctx, who, role),
}
@@ -731,8 +768,8 @@ impl PolkadotProtocol {
relay_parent: Hash,
collation: Collation
) {
let collation_para = collation.receipt.parachain_index;
let collated_acc = collation.receipt.collator.clone();
let collation_para = collation.info.parachain_index;
let collated_acc = collation.info.collator.clone();
match self.peers.get(&from) {
None => ctx.report_peer(from, cost::UNKNOWN_PEER),
@@ -743,7 +780,7 @@ impl PolkadotProtocol {
Some((ref acc_id, ref para_id)) => {
ctx.report_peer(from.clone(), benefit::EXPECTED_MESSAGE);
let structurally_valid = para_id == &collation_para && acc_id == &collated_acc;
if structurally_valid && collation.receipt.check_signature().is_ok() {
if structurally_valid && collation.info.check_signature().is_ok() {
debug!(target: "p_net", "Received collation for parachain {:?} from peer {}", para_id, from);
ctx.report_peer(from, benefit::GOOD_COLLATION);
self.collators.on_collation(acc_id.clone(), relay_parent, collation)
@@ -798,23 +835,31 @@ impl PolkadotProtocol {
targets: HashSet<ValidatorId>,
collation: Collation,
outgoing_targeted: OutgoingMessages,
) -> std::io::Result<()> {
) -> impl futures::future::Future<Item = (), Error=()> {
debug!(target: "p_net", "Importing local collation on relay parent {:?} and parachain {:?}",
relay_parent, collation.receipt.parachain_index);
relay_parent, collation.info.parachain_index);
let outgoing_queues = polkadot_validation::outgoing_queues(&outgoing_targeted)
.map(|(_target, root, data)| (root, data))
.collect();
if let Some(ref availability_store) = self.availability_store {
availability_store.make_available(av_store::Data {
relay_parent,
parachain_id: collation.receipt.parachain_index,
candidate_hash: collation.receipt.hash(),
block_data: collation.pov.block_data.clone(),
outgoing_queues: Some(outgoing_queues),
})?;
}
let res = match self.availability_store {
Some(ref availability_store) => {
let availability_store_cloned = availability_store.clone();
let collation_cloned = collation.clone();
Either::A((async move {
let _ = availability_store_cloned.make_available(av_store::Data {
relay_parent,
parachain_id: collation_cloned.info.parachain_index,
block_data: collation_cloned.pov.block_data.clone(),
outgoing_queues: Some(outgoing_targeted.clone().into()),
}).await;
}
)
.unit_error()
.boxed()
.compat()
.then(|_| Ok(()))
)
}
None => Either::B(futures::future::ok::<(), ()>(())),
};
for (primary, cloned_collation) in self.local_collations.add_collation(relay_parent, targets, collation.clone()) {
match self.validators.get(&primary) {
@@ -831,7 +876,7 @@ impl PolkadotProtocol {
}
}
Ok(())
res
}
/// Give the network protocol a handle to an availability store, used for
+35 -9
View File
@@ -29,11 +29,12 @@ use polkadot_validation::{
};
use polkadot_primitives::{Block, Hash};
use polkadot_primitives::parachain::{
OutgoingMessages, CandidateReceipt, ParachainHost, ValidatorIndex, Collation, PoVBlock,
OutgoingMessages, CandidateReceipt, ParachainHost, ValidatorIndex, Collation, PoVBlock, ErasureChunk,
};
use crate::gossip::{RegisteredMessageValidator, GossipMessage, GossipStatement};
use crate::gossip::{RegisteredMessageValidator, GossipMessage, GossipStatement, ErasureChunkMessage};
use futures::prelude::*;
use futures03::{future::FutureExt, TryFutureExt};
use parking_lot::Mutex;
use log::{debug, trace};
@@ -52,7 +53,7 @@ pub(crate) fn attestation_topic(parent_hash: Hash) -> Hash {
BlakeTwo256::hash(&v[..])
}
/// Create a `Stream` of checked statements.
/// Create a `Stream` of checked messages.
///
/// The returned stream will not terminate, so it is required to make sure that the stream is
/// dropped when it is not required anymore. Otherwise, it will stick around in memory
@@ -192,19 +193,22 @@ impl<P: ProvideRuntimeApi + Send + Sync + 'static, E, N, T> Router<P, E, N, T> w
let parent_hash = self.parent_hash();
producer.prime(self.fetcher.api().clone())
.validate()
.boxed()
.compat()
.map(move |validated| {
// store the data before broadcasting statements, so other peers can fetch.
knowledge.lock().note_candidate(
candidate_hash,
Some(validated.pov_block().clone()),
validated.outgoing_messages().cloned(),
Some(validated.0.pov_block().clone()),
validated.0.outgoing_messages().cloned(),
);
// propagate the statement.
// consider something more targeted than gossip in the future.
let statement = GossipStatement::new(
parent_hash,
match table.import_validated(validated) {
match table.import_validated(validated.0) {
None => return,
Some(s) => s,
}
@@ -225,11 +229,19 @@ impl<P: ProvideRuntimeApi + Send, E, N, T> TableRouter for Router<P, E, N, T> wh
type Error = io::Error;
type FetchValidationProof = validation::PoVReceiver;
fn local_collation(&self, collation: Collation, outgoing: OutgoingMessages) {
// We have fetched from a collator and here the receipt should have been already formed.
fn local_collation(
&self,
collation: Collation,
receipt: CandidateReceipt,
outgoing: OutgoingMessages,
chunks: (ValidatorIndex, &[ErasureChunk])
) {
// produce a signed statement
let hash = collation.receipt.hash();
let hash = receipt.hash();
let erasure_root = receipt.erasure_root;
let validated = Validated::collated_local(
collation.receipt,
receipt,
collation.pov.clone(),
outgoing.clone(),
);
@@ -245,6 +257,20 @@ impl<P: ProvideRuntimeApi + Send, E, N, T> TableRouter for Router<P, E, N, T> wh
// give to network to make available.
self.fetcher.knowledge().lock().note_candidate(hash, Some(collation.pov), Some(outgoing));
self.network().gossip_message(self.attestation_topic, statement.into());
for chunk in chunks.1 {
let relay_parent = self.parent_hash();
let message = ErasureChunkMessage {
chunk: chunk.clone(),
relay_parent,
candidate_hash: hash,
};
self.network().gossip_message(
av_store::erasure_coding_topic(relay_parent, erasure_root, chunk.index),
message.into()
);
}
}
fn fetch_pov_block(&self, candidate: &CandidateReceipt) -> Self::FetchValidationProof {
+2 -51
View File
@@ -24,7 +24,7 @@ use polkadot_validation::GenericStatement;
use polkadot_primitives::{Block, Hash};
use polkadot_primitives::parachain::{
CandidateReceipt, HeadData, PoVBlock, BlockData, CollatorId, ValidatorId,
StructuredUnroutedIngress
StructuredUnroutedIngress,
};
use sp_core::crypto::UncheckedInto;
use codec::Encode;
@@ -183,6 +183,7 @@ fn fetches_from_those_with_knowledge() {
fees: 1_000_000,
block_data_hash,
upward_messages: Vec::new(),
erasure_root: [1u8; 32].into(),
};
let candidate_hash = candidate_receipt.hash();
@@ -248,56 +249,6 @@ fn fetches_from_those_with_knowledge() {
}
}
#[test]
fn fetches_available_block_data() {
let mut protocol = PolkadotProtocol::new(None);
let peer_a = PeerId::random();
let parent_hash = [0; 32].into();
let block_data = BlockData(vec![1, 2, 3, 4]);
let block_data_hash = block_data.hash();
let para_id = 5.into();
let candidate_receipt = CandidateReceipt {
parachain_index: para_id,
collator: [255; 32].unchecked_into(),
head_data: HeadData(vec![9, 9, 9]),
signature: Default::default(),
egress_queue_roots: Vec::new(),
fees: 1_000_000,
block_data_hash,
upward_messages: Vec::new(),
};
let candidate_hash = candidate_receipt.hash();
let av_store = ::av_store::Store::new_in_memory();
let status = Status { collating_for: None };
protocol.register_availability_store(av_store.clone());
av_store.make_available(::av_store::Data {
relay_parent: parent_hash,
parachain_id: para_id,
candidate_hash,
block_data: block_data.clone(),
outgoing_queues: None,
}).unwrap();
// connect peer A
{
let mut ctx = TestContext::default();
protocol.on_connect(&mut ctx, peer_a.clone(), make_status(&status, Roles::FULL));
}
// peer A asks for historic block data and gets response
{
let mut ctx = TestContext::default();
on_message(&mut protocol, &mut ctx, peer_a.clone(), Message::RequestBlockData(1, parent_hash, candidate_hash));
assert!(ctx.has_message(peer_a, Message::BlockData(1, Some(block_data))));
}
}
#[test]
fn remove_bad_collator() {
let mut protocol = PolkadotProtocol::new(None);
+34 -3
View File
@@ -30,12 +30,12 @@ use polkadot_primitives::{Block, BlockNumber, Hash, Header, BlockId};
use polkadot_primitives::parachain::{
Id as ParaId, Chain, DutyRoster, ParachainHost, TargetedMessage,
ValidatorId, StructuredUnroutedIngress, BlockIngressRoots, Status,
FeeSchedule, HeadData, Retriable, CollatorId
FeeSchedule, HeadData, Retriable, CollatorId, ErasureChunk, CandidateReceipt,
};
use parking_lot::Mutex;
use sp_blockchain::Result as ClientResult;
use sp_api::{Core, RuntimeVersion, StorageProof, ApiExt};
use sp_runtime::traits::{ApiRef, ProvideRuntimeApi};
use sp_runtime::traits::{ApiRef, {Block as BlockT}, ProvideRuntimeApi};
use std::collections::HashMap;
use std::sync::Arc;
@@ -322,6 +322,16 @@ impl ParachainHost<Block> for RuntimeApi {
let (id, _) = id.unwrap();
Ok(NativeOrEncoded::Native(self.data.lock().ingress.get(&id).cloned()))
}
fn ParachainHost_get_heads_runtime_api_impl(
&self,
_at: &BlockId,
_: ExecutionContext,
_extrinsics: Option<Vec<<Block as BlockT>::Extrinsic>>,
_: Vec<u8>,
) -> ClientResult<NativeOrEncoded<Option<Vec<CandidateReceipt>>>> {
Ok(NativeOrEncoded::Native(Some(Vec::new())))
}
}
type TestValidationNetwork = crate::validation::ValidationNetwork<
@@ -399,13 +409,34 @@ impl IngressBuilder {
}
}
#[derive(Clone)]
struct DummyGossipMessages;
use futures::stream;
impl av_store::ProvideGossipMessages for DummyGossipMessages {
fn gossip_messages_for(
&self,
_topic: Hash
) -> Box<dyn futures03::Stream<Item = (Hash, Hash, ErasureChunk)> + Send + Unpin> {
Box::new(futures03::stream::empty())
}
fn gossip_erasure_chunk(
&self,
_relay_parent: Hash,
_candidate_hash: Hash,
_erasure_root: Hash,
_chunk: ErasureChunk,
) {}
}
fn make_table(data: &ApiData, local_key: &Sr25519Keyring, parent_hash: Hash) -> Arc<SharedTable> {
use av_store::Store;
use sp_core::crypto::Pair;
let sr_pair = local_key.pair();
let local_key = polkadot_primitives::parachain::ValidatorPair::from(local_key.pair());
let store = Store::new_in_memory();
let store = Store::new_in_memory(DummyGossipMessages);
let (group_info, _) = ::polkadot_validation::make_group_info(
DutyRoster { validator_duty: data.duties.clone() },
&data.validators, // only possible as long as parachain crypto === aura crypto
+2 -2
View File
@@ -27,7 +27,7 @@ use polkadot_validation::{
use polkadot_primitives::{Block, BlockId, Hash};
use polkadot_primitives::parachain::{
Id as ParaId, Collation, OutgoingMessages, ParachainHost, CandidateReceipt, CollatorId,
ValidatorId, PoVBlock
ValidatorId, PoVBlock,
};
use futures::prelude::*;
@@ -243,7 +243,7 @@ impl<P, E, N, T> ParachainNetwork for ValidationNetwork<P, E, N, T> where
let table_router_clone = table_router.clone();
let work = table_router.checked_statements()
.for_each(move |msg| { table_router_clone.import_statement(msg); Ok(()) });
executor.spawn(work.select(exit).map(|_| ()).map_err(|_| ()));
executor.spawn(work.select(exit.clone()).map(|_| ()).map_err(|_| ()));
table_router
});