mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-19 15:51:04 +00:00
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:
committed by
GitHub
parent
bd8ebbfee5
commit
55c4c830fe
@@ -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(()));
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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,
|
||||
)?;
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user