ICMP message-routing gossip (#304)

* core logic for ICMP gossip

* refactor gossip to make more extension friendly

* move files aroun

* extract attestation-gossip logic to its own module

* message validation and broadcast logic

* fix upstream crates' compilation

* add a test

* another test for overlapping

* Some grammar and phrasing tweaks

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

* add since parameter to ingress runtime API

* broadcast out known unrouted message queues

* fix compilation of service and collator

* remove useless index_mapping

* some tests for icmp propagation

* fix decoding bug and test icmp queue validation

* simplify engine-id definition

Co-Authored-By: Sergei Pepyakin <sergei@parity.io>

* address some grumbles

* some cleanup of old circulation code

* give network a handle to extrinsic store on startup

* an honest collator ensures data available as well

* address some grumbles

* add docs; rename the attestation session to "leaf work"

* module docs

* move gossip back to gossip.rs

* clean up and document attestation-gossip a bit

* some more docs on the availability store

* store all outgoing message queues in the availability store

* filter `Extrinsic` out of validation crate

* expunge Extrinsic from network

* expunge Extrinsic from erasure-coding

* expunge Extrinsic from collator

* expunge from adder-collator

* rename ExtrinsicStore to AvailabilityStore everywhere

* annotate and clean up message-routing tests
This commit is contained in:
Robert Habermeier
2019-08-29 11:49:59 +02:00
committed by GitHub
parent bd8ebbfee5
commit 55c4c830fe
22 changed files with 1981 additions and 818 deletions
@@ -29,13 +29,13 @@ use client::{error::Result as ClientResult, BlockchainEvents, BlockBody};
use client::block_builder::api::BlockBuilder;
use client::blockchain::HeaderBackend;
use consensus::SelectChain;
use extrinsic_store::Store as ExtrinsicStore;
use availability_store::Store as AvailabilityStore;
use futures::prelude::*;
use futures03::{TryStreamExt as _, StreamExt as _};
use log::error;
use polkadot_primitives::{Block, BlockId};
use polkadot_primitives::parachain::{CandidateReceipt, ParachainHost};
use runtime_primitives::traits::{ProvideRuntimeApi, Header as HeaderT};
use runtime_primitives::traits::{ProvideRuntimeApi};
use babe_primitives::BabeApi;
use keystore::KeyStorePtr;
@@ -73,7 +73,7 @@ pub(crate) fn fetch_candidates<P: BlockBody<Block>>(client: &P, block: &BlockId)
//
// NOTE: this will need to be changed to finality notification rather than
// block import notifications when the consensus switches to non-instant finality.
fn prune_unneeded_availability<P>(client: Arc<P>, extrinsic_store: ExtrinsicStore)
fn prune_unneeded_availability<P>(client: Arc<P>, availability_store: AvailabilityStore)
-> impl Future<Item=(),Error=()> + Send
where P: Send + Sync + BlockchainEvents<Block> + BlockBody<Block> + 'static
{
@@ -94,7 +94,7 @@ fn prune_unneeded_availability<P>(client: Arc<P>, extrinsic_store: ExtrinsicStor
}
};
if let Err(e) = extrinsic_store.candidates_finalized(parent_hash, candidate_hashes) {
if let Err(e) = availability_store.candidates_finalized(parent_hash, candidate_hashes) {
warn!(target: "validation", "Failed to prune unneeded available data: {:?}", e);
}
@@ -115,7 +115,7 @@ pub(crate) fn start<C, N, P, SC>(
parachain_validation: Arc<crate::ParachainValidation<C, N, P>>,
thread_pool: TaskExecutor,
keystore: KeyStorePtr,
extrinsic_store: ExtrinsicStore,
availability_store: AvailabilityStore,
max_block_data_size: Option<u64>,
) -> ServiceHandle
where
@@ -148,7 +148,6 @@ pub(crate) fn start<C, N, P, SC>(
if notification.is_new_best {
let res = validation.get_or_instantiate(
parent_hash,
notification.header.parent_hash().clone(),
&keystore,
max_block_data_size,
);
@@ -194,7 +193,7 @@ pub(crate) fn start<C, N, P, SC>(
error!("Failed to spawn old sessions pruning task");
}
let prune_available = prune_unneeded_availability(client, extrinsic_store)
let prune_available = prune_unneeded_availability(client, availability_store)
.select(exit.clone())
.then(|_| Ok(()));
+26 -26
View File
@@ -23,7 +23,7 @@ use std::sync::Arc;
use polkadot_primitives::{Block, Hash, BlockId, Balance, parachain::{
CollatorId, ConsolidatedIngress, StructuredUnroutedIngress, CandidateReceipt, ParachainHost,
Id as ParaId, Collation, Extrinsic, OutgoingMessage, UpwardMessage, FeeSchedule,
Id as ParaId, Collation, TargetedMessage, OutgoingMessages, UpwardMessage, FeeSchedule,
}};
use runtime_primitives::traits::ProvideRuntimeApi;
use parachain::{wasm_executor::{self, ExternalitiesError, ExecutionMode}, MessageRef, UpwardMessageRef};
@@ -100,10 +100,10 @@ impl<C: Collators, P> CollationFetch<C, P> {
impl<C: Collators, P: ProvideRuntimeApi> Future for CollationFetch<C, P>
where P::Api: ParachainHost<Block>,
{
type Item = (Collation, Extrinsic);
type Item = (Collation, OutgoingMessages);
type Error = C::Error;
fn poll(&mut self) -> Poll<(Collation, Extrinsic), C::Error> {
fn poll(&mut self) -> Poll<(Collation, OutgoingMessages), C::Error> {
loop {
let collation = {
let parachain = self.parachain.clone();
@@ -182,15 +182,15 @@ impl std::error::Error for Error {
}
}
/// Compute a trie root for a set of messages.
/// Compute a trie root for a set of messages, given the raw message data.
pub fn message_queue_root<A, I: IntoIterator<Item=A>>(messages: I) -> Hash
where A: AsRef<[u8]>
{
::trie::trie_types::Layout::<primitives::Blake2Hasher>::ordered_trie_root(messages)
trie::trie_types::Layout::<primitives::Blake2Hasher>::ordered_trie_root(messages)
}
/// Compute the set of egress roots for all given outgoing messages.
pub fn egress_roots(outgoing: &mut [OutgoingMessage]) -> Vec<(ParaId, Hash)> {
pub fn egress_roots(outgoing: &mut [TargetedMessage]) -> Vec<(ParaId, Hash)> {
// stable sort messages by parachain ID.
outgoing.sort_by_key(|msg| ParaId::from(msg.target));
@@ -214,10 +214,10 @@ pub fn egress_roots(outgoing: &mut [OutgoingMessage]) -> Vec<(ParaId, Hash)> {
egress_roots
}
fn check_extrinsic(
mut outgoing: Vec<OutgoingMessage>,
fn check_egress(
mut outgoing: Vec<TargetedMessage>,
expected_egress_roots: &[(ParaId, Hash)],
) -> Result<Extrinsic, Error> {
) -> Result<OutgoingMessages, Error> {
// stable sort messages by parachain ID.
outgoing.sort_by_key(|msg| ParaId::from(msg.target));
@@ -264,12 +264,12 @@ fn check_extrinsic(
}
}
Ok(Extrinsic { outgoing_messages: outgoing })
Ok(OutgoingMessages { outgoing_messages: outgoing })
}
struct Externalities {
parachain_index: ParaId,
outgoing: Vec<OutgoingMessage>,
outgoing: Vec<TargetedMessage>,
upward: Vec<UpwardMessage>,
fees_charged: Balance,
free_balance: Balance,
@@ -284,7 +284,7 @@ impl wasm_executor::Externalities for Externalities {
}
self.apply_message_fee(message.data.len())?;
self.outgoing.push(OutgoingMessage {
self.outgoing.push(TargetedMessage {
target,
data: message.data.to_vec(),
});
@@ -317,11 +317,11 @@ impl Externalities {
}
}
// Performs final checks of validity, producing the extrinsic data.
// Performs final checks of validity, producing the outgoing message data.
fn final_checks(
self,
candidate: &CandidateReceipt,
) -> Result<Extrinsic, Error> {
) -> Result<OutgoingMessages, Error> {
if &self.upward != &candidate.upward_messages {
return Err(Error::UpwardMessagesInvalid {
expected: candidate.upward_messages.clone(),
@@ -336,7 +336,7 @@ impl Externalities {
});
}
check_extrinsic(
check_egress(
self.outgoing,
&candidate.egress_queue_roots[..],
)
@@ -386,7 +386,7 @@ pub fn validate_collation<P>(
relay_parent: &BlockId,
collation: &Collation,
max_block_data_size: Option<u64>,
) -> Result<Extrinsic, Error> where
) -> Result<OutgoingMessages, Error> where
P: ProvideRuntimeApi,
P::Api: ParachainHost<Block>,
{
@@ -407,7 +407,7 @@ pub fn validate_collation<P>(
let chain_status = api.parachain_status(relay_parent, para_id)?
.ok_or_else(|| Error::InactiveParachain(para_id))?;
let roots = api.ingress(relay_parent, para_id)?
let roots = api.ingress(relay_parent, para_id, None)?
.ok_or_else(|| Error::InactiveParachain(para_id))?;
validate_incoming(&roots, &collation.pov.ingress)?;
@@ -459,42 +459,42 @@ mod tests {
#[test]
fn compute_and_check_egress() {
let messages = vec![
OutgoingMessage { target: 3.into(), data: vec![1, 1, 1] },
OutgoingMessage { target: 1.into(), data: vec![1, 2, 3] },
OutgoingMessage { target: 2.into(), data: vec![4, 5, 6] },
OutgoingMessage { target: 1.into(), data: vec![7, 8, 9] },
TargetedMessage { target: 3.into(), data: vec![1, 1, 1] },
TargetedMessage { target: 1.into(), data: vec![1, 2, 3] },
TargetedMessage { target: 2.into(), data: vec![4, 5, 6] },
TargetedMessage { target: 1.into(), data: vec![7, 8, 9] },
];
let root_1 = message_queue_root(&[vec![1, 2, 3], vec![7, 8, 9]]);
let root_2 = message_queue_root(&[vec![4, 5, 6]]);
let root_3 = message_queue_root(&[vec![1, 1, 1]]);
assert!(check_extrinsic(
assert!(check_egress(
messages.clone(),
&[(1.into(), root_1), (2.into(), root_2), (3.into(), root_3)],
).is_ok());
let egress_roots = egress_roots(&mut messages.clone()[..]);
assert!(check_extrinsic(
assert!(check_egress(
messages.clone(),
&egress_roots[..],
).is_ok());
// missing root.
assert!(check_extrinsic(
assert!(check_egress(
messages.clone(),
&[(1.into(), root_1), (3.into(), root_3)],
).is_err());
// extra root.
assert!(check_extrinsic(
assert!(check_egress(
messages.clone(),
&[(1.into(), root_1), (2.into(), root_2), (3.into(), root_3), (4.into(), Default::default())],
).is_err());
// root mismatch.
assert!(check_extrinsic(
assert!(check_egress(
messages.clone(),
&[(1.into(), root_2), (2.into(), root_1), (3.into(), root_3)],
).is_err());
+32 -65
View File
@@ -37,17 +37,17 @@ use client::blockchain::HeaderBackend;
use client::block_builder::api::BlockBuilder as BlockBuilderApi;
use codec::Encode;
use consensus::SelectChain;
use extrinsic_store::Store as ExtrinsicStore;
use availability_store::Store as AvailabilityStore;
use parking_lot::Mutex;
use polkadot_primitives::{Hash, Block, BlockId, BlockNumber, Header};
use polkadot_primitives::parachain::{
Id as ParaId, Chain, DutyRoster, Extrinsic as ParachainExtrinsic, CandidateReceipt,
ParachainHost, AttestedCandidate, Statement as PrimitiveStatement, Message, OutgoingMessage,
Id as ParaId, Chain, DutyRoster, OutgoingMessages, CandidateReceipt,
ParachainHost, AttestedCandidate, Statement as PrimitiveStatement, Message,
Collation, PoVBlock, ValidatorSignature, ValidatorPair, ValidatorId
};
use primitives::Pair;
use runtime_primitives::{
traits::{ProvideRuntimeApi, Header as HeaderT, DigestFor}, ApplyError
traits::{ProvideRuntimeApi, DigestFor}, ApplyError
};
use futures_timer::{Delay, Interval};
use transaction_pool::txpool::{Pool, ChainApi as PoolChainApi};
@@ -88,27 +88,6 @@ const MAX_TRANSACTIONS_SIZE: usize = 4 * 1024 * 1024;
/// Incoming messages; a series of sorted (ParaId, Message) pairs.
pub type Incoming = Vec<(ParaId, Vec<Message>)>;
/// Outgoing messages from various candidates.
pub type Outgoing = Vec<MessagesFrom>;
/// Some messages from a parachain.
pub struct MessagesFrom {
/// The parachain originating the messages.
pub from: ParaId,
/// The messages themselves.
pub messages: ParachainExtrinsic,
}
impl MessagesFrom {
/// Construct from the raw messages.
pub fn from_messages(from: ParaId, messages: Vec<OutgoingMessage>) -> Self {
MessagesFrom {
from,
messages: ParachainExtrinsic { outgoing_messages: messages },
}
}
}
/// A handle to a statement table router.
///
/// This is expected to be a lightweight, shared type like an `Arc`.
@@ -120,7 +99,7 @@ pub trait TableRouter: Clone {
/// Call with local candidate data. This will make the data available on the network,
/// and sign, import, and broadcast a statement about the candidate.
fn local_collation(&self, collation: Collation, extrinsic: ParachainExtrinsic);
fn local_collation(&self, collation: Collation, outgoing: OutgoingMessages);
/// Fetch validation proof for a specific candidate.
fn fetch_pov_block(&self, candidate: &CandidateReceipt) -> Self::FetchValidationProof;
@@ -227,6 +206,18 @@ pub fn make_group_info(
}
/// Compute the (target, root, messages) of all outgoing queues.
pub fn outgoing_queues(outgoing_targeted: &'_ OutgoingMessages)
-> impl Iterator<Item=(ParaId, Hash, Vec<Message>)> + '_
{
outgoing_targeted.message_queues().filter_map(|queue| {
let target = queue.get(0)?.target;
let queue_root = message_queue_root(queue);
let queue_data = queue.iter().map(|msg| msg.clone().into()).collect();
Some((target, queue_root, queue_data))
})
}
// finds the first key we are capable of signing with out of the given set of validators,
// if any.
fn signing_key(validators: &[ValidatorId], keystore: &KeyStorePtr) -> Option<Arc<ValidatorPair>> {
@@ -249,7 +240,7 @@ struct ParachainValidation<C, N, P> {
/// handle to remote task executor
handle: TaskExecutor,
/// Store for extrinsic data.
extrinsic_store: ExtrinsicStore,
availability_store: AvailabilityStore,
/// Live agreements. Maps relay chain parent hashes to attestation
/// instances.
live_instances: Mutex<HashMap<Hash, Arc<AttestationTracker>>>,
@@ -274,7 +265,6 @@ impl<C, N, P> ParachainValidation<C, N, P> where
fn get_or_instantiate(
&self,
parent_hash: Hash,
grandparent_hash: Hash,
keystore: &KeyStorePtr,
max_block_data_size: Option<u64>,
)
@@ -290,32 +280,6 @@ impl<C, N, P> ParachainValidation<C, N, P> where
let validators = self.client.runtime_api().validators(&id)?;
let sign_with = signing_key(&validators[..], keystore);
// compute the parent candidates, if we know of them.
// this will allow us to circulate outgoing messages to other peers as necessary.
let parent_candidates: Vec<_> = crate::attestation_service::fetch_candidates(&*self.client, &id)
.ok()
.and_then(|x| x)
.map(|x| x.collect())
.unwrap_or_default();
// TODO: https://github.com/paritytech/polkadot/issues/253
//
// We probably don't only want active validators to do this, or messages
// will disappear when validators exit the set.
let _outgoing: Vec<_> = {
// extract all extrinsic data that we have and propagate to peers.
live_instances.get(&grandparent_hash).map(|parent_validation| {
parent_candidates.iter().filter_map(|c| {
let para_id = c.parachain_index;
let hash = c.hash();
parent_validation.table.extrinsic_data(&hash).map(|ex| MessagesFrom {
from: para_id,
messages: ex,
})
}).collect()
}).unwrap_or_default()
};
let duty_roster = self.client.runtime_api().duty_roster(&id)?;
let (group_info, local_duty) = make_group_info(
@@ -339,7 +303,7 @@ impl<C, N, P> ParachainValidation<C, N, P> where
group_info,
sign_with,
parent_hash,
self.extrinsic_store.clone(),
self.availability_store.clone(),
max_block_data_size,
));
@@ -380,10 +344,10 @@ impl<C, N, P> ParachainValidation<C, N, P> where
max_block_data_size: Option<u64>,
exit: exit_future::Exit,
) {
use extrinsic_store::Data;
use availability_store::Data;
let (collators, client) = (self.collators.clone(), self.client.clone());
let extrinsic_store = self.extrinsic_store.clone();
let availability_store = self.availability_store.clone();
let with_router = move |router: N::TableRouter| {
// fetch a local collation from connected collators.
@@ -396,20 +360,24 @@ impl<C, N, P> ParachainValidation<C, N, P> where
);
collation_work.then(move |result| match result {
Ok((collation, extrinsic)) => {
let res = extrinsic_store.make_available(Data {
Ok((collation, outgoing_targeted)) => {
let outgoing_queues = crate::outgoing_queues(&outgoing_targeted)
.map(|(_target, root, data)| (root, data))
.collect();
let res = availability_store.make_available(Data {
relay_parent,
parachain_id: collation.receipt.parachain_index,
candidate_hash: collation.receipt.hash(),
block_data: collation.pov.block_data.clone(),
extrinsic: Some(extrinsic.clone()),
outgoing_queues: Some(outgoing_queues),
});
match res {
Ok(()) => {
// TODO: https://github.com/paritytech/polkadot/issues/51
// Erasure-code and provide merkle branches.
router.local_collation(collation, extrinsic);
router.local_collation(collation, outgoing_targeted);
}
Err(e) => warn!(
target: "validation",
@@ -482,7 +450,7 @@ impl<C, N, P, SC, TxApi> ProposerFactory<C, N, P, SC, TxApi> where
transaction_pool: Arc<Pool<TxApi>>,
thread_pool: TaskExecutor,
keystore: KeyStorePtr,
extrinsic_store: ExtrinsicStore,
availability_store: AvailabilityStore,
babe_slot_duration: u64,
max_block_data_size: Option<u64>,
) -> Self {
@@ -491,7 +459,7 @@ impl<C, N, P, SC, TxApi> ProposerFactory<C, N, P, SC, TxApi> where
network,
collators,
handle: thread_pool.clone(),
extrinsic_store: extrinsic_store.clone(),
availability_store: availability_store.clone(),
live_instances: Mutex::new(HashMap::new()),
});
@@ -501,7 +469,7 @@ impl<C, N, P, SC, TxApi> ProposerFactory<C, N, P, SC, TxApi> where
parachain_validation.clone(),
thread_pool,
keystore.clone(),
extrinsic_store,
availability_store,
max_block_data_size,
);
@@ -540,7 +508,6 @@ impl<C, N, P, SC, TxApi> consensus::Environment<Block> for ProposerFactory<C, N,
let tracker = self.parachain_validation.get_or_instantiate(
parent_hash,
parent_header.parent_hash().clone(),
&self.keystore,
self.max_block_data_size,
)?;
+42 -51
View File
@@ -20,11 +20,11 @@
use std::collections::hash_map::{HashMap, Entry};
use std::sync::Arc;
use extrinsic_store::{Data, Store as ExtrinsicStore};
use availability_store::{Data, Store as AvailabilityStore};
use table::{self, Table, Context as TableContextTrait};
use polkadot_primitives::{Block, BlockId, Hash};
use polkadot_primitives::parachain::{
Id as ParaId, Collation, Extrinsic, CandidateReceipt, ValidatorPair, ValidatorId,
Id as ParaId, Collation, OutgoingMessages, CandidateReceipt, ValidatorPair, ValidatorId,
AttestedCandidate, ParachainHost, PoVBlock, ValidatorIndex
};
@@ -91,7 +91,7 @@ impl TableContext {
}
pub(crate) enum Validation {
Valid(PoVBlock, Extrinsic),
Valid(PoVBlock, OutgoingMessages),
Invalid(PoVBlock), // should take proof.
}
@@ -122,7 +122,7 @@ impl ValidationWork {
struct SharedTableInner {
table: Table<TableContext>,
trackers: Vec<IncludabilitySender>,
extrinsic_store: ExtrinsicStore,
availability_store: AvailabilityStore,
validated: HashMap<Hash, ValidationWork>,
}
@@ -186,7 +186,7 @@ impl SharedTableInner {
};
work.map(|work| ParachainWork {
extrinsic_store: self.extrinsic_store.clone(),
availability_store: self.availability_store.clone(),
relay_parent: context.parent_hash.clone(),
work,
max_block_data_size,
@@ -221,24 +221,24 @@ impl Validated {
}
/// Note that we've validated a candidate with given hash and it is good.
/// Extrinsic data required.
pub fn known_good(hash: Hash, collation: PoVBlock, extrinsic: Extrinsic) -> Self {
/// outgoing message required.
pub fn known_good(hash: Hash, collation: PoVBlock, outgoing: OutgoingMessages) -> Self {
Validated {
statement: GenericStatement::Valid(hash),
result: Validation::Valid(collation, extrinsic),
result: Validation::Valid(collation, outgoing),
}
}
/// Note that we've collated a candidate.
/// Extrinsic data required.
/// outgoing message required.
pub fn collated_local(
receipt: CandidateReceipt,
collation: PoVBlock,
extrinsic: Extrinsic,
outgoing: OutgoingMessages,
) -> Self {
Validated {
statement: GenericStatement::Candidate(receipt),
result: Validation::Valid(collation, extrinsic),
result: Validation::Valid(collation, outgoing),
}
}
@@ -249,8 +249,8 @@ impl Validated {
}
}
/// Get a reference to the extrinsic data, if any.
pub fn extrinsic(&self) -> Option<&Extrinsic> {
/// Get a reference to the outgoing messages data, if any.
pub fn outgoing_messages(&self) -> Option<&OutgoingMessages> {
match self.result {
Validation::Valid(_, ref ex) => Some(ex),
Validation::Invalid(_) => None,
@@ -262,7 +262,7 @@ impl Validated {
pub struct ParachainWork<Fetch> {
work: Work<Fetch>,
relay_parent: Hash,
extrinsic_store: ExtrinsicStore,
availability_store: AvailabilityStore,
max_block_data_size: Option<u64>,
}
@@ -272,7 +272,7 @@ impl<Fetch: Future> ParachainWork<Fetch> {
pub fn prime<P: ProvideRuntimeApi>(self, api: Arc<P>)
-> PrimedParachainWork<
Fetch,
impl Send + FnMut(&BlockId, &Collation) -> Result<Extrinsic, ()>,
impl Send + FnMut(&BlockId, &Collation) -> Result<OutgoingMessages, ()>,
>
where
P: Send + Sync + 'static,
@@ -301,7 +301,7 @@ impl<Fetch: Future> ParachainWork<Fetch> {
/// Prime the parachain work with a custom validation function.
pub fn prime_with<F>(self, validate: F) -> PrimedParachainWork<Fetch, F>
where F: FnMut(&BlockId, &Collation) -> Result<Extrinsic, ()>
where F: FnMut(&BlockId, &Collation) -> Result<OutgoingMessages, ()>
{
PrimedParachainWork { inner: self, validate }
}
@@ -321,7 +321,7 @@ pub struct PrimedParachainWork<Fetch, F> {
impl<Fetch, F, Err> Future for PrimedParachainWork<Fetch, F>
where
Fetch: Future<Item=PoVBlock,Error=Err>,
F: FnMut(&BlockId, &Collation) -> Result<Extrinsic, ()>,
F: FnMut(&BlockId, &Collation) -> Result<OutgoingMessages, ()>,
Err: From<::std::io::Error>,
{
type Item = Validated;
@@ -347,18 +347,22 @@ impl<Fetch, F, Err> Future for PrimedParachainWork<Fetch, F>
GenericStatement::Invalid(candidate_hash),
Validation::Invalid(pov_block),
),
Ok(extrinsic) => {
self.inner.extrinsic_store.make_available(Data {
Ok(outgoing_targeted) => {
let outgoing_queues = crate::outgoing_queues(&outgoing_targeted)
.map(|(_target, root, data)| (root, data))
.collect();
self.inner.availability_store.make_available(Data {
relay_parent: self.inner.relay_parent,
parachain_id: work.candidate_receipt.parachain_index,
candidate_hash,
block_data: pov_block.block_data.clone(),
extrinsic: Some(extrinsic.clone()),
outgoing_queues: Some(outgoing_queues),
})?;
(
GenericStatement::Valid(candidate_hash),
Validation::Valid(pov_block, extrinsic)
Validation::Valid(pov_block, outgoing_targeted)
)
}
};
@@ -397,7 +401,7 @@ impl SharedTable {
groups: HashMap<ParaId, GroupInfo>,
key: Option<Arc<ValidatorPair>>,
parent_hash: Hash,
extrinsic_store: ExtrinsicStore,
availability_store: AvailabilityStore,
max_block_data_size: Option<u64>,
) -> Self {
SharedTable {
@@ -407,7 +411,7 @@ impl SharedTable {
table: Table::default(),
validated: HashMap::new(),
trackers: Vec::new(),
extrinsic_store,
availability_store,
}))
}
}
@@ -427,19 +431,6 @@ impl SharedTable {
&self.context.groups
}
/// Get extrinsic data for candidate with given hash, if any.
///
/// This will return `Some` for any candidates that have been validated
/// locally.
pub(crate) fn extrinsic_data(&self, hash: &Hash) -> Option<Extrinsic> {
self.inner.lock().validated.get(hash).and_then(|x| match *x {
ValidationWork::Error(_) => None,
ValidationWork::InProgress => None,
ValidationWork::Done(Validation::Invalid(_)) => None,
ValidationWork::Done(Validation::Valid(_, ref ex)) => Some(ex.clone()),
})
}
/// Import a single statement with remote source, whose signature has already been checked.
///
/// The statement producer, if any, will produce only statements concerning the same candidate
@@ -598,7 +589,7 @@ mod tests {
type Error = ::std::io::Error;
type FetchValidationProof = future::FutureResult<PoVBlock,Self::Error>;
fn local_collation(&self, _collation: Collation, _extrinsic: Extrinsic) {
fn local_collation(&self, _collation: Collation, _outgoing: OutgoingMessages) {
}
fn fetch_pov_block(&self, _candidate: &CandidateReceipt) -> Self::FetchValidationProof {
@@ -631,7 +622,7 @@ mod tests {
groups,
Some(local_key.clone()),
parent_hash,
ExtrinsicStore::new_in_memory(),
AvailabilityStore::new_in_memory(),
None,
);
@@ -686,7 +677,7 @@ mod tests {
groups,
Some(local_key.clone()),
parent_hash,
ExtrinsicStore::new_in_memory(),
AvailabilityStore::new_in_memory(),
None,
);
@@ -718,7 +709,7 @@ mod tests {
#[test]
fn evaluate_makes_block_data_available() {
let store = ExtrinsicStore::new_in_memory();
let store = AvailabilityStore::new_in_memory();
let relay_parent = [0; 32].into();
let para_id = 5.into();
let pov_block = pov_block_with_data(vec![1, 2, 3]);
@@ -742,11 +733,11 @@ mod tests {
fetch: future::ok(pov_block.clone()),
},
relay_parent,
extrinsic_store: store.clone(),
availability_store: store.clone(),
max_block_data_size: None,
};
let validated = producer.prime_with(|_, _| Ok(Extrinsic { outgoing_messages: Vec::new() }))
let validated = producer.prime_with(|_, _| Ok(OutgoingMessages { outgoing_messages: Vec::new() }))
.wait()
.unwrap();
@@ -754,12 +745,12 @@ mod tests {
assert_eq!(validated.statement, GenericStatement::Valid(hash));
assert_eq!(store.block_data(relay_parent, hash).unwrap(), pov_block.block_data);
assert!(store.extrinsic(relay_parent, hash).is_some());
// TODO: check that a message queue is included by root.
}
#[test]
fn full_availability() {
let store = ExtrinsicStore::new_in_memory();
let store = AvailabilityStore::new_in_memory();
let relay_parent = [0; 32].into();
let para_id = 5.into();
let pov_block = pov_block_with_data(vec![1, 2, 3]);
@@ -783,18 +774,18 @@ mod tests {
fetch: future::ok::<_, ::std::io::Error>(pov_block.clone()),
},
relay_parent,
extrinsic_store: store.clone(),
availability_store: store.clone(),
max_block_data_size: None,
};
let validated = producer.prime_with(|_, _| Ok(Extrinsic { outgoing_messages: Vec::new() }))
let validated = producer.prime_with(|_, _| Ok(OutgoingMessages { outgoing_messages: Vec::new() }))
.wait()
.unwrap();
assert_eq!(validated.pov_block(), &pov_block);
assert_eq!(store.block_data(relay_parent, hash).unwrap(), pov_block.block_data);
assert!(store.extrinsic(relay_parent, hash).is_some());
// TODO: check that a message queue is included by root.
}
#[test]
@@ -822,7 +813,7 @@ mod tests {
groups,
Some(local_key.clone()),
parent_hash,
ExtrinsicStore::new_in_memory(),
AvailabilityStore::new_in_memory(),
None,
);
@@ -868,7 +859,7 @@ mod tests {
let para_id = ParaId::from(1);
let pov_block = pov_block_with_data(vec![1, 2, 3]);
let extrinsic = Extrinsic { outgoing_messages: Vec::new() };
let outgoing_messages = OutgoingMessages { outgoing_messages: Vec::new() };
let parent_hash = Default::default();
let local_key = Sr25519Keyring::Alice.pair();
@@ -888,7 +879,7 @@ mod tests {
groups,
Some(local_key.clone()),
parent_hash,
ExtrinsicStore::new_in_memory(),
AvailabilityStore::new_in_memory(),
None,
);
@@ -907,7 +898,7 @@ mod tests {
let signed_statement = shared_table.import_validated(Validated::collated_local(
candidate,
pov_block,
extrinsic,
outgoing_messages,
)).unwrap();
assert!(shared_table.inner.lock().validated.get(&hash).expect("validation has started").is_done());