Make everything compile and fix tests

This commit is contained in:
Bastian Köcher
2020-01-14 22:22:21 +01:00
parent 1418b842aa
commit 828447d49c
26 changed files with 5214 additions and 3536 deletions
+1
View File
@@ -0,0 +1 @@
hard_tabs=true
+4036 -2722
View File
File diff suppressed because it is too large Load Diff
+23 -12
View File
@@ -6,33 +6,44 @@ edition = "2018"
[dependencies] [dependencies]
# Substrate dependencies # Substrate dependencies
sr-primitives = { package = "sr-primitives", git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
substrate-primitives = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
substrate-client = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
substrate-service = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
consensus-common = { package = "substrate-consensus-common", git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sp-api = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
inherents = { package = "substrate-inherents", git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sc-client = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
cli = { package = "substrate-cli", git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
sc-service = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
sc-cli = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
# Polkadot dependencies # Polkadot dependencies
polkadot-collator = { git = "https://github.com/paritytech/polkadot", branch = "bkchr-cumulus-branch" } polkadot-collator = { git = "https://github.com/paritytech/polkadot", branch = "bkchr-cumulus-branch" }
polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "bkchr-cumulus-branch" }
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "bkchr-cumulus-branch" } polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "bkchr-cumulus-branch" }
# Cumulus dependencies # Cumulus dependencies
cumulus-consensus = { path = "../consensus" } cumulus-consensus = { path = "../consensus" }
cumulus-runtime = { path = "../runtime" } cumulus-runtime = { path = "../runtime" }
# other deps # Other dependencies
log = "0.4.8" log = "0.4.8"
codec = { package = "parity-scale-codec", version = "1.0.6", features = [ "derive" ] } codec = { package = "parity-scale-codec", version = "1.0.6", features = [ "derive" ] }
futures = "0.1.29" futures = { version = "0.3.1", features = ["compat"] }
futures03 = { package = "futures-preview", version = "0.3.0-alpha.19", features = ["compat"] }
parking_lot = "0.9" parking_lot = "0.9"
[dev-dependencies] [dev-dependencies]
# Cumulus dependencies
test-runtime = { package = "cumulus-test-runtime", path = "../test/runtime" } test-runtime = { package = "cumulus-test-runtime", path = "../test/runtime" }
test-client = { package = "cumulus-test-client", path = "../test/client" } test-client = { package = "cumulus-test-client", path = "../test/client" }
# Substrate dependencies
substrate-test-client = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } substrate-test-client = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
polkadot-executor = { git = "https://github.com/paritytech/polkadot", branch = "bkchr-cumulus-branch" } sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
keyring = { package = "substrate-keyring", git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
# Polkadot dependencies
polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "bkchr-cumulus-branch" }
# Other dependencies
env_logger = "0.7.1" env_logger = "0.7.1"
+272 -196
View File
@@ -18,34 +18,32 @@
use cumulus_runtime::ParachainBlockData; use cumulus_runtime::ParachainBlockData;
use sr_primitives::traits::{Block as BlockT, Header as HeaderT}; use sp_consensus::{
use consensus_common::{ BlockImport, BlockImportParams, BlockOrigin, Environment, Error as ConsensusError,
BlockImport, Environment, Proposer, ForkChoiceStrategy, BlockImportParams, BlockOrigin, ForkChoiceStrategy, Proposal, Proposer, RecordProof,
Error as ConsensusError,
}; };
use inherents::InherentDataProviders; use sp_inherents::InherentDataProviders;
use substrate_primitives::Blake2Hasher; use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use polkadot_collator::{ use polkadot_collator::{
InvalidHead, ParachainContext, BuildParachainContext, Network as CollatorNetwork, VersionInfo, BuildParachainContext, InvalidHead, Network as CollatorNetwork, ParachainContext,
TaskExecutor, PolkadotClient, PolkadotClient,
}; };
use polkadot_primitives::{ use polkadot_primitives::{
Hash as PHash, Block as PBlock,
parachain::{ parachain::{
self, BlockData, Message, Id as ParaId, OutgoingMessages, Status as ParachainStatus, self, BlockData, CollatorPair, Id as ParaId, Message, OutgoingMessages,
CollatorPair, Status as ParachainStatus,
} },
Block as PBlock, Hash as PHash,
}; };
use codec::{Decode, Encode}; use codec::{Decode, Encode};
use log::{error, trace}; use log::{error, trace};
use futures03::{TryFutureExt, future}; use futures::{future, task::Spawn, Future, FutureExt, TryFutureExt};
use futures::{Future, future::IntoFuture};
use std::{sync::Arc, marker::PhantomData, time::Duration, fmt::Debug}; use std::{fmt::Debug, marker::PhantomData, sync::Arc, time::Duration};
use parking_lot::Mutex; use parking_lot::Mutex;
@@ -95,17 +93,25 @@ impl<Block, PF, BI> Clone for Collator<Block, PF, BI> {
} }
impl<Block, PF, BI> ParachainContext for Collator<Block, PF, BI> impl<Block, PF, BI> ParachainContext for Collator<Block, PF, BI>
where where
Block: BlockT, Block: BlockT,
PF: Environment<Block> + 'static + Send, PF: Environment<Block> + 'static + Send,
BI: BlockImport<Block, Error=ConsensusError> + Send + Sync + 'static, PF::Proposer: Send,
BI: BlockImport<
Block,
Error = ConsensusError,
Transaction = <PF::Proposer as Proposer<Block>>::Transaction,
> + Send
+ Sync
+ 'static,
{ {
type ProduceCandidate = Box< type ProduceCandidate = Box<
dyn Future<Item=(BlockData, parachain::HeadData, OutgoingMessages), Error=InvalidHead> dyn Future<Output = Result<(BlockData, parachain::HeadData, OutgoingMessages), InvalidHead>>
+ Send + Send
+ Unpin,
>; >;
fn produce_candidate<I: IntoIterator<Item=(ParaId, Message)>>( fn produce_candidate<I: IntoIterator<Item = (ParaId, Message)>>(
&mut self, &mut self,
_relay_chain_parent: PHash, _relay_chain_parent: PHash,
status: ParachainStatus, status: ParachainStatus,
@@ -117,124 +123,145 @@ impl<Block, PF, BI> ParachainContext for Collator<Block, PF, BI>
let inherent_providers = self.inherent_data_providers.clone(); let inherent_providers = self.inherent_data_providers.clone();
let block_import = self.block_import.clone(); let block_import = self.block_import.clone();
let res = HeadData::<Block>::decode(&mut &status.head_data.0[..]) let res = future::ready(
.map_err(|e| { HeadData::<Block>::decode(&mut &status.head_data.0[..]).map_err(|e| {
error!(target: "cumulus-collator", "Could not decode the head data: {:?}", e); error!(target: "cumulus-collator", "Could not decode the head data: {:?}", e);
InvalidHead InvalidHead
}) }),
.into_future() )
.and_then(move |last_head| { .and_then(move |last_head| {
let parent_state_root = *last_head.header.state_root(); let parent_state_root = *last_head.header.state_root();
factory.lock() let proposer_inherent_data = factory
.init(&last_head.header) .lock()
.map_err(|e| { .init(&last_head.header)
error!( .map_err(|e| {
target: "cumulus-collator", error!(
"Could not create proposer: {:?}", target: "cumulus-collator",
e, "Could not create proposer: {:?}",
); e,
InvalidHead );
}) InvalidHead
.and_then(|mut proposer| { })
let inherent_data = inherent_providers.create_inherent_data() .and_then(|proposer| {
.map_err(|e| { inherent_providers
error!( .create_inherent_data()
target: "cumulus-collator",
"Failed to create inherent data: {:?}",
e,
);
InvalidHead
})?;
let future = proposer.propose(
inherent_data,
Default::default(),
//TODO: Fix this.
Duration::from_secs(6),
true,
)
.map_err(|e| { .map_err(|e| {
error!( error!(
target: "cumulus-collator", target: "cumulus-collator",
"Proposing failed: {:?}", "Failed to create inherent data: {:?}",
e, e,
); );
InvalidHead InvalidHead
}) })
.and_then(move |(block, proof)| { .map(move |inherent_data| (proposer, inherent_data))
let res = match proof { });
Some(proof) => {
let (header, extrinsics) = block.deconstruct();
// Create the parachain block data for the validators. future::ready(proposer_inherent_data).and_then(move |(mut proposer, inherent_data)| {
Ok( proposer
ParachainBlockData::<Block>::new( .propose(
header, inherent_data,
extrinsics, Default::default(),
proof, //TODO: Fix this.
parent_state_root, Duration::from_secs(6),
) RecordProof::Yes,
) )
} .map_err(|e| {
None => { error!(
error!( target: "cumulus-collator",
target: "cumulus-collator", "Proposing failed: {:?}",
"Proposer did not return the requested proof.", e,
); );
Err(InvalidHead) InvalidHead
} })
}; .and_then(move |proposal| {
let Proposal {
block,
storage_changes,
proof,
} = proposal;
let res = match proof {
Some(proof) => {
let (header, extrinsics) = block.deconstruct();
future::ready(res) // Create the parachain block data for the validators.
}) Ok((
.compat(); ParachainBlockData::<Block>::new(
header,
extrinsics,
proof.iter_nodes().collect(),
parent_state_root,
),
storage_changes,
))
}
None => {
error!(
target: "cumulus-collator",
"Proposer did not return the requested proof.",
);
Err(InvalidHead)
}
};
Ok(future) future::ready(res)
}) })
}) })
.flatten() })
.and_then(move |b| { .and_then(move |(b, storage_changes)| {
let block_import_params = BlockImportParams { let block_import_params = BlockImportParams {
origin: BlockOrigin::Own, origin: BlockOrigin::Own,
header: b.header().clone(), header: b.header().clone(),
justification: None, justification: None,
post_digests: vec![], post_digests: vec![],
body: Some(b.extrinsics().to_vec()), body: Some(b.extrinsics().to_vec()),
finalized: false, finalized: false,
auxiliary: vec![], // block-weight is written in block import. auxiliary: vec![], // block-weight is written in block import.
// TODO: block-import handles fork choice and this shouldn't even have the // TODO: block-import handles fork choice and this shouldn't even have the
// option to specify one. // option to specify one.
// https://github.com/paritytech/substrate/issues/3623 // https://github.com/paritytech/substrate/issues/3623
fork_choice: ForkChoiceStrategy::LongestChain, fork_choice: ForkChoiceStrategy::LongestChain,
}; allow_missing_state: false,
import_existing: false,
storage_changes: Some(storage_changes),
};
if let Err(err) = block_import.lock().import_block( let res = if let Err(err) = block_import
block_import_params, .lock()
Default::default(), .import_block(block_import_params, Default::default())
) { {
error!( error!(
target: "cumulus-collator", target: "cumulus-collator",
"Error importing build block (at {:?}): {:?}", "Error importing build block (at {:?}): {:?}",
b.header().parent_hash(), b.header().parent_hash(),
err, err,
); );
Err(InvalidHead) Err(InvalidHead)
} else { } else {
Ok(b) Ok(b)
} };
})
.map(|b| {
let block_data = BlockData(b.encode());
let head_data = HeadData::<Block> { header: b.into_header() };
let messages = OutgoingMessages { outgoing_messages: Vec::new() };
(block_data, parachain::HeadData(head_data.encode()), messages) future::ready(res)
}) })
.then(|r| { .map_ok(|b| {
trace!(target: "cumulus-collator", "Produced candidate: {:?}", r); let block_data = BlockData(b.encode());
r let head_data = HeadData::<Block> {
}); header: b.into_header(),
};
let messages = OutgoingMessages {
outgoing_messages: Vec::new(),
};
(
block_data,
parachain::HeadData(head_data.encode()),
messages,
)
})
.then(|r| {
trace!(target: "cumulus-collator", "Produced candidate: {:?}", r);
future::ready(r)
});
Box::new(res) Box::new(res)
} }
@@ -256,24 +283,44 @@ impl<Block, SP> CollatorBuilder<Block, SP> {
} }
} }
impl<Block: BlockT, SP: SetupParachain<Block>> BuildParachainContext for CollatorBuilder<Block, SP> { impl<Block: BlockT, SP: SetupParachain<Block>> BuildParachainContext for CollatorBuilder<Block, SP>
where
<SP::ProposerFactory as Environment<Block>>::Proposer: Send,
{
type ParachainContext = Collator<Block, SP::ProposerFactory, SP::BlockImport>; type ParachainContext = Collator<Block, SP::ProposerFactory, SP::BlockImport>;
fn build<B, E>( fn build<B, E, R, Spawner, Extrinsic>(
self, self,
client: Arc<PolkadotClient<B, E>>, client: Arc<PolkadotClient<B, E, R>>,
task_executor: TaskExecutor, spawner: Spawner,
network: Arc<dyn CollatorNetwork>, network: Arc<dyn CollatorNetwork>,
) -> Result<Self::ParachainContext, ()> ) -> Result<Self::ParachainContext, ()>
where where
B: substrate_client::backend::Backend<PBlock, Blake2Hasher> + 'static, PolkadotClient<B, E, R>: sp_api::ProvideRuntimeApi<PBlock>,
E: substrate_client::CallExecutor<PBlock, Blake2Hasher> + Clone + Send + Sync + 'static <PolkadotClient<B, E, R> as sp_api::ProvideRuntimeApi<PBlock>>::Api:
polkadot_service::RuntimeApiCollection<Extrinsic>,
E: sc_client::CallExecutor<PBlock> + Clone + Send + Sync + 'static,
Spawner: Spawn + Clone + Send + Sync + 'static,
Extrinsic: codec::Codec + Send + Sync + 'static,
<<PolkadotClient<B, E, R> as sp_api::ProvideRuntimeApi<PBlock>>::Api as sp_api::ApiExt<
PBlock,
>>::StateBackend: sp_api::StateBackend<sp_core::Blake2Hasher>,
R: Send + Sync + 'static,
B: sc_client_api::Backend<PBlock> + 'static,
// Rust bug: https://github.com/rust-lang/rust/issues/24159
B::State: sp_api::StateBackend<sp_core::Blake2Hasher>,
{ {
let (proposer_factory, block_import, inherent_data_providers) = self.setup_parachain let (proposer_factory, block_import, inherent_data_providers) = self
.setup_parachain(client, task_executor) .setup_parachain
.setup_parachain(client, spawner)
.map_err(|e| error!("Error setting up the parachain: {}", e))?; .map_err(|e| error!("Error setting up the parachain: {}", e))?;
Ok(Collator::new(proposer_factory, inherent_data_providers, network, block_import)) Ok(Collator::new(
proposer_factory,
inherent_data_providers,
network,
block_import,
))
} }
} }
@@ -282,14 +329,32 @@ pub trait SetupParachain<Block: BlockT>: Send {
/// The proposer factory of the parachain to build blocks. /// The proposer factory of the parachain to build blocks.
type ProposerFactory: Environment<Block> + Send + 'static; type ProposerFactory: Environment<Block> + Send + 'static;
/// The block import for importing the blocks build by the collator. /// The block import for importing the blocks build by the collator.
type BlockImport: BlockImport<Block, Error=ConsensusError> + Send + Sync + 'static; type BlockImport: BlockImport<
Block,
Error = ConsensusError,
Transaction = <<Self::ProposerFactory as Environment<Block>>::Proposer as Proposer<
Block,
>>::Transaction,
> + Send
+ Sync
+ 'static;
/// Setup the parachain. /// Setup the parachain.
fn setup_parachain<P: cumulus_consensus::PolkadotClient>( fn setup_parachain<P, SP>(
self, self,
polkadot_client: P, polkadot_client: P,
task_executor: TaskExecutor, spawner: SP,
) -> Result<(Self::ProposerFactory, Self::BlockImport, InherentDataProviders), String>; ) -> Result<
(
Self::ProposerFactory,
Self::BlockImport,
InherentDataProviders,
),
String,
>
where
P: cumulus_consensus::PolkadotClient,
SP: Spawn + Clone + Send + Sync + 'static;
} }
/// Run a collator with the given proposer factory. /// Run a collator with the given proposer factory.
@@ -298,16 +363,16 @@ pub fn run_collator<Block, SP, E>(
para_id: ParaId, para_id: ParaId,
exit: E, exit: E,
key: Arc<CollatorPair>, key: Arc<CollatorPair>,
version: VersionInfo, configuration: polkadot_collator::Configuration,
) -> Result<(), cli::error::Error> ) -> Result<(), sc_cli::error::Error>
where where
Block: BlockT, Block: BlockT,
SP: SetupParachain<Block> + Send + 'static, SP: SetupParachain<Block> + Send + 'static,
E: IntoFuture<Item=(), Error=()>, <<SP as SetupParachain<Block>>::ProposerFactory as Environment<Block>>::Proposer: Send,
E::Future: Send + Clone + Sync + 'static, E: Future<Output = ()> + Unpin + Send + Clone + Sync + 'static,
{ {
let builder = CollatorBuilder::new(setup_parachain); let builder = CollatorBuilder::new(setup_parachain);
polkadot_collator::run_collator(builder, para_id, exit, key, version) polkadot_collator::run_collator(builder, para_id, exit, key, configuration)
} }
#[cfg(test)] #[cfg(test)]
@@ -315,26 +380,31 @@ mod tests {
use super::*; use super::*;
use std::time::Duration; use std::time::Duration;
use polkadot_collator::{collate, RelayChainContext, PeerId, CollatorId, SignedStatement}; use polkadot_collator::{collate, CollatorId, PeerId, RelayChainContext, SignedStatement};
use polkadot_primitives::parachain::{ConsolidatedIngress, HeadData, FeeSchedule}; use polkadot_primitives::parachain::{ConsolidatedIngress, FeeSchedule, HeadData};
use keyring::Sr25519Keyring; use sp_blockchain::Result as ClientResult;
use sr_primitives::{generic::BlockId, traits::{DigestFor, Header as HeaderT}}; use sp_inherents::InherentData;
use inherents::InherentData; use sp_keyring::Sr25519Keyring;
use substrate_client::error::Result as ClientResult; use sp_runtime::{
generic::BlockId,
traits::{DigestFor, Header as HeaderT},
};
use sp_state_machine::StorageProof;
use substrate_test_client::{NativeExecutor, WasmExecutionMethod::Interpreted}; use substrate_test_client::{NativeExecutor, WasmExecutionMethod::Interpreted};
use test_client::{
Client, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt,
};
use test_runtime::{Block, Header}; use test_runtime::{Block, Header};
use test_client::{Client, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt};
use futures03::future;
use futures::Stream; use futures::Stream;
#[derive(Debug)] #[derive(Debug)]
struct Error; struct Error;
impl From<consensus_common::Error> for Error { impl From<sp_consensus::Error> for Error {
fn from(_: consensus_common::Error) -> Self { fn from(_: sp_consensus::Error) -> Self {
unimplemented!("Not required in tests") unimplemented!("Not required in tests")
} }
} }
@@ -354,14 +424,15 @@ mod tests {
impl Proposer<Block> for DummyProposer { impl Proposer<Block> for DummyProposer {
type Error = Error; type Error = Error;
type Proposal = future::Ready<Result<(Block, Option<Vec<Vec<u8>>>), Error>>; type Proposal = future::Ready<Result<Proposal<Block, Self::Transaction>, Error>>;
type Transaction = sc_client_api::TransactionFor<test_client::Backend, Block>;
fn propose( fn propose(
&mut self, &mut self,
_: InherentData, _: InherentData,
digest : DigestFor<Block>, digest: DigestFor<Block>,
_: Duration, _: Duration,
_: bool, _: RecordProof,
) -> Self::Proposal { ) -> Self::Proposal {
let header = Header::new( let header = Header::new(
1337, 1337,
@@ -371,22 +442,25 @@ mod tests {
digest, digest,
); );
future::ready(Ok((Block::new(header, Vec::new()), Some(Default::default())))) future::ready(Ok(Proposal {
block: Block::new(header, Vec::new()),
storage_changes: Default::default(),
proof: Some(StorageProof::empty()),
}))
} }
} }
struct DummyCollatorNetwork; struct DummyCollatorNetwork;
impl CollatorNetwork for DummyCollatorNetwork { impl CollatorNetwork for DummyCollatorNetwork {
fn collator_id_to_peer_id(&self, _: CollatorId) -> fn collator_id_to_peer_id(
Box<dyn Future<Item=Option<PeerId>, Error=()> + Send> &self,
{ _: CollatorId,
) -> Box<dyn Future<Output = Option<PeerId>> + Send> {
unimplemented!("Not required in tests") unimplemented!("Not required in tests")
} }
fn checked_statements(&self, _: PHash) -> fn checked_statements(&self, _: PHash) -> Box<dyn Stream<Item = SignedStatement>> {
Box<dyn Stream<Item=SignedStatement, Error=()>>
{
unimplemented!("Not required in tests") unimplemented!("Not required in tests")
} }
} }
@@ -395,10 +469,10 @@ mod tests {
impl RelayChainContext for DummyRelayChainContext { impl RelayChainContext for DummyRelayChainContext {
type Error = Error; type Error = Error;
type FutureEgress = Result<ConsolidatedIngress, Self::Error>; type FutureEgress = future::Ready<Result<ConsolidatedIngress, Error>>;
fn unrouted_egress(&self, _id: ParaId) -> Self::FutureEgress { fn unrouted_egress(&self, _id: ParaId) -> Self::FutureEgress {
Ok(ConsolidatedIngress(Vec::new())) future::ready(Ok(ConsolidatedIngress(Vec::new())))
} }
} }
@@ -407,7 +481,7 @@ mod tests {
impl cumulus_consensus::PolkadotClient for DummyPolkadotClient { impl cumulus_consensus::PolkadotClient for DummyPolkadotClient {
type Error = Error; type Error = Error;
type Finalized = Box<dyn futures03::Stream<Item=Vec<u8>> + Send + Unpin>; type Finalized = Box<dyn futures::Stream<Item = Vec<u8>> + Send + Unpin>;
fn finalized_heads(&self, _: ParaId) -> ClientResult<Self::Finalized> { fn finalized_heads(&self, _: ParaId) -> ClientResult<Self::Finalized> {
unimplemented!("Not required in tests") unimplemented!("Not required in tests")
@@ -417,7 +491,7 @@ mod tests {
&self, &self,
_: &BlockId<PBlock>, _: &BlockId<PBlock>,
_: ParaId, _: ParaId,
) -> ClientResult<Option<Vec<u8>>>{ ) -> ClientResult<Option<Vec<u8>>> {
unimplemented!("Not required in tests") unimplemented!("Not required in tests")
} }
} }
@@ -428,45 +502,45 @@ mod tests {
type ProposerFactory = DummyFactory; type ProposerFactory = DummyFactory;
type BlockImport = Client; type BlockImport = Client;
fn setup_parachain<P: cumulus_consensus::PolkadotClient>( fn setup_parachain<P, SP>(
self, self,
_: P, _: P,
_: TaskExecutor, _: SP,
) -> Result<(Self::ProposerFactory, Self::BlockImport, InherentDataProviders), String> { ) -> Result<
Ok((DummyFactory, TestClientBuilder::new().build(), InherentDataProviders::default())) (
} Self::ProposerFactory,
} Self::BlockImport,
InherentDataProviders,
type BoxFuture = Box<dyn Future<Item = (), Error = ()> + Send>; ),
String,
struct DummyFutureExecutor; > {
Ok((
impl futures::future::Executor<BoxFuture> DummyFactory,
for DummyFutureExecutor TestClientBuilder::new().build(),
{ InherentDataProviders::default(),
fn execute( ))
&self,
_: BoxFuture,
) -> Result<(), futures::future::ExecuteError<BoxFuture>> {
unimplemented!("Not required in tests")
} }
} }
#[test] #[test]
fn collates_produces_a_block() { fn collates_produces_a_block() {
let _ = env_logger::try_init(); let _ = env_logger::try_init();
let spawner = futures::executor::ThreadPool::new().unwrap();
let builder = CollatorBuilder::new(DummySetup); let builder = CollatorBuilder::new(DummySetup);
let context = builder.build( let context = builder
Arc::new( .build::<_, _, polkadot_service::polkadot_runtime::RuntimeApi, _, _>(
substrate_test_client::TestClientBuilder::<_, _, ()>::default() Arc::new(
.build_with_native_executor( substrate_test_client::TestClientBuilder::<_, _, ()>::default()
Some(NativeExecutor::<polkadot_executor::Executor>::new(Interpreted, None)), .build_with_native_executor(Some(NativeExecutor::<
).0 polkadot_service::PolkadotExecutor,
), >::new(Interpreted, None)))
Arc::new(DummyFutureExecutor), .0,
Arc::new(DummyCollatorNetwork), ),
).expect("Creates parachain context"); spawner,
Arc::new(DummyCollatorNetwork),
)
.expect("Creates parachain context");
let id = ParaId::from(100); let id = ParaId::from(100);
let header = Header::new( let header = Header::new(
@@ -491,7 +565,9 @@ mod tests {
DummyRelayChainContext, DummyRelayChainContext,
context, context,
Arc::new(Sr25519Keyring::Alice.pair().into()), Arc::new(Sr25519Keyring::Alice.pair().into()),
).wait().unwrap().0; );
let collation = futures::executor::block_on(collation).unwrap().0;
let block_data = collation.pov.block_data; let block_data = collation.pov.block_data;
+10 -6
View File
@@ -7,18 +7,22 @@ edition = "2018"
[dependencies] [dependencies]
# substrate deps # substrate deps
substrate-client = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sc-client = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
substrate-consensus-common = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
substrate-primitives = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
substrate-inherents = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
sr-primitives = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
sp-api = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
# polkadot deps # polkadot deps
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "bkchr-cumulus-branch" } polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "bkchr-cumulus-branch" }
polkadot-runtime = { git = "https://github.com/paritytech/polkadot", branch = "bkchr-cumulus-branch" } polkadot-runtime = { git = "https://github.com/paritytech/polkadot", branch = "bkchr-cumulus-branch" }
# other deps # other deps
futures = { package = "futures-preview", version = "0.3.0-alpha.19", features = ["compat"] } futures = { version = "0.3.1", features = ["compat"] }
tokio = "0.1.22" tokio = "0.1.22"
codec = { package = "parity-scale-codec", version = "1.0.5", features = [ "derive" ] } codec = { package = "parity-scale-codec", version = "1.0.5", features = [ "derive" ] }
log = "0.4" log = "0.4"
+59 -46
View File
@@ -16,38 +16,37 @@
use std::sync::Arc; use std::sync::Arc;
use substrate_primitives::{H256, Blake2Hasher}; use sc_client::Client;
use sc_client_api::{Backend, CallExecutor, TransactionFor};
use sr_primitives::{ use sp_api::ProvideRuntimeApi;
traits::{Block as BlockT, ProvideRuntimeApi, Header as HeaderT}, Justification, use sp_block_builder::BlockBuilder as BlockBuilderApi;
use sp_blockchain::Result as ClientResult;
use sp_consensus::{
error::Error as ConsensusError,
import_queue::{BasicQueue, CacheKeyId, Verifier as VerifierT},
BlockImport, BlockImportParams, BlockOrigin, ForkChoiceStrategy,
};
use sp_inherents::InherentDataProviders;
use sp_runtime::{
generic::BlockId, generic::BlockId,
traits::{Block as BlockT, Header as HeaderT},
Justification,
}; };
use substrate_client::{
block_builder::api::BlockBuilder as BlockBuilderApi, backend::Backend, CallExecutor, Client,
error::Result as ClientResult,
};
use substrate_consensus_common::{
import_queue::{Verifier as VerifierT, BasicQueue, CacheKeyId}, BlockImportParams,
ForkChoiceStrategy, BlockOrigin, error::Error as ConsensusError, BlockImport,
};
use substrate_inherents::InherentDataProviders;
/// A verifier that just checks the inherents. /// A verifier that just checks the inherents.
struct Verifier<B, E, Block: BlockT, RA> { struct Verifier<B, E, Block: BlockT, RA> {
client: Arc<Client<B, E, Block, RA>>, client: Arc<Client<B, E, Block, RA>>,
inherent_data_providers: InherentDataProviders, inherent_data_providers: InherentDataProviders,
} }
impl<B, E, Block, RA> VerifierT<Block> for Verifier<B, E, Block, RA> where impl<B, E, Block, RA> VerifierT<Block> for Verifier<B, E, Block, RA>
Block: BlockT<Hash=H256>, where
B: Backend<Block, Blake2Hasher> + 'static, Block: BlockT,
E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync, B: Backend<Block> + 'static,
E: CallExecutor<Block> + 'static + Clone + Send + Sync,
RA: Send + Sync, RA: Send + Sync,
Client<B, E, Block, RA>: ProvideRuntimeApi + Send + Sync, Client<B, E, Block, RA>: ProvideRuntimeApi<Block> + Send + Sync,
<Client<B, E, Block, RA> as ProvideRuntimeApi>::Api: BlockBuilderApi<Block> <Client<B, E, Block, RA> as ProvideRuntimeApi<Block>>::Api: BlockBuilderApi<Block>,
{ {
fn verify( fn verify(
&mut self, &mut self,
@@ -55,33 +54,41 @@ impl<B, E, Block, RA> VerifierT<Block> for Verifier<B, E, Block, RA> where
header: Block::Header, header: Block::Header,
justification: Option<Justification>, justification: Option<Justification>,
mut body: Option<Vec<Block::Extrinsic>>, mut body: Option<Vec<Block::Extrinsic>>,
) -> Result<(BlockImportParams<Block>, Option<Vec<(CacheKeyId, Vec<u8>)>>), String> { ) -> Result<
(
BlockImportParams<Block, ()>,
Option<Vec<(CacheKeyId, Vec<u8>)>>,
),
String,
> {
if let Some(inner_body) = body.take() { if let Some(inner_body) = body.take() {
let inherent_data = self.inherent_data_providers let inherent_data = self
.inherent_data_providers
.create_inherent_data() .create_inherent_data()
.map_err(String::from)?; .map_err(|e| e.into_string())?;
let block = Block::new(header.clone(), inner_body); let block = Block::new(header.clone(), inner_body);
let inherent_res = self.client.runtime_api().check_inherents( let inherent_res = self
&BlockId::Hash(*header.parent_hash()), .client
block.clone(), .runtime_api()
inherent_data, .check_inherents(
).map_err(|e| format!("{:?}", e))?; &BlockId::Hash(*header.parent_hash()),
block.clone(),
inherent_data,
)
.map_err(|e| format!("{:?}", e))?;
if !inherent_res.ok() { if !inherent_res.ok() {
inherent_res inherent_res.into_errors().try_for_each(|(i, e)| {
.into_errors() Err(self.inherent_data_providers.error_to_string(&i, &e))
.try_for_each(|(i, e)| { })?;
Err(self.inherent_data_providers.error_to_string(&i, &e))
})?;
} }
let (_, inner_body) = block.deconstruct(); let (_, inner_body) = block.deconstruct();
body = Some(inner_body); body = Some(inner_body);
} }
let block_import_params = BlockImportParams { let block_import_params = BlockImportParams {
origin, origin,
header, header,
@@ -91,6 +98,9 @@ impl<B, E, Block, RA> VerifierT<Block> for Verifier<B, E, Block, RA> where
justification, justification,
auxiliary: Vec::new(), auxiliary: Vec::new(),
fork_choice: ForkChoiceStrategy::LongestChain, fork_choice: ForkChoiceStrategy::LongestChain,
allow_missing_state: false,
import_existing: false,
storage_changes: None,
}; };
Ok((block_import_params, None)) Ok((block_import_params, None))
@@ -98,22 +108,25 @@ impl<B, E, Block, RA> VerifierT<Block> for Verifier<B, E, Block, RA> where
} }
/// Start an import queue for a Cumulus collator that does not uses any special authoring logic. /// Start an import queue for a Cumulus collator that does not uses any special authoring logic.
pub fn import_queue<B, E, Block: BlockT<Hash=H256>, I, RA>( pub fn import_queue<B, E, Block: BlockT, I, RA>(
client: Arc<Client<B, E, Block, RA>>, client: Arc<Client<B, E, Block, RA>>,
block_import: I, block_import: I,
inherent_data_providers: InherentDataProviders, inherent_data_providers: InherentDataProviders,
) -> ClientResult<BasicQueue<Block>> ) -> ClientResult<BasicQueue<Block, TransactionFor<B, Block>>>
where where
B: Backend<Block, Blake2Hasher> + 'static, B: Backend<Block> + 'static,
I: BlockImport<Block,Error=ConsensusError> + Send + Sync + 'static, I: BlockImport<Block, Error = ConsensusError, Transaction = TransactionFor<B, Block>>
E: CallExecutor<Block, Blake2Hasher> + Clone + Send + Sync + 'static, + Send
RA: Send + Sync + 'static, + Sync
Client<B, E, Block, RA>: ProvideRuntimeApi + Send + Sync + 'static, + 'static,
<Client<B, E, Block, RA> as ProvideRuntimeApi>::Api: BlockBuilderApi<Block>, E: CallExecutor<Block> + Clone + Send + Sync + 'static,
RA: Send + Sync + 'static,
Client<B, E, Block, RA>: ProvideRuntimeApi<Block> + Send + Sync + 'static,
<Client<B, E, Block, RA> as ProvideRuntimeApi<Block>>::Api: BlockBuilderApi<Block>,
{ {
let verifier = Verifier { let verifier = Verifier {
client, client,
inherent_data_providers inherent_data_providers,
}; };
Ok(BasicQueue::new( Ok(BasicQueue::new(
+72 -55
View File
@@ -14,26 +14,29 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>. // along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
use substrate_client::{ use sc_client::{BlockchainEvents, Client};
backend::{Backend, Finalizer}, CallExecutor, Client, BlockchainEvents, use sc_client_api::{
error::{Error as ClientError, Result as ClientResult}, backend::{Backend, Finalizer, StateBackend, StateBackendFor},
CallExecutor,
}; };
use substrate_primitives::{Blake2Hasher, H256}; use sp_api::ProvideRuntimeApi;
use sr_primitives::{ use sp_blockchain::{Error as ClientError, Result as ClientResult};
use sp_consensus::{Error as ConsensusError, SelectChain as SelectChainT};
use sp_runtime::{
generic::BlockId, generic::BlockId,
traits::{Block as BlockT, Header as HeaderT, ProvideRuntimeApi}, traits::{Block as BlockT, Header as HeaderT},
}; };
use substrate_consensus_common::{Error as ConsensusError, SelectChain as SelectChainT};
use polkadot_primitives::{ use polkadot_primitives::{
Hash as PHash, Block as PBlock, parachain::{Id as ParaId, ParachainHost}, parachain::{Id as ParaId, ParachainHost},
Block as PBlock, Hash as PHash,
}; };
use futures::{Stream, StreamExt, TryStreamExt, future, Future, TryFutureExt, FutureExt};
use codec::Decode; use codec::Decode;
use futures::{future, Future, FutureExt, Stream, StreamExt, TryFutureExt, TryStreamExt};
use log::warn; use log::warn;
use std::{sync::Arc, marker::PhantomData}; use std::{marker::PhantomData, sync::Arc};
pub mod import_queue; pub mod import_queue;
@@ -85,11 +88,14 @@ pub trait PolkadotClient: Clone + 'static {
} }
/// Spawns a future that follows the Polkadot relay chain for the given parachain. /// Spawns a future that follows the Polkadot relay chain for the given parachain.
pub fn follow_polkadot<L, P>(para_id: ParaId, local: Arc<L>, polkadot: P) pub fn follow_polkadot<L, P>(
-> ClientResult<impl Future<Output = ()> + Send + Unpin> para_id: ParaId,
where local: Arc<L>,
L: LocalClient + Send + Sync, polkadot: P,
P: PolkadotClient, ) -> ClientResult<impl Future<Output = ()> + Send + Unpin>
where
L: LocalClient + Send + Sync,
P: PolkadotClient,
{ {
let finalized_heads = polkadot.finalized_heads(para_id)?; let finalized_heads = polkadot.finalized_heads(para_id)?;
@@ -102,21 +108,25 @@ pub fn follow_polkadot<L, P>(para_id: ParaId, local: Arc<L>, polkadot: P)
.map_err(|_| Error::InvalidHeadData) .map_err(|_| Error::InvalidHeadData)
}) })
.try_for_each(move |p_head| { .try_for_each(move |p_head| {
future::ready(local.finalize(p_head.hash()).map_err(Error::Client).map(|_| ())) future::ready(
local
.finalize(p_head.hash())
.map_err(Error::Client)
.map(|_| ()),
)
}) })
}; };
Ok( Ok(follow_finalized
follow_finalized .map_err(|e| warn!("Could not follow relay-chain: {:?}", e))
.map_err(|e| warn!("Could not follow relay-chain: {:?}", e)) .map(|_| ()))
.map(|_| ())
)
} }
impl<B, E, Block, RA> LocalClient for Client<B, E, Block, RA> where impl<B, E, Block, RA> LocalClient for Client<B, E, Block, RA>
B: Backend<Block, Blake2Hasher>, where
E: CallExecutor<Block, Blake2Hasher>, B: Backend<Block>,
Block: BlockT<Hash=H256>, E: CallExecutor<Block>,
Block: BlockT,
{ {
type Block = Block; type Block = Block;
@@ -126,30 +136,36 @@ impl<B, E, Block, RA> LocalClient for Client<B, E, Block, RA> where
Err(e) => match e { Err(e) => match e {
ClientError::UnknownBlock(_) => Ok(false), ClientError::UnknownBlock(_) => Ok(false),
_ => Err(e), _ => Err(e),
} },
} }
} }
} }
impl<B, E, RA> PolkadotClient for Arc<Client<B, E, PBlock, RA>> where impl<B, E, RA> PolkadotClient for Arc<Client<B, E, PBlock, RA>>
B: Backend<PBlock, Blake2Hasher> + Send + Sync + 'static, where
E: CallExecutor<PBlock, Blake2Hasher> + Send + Sync + 'static, B: Backend<PBlock> + Send + Sync + 'static,
Client<B, E, PBlock, RA>: ProvideRuntimeApi + Send + Sync + 'static, E: CallExecutor<PBlock> + Send + Sync + 'static,
<Client<B, E, PBlock, RA> as ProvideRuntimeApi>::Api: ParachainHost<PBlock>, Client<B, E, PBlock, RA>: ProvideRuntimeApi<PBlock> + Send + Sync + 'static,
<Client<B, E, PBlock, RA> as ProvideRuntimeApi<PBlock>>::Api:
ParachainHost<PBlock, Error = ClientError>,
// Rust bug: https://github.com/rust-lang/rust/issues/24159
StateBackendFor<B, PBlock>: StateBackend<sp_core::Blake2Hasher>,
{ {
type Error = ClientError; type Error = ClientError;
type Finalized = Box<dyn Stream<Item=Vec<u8>> + Send + Unpin>; type Finalized = Box<dyn Stream<Item = Vec<u8>> + Send + Unpin>;
fn finalized_heads(&self, para_id: ParaId) -> ClientResult<Self::Finalized> { fn finalized_heads(&self, para_id: ParaId) -> ClientResult<Self::Finalized> {
let polkadot = self.clone(); let polkadot = self.clone();
let s = self.finality_notification_stream() let s = self.finality_notification_stream().filter_map(move |n| {
.filter_map(move |n| future::ready(
future::ready( polkadot
polkadot.parachain_head_at(&BlockId::hash(n.hash), para_id).ok().and_then(|h| h), .parachain_head_at(&BlockId::hash(n.hash), para_id)
), .ok()
); .and_then(|h| h),
)
});
Ok(Box::new(s)) Ok(Box::new(s))
} }
@@ -159,7 +175,9 @@ impl<B, E, RA> PolkadotClient for Arc<Client<B, E, PBlock, RA>> where
at: &BlockId<PBlock>, at: &BlockId<PBlock>,
para_id: ParaId, para_id: ParaId,
) -> ClientResult<Option<Vec<u8>>> { ) -> ClientResult<Option<Vec<u8>>> {
self.runtime_api().parachain_status(at, para_id).map(|s| s.map(|s| s.head_data.0)) self.runtime_api()
.parachain_status(at, para_id)
.map(|s| s.map(|s| s.head_data.0))
} }
} }
@@ -201,42 +219,41 @@ impl<Block, PC: Clone, SC: Clone> Clone for SelectChain<Block, PC, SC> {
} }
} }
impl<Block, PC, SC> SelectChainT<Block> for SelectChain<Block, PC, SC> where impl<Block, PC, SC> SelectChainT<Block> for SelectChain<Block, PC, SC>
Block: BlockT<Hash=H256>, where
Block: BlockT,
PC: PolkadotClient + Clone + Send + Sync, PC: PolkadotClient + Clone + Send + Sync,
PC::Error: ToString, PC::Error: ToString,
SC: SelectChainT<PBlock>, SC: SelectChainT<PBlock>,
{ {
fn leaves(&self) -> Result<Vec<<Block as BlockT>::Hash>, ConsensusError> { fn leaves(&self) -> Result<Vec<<Block as BlockT>::Hash>, ConsensusError> {
let leaves = self.polkadot_select_chain.leaves()?; let leaves = self.polkadot_select_chain.leaves()?;
leaves.into_iter() leaves
.filter_map(|l| .into_iter()
.filter_map(|l| {
self.polkadot_client self.polkadot_client
.parachain_head_at(&BlockId::Hash(l), self.para_id) .parachain_head_at(&BlockId::Hash(l), self.para_id)
.map(|h| h.and_then(|d| <<Block as BlockT>::Hash>::decode(&mut &d[..]).ok())) .map(|h| h.and_then(|d| <<Block as BlockT>::Hash>::decode(&mut &d[..]).ok()))
.transpose() .transpose()
) })
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()
.map_err(|e| ConsensusError::ChainLookup(e.to_string())) .map_err(|e| ConsensusError::ChainLookup(e.to_string()))
} }
fn best_chain(&self) -> Result<<Block as BlockT>::Header, ConsensusError> { fn best_chain(&self) -> Result<<Block as BlockT>::Header, ConsensusError> {
let best_chain = self.polkadot_select_chain.best_chain()?; let best_chain = self.polkadot_select_chain.best_chain()?;
let para_best_chain = self.polkadot_client let para_best_chain = self
.polkadot_client
.parachain_head_at(&BlockId::Hash(best_chain.hash()), self.para_id) .parachain_head_at(&BlockId::Hash(best_chain.hash()), self.para_id)
.map_err(|e| ConsensusError::ChainLookup(e.to_string()))?; .map_err(|e| ConsensusError::ChainLookup(e.to_string()))?;
match para_best_chain { match para_best_chain {
Some(best) => Decode::decode(&mut &best[..]) Some(best) => Decode::decode(&mut &best[..]).map_err(|e| {
.map_err(|e| ConsensusError::ChainLookup(format!("Error decoding parachain head: {}", e.what()))
ConsensusError::ChainLookup( }),
format!("Error decoding parachain head: {}", e.what()), None => Err(ConsensusError::ChainLookup(
), "Could not find parachain head for best relay chain!".into(),
), )),
None => Err(
ConsensusError::ChainLookup(
"Could not find parachain head for best relay chain!".into()),
)
} }
} }
} }
+4 -3
View File
@@ -7,9 +7,10 @@ edition = "2018"
[dependencies] [dependencies]
# substrate deps # substrate deps
substrate-client = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sc-client = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
substrate-consensus-common = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
sr-primitives = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
# polkadot deps # polkadot deps
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "bkchr-cumulus-branch" } polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "bkchr-cumulus-branch" }
+44 -38
View File
@@ -18,14 +18,14 @@
//! //!
//! Contains message send between collators and logic to process them. //! Contains message send between collators and logic to process them.
use substrate_client::error::{Error as ClientError}; use sp_blockchain::Error as ClientError;
use sr_primitives::traits::{Block as BlockT}; use sp_consensus::block_validation::{BlockAnnounceValidator, Validation};
use substrate_consensus_common::block_validation::{Validation, BlockAnnounceValidator}; use sp_runtime::traits::Block as BlockT;
use polkadot_network::gossip::{GossipMessage, GossipStatement};
use polkadot_primitives::parachain::ValidatorId; use polkadot_primitives::parachain::ValidatorId;
use polkadot_statement_table::{SignedStatement, Statement}; use polkadot_statement_table::{SignedStatement, Statement};
use polkadot_validation::check_statement; use polkadot_validation::check_statement;
use polkadot_network::gossip::{GossipStatement, GossipMessage};
use codec::{Decode, Encode}; use codec::{Decode, Encode};
@@ -52,68 +52,74 @@ impl<B: BlockT> JustifiedBlockAnnounceValidator<B> {
} }
impl<B: BlockT> BlockAnnounceValidator<B> for JustifiedBlockAnnounceValidator<B> { impl<B: BlockT> BlockAnnounceValidator<B> for JustifiedBlockAnnounceValidator<B> {
fn validate(&mut self, header: &B::Header, mut data: &[u8]) fn validate(
-> Result<Validation, Box<dyn std::error::Error + Send>> &mut self,
{ header: &B::Header,
mut data: &[u8],
) -> Result<Validation, Box<dyn std::error::Error + Send>> {
// If no data is provided the announce is valid. // If no data is provided the announce is valid.
if data.is_empty() { if data.is_empty() {
return Ok(Validation::Success) return Ok(Validation::Success);
} }
// Check data is a gossip message. // Check data is a gossip message.
let gossip_message = GossipMessage::decode(&mut data) let gossip_message = GossipMessage::decode(&mut data).map_err(|_| {
.map_err(|_| Box::new(ClientError::BadJustification( Box::new(ClientError::BadJustification(
"cannot decode block announced justification, must be a gossip message".to_string() "cannot decode block announced justification, must be a gossip message".to_string(),
)) as Box<_>)?; )) as Box<_>
})?;
// Check message is a gossip statement. // Check message is a gossip statement.
let gossip_statement = match gossip_message { let gossip_statement = match gossip_message {
GossipMessage::Statement(gossip_statement) => gossip_statement, GossipMessage::Statement(gossip_statement) => gossip_statement,
_ => return Err(Box::new(ClientError::BadJustification( _ => {
"block announced justification statement must be a gossip statement".to_string() return Err(Box::new(ClientError::BadJustification(
)) as Box<_>) "block announced justification statement must be a gossip statement"
.to_string(),
)) as Box<_>)
}
}; };
let GossipStatement { let GossipStatement {
relay_chain_leaf, relay_chain_leaf,
signed_statement: SignedStatement { signed_statement: SignedStatement {
statement, statement,
signature, signature,
sender, sender,
} },
} = gossip_statement; } = gossip_statement;
// Check that the signer is a legit validator. // Check that the signer is a legit validator.
let signer = self.authorities.get(sender as usize) let signer = self.authorities.get(sender as usize).ok_or_else(|| {
.ok_or_else(|| Box::new(ClientError::BadJustification( Box::new(ClientError::BadJustification(
"block accounced justification signer is a validator index out of bound".to_string() "block accounced justification signer is a validator index out of bound"
)) as Box<_>)?; .to_string(),
)) as Box<_>
})?;
// Check statement is correctly signed. // Check statement is correctly signed.
if !check_statement( if !check_statement(&statement, &signature, signer.clone(), &relay_chain_leaf) {
&statement,
&signature,
signer.clone(),
&relay_chain_leaf,
) {
return Err(Box::new(ClientError::BadJustification( return Err(Box::new(ClientError::BadJustification(
"block announced justification signature is invalid".to_string() "block announced justification signature is invalid".to_string(),
)) as Box<_>) )) as Box<_>);
} }
// Check statement is a candidate statement. // Check statement is a candidate statement.
let candidate_receipt = match statement { let candidate_receipt = match statement {
Statement::Candidate(candidate_receipt) => candidate_receipt, Statement::Candidate(candidate_receipt) => candidate_receipt,
_ => return Err(Box::new(ClientError::BadJustification( _ => {
"block announced justification statement must be a candidate statement".to_string() return Err(Box::new(ClientError::BadJustification(
)) as Box<_>) "block announced justification statement must be a candidate statement"
.to_string(),
)) as Box<_>)
}
}; };
// Check the header in the candidate_receipt match header given header. // Check the header in the candidate_receipt match header given header.
if header.encode() != candidate_receipt.head_data.0 { if header.encode() != candidate_receipt.head_data.0 {
return Err(Box::new(ClientError::BadJustification( return Err(Box::new(ClientError::BadJustification(
"block announced header does not match the one justified".to_string() "block announced header does not match the one justified".to_string(),
)) as Box<_>) )) as Box<_>);
} }
Ok(Validation::Success) Ok(Validation::Success)
+18 -17
View File
@@ -7,40 +7,41 @@ edition = "2018"
[dependencies] [dependencies]
# Other dependencies # Other dependencies
codec = { package = "parity-scale-codec", version = "1.0.5", default-features = false, features = [ "derive" ] } codec = { package = "parity-scale-codec", version = "1.0.5", default-features = false, features = [ "derive" ] }
memory-db = { version = "0.15.2", default-features = false } memory-db = { version = "0.18.0", default-features = false }
hash-db = { version = "0.15.2", default-features = false } hash-db = { version = "0.15.2", default-features = false }
trie-db = { version = "0.15.2", default-features = false } trie-db = { version = "0.18.0", default-features = false }
hashbrown = "0.6.1" hashbrown = "0.6.1"
# Substrate dependencies # Substrate dependencies
rstd = { package = "sr-std", git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" } sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" }
runtime-primitives = { package = "sr-primitives", git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" } sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" }
primitives = { package = "substrate-primitives", git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" } sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" }
rio = { package = "sr-io", git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" } sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" }
executive = { package = "srml-executive", git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" } frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" }
substrate-trie = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" } sp-trie = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" }
# Polkadot dependencies # Polkadot dependencies
parachain = { package = "polkadot-parachain", git = "https://github.com/paritytech/polkadot", branch = "bkchr-cumulus-branch", default-features = false, features = [ "wasm-api" ] } parachain = { package = "polkadot-parachain", git = "https://github.com/paritytech/polkadot", branch = "bkchr-cumulus-branch", default-features = false, features = [ "wasm-api" ] }
[dev-dependencies] [dev-dependencies]
keyring = { package = "substrate-keyring", git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
executor = { package = "substrate-executor", git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
consensus-common = { package = "substrate-consensus-common", git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sc-executor = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
test-client = { package = "cumulus-test-client", path = "../test/client" } test-client = { package = "cumulus-test-client", path = "../test/client" }
[features] [features]
default = ["std"] default = ["std"]
std = [ std = [
"codec/std", "codec/std",
"rstd/std", "sp-std/std",
"rio/std", "sp-io/std",
"runtime-primitives/std", "sp-runtime/std",
"primitives/std", "sp-core/std",
"executive/std", "frame-executive/std",
"memory-db/std", "memory-db/std",
"hash-db/std", "hash-db/std",
"trie-db/std", "trie-db/std",
"substrate-trie/std", "sp-trie/std",
"parachain/std", "parachain/std",
] ]
+4 -5
View File
@@ -16,15 +16,14 @@
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
use codec::{Decode, Encode};
use sp_runtime::traits::Block as BlockT;
///! The Cumulus runtime to make a runtime a parachain. ///! The Cumulus runtime to make a runtime a parachain.
use sp_std::vec::Vec;
use rstd::vec::Vec;
use codec::{Encode, Decode};
use runtime_primitives::traits::Block as BlockT;
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
#[doc(hidden)] #[doc(hidden)]
pub use rstd::slice; pub use sp_std::slice;
#[macro_use] #[macro_use]
pub mod validate_block; pub mod validate_block;
@@ -17,23 +17,38 @@
//! The actual implementation of the validate block functionality. //! The actual implementation of the validate block functionality.
use crate::WitnessData; use crate::WitnessData;
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT}; use frame_executive::ExecuteBlock;
use executive::ExecuteBlock; use sp_runtime::traits::{Block as BlockT, HasherFor, Header as HeaderT};
use primitives::{Blake2Hasher, H256};
use substrate_trie::{MemoryDB, read_trie_value, delta_trie_root, Layout}; use sp_trie::{delta_trie_root, read_trie_value, Layout, MemoryDB};
use rstd::{slice, ptr, cmp, vec::Vec, boxed::Box, mem}; use sp_std::{boxed::Box, vec::Vec};
use hash_db::{HashDB, EMPTY_PREFIX}; use hash_db::{HashDB, EMPTY_PREFIX};
use trie_db::{Trie, TrieDB};
use parachain::{ValidationParams, ValidationResult}; use parachain::{ValidationParams, ValidationResult};
use codec::{Decode, Encode};
/// Stores the global [`Storage`] instance.
///
/// As wasm is always executed with one thread, this global varibale is safe!
static mut STORAGE: Option<Box<dyn Storage>> = None; static mut STORAGE: Option<Box<dyn Storage>> = None;
/// The message to use as expect message while accessing the `STORAGE`.
const STORAGE_SET_EXPECT: &str = /// Returns a mutable reference to the [`Storage`] implementation.
"`STORAGE` needs to be set before calling this function."; ///
const STORAGE_ROOT_LEN: usize = 32; /// # Panic
///
/// Panics if the [`STORAGE`] is not initialized.
fn storage() -> &'static mut dyn Storage {
unsafe {
&mut **STORAGE
.as_mut()
.expect("`STORAGE` needs to be set before calling this function.")
}
}
/// Abstract the storage into a trait without `Block` generic. /// Abstract the storage into a trait without `Block` generic.
trait Storage { trait Storage {
@@ -47,16 +62,17 @@ trait Storage {
fn remove(&mut self, key: &[u8]); fn remove(&mut self, key: &[u8]);
/// Calculate the storage root. /// Calculate the storage root.
fn storage_root(&mut self) -> [u8; STORAGE_ROOT_LEN]; ///
/// Returns the SCALE encoded hash.
fn storage_root(&mut self) -> Vec<u8>;
/// Clear all keys that start with the given prefix.
fn clear_prefix(&mut self, prefix: &[u8]);
} }
/// Validate a given parachain block on a validator. /// Validate a given parachain block on a validator.
#[doc(hidden)] #[doc(hidden)]
pub fn validate_block<B: BlockT<Hash = H256>, E: ExecuteBlock<B>>( pub fn validate_block<B: BlockT, E: ExecuteBlock<B>>(params: ValidationParams) -> ValidationResult {
params: ValidationParams,
) -> ValidationResult {
use codec::{Decode, Encode};
let block_data = crate::ParachainBlockData::<B>::decode(&mut &params.block_data[..]) let block_data = crate::ParachainBlockData::<B>::decode(&mut &params.block_data[..])
.expect("Invalid parachain block data"); .expect("Invalid parachain block data");
@@ -66,23 +82,28 @@ pub fn validate_block<B: BlockT<Hash = H256>, E: ExecuteBlock<B>>(
// TODO: Add `PolkadotInherent`. // TODO: Add `PolkadotInherent`.
let block = B::new(block_data.header, block_data.extrinsics); let block = B::new(block_data.header, block_data.extrinsics);
assert!(parent_head.hash() == *block.header().parent_hash(), "Invalid parent hash"); assert!(
parent_head.hash() == *block.header().parent_hash(),
"Invalid parent hash"
);
let storage = WitnessStorage::<B>::new( let storage = WitnessStorage::<B>::new(
block_data.witness_data, block_data.witness_data,
block_data.witness_data_storage_root, block_data.witness_data_storage_root,
).expect("Witness data and storage root always match; qed"); )
.expect("Witness data and storage root always match; qed");
let _guard = unsafe { let _guard = unsafe {
STORAGE = Some(Box::new(storage)); STORAGE = Some(Box::new(storage));
( (
// Replace storage calls with our own implementations // Replace storage calls with our own implementations
rio::ext_get_allocated_storage.replace_implementation(ext_get_allocated_storage), sp_io::storage::host_read.replace_implementation(host_storage_read),
rio::ext_get_storage_into.replace_implementation(ext_get_storage_into), sp_io::storage::host_set.replace_implementation(host_storage_set),
rio::ext_set_storage.replace_implementation(ext_set_storage), sp_io::storage::host_get.replace_implementation(host_storage_get),
rio::ext_exists_storage.replace_implementation(ext_exists_storage), sp_io::storage::host_exists.replace_implementation(host_storage_exists),
rio::ext_clear_storage.replace_implementation(ext_clear_storage), sp_io::storage::host_clear.replace_implementation(host_storage_clear),
rio::ext_storage_root.replace_implementation(ext_storage_root), sp_io::storage::host_root.replace_implementation(host_storage_root),
sp_io::storage::host_clear_prefix.replace_implementation(host_clear_prefix),
) )
}; };
@@ -94,24 +115,23 @@ pub fn validate_block<B: BlockT<Hash = H256>, E: ExecuteBlock<B>>(
/// The storage implementation used when validating a block that is using the /// The storage implementation used when validating a block that is using the
/// witness data as source. /// witness data as source.
struct WitnessStorage<B: BlockT> { struct WitnessStorage<B: BlockT> {
witness_data: MemoryDB<Blake2Hasher>, witness_data: MemoryDB<HasherFor<B>>,
overlay: hashbrown::HashMap<Vec<u8>, Option<Vec<u8>>>, overlay: hashbrown::HashMap<Vec<u8>, Option<Vec<u8>>>,
storage_root: B::Hash, storage_root: B::Hash,
} }
impl<B: BlockT<Hash = H256>> WitnessStorage<B> { impl<B: BlockT> WitnessStorage<B> {
/// Initialize from the given witness data and storage root. /// Initialize from the given witness data and storage root.
/// ///
/// Returns an error if given storage root was not found in the witness data. /// Returns an error if given storage root was not found in the witness data.
fn new( fn new(data: WitnessData, storage_root: B::Hash) -> Result<Self, &'static str> {
data: WitnessData,
storage_root: B::Hash,
) -> Result<Self, &'static str> {
let mut db = MemoryDB::default(); let mut db = MemoryDB::default();
data.into_iter().for_each(|i| { db.insert(EMPTY_PREFIX, &i); }); data.into_iter().for_each(|i| {
db.insert(EMPTY_PREFIX, &i);
});
if !db.contains(&storage_root, EMPTY_PREFIX) { if !HashDB::contains(&db, &storage_root, EMPTY_PREFIX) {
return Err("Witness data does not contain given storage root.") return Err("Witness data does not contain given storage root.");
} }
Ok(Self { Ok(Self {
@@ -122,15 +142,36 @@ impl<B: BlockT<Hash = H256>> WitnessStorage<B> {
} }
} }
impl<B: BlockT<Hash = H256>> Storage for WitnessStorage<B> { /// TODO: `TrieError` should implement `Debug` on `no_std`
fn unwrap_trie_error<R, T, E>(result: Result<R, Box<trie_db::TrieError<T, E>>>) -> R {
match result {
Ok(r) => r,
Err(error) => match *error {
trie_db::TrieError::InvalidStateRoot(_) => panic!("trie_db: Invalid state root"),
trie_db::TrieError::IncompleteDatabase(_) => panic!("trie_db: IncompleteDatabase"),
trie_db::TrieError::DecoderError(_, _) => panic!("trie_db: DecodeError"),
trie_db::TrieError::InvalidHash(_, _) => panic!("trie_db: InvalidHash"),
trie_db::TrieError::ValueAtIncompleteKey(_, _) => {
panic!("trie_db: ValueAtIncompleteKey")
}
},
}
}
impl<B: BlockT> Storage for WitnessStorage<B> {
fn get(&self, key: &[u8]) -> Option<Vec<u8>> { fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
self.overlay.get(key).cloned().or_else(|| { self.overlay
read_trie_value::<Layout<Blake2Hasher>, _>( .get(key)
&self.witness_data, .cloned()
&self.storage_root, .or_else(|| {
key, read_trie_value::<Layout<HasherFor<B>>, _>(
).ok() &self.witness_data,
}).unwrap_or(None) &self.storage_root,
key,
)
.ok()
})
.unwrap_or(None)
} }
fn insert(&mut self, key: &[u8], value: &[u8]) { fn insert(&mut self, key: &[u8], value: &[u8]) {
@@ -141,98 +182,77 @@ impl<B: BlockT<Hash = H256>> Storage for WitnessStorage<B> {
self.overlay.insert(key.to_vec(), None); self.overlay.insert(key.to_vec(), None);
} }
fn storage_root(&mut self) -> [u8; STORAGE_ROOT_LEN] { fn storage_root(&mut self) -> Vec<u8> {
let root = match delta_trie_root::<Layout<Blake2Hasher>, _, _, _, _>( let root = unwrap_trie_error(delta_trie_root::<Layout<HasherFor<B>>, _, _, _, _>(
&mut self.witness_data, &mut self.witness_data,
self.storage_root.clone(), self.storage_root.clone(),
self.overlay.drain(), self.overlay.drain(),
) { ));
Ok(root) => root,
Err(e) => match *e { root.encode()
trie_db::TrieError::InvalidStateRoot(_) => panic!("Invalid state root"), }
trie_db::TrieError::IncompleteDatabase(_) => panic!("IncompleteDatabase"),
trie_db::TrieError::DecoderError(_, _) => panic!("DecodeError"), fn clear_prefix(&mut self, prefix: &[u8]) {
self.overlay.iter_mut().for_each(|(k, v)| {
if k.starts_with(prefix) {
*v = None;
} }
});
let trie = match TrieDB::<Layout<HasherFor<B>>>::new(&self.witness_data, &self.storage_root)
{
Ok(r) => r,
Err(_) => panic!(),
}; };
root.into() let mut iter = unwrap_trie_error(trie.iter());
} unwrap_trie_error(iter.seek(prefix));
}
unsafe fn ext_get_allocated_storage( for x in iter {
key_data: *const u8, let (key, _) = unwrap_trie_error(x);
key_len: u32,
written_out: *mut u32, if !key.starts_with(prefix) {
) -> *mut u8 { break;
let key = slice::from_raw_parts(key_data, key_len as usize); }
match STORAGE.as_mut().expect(STORAGE_SET_EXPECT).get(key) {
Some(value) => { self.overlay.insert(key, None);
let mut out_value: Vec<_> = value.clone();
*written_out = out_value.len() as u32;
let ptr = out_value.as_mut_ptr();
mem::forget(out_value);
ptr
},
None => {
*written_out = u32::max_value();
ptr::null_mut()
} }
} }
} }
unsafe fn ext_set_storage( fn host_storage_read(key: &[u8], value_out: &mut [u8], value_offset: u32) -> Option<u32> {
key_data: *const u8, match storage().get(key) {
key_len: u32,
value_data: *const u8,
value_len: u32,
) {
let key = slice::from_raw_parts(key_data, key_len as usize);
let value = slice::from_raw_parts(value_data, value_len as usize);
STORAGE.as_mut().expect(STORAGE_SET_EXPECT).insert(key, value);
}
unsafe fn ext_get_storage_into(
key_data: *const u8,
key_len: u32,
value_data: *mut u8,
value_len: u32,
value_offset: u32,
) -> u32 {
let key = slice::from_raw_parts(key_data, key_len as usize);
let out_value = slice::from_raw_parts_mut(value_data, value_len as usize);
match STORAGE.as_mut().expect(STORAGE_SET_EXPECT).get(key) {
Some(value) => { Some(value) => {
let value = &value[value_offset as usize..]; let value_offset = value_offset as usize;
let len = cmp::min(value_len as usize, value.len()); let data = &value[value_offset.min(value.len())..];
out_value[..len].copy_from_slice(&value[..len]); let written = sp_std::cmp::min(data.len(), value_out.len());
len as u32 value_out[..written].copy_from_slice(&data[..written]);
}, Some(value.len() as u32)
None => {
u32::max_value()
} }
None => None,
} }
} }
unsafe fn ext_exists_storage(key_data: *const u8, key_len: u32) -> u32 { fn host_storage_set(key: &[u8], value: &[u8]) {
let key = slice::from_raw_parts(key_data, key_len as usize); storage().insert(key, value);
if STORAGE.as_mut().expect(STORAGE_SET_EXPECT).get(key).is_some() {
1
} else {
0
}
} }
unsafe fn ext_clear_storage(key_data: *const u8, key_len: u32) { fn host_storage_get(key: &[u8]) -> Option<Vec<u8>> {
let key = slice::from_raw_parts(key_data, key_len as usize); storage().get(key).clone()
STORAGE.as_mut().expect(STORAGE_SET_EXPECT).remove(key);
} }
unsafe fn ext_storage_root(result: *mut u8) { fn host_storage_exists(key: &[u8]) -> bool {
let res = STORAGE.as_mut().expect(STORAGE_SET_EXPECT).storage_root(); storage().get(key).is_some()
let result = slice::from_raw_parts_mut(result, STORAGE_ROOT_LEN); }
result.copy_from_slice(&res);
fn host_storage_clear(key: &[u8]) {
storage().remove(key);
}
fn host_storage_root() -> Vec<u8> {
storage().storage_root()
}
fn host_clear_prefix(prefix: &[u8]) {
storage().clear_prefix(prefix)
} }
+8 -12
View File
@@ -16,11 +16,11 @@
//! A module that enables a runtime to work as parachain. //! A module that enables a runtime to work as parachain.
#[cfg(test)]
mod tests;
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
#[doc(hidden)] #[doc(hidden)]
pub mod implementation; pub mod implementation;
#[cfg(test)]
mod tests;
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
#[doc(hidden)] #[doc(hidden)]
@@ -60,20 +60,16 @@ macro_rules! register_validate_block_impl {
use super::*; use super::*;
#[no_mangle] #[no_mangle]
unsafe fn validate_block( unsafe fn validate_block(arguments: *const u8, arguments_len: usize) -> u64 {
arguments: *const u8, let params =
arguments_len: usize, $crate::validate_block::parachain::load_params(arguments, arguments_len);
) -> u64 {
let params = $crate::validate_block::parachain::wasm_api::load_params(
arguments,
arguments_len,
);
let res = $crate::validate_block::implementation::validate_block::< let res = $crate::validate_block::implementation::validate_block::<
$block, $block_executor $block,
$block_executor,
>(params); >(params);
$crate::validate_block::parachain::wasm_api::write_result(res) $crate::validate_block::parachain::write_result(&res)
} }
} }
}; };
+51 -35
View File
@@ -16,18 +16,22 @@
use crate::{ParachainBlockData, WitnessData}; use crate::{ParachainBlockData, WitnessData};
use rio::TestExternalities;
use keyring::AccountKeyring;
use runtime_primitives::{generic::BlockId, traits::{Block as BlockT, Header as HeaderT}};
use executor::{call_in_wasm, error::Result, WasmExecutionMethod};
use test_client::{
TestClientBuilder, TestClientBuilderExt, DefaultTestClientBuilderExt, Client, LongestChain,
runtime::{Block, Transfer, Hash, WASM_BINARY, Header}
};
use consensus_common::SelectChain;
use parachain::{ValidationParams, ValidationResult}; use parachain::{ValidationParams, ValidationResult};
use sc_executor::{call_in_wasm, error::Result, WasmExecutionMethod};
use sp_blockchain::HeaderBackend;
use sp_consensus::SelectChain;
use sp_io::TestExternalities;
use sp_keyring::AccountKeyring;
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, Header as HeaderT},
};
use test_client::{
runtime::{Block, Hash, Header, Transfer, WASM_BINARY},
Client, DefaultTestClientBuilderExt, LongestChain, TestClientBuilder, TestClientBuilderExt,
};
use codec::{Encode, Decode}; use codec::{Decode, Encode};
fn call_validate_block( fn call_validate_block(
parent_head: Header, parent_head: Header,
@@ -39,9 +43,16 @@ fn call_validate_block(
block_data: block_data.encode(), block_data: block_data.encode(),
parent_head: parent_head.encode(), parent_head: parent_head.encode(),
ingress: Vec::new(), ingress: Vec::new(),
}.encode(); }
.encode();
call_in_wasm( call_in_wasm::<
_,
(
sp_io::SubstrateHostFunctions,
sc_executor::deprecated_host_interface::SubstrateExternals,
),
>(
"validate_block", "validate_block",
&params, &params,
WasmExecutionMethod::Interpreted, WasmExecutionMethod::Interpreted,
@@ -60,25 +71,29 @@ fn create_extrinsics() -> Vec<<Block as BlockT>::Extrinsic> {
to: AccountKeyring::Bob.into(), to: AccountKeyring::Bob.into(),
amount: 69, amount: 69,
nonce: 0, nonce: 0,
}.into_signed_tx(), }
.into_signed_tx(),
Transfer { Transfer {
from: AccountKeyring::Alice.into(), from: AccountKeyring::Alice.into(),
to: AccountKeyring::Charlie.into(), to: AccountKeyring::Charlie.into(),
amount: 100, amount: 100,
nonce: 1, nonce: 1,
}.into_signed_tx(), }
.into_signed_tx(),
Transfer { Transfer {
from: AccountKeyring::Bob.into(), from: AccountKeyring::Bob.into(),
to: AccountKeyring::Charlie.into(), to: AccountKeyring::Charlie.into(),
amount: 100, amount: 100,
nonce: 0, nonce: 0,
}.into_signed_tx(), }
.into_signed_tx(),
Transfer { Transfer {
from: AccountKeyring::Charlie.into(), from: AccountKeyring::Charlie.into(),
to: AccountKeyring::Alice.into(), to: AccountKeyring::Alice.into(),
amount: 500, amount: 500,
nonce: 0, nonce: 0,
}.into_signed_tx(), }
.into_signed_tx(),
] ]
} }
@@ -90,20 +105,25 @@ fn build_block_with_proof(
client: &Client, client: &Client,
extrinsics: Vec<<Block as BlockT>::Extrinsic>, extrinsics: Vec<<Block as BlockT>::Extrinsic>,
) -> (Block, WitnessData) { ) -> (Block, WitnessData) {
let block_id = BlockId::Hash(client.info().chain.best_hash); let block_id = BlockId::Hash(client.info().best_hash);
let mut builder = client.new_block_at( let mut builder = client
&block_id, .new_block_at(&block_id, Default::default(), true)
Default::default(), .expect("Initializes new block");
true,
).expect("Initializes new block");
extrinsics.into_iter().for_each(|e| builder.push(e).expect("Pushes an extrinsic")); extrinsics
.into_iter()
.for_each(|e| builder.push(e).expect("Pushes an extrinsic"));
let (block, proof) = builder let built_block = builder.build().expect("Creates block");
.bake_and_extract_proof()
.expect("Finalizes block");
(block, proof.expect("We enabled proof recording before.")) (
built_block.block,
built_block
.proof
.expect("We enabled proof recording before.")
.iter_nodes()
.collect(),
)
} }
#[test] #[test]
@@ -118,7 +138,7 @@ fn validate_block_with_no_extrinsics() {
header.clone(), header.clone(),
extrinsics, extrinsics,
witness_data, witness_data,
witness_data_storage_root witness_data_storage_root,
); );
let res_header = call_validate_block(parent_head, block_data).expect("Calls `validate_block`"); let res_header = call_validate_block(parent_head, block_data).expect("Calls `validate_block`");
@@ -137,7 +157,7 @@ fn validate_block_with_extrinsics() {
header.clone(), header.clone(),
extrinsics, extrinsics,
witness_data, witness_data,
witness_data_storage_root witness_data_storage_root,
); );
let res_header = call_validate_block(parent_head, block_data).expect("Calls `validate_block`"); let res_header = call_validate_block(parent_head, block_data).expect("Calls `validate_block`");
@@ -154,11 +174,7 @@ fn validate_block_invalid_parent_hash() {
let (mut header, extrinsics) = block.deconstruct(); let (mut header, extrinsics) = block.deconstruct();
header.set_parent_hash(Hash::from_low_u64_be(1)); header.set_parent_hash(Hash::from_low_u64_be(1));
let block_data = ParachainBlockData::new( let block_data =
header, ParachainBlockData::new(header, extrinsics, witness_data, witness_data_storage_root);
extrinsics,
witness_data,
witness_data_storage_root
);
call_validate_block(parent_head, block_data).expect("Calls `validate_block`"); call_validate_block(parent_head, block_data).expect("Calls `validate_block`");
} }
+3 -3
View File
@@ -7,8 +7,8 @@ edition = "2018"
[dependencies] [dependencies]
test-client = { package = "substrate-test-client", git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } test-client = { package = "substrate-test-client", git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
runtime = { package = "cumulus-test-runtime", path = "../runtime" } runtime = { package = "cumulus-test-runtime", path = "../runtime" }
runtime_primitives = { package = "sr-primitives", git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
primitives = { package = "substrate-primitives", git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
keyring = { package = "substrate-keyring", git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
codec = { package = "parity-scale-codec", version = "1.0.5", default-features = false, features = [ "derive" ] } codec = { package = "parity-scale-codec", version = "1.0.5", default-features = false, features = [ "derive" ] }
+27 -22
View File
@@ -16,15 +16,18 @@
//! A Cumulus test client. //! A Cumulus test client.
pub use test_client::*;
pub use runtime; pub use runtime;
use runtime::{Block, genesismap::{GenesisConfig, additional_storage_with_genesis}}; use runtime::{
use runtime_primitives::traits::{Hash as HashT, Header as HeaderT, Block as BlockT}; genesismap::{additional_storage_with_genesis, GenesisConfig},
use primitives::{storage::well_known_keys, sr25519}; Block,
use keyring::{Sr25519Keyring, AccountKeyring}; };
use sp_core::{sr25519, storage::Storage};
use sp_keyring::{AccountKeyring, Sr25519Keyring};
use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT};
pub use test_client::*;
mod local_executor { mod local_executor {
use test_client::executor::native_executor_instance; use test_client::sc_executor::native_executor_instance;
native_executor_instance!( native_executor_instance!(
pub LocalExecutor, pub LocalExecutor,
runtime::api::dispatch, runtime::api::dispatch,
@@ -39,16 +42,17 @@ pub use local_executor::LocalExecutor;
pub type Backend = test_client::Backend<Block>; pub type Backend = test_client::Backend<Block>;
/// Test client executor. /// Test client executor.
pub type Executor = client::LocalCallExecutor<Backend, executor::NativeExecutor<LocalExecutor>>; pub type Executor =
sc_client::LocalCallExecutor<Backend, sc_executor::NativeExecutor<LocalExecutor>>;
/// Test client builder for Cumulus /// Test client builder for Cumulus
pub type TestClientBuilder = test_client::TestClientBuilder<Executor, Backend, GenesisParameters>; pub type TestClientBuilder = test_client::TestClientBuilder<Executor, Backend, GenesisParameters>;
/// LongestChain type for the test runtime/client. /// LongestChain type for the test runtime/client.
pub type LongestChain = test_client::client::LongestChain<Backend, Block>; pub type LongestChain = test_client::sc_client::LongestChain<Backend, Block>;
/// Test client type with `LocalExecutor` and generic Backend. /// Test client type with `LocalExecutor` and generic Backend.
pub type Client = client::Client<Backend, Executor, Block, runtime::RuntimeApi>; pub type Client = sc_client::Client<Backend, Executor, Block, runtime::RuntimeApi>;
/// Parameters of test-client builder with test-runtime. /// Parameters of test-client builder with test-runtime.
#[derive(Default)] #[derive(Default)]
@@ -57,22 +61,24 @@ pub struct GenesisParameters {
} }
impl test_client::GenesisInit for GenesisParameters { impl test_client::GenesisInit for GenesisParameters {
fn genesis_storage(&self) -> (StorageOverlay, ChildrenStorageOverlay) { fn genesis_storage(&self) -> Storage {
use codec::Encode; use codec::Encode;
let mut storage = genesis_config(self.support_changes_trie).genesis_map();
storage.0.insert(well_known_keys::CODE.to_vec(), runtime::WASM_BINARY.to_vec());
let child_roots = storage.1.iter().map(|(sk, child_map)| { let mut storage = genesis_config(self.support_changes_trie).genesis_map();
let state_root = <<<runtime::Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
child_map.clone().into_iter().collect() let child_roots = storage.children.iter().map(|(sk, child_content)| {
); let state_root =
<<<runtime::Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
child_content.data.clone().into_iter().collect(),
);
(sk.clone(), state_root.encode()) (sk.clone(), state_root.encode())
}); });
let state_root = <<<runtime::Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root( let state_root =
storage.0.clone().into_iter().chain(child_roots).collect() <<<runtime::Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
); storage.top.clone().into_iter().chain(child_roots).collect(),
let block: runtime::Block = client::genesis::construct_genesis_block(state_root); );
storage.0.extend(additional_storage_with_genesis(&block)); let block: runtime::Block = sc_client::genesis::construct_genesis_block(state_root);
storage.top.extend(additional_storage_with_genesis(&block));
storage storage
} }
@@ -129,7 +135,6 @@ fn genesis_config(support_changes_trie: bool) -> GenesisConfig {
AccountKeyring::Charlie.into(), AccountKeyring::Charlie.into(),
], ],
1000, 1000,
None,
Default::default(), Default::default(),
Default::default(), Default::default(),
) )
+19 -16
View File
@@ -12,31 +12,33 @@ path = 'src/main.rs'
[dependencies] [dependencies]
derive_more = '0.15.0' derive_more = '0.15.0'
exit-future = '0.1.4' exit-future = '0.1.4'
futures = '0.1.29' futures = { version = "0.3.1", features = ["compat"] }
futures03 = { package = "futures-preview", version = "0.3.0-alpha.19", features = ["compat"] }
log = '0.4.8' log = '0.4.8'
parking_lot = '0.9.0' parking_lot = '0.9.0'
tokio = '0.1.22' tokio = '0.1.22'
trie-root = '0.15.2' trie-root = '0.15.2'
codec = { package = 'parity-scale-codec', version = '1.0.0' } codec = { package = 'parity-scale-codec', version = '1.0.0' }
parachain-runtime = { package = "cumulus-test-parachain-runtime", path = "runtime" }
structopt = "0.3.3" structopt = "0.3.3"
ctrlc = { version = "3.1.3", features = ["termination"] } ctrlc = { version = "3.1.3", features = ["termination"] }
# Parachain dependencies
parachain-runtime = { package = "cumulus-test-parachain-runtime", path = "runtime" }
# Substrate dependencies # Substrate dependencies
sr-primitives = { git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" } sp-runtime = { git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" }
sr-io = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sp-io = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
substrate-cli = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
substrate-primitives = { package = "substrate-primitives", git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
substrate-executor = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
substrate-service = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sc-cli = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
inherents = { package = "substrate-inherents", git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sc-executor = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
transaction-pool = { package = "substrate-transaction-pool", git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sc-service = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
network = { package = "substrate-network", git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sc-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
substrate-client = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
srml-timestamp = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sc-network = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
basic-authorship = { package = "substrate-basic-authorship", git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sc-client = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
consensus-common = { package = "substrate-consensus-common", git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" } sc-basic-authority = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "bkchr-cumulus-branch" }
# Cumulus dependencies # Cumulus dependencies
cumulus-consensus = { path = "../../consensus" } cumulus-consensus = { path = "../../consensus" }
@@ -45,6 +47,7 @@ cumulus-collator = { path = "../../collator" }
# Polkadot dependencies # Polkadot dependencies
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "bkchr-cumulus-branch" } polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "bkchr-cumulus-branch" }
polkadot-collator = { git = "https://github.com/paritytech/polkadot", branch = "bkchr-cumulus-branch" } polkadot-collator = { git = "https://github.com/paritytech/polkadot", branch = "bkchr-cumulus-branch" }
polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "bkchr-cumulus-branch" }
[build-dependencies] [build-dependencies]
vergen = '3.0.4' vergen = '3.0.4'
+7 -4
View File
@@ -16,7 +16,7 @@
use std::{env, path::PathBuf}; use std::{env, path::PathBuf};
use vergen::{ConstantsFlags, generate_cargo_keys}; use vergen::{generate_cargo_keys, ConstantsFlags};
const ERROR_MSG: &str = "Failed to generate metadata files"; const ERROR_MSG: &str = "Failed to generate metadata files";
@@ -24,13 +24,16 @@ fn main() {
generate_cargo_keys(ConstantsFlags::SHA_SHORT).expect(ERROR_MSG); generate_cargo_keys(ConstantsFlags::SHA_SHORT).expect(ERROR_MSG);
let mut manifest_dir = PathBuf::from( let mut manifest_dir = PathBuf::from(
env::var("CARGO_MANIFEST_DIR").expect("`CARGO_MANIFEST_DIR` is always set by cargo.") env::var("CARGO_MANIFEST_DIR").expect("`CARGO_MANIFEST_DIR` is always set by cargo."),
); );
while manifest_dir.parent().is_some() { while manifest_dir.parent().is_some() {
if manifest_dir.join(".git/HEAD").exists() { if manifest_dir.join(".git/HEAD").exists() {
println!("cargo:rerun-if-changed={}", manifest_dir.join(".git/HEAD").display()); println!(
return "cargo:rerun-if-changed={}",
manifest_dir.join(".git/HEAD").display()
);
return;
} }
manifest_dir.pop(); manifest_dir.pop();
File diff suppressed because one or more lines are too long
+41 -36
View File
@@ -6,27 +6,30 @@ edition = '2018'
[dependencies] [dependencies]
serde = { version = "1.0.101", optional = true, features = ["derive"] } serde = { version = "1.0.101", optional = true, features = ["derive"] }
safe-mix = { version = "1.0.0", default-features = false }
codec = { package = "parity-scale-codec", version = "1.0.6", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "1.0.6", default-features = false, features = ["derive"] }
# Substrate dependencies # Substrate dependencies
rstd = { package = "sr-std", git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" } sp-std = { git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" }
runtime-io = { package = "sr-io", git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" } sp-api = { git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" }
version = { package = "sr-version", git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" } sp-io = { git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" }
support = { package = "srml-support", git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" } sp-version = { git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" }
primitives = { package = "substrate-primitives", git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" } sp-runtime = { git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" }
substrate-session = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" } sp-core = { git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" }
balances = { package = "srml-balances", git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" } sp-session = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" }
executive = { package = "srml-executive", git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" } sp-offchain = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" }
indices = { package = "srml-indices", git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" } sp-block-builder = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" }
randomness-collective-flip = { package = "srml-randomness-collective-flip", git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" } sp-transaction-pool = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" }
system = { package = "srml-system", git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" } sp-inherents = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" }
timestamp = { package = "srml-timestamp", git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" }
sudo = { package = "srml-sudo", git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" } frame-support = { git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" }
sr-primitives = { git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" } frame-executive = { git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" }
client = { package = "substrate-client", git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" } frame-system = { git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" }
offchain-primitives = { package = "substrate-offchain-primitives", git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" } pallet-balances = { git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" }
transaction-payment = { package = "srml-transaction-payment", git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" } pallet-indices = { git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" }
pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" }
pallet-timestamp = { git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" }
pallet-sudo = { git = "https://github.com/paritytech/substrate", default_features = false, branch = "bkchr-cumulus-branch" }
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "bkchr-cumulus-branch" }
# Cumulus dependencies # Cumulus dependencies
cumulus-runtime = { path = "../../../runtime", default-features = false } cumulus-runtime = { path = "../../../runtime", default-features = false }
@@ -38,24 +41,26 @@ wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.
default = ['std'] default = ['std']
std = [ std = [
'codec/std', 'codec/std',
'client/std',
'rstd/std',
'runtime-io/std',
'support/std',
'balances/std',
'executive/std',
'indices/std',
'primitives/std',
'sr-primitives/std',
'randomness-collective-flip/std',
'system/std',
'timestamp/std',
'sudo/std',
'version/std',
'serde', 'serde',
'safe-mix/std', 'sp-api/std',
'offchain-primitives/std', 'sp-std/std',
'substrate-session/std', 'sp-io/std',
'sp-core/std',
'sp-runtime/std',
'sp-version/std',
'sp-offchain/std',
'sp-session/std',
'sp-block-builder/std',
'sp-transaction-pool/std',
'sp-inherents/std',
'frame-support/std',
'frame-executive/std',
'frame-system/std',
'pallet-balances/std',
'pallet-indices/std',
'pallet-randomness-collective-flip/std',
'pallet-timestamp/std',
'pallet-sudo/std',
'pallet-transaction-payment/std',
'cumulus-runtime/std', 'cumulus-runtime/std',
'transaction-payment/std',
] ]
+60 -50
View File
@@ -16,35 +16,35 @@
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
#![recursion_limit="256"] #![recursion_limit = "256"]
// Make the WASM binary available. // Make the WASM binary available.
#[cfg(feature = "std")] #[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
use rstd::prelude::*; use sp_api::impl_runtime_apis;
use primitives::OpaqueMetadata; use sp_core::OpaqueMetadata;
use sr_primitives::{ use sp_runtime::traits::{
ApplyResult, transaction_validity::TransactionValidity, generic, create_runtime_str, BlakeTwo256, Block as BlockT, ConvertInto, NumberFor, StaticLookup, Verify,
impl_opaque_keys, AnySignature
}; };
use sr_primitives::traits::{NumberFor, BlakeTwo256, Block as BlockT, StaticLookup, Verify, ConvertInto}; use sp_runtime::{
use sr_primitives::weights::Weight; create_runtime_str, generic, impl_opaque_keys, transaction_validity::TransactionValidity,
use client::{ AnySignature, ApplyExtrinsicResult,
block_builder::api::{CheckInherentsResult, InherentData, self as block_builder_api},
runtime_api as client_api, impl_runtime_apis
}; };
use version::RuntimeVersion; use sp_std::prelude::*;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use version::NativeVersion; use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
// A few exports that help ease life for downstream crates. // A few exports that help ease life for downstream crates.
pub use frame_support::{
construct_runtime, parameter_types, traits::Randomness, weights::Weight, StorageValue,
};
pub use pallet_balances::Call as BalancesCall;
pub use pallet_timestamp::Call as TimestampCall;
#[cfg(any(feature = "std", test))] #[cfg(any(feature = "std", test))]
pub use sr_primitives::BuildStorage; pub use sp_runtime::BuildStorage;
pub use timestamp::Call as TimestampCall; pub use sp_runtime::{Perbill, Permill};
pub use balances::Call as BalancesCall;
pub use sr_primitives::{Permill, Perbill};
pub use support::{StorageValue, construct_runtime, parameter_types, traits::Randomness};
/// An index to a block. /// An index to a block.
pub type BlockNumber = u32; pub type BlockNumber = u32;
@@ -67,7 +67,7 @@ pub type Balance = u128;
pub type Index = u32; pub type Index = u32;
/// A hash of some data used by the chain. /// A hash of some data used by the chain.
pub type Hash = primitives::H256; pub type Hash = sp_core::H256;
/// Digest item type. /// Digest item type.
pub type DigestItem = generic::DigestItem<Hash>; pub type DigestItem = generic::DigestItem<Hash>;
@@ -79,7 +79,7 @@ pub type DigestItem = generic::DigestItem<Hash>;
pub mod opaque { pub mod opaque {
use super::*; use super::*;
pub use sr_primitives::OpaqueExtrinsic as UncheckedExtrinsic; pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;
/// Opaque block header type. /// Opaque block header type.
pub type Header = generic::Header<BlockNumber, BlakeTwo256>; pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
@@ -136,7 +136,7 @@ parameter_types! {
pub const Version: RuntimeVersion = VERSION; pub const Version: RuntimeVersion = VERSION;
} }
impl system::Trait for Runtime { impl frame_system::Trait for Runtime {
/// The identifier used to distinguish between accounts. /// The identifier used to distinguish between accounts.
type AccountId = AccountId; type AccountId = AccountId;
/// The aggregated dispatch type that is available for extrinsics. /// The aggregated dispatch type that is available for extrinsics.
@@ -165,15 +165,18 @@ impl system::Trait for Runtime {
type MaximumBlockLength = MaximumBlockLength; type MaximumBlockLength = MaximumBlockLength;
/// Portion of the block weight that is available to all normal transactions. /// Portion of the block weight that is available to all normal transactions.
type AvailableBlockRatio = AvailableBlockRatio; type AvailableBlockRatio = AvailableBlockRatio;
/// Runtime version.
type Version = Version; type Version = Version;
/// Converts a module to an index of this module in the runtime.
type ModuleToIndex = ModuleToIndex;
} }
impl indices::Trait for Runtime { impl pallet_indices::Trait for Runtime {
/// The type for recording indexing into the account enumeration. If this ever overflows, there /// The type for recording indexing into the account enumeration. If this ever overflows, there
/// will be problems! /// will be problems!
type AccountIndex = u32; type AccountIndex = u32;
/// Use the standard means of resolving an index hint from an id. /// Use the standard means of resolving an index hint from an id.
type ResolveHint = indices::SimpleResolveHint<Self::AccountId, Self::AccountIndex>; type ResolveHint = pallet_indices::SimpleResolveHint<Self::AccountId, Self::AccountIndex>;
/// Determine whether an account is dead. /// Determine whether an account is dead.
type IsDeadAccount = Balances; type IsDeadAccount = Balances;
/// The ubiquitous event type. /// The ubiquitous event type.
@@ -184,7 +187,7 @@ parameter_types! {
pub const MinimumPeriod: u64 = SLOT_DURATION / 2; pub const MinimumPeriod: u64 = SLOT_DURATION / 2;
} }
impl timestamp::Trait for Runtime { impl pallet_timestamp::Trait for Runtime {
/// A timestamp: milliseconds since the unix epoch. /// A timestamp: milliseconds since the unix epoch.
type Moment = u64; type Moment = u64;
type OnTimestampSet = (); type OnTimestampSet = ();
@@ -199,7 +202,7 @@ parameter_types! {
pub const TransactionByteFee: u128 = 1; pub const TransactionByteFee: u128 = 1;
} }
impl balances::Trait for Runtime { impl pallet_balances::Trait for Runtime {
/// The type for recording an account's balance. /// The type for recording an account's balance.
type Balance = Balance; type Balance = Balance;
/// What to do if an account's free balance gets zeroed. /// What to do if an account's free balance gets zeroed.
@@ -215,7 +218,7 @@ impl balances::Trait for Runtime {
type CreationFee = CreationFee; type CreationFee = CreationFee;
} }
impl transaction_payment::Trait for Runtime { impl pallet_transaction_payment::Trait for Runtime {
type Currency = Balances; type Currency = Balances;
type OnTransactionPayment = (); type OnTransactionPayment = ();
type TransactionBaseFee = TransactionBaseFee; type TransactionBaseFee = TransactionBaseFee;
@@ -224,7 +227,7 @@ impl transaction_payment::Trait for Runtime {
type FeeMultiplierUpdate = (); type FeeMultiplierUpdate = ();
} }
impl sudo::Trait for Runtime { impl pallet_sudo::Trait for Runtime {
type Event = Event; type Event = Event;
type Proposal = Call; type Proposal = Call;
} }
@@ -235,12 +238,12 @@ construct_runtime! {
NodeBlock = opaque::Block, NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic UncheckedExtrinsic = UncheckedExtrinsic
{ {
System: system::{Module, Call, Storage, Config, Event}, System: frame_system::{Module, Call, Storage, Config, Event},
Timestamp: timestamp::{Module, Call, Storage, Inherent}, Timestamp: pallet_timestamp::{Module, Call, Storage, Inherent},
Indices: indices::{default, Config<T>}, Indices: pallet_indices,
Balances: balances::{default, Error}, Balances: pallet_balances,
Sudo: sudo, Sudo: pallet_sudo,
RandomnessCollectiveFlip: randomness_collective_flip::{Module, Call, Storage}, RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage},
} }
} }
@@ -256,22 +259,28 @@ pub type SignedBlock = generic::SignedBlock<Block>;
pub type BlockId = generic::BlockId<Block>; pub type BlockId = generic::BlockId<Block>;
/// The SignedExtension to the basic transaction logic. /// The SignedExtension to the basic transaction logic.
pub type SignedExtra = ( pub type SignedExtra = (
system::CheckVersion<Runtime>, frame_system::CheckVersion<Runtime>,
system::CheckGenesis<Runtime>, frame_system::CheckGenesis<Runtime>,
system::CheckEra<Runtime>, frame_system::CheckEra<Runtime>,
system::CheckNonce<Runtime>, frame_system::CheckNonce<Runtime>,
system::CheckWeight<Runtime>, frame_system::CheckWeight<Runtime>,
transaction_payment::ChargeTransactionPayment<Runtime>, pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
); );
/// Unchecked extrinsic type as expected by this runtime. /// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>; pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
/// Extrinsic type that has already been checked. /// Extrinsic type that has already been checked.
pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Call, SignedExtra>; pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Call, SignedExtra>;
/// Executive: handles dispatch to the various modules. /// Executive: handles dispatch to the various modules.
pub type Executive = executive::Executive<Runtime, Block, system::ChainContext<Runtime>, Runtime, AllModules>; pub type Executive = frame_executive::Executive<
Runtime,
Block,
frame_system::ChainContext<Runtime>,
Runtime,
AllModules,
>;
impl_runtime_apis! { impl_runtime_apis! {
impl client_api::Core<Block> for Runtime { impl sp_api::Core<Block> for Runtime {
fn version() -> RuntimeVersion { fn version() -> RuntimeVersion {
VERSION VERSION
} }
@@ -285,14 +294,16 @@ impl_runtime_apis! {
} }
} }
impl client_api::Metadata<Block> for Runtime { impl sp_api::Metadata<Block> for Runtime {
fn metadata() -> OpaqueMetadata { fn metadata() -> OpaqueMetadata {
Runtime::metadata().into() Runtime::metadata().into()
} }
} }
impl block_builder_api::BlockBuilder<Block> for Runtime { impl sp_block_builder::BlockBuilder<Block> for Runtime {
fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyResult { fn apply_extrinsic(
extrinsic: <Block as BlockT>::Extrinsic,
) -> ApplyExtrinsicResult {
Executive::apply_extrinsic(extrinsic) Executive::apply_extrinsic(extrinsic)
} }
@@ -300,11 +311,11 @@ impl_runtime_apis! {
Executive::finalize_block() Executive::finalize_block()
} }
fn inherent_extrinsics(data: InherentData) -> Vec<<Block as BlockT>::Extrinsic> { fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
data.create_extrinsics() data.create_extrinsics()
} }
fn check_inherents(block: Block, data: InherentData) -> CheckInherentsResult { fn check_inherents(block: Block, data: sp_inherents::InherentData) -> sp_inherents::CheckInherentsResult {
data.check_extrinsics(&block) data.check_extrinsics(&block)
} }
@@ -313,21 +324,20 @@ impl_runtime_apis! {
} }
} }
impl client_api::TaggedTransactionQueue<Block> for Runtime { impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
fn validate_transaction(tx: <Block as BlockT>::Extrinsic) -> TransactionValidity { fn validate_transaction(tx: <Block as BlockT>::Extrinsic) -> TransactionValidity {
Executive::validate_transaction(tx) Executive::validate_transaction(tx)
} }
} }
impl offchain_primitives::OffchainWorkerApi<Block> for Runtime { impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
fn offchain_worker(number: NumberFor<Block>) { fn offchain_worker(number: NumberFor<Block>) {
Executive::offchain_worker(number) Executive::offchain_worker(number)
} }
} }
impl substrate_session::SessionKeys<Block> for Runtime { impl sp_session::SessionKeys<Block> for Runtime {
fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> { fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
let seed = seed.as_ref().map(|s| rstd::str::from_utf8(&s).expect("Seed is an utf8 string"));
opaque::SessionKeys::generate(seed) opaque::SessionKeys::generate(seed)
} }
} }
+40 -33
View File
@@ -14,14 +14,14 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>. // along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
use substrate_primitives::{Pair, Public};
use parachain_runtime::{ use parachain_runtime::{
AccountId, BalancesConfig, GenesisConfig, SudoConfig, IndicesConfig, SystemConfig, WASM_BINARY, AccountId, BalancesConfig, GenesisConfig, IndicesConfig, SudoConfig, SystemConfig, WASM_BINARY,
}; };
use substrate_service; use sc_service;
use sp_core::{Pair, Public};
/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type. /// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.
pub type ChainSpec = substrate_service::ChainSpec<GenesisConfig>; pub type ChainSpec = sc_service::ChainSpec<GenesisConfig>;
/// Helper function to generate a crypto pair from seed /// Helper function to generate a crypto pair from seed
pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public { pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
@@ -32,7 +32,10 @@ pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Pu
/// Helper function to generate stash, controller and session key from seed /// Helper function to generate stash, controller and session key from seed
pub fn get_authority_keys_from_seed(seed: &str) -> (AccountId, AccountId) { pub fn get_authority_keys_from_seed(seed: &str) -> (AccountId, AccountId) {
(get_from_seed::<AccountId>(&format!("{}//stash", seed)), get_from_seed::<AccountId>(seed)) (
get_from_seed::<AccountId>(&format!("{}//stash", seed)),
get_from_seed::<AccountId>(seed),
)
} }
/// Returns the chain spec. /// Returns the chain spec.
@@ -40,28 +43,30 @@ pub fn get_chain_spec() -> ChainSpec {
ChainSpec::from_genesis( ChainSpec::from_genesis(
"Local Testnet", "Local Testnet",
"parachain_local_testnet", "parachain_local_testnet",
|| testnet_genesis( || {
vec![ testnet_genesis(
get_authority_keys_from_seed("Alice"), vec![
get_authority_keys_from_seed("Bob"), get_authority_keys_from_seed("Alice"),
], get_authority_keys_from_seed("Bob"),
get_from_seed::<AccountId>("Alice"), ],
vec![
get_from_seed::<AccountId>("Alice"), get_from_seed::<AccountId>("Alice"),
get_from_seed::<AccountId>("Bob"), vec![
get_from_seed::<AccountId>("Charlie"), get_from_seed::<AccountId>("Alice"),
get_from_seed::<AccountId>("Dave"), get_from_seed::<AccountId>("Bob"),
get_from_seed::<AccountId>("Eve"), get_from_seed::<AccountId>("Charlie"),
get_from_seed::<AccountId>("Ferdie"), get_from_seed::<AccountId>("Dave"),
get_from_seed::<AccountId>("Alice//stash"), get_from_seed::<AccountId>("Eve"),
get_from_seed::<AccountId>("Bob//stash"), get_from_seed::<AccountId>("Ferdie"),
get_from_seed::<AccountId>("Charlie//stash"), get_from_seed::<AccountId>("Alice//stash"),
get_from_seed::<AccountId>("Dave//stash"), get_from_seed::<AccountId>("Bob//stash"),
get_from_seed::<AccountId>("Eve//stash"), get_from_seed::<AccountId>("Charlie//stash"),
get_from_seed::<AccountId>("Ferdie//stash"), get_from_seed::<AccountId>("Dave//stash"),
], get_from_seed::<AccountId>("Eve//stash"),
true, get_from_seed::<AccountId>("Ferdie//stash"),
), ],
true,
)
},
vec![], vec![],
None, None,
None, None,
@@ -77,19 +82,21 @@ fn testnet_genesis(
_enable_println: bool, _enable_println: bool,
) -> GenesisConfig { ) -> GenesisConfig {
GenesisConfig { GenesisConfig {
system: Some(SystemConfig { frame_system: Some(SystemConfig {
code: WASM_BINARY.to_vec(), code: WASM_BINARY.to_vec(),
changes_trie_config: Default::default(), changes_trie_config: Default::default(),
}), }),
indices: Some(IndicesConfig { pallet_indices: Some(IndicesConfig {
ids: endowed_accounts.clone(), ids: endowed_accounts.clone(),
}), }),
balances: Some(BalancesConfig { pallet_balances: Some(BalancesConfig {
balances: endowed_accounts.iter().cloned().map(|k|(k, 1 << 60)).collect(), balances: endowed_accounts
.iter()
.cloned()
.map(|k| (k, 1 << 60))
.collect(),
vesting: vec![], vesting: vec![],
}), }),
sudo: Some(SudoConfig { pallet_sudo: Some(SudoConfig { key: root_key }),
key: root_key,
}),
} }
} }
+93 -50
View File
@@ -18,23 +18,29 @@ use crate::chain_spec;
use parachain_runtime::Block; use parachain_runtime::Block;
pub use substrate_cli::{VersionInfo, IntoExit, error::{self, Result}}; pub use sc_cli::{
use substrate_cli::{parse_and_prepare, ParseAndPrepare, NoCustom}; error::{self, Result},
use substrate_service::{Roles as ServiceRoles, Configuration}; IntoExit, VersionInfo,
use sr_primitives::{traits::{Block as BlockT, Header as HeaderT, Hash as HashT}, BuildStorage}; };
use substrate_client::genesis; use sc_cli::{parse_and_prepare, NoCustom, ParseAndPrepare};
use substrate_primitives::hexdisplay::HexDisplay; use sc_client::genesis;
use sc_service::{Configuration, Roles as ServiceRoles};
use sp_core::hexdisplay::HexDisplay;
use sp_runtime::{
traits::{Block as BlockT, Hash as HashT, Header as HeaderT},
BuildStorage,
};
use futures::{channel::oneshot, future::Map, FutureExt};
use codec::Encode; use codec::Encode;
use log::info; use log::info;
use std::{path::PathBuf, cell::RefCell, sync::Arc}; use std::{cell::RefCell, path::PathBuf, sync::Arc};
use structopt::StructOpt; use structopt::StructOpt;
use futures::{sync::oneshot, future, Future};
/// Sub-commands supported by the collator. /// Sub-commands supported by the collator.
#[derive(Debug, StructOpt, Clone)] #[derive(Debug, StructOpt, Clone)]
enum SubCommands { enum SubCommands {
@@ -43,8 +49,10 @@ enum SubCommands {
ExportGenesisState(ExportGenesisStateCommand), ExportGenesisState(ExportGenesisStateCommand),
} }
impl substrate_cli::GetLogFilter for SubCommands { impl sc_cli::GetSharedParams for SubCommands {
fn get_log_filter(&self) -> Option<String> { None } fn shared_params(&self) -> Option<&sc_cli::SharedParams> {
None
}
} }
/// Command for exporting the genesis state of the parachain /// Command for exporting the genesis state of the parachain
@@ -57,10 +65,10 @@ struct ExportGenesisStateCommand {
/// Parse command line arguments into service configuration. /// Parse command line arguments into service configuration.
pub fn run<I, T, E>(args: I, exit: E, version: VersionInfo) -> error::Result<()> pub fn run<I, T, E>(args: I, exit: E, version: VersionInfo) -> error::Result<()>
where where
I: IntoIterator<Item = T>, I: IntoIterator<Item = T>,
T: Into<std::ffi::OsString> + Clone, T: Into<std::ffi::OsString> + Clone,
E: IntoExit + Send + 'static, E: IntoExit + Send + 'static,
{ {
type Config<T> = Configuration<(), T>; type Config<T> = Configuration<(), T>;
match parse_and_prepare::<SubCommands, NoCustom, _>( match parse_and_prepare::<SubCommands, NoCustom, _>(
@@ -68,37 +76,68 @@ pub fn run<I, T, E>(args: I, exit: E, version: VersionInfo) -> error::Result<()>
"cumulus-test-parachain-collator", "cumulus-test-parachain-collator",
args, args,
) { ) {
ParseAndPrepare::Run(cmd) => cmd.run(load_spec, exit, ParseAndPrepare::Run(cmd) => cmd.run(
|exit, _cli_args, _custom_args, mut config: Config<_>| { load_spec,
info!("{}", version.name); exit,
info!(" version {}", config.full_version()); |exit, _cli_args, _custom_args, mut config: Config<_>| {
info!(" by {}, 2019", version.author); info!("{}", version.name);
info!("Chain specification: {}", config.chain_spec.name()); info!(" version {}", config.full_version());
info!("Node name: {}", config.name); info!(" by {}, 2019", version.author);
info!("Roles: {:?}", config.roles); info!("Chain specification: {}", config.chain_spec.name());
info!("Parachain id: {:?}", crate::PARA_ID); info!("Node name: {}", config.name);
info!("Roles: {:?}", config.roles);
info!("Parachain id: {:?}", crate::PARA_ID);
// TODO // TODO
let key = Arc::new(substrate_primitives::Pair::from_seed(&[10; 32])); let key = Arc::new(sp_core::Pair::from_seed(&[10; 32]));
// TODO // TODO
config.network.listen_addresses = Vec::new(); config.network.listen_addresses = Vec::new();
config.network.boot_nodes = vec![];
config.chain_spec = chain_spec::get_chain_spec();
match config.roles { // TODO
ServiceRoles::LIGHT => unimplemented!("Light client not supported!"), let mut polkadot_config =
_ => crate::service::run_collator(config, exit, key, version.clone()), polkadot_collator::Configuration::default_with_spec_and_base_path(
}.map_err(|e| format!("{:?}", e)) polkadot_service::ChainSpec::from_json_bytes(
}), &include_bytes!("../res/polkadot_chainspec.json")[..],
ParseAndPrepare::BuildSpec(cmd) => cmd.run(load_spec), )?,
ParseAndPrepare::ExportBlocks(cmd) => cmd.run_with_builder(|config: Config<_>| config.in_chain_config_dir("polkadot"),
Ok(new_full_start!(config).0), load_spec, exit), );
ParseAndPrepare::ImportBlocks(cmd) => cmd.run_with_builder(|config: Config<_>| polkadot_config.network.boot_nodes = config.network.boot_nodes.clone();
Ok(new_full_start!(config).0), load_spec, exit),
if let Some(ref config_dir) = polkadot_config.config_dir {
polkadot_config.database = sc_service::config::DatabaseConfig::Path {
cache_size: Default::default(),
path: config_dir.join("db"),
};
}
match config.roles {
ServiceRoles::LIGHT => unimplemented!("Light client not supported!"),
_ => crate::service::run_collator(config, exit, key, polkadot_config),
}
.map_err(|e| format!("{:?}", e))
},
),
ParseAndPrepare::BuildSpec(cmd) => cmd.run::<NoCustom, _, _, _>(load_spec),
ParseAndPrepare::ExportBlocks(cmd) => cmd.run_with_builder(
|config: Config<_>| Ok(new_full_start!(config).0),
load_spec,
exit,
),
ParseAndPrepare::ImportBlocks(cmd) => cmd.run_with_builder(
|config: Config<_>| Ok(new_full_start!(config).0),
load_spec,
exit,
),
ParseAndPrepare::CheckBlock(cmd) => cmd.run_with_builder(
|config: Config<_>| Ok(new_full_start!(config).0),
load_spec,
exit,
),
ParseAndPrepare::PurgeChain(cmd) => cmd.run(load_spec), ParseAndPrepare::PurgeChain(cmd) => cmd.run(load_spec),
ParseAndPrepare::RevertChain(cmd) => cmd.run_with_builder(|config: Config<_>| ParseAndPrepare::RevertChain(cmd) => {
Ok(new_full_start!(config).0), load_spec), cmd.run_with_builder(|config: Config<_>| Ok(new_full_start!(config).0), load_spec)
}
ParseAndPrepare::CustomCommand(SubCommands::ExportGenesisState(cmd)) => { ParseAndPrepare::CustomCommand(SubCommands::ExportGenesisState(cmd)) => {
export_genesis_state(cmd.output) export_genesis_state(cmd.output)
} }
@@ -113,16 +152,16 @@ fn load_spec(_: &str) -> std::result::Result<Option<chain_spec::ChainSpec>, Stri
/// Export the genesis state of the parachain. /// Export the genesis state of the parachain.
fn export_genesis_state(output: Option<PathBuf>) -> error::Result<()> { fn export_genesis_state(output: Option<PathBuf>) -> error::Result<()> {
let storage = chain_spec::get_chain_spec().build_storage()?; let storage = (&chain_spec::get_chain_spec()).build_storage()?;
let child_roots = storage.1.iter().map(|(sk, child_map)| { let child_roots = storage.children.iter().map(|(sk, child_content)| {
let state_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root( let state_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
child_map.clone().into_iter().collect() child_content.data.clone().into_iter().collect(),
); );
(sk.clone(), state_root.encode()) (sk.clone(), state_root.encode())
}); });
let state_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root( let state_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
storage.0.clone().into_iter().chain(child_roots).collect() storage.top.clone().into_iter().chain(child_roots).collect(),
); );
let block: Block = genesis::construct_genesis_block(state_root); let block: Block = genesis::construct_genesis_block(state_root);
@@ -140,19 +179,23 @@ fn export_genesis_state(output: Option<PathBuf>) -> error::Result<()> {
// handles ctrl-c // handles ctrl-c
pub struct Exit; pub struct Exit;
impl IntoExit for Exit { impl IntoExit for Exit {
type Exit = future::MapErr<oneshot::Receiver<()>, fn(oneshot::Canceled) -> ()>; type Exit = Map<oneshot::Receiver<()>, fn(std::result::Result<(), oneshot::Canceled>) -> ()>;
fn into_exit(self) -> Self::Exit { fn into_exit(self) -> Self::Exit {
// can't use signal directly here because CtrlC takes only `Fn`. // can't use signal directly here because CtrlC takes only `Fn`.
let (exit_send, exit) = oneshot::channel(); let (exit_send, exit) = oneshot::channel();
let exit_send_cell = RefCell::new(Some(exit_send)); let exit_send_cell = RefCell::new(Some(exit_send));
ctrlc::set_handler(move || { ctrlc::set_handler(move || {
let exit_send = exit_send_cell.try_borrow_mut().expect("signal handler not reentrant; qed").take(); let exit_send = exit_send_cell
.try_borrow_mut()
.expect("signal handler not reentrant; qed")
.take();
if let Some(exit_send) = exit_send { if let Some(exit_send) = exit_send {
exit_send.send(()).expect("Error sending exit notification"); exit_send.send(()).expect("Error sending exit notification");
} }
}).expect("Error setting Ctrl-C handler"); })
.expect("Error setting Ctrl-C handler");
exit.map_err(drop) exit.map(drop)
} }
} }
+1 -1
View File
@@ -26,7 +26,7 @@ mod chain_spec;
mod service; mod service;
mod cli; mod cli;
pub use substrate_cli::{VersionInfo, IntoExit, error}; pub use sc_cli::{error, IntoExit, VersionInfo};
/// The parachain id of this parachain. /// The parachain id of this parachain.
pub const PARA_ID: ParaId = ParaId::new(100); pub const PARA_ID: ParaId = ParaId::new(100);
+97 -59
View File
@@ -16,20 +16,19 @@
use std::sync::Arc; use std::sync::Arc;
use parachain_runtime::{self, GenesisConfig, opaque::Block}; use parachain_runtime::{self, opaque::Block, GenesisConfig};
use inherents::InherentDataProviders; use sc_executor::native_executor_instance;
use substrate_service::{AbstractService, Configuration}; use sc_network::construct_simple_protocol;
use network::construct_simple_protocol; use sc_service::{AbstractService, Configuration};
use substrate_executor::native_executor_instance; use sp_consensus::{BlockImport, Environment, Proposer};
use sp_inherents::InherentDataProviders;
use futures::prelude::*; use futures::{compat::Future01CompatExt, future, task::Spawn, FutureExt, TryFutureExt};
use futures03::FutureExt;
use log::error; use log::error;
pub use substrate_executor::NativeExecutor; pub use sc_executor::NativeExecutor;
// Our native executor instance. // Our native executor instance.
native_executor_instance!( native_executor_instance!(
@@ -49,29 +48,35 @@ construct_simple_protocol! {
/// be able to perform chain operations. /// be able to perform chain operations.
macro_rules! new_full_start { macro_rules! new_full_start {
($config:expr) => {{ ($config:expr) => {{
let inherent_data_providers = inherents::InherentDataProviders::new(); let inherent_data_providers = sp_inherents::InherentDataProviders::new();
let builder = substrate_service::ServiceBuilder::new_full::< let builder = sc_service::ServiceBuilder::new_full::<
parachain_runtime::opaque::Block, parachain_runtime::RuntimeApi, crate::service::Executor, parachain_runtime::opaque::Block,
parachain_runtime::RuntimeApi,
crate::service::Executor,
>($config)? >($config)?
.with_select_chain(|_config, backend| { .with_select_chain(|_config, backend| Ok(sc_client::LongestChain::new(backend.clone())))?
Ok(substrate_client::LongestChain::new(backend.clone())) .with_transaction_pool(|config, client, _| {
})? let pool_api = sc_transaction_pool::FullChainApi::new(client.clone());
.with_transaction_pool(|config, client| let pool = sc_transaction_pool::BasicPool::new(config, pool_api);
Ok(transaction_pool::txpool::Pool::new(config, transaction_pool::FullChainApi::new(client))) let maintainer =
)? sc_transaction_pool::FullBasicPoolMaintainer::new(pool.pool().clone(), client);
.with_import_queue(|_config, client, _, _| { let maintainable_pool =
let import_queue = cumulus_consensus::import_queue::import_queue( sp_transaction_pool::MaintainableTransactionPool::new(pool, maintainer);
client.clone(), Ok(maintainable_pool)
client, })?
inherent_data_providers.clone(), .with_import_queue(|_config, client, _, _| {
)?; let import_queue = cumulus_consensus::import_queue::import_queue(
client.clone(),
client,
inherent_data_providers.clone(),
)?;
Ok(import_queue) Ok(import_queue)
})?; })?;
(builder, inherent_data_providers) (builder, inherent_data_providers)
}} }};
} }
/// Run the collator with the given `config`. /// Run the collator with the given `config`.
@@ -79,13 +84,17 @@ pub fn run_collator<C: Send + Default + 'static, E: crate::cli::IntoExit + Send
config: Configuration<C, GenesisConfig>, config: Configuration<C, GenesisConfig>,
exit: E, exit: E,
key: Arc<polkadot_primitives::parachain::CollatorPair>, key: Arc<polkadot_primitives::parachain::CollatorPair>,
version: crate::cli::VersionInfo, polkadot_config: polkadot_collator::Configuration,
) -> crate::cli::Result<()> { ) -> crate::cli::Result<()> {
let (builder, inherent_data_providers) = new_full_start!(config); let (builder, inherent_data_providers) = new_full_start!(config);
inherent_data_providers.register_provider(srml_timestamp::InherentDataProvider).unwrap(); inherent_data_providers
.register_provider(sp_timestamp::InherentDataProvider)
.unwrap();
let service = builder.with_network_protocol(|_| Ok(NodeProtocol::new()))?.build()?; let service = builder
let proposer_factory = basic_authorship::ProposerFactory { .with_network_protocol(|_| Ok(NodeProtocol::new()))?
.build()?;
let proposer_factory = sc_basic_authority::ProposerFactory {
client: service.client(), client: service.client(),
transaction_pool: service.transaction_pool(), transaction_pool: service.transaction_pool(),
}; };
@@ -101,7 +110,13 @@ pub fn run_collator<C: Send + Default + 'static, E: crate::cli::IntoExit + Send
block_import, block_import,
}; };
cumulus_collator::run_collator(setup_parachain, crate::PARA_ID, on_exit, key, version) cumulus_collator::run_collator(
setup_parachain,
crate::PARA_ID,
on_exit,
key,
polkadot_config,
)
} }
struct SetupParachain<S, PF, E, BI> { struct SetupParachain<S, PF, E, BI> {
@@ -112,43 +127,66 @@ struct SetupParachain<S, PF, E, BI> {
block_import: BI, block_import: BI,
} }
type TransactionFor<E, Block> =
<<E as Environment<Block>>::Proposer as Proposer<Block>>::Transaction;
impl<S, PF, E, BI> cumulus_collator::SetupParachain<Block> for SetupParachain<S, PF, E, BI> impl<S, PF, E, BI> cumulus_collator::SetupParachain<Block> for SetupParachain<S, PF, E, BI>
where where
S: AbstractService, S: AbstractService,
E: Send + crate::cli::IntoExit, E: Send + crate::cli::IntoExit,
PF: consensus_common::Environment<Block> + Send + 'static, PF: Environment<Block> + Send + 'static,
BI: consensus_common::BlockImport<Block, Error=consensus_common::Error> + Send + Sync + 'static, BI: BlockImport<Block, Error = sp_consensus::Error, Transaction = TransactionFor<PF, Block>>
+ Send
+ Sync
+ 'static,
{ {
type ProposerFactory = PF; type ProposerFactory = PF;
type BlockImport = BI; type BlockImport = BI;
fn setup_parachain<P: cumulus_consensus::PolkadotClient>( fn setup_parachain<P: cumulus_consensus::PolkadotClient, Spawner>(
self, self,
polkadot_client: P, polkadot_client: P,
task_executor: polkadot_collator::TaskExecutor, spawner: Spawner,
) -> Result<(Self::ProposerFactory, Self::BlockImport, InherentDataProviders), String> { ) -> Result<
(
Self::ProposerFactory,
Self::BlockImport,
InherentDataProviders,
),
String,
>
where
Spawner: Spawn + Clone + Send + Sync + 'static,
{
let client = self.service.client(); let client = self.service.client();
let follow = match cumulus_consensus::follow_polkadot(crate::PARA_ID, client, polkadot_client) { let follow =
Ok(follow) => follow, match cumulus_consensus::follow_polkadot(crate::PARA_ID, client, polkadot_client) {
Err(e) => { Ok(follow) => follow,
return Err(format!("Could not start following polkadot: {:?}", e)); Err(e) => {
} return Err(format!("Could not start following polkadot: {:?}", e));
}; }
};
task_executor.execute( spawner
Box::new( .spawn_obj(
self.service Box::new(
.map_err(|e| error!("Parachain service error: {:?}", e)) future::select(
.select(futures03::compat::Compat::new(follow.map(|_| Ok::<(), ()>(())))) self.service
.map(|_| ()) .compat()
.map_err(|_| ()) .map_err(|e| error!("Parachain service error: {:?}", e)),
.select(self.exit.into_exit()) future::select(follow, self.exit.into_exit()),
.map(|_| ()) )
.map_err(|_| ()) .map(|_| ()),
), )
).map_err(|_| "Could not spawn parachain server!")?; .into(),
)
.map_err(|_| "Could not spawn parachain server!")?;
Ok((self.proposer_factory, self.block_import, self.inherent_data_providers)) Ok((
self.proposer_factory,
self.block_import,
self.inherent_data_providers,
))
} }
} }
+1 -1
View File
@@ -24,4 +24,4 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
pub use substrate_test_runtime::*; pub use substrate_test_runtime::*;
runtime::register_validate_block!(Block, system::BlockExecutor); runtime::register_validate_block!(Block, system::BlockExecutor);