Allow parachains to send messages (#274)

* Slots module

* Integrate slots

* More drafting

* Minor updates

* Update parachains to use trati

* More build fixes

* Full code now compiles

* Add renew bid function

* Implement calculate_winner

* Warning remove

* Update gitignore

* Test framework

* Tests

* Further testing

* More tests, new parameterisation.

* Fix and new test

* Thread-safe tests

* Test off-boarding and a fix.

* Test onboarding

* Allow late onboarding.

* Another test and fix

* Avoid println in nostd

* Compact representation of paraids

* Introduce documentation.

* Introduce events.

* Additional test and fix

* Additional test

* Tidy up line lengths.

* Remove printlns

* Use later substrate utils.

* Allow parachains to send messages.

* Fix build/test

* Make slots work with latest substrate

* Update runtime/src/slot_range.rs

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

* Update runtime/src/slots.rs

Co-Authored-By: Shawn Tabrizi <shawntabrizi@gmail.com>

* Update runtime/src/slots.rs

Co-Authored-By: Shawn Tabrizi <shawntabrizi@gmail.com>

* Polish logic

* Rewind to earlier substrate master

* Remove dead code.

* Fix build

* Update substrate ref to master

* Update to new inherent digests API

* address grumbles

* fix

* Fix a warning.

* Reworded a comment.

* Check that receipt matches expectations

* Add test for final checks

* Split out queuing logic.

* Test final piece of queuing logic

* Fix up docs.

* More docs fixes
This commit is contained in:
Gavin Wood
2019-06-03 16:48:33 +02:00
committed by GitHub
parent 2b9db4e7f1
commit 4b7dfc4c25
18 changed files with 924 additions and 220 deletions
+98 -5
View File
@@ -21,13 +21,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::{
use polkadot_primitives::{Block, Hash, BlockId, parachain::CollatorId, parachain::{
ConsolidatedIngress, ConsolidatedIngressRoots, CandidateReceipt, ParachainHost,
};
Id as ParaId, Collation, Extrinsic, OutgoingMessage, UpwardMessage
}};
use runtime_primitives::traits::ProvideRuntimeApi;
use parachain::{wasm_executor::{self, ExternalitiesError}, MessageRef};
use parachain::{wasm_executor::{self, ExternalitiesError}, MessageRef, UpwardMessageRef};
use error_chain::bail;
use futures::prelude::*;
@@ -190,6 +189,10 @@ error_chain! {
description("Block data is too big."),
display("Block data is too big (maximum allowed size: {}, actual size: {})", max_size, size),
}
UpwardMessagesInvalid(expected: Vec<UpwardMessage>, got: Vec<UpwardMessage>) {
description("Parachain validation produced wrong relay-chain messages."),
display("Parachain validation produced wrong relay-chain messages (expected: {:?}, got {:?})", expected, got),
}
}
}
@@ -275,6 +278,7 @@ fn check_extrinsic(
struct Externalities {
parachain_index: ParaId,
outgoing: Vec<OutgoingMessage>,
upward: Vec<UpwardMessage>,
}
impl wasm_executor::Externalities for Externalities {
@@ -293,14 +297,35 @@ impl wasm_executor::Externalities for Externalities {
Ok(())
}
fn post_upward_message(&mut self, message: UpwardMessageRef)
-> Result<(), ExternalitiesError>
{
// TODO: https://github.com/paritytech/polkadot/issues/92
// check per-message and per-byte fees for the parachain.
self.upward.push(UpwardMessage {
origin: message.origin,
data: message.data.to_vec(),
});
Ok(())
}
}
impl Externalities {
// Performs final checks of validity, producing the extrinsic data.
fn final_checks(
self,
candidate: &CandidateReceipt,
) -> Result<Extrinsic, Error> {
if &self.upward != &candidate.upward_messages {
bail!(ErrorKind::UpwardMessagesInvalid(
candidate.upward_messages.clone(),
self.upward.clone(),
));
}
check_extrinsic(
self.outgoing,
&candidate.egress_queue_roots[..],
@@ -382,6 +407,7 @@ pub fn validate_collation<P>(
let mut ext = Externalities {
parachain_index: collation.receipt.parachain_index.clone(),
outgoing: Vec::new(),
upward: Vec::new(),
};
match wasm_executor::validate_candidate(&validation_code, params, &mut ext) {
@@ -403,6 +429,8 @@ pub fn validate_collation<P>(
mod tests {
use super::*;
use parachain::wasm_executor::Externalities as ExternalitiesTrait;
use parachain::ParachainDispatchOrigin;
use polkadot_primitives::parachain::{Statement::Candidate, CandidateReceipt, HeadData};
#[test]
fn compute_and_check_egress() {
@@ -453,9 +481,74 @@ mod tests {
let mut ext = Externalities {
parachain_index: 5.into(),
outgoing: Vec::new(),
upward: Vec::new(),
};
assert!(ext.post_message(MessageRef { target: 1.into(), data: &[] }).is_ok());
assert!(ext.post_message(MessageRef { target: 5.into(), data: &[] }).is_err());
}
#[test]
fn ext_checks_upward_messages() {
let ext = || Externalities {
parachain_index: 5.into(),
outgoing: Vec::new(),
upward: vec![
UpwardMessage{ data: vec![42], origin: ParachainDispatchOrigin::Parachain },
],
};
let receipt = CandidateReceipt {
parachain_index: 5.into(),
collator: Default::default(),
signature: Default::default(),
head_data: HeadData(Vec::new()),
egress_queue_roots: Vec::new(),
fees: 0,
block_data_hash: Default::default(),
upward_messages: vec![
UpwardMessage{ data: vec![42], origin: ParachainDispatchOrigin::Signed },
UpwardMessage{ data: vec![69], origin: ParachainDispatchOrigin::Parachain },
],
};
assert!(ext().final_checks(&receipt).is_err());
let receipt = CandidateReceipt {
parachain_index: 5.into(),
collator: Default::default(),
signature: Default::default(),
head_data: HeadData(Vec::new()),
egress_queue_roots: Vec::new(),
fees: 0,
block_data_hash: Default::default(),
upward_messages: vec![
UpwardMessage{ data: vec![42], origin: ParachainDispatchOrigin::Signed },
],
};
assert!(ext().final_checks(&receipt).is_err());
let receipt = CandidateReceipt {
parachain_index: 5.into(),
collator: Default::default(),
signature: Default::default(),
head_data: HeadData(Vec::new()),
egress_queue_roots: Vec::new(),
fees: 0,
block_data_hash: Default::default(),
upward_messages: vec![
UpwardMessage{ data: vec![69], origin: ParachainDispatchOrigin::Parachain },
],
};
assert!(ext().final_checks(&receipt).is_err());
let receipt = CandidateReceipt {
parachain_index: 5.into(),
collator: Default::default(),
signature: Default::default(),
head_data: HeadData(Vec::new()),
egress_queue_roots: Vec::new(),
fees: 0,
block_data_hash: Default::default(),
upward_messages: vec![
UpwardMessage{ data: vec![42], origin: ParachainDispatchOrigin::Parachain },
],
};
assert!(ext().final_checks(&receipt).is_ok());
}
}
+7 -3
View File
@@ -48,7 +48,7 @@ use polkadot_primitives::parachain::{
Collation, PoVBlock,
};
use primitives::{Pair, ed25519};
use runtime_primitives::{traits::{ProvideRuntimeApi, Header as HeaderT}, ApplyError};
use runtime_primitives::{traits::{ProvideRuntimeApi, Header as HeaderT, Block as BlockT}, ApplyError};
use tokio::runtime::TaskExecutor;
use tokio::timer::{Delay, Interval};
use transaction_pool::txpool::{Pool, ChainApi as PoolChainApi};
@@ -570,7 +570,11 @@ impl<C, TxApi> consensus::Proposer<Block> for Proposer<C, TxApi> where
type Error = Error;
type Create = Either<CreateProposal<C, TxApi>, future::FutureResult<Block, Error>>;
fn propose(&self, inherent_data: InherentData, max_duration: Duration) -> Self::Create {
fn propose(&self,
inherent_data: InherentData,
_digest: <<Block as BlockT>::Header as HeaderT>::Digest,
max_duration: Duration,
) -> Self::Create {
const ATTEMPT_PROPOSE_EVERY: Duration = Duration::from_millis(100);
const SLOT_DURATION_DENOMINATOR: u64 = 3; // wait up to 1/3 of the slot for candidates.
@@ -712,7 +716,7 @@ impl<C, TxApi> CreateProposal<C, TxApi> where
let runtime_api = self.client.runtime_api();
let mut block_builder = BlockBuilder::at_block(&self.parent_id, &*self.client, false)?;
let mut block_builder = BlockBuilder::at_block(&self.parent_id, &*self.client, false, Default::default())?;
{
let inherents = runtime_api.inherent_extrinsics(&self.parent_id, inherent_data)?;
+6 -6
View File
@@ -630,10 +630,10 @@ mod tests {
collator: [1; 32].unchecked_into(),
signature: Default::default(),
head_data: ::polkadot_primitives::parachain::HeadData(vec![1, 2, 3, 4]),
balance_uploads: Vec::new(),
egress_queue_roots: Vec::new(),
fees: 1_000_000,
block_data_hash: [2; 32].into(),
upward_messages: Vec::new(),
};
let candidate_statement = GenericStatement::Candidate(candidate);
@@ -684,10 +684,10 @@ mod tests {
collator: [1; 32].unchecked_into(),
signature: Default::default(),
head_data: ::polkadot_primitives::parachain::HeadData(vec![1, 2, 3, 4]),
balance_uploads: Vec::new(),
egress_queue_roots: Vec::new(),
fees: 1_000_000,
block_data_hash: [2; 32].into(),
upward_messages: Vec::new(),
};
let candidate_statement = GenericStatement::Candidate(candidate);
@@ -717,10 +717,10 @@ mod tests {
collator: [1; 32].unchecked_into(),
signature: Default::default(),
head_data: ::polkadot_primitives::parachain::HeadData(vec![1, 2, 3, 4]),
balance_uploads: Vec::new(),
egress_queue_roots: Vec::new(),
fees: 1_000_000,
block_data_hash: [2; 32].into(),
upward_messages: Vec::new(),
};
let hash = candidate.hash();
@@ -758,10 +758,10 @@ mod tests {
collator: [1; 32].unchecked_into(),
signature: Default::default(),
head_data: ::polkadot_primitives::parachain::HeadData(vec![1, 2, 3, 4]),
balance_uploads: Vec::new(),
egress_queue_roots: Vec::new(),
fees: 1_000_000,
block_data_hash: [2; 32].into(),
upward_messages: Vec::new(),
};
let hash = candidate.hash();
@@ -819,10 +819,10 @@ mod tests {
collator: [1; 32].unchecked_into(),
signature: Default::default(),
head_data: ::polkadot_primitives::parachain::HeadData(vec![1, 2, 3, 4]),
balance_uploads: Vec::new(),
egress_queue_roots: Vec::new(),
fees: 1_000_000,
block_data_hash: [2; 32].into(),
upward_messages: Vec::new(),
};
let hash = candidate.hash();
@@ -884,10 +884,10 @@ mod tests {
collator: [1; 32].unchecked_into(),
signature: Default::default(),
head_data: ::polkadot_primitives::parachain::HeadData(vec![1, 2, 3, 4]),
balance_uploads: Vec::new(),
egress_queue_roots: Vec::new(),
fees: 1_000_000,
block_data_hash: [2; 32].into(),
upward_messages: Vec::new(),
};
let hash = candidate.hash();