Introduce a Proof-of-Validation block type and use that in place of BlockData (#227)

* validators expect collators to give them parachain messages

* mostly port network to use pov_block

* network tests pass

* verify ingress when fetching pov block

* fix runtime compilation

* all tests build

* fix some grumbles

* Update validation/src/collation.rs

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

* Update primitives/src/parachain.rs

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

* Update network/src/lib.rs

Co-Authored-By: rphmeier <rphmeier@gmail.com>
This commit is contained in:
Robert Habermeier
2019-04-24 13:24:03 +02:00
committed by GitHub
parent 2bbfa0ae98
commit 1437c8e224
17 changed files with 380 additions and 234 deletions
@@ -42,7 +42,7 @@ use tokio::runtime::TaskExecutor;
use tokio::runtime::current_thread::Runtime as LocalRuntime;
use tokio::timer::Interval;
use super::{Network, Collators, TableRouter};
use super::{Network, Collators};
/// Gets a list of the candidates in a block.
pub(crate) fn fetch_candidates<P: BlockBody<Block>>(client: &P, block: &BlockId)
@@ -117,7 +117,6 @@ pub(crate) fn start<C, N, P>(
P::Api: ParachainHost<Block> + Core<Block> + BlockBuilder<Block>,
N: Network + Send + Sync + 'static,
N::TableRouter: Send + 'static,
<<N::TableRouter as TableRouter>::FetchIncoming as IntoFuture>::Future: Send + 'static,
<N::BuildTableRouter as IntoFuture>::Future: Send + 'static,
{
const TIMER_DELAY: Duration = Duration::from_secs(5);
+66 -21
View File
@@ -23,10 +23,12 @@ use std::sync::Arc;
use polkadot_primitives::{Block, Hash, BlockId, parachain::CollatorId};
use polkadot_primitives::parachain::{Id as ParaId, Collation, Extrinsic, OutgoingMessage};
use polkadot_primitives::parachain::{CandidateReceipt, ParachainHost};
use polkadot_primitives::parachain::{
ConsolidatedIngress, ConsolidatedIngressRoots, CandidateReceipt, ParachainHost,
};
use runtime_primitives::traits::ProvideRuntimeApi;
use parachain::{wasm_executor::{self, ExternalitiesError}, MessageRef};
use super::Incoming;
use error_chain::bail;
use futures::prelude::*;
@@ -60,7 +62,6 @@ pub struct CollationFetch<C: Collators, P> {
relay_parent_hash: Hash,
relay_parent: BlockId,
collators: C,
incoming: Incoming,
live_fetch: Option<<C::Collation as IntoFuture>::Future>,
client: Arc<P>,
}
@@ -72,7 +73,6 @@ impl<C: Collators, P> CollationFetch<C, P> {
relay_parent_hash: Hash,
collators: C,
client: Arc<P>,
incoming: Incoming,
) -> Self {
CollationFetch {
relay_parent: BlockId::hash(relay_parent_hash),
@@ -81,7 +81,6 @@ impl<C: Collators, P> CollationFetch<C, P> {
client,
parachain,
live_fetch: None,
incoming,
}
}
@@ -104,7 +103,7 @@ impl<C: Collators, P: ProvideRuntimeApi> Future for CollationFetch<C, P>
fn poll(&mut self) -> Poll<(Collation, Extrinsic), C::Error> {
loop {
let x = {
let collation = {
let parachain = self.parachain.clone();
let (r, c) = (self.relay_parent_hash, &self.collators);
let poll = self.live_fetch
@@ -114,16 +113,18 @@ impl<C: Collators, P: ProvideRuntimeApi> Future for CollationFetch<C, P>
try_ready!(poll)
};
match validate_collation(&*self.client, &self.relay_parent, &x, &self.incoming) {
let res = validate_collation(&*self.client, &self.relay_parent, &collation);
match res {
Ok(e) => {
return Ok(Async::Ready((x, e)))
return Ok(Async::Ready((collation, e)))
}
Err(e) => {
debug!("Failed to validate parachain due to API error: {}", e);
// just continue if we got a bad collation or failed to validate
self.live_fetch = None;
self.collators.note_bad_collator(x.receipt.collator)
self.collators.note_bad_collator(collation.receipt.collator)
}
}
}
@@ -145,15 +146,33 @@ error_chain! {
display("Collated for inactive parachain: {:?}", id),
}
EgressRootMismatch(id: ParaId, expected: Hash, got: Hash) {
description("Got unexpected egress route."),
description("Got unexpected egress root."),
display(
"Got unexpected egress route to {:?}. (expected: {:?}, got {:?})",
"Got unexpected egress root to {:?}. (expected: {:?}, got {:?})",
id, expected, got
),
}
MissingEgressRoute(expected: Option<ParaId>, got: Option<ParaId>) {
description("Missing or extra egress route."),
display("Missing or extra egress route. (expected: {:?}, got {:?})", expected, got),
IngressRootMismatch(id: ParaId, expected: Hash, got: Hash) {
description("Got unexpected ingress root."),
display(
"Got unexpected ingress root to {:?}. (expected: {:?}, got {:?})",
id, expected, got
),
}
IngressChainMismatch(expected: ParaId, got: ParaId) {
description("Got ingress from wrong chain"),
display(
"Got ingress from wrong chain. (expected: {:?}, got {:?})",
expected, got
),
}
IngressCanonicalityMismatch(expected: usize, got: usize) {
description("Ingress canonicality mismatch."),
display("Got data for {} roots, expected {}", got, expected),
}
MissingEgressRoot(expected: Option<ParaId>, got: Option<ParaId>) {
description("Missing or extra egress root."),
display("Missing or extra egress root. (expected: {:?}, got {:?})", expected, got),
}
WrongHeadData(expected: Vec<u8>, got: Vec<u8>) {
description("Parachain validation produced wrong head data."),
@@ -206,11 +225,11 @@ fn check_extrinsic(
let mut expected_egress_roots = expected_egress_roots.iter();
while let Some(batch_target) = messages_iter.peek().map(|o| o.target) {
let expected_root = match expected_egress_roots.next() {
None => return Err(ErrorKind::MissingEgressRoute(Some(batch_target), None).into()),
None => return Err(ErrorKind::MissingEgressRoot(Some(batch_target), None).into()),
Some(&(id, ref root)) => if id == batch_target {
root
} else {
return Err(ErrorKind::MissingEgressRoute(Some(batch_target), Some(id)).into());
return Err(ErrorKind::MissingEgressRoot(Some(batch_target), Some(id)).into());
}
};
@@ -234,7 +253,7 @@ fn check_extrinsic(
// also check that there are no more additional expected roots.
if let Some((next_target, _)) = expected_egress_roots.next() {
return Err(ErrorKind::MissingEgressRoute(None, Some(*next_target)).into());
return Err(ErrorKind::MissingEgressRoot(None, Some(*next_target)).into());
}
}
@@ -277,16 +296,38 @@ impl Externalities {
}
}
/// Validate incoming messages against expected roots.
pub fn validate_incoming(
roots: &ConsolidatedIngressRoots,
ingress: &ConsolidatedIngress,
) -> Result<(), Error> {
if roots.0.len() != ingress.0.len() {
bail!(ErrorKind::IngressCanonicalityMismatch(roots.0.len(), ingress.0.len()));
}
let all_iter = roots.0.iter().zip(&ingress.0);
for ((expected_id, root), (got_id, messages)) in all_iter {
if expected_id != got_id {
bail!(ErrorKind::IngressChainMismatch(*expected_id, *got_id));
}
let got_root = message_queue_root(messages.iter().map(|msg| &msg.0[..]));
if &got_root != root {
bail!(ErrorKind::IngressRootMismatch(*expected_id, *root, got_root));
}
}
Ok(())
}
/// Check whether a given collation is valid. Returns `Ok` on success, error otherwise.
///
/// This assumes that basic validity checks have been done:
/// - Block data hash is the same as linked in candidate receipt.
/// - incoming messages have been validated against canonical ingress roots
pub fn validate_collation<P>(
client: &P,
relay_parent: &BlockId,
collation: &Collation,
incoming: &Incoming,
) -> Result<Extrinsic, Error> where
P: ProvideRuntimeApi,
P::Api: ParachainHost<Block>,
@@ -301,10 +342,14 @@ pub fn validate_collation<P>(
let chain_head = api.parachain_head(relay_parent, para_id)?
.ok_or_else(|| ErrorKind::InactiveParachain(para_id))?;
let roots = api.ingress(relay_parent, para_id)?
.ok_or_else(|| ErrorKind::InactiveParachain(para_id))?;
validate_incoming(&roots, &collation.pov.ingress)?;
let params = ValidationParams {
parent_head: chain_head,
block_data: collation.block_data.0.clone(),
ingress: incoming.iter()
block_data: collation.pov.block_data.0.clone(),
ingress: collation.pov.ingress.0.iter()
.flat_map(|&(source, ref messages)| {
messages.iter().map(move |msg| IncomingMessage {
source,
+20 -44
View File
@@ -78,8 +78,9 @@ use extrinsic_store::Store as ExtrinsicStore;
use parking_lot::Mutex;
use polkadot_primitives::{Hash, Block, BlockId, BlockNumber, Header, SessionKey};
use polkadot_primitives::parachain::{
Id as ParaId, Chain, DutyRoster, BlockData, Extrinsic as ParachainExtrinsic, CandidateReceipt,
ParachainHost, AttestedCandidate, Statement as PrimitiveStatement, Message, OutgoingMessage, CollatorSignature
Id as ParaId, Chain, DutyRoster, Extrinsic as ParachainExtrinsic, CandidateReceipt,
ParachainHost, AttestedCandidate, Statement as PrimitiveStatement, Message, OutgoingMessage, CollatorSignature,
Collation, PoVBlock,
};
use primitives::{Pair, ed25519};
use runtime_primitives::{traits::{ProvideRuntimeApi, Header as HeaderT}, ApplyError};
@@ -97,7 +98,9 @@ use runtime_aura::timestamp::TimestampInherentData;
use ed25519::Public as AuthorityId;
pub use self::collation::{validate_collation, message_queue_root, egress_roots, Collators};
pub use self::collation::{
validate_collation, validate_incoming, message_queue_root, egress_roots, Collators,
};
pub use self::error::{ErrorKind, Error};
pub use self::shared_table::{
SharedTable, ParachainWork, PrimedParachainWork, Validated, Statement, SignedStatement,
@@ -146,24 +149,14 @@ pub trait TableRouter: Clone {
/// Errors when fetching data from the network.
type Error: std::fmt::Debug;
/// Future that resolves when candidate data is fetched.
type FetchCandidate: IntoFuture<Item=BlockData,Error=Self::Error>;
/// Fetch incoming messages for a candidate.
type FetchIncoming: IntoFuture<Item=Incoming,Error=Self::Error>;
type FetchValidationProof: IntoFuture<Item=PoVBlock,Error=Self::Error>;
/// 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_candidate(&self, candidate: CandidateReceipt, block_data: BlockData, extrinsic: ParachainExtrinsic);
fn local_collation(&self, collation: Collation, extrinsic: ParachainExtrinsic);
/// Fetch block data for a specific candidate.
fn fetch_block_data(&self, candidate: &CandidateReceipt) -> Self::FetchCandidate;
/// Fetches the incoming message data to a parachain from the network. Incoming data should be
/// checked.
///
/// The `ParachainHost::ingress` function can be used to fetch incoming roots,
/// and the `message_queue_root` function can be used to check that messages actually have
/// expected root.
fn fetch_incoming(&self, id: ParaId) -> Self::FetchIncoming;
/// Fetch validation proof for a specific candidate.
fn fetch_pov_block(&self, candidate: &CandidateReceipt) -> Self::FetchValidationProof;
}
/// A long-lived network which can create parachain statement and BFT message routing processes on demand.
@@ -291,7 +284,6 @@ impl<C, N, P> ParachainValidation<C, N, P> where
P::Api: ParachainHost<Block> + BlockBuilderApi<Block>,
<C::Collation as IntoFuture>::Future: Send + 'static,
N::TableRouter: Send + 'static,
<<N::TableRouter as TableRouter>::FetchIncoming as IntoFuture>::Future: Send + 'static,
<N::BuildTableRouter as IntoFuture>::Future: Send + 'static,
{
/// Get an attestation table for given parent hash.
@@ -400,23 +392,13 @@ impl<C, N, P> ParachainValidation<C, N, P> where
let extrinsic_store = self.extrinsic_store.clone();
let with_router = move |router: N::TableRouter| {
let fetch_incoming = router.fetch_incoming(validation_para)
.into_future()
.map_err(|e| format!("{:?}", e));
// fetch incoming messages to our parachain from network and
// then fetch a local collation.
let collation_work = fetch_incoming
.map_err(|e| String::clone(&e))
.and_then(move |incoming| {
CollationFetch::new(
validation_para,
relay_parent,
collators,
client,
incoming,
).map_err(|e| format!("{:?}", e))
});
// fetch a local collation from connected collators.
let collation_work = CollationFetch::new(
validation_para,
relay_parent,
collators,
client,
);
collation_work.then(move |result| match result {
Ok((collation, extrinsic)) => {
@@ -424,7 +406,7 @@ impl<C, N, P> ParachainValidation<C, N, P> where
relay_parent,
parachain_id: collation.receipt.parachain_index,
candidate_hash: collation.receipt.hash(),
block_data: collation.block_data.clone(),
block_data: collation.pov.block_data.clone(),
extrinsic: Some(extrinsic.clone()),
});
@@ -432,11 +414,7 @@ impl<C, N, P> ParachainValidation<C, N, P> where
Ok(()) => {
// TODO: https://github.com/paritytech/polkadot/issues/51
// Erasure-code and provide merkle branches.
router.local_candidate(
collation.receipt,
collation.block_data,
extrinsic,
)
router.local_collation(collation, extrinsic);
}
Err(e) => warn!(
target: "validation",
@@ -448,7 +426,7 @@ impl<C, N, P> ParachainValidation<C, N, P> where
Ok(())
}
Err(e) => {
warn!(target: "validation", "Failed to collate candidate: {}", e);
warn!(target: "validation", "Failed to collate candidate: {:?}", e);
Ok(())
}
})
@@ -493,7 +471,6 @@ impl<C, N, P, TxApi> ProposerFactory<C, N, P, TxApi> where
P::Api: ParachainHost<Block> + Core<Block> + BlockBuilderApi<Block>,
N: Network + Send + Sync + 'static,
N::TableRouter: Send + 'static,
<<N::TableRouter as TableRouter>::FetchIncoming as IntoFuture>::Future: Send + 'static,
<N::BuildTableRouter as IntoFuture>::Future: Send + 'static,
TxApi: PoolChainApi,
{
@@ -543,7 +520,6 @@ impl<C, N, P, TxApi> consensus::Environment<Block> for ProposerFactory<C, N, P,
P::Api: ParachainHost<Block> + BlockBuilderApi<Block>,
<C::Collation as IntoFuture>::Future: Send + 'static,
N::TableRouter: Send + 'static,
<<N::TableRouter as TableRouter>::FetchIncoming as IntoFuture>::Future: Send + 'static,
<N::BuildTableRouter as IntoFuture>::Future: Send + 'static,
{
type Proposer = Proposer<P, TxApi>;
+60 -63
View File
@@ -24,14 +24,14 @@ use extrinsic_store::{Data, Store as ExtrinsicStore};
use table::{self, Table, Context as TableContextTrait};
use polkadot_primitives::{Block, BlockId, Hash, SessionKey};
use polkadot_primitives::parachain::{
Id as ParaId, BlockData, Collation, Extrinsic, CandidateReceipt,
AttestedCandidate, ParachainHost
Id as ParaId, Collation, Extrinsic, CandidateReceipt,
AttestedCandidate, ParachainHost, PoVBlock
};
use parking_lot::Mutex;
use futures::{future, prelude::*};
use futures::prelude::*;
use super::{GroupInfo, Incoming, TableRouter};
use super::{GroupInfo, TableRouter};
use self::includable::IncludabilitySender;
use primitives::{ed25519, Pair};
use runtime_primitives::traits::ProvideRuntimeApi;
@@ -75,8 +75,8 @@ impl TableContext {
}
pub(crate) enum Validation {
Valid(BlockData, Extrinsic),
Invalid(BlockData), // should take proof.
Valid(PoVBlock, Extrinsic),
Invalid(PoVBlock), // should take proof.
}
enum ValidationWork {
@@ -121,10 +121,9 @@ impl SharedTableInner {
context: &TableContext,
router: &R,
statement: table::SignedStatement,
) -> Option<ParachainWork<future::Join<
<R::FetchCandidate as IntoFuture>::Future,
<R::FetchIncoming as IntoFuture>::Future,
>>> {
) -> Option<ParachainWork<
<R::FetchValidationProof as IntoFuture>::Future,
>> {
let summary = match self.table.import_statement(context, statement) {
Some(summary) => summary,
None => return None,
@@ -149,7 +148,6 @@ impl SharedTableInner {
};
let work = if do_validation {
let fetch_incoming = router.fetch_incoming(summary.group_id);
match self.table.get_candidate(&digest) {
None => {
let message = format!(
@@ -163,11 +161,11 @@ impl SharedTableInner {
None
}
Some(candidate) => {
let fetch_block_data = router.fetch_block_data(candidate).into_future();
let fetch = router.fetch_pov_block(candidate).into_future();
Some(Work {
candidate_receipt: candidate.clone(),
fetch: fetch_block_data.join(fetch_incoming),
fetch,
})
}
}
@@ -202,19 +200,19 @@ pub struct Validated {
impl Validated {
/// Note that we've validated a candidate with given hash and it is bad.
pub fn known_bad(hash: Hash, block_data: BlockData) -> Self {
pub fn known_bad(hash: Hash, collation: PoVBlock) -> Self {
Validated {
statement: GenericStatement::Invalid(hash),
result: Validation::Invalid(block_data),
result: Validation::Invalid(collation),
}
}
/// Note that we've validated a candidate with given hash and it is good.
/// Extrinsic data required.
pub fn known_good(hash: Hash, block_data: BlockData, extrinsic: Extrinsic) -> Self {
pub fn known_good(hash: Hash, collation: PoVBlock, extrinsic: Extrinsic) -> Self {
Validated {
statement: GenericStatement::Valid(hash),
result: Validation::Valid(block_data, extrinsic),
result: Validation::Valid(collation, extrinsic),
}
}
@@ -222,17 +220,17 @@ impl Validated {
/// Extrinsic data required.
pub fn collated_local(
receipt: CandidateReceipt,
block_data: BlockData,
collation: PoVBlock,
extrinsic: Extrinsic,
) -> Self {
Validated {
statement: GenericStatement::Candidate(receipt),
result: Validation::Valid(block_data, extrinsic),
result: Validation::Valid(collation, extrinsic),
}
}
/// Get a reference to the block data.
pub fn block_data(&self) -> &BlockData {
/// Get a reference to the proof-of-validation block.
pub fn pov_block(&self) -> &PoVBlock {
match self.result {
Validation::Valid(ref b, _) | Validation::Invalid(ref b) => b,
}
@@ -260,18 +258,17 @@ impl<Fetch: Future> ParachainWork<Fetch> {
pub fn prime<P: ProvideRuntimeApi>(self, api: Arc<P>)
-> PrimedParachainWork<
Fetch,
impl Send + FnMut(&BlockId, &Collation, &Incoming) -> Result<Extrinsic, ()>,
impl Send + FnMut(&BlockId, &Collation) -> Result<Extrinsic, ()>,
>
where
P: Send + Sync + 'static,
P::Api: ParachainHost<Block>,
{
let validate = move |id: &_, collation: &_, incoming: &_| {
let validate = move |id: &_, collation: &_| {
let res = ::collation::validate_collation(
&*api,
id,
collation,
incoming,
);
match res {
@@ -288,7 +285,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, &Incoming) -> Result<Extrinsic, ()>
where F: FnMut(&BlockId, &Collation) -> Result<Extrinsic, ()>
{
PrimedParachainWork { inner: self, validate }
}
@@ -307,8 +304,8 @@ pub struct PrimedParachainWork<Fetch, F> {
impl<Fetch, F, Err> Future for PrimedParachainWork<Fetch, F>
where
Fetch: Future<Item=(BlockData, Incoming),Error=Err>,
F: FnMut(&BlockId, &Collation, &Incoming) -> Result<Extrinsic, ()>,
Fetch: Future<Item=PoVBlock,Error=Err>,
F: FnMut(&BlockId, &Collation) -> Result<Extrinsic, ()>,
Err: From<::std::io::Error>,
{
type Item = Validated;
@@ -318,11 +315,10 @@ impl<Fetch, F, Err> Future for PrimedParachainWork<Fetch, F>
let work = &mut self.inner.work;
let candidate = &work.candidate_receipt;
let (block, incoming) = try_ready!(work.fetch.poll());
let pov_block = try_ready!(work.fetch.poll());
let validation_res = (self.validate)(
&BlockId::hash(self.inner.relay_parent),
&Collation { block_data: block.clone(), receipt: candidate.clone() },
&incoming,
&Collation { pov: pov_block.clone(), receipt: candidate.clone() },
);
let candidate_hash = candidate.hash();
@@ -333,20 +329,20 @@ impl<Fetch, F, Err> Future for PrimedParachainWork<Fetch, F>
let (validity_statement, result) = match validation_res {
Err(()) => (
GenericStatement::Invalid(candidate_hash),
Validation::Invalid(block),
Validation::Invalid(pov_block),
),
Ok(extrinsic) => {
self.inner.extrinsic_store.make_available(Data {
relay_parent: self.inner.relay_parent,
parachain_id: work.candidate_receipt.parachain_index,
candidate_hash,
block_data: block.clone(),
block_data: pov_block.block_data.clone(),
extrinsic: Some(extrinsic.clone()),
})?;
(
GenericStatement::Valid(candidate_hash),
Validation::Valid(block, extrinsic)
Validation::Valid(pov_block, extrinsic)
)
}
};
@@ -431,10 +427,9 @@ impl SharedTable {
&self,
router: &R,
statement: table::SignedStatement,
) -> Option<ParachainWork<future::Join<
<R::FetchCandidate as IntoFuture>::Future,
<R::FetchIncoming as IntoFuture>::Future,
>>> {
) -> Option<ParachainWork<
<R::FetchValidationProof as IntoFuture>::Future,
>> {
self.inner.lock().import_remote_statement(&*self.context, router, statement)
}
@@ -448,10 +443,9 @@ impl SharedTable {
where
R: TableRouter,
I: IntoIterator<Item=table::SignedStatement>,
U: ::std::iter::FromIterator<Option<ParachainWork<future::Join<
<R::FetchCandidate as IntoFuture>::Future,
<R::FetchIncoming as IntoFuture>::Future,
>>>>,
U: ::std::iter::FromIterator<Option<ParachainWork<
<R::FetchValidationProof as IntoFuture>::Future,
>>>,
{
let mut inner = self.inner.lock();
@@ -547,24 +541,27 @@ mod tests {
use super::*;
use substrate_keyring::AuthorityKeyring;
use primitives::crypto::UncheckedInto;
use polkadot_primitives::parachain::{BlockData, ConsolidatedIngress};
use futures::future;
fn pov_block_with_data(data: Vec<u8>) -> PoVBlock {
PoVBlock {
block_data: BlockData(data),
ingress: ConsolidatedIngress(Vec::new()),
}
}
#[derive(Clone)]
struct DummyRouter;
impl TableRouter for DummyRouter {
type Error = ::std::io::Error;
type FetchCandidate = ::futures::future::FutureResult<BlockData,Self::Error>;
type FetchIncoming = ::futures::future::FutureResult<Incoming,Self::Error>;
fn local_candidate(&self, _candidate: CandidateReceipt, _block_data: BlockData, _extrinsic: Extrinsic) {
type FetchValidationProof = future::FutureResult<PoVBlock,Self::Error>;
fn local_collation(&self, _collation: Collation, _extrinsic: Extrinsic) {
}
fn fetch_block_data(&self, _candidate: &CandidateReceipt) -> Self::FetchCandidate {
future::ok(BlockData(vec![1, 2, 3, 4, 5]))
}
fn fetch_incoming(&self, _para_id: ParaId) -> Self::FetchIncoming {
future::ok(Vec::new())
fn fetch_pov_block(&self, _candidate: &CandidateReceipt) -> Self::FetchValidationProof {
future::ok(pov_block_with_data(vec![1, 2, 3, 4, 5]))
}
}
@@ -675,7 +672,7 @@ mod tests {
let store = ExtrinsicStore::new_in_memory();
let relay_parent = [0; 32].into();
let para_id = 5.into();
let block_data = BlockData(vec![1, 2, 3]);
let pov_block = pov_block_with_data(vec![1, 2, 3]);
let candidate = CandidateReceipt {
parachain_index: para_id,
@@ -693,20 +690,20 @@ mod tests {
let producer: ParachainWork<future::FutureResult<_, ::std::io::Error>> = ParachainWork {
work: Work {
candidate_receipt: candidate,
fetch: future::ok((block_data.clone(), Vec::new())),
fetch: future::ok(pov_block.clone()),
},
relay_parent,
extrinsic_store: store.clone(),
};
let validated = producer.prime_with(|_, _, _| Ok(Extrinsic { outgoing_messages: Vec::new() }))
let validated = producer.prime_with(|_, _| Ok(Extrinsic { outgoing_messages: Vec::new() }))
.wait()
.unwrap();
assert_eq!(validated.block_data(), &block_data);
assert_eq!(validated.pov_block(), &pov_block);
assert_eq!(validated.statement, GenericStatement::Valid(hash));
assert_eq!(store.block_data(relay_parent, hash).unwrap(), block_data);
assert_eq!(store.block_data(relay_parent, hash).unwrap(), pov_block.block_data);
assert!(store.extrinsic(relay_parent, hash).is_some());
}
@@ -715,7 +712,7 @@ mod tests {
let store = ExtrinsicStore::new_in_memory();
let relay_parent = [0; 32].into();
let para_id = 5.into();
let block_data = BlockData(vec![1, 2, 3]);
let pov_block = pov_block_with_data(vec![1, 2, 3]);
let candidate = CandidateReceipt {
parachain_index: para_id,
@@ -733,19 +730,19 @@ mod tests {
let producer = ParachainWork {
work: Work {
candidate_receipt: candidate,
fetch: future::ok::<_, ::std::io::Error>((block_data.clone(), Vec::new())),
fetch: future::ok::<_, ::std::io::Error>(pov_block.clone()),
},
relay_parent,
extrinsic_store: store.clone(),
};
let validated = producer.prime_with(|_, _, _| Ok(Extrinsic { outgoing_messages: Vec::new() }))
let validated = producer.prime_with(|_, _| Ok(Extrinsic { outgoing_messages: Vec::new() }))
.wait()
.unwrap();
assert_eq!(validated.block_data(), &block_data);
assert_eq!(validated.pov_block(), &pov_block);
assert_eq!(store.block_data(relay_parent, hash).unwrap(), block_data);
assert_eq!(store.block_data(relay_parent, hash).unwrap(), pov_block.block_data);
assert!(store.extrinsic(relay_parent, hash).is_some());
}
@@ -815,7 +812,7 @@ mod tests {
let mut groups = HashMap::new();
let para_id = ParaId::from(1);
let block_data = BlockData(vec![1, 2, 3]);
let pov_block = pov_block_with_data(vec![1, 2, 3]);
let extrinsic = Extrinsic { outgoing_messages: Vec::new() };
let parent_hash = Default::default();
@@ -851,7 +848,7 @@ mod tests {
let hash = candidate.hash();
let signed_statement = shared_table.import_validated(Validated::collated_local(
candidate,
block_data,
pov_block,
extrinsic,
));