Make work with Substrate master (#36)

* Fix up wasm runtime build

* Fixes for runtime

* Fix.

* More fixes

* Runtime builds on native.

* Native and wasm both build without warnings.

* Fix runtime tests.

* Merge #20

* Final fix for native runtime.

* Compile polkadot wo consensus

* Reverted changes to polkadot-consensus

* reintroduce minimal subset of consensus

* reintroduce checked_block to runtime for std

* polkadot_consensus compiles without most of the code

* remove checked_block again and do more checks in parachains for runtime

* uncomment proposer

* remove offline tracker

* extract out parachain-attestation logic from proposal directly

* reintroduce transaction_pool

* write some custom aura verification logic for the block verifier

* use transaction pool in more generic way

* service compiles again

* polkadot-network and tests pass

* remove unused session_key function from router

* everything but CLI compiles due to service hell

* Fixes compilation of `polkadot_cli`

* everything compiles

* update adder wasm
This commit is contained in:
Gav Wood
2018-11-25 11:25:36 +01:00
committed by GitHub
parent e68cd9df10
commit c31f8168df
52 changed files with 3281 additions and 4669 deletions
+1762 -1464
View File
File diff suppressed because it is too large Load Diff
+1 -6
View File
@@ -19,7 +19,6 @@ vergen = "0.1"
[workspace] [workspace]
members = [ members = [
"api",
"availability-store", "availability-store",
"cli", "cli",
"collator", "collator",
@@ -30,7 +29,6 @@ members = [
"runtime", "runtime",
"service", "service",
"statement-table", "statement-table",
"transaction-pool",
"service", "service",
"test-parachains/adder", "test-parachains/adder",
@@ -42,11 +40,8 @@ exclude = [
] ]
[badges] [badges]
travis-ci = { repository = "paritytech/substrate", branch = "master" }
maintenance = { status = "actively-developed" } maintenance = { status = "actively-developed" }
is-it-maintained-issue-resolution = { repository = "paritytech/substrate" }
is-it-maintained-open-issues = { repository = "paritytech/substrate" }
[profile.release] [profile.release]
# Substrate runtime requires unwinding. # Polkadot runtime requires unwinding.
panic = "unwind" panic = "unwind"
-22
View File
@@ -1,22 +0,0 @@
[package]
name = "polkadot-api"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
error-chain = "0.12"
log = "0.3"
polkadot-executor = { path = "../executor" }
polkadot-runtime = { path = "../runtime" }
polkadot-primitives = { path = "../primitives" }
parity-codec = { git = "https://github.com/paritytech/substrate" }
sr-io = { git = "https://github.com/paritytech/substrate" }
srml-executive = { git = "https://github.com/paritytech/substrate" }
sr-primitives = { git = "https://github.com/paritytech/substrate" }
substrate-client = { git = "https://github.com/paritytech/substrate" }
substrate-primitives = { git = "https://github.com/paritytech/substrate" }
substrate-executor = { git = "https://github.com/paritytech/substrate" }
substrate-state-machine = { git = "https://github.com/paritytech/substrate" }
[dev-dependencies]
substrate-keyring = { git = "https://github.com/paritytech/substrate" }
-5
View File
@@ -1,5 +0,0 @@
= Polkadot API
placeholder
//TODO Write content :)
-220
View File
@@ -1,220 +0,0 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Strongly typed API for full Polkadot client.
use client::backend::LocalBackend;
use client::block_builder::BlockBuilder as ClientBlockBuilder;
use client::{Client, LocalCallExecutor};
use polkadot_executor::Executor as LocalDispatch;
use substrate_executor::NativeExecutor;
//use runtime::{Block, Header, Address, BlockId};
use runtime::Address;
use primitives::{
Block, BlockId,
AccountId, Hash, Index, InherentData,
SessionKey, Timestamp, UncheckedExtrinsic,
};
use primitives::parachain::{DutyRoster, Id as ParaId};
use substrate_primitives::{Blake2Hasher, RlpCodec};
use {BlockBuilder, PolkadotApi, LocalPolkadotApi, ErrorKind, Result};
impl<B: LocalBackend<Block, Blake2Hasher, RlpCodec>> BlockBuilder for ClientBlockBuilder<B, LocalCallExecutor<B, NativeExecutor<LocalDispatch>>, Block, Blake2Hasher, RlpCodec> {
fn push_extrinsic(&mut self, extrinsic: UncheckedExtrinsic) -> Result<()> {
self.push(extrinsic).map_err(Into::into)
}
/// Bake the block with provided extrinsics.
fn bake(self) -> Result<Block> {
ClientBlockBuilder::bake(self).map_err(Into::into)
}
}
impl<B: LocalBackend<Block, Blake2Hasher, RlpCodec>> PolkadotApi for Client<B, LocalCallExecutor<B, NativeExecutor<LocalDispatch>>, Block> {
type BlockBuilder = ClientBlockBuilder<B, LocalCallExecutor<B, NativeExecutor<LocalDispatch>>, Block, Blake2Hasher, RlpCodec>;
fn session_keys(&self, at: &BlockId) -> Result<Vec<SessionKey>> {
Ok(self.authorities_at(at)?)
}
fn validators(&self, at: &BlockId) -> Result<Vec<AccountId>> {
Ok(self.call_api_at(at, "validators", &())?)
}
fn random_seed(&self, at: &BlockId) -> Result<Hash> {
Ok(self.call_api_at(at, "random_seed", &())?)
}
fn duty_roster(&self, at: &BlockId) -> Result<DutyRoster> {
Ok(self.call_api_at(at, "duty_roster", &())?)
}
fn timestamp(&self, at: &BlockId) -> Result<Timestamp> {
Ok(self.call_api_at(at, "timestamp", &())?)
}
fn evaluate_block(&self, at: &BlockId, block: Block) -> Result<bool> {
let res: Result<()> = self.call_api_at(at, "execute_block", &block).map_err(From::from);
match res {
Ok(_) => Ok(true),
Err(err) => match err.kind() {
&ErrorKind::Execution(_) => Ok(false),
_ => Err(err)
}
}
}
fn index(&self, at: &BlockId, account: AccountId) -> Result<Index> {
Ok(self.call_api_at(at, "account_nonce", &account)?)
}
fn lookup(&self, at: &BlockId, address: Address) -> Result<Option<AccountId>> {
Ok(self.call_api_at(at, "lookup_address", &address)?)
}
fn active_parachains(&self, at: &BlockId) -> Result<Vec<ParaId>> {
Ok(self.call_api_at(at, "active_parachains", &())?)
}
fn parachain_code(&self, at: &BlockId, parachain: ParaId) -> Result<Option<Vec<u8>>> {
Ok(self.call_api_at(at, "parachain_code", &parachain)?)
}
fn parachain_head(&self, at: &BlockId, parachain: ParaId) -> Result<Option<Vec<u8>>> {
Ok(self.call_api_at(at, "parachain_head", &parachain)?)
}
fn build_block(&self, at: &BlockId, inherent_data: InherentData) -> Result<Self::BlockBuilder> {
let mut block_builder = self.new_block_at(at)?;
for inherent in self.inherent_extrinsics(at, inherent_data)? {
block_builder.push(inherent)?;
}
Ok(block_builder)
}
fn inherent_extrinsics(&self, at: &BlockId, inherent_data: InherentData) -> Result<Vec<UncheckedExtrinsic>> {
let runtime_version = self.runtime_version_at(at)?;
Ok(self.call_api_at(at, "inherent_extrinsics", &(inherent_data, runtime_version.spec_version))?)
}
}
impl<B: LocalBackend<Block, Blake2Hasher, RlpCodec>> LocalPolkadotApi for Client<B, LocalCallExecutor<B, NativeExecutor<LocalDispatch>>, Block>
{}
#[cfg(test)]
mod tests {
use super::*;
use keyring::Keyring;
use client::LocalCallExecutor;
use client::in_mem::Backend as InMemory;
use substrate_executor::NativeExecutionDispatch;
use runtime::{GenesisConfig, ConsensusConfig, SessionConfig};
fn validators() -> Vec<AccountId> {
vec![
Keyring::One.to_raw_public().into(),
Keyring::Two.to_raw_public().into(),
]
}
fn session_keys() -> Vec<SessionKey> {
vec![
Keyring::One.to_raw_public().into(),
Keyring::Two.to_raw_public().into(),
]
}
fn client() -> Client<InMemory<Block, Blake2Hasher, RlpCodec>, LocalCallExecutor<InMemory<Block, Blake2Hasher, RlpCodec>, NativeExecutor<LocalDispatch>>, Block> {
let genesis_config = GenesisConfig {
consensus: Some(ConsensusConfig {
code: LocalDispatch::native_equivalent().to_vec(),
authorities: session_keys(),
}),
system: None,
balances: Some(Default::default()),
session: Some(SessionConfig {
validators: validators(),
session_length: 100,
}),
council: Some(Default::default()),
democracy: Some(Default::default()),
parachains: Some(Default::default()),
staking: Some(Default::default()),
timestamp: Some(Default::default()),
treasury: Some(Default::default()),
};
::client::new_in_mem(LocalDispatch::new(), genesis_config).unwrap()
}
#[test]
fn gets_session_and_validator_keys() {
let client = client();
let id = BlockId::number(0);
assert_eq!(client.session_keys(&id).unwrap(), session_keys());
assert_eq!(client.validators(&id).unwrap(), validators());
}
#[test]
fn build_block_implicit_succeeds() {
let client = client();
let id = BlockId::number(0);
let block_builder = client.build_block(&id, InherentData {
timestamp: 1_000_000,
parachain_heads: Vec::new(),
offline_indices: Vec::new(),
}).unwrap();
let block = block_builder.bake().unwrap();
assert_eq!(block.header.number, 1);
assert!(block.header.extrinsics_root != Default::default());
assert!(client.evaluate_block(&id, block).unwrap());
}
#[test]
fn build_block_with_inherent_succeeds() {
let client = client();
let id = BlockId::number(0);
let inherent = client.inherent_extrinsics(&id, InherentData {
timestamp: 1_000_000,
parachain_heads: Vec::new(),
offline_indices: Vec::new(),
}).unwrap();
let mut block_builder = client.new_block_at(&id).unwrap();
for extrinsic in inherent {
block_builder.push(extrinsic).unwrap();
}
let block = block_builder.bake().unwrap();
assert_eq!(block.header.number, 1);
assert!(block.header.extrinsics_root != Default::default());
assert!(client.evaluate_block(&id, block).unwrap());
}
#[test]
fn gets_random_seed_with_genesis() {
let client = client();
let id = BlockId::number(0);
client.random_seed(&id).unwrap();
}
}
-149
View File
@@ -1,149 +0,0 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Strongly typed API for Polkadot based around the locally-compiled native
//! runtime.
extern crate polkadot_executor;
extern crate polkadot_primitives as primitives;
extern crate polkadot_runtime as runtime;
extern crate parity_codec as codec;
extern crate sr_io as runtime_io;
extern crate substrate_client as client;
extern crate substrate_executor as substrate_executor;
extern crate srml_executive;
extern crate substrate_primitives;
extern crate sr_primitives as runtime_primitives;
extern crate substrate_state_machine as state_machine;
#[macro_use]
extern crate error_chain;
extern crate log;
#[cfg(test)]
extern crate substrate_keyring as keyring;
pub mod full;
pub mod light;
use primitives::{
AccountId, Block, BlockId, Hash, Index, SessionKey, Timestamp,
UncheckedExtrinsic, InherentData,
};
use runtime::Address;
use primitives::parachain::{DutyRoster, Id as ParaId};
error_chain! {
errors {
/// Unknown runtime code.
UnknownRuntime {
description("Unknown runtime code")
display("Unknown runtime code")
}
/// Unknown block ID.
UnknownBlock(b: String) {
description("Unknown block")
display("Unknown block {}", b)
}
/// Execution error.
Execution(e: String) {
description("Execution error")
display("Execution error: {}", e)
}
/// Some other error.
// TODO: allow to be specified as associated type of PolkadotApi
Other(e: Box<::std::error::Error + Send>) {
description("Other error")
display("Other error: {}", e.description())
}
}
}
impl From<client::error::Error> for Error {
fn from(e: client::error::Error) -> Error {
match e {
client::error::Error(client::error::ErrorKind::UnknownBlock(b), _) => Error::from_kind(ErrorKind::UnknownBlock(b)),
client::error::Error(client::error::ErrorKind::Execution(e), _) =>
Error::from_kind(ErrorKind::Execution(format!("{}", e))),
other => Error::from_kind(ErrorKind::Other(Box::new(other) as Box<_>)),
}
}
}
/// Build new blocks.
pub trait BlockBuilder {
/// Push an extrinsic onto the block. Fails if the extrinsic is invalid.
fn push_extrinsic(&mut self, extrinsic: UncheckedExtrinsic) -> Result<()>;
/// Bake the block with provided extrinsics.
fn bake(self) -> Result<Block>;
}
/// Trait encapsulating the Polkadot API.
///
/// All calls should fail when the exact runtime is unknown.
pub trait PolkadotApi {
/// The block builder for this API type.
type BlockBuilder: BlockBuilder;
/// Get session keys at a given block.
fn session_keys(&self, at: &BlockId) -> Result<Vec<SessionKey>>;
/// Get validators at a given block.
fn validators(&self, at: &BlockId) -> Result<Vec<AccountId>>;
/// Get the value of the randomness beacon at a given block.
fn random_seed(&self, at: &BlockId) -> Result<Hash>;
/// Get the authority duty roster at a block.
fn duty_roster(&self, at: &BlockId) -> Result<DutyRoster>;
/// Get the timestamp registered at a block.
fn timestamp(&self, at: &BlockId) -> Result<Timestamp>;
/// Get the nonce (né index) of an account at a block.
fn index(&self, at: &BlockId, account: AccountId) -> Result<Index>;
/// Get the account id of an address at a block.
fn lookup(&self, at: &BlockId, address: Address) -> Result<Option<AccountId>>;
/// Get the active parachains at a block.
fn active_parachains(&self, at: &BlockId) -> Result<Vec<ParaId>>;
/// Get the validation code of a parachain at a block. If the parachain is active, this will always return `Some`.
fn parachain_code(&self, at: &BlockId, parachain: ParaId) -> Result<Option<Vec<u8>>>;
/// Get the chain head of a parachain. If the parachain is active, this will always return `Some`.
fn parachain_head(&self, at: &BlockId, parachain: ParaId) -> Result<Option<Vec<u8>>>;
/// Evaluate a block. Returns true if the block is good, false if it is known to be bad,
/// and an error if we can't evaluate for some reason.
fn evaluate_block(&self, at: &BlockId, block: Block) -> Result<bool>;
/// Build a block on top of the given, with inherent extrinsics pre-pushed.
fn build_block(&self, at: &BlockId, inherent_data: InherentData) -> Result<Self::BlockBuilder>;
/// Attempt to produce the (encoded) inherent extrinsics for a block being built upon the given.
/// This may vary by runtime and will fail if a runtime doesn't follow the same API.
fn inherent_extrinsics(&self, at: &BlockId, inherent_data: InherentData) -> Result<Vec<UncheckedExtrinsic>>;
}
/// Mark for all Polkadot API implementations, that are making use of state data, stored locally.
pub trait LocalPolkadotApi: PolkadotApi {}
/// Mark for all Polkadot API implementations, that are fetching required state data from remote nodes.
pub trait RemotePolkadotApi: PolkadotApi {}
-108
View File
@@ -1,108 +0,0 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Strongly typed API for light Polkadot client.
use std::sync::Arc;
use client::backend::{Backend, RemoteBackend};
use client::{Client, CallExecutor};
use codec::Decode;
use primitives::{
AccountId, Block, BlockId, Hash, Index, InherentData,
SessionKey, Timestamp, UncheckedExtrinsic,
};
use runtime::Address;
use primitives::parachain::{DutyRoster, Id as ParaId};
use {PolkadotApi, BlockBuilder, RemotePolkadotApi, Result, ErrorKind};
use substrate_primitives::{Blake2Hasher, RlpCodec};
/// Light block builder. TODO: make this work (efficiently)
#[derive(Clone, Copy)]
pub struct LightBlockBuilder;
impl BlockBuilder for LightBlockBuilder {
fn push_extrinsic(&mut self, _xt: UncheckedExtrinsic) -> Result<()> {
Err(ErrorKind::UnknownRuntime.into())
}
fn bake(self) -> Result<Block> {
Err(ErrorKind::UnknownRuntime.into())
}
}
/// Remote polkadot API implementation.
pub struct RemotePolkadotApiWrapper<B: Backend<Block, Blake2Hasher, RlpCodec>, E: CallExecutor<Block, Blake2Hasher, RlpCodec>>(pub Arc<Client<B, E, Block>>);
impl<B: Backend<Block, Blake2Hasher, RlpCodec>, E: CallExecutor<Block, Blake2Hasher, RlpCodec>> PolkadotApi for RemotePolkadotApiWrapper<B, E> {
type BlockBuilder = LightBlockBuilder;
fn session_keys(&self, at: &BlockId) -> Result<Vec<SessionKey>> {
self.0.executor().call(at, "authorities", &[])
.and_then(|r| Vec::<SessionKey>::decode(&mut &r.return_data[..])
.ok_or("error decoding session keys".into()))
.map_err(Into::into)
}
fn validators(&self, _at: &BlockId) -> Result<Vec<AccountId>> {
Err(ErrorKind::UnknownRuntime.into())
}
fn random_seed(&self, _at: &BlockId) -> Result<Hash> {
Err(ErrorKind::UnknownRuntime.into())
}
fn duty_roster(&self, _at: &BlockId) -> Result<DutyRoster> {
Err(ErrorKind::UnknownRuntime.into())
}
fn timestamp(&self, _at: &BlockId) -> Result<Timestamp> {
Err(ErrorKind::UnknownRuntime.into())
}
fn evaluate_block(&self, _at: &BlockId, _block: Block) -> Result<bool> {
Err(ErrorKind::UnknownRuntime.into())
}
fn index(&self, _at: &BlockId, _account: AccountId) -> Result<Index> {
Err(ErrorKind::UnknownRuntime.into())
}
fn lookup(&self, _at: &BlockId, _address: Address) -> Result<Option<AccountId>> {
Err(ErrorKind::UnknownRuntime.into())
}
fn active_parachains(&self, _at: &BlockId) -> Result<Vec<ParaId>> {
Err(ErrorKind::UnknownRuntime.into())
}
fn parachain_code(&self, _at: &BlockId, _parachain: ParaId) -> Result<Option<Vec<u8>>> {
Err(ErrorKind::UnknownRuntime.into())
}
fn parachain_head(&self, _at: &BlockId, _parachain: ParaId) -> Result<Option<Vec<u8>>> {
Err(ErrorKind::UnknownRuntime.into())
}
fn build_block(&self, _at: &BlockId, _inherent: InherentData) -> Result<Self::BlockBuilder> {
Err(ErrorKind::UnknownRuntime.into())
}
fn inherent_extrinsics(&self, _at: &BlockId, _inherent: InherentData) -> Result<Vec<UncheckedExtrinsic>> {
Err(ErrorKind::UnknownRuntime.into())
}
}
impl<B: RemoteBackend<Block, Blake2Hasher, RlpCodec>, E: CallExecutor<Block, Blake2Hasher, RlpCodec>> RemotePolkadotApi for RemotePolkadotApiWrapper<B, E> {}
+1 -1
View File
@@ -8,7 +8,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
polkadot-primitives = { path = "../primitives" } polkadot-primitives = { path = "../primitives" }
parking_lot = "0.4" parking_lot = "0.4"
log = "0.3" log = "0.3"
parity-codec = { git = "https://github.com/paritytech/substrate" } parity-codec = "2.1"
substrate-primitives = { git = "https://github.com/paritytech/substrate" } substrate-primitives = { git = "https://github.com/paritytech/substrate" }
kvdb = { git = "https://github.com/paritytech/parity-common.git" } kvdb = { git = "https://github.com/paritytech/parity-common.git" }
kvdb-rocksdb = { git = "https://github.com/paritytech/parity-common.git" } kvdb-rocksdb = { git = "https://github.com/paritytech/parity-common.git" }
+1 -1
View File
@@ -110,7 +110,7 @@ impl Store {
let mut tx = DBTransaction::new(); let mut tx = DBTransaction::new();
// note the meta key. // note the meta key.
let mut v = match self.inner.get(columns::META, &*data.relay_parent) { let mut v = match self.inner.get(columns::META, data.relay_parent.as_ref()) {
Ok(Some(raw)) => Vec::decode(&mut &raw[..]).expect("all stored data serialized correctly; qed"), Ok(Some(raw)) => Vec::decode(&mut &raw[..]).expect("all stored data serialized correctly; qed"),
Ok(None) => Vec::new(), Ok(None) => Vec::new(),
Err(e) => { Err(e) => {
+1
View File
@@ -11,3 +11,4 @@ futures = "0.1.17"
exit-future = "0.1" exit-future = "0.1"
substrate-cli = { git = "https://github.com/paritytech/substrate" } substrate-cli = { git = "https://github.com/paritytech/substrate" }
polkadot-service = { path = "../service" } polkadot-service = { path = "../service" }
structopt = "0.2.13"
+38 -12
View File
@@ -25,20 +25,27 @@ extern crate tokio;
extern crate substrate_cli as cli; extern crate substrate_cli as cli;
extern crate polkadot_service as service; extern crate polkadot_service as service;
extern crate exit_future; extern crate exit_future;
extern crate structopt;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
mod chain_spec; mod chain_spec;
pub use cli::error; use std::ops::Deref;
use chain_spec::ChainSpec; use chain_spec::ChainSpec;
use futures::Future; use futures::Future;
use tokio::runtime::Runtime; use tokio::runtime::Runtime;
pub use service::{Components as ServiceComponents, Service, CustomConfiguration}; use structopt::StructOpt;
use service::Service as BareService;
pub use service::{
Components as ServiceComponents, PolkadotService, CustomConfiguration, ServiceFactory, Factory,
ProvideRuntimeApi, CoreApi, ParachainHost,
};
pub use cli::{VersionInfo, IntoExit}; pub use cli::{VersionInfo, IntoExit};
pub use cli::error;
fn load_spec(id: &str) -> Result<Option<service::ChainSpec>, String> { fn load_spec(id: &str) -> Result<Option<service::ChainSpec>, String> {
Ok(match ChainSpec::from(id) { Ok(match ChainSpec::from(id) {
@@ -62,7 +69,7 @@ pub trait Worker: IntoExit {
fn configuration(&self) -> service::CustomConfiguration { Default::default() } fn configuration(&self) -> service::CustomConfiguration { Default::default() }
/// Do work and schedule exit. /// Do work and schedule exit.
fn work<C: service::Components>(self, service: &service::Service<C>) -> Self::Work; fn work<S: PolkadotService>(self, service: &S) -> Self::Work;
} }
/// Parse command line arguments into service configuration. /// Parse command line arguments into service configuration.
@@ -78,10 +85,26 @@ pub fn run<I, T, W>(args: I, worker: W, version: cli::VersionInfo) -> error::Res
T: Into<std::ffi::OsString> + Clone, T: Into<std::ffi::OsString> + Clone,
W: Worker, W: Worker,
{ {
let full_version = polkadot_service::full_version_from_strs(
version.version,
version.commit
);
match cli::prepare_execution::<service::Factory, _, _, _, _>(args, worker, version, load_spec, "parity-polkadot")? { let matches = match cli::CoreParams::clap()
.name(version.executable_name)
.author(version.author)
.about(version.description)
.version(&(full_version + "\n")[..])
.get_matches_from_safe(args) {
Ok(m) => m,
Err(e) => e.exit(),
};
let (spec, mut config) = cli::parse_matches::<service::Factory, _>(load_spec, version, "parity-polkadot", &matches)?;
match cli::execute_default::<service::Factory, _,>(spec, worker, &matches)? {
cli::Action::ExecutedInternally => (), cli::Action::ExecutedInternally => (),
cli::Action::RunService((mut config, worker)) => { cli::Action::RunService(worker) => {
info!("Parity ·:· Polkadot"); info!("Parity ·:· Polkadot");
info!(" version {}", config.full_version()); info!(" version {}", config.full_version());
info!(" by Parity Technologies, 2017, 2018"); info!(" by Parity Technologies, 2017, 2018");
@@ -92,20 +115,23 @@ pub fn run<I, T, W>(args: I, worker: W, version: cli::VersionInfo) -> error::Res
let mut runtime = Runtime::new()?; let mut runtime = Runtime::new()?;
let executor = runtime.executor(); let executor = runtime.executor();
match config.roles == service::Roles::LIGHT { match config.roles == service::Roles::LIGHT {
true => run_until_exit(&mut runtime, service::new_light(config, executor)?, worker)?, true => run_until_exit(&mut runtime, Factory::new_light(config, executor)?, worker)?,
false => run_until_exit(&mut runtime, service::new_full(config, executor)?, worker)?, false => run_until_exit(&mut runtime, Factory::new_full(config, executor)?, worker)?,
} }
} }
} }
Ok(()) Ok(())
} }
fn run_until_exit<C, W>(
fn run_until_exit<T, C, W>(
runtime: &mut Runtime, runtime: &mut Runtime,
service: service::Service<C>, service: T,
worker: W, worker: W,
) -> error::Result<()> ) -> error::Result<()>
where where
T: Deref<Target=BareService<C>>,
C: service::Components, C: service::Components,
BareService<C>: PolkadotService,
W: Worker, W: Worker,
{ {
let (exit_send, exit) = exit_future::signal(); let (exit_send, exit) = exit_future::signal();
@@ -113,7 +139,7 @@ fn run_until_exit<C, W>(
let executor = runtime.executor(); let executor = runtime.executor();
cli::informant::start(&service, exit.clone(), executor.clone()); cli::informant::start(&service, exit.clone(), executor.clone());
let _ = runtime.block_on(worker.work(&service)); let _ = runtime.block_on(worker.work(&*service));
exit_send.fire(); exit_send.fire();
Ok(()) Ok(())
} }
+1 -2
View File
@@ -7,9 +7,8 @@ description = "Collator node implementation"
[dependencies] [dependencies]
futures = "0.1.17" futures = "0.1.17"
substrate-client = { git = "https://github.com/paritytech/substrate" } substrate-client = { git = "https://github.com/paritytech/substrate" }
parity-codec = { git = "https://github.com/paritytech/substrate" } parity-codec = "2.1"
substrate-primitives = { git = "https://github.com/paritytech/substrate" } substrate-primitives = { git = "https://github.com/paritytech/substrate" }
polkadot-api = { path = "../api" }
polkadot-runtime = { path = "../runtime", version = "0.1" } polkadot-runtime = { path = "../runtime", version = "0.1" }
polkadot-primitives = { path = "../primitives", version = "0.1" } polkadot-primitives = { path = "../primitives", version = "0.1" }
polkadot-cli = { path = "../cli" } polkadot-cli = { path = "../cli" }
+17 -16
View File
@@ -50,7 +50,6 @@ extern crate parity_codec as codec;
extern crate substrate_primitives as primitives; extern crate substrate_primitives as primitives;
extern crate tokio; extern crate tokio;
extern crate polkadot_api;
extern crate polkadot_cli; extern crate polkadot_cli;
extern crate polkadot_runtime; extern crate polkadot_runtime;
extern crate polkadot_primitives; extern crate polkadot_primitives;
@@ -61,17 +60,16 @@ extern crate log;
use std::collections::{BTreeSet, BTreeMap, HashSet}; use std::collections::{BTreeSet, BTreeMap, HashSet};
use std::fmt; use std::fmt;
use std::sync::Arc; use std::sync::Arc;
use std::time::{Duration, Instant}; use std::time::Duration;
use futures::{future, stream, Stream, Future, IntoFuture}; use futures::{future, stream, Stream, Future, IntoFuture};
use client::BlockchainEvents; use client::BlockchainEvents;
use polkadot_api::PolkadotApi;
use primitives::ed25519; use primitives::ed25519;
use polkadot_primitives::{AccountId, BlockId, SessionKey}; use polkadot_primitives::{AccountId, BlockId, SessionKey};
use polkadot_primitives::parachain::{self, BlockData, DutyRoster, HeadData, ConsolidatedIngress, Message, Id as ParaId}; use polkadot_primitives::parachain::{self, BlockData, DutyRoster, HeadData, ConsolidatedIngress, Message, Id as ParaId};
use polkadot_cli::{ServiceComponents, Service, CustomConfiguration}; use polkadot_cli::{PolkadotService, CustomConfiguration, CoreApi, ParachainHost};
use polkadot_cli::{Worker, IntoExit}; use polkadot_cli::{Worker, IntoExit, ProvideRuntimeApi};
use tokio::timer::Deadline; use tokio::timer::Timeout;
pub use polkadot_cli::VersionInfo; pub use polkadot_cli::VersionInfo;
@@ -193,7 +191,7 @@ pub fn collate<'a, R, P>(
).map_err(Error::Collator)?; ).map_err(Error::Collator)?;
let block_data_hash = block_data.hash(); let block_data_hash = block_data.hash();
let signature = key.sign(&block_data_hash.0[..]).into(); let signature = key.sign(block_data_hash.as_ref()).into();
let receipt = parachain::CandidateReceipt { let receipt = parachain::CandidateReceipt {
parachain_index: local_id, parachain_index: local_id,
@@ -217,7 +215,7 @@ pub fn collate<'a, R, P>(
struct ApiContext; struct ApiContext;
impl RelayChainContext for ApiContext { impl RelayChainContext for ApiContext {
type Error = ::polkadot_api::Error; type Error = client::error::Error;
type FutureEgress = Result<Vec<Vec<Message>>, Self::Error>; type FutureEgress = Result<Vec<Vec<Message>>, Self::Error>;
fn routing_parachains(&self) -> BTreeSet<ParaId> { fn routing_parachains(&self) -> BTreeSet<ParaId> {
@@ -261,10 +259,12 @@ impl<P, E> Worker for CollationNode<P, E> where
config config
} }
fn work<C: ServiceComponents>(self, service: &Service<C>) -> Self::Work { fn work<S>(self, service: &S) -> Self::Work
where S: PolkadotService,
{
let CollationNode { parachain_context, exit, para_id, key } = self; let CollationNode { parachain_context, exit, para_id, key } = self;
let client = service.client(); let client = service.client();
let api = service.api();
let network = service.network(); let network = service.network();
let work = client.import_notification_stream() let work = client.import_notification_stream()
@@ -282,19 +282,20 @@ impl<P, E> Worker for CollationNode<P, E> where
let id = BlockId::hash(relay_parent); let id = BlockId::hash(relay_parent);
let network = network.clone(); let network = network.clone();
let api = api.clone(); let client = client.clone();
let key = key.clone(); let key = key.clone();
let parachain_context = parachain_context.clone(); let parachain_context = parachain_context.clone();
let work = future::lazy(move || { let work = future::lazy(move || {
let last_head = match try_fr!(api.parachain_head(&id, para_id)) { let api = client.runtime_api();
let last_head = match try_fr!(api.parachain_head(&id, &para_id)) {
Some(last_head) => last_head, Some(last_head) => last_head,
None => return future::Either::A(future::ok(())), None => return future::Either::A(future::ok(())),
}; };
let targets = compute_targets( let targets = compute_targets(
para_id, para_id,
try_fr!(api.session_keys(&id)).as_slice(), try_fr!(api.authorities(&id)).as_slice(),
try_fr!(api.duty_roster(&id)), try_fr!(api.duty_roster(&id)),
); );
@@ -315,11 +316,11 @@ impl<P, E> Worker for CollationNode<P, E> where
future::Either::B(collation_work) future::Either::B(collation_work)
}); });
let deadlined = Deadline::new(work, Instant::now() + COLLATION_TIMEOUT); let deadlined = Timeout::new(work, COLLATION_TIMEOUT);
let silenced = deadlined.then(|res| match res { let silenced = deadlined.then(|res| match res {
Ok(()) => Ok(()), Ok(()) => Ok(()),
Err(e) => { Err(_) => {
warn!("Collation failure: {}", e); warn!("Collation failure: timeout");
Ok(()) Ok(())
} }
}); });
+5 -5
View File
@@ -10,17 +10,17 @@ tokio = "0.1.7"
error-chain = "0.12" error-chain = "0.12"
log = "0.3" log = "0.3"
exit-future = "0.1" exit-future = "0.1"
rhododendron = "0.3" parity-codec = "2.1"
polkadot-api = { path = "../api" }
polkadot-availability-store = { path = "../availability-store" } polkadot-availability-store = { path = "../availability-store" }
polkadot-parachain = { path = "../parachain" } polkadot-parachain = { path = "../parachain" }
polkadot-primitives = { path = "../primitives" } polkadot-primitives = { path = "../primitives" }
polkadot-runtime = { path = "../runtime" } polkadot-runtime = { path = "../runtime" }
polkadot-statement-table = { path = "../statement-table" } polkadot-statement-table = { path = "../statement-table" }
polkadot-transaction-pool = { path = "../transaction-pool" } substrate-consensus-aura = { git = "https://github.com/paritytech/substrate" }
substrate-bft = { git = "https://github.com/paritytech/substrate" } substrate-finality-grandpa = { git = "https://github.com/paritytech/substrate" }
parity-codec = { git = "https://github.com/paritytech/substrate" } substrate-consensus-common = { git = "https://github.com/paritytech/substrate" }
substrate-primitives = { git = "https://github.com/paritytech/substrate" } substrate-primitives = { git = "https://github.com/paritytech/substrate" }
substrate-transaction-pool = { git = "https://github.com/paritytech/substrate" }
srml-support = { git = "https://github.com/paritytech/substrate" } srml-support = { git = "https://github.com/paritytech/substrate" }
substrate-client = { git = "https://github.com/paritytech/substrate" } substrate-client = { git = "https://github.com/paritytech/substrate" }
sr-primitives = { git = "https://github.com/paritytech/substrate" } sr-primitives = { git = "https://github.com/paritytech/substrate" }
+20 -9
View File
@@ -21,9 +21,10 @@
use std::sync::Arc; use std::sync::Arc;
use polkadot_api::PolkadotApi; use polkadot_primitives::{Block, Hash, AccountId, BlockId};
use polkadot_primitives::{Hash, AccountId, BlockId};
use polkadot_primitives::parachain::{Id as ParaId, Collation, Extrinsic}; use polkadot_primitives::parachain::{Id as ParaId, Collation, Extrinsic};
use polkadot_primitives::parachain::ParachainHost;
use runtime_primitives::traits::ProvideRuntimeApi;
use futures::prelude::*; use futures::prelude::*;
@@ -52,7 +53,7 @@ pub trait Collators: Clone {
/// A future which resolves when a collation is available. /// A future which resolves when a collation is available.
/// ///
/// This future is fused. /// This future is fused.
pub struct CollationFetch<C: Collators, P: PolkadotApi> { pub struct CollationFetch<C: Collators, P: ProvideRuntimeApi> {
parachain: ParaId, parachain: ParaId,
relay_parent_hash: Hash, relay_parent_hash: Hash,
relay_parent: BlockId, relay_parent: BlockId,
@@ -61,7 +62,7 @@ pub struct CollationFetch<C: Collators, P: PolkadotApi> {
client: Arc<P>, client: Arc<P>,
} }
impl<C: Collators, P: PolkadotApi> CollationFetch<C, P> { impl<C: Collators, P: ProvideRuntimeApi> CollationFetch<C, P> {
/// Create a new collation fetcher for the given chain. /// Create a new collation fetcher for the given chain.
pub fn new(parachain: ParaId, relay_parent: BlockId, relay_parent_hash: Hash, collators: C, client: Arc<P>) -> Self { pub fn new(parachain: ParaId, relay_parent: BlockId, relay_parent_hash: Hash, collators: C, client: Arc<P>) -> Self {
CollationFetch { CollationFetch {
@@ -80,7 +81,9 @@ impl<C: Collators, P: PolkadotApi> CollationFetch<C, P> {
} }
} }
impl<C: Collators, P: PolkadotApi> Future for CollationFetch<C, P> { impl<C: Collators, P: ProvideRuntimeApi> Future for CollationFetch<C, P>
where P::Api: ParachainHost<Block>,
{
type Item = (Collation, Extrinsic); type Item = (Collation, Extrinsic);
type Error = C::Error; type Error = C::Error;
@@ -133,19 +136,27 @@ error_chain! {
} }
links { links {
PolkadotApi(::polkadot_api::Error, ::polkadot_api::ErrorKind); Client(::client::error::Error, ::client::error::ErrorKind);
} }
} }
/// Check whether a given collation is valid. Returns `Ok` on success, error otherwise. /// Check whether a given collation is valid. Returns `Ok` on success, error otherwise.
pub fn validate_collation<P: PolkadotApi>(client: &P, relay_parent: &BlockId, collation: &Collation) -> Result<(), Error> { pub fn validate_collation<P>(
client: &P,
relay_parent: &BlockId,
collation: &Collation
) -> Result<(), Error> where
P: ProvideRuntimeApi,
P::Api: ParachainHost<Block>
{
use parachain::{self, ValidationParams}; use parachain::{self, ValidationParams};
let api = client.runtime_api();
let para_id = collation.receipt.parachain_index; let para_id = collation.receipt.parachain_index;
let validation_code = client.parachain_code(relay_parent, para_id)? let validation_code = api.parachain_code(relay_parent, &para_id)?
.ok_or_else(|| ErrorKind::InactiveParachain(para_id))?; .ok_or_else(|| ErrorKind::InactiveParachain(para_id))?;
let chain_head = client.parachain_head(relay_parent, para_id)? let chain_head = api.parachain_head(relay_parent, &para_id)?
.ok_or_else(|| ErrorKind::InactiveParachain(para_id))?; .ok_or_else(|| ErrorKind::InactiveParachain(para_id))?;
let params = ValidationParams { let params = ValidationParams {
+7 -7
View File
@@ -20,8 +20,8 @@ use primitives::AuthorityId;
error_chain! { error_chain! {
links { links {
PolkadotApi(::polkadot_api::Error, ::polkadot_api::ErrorKind); Client(::client::error::Error, ::client::error::ErrorKind);
Bft(::bft::Error, ::bft::ErrorKind); Consensus(::consensus::error::Error, ::consensus::error::ErrorKind);
} }
errors { errors {
@@ -48,8 +48,8 @@ error_chain! {
} }
} }
impl From<::bft::InputStreamConcluded> for Error { // impl From<::bft::InputStreamConcluded> for Error {
fn from(err: ::bft::InputStreamConcluded) -> Self { // fn from(err: ::bft::InputStreamConcluded) -> Self {
::bft::Error::from(err).into() // ::bft::Error::from(err).into()
} // }
} // }
+6 -48
View File
@@ -18,14 +18,13 @@
use super::MAX_TRANSACTIONS_SIZE; use super::MAX_TRANSACTIONS_SIZE;
use codec::{Decode, Encode}; use codec::Encode;
use polkadot_runtime::{Block as PolkadotGenericBlock, CheckedBlock};
use polkadot_primitives::{Block, Hash, BlockNumber, Timestamp}; use polkadot_primitives::{Block, Hash, BlockNumber, Timestamp};
use polkadot_primitives::parachain::Id as ParaId; use polkadot_primitives::parachain::Id as ParaId;
error_chain! { error_chain! {
links { links {
PolkadotApi(::polkadot_api::Error, ::polkadot_api::ErrorKind); Client(::client::error::Error, ::client::error::ErrorKind);
} }
errors { errors {
@@ -33,10 +32,6 @@ error_chain! {
description("Proposal provided not a Polkadot block."), description("Proposal provided not a Polkadot block."),
display("Proposal provided not a Polkadot block."), display("Proposal provided not a Polkadot block."),
} }
TimestampInFuture {
description("Proposal had timestamp too far in the future."),
display("Proposal had timestamp too far in the future."),
}
TooManyCandidates(expected: usize, got: usize) { TooManyCandidates(expected: usize, got: usize) {
description("Proposal included more candidates than is possible."), description("Proposal included more candidates than is possible."),
display("Proposal included {} candidates for {} parachains", got, expected), display("Proposal included {} candidates for {} parachains", got, expected),
@@ -71,18 +66,11 @@ error_chain! {
/// upon any initial validity checks failing. /// upon any initial validity checks failing.
pub fn evaluate_initial( pub fn evaluate_initial(
proposal: &Block, proposal: &Block,
now: Timestamp, _now: Timestamp,
parent_hash: &Hash, parent_hash: &Hash,
parent_number: BlockNumber, parent_number: BlockNumber,
active_parachains: &[ParaId], _active_parachains: &[ParaId],
) -> Result<CheckedBlock> { ) -> Result<()> {
const MAX_TIMESTAMP_DRIFT: Timestamp = 60;
let encoded = Encode::encode(proposal);
let proposal = PolkadotGenericBlock::decode(&mut &encoded[..])
.and_then(|b| CheckedBlock::new(b).ok())
.ok_or_else(|| ErrorKind::ProposalNotForPolkadot)?;
let transactions_size = proposal.extrinsics.iter().fold(0, |a, tx| { let transactions_size = proposal.extrinsics.iter().fold(0, |a, tx| {
a + Encode::encode(tx).len() a + Encode::encode(tx).len()
}); });
@@ -99,35 +87,5 @@ pub fn evaluate_initial(
bail!(ErrorKind::WrongNumber(parent_number + 1, proposal.header.number)); bail!(ErrorKind::WrongNumber(parent_number + 1, proposal.header.number));
} }
let block_timestamp = proposal.timestamp(); Ok(())
// lenient maximum -- small drifts will just be delayed using a timer.
if block_timestamp > now + MAX_TIMESTAMP_DRIFT {
bail!(ErrorKind::TimestampInFuture)
}
{
let n_parachains = active_parachains.len();
if proposal.parachain_heads().len() > n_parachains {
bail!(ErrorKind::TooManyCandidates(n_parachains, proposal.parachain_heads().len()));
}
let mut last_id = None;
let mut iter = active_parachains.iter();
for head in proposal.parachain_heads() {
// proposed heads must be ascending order by parachain ID without duplicate.
if last_id.as_ref().map_or(false, |x| x >= &head.parachain_index) {
bail!(ErrorKind::ParachainOutOfOrder);
}
if !iter.any(|x| x == &head.parachain_index) {
// must be unknown since active parachains are always sorted.
bail!(ErrorKind::UnknownParachain(head.parachain_index))
}
last_id = Some(head.parachain_index);
}
}
Ok(proposal)
} }
+245 -351
View File
@@ -30,15 +30,12 @@
//! Groups themselves may be compromised by malicious authorities. //! Groups themselves may be compromised by malicious authorities.
extern crate parking_lot; extern crate parking_lot;
extern crate polkadot_api;
extern crate polkadot_availability_store as extrinsic_store; extern crate polkadot_availability_store as extrinsic_store;
extern crate polkadot_statement_table as table; extern crate polkadot_statement_table as table;
extern crate polkadot_parachain as parachain; extern crate polkadot_parachain as parachain;
extern crate polkadot_transaction_pool as transaction_pool;
extern crate polkadot_runtime; extern crate polkadot_runtime;
extern crate polkadot_primitives; extern crate polkadot_primitives;
extern crate substrate_bft as bft;
extern crate parity_codec as codec; extern crate parity_codec as codec;
extern crate substrate_primitives as primitives; extern crate substrate_primitives as primitives;
extern crate srml_support as runtime_support; extern crate srml_support as runtime_support;
@@ -47,7 +44,10 @@ extern crate substrate_client as client;
extern crate exit_future; extern crate exit_future;
extern crate tokio; extern crate tokio;
extern crate rhododendron; extern crate substrate_consensus_common as consensus;
extern crate substrate_consensus_aura as aura;
extern crate substrate_finality_grandpa as grandpa;
extern crate substrate_transaction_pool as transaction_pool;
#[macro_use] #[macro_use]
extern crate error_chain; extern crate error_chain;
@@ -65,40 +65,40 @@ use std::collections::{HashMap, HashSet};
use std::sync::Arc; use std::sync::Arc;
use std::time::{self, Duration, Instant}; use std::time::{self, Duration, Instant};
use aura::ExtraVerification;
use client::blockchain::HeaderBackend;
use client::block_builder::api::BlockBuilder;
use codec::{Decode, Encode}; use codec::{Decode, Encode};
use extrinsic_store::Store as ExtrinsicStore; use extrinsic_store::Store as ExtrinsicStore;
use polkadot_api::PolkadotApi; use parking_lot::Mutex;
use polkadot_primitives::{AccountId, Hash, Block, BlockId, BlockNumber, Header, Timestamp, SessionKey}; use polkadot_primitives::{Hash, Block, BlockId, BlockNumber, Header, Timestamp, SessionKey};
use polkadot_primitives::{Compact, UncheckedExtrinsic};
use polkadot_primitives::parachain::{Id as ParaId, Chain, DutyRoster, BlockData, Extrinsic as ParachainExtrinsic, CandidateReceipt, CandidateSignature}; use polkadot_primitives::parachain::{Id as ParaId, Chain, DutyRoster, BlockData, Extrinsic as ParachainExtrinsic, CandidateReceipt, CandidateSignature};
use polkadot_primitives::parachain::ParachainHost;
use primitives::{AuthorityId, ed25519}; use primitives::{AuthorityId, ed25519};
use transaction_pool::TransactionPool; use runtime_primitives::traits::ProvideRuntimeApi;
use tokio::runtime::TaskExecutor; use tokio::runtime::TaskExecutor;
use tokio::timer::{Delay, Interval}; use tokio::timer::{Delay, Interval};
use transaction_pool::txpool::{Pool, ChainApi as PoolChainApi};
use futures::prelude::*; use futures::prelude::*;
use futures::future; use futures::future::{self, Either};
use collation::CollationFetch; use collation::CollationFetch;
use dynamic_inclusion::DynamicInclusion; use dynamic_inclusion::DynamicInclusion;
use parking_lot::RwLock;
pub use self::collation::{validate_collation, Collators}; pub use self::collation::{validate_collation, Collators};
pub use self::error::{ErrorKind, Error}; pub use self::error::{ErrorKind, Error};
pub use self::offline_tracker::OfflineTracker;
pub use self::shared_table::{SharedTable, StatementProducer, ProducedStatements, Statement, SignedStatement, GenericStatement}; pub use self::shared_table::{SharedTable, StatementProducer, ProducedStatements, Statement, SignedStatement, GenericStatement};
pub use service::Service; pub use service::Service;
mod dynamic_inclusion; mod dynamic_inclusion;
mod evaluation; mod evaluation;
mod error; mod error;
mod offline_tracker;
mod service; mod service;
mod shared_table; mod shared_table;
pub mod collation; pub mod collation;
/// Shared offline validator tracker.
pub type SharedOfflineTracker = Arc<RwLock<OfflineTracker>>;
// block size limit. // block size limit.
const MAX_TRANSACTIONS_SIZE: usize = 4 * 1024 * 1024; const MAX_TRANSACTIONS_SIZE: usize = 4 * 1024 * 1024;
@@ -129,14 +129,14 @@ pub trait Network {
/// The table router type. This should handle importing of any statements, /// The table router type. This should handle importing of any statements,
/// routing statements to peers, and driving completion of any `StatementProducers`. /// routing statements to peers, and driving completion of any `StatementProducers`.
type TableRouter: TableRouter; type TableRouter: TableRouter;
/// The input stream of BFT messages. Should never logically conclude.
type Input: Stream<Item=bft::Communication<Block>,Error=Error>;
/// The output sink of BFT messages. Messages sent here should eventually pass to all
/// current authorities.
type Output: Sink<SinkItem=bft::Communication<Block>,SinkError=Error>;
/// Instantiate a table router using the given shared table and task executor. /// Instantiate a table router using the given shared table and task executor.
fn communication_for(&self, validators: &[SessionKey], table: Arc<SharedTable>, task_executor: TaskExecutor) -> (Self::TableRouter, Self::Input, Self::Output); fn communication_for(
&self,
validators: &[SessionKey],
table: Arc<SharedTable>,
task_executor: TaskExecutor
) -> Self::TableRouter;
} }
/// Information about a specific group. /// Information about a specific group.
@@ -157,7 +157,7 @@ pub struct GroupInfo {
/// parent hash. /// parent hash.
pub fn sign_table_statement(statement: &Statement, key: &ed25519::Pair, parent_hash: &Hash) -> CandidateSignature { pub fn sign_table_statement(statement: &Statement, key: &ed25519::Pair, parent_hash: &Hash) -> CandidateSignature {
let mut encoded = statement.encode(); let mut encoded = statement.encode();
encoded.extend(&parent_hash.0); encoded.extend(parent_hash.as_ref());
key.sign(&encoded).into() key.sign(&encoded).into()
} }
@@ -167,7 +167,7 @@ pub fn check_statement(statement: &Statement, signature: &CandidateSignature, si
use runtime_primitives::traits::Verify; use runtime_primitives::traits::Verify;
let mut encoded = statement.encode(); let mut encoded = statement.encode();
encoded.extend(&parent_hash.0); encoded.extend(parent_hash.as_ref());
signature.verify(&encoded[..], &signer.into()) signature.verify(&encoded[..], &signer.into())
} }
@@ -229,62 +229,58 @@ fn make_group_info(roster: DutyRoster, authorities: &[AuthorityId], local_id: Au
} }
} }
/// Polkadot proposer factory. /// Constructs parachain-agreement instances.
pub struct ProposerFactory<C, N, P> struct ParachainConsensus<C, N, P> {
where
P: PolkadotApi + Send + Sync + 'static
{
/// The client instance. /// The client instance.
pub client: Arc<P>, client: Arc<P>,
/// The transaction pool.
pub transaction_pool: Arc<TransactionPool<P>>,
/// The backing network handle. /// The backing network handle.
pub network: N, network: N,
/// Parachain collators. /// Parachain collators.
pub collators: C, collators: C,
/// handle to remote task executor /// handle to remote task executor
pub handle: TaskExecutor, handle: TaskExecutor,
/// The duration after which parachain-empty blocks will be allowed.
pub parachain_empty_duration: Duration,
/// Store for extrinsic data. /// Store for extrinsic data.
pub extrinsic_store: ExtrinsicStore, extrinsic_store: ExtrinsicStore,
/// Offline-tracker. /// The time after which no parachains may be included.
pub offline: SharedOfflineTracker, parachain_empty_duration: Duration,
/// Live agreements.
live_instances: Mutex<HashMap<Hash, Arc<AttestationTracker>>>,
} }
impl<C, N, P> bft::Environment<Block> for ProposerFactory<C, N, P> impl<C, N, P> ParachainConsensus<C, N, P> where
where C: Collators + Send + 'static,
C: Collators + Send + 'static, N: Network,
N: Network, P: ProvideRuntimeApi + HeaderBackend<Block> + Send + Sync + 'static,
P: PolkadotApi + Send + Sync + 'static, P::Api: ParachainHost<Block> + BlockBuilder<Block>,
<C::Collation as IntoFuture>::Future: Send + 'static, <C::Collation as IntoFuture>::Future: Send + 'static,
N::TableRouter: Send + 'static, N::TableRouter: Send + 'static,
{ {
type Proposer = Proposer<P>; /// Get an attestation table for given parent hash.
type Input = N::Input; ///
type Output = N::Output; /// This starts a parachain agreement process for given parent hash if
type Error = Error; /// one has not already started.
fn get_or_instantiate(
fn init(
&self, &self,
parent_header: &Header, parent_hash: Hash,
authorities: &[AuthorityId], authorities: &[AuthorityId],
sign_with: Arc<ed25519::Pair>, sign_with: Arc<ed25519::Pair>,
) -> Result<(Self::Proposer, Self::Input, Self::Output), Error> { )
-> Result<Arc<AttestationTracker>, Error>
{
use runtime_primitives::traits::{Hash as HashT, BlakeTwo256}; use runtime_primitives::traits::{Hash as HashT, BlakeTwo256};
// force delay in evaluation this long. let mut live_instances = self.live_instances.lock();
const FORCE_DELAY: Timestamp = 5; if let Some(tracker) = live_instances.get(&parent_hash) {
return Ok(tracker.clone());
let parent_hash = parent_header.hash().into(); }
let id = BlockId::hash(parent_hash); let id = BlockId::hash(parent_hash);
let duty_roster = self.client.duty_roster(&id)?; let duty_roster = self.client.runtime_api().duty_roster(&id)?;
let random_seed = self.client.random_seed(&id)?; let random_seed = self.client.runtime_api().random_seed(&id)?;
let random_seed = BlakeTwo256::hash(&*random_seed); let _random_seed = BlakeTwo256::hash(random_seed.as_ref());
let validators = self.client.validators(&id)?; let _validators = self.client.runtime_api().validators(&id)?;
self.offline.write().note_new_block(&validators[..]);
let (group_info, local_duty) = make_group_info( let (group_info, local_duty) = make_group_info(
duty_roster, duty_roster,
@@ -292,28 +288,21 @@ impl<C, N, P> bft::Environment<Block> for ProposerFactory<C, N, P>
sign_with.public().into(), sign_with.public().into(),
)?; )?;
info!("Starting consensus session on top of parent {:?}. Local parachain duty is {:?}", info!("Starting parachain attestation session on top of parent {:?}. Local parachain duty is {:?}",
parent_hash, local_duty.validation); parent_hash, local_duty.validation);
let active_parachains = self.client.active_parachains(&id)?; let active_parachains = self.client.runtime_api().active_parachains(&id)?;
debug!(target: "consensus", "Active parachains: {:?}", active_parachains); debug!(target: "consensus", "Active parachains: {:?}", active_parachains);
let n_parachains = active_parachains.len(); let _n_parachains = active_parachains.len();
let table = Arc::new(SharedTable::new(group_info, sign_with.clone(), parent_hash, self.extrinsic_store.clone())); let table = Arc::new(SharedTable::new(group_info, sign_with.clone(), parent_hash, self.extrinsic_store.clone()));
let (router, input, output) = self.network.communication_for( let router = self.network.communication_for(
authorities, authorities,
table.clone(), table.clone(),
self.handle.clone() self.handle.clone()
); );
let now = Instant::now();
let dynamic_inclusion = DynamicInclusion::new(
n_parachains,
now,
self.parachain_empty_duration.clone(),
);
let validation_para = match local_duty.validation { let validation_para = match local_duty.validation {
Chain::Relay => None, Chain::Relay => None,
Chain::Parachain(id) => Some(id), Chain::Parachain(id) => Some(id),
@@ -326,6 +315,7 @@ impl<C, N, P> bft::Environment<Block> for ProposerFactory<C, N, P>
self.collators.clone(), self.collators.clone(),
self.client.clone(), self.client.clone(),
)); ));
let drop_signal = dispatch_collation_work( let drop_signal = dispatch_collation_work(
router.clone(), router.clone(),
&self.handle, &self.handle,
@@ -333,23 +323,96 @@ impl<C, N, P> bft::Environment<Block> for ProposerFactory<C, N, P>
self.extrinsic_store.clone(), self.extrinsic_store.clone(),
); );
let proposer = Proposer { let now = Instant::now();
client: self.client.clone(), let dynamic_inclusion = DynamicInclusion::new(
dynamic_inclusion, table.num_parachains(),
local_key: sign_with, now,
parent_hash, self.parachain_empty_duration.clone(),
parent_id: id, );
parent_number: parent_header.number,
random_seed,
table,
transaction_pool: self.transaction_pool.clone(),
offline: self.offline.clone(),
validators,
minimum_timestamp: current_timestamp() + FORCE_DELAY,
_drop_signal: drop_signal,
};
Ok((proposer, input, output)) let tracker = Arc::new(AttestationTracker {
table,
dynamic_inclusion,
_drop_signal: drop_signal
});
live_instances.insert(parent_hash, tracker.clone());
Ok(tracker)
}
/// Retain consensus sessions matching predicate.
fn retain<F: FnMut(&Hash) -> bool>(&self, mut pred: F) {
self.live_instances.lock().retain(|k, _| pred(k))
}
}
/// Parachain consensus for a single block.
struct AttestationTracker {
_drop_signal: exit_future::Signal,
table: Arc<SharedTable>,
dynamic_inclusion: DynamicInclusion,
}
/// Polkadot proposer factory.
struct ProposerFactory<C, N, P, TxApi: PoolChainApi> {
parachain_consensus: Arc<ParachainConsensus<C, N, P>>,
transaction_pool: Arc<Pool<TxApi>>,
}
impl<C, N, P, TxApi> ProposerFactory<C, N, P, TxApi> where
TxApi: PoolChainApi,
{
/// Create a new proposer factory.
fn new(
parachain_consensus: Arc<ParachainConsensus<C, N, P>>,
transaction_pool: Arc<Pool<TxApi>>,
) -> Self {
ProposerFactory {
parachain_consensus,
transaction_pool,
}
}
}
impl<C, N, P, TxApi> consensus::Environment<Block> for ProposerFactory<C, N, P, TxApi> where
C: Collators + Send + 'static,
N: Network,
TxApi: PoolChainApi<Block=Block>,
P: ProvideRuntimeApi + HeaderBackend<Block> + Send + Sync + 'static,
P::Api: ParachainHost<Block> + BlockBuilder<Block>,
<C::Collation as IntoFuture>::Future: Send + 'static,
N::TableRouter: Send + 'static,
{
type Proposer = Proposer<P, TxApi>;
type Error = Error;
fn init(
&self,
parent_header: &Header,
authorities: &[AuthorityId],
sign_with: Arc<ed25519::Pair>,
) -> Result<Self::Proposer, Error> {
// force delay in evaluation this long.
const FORCE_DELAY: Timestamp = Compact(5);
let parent_hash = parent_header.hash();
let parent_id = BlockId::hash(parent_hash);
let tracker = self.parachain_consensus.get_or_instantiate(
parent_hash,
authorities,
sign_with,
)?;
Ok(Proposer {
client: self.parachain_consensus.client.clone(),
tracker,
parent_hash,
parent_id,
parent_number: parent_header.number,
transaction_pool: self.transaction_pool.clone(),
minimum_timestamp: current_timestamp().0 + FORCE_DELAY.0,
})
} }
} }
@@ -362,7 +425,8 @@ fn dispatch_collation_work<R, C, P>(
extrinsic_store: ExtrinsicStore, extrinsic_store: ExtrinsicStore,
) -> exit_future::Signal where ) -> exit_future::Signal where
C: Collators + Send + 'static, C: Collators + Send + 'static,
P: PolkadotApi + Send + Sync + 'static, P: ProvideRuntimeApi + HeaderBackend<Block> + Send + Sync + 'static,
P::Api: ParachainHost<Block>,
<C::Collation as IntoFuture>::Future: Send + 'static, <C::Collation as IntoFuture>::Future: Send + 'static,
R: TableRouter + Send + 'static, R: TableRouter + Send + 'static,
{ {
@@ -413,50 +477,35 @@ struct LocalDuty {
} }
/// The Polkadot proposer logic. /// The Polkadot proposer logic.
pub struct Proposer<C: PolkadotApi + Send + Sync> { pub struct Proposer<C: Send + Sync, TxApi: PoolChainApi> where
C: ProvideRuntimeApi + HeaderBackend<Block>,
{
client: Arc<C>, client: Arc<C>,
dynamic_inclusion: DynamicInclusion,
local_key: Arc<ed25519::Pair>,
parent_hash: Hash, parent_hash: Hash,
parent_id: BlockId, parent_id: BlockId,
parent_number: BlockNumber, parent_number: BlockNumber,
random_seed: Hash, tracker: Arc<AttestationTracker>,
table: Arc<SharedTable>, transaction_pool: Arc<Pool<TxApi>>,
transaction_pool: Arc<TransactionPool<C>>,
offline: SharedOfflineTracker,
validators: Vec<AccountId>,
minimum_timestamp: u64, minimum_timestamp: u64,
_drop_signal: exit_future::Signal,
} }
impl<C: PolkadotApi + Send + Sync> Proposer<C> { impl<C, TxApi> consensus::Proposer<Block> for Proposer<C, TxApi> where
fn primary_index(&self, round_number: usize, len: usize) -> usize { TxApi: PoolChainApi<Block=Block>,
use primitives::uint::U256; C: ProvideRuntimeApi + HeaderBackend<Block> + Send + Sync,
C::Api: ParachainHost<Block> + BlockBuilder<Block>,
let big_len = U256::from(len);
let offset = U256::from_big_endian(&self.random_seed.0) % big_len;
let offset = offset.low_u64() as usize + round_number;
offset % len
}
}
impl<C> bft::Proposer<Block> for Proposer<C>
where
C: PolkadotApi + Send + Sync,
{ {
type Error = Error; type Error = Error;
type Create = future::Either< type Create = Either<
CreateProposal<C>, CreateProposal<C, TxApi>,
future::FutureResult<Block, Error>, future::FutureResult<Block, Error>,
>; >;
type Evaluate = Box<Future<Item=bool, Error=Error>>;
fn propose(&self) -> Self::Create { fn propose(&self) -> Self::Create {
const ATTEMPT_PROPOSE_EVERY: Duration = Duration::from_millis(100); const ATTEMPT_PROPOSE_EVERY: Duration = Duration::from_millis(100);
let initial_included = self.table.includable_count(); let initial_included = self.tracker.table.includable_count();
let now = Instant::now(); let now = Instant::now();
let enough_candidates = self.dynamic_inclusion.acceptable_in( let enough_candidates = self.tracker.dynamic_inclusion.acceptable_in(
now, now,
initial_included, initial_included,
).unwrap_or_else(|| now + Duration::from_millis(1)); ).unwrap_or_else(|| now + Duration::from_millis(1));
@@ -464,216 +513,69 @@ impl<C> bft::Proposer<Block> for Proposer<C>
let timing = ProposalTiming { let timing = ProposalTiming {
attempt_propose: Interval::new(now + ATTEMPT_PROPOSE_EVERY, ATTEMPT_PROPOSE_EVERY), attempt_propose: Interval::new(now + ATTEMPT_PROPOSE_EVERY, ATTEMPT_PROPOSE_EVERY),
enough_candidates: Delay::new(enough_candidates), enough_candidates: Delay::new(enough_candidates),
dynamic_inclusion: self.dynamic_inclusion.clone(), dynamic_inclusion: self.tracker.dynamic_inclusion.clone(),
last_included: initial_included, last_included: initial_included,
}; };
future::Either::A(CreateProposal { Either::A(CreateProposal {
parent_hash: self.parent_hash.clone(), parent_hash: self.parent_hash.clone(),
parent_number: self.parent_number.clone(), parent_number: self.parent_number.clone(),
parent_id: self.parent_id.clone(), parent_id: self.parent_id.clone(),
client: self.client.clone(), client: self.client.clone(),
transaction_pool: self.transaction_pool.clone(), transaction_pool: self.transaction_pool.clone(),
table: self.table.clone(), table: self.tracker.table.clone(),
offline: self.offline.clone(), minimum_timestamp: self.minimum_timestamp.into(),
validators: self.validators.clone(),
minimum_timestamp: self.minimum_timestamp,
timing, timing,
}) })
} }
}
fn evaluate(&self, unchecked_proposal: &Block) -> Self::Evaluate { /// Does verification before importing blocks.
debug!(target: "bft", "evaluating block on top of parent ({}, {:?})", self.parent_number, self.parent_hash); /// Should be used for further verification in aura.
pub struct BlockVerifier;
let active_parachains = match self.client.active_parachains(&self.parent_id) { impl ExtraVerification<Block> for BlockVerifier {
Ok(x) => x, type Verified = Either<
Err(e) => return Box::new(future::err(e.into())) as Box<_>, future::FutureResult<(), String>,
Box<dyn Future<Item=(), Error=String>>,
>;
fn verify(&self, _header: &Header, body: Option<&[UncheckedExtrinsic]>) -> Self::Verified {
use polkadot_runtime::{Call, UncheckedExtrinsic, TimestampCall};
let body = match body {
None => return Either::A(future::ok(())),
Some(body) => body,
}; };
let current_timestamp = current_timestamp(); // TODO: reintroduce or revisit necessaity for includability tracker.
let timestamp = current_timestamp();
// do initial serialization and structural integrity checks. let maybe_in_block = body.iter()
let maybe_proposal = evaluation::evaluate_initial( .filter_map(|ex| {
unchecked_proposal, let encoded = ex.encode();
current_timestamp, let runtime_ex = UncheckedExtrinsic::decode(&mut &encoded[..])?;
&self.parent_hash, match runtime_ex.function {
self.parent_number, Call::Timestamp(TimestampCall::set(t)) => Some(t),
&active_parachains, _ => None,
); }
})
.next();
let proposal = match maybe_proposal { let timestamp_in_block = match maybe_in_block {
Ok(p) => p, None => return Either::A(future::ok(())),
Err(e) => { Some(t) => t,
// TODO: these errors are easily re-checked in runtime.
debug!(target: "bft", "Invalid proposal: {:?}", e);
return Box::new(future::ok(false));
}
}; };
let vote_delays = { // we wait until the block timestamp is earlier than current.
let now = Instant::now(); if timestamp.0 < timestamp_in_block.0 {
let diff_secs = timestamp_in_block.0 - timestamp.0;
let included_candidate_hashes = proposal let delay = Delay::new(Instant::now() + Duration::from_secs(diff_secs))
.parachain_heads() .map_err(move |e| format!("Error waiting for {} seconds: {:?}", diff_secs, e));
.iter() Either::B(Box::new(delay))
.map(|candidate| candidate.hash()); } else {
Either::A(future::ok(()))
// delay casting vote until we have proof that all candidates are
// includable.
let includability_tracker = self.table.track_includability(included_candidate_hashes)
.map_err(|_| ErrorKind::PrematureDestruction.into());
// the duration at which the given number of parachains is acceptable.
let count_delay = self.dynamic_inclusion.acceptable_in(
now,
proposal.parachain_heads().len(),
);
// the duration until the given timestamp is current
let proposed_timestamp = ::std::cmp::max(self.minimum_timestamp, proposal.timestamp());
let timestamp_delay = if proposed_timestamp > current_timestamp {
let delay_s = proposed_timestamp - current_timestamp;
debug!(target: "bft", "Delaying evaluation of proposal for {} seconds", delay_s);
Some(now + Duration::from_secs(delay_s))
} else {
None
};
// delay casting vote until able according to minimum block time,
// timestamp delay, and count delay.
// construct a future from the maximum of the two durations.
let max_delay = ::std::cmp::max(timestamp_delay, count_delay);
let temporary_delay = match max_delay {
Some(duration) => future::Either::A(
Delay::new(duration).map_err(|e| Error::from(ErrorKind::Timer(e)))
),
None => future::Either::B(future::ok(())),
};
includability_tracker.join(temporary_delay)
};
// refuse to vote if this block says a validator is offline that we
// think isn't.
let offline = proposal.noted_offline();
if !self.offline.read().check_consistency(&self.validators[..], offline) {
return Box::new(futures::empty());
} }
// evaluate whether the block is actually valid.
// TODO: is it better to delay this until the delays are finished?
let evaluated = self.client
.evaluate_block(&self.parent_id, unchecked_proposal.clone())
.map_err(Into::into);
let future = future::result(evaluated).and_then(move |good| {
let end_result = future::ok(good);
if good {
// delay a "good" vote.
future::Either::A(vote_delays.and_then(|_| end_result))
} else {
// don't delay a "bad" evaluation.
future::Either::B(end_result)
}
});
Box::new(future) as Box<_>
}
fn round_proposer(&self, round_number: usize, authorities: &[AuthorityId]) -> AuthorityId {
let offset = self.primary_index(round_number, authorities.len());
let proposer = authorities[offset].clone();
trace!(target: "bft", "proposer for round {} is {}", round_number, proposer);
proposer
}
fn import_misbehavior(&self, misbehavior: Vec<(AuthorityId, bft::Misbehavior<Hash>)>) {
use rhododendron::Misbehavior as GenericMisbehavior;
use runtime_primitives::bft::{MisbehaviorKind, MisbehaviorReport};
use polkadot_runtime::{Call, UncheckedExtrinsic, ConsensusCall, RawAddress};
let local_id = self.local_key.public().0.into();
let mut next_index = {
let cur_index = self.transaction_pool.cull_and_get_pending(&BlockId::hash(self.parent_hash), |pending| pending
.filter(|tx| tx.verified.sender().map(|s| s == local_id).unwrap_or(false))
.last()
.map(|tx| Ok(tx.verified.index()))
.unwrap_or_else(|| self.client.index(&self.parent_id, local_id))
);
match cur_index {
Ok(Ok(cur_index)) => cur_index + 1,
Ok(Err(e)) => {
warn!(target: "consensus", "Error computing next transaction index: {}", e);
return;
}
Err(e) => {
warn!(target: "consensus", "Error computing next transaction index: {}", e);
return;
}
}
};
for (target, misbehavior) in misbehavior {
let report = MisbehaviorReport {
parent_hash: self.parent_hash,
parent_number: self.parent_number,
target,
misbehavior: match misbehavior {
GenericMisbehavior::ProposeOutOfTurn(_, _, _) => continue,
GenericMisbehavior::DoublePropose(_, _, _) => continue,
GenericMisbehavior::DoublePrepare(round, (h1, s1), (h2, s2))
=> MisbehaviorKind::BftDoublePrepare(round as u32, (h1, s1.signature), (h2, s2.signature)),
GenericMisbehavior::DoubleCommit(round, (h1, s1), (h2, s2))
=> MisbehaviorKind::BftDoubleCommit(round as u32, (h1, s1.signature), (h2, s2.signature)),
}
};
let payload = (next_index, Call::Consensus(ConsensusCall::report_misbehavior(report)));
let signature = self.local_key.sign(&payload.encode()).into();
next_index += 1;
let local_id = self.local_key.public().0.into();
let extrinsic = UncheckedExtrinsic {
signature: Some((RawAddress::Id(local_id), signature)),
index: payload.0,
function: payload.1,
};
let uxt: Vec<u8> = Decode::decode(&mut extrinsic.encode().as_slice()).expect("Encoded extrinsic is valid");
self.transaction_pool.submit_one(&BlockId::hash(self.parent_hash), polkadot_primitives::UncheckedExtrinsic(uxt))
.expect("locally signed extrinsic is valid; qed");
}
}
fn on_round_end(&self, round_number: usize, was_proposed: bool) {
let primary_validator = self.validators[
self.primary_index(round_number, self.validators.len())
];
// alter the message based on whether we think the empty proposer was forced to skip the round.
// this is determined by checking if our local validator would have been forced to skip the round.
let consider_online = was_proposed || {
let forced_delay = self.dynamic_inclusion.acceptable_in(Instant::now(), self.table.includable_count());
let public = ed25519::Public::from_raw(primary_validator.0);
match forced_delay {
None => info!(
"Potential Offline Validator: {} failed to propose during assigned slot: {}",
public,
round_number,
),
Some(_) => info!(
"Potential Offline Validator {} potentially forced to skip assigned slot: {}",
public,
round_number,
),
}
forced_delay.is_some()
};
self.offline.write().note_round_end(primary_validator, consider_online);
} }
} }
@@ -681,6 +583,7 @@ fn current_timestamp() -> Timestamp {
time::SystemTime::now().duration_since(time::UNIX_EPOCH) time::SystemTime::now().duration_since(time::UNIX_EPOCH)
.expect("now always later than unix epoch; qed") .expect("now always later than unix epoch; qed")
.as_secs() .as_secs()
.into()
} }
struct ProposalTiming { struct ProposalTiming {
@@ -721,75 +624,62 @@ impl ProposalTiming {
} }
/// Future which resolves upon the creation of a proposal. /// Future which resolves upon the creation of a proposal.
pub struct CreateProposal<C: PolkadotApi + Send + Sync> { pub struct CreateProposal<C: Send + Sync, TxApi: PoolChainApi> {
parent_hash: Hash, parent_hash: Hash,
parent_number: BlockNumber, parent_number: BlockNumber,
parent_id: BlockId, parent_id: BlockId,
client: Arc<C>, client: Arc<C>,
transaction_pool: Arc<TransactionPool<C>>, transaction_pool: Arc<Pool<TxApi>>,
table: Arc<SharedTable>, table: Arc<SharedTable>,
timing: ProposalTiming, timing: ProposalTiming,
validators: Vec<AccountId>,
offline: SharedOfflineTracker,
minimum_timestamp: Timestamp, minimum_timestamp: Timestamp,
} }
impl<C> CreateProposal<C> where C: PolkadotApi + Send + Sync { impl<C, TxApi> CreateProposal<C, TxApi> where
TxApi: PoolChainApi<Block=Block>,
C: ProvideRuntimeApi + HeaderBackend<Block> + Send + Sync,
C::Api: ParachainHost<Block> + BlockBuilder<Block>,
{
fn propose_with(&self, candidates: Vec<CandidateReceipt>) -> Result<Block, Error> { fn propose_with(&self, candidates: Vec<CandidateReceipt>) -> Result<Block, Error> {
use polkadot_api::BlockBuilder; use client::block_builder::BlockBuilder;
use runtime_primitives::traits::{Hash as HashT, BlakeTwo256}; use runtime_primitives::traits::{Hash as HashT, BlakeTwo256};
use polkadot_primitives::InherentData; use polkadot_primitives::InherentData;
const MAX_VOTE_OFFLINE_SECONDS: Duration = Duration::from_secs(60);
// TODO: handle case when current timestamp behind that in state. // TODO: handle case when current timestamp behind that in state.
let timestamp = ::std::cmp::max(self.minimum_timestamp, current_timestamp()); let timestamp = ::std::cmp::max(self.minimum_timestamp.0, current_timestamp().0).into();
let elapsed_since_start = self.timing.dynamic_inclusion.started_at().elapsed(); let _elapsed_since_start = self.timing.dynamic_inclusion.started_at().elapsed();
let offline_indices = if elapsed_since_start > MAX_VOTE_OFFLINE_SECONDS {
Vec::new()
} else {
self.offline.read().reports(&self.validators[..])
};
if !offline_indices.is_empty() { let _inherent_data = InherentData {
info!(
"Submitting offline validators {:?} for slash-vote",
offline_indices.iter().map(|&i| self.validators[i as usize]).collect::<Vec<_>>(),
)
}
let inherent_data = InherentData {
timestamp, timestamp,
parachain_heads: candidates, parachain_heads: candidates,
offline_indices,
}; };
let mut block_builder = self.client.build_block(&self.parent_id, inherent_data)?; let mut block_builder = BlockBuilder::at_block(&self.parent_id, &*self.client)?;
{ {
let mut unqueue_invalid = Vec::new(); let mut unqueue_invalid = Vec::new();
let result = self.transaction_pool.cull_and_get_pending(&BlockId::hash(self.parent_hash), |pending_iterator| { let mut pending_size = 0;
let mut pending_size = 0;
for pending in pending_iterator {
if pending_size + pending.verified.encoded_size() >= MAX_TRANSACTIONS_SIZE { break }
match block_builder.push_extrinsic(pending.original.clone()) { let ready_iter = self.transaction_pool.ready();
Ok(()) => { for ready in ready_iter {
pending_size += pending.verified.encoded_size(); let encoded_size = ready.data.encode().len();
} if pending_size + encoded_size >= MAX_TRANSACTIONS_SIZE {
Err(e) => { break
trace!(target: "transaction-pool", "Invalid transaction: {}", e); }
unqueue_invalid.push(pending.verified.hash().clone());
} match block_builder.push(ready.data.clone()) {
Ok(()) => {
pending_size += encoded_size;
}
Err(e) => {
trace!(target: "transaction-pool", "Invalid transaction: {}", e);
unqueue_invalid.push(ready.hash.clone());
} }
} }
});
if let Err(e) = result {
warn!("Unable to get the pending set: {:?}", e);
} }
self.transaction_pool.remove(&unqueue_invalid, false); self.transaction_pool.remove_invalid(&unqueue_invalid);
} }
let polkadot_block = block_builder.bake()?; let polkadot_block = block_builder.bake()?;
@@ -808,7 +698,7 @@ impl<C> CreateProposal<C> where C: PolkadotApi + Send + Sync {
.expect("polkadot blocks defined to serialize to substrate blocks correctly; qed"); .expect("polkadot blocks defined to serialize to substrate blocks correctly; qed");
// TODO: full re-evaluation // TODO: full re-evaluation
let active_parachains = self.client.active_parachains(&self.parent_id)?; let active_parachains = self.client.runtime_api().active_parachains(&self.parent_id)?;
assert!(evaluation::evaluate_initial( assert!(evaluation::evaluate_initial(
&substrate_block, &substrate_block,
timestamp, timestamp,
@@ -821,7 +711,11 @@ impl<C> CreateProposal<C> where C: PolkadotApi + Send + Sync {
} }
} }
impl<C> Future for CreateProposal<C> where C: PolkadotApi + Send + Sync { impl<C, TxApi> Future for CreateProposal<C, TxApi> where
TxApi: PoolChainApi<Block=Block>,
C: ProvideRuntimeApi + HeaderBackend<Block> + Send + Sync,
C::Api: ParachainHost<Block> + BlockBuilder<Block>,
{
type Item = Block; type Item = Block;
type Error = Error; type Error = Error;
-167
View File
@@ -1,167 +0,0 @@
// Copyright 2018 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Tracks offline validators.
use polkadot_primitives::AccountId;
use std::collections::HashMap;
use std::time::{Instant, Duration};
struct Observed {
last_round_end: Instant,
offline_since: Instant,
}
#[derive(Eq, PartialEq)]
enum Activity {
Offline,
StillOffline(Duration),
Online,
}
impl Observed {
fn new() -> Observed {
let now = Instant::now();
Observed {
last_round_end: now,
offline_since: now,
}
}
fn note_round_end(&mut self, now: Instant, was_online: Option<bool>) {
self.last_round_end = now;
if let Some(false) = was_online {
self.offline_since = now;
}
}
/// Returns what we have observed about the online/offline state of the validator.
fn activity(&self) -> Activity {
// can happen if clocks are not monotonic
if self.offline_since > self.last_round_end { return Activity::Online }
if self.offline_since == self.last_round_end { return Activity::Offline }
Activity::StillOffline(self.last_round_end.duration_since(self.offline_since))
}
}
/// Tracks offline validators and can issue a report for those offline.
pub struct OfflineTracker {
observed: HashMap<AccountId, Observed>,
block_instant: Instant,
}
impl OfflineTracker {
/// Create a new tracker.
pub fn new() -> Self {
OfflineTracker { observed: HashMap::new(), block_instant: Instant::now() }
}
/// Note new consensus is starting with the given set of validators.
pub fn note_new_block(&mut self, validators: &[AccountId]) {
use std::collections::HashSet;
let set: HashSet<_> = validators.iter().cloned().collect();
self.observed.retain(|k, _| set.contains(k));
self.block_instant = Instant::now();
}
/// Note that a round has ended.
pub fn note_round_end(&mut self, validator: AccountId, was_online: bool) {
self.observed.entry(validator).or_insert_with(Observed::new);
for (val, obs) in self.observed.iter_mut() {
obs.note_round_end(
self.block_instant,
if val == &validator {
Some(was_online)
} else {
None
}
)
}
}
/// Generate a vector of indices for offline account IDs.
pub fn reports(&self, validators: &[AccountId]) -> Vec<u32> {
validators.iter()
.enumerate()
.filter_map(|(i, v)| if self.is_known_offline_now(v) {
Some(i as u32)
} else {
None
})
.collect()
}
/// Whether reports on a validator set are consistent with our view of things.
pub fn check_consistency(&self, validators: &[AccountId], reports: &[u32]) -> bool {
reports.iter().cloned().all(|r| {
let v = match validators.get(r as usize) {
Some(v) => v,
None => return false,
};
// we must think all validators reported externally are offline.
self.is_known_offline_now(v)
})
}
/// Rwturns true only if we have seen the validator miss the last round. For further
/// rounds where we can't say for sure that they're still offline, we give them the
/// benefit of the doubt.
fn is_known_offline_now(&self, v: &AccountId) -> bool {
self.observed.get(v).map(|o| o.activity() == Activity::Offline).unwrap_or(false)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn validator_offline() {
let mut tracker = OfflineTracker::new();
let v = [0; 32].into();
let v2 = [1; 32].into();
let v3 = [2; 32].into();
tracker.note_new_block(&[v, v2, v3]);
tracker.note_round_end(v, true);
tracker.note_round_end(v2, true);
tracker.note_round_end(v3, true);
assert_eq!(tracker.reports(&[v, v2, v3]), vec![0u32; 0]);
tracker.note_new_block(&[v, v2, v3]);
tracker.note_round_end(v, true);
tracker.note_round_end(v2, false);
tracker.note_round_end(v3, true);
assert_eq!(tracker.reports(&[v, v2, v3]), vec![1]);
tracker.note_new_block(&[v, v2, v3]);
tracker.note_round_end(v, false);
assert_eq!(tracker.reports(&[v, v2, v3]), vec![0]);
tracker.note_new_block(&[v, v2, v3]);
tracker.note_round_end(v, false);
tracker.note_round_end(v2, true);
tracker.note_round_end(v3, false);
assert_eq!(tracker.reports(&[v, v2, v3]), vec![0, 2]);
tracker.note_new_block(&[v, v2]);
tracker.note_round_end(v, false);
assert_eq!(tracker.reports(&[v, v2, v3]), vec![0]);
}
}
+93 -95
View File
@@ -27,47 +27,23 @@ use std::thread;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use std::sync::Arc; use std::sync::Arc;
use bft::{self, BftService};
use client::{BlockchainEvents, ChainHead, BlockBody}; use client::{BlockchainEvents, ChainHead, BlockBody};
use client::block_builder::api::BlockBuilder;
use client::blockchain::HeaderBackend;
use client::runtime_api::Core;
use primitives::ed25519; use primitives::ed25519;
use futures::prelude::*; use futures::prelude::*;
use polkadot_api::LocalPolkadotApi; use polkadot_primitives::{Block, BlockId};
use polkadot_primitives::{Block, Header}; use polkadot_primitives::parachain::ParachainHost;
use transaction_pool::TransactionPool;
use extrinsic_store::Store as ExtrinsicStore; use extrinsic_store::Store as ExtrinsicStore;
use runtime_primitives::traits::ProvideRuntimeApi;
use transaction_pool::txpool::{ChainApi as PoolChainApi, Pool};
use tokio::executor::current_thread::TaskExecutor as LocalThreadHandle;
use tokio::runtime::TaskExecutor as ThreadPoolHandle; use tokio::runtime::TaskExecutor as ThreadPoolHandle;
use tokio::runtime::current_thread::Runtime as LocalRuntime; use tokio::runtime::current_thread::Runtime as LocalRuntime;
use tokio::timer::Interval; use tokio::timer::Interval;
use super::{Network, Collators, ProposerFactory}; use super::{Network, Collators, ProposerFactory};
use error;
const TIMER_DELAY_MS: u64 = 5000;
const TIMER_INTERVAL_MS: u64 = 500;
// spin up an instance of BFT agreement on the current thread's executor.
// panics if there is no current thread executor.
fn start_bft<F, C>(
header: Header,
bft_service: Arc<BftService<Block, F, C>>,
) where
F: bft::Environment<Block> + 'static,
C: bft::BlockImport<Block> + bft::Authorities<Block> + 'static,
F::Error: ::std::fmt::Debug,
<F::Proposer as bft::Proposer<Block>>::Error: ::std::fmt::Display + Into<error::Error>,
<F as bft::Environment<Block>>::Error: ::std::fmt::Display
{
let mut handle = LocalThreadHandle::current();
match bft_service.build_upon(&header) {
Ok(Some(bft_work)) => if let Err(e) = handle.spawn_local(Box::new(bft_work)) {
warn!(target: "bft", "Couldn't initialize BFT agreement: {:?}", e);
}
Ok(None) => trace!(target: "bft", "Could not start agreement on top of {}", header.hash()),
Err(e) => warn!(target: "bft", "BFT agreement error: {}", e),
}
}
// creates a task to prune redundant entries in availability store upon block finalization // creates a task to prune redundant entries in availability store upon block finalization
// //
@@ -79,13 +55,11 @@ fn prune_unneeded_availability<C>(client: Arc<C>, extrinsic_store: ExtrinsicStor
{ {
use codec::{Encode, Decode}; use codec::{Encode, Decode};
use polkadot_primitives::BlockId; use polkadot_primitives::BlockId;
use polkadot_runtime::CheckedBlock;
enum NotifyError { enum NotifyError {
NoBody, NoBody,
BodyFetch(::client::error::Error), BodyFetch(::client::error::Error),
UnexpectedFormat, UnexpectedFormat,
ExtrinsicsWrong,
} }
impl NotifyError { impl NotifyError {
@@ -94,31 +68,43 @@ fn prune_unneeded_availability<C>(client: Arc<C>, extrinsic_store: ExtrinsicStor
NotifyError::NoBody => warn!("No block body for imported block {:?}", hash), NotifyError::NoBody => warn!("No block body for imported block {:?}", hash),
NotifyError::BodyFetch(ref err) => warn!("Failed to fetch block body for imported block {:?}: {:?}", hash, err), NotifyError::BodyFetch(ref err) => warn!("Failed to fetch block body for imported block {:?}: {:?}", hash, err),
NotifyError::UnexpectedFormat => warn!("Consensus outdated: Block {:?} has unexpected body format", hash), NotifyError::UnexpectedFormat => warn!("Consensus outdated: Block {:?} has unexpected body format", hash),
NotifyError::ExtrinsicsWrong => warn!("Consensus outdated: Extrinsics cannot be decoded for {:?}", hash),
} }
} }
} }
client.import_notification_stream() client.finality_notification_stream()
.for_each(move |notification| { .for_each(move |notification| {
use polkadot_runtime::{Call, ParachainsCall};
let hash = notification.hash; let hash = notification.hash;
let parent_hash = notification.header.parent_hash; let parent_hash = notification.header.parent_hash;
let checked_block = client.block_body(&BlockId::hash(hash)) let runtime_block = client.block_body(&BlockId::hash(hash))
.map_err(NotifyError::BodyFetch) .map_err(NotifyError::BodyFetch)
.and_then(|maybe_body| maybe_body.ok_or(NotifyError::NoBody)) .and_then(|maybe_body| maybe_body.ok_or(NotifyError::NoBody))
.map(|extrinsics| Block { header: notification.header, extrinsics }) .map(|extrinsics| Block { header: notification.header, extrinsics })
.map(|b: Block| ::polkadot_runtime::Block::decode(&mut b.encode().as_slice())) .map(|b: Block| ::polkadot_runtime::Block::decode(&mut b.encode().as_slice()))
.and_then(|maybe_block| maybe_block.ok_or(NotifyError::UnexpectedFormat)) .and_then(|maybe_block| maybe_block.ok_or(NotifyError::UnexpectedFormat));
.and_then(|block| CheckedBlock::new(block).map_err(|_| NotifyError::ExtrinsicsWrong));
match checked_block { let runtime_block = match runtime_block {
Ok(block) => { Ok(r) => r,
let candidate_hashes = block.parachain_heads().iter().map(|c| c.hash()).collect(); Err(e) => { e.log(&hash); return Ok(()) }
if let Err(e) = extrinsic_store.candidates_finalized(parent_hash, candidate_hashes) { };
warn!(target: "consensus", "Failed to prune unneeded available data: {:?}", e);
} let candidate_hashes = match runtime_block.extrinsics
} .iter()
Err(e) => e.log(&hash) .filter_map(|ex| match ex.function {
Call::Parachains(ParachainsCall::set_heads(ref heads)) =>
Some(heads.iter().map(|c| c.hash()).collect()),
_ => None,
})
.next()
{
Some(x) => x,
None => return Ok(()),
};
if let Err(e) = extrinsic_store.candidates_finalized(parent_hash, candidate_hashes) {
warn!(target: "consensus", "Failed to prune unneeded available data: {:?}", e);
} }
Ok(()) Ok(())
@@ -133,90 +119,102 @@ pub struct Service {
impl Service { impl Service {
/// Create and start a new instance. /// Create and start a new instance.
pub fn new<A, C, N>( pub fn new<C, N, TxApi>(
client: Arc<C>, client: Arc<C>,
api: Arc<A>,
network: N, network: N,
transaction_pool: Arc<TransactionPool<A>>, transaction_pool: Arc<Pool<TxApi>>,
thread_pool: ThreadPoolHandle, thread_pool: ThreadPoolHandle,
parachain_empty_duration: Duration, parachain_empty_duration: Duration,
key: ed25519::Pair, key: ed25519::Pair,
extrinsic_store: ExtrinsicStore, extrinsic_store: ExtrinsicStore,
) -> Service ) -> Service
where where
A: LocalPolkadotApi + Send + Sync + 'static,
C: BlockchainEvents<Block> + ChainHead<Block> + BlockBody<Block>, C: BlockchainEvents<Block> + ChainHead<Block> + BlockBody<Block>,
C: bft::BlockImport<Block> + bft::Authorities<Block> + Send + Sync + 'static, C: ProvideRuntimeApi + HeaderBackend<Block> + Send + Sync + 'static,
N: Network + Collators + Send + 'static, C::Api: ParachainHost<Block> + Core<Block> + BlockBuilder<Block>,
N: Network + Collators + Send + Sync + 'static,
N::TableRouter: Send + 'static, N::TableRouter: Send + 'static,
<N::Collation as IntoFuture>::Future: Send + 'static, <N::Collation as IntoFuture>::Future: Send + 'static,
TxApi: PoolChainApi<Block=Block> + Send + 'static,
{ {
use parking_lot::RwLock; use parking_lot::Mutex;
use super::OfflineTracker; use std::collections::HashMap;
const TIMER_DELAY: Duration = Duration::from_secs(5);
const TIMER_INTERVAL: Duration = Duration::from_secs(30);
let (signal, exit) = ::exit_future::signal(); let (signal, exit) = ::exit_future::signal();
let thread = thread::spawn(move || { let thread = thread::spawn(move || {
let mut runtime = LocalRuntime::new().expect("Could not create local runtime"); let mut runtime = LocalRuntime::new().expect("Could not create local runtime");
let key = Arc::new(key); let key = Arc::new(key);
let factory = ProposerFactory { let parachain_consensus = Arc::new(::ParachainConsensus{
client: api.clone(), client: client.clone(),
transaction_pool: transaction_pool.clone(), network: network.clone(),
collators: network.clone(), collators: network.clone(),
network,
parachain_empty_duration,
handle: thread_pool.clone(), handle: thread_pool.clone(),
extrinsic_store: extrinsic_store.clone(), extrinsic_store: extrinsic_store.clone(),
offline: Arc::new(RwLock::new(OfflineTracker::new())), parachain_empty_duration,
}; live_instances: Mutex::new(HashMap::new()),
let bft_service = Arc::new(BftService::new(client.clone(), key, factory)); });
let factory = ProposerFactory::new(
parachain_consensus.clone(),
transaction_pool
);
let notifications = { let notifications = {
let client = client.clone(); let client = client.clone();
let bft_service = bft_service.clone(); let consensus = parachain_consensus.clone();
let key = key.clone();
client.import_notification_stream().for_each(move |notification| { client.import_notification_stream().for_each(move |notification| {
let parent_hash = notification.hash;
if notification.is_new_best { if notification.is_new_best {
trace!(target: "bft", "Attempting to start new consensus round after import notification of {:?}", notification.hash); let res = client
start_bft(notification.header, bft_service.clone()); .runtime_api()
} .authorities(&BlockId::hash(parent_hash))
Ok(()) .map_err(Into::into)
}) .and_then(|authorities| {
}; consensus.get_or_instantiate(
parent_hash,
&authorities,
key.clone(),
)
});
let interval = Interval::new( if let Err(e) = res {
Instant::now() + Duration::from_millis(TIMER_DELAY_MS), warn!("Unable to start parachain consensus on top of {:?}: {}",
Duration::from_millis(TIMER_INTERVAL_MS), parent_hash, e);
);
let mut prev_best = match client.best_block_header() {
Ok(header) => header.hash(),
Err(e) => {
warn!("Can't start consensus service. Error reading best block header: {:?}", e);
return;
}
};
let timed = {
let c = client.clone();
let s = bft_service.clone();
interval.map_err(|e| debug!(target: "bft", "Timer error: {:?}", e)).for_each(move |_| {
if let Ok(best_block) = c.best_block_header() {
let hash = best_block.hash();
if hash == prev_best {
debug!(target: "bft", "Starting consensus round after a timeout");
start_bft(best_block, s.clone());
} }
prev_best = hash;
} }
Ok(()) Ok(())
}) })
}; };
let prune_old_sessions = {
let client = client.clone();
let interval = Interval::new(
Instant::now() + TIMER_DELAY,
TIMER_INTERVAL,
);
interval
.for_each(move |_| match client.leaves() {
Ok(leaves) => {
parachain_consensus.retain(|h| leaves.contains(h));
Ok(())
}
Err(e) => {
warn!("Error fetching leaves from client: {:?}", e);
Ok(())
}
})
.map_err(|e| warn!("Timer error {:?}", e))
};
runtime.spawn(notifications); runtime.spawn(notifications);
runtime.spawn(timed); thread_pool.spawn(prune_old_sessions);
let prune_available = prune_unneeded_availability(client, extrinsic_store) let prune_available = prune_unneeded_availability(client, extrinsic_store)
.select(exit.clone()) .select(exit.clone())
@@ -449,6 +449,11 @@ impl SharedTable {
f(inner.table.proposed_candidates(&*self.context)) f(inner.table.proposed_candidates(&*self.context))
} }
/// Get the number of total parachains.
pub fn num_parachains(&self) -> usize {
self.group_info().len()
}
/// Get the number of parachains which have available candidates. /// Get the number of parachains which have available candidates.
pub fn includable_count(&self) -> usize { pub fn includable_count(&self) -> usize {
self.inner.lock().table.includable_count() self.inner.lock().table.includable_count()
+6 -1
View File
@@ -21,4 +21,9 @@ extern crate polkadot_runtime;
#[macro_use] extern crate substrate_executor; #[macro_use] extern crate substrate_executor;
extern crate substrate_primitives as primitives; extern crate substrate_primitives as primitives;
native_executor_instance!(pub Executor, polkadot_runtime::api::dispatch, polkadot_runtime::VERSION, include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm")); native_executor_instance!(
pub Executor,
polkadot_runtime::api::dispatch,
polkadot_runtime::native_version,
include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm")
);
+3 -4
View File
@@ -6,15 +6,14 @@ description = "Polkadot-specific networking protocol"
[dependencies] [dependencies]
parking_lot = "0.4" parking_lot = "0.4"
polkadot-api = { path = "../api" }
polkadot-availability-store = { path = "../availability-store" } polkadot-availability-store = { path = "../availability-store" }
polkadot-consensus = { path = "../consensus" } polkadot-consensus = { path = "../consensus" }
polkadot-primitives = { path = "../primitives" } polkadot-primitives = { path = "../primitives" }
substrate-bft = { git = "https://github.com/paritytech/substrate" } parity-codec = "2.1"
parity-codec = { git = "https://github.com/paritytech/substrate" } parity-codec-derive = "2.1"
parity-codec-derive = { git = "https://github.com/paritytech/substrate" }
substrate-network = { git = "https://github.com/paritytech/substrate" } substrate-network = { git = "https://github.com/paritytech/substrate" }
substrate-primitives = { git = "https://github.com/paritytech/substrate" } substrate-primitives = { git = "https://github.com/paritytech/substrate" }
sr-primitives = { git = "https://github.com/paritytech/substrate" }
futures = "0.1" futures = "0.1"
tokio = "0.1.7" tokio = "0.1.7"
log = "0.4" log = "0.4"
+48 -196
View File
@@ -15,17 +15,15 @@
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>. // along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! The "consensus" networking code built on top of the base network service. //! The "consensus" networking code built on top of the base network service.
//!
//! This fulfills the `polkadot_consensus::Network` trait, providing a hook to be called //! This fulfills the `polkadot_consensus::Network` trait, providing a hook to be called
//! each time consensus begins on a new chain head. //! each time consensus begins on a new chain head.
use bft; use sr_primitives::traits::ProvideRuntimeApi;
use substrate_primitives::ed25519;
use substrate_network::{self as net, generic_message as msg};
use substrate_network::consensus_gossip::ConsensusMessage; use substrate_network::consensus_gossip::ConsensusMessage;
use polkadot_api::{PolkadotApi, LocalPolkadotApi};
use polkadot_consensus::{Network, SharedTable, Collators}; use polkadot_consensus::{Network, SharedTable, Collators};
use polkadot_primitives::{AccountId, Block, Hash, SessionKey}; use polkadot_primitives::{AccountId, Block, Hash, SessionKey};
use polkadot_primitives::parachain::{Id as ParaId, Collation}; use polkadot_primitives::parachain::{Id as ParaId, Collation, ParachainHost};
use codec::Decode; use codec::Decode;
use futures::prelude::*; use futures::prelude::*;
@@ -36,152 +34,32 @@ use std::sync::Arc;
use tokio::runtime::TaskExecutor; use tokio::runtime::TaskExecutor;
use parking_lot::Mutex; use parking_lot::Mutex;
use super::{Message, NetworkService, Knowledge, CurrentConsensus}; use super::{NetworkService, Knowledge, CurrentConsensus};
use router::Router; use router::Router;
/// Sink for output BFT messages.
pub struct BftSink<E> {
network: Arc<NetworkService>,
parent_hash: Hash,
_marker: ::std::marker::PhantomData<E>,
}
impl<E> Sink for BftSink<E> {
type SinkItem = bft::Communication<Block>;
// TODO: replace this with the ! type when that's stabilized
type SinkError = E;
fn start_send(&mut self, message: bft::Communication<Block>) -> ::futures::StartSend<bft::Communication<Block>, E> {
let network_message = net::LocalizedBftMessage {
message: match message {
::rhododendron::Communication::Consensus(c) => msg::BftMessage::Consensus(match c {
::rhododendron::LocalizedMessage::Propose(proposal) => msg::SignedConsensusMessage::Propose(msg::SignedConsensusProposal {
round_number: proposal.round_number as u32,
proposal: proposal.proposal,
digest: proposal.digest,
sender: proposal.sender,
digest_signature: proposal.digest_signature.signature,
full_signature: proposal.full_signature.signature,
}),
::rhododendron::LocalizedMessage::Vote(vote) => msg::SignedConsensusMessage::Vote(msg::SignedConsensusVote {
sender: vote.sender,
signature: vote.signature.signature,
vote: match vote.vote {
::rhododendron::Vote::Prepare(r, h) => msg::ConsensusVote::Prepare(r as u32, h),
::rhododendron::Vote::Commit(r, h) => msg::ConsensusVote::Commit(r as u32, h),
::rhododendron::Vote::AdvanceRound(r) => msg::ConsensusVote::AdvanceRound(r as u32),
}
}),
}),
::rhododendron::Communication::Auxiliary(justification) => {
let unchecked: bft::UncheckedJustification<_> = justification.uncheck().into();
msg::BftMessage::Auxiliary(unchecked.into())
}
},
parent_hash: self.parent_hash,
};
self.network.with_spec(
move |spec, ctx| spec.consensus_gossip.multicast_bft_message(ctx, network_message)
);
Ok(::futures::AsyncSink::Ready)
}
fn poll_complete(&mut self) -> ::futures::Poll<(), E> {
Ok(Async::Ready(()))
}
}
// check signature and authority validity of message.
fn process_bft_message(msg: msg::LocalizedBftMessage<Block, Hash>, local_id: &SessionKey, authorities: &[SessionKey]) -> Result<Option<bft::Communication<Block>>, bft::Error> {
Ok(Some(match msg.message {
msg::BftMessage::Consensus(c) => ::rhododendron::Communication::Consensus(match c {
msg::SignedConsensusMessage::Propose(proposal) => ::rhododendron::LocalizedMessage::Propose({
if &proposal.sender == local_id { return Ok(None) }
let proposal = ::rhododendron::LocalizedProposal {
round_number: proposal.round_number as usize,
proposal: proposal.proposal,
digest: proposal.digest,
sender: proposal.sender,
digest_signature: ed25519::LocalizedSignature {
signature: proposal.digest_signature,
signer: ed25519::Public(proposal.sender.into()),
},
full_signature: ed25519::LocalizedSignature {
signature: proposal.full_signature,
signer: ed25519::Public(proposal.sender.into()),
}
};
bft::check_proposal(authorities, &msg.parent_hash, &proposal)?;
trace!(target: "bft", "importing proposal message for round {} from {}", proposal.round_number, Hash::from(proposal.sender.0));
proposal
}),
msg::SignedConsensusMessage::Vote(vote) => ::rhododendron::LocalizedMessage::Vote({
if &vote.sender == local_id { return Ok(None) }
let vote = ::rhododendron::LocalizedVote {
sender: vote.sender,
signature: ed25519::LocalizedSignature {
signature: vote.signature,
signer: ed25519::Public(vote.sender.0),
},
vote: match vote.vote {
msg::ConsensusVote::Prepare(r, h) => ::rhododendron::Vote::Prepare(r as usize, h),
msg::ConsensusVote::Commit(r, h) => ::rhododendron::Vote::Commit(r as usize, h),
msg::ConsensusVote::AdvanceRound(r) => ::rhododendron::Vote::AdvanceRound(r as usize),
}
};
bft::check_vote::<Block>(authorities, &msg.parent_hash, &vote)?;
trace!(target: "bft", "importing vote {:?} from {}", vote.vote, Hash::from(vote.sender.0));
vote
}),
}),
msg::BftMessage::Auxiliary(a) => {
let justification = bft::UncheckedJustification::from(a);
// TODO: get proper error
let justification: Result<_, bft::Error> = bft::check_prepare_justification::<Block>(authorities, msg.parent_hash, justification)
.map_err(|_| bft::ErrorKind::InvalidJustification.into());
::rhododendron::Communication::Auxiliary(justification?)
},
}))
}
// task that processes all gossipped consensus messages, // task that processes all gossipped consensus messages,
// checking signatures // checking signatures
struct MessageProcessTask<P: PolkadotApi> { struct MessageProcessTask<P> {
inner_stream: mpsc::UnboundedReceiver<ConsensusMessage<Block>>, inner_stream: mpsc::UnboundedReceiver<ConsensusMessage>,
bft_messages: mpsc::UnboundedSender<bft::Communication<Block>>, parent_hash: Hash,
validators: Vec<SessionKey>,
table_router: Router<P>, table_router: Router<P>,
} }
impl<P: LocalPolkadotApi + Send + Sync + 'static> MessageProcessTask<P> { impl<P: ProvideRuntimeApi + Send + Sync + 'static> MessageProcessTask<P>
fn process_message(&self, msg: ConsensusMessage<Block>) -> Option<Async<()>> { where P::Api: ParachainHost<Block>,
match msg { {
ConsensusMessage::Bft(msg) => { fn process_message(&self, msg: ConsensusMessage) -> Option<Async<()>> {
let local_id = self.table_router.session_key(); use polkadot_consensus::SignedStatement;
match process_bft_message(msg, &local_id, &self.validators[..]) {
Ok(Some(msg)) => { debug!(target: "consensus", "Processing consensus statement for live consensus");
if let Err(_) = self.bft_messages.unbounded_send(msg) { if let Some(statement) = SignedStatement::decode(&mut msg.as_slice()) {
// if the BFT receiving stream has ended then if ::polkadot_consensus::check_statement(
// we should just bail. &statement.statement,
trace!(target: "bft", "BFT message stream appears to have closed"); &statement.signature,
return Some(Async::Ready(())); statement.sender,
} &self.parent_hash
} ) {
Ok(None) => {} // ignored local message self.table_router.import_statement(statement);
Err(e) => {
debug!("Message validation failed: {:?}", e);
}
}
}
ConsensusMessage::ChainSpecific(msg, _) => {
debug!(target: "consensus", "Processing consensus statement for live consensus");
if let Some(Message::Statement(parent_hash, statement)) = Decode::decode(&mut msg.as_slice()) {
if ::polkadot_consensus::check_statement(&statement.statement, &statement.signature, statement.sender, &parent_hash) {
self.table_router.import_statement(statement);
}
}
} }
} }
@@ -189,7 +67,9 @@ impl<P: LocalPolkadotApi + Send + Sync + 'static> MessageProcessTask<P> {
} }
} }
impl<P: LocalPolkadotApi + Send + Sync + 'static> Future for MessageProcessTask<P> { impl<P: ProvideRuntimeApi + Send + Sync + 'static> Future for MessageProcessTask<P>
where P::Api: ParachainHost<Block>,
{
type Item = (); type Item = ();
type Error = (); type Error = ();
@@ -207,23 +87,6 @@ impl<P: LocalPolkadotApi + Send + Sync + 'static> Future for MessageProcessTask<
} }
} }
/// Input stream from the consensus network.
pub struct InputAdapter {
input: mpsc::UnboundedReceiver<bft::Communication<Block>>,
}
impl Stream for InputAdapter {
type Item = bft::Communication<Block>;
type Error = ::polkadot_consensus::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
match self.input.poll() {
Err(_) | Ok(Async::Ready(None)) => Err(bft::InputStreamConcluded.into()),
Ok(x) => Ok(x)
}
}
}
/// Wrapper around the network service /// Wrapper around the network service
pub struct ConsensusNetwork<P> { pub struct ConsensusNetwork<P> {
network: Arc<NetworkService>, network: Arc<NetworkService>,
@@ -246,27 +109,21 @@ impl<P> Clone for ConsensusNetwork<P> {
} }
} }
/// A long-lived network which can create parachain statement and BFT message routing processes on demand. /// A long-lived network which can create parachain statement routing processes on demand.
impl<P: LocalPolkadotApi + Send + Sync + 'static> Network for ConsensusNetwork<P> { impl<P: ProvideRuntimeApi + Send + Sync + 'static> Network for ConsensusNetwork<P>
where P::Api: ParachainHost<Block>,
{
type TableRouter = Router<P>; type TableRouter = Router<P>;
/// The input stream of BFT messages. Should never logically conclude.
type Input = InputAdapter;
/// The output sink of BFT messages. Messages sent here should eventually pass to all
/// current validators.
type Output = BftSink<::polkadot_consensus::Error>;
/// Instantiate a table router using the given shared table. /// Instantiate a table router using the given shared table.
fn communication_for(&self, validators: &[SessionKey], table: Arc<SharedTable>, task_executor: TaskExecutor) -> (Self::TableRouter, Self::Input, Self::Output) { fn communication_for(
&self,
_validators: &[SessionKey],
table: Arc<SharedTable>,
task_executor: TaskExecutor
) -> Self::TableRouter {
let parent_hash = table.consensus_parent_hash().clone(); let parent_hash = table.consensus_parent_hash().clone();
let sink = BftSink {
network: self.network.clone(),
parent_hash,
_marker: Default::default(),
};
let (bft_send, bft_recv) = mpsc::unbounded();
let knowledge = Arc::new(Mutex::new(Knowledge::new())); let knowledge = Arc::new(Mutex::new(Knowledge::new()));
let local_session_key = table.session_key(); let local_session_key = table.session_key();
@@ -279,9 +136,12 @@ impl<P: LocalPolkadotApi + Send + Sync + 'static> Network for ConsensusNetwork<P
knowledge.clone(), knowledge.clone(),
); );
let attestation_topic = table_router.gossip_topic();
// spin up a task in the background that processes all incoming statements // spin up a task in the background that processes all incoming statements
// TODO: propagate statements on a timer? // TODO: propagate statements on a timer?
let process_task = self.network.with_spec(|spec, ctx| { let inner_stream = self.network.consensus_gossip().write().messages_for(attestation_topic);
task_executor.spawn(self.network.with_spec(|spec, ctx| {
spec.new_consensus(ctx, CurrentConsensus { spec.new_consensus(ctx, CurrentConsensus {
knowledge, knowledge,
parent_hash, parent_hash,
@@ -289,19 +149,13 @@ impl<P: LocalPolkadotApi + Send + Sync + 'static> Network for ConsensusNetwork<P
}); });
MessageProcessTask { MessageProcessTask {
inner_stream: spec.consensus_gossip.messages_for(parent_hash), inner_stream,
bft_messages: bft_send, parent_hash,
validators: validators.to_vec(),
table_router: table_router.clone(), table_router: table_router.clone(),
} }
}); }));
match process_task { table_router
Some(task) => task_executor.spawn(task),
None => warn!(target: "p_net", "Cannot process incoming messages: network appears to be down"),
}
(table_router, InputAdapter { input: bft_recv }, sink)
} }
} }
@@ -310,23 +164,21 @@ impl<P: LocalPolkadotApi + Send + Sync + 'static> Network for ConsensusNetwork<P
pub struct NetworkDown; pub struct NetworkDown;
/// A future that resolves when a collation is received. /// A future that resolves when a collation is received.
pub struct AwaitingCollation(Option<::futures::sync::oneshot::Receiver<Collation>>); pub struct AwaitingCollation(::futures::sync::oneshot::Receiver<Collation>);
impl Future for AwaitingCollation { impl Future for AwaitingCollation {
type Item = Collation; type Item = Collation;
type Error = NetworkDown; type Error = NetworkDown;
fn poll(&mut self) -> Poll<Collation, NetworkDown> { fn poll(&mut self) -> Poll<Collation, NetworkDown> {
match self.0.poll().map_err(|_| NetworkDown)? { self.0.poll().map_err(|_| NetworkDown)
Async::Ready(None) => Err(NetworkDown),
Async::Ready(Some(x)) => Ok(Async::Ready(x)),
Async::NotReady => Ok(Async::NotReady),
}
} }
} }
impl<P: LocalPolkadotApi + Send + Sync + 'static> Collators for ConsensusNetwork<P> { impl<P: ProvideRuntimeApi + Send + Sync + 'static> Collators for ConsensusNetwork<P>
where P::Api: ParachainHost<Block>,
{
type Error = NetworkDown; type Error = NetworkDown;
type Collation = AwaitingCollation; type Collation = AwaitingCollation;
+13 -37
View File
@@ -20,14 +20,13 @@
//! parachain block and extrinsic data fetching, communication between collators and validators, //! parachain block and extrinsic data fetching, communication between collators and validators,
//! and more. //! and more.
extern crate substrate_bft as bft;
extern crate parity_codec as codec; extern crate parity_codec as codec;
extern crate substrate_network; extern crate substrate_network;
extern crate substrate_primitives; extern crate substrate_primitives;
extern crate sr_primitives;
extern crate polkadot_api;
extern crate polkadot_availability_store as av_store;
extern crate polkadot_consensus; extern crate polkadot_consensus;
extern crate polkadot_availability_store as av_store;
extern crate polkadot_primitives; extern crate polkadot_primitives;
extern crate futures; extern crate futures;
@@ -48,13 +47,12 @@ pub mod consensus;
use codec::{Decode, Encode}; use codec::{Decode, Encode};
use futures::sync::oneshot; use futures::sync::oneshot;
use parking_lot::Mutex; use parking_lot::Mutex;
use polkadot_consensus::{Statement, SignedStatement, GenericStatement}; use polkadot_consensus::{Statement, GenericStatement};
use polkadot_primitives::{AccountId, Block, SessionKey, Hash, Header}; use polkadot_primitives::{AccountId, Block, SessionKey, Hash, Header};
use polkadot_primitives::parachain::{Id as ParaId, BlockData, Extrinsic, CandidateReceipt, Collation}; use polkadot_primitives::parachain::{Id as ParaId, BlockData, Extrinsic, CandidateReceipt, Collation};
use substrate_network::{NodeIndex, RequestId, Context, Severity}; use substrate_network::{NodeIndex, RequestId, Context, Severity};
use substrate_network::consensus_gossip::ConsensusGossip;
use substrate_network::{message, generic_message}; use substrate_network::{message, generic_message};
use substrate_network::specialization::Specialization; use substrate_network::specialization::NetworkSpecialization as Specialization;
use substrate_network::StatusMessage as GenericFullStatus; use substrate_network::StatusMessage as GenericFullStatus;
use self::collator_pool::{CollatorPool, Role, Action}; use self::collator_pool::{CollatorPool, Role, Action};
use self::local_collations::LocalCollations; use self::local_collations::LocalCollations;
@@ -185,8 +183,6 @@ impl CurrentConsensus {
/// Polkadot-specific messages. /// Polkadot-specific messages.
#[derive(Debug, Encode, Decode)] #[derive(Debug, Encode, Decode)]
pub enum Message { pub enum Message {
/// signed statement and localized parent hash.
Statement(Hash, SignedStatement),
/// As a validator, tell the peer your current session key. /// As a validator, tell the peer your current session key.
// TODO: do this with a cryptographic proof of some kind // TODO: do this with a cryptographic proof of some kind
SessionKey(SessionKey), SessionKey(SessionKey),
@@ -210,7 +206,6 @@ fn send_polkadot_message(ctx: &mut Context<Block>, to: NodeIndex, message: Messa
pub struct PolkadotProtocol { pub struct PolkadotProtocol {
peers: HashMap<NodeIndex, PeerInfo>, peers: HashMap<NodeIndex, PeerInfo>,
collating_for: Option<(AccountId, ParaId)>, collating_for: Option<(AccountId, ParaId)>,
consensus_gossip: ConsensusGossip<Block>,
collators: CollatorPool, collators: CollatorPool,
validators: HashMap<SessionKey, NodeIndex>, validators: HashMap<SessionKey, NodeIndex>,
local_collations: LocalCollations<Collation>, local_collations: LocalCollations<Collation>,
@@ -226,7 +221,6 @@ impl PolkadotProtocol {
pub fn new(collating_for: Option<(AccountId, ParaId)>) -> Self { pub fn new(collating_for: Option<(AccountId, ParaId)>) -> Self {
PolkadotProtocol { PolkadotProtocol {
peers: HashMap::new(), peers: HashMap::new(),
consensus_gossip: ConsensusGossip::new(),
collators: CollatorPool::new(), collators: CollatorPool::new(),
collating_for, collating_for,
validators: HashMap::new(), validators: HashMap::new(),
@@ -239,13 +233,6 @@ impl PolkadotProtocol {
} }
} }
/// Gossip a consensus statement.
fn gossip_statement(&mut self, ctx: &mut Context<Block>, parent_hash: Hash, statement: SignedStatement) {
// TODO: something more targeted than gossip.
let raw = Message::Statement(parent_hash, statement).encode();
self.consensus_gossip.multicast_chain_specific(ctx, raw, parent_hash);
}
/// Fetch block data by candidate receipt. /// Fetch block data by candidate receipt.
fn fetch_block_data(&mut self, ctx: &mut Context<Block>, candidate: &CandidateReceipt, relay_parent: Hash) -> oneshot::Receiver<BlockData> { fn fetch_block_data(&mut self, ctx: &mut Context<Block>, candidate: &CandidateReceipt, relay_parent: Hash) -> oneshot::Receiver<BlockData> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
@@ -279,7 +266,6 @@ impl PolkadotProtocol {
} }
self.live_consensus = Some(consensus); self.live_consensus = Some(consensus);
self.consensus_gossip.collect_garbage(old_data.as_ref().map(|&(ref hash, _)| hash));
} }
fn dispatch_pending_requests(&mut self, ctx: &mut Context<Block>) { fn dispatch_pending_requests(&mut self, ctx: &mut Context<Block>) {
@@ -332,11 +318,9 @@ impl PolkadotProtocol {
self.pending = new_pending; self.pending = new_pending;
} }
fn on_polkadot_message(&mut self, ctx: &mut Context<Block>, who: NodeIndex, raw: Vec<u8>, msg: Message) { fn on_polkadot_message(&mut self, ctx: &mut Context<Block>, who: NodeIndex, msg: Message) {
trace!(target: "p_net", "Polkadot message from {}: {:?}", who, msg); trace!(target: "p_net", "Polkadot message from {}: {:?}", who, msg);
match msg { match msg {
Message::Statement(parent_hash, _statement) =>
self.consensus_gossip.on_chain_specific(ctx, who, raw, parent_hash),
Message::SessionKey(key) => self.on_session_key(ctx, who, key), Message::SessionKey(key) => self.on_session_key(ctx, who, key),
Message::RequestBlockData(req_id, relay_parent, candidate_hash) => { Message::RequestBlockData(req_id, relay_parent, candidate_hash) => {
let block_data = self.live_consensus.as_ref() let block_data = self.live_consensus.as_ref()
@@ -445,7 +429,7 @@ impl Specialization<Block> for PolkadotProtocol {
} }
}; };
let validator = status.roles.contains(substrate_network::Roles::AUTHORITY); let validator = status.roles.contains(substrate_network::config::Roles::AUTHORITY);
let send_key = validator || local_status.collating_for.is_some(); let send_key = validator || local_status.collating_for.is_some();
let mut peer_info = PeerInfo { let mut peer_info = PeerInfo {
@@ -479,7 +463,6 @@ impl Specialization<Block> for PolkadotProtocol {
} }
self.peers.insert(who, peer_info); self.peers.insert(who, peer_info);
self.consensus_gossip.new_peer(ctx, who, status.roles);
self.dispatch_pending_requests(ctx); self.dispatch_pending_requests(ctx);
} }
@@ -521,37 +504,30 @@ impl Specialization<Block> for PolkadotProtocol {
retain retain
}); });
} }
self.consensus_gossip.peer_disconnected(ctx, who);
self.dispatch_pending_requests(ctx); self.dispatch_pending_requests(ctx);
} }
} }
fn on_message(&mut self, ctx: &mut Context<Block>, who: NodeIndex, message: message::Message<Block>) { fn on_message(&mut self, ctx: &mut Context<Block>, who: NodeIndex, message: &mut Option<message::Message<Block>>) {
match message { match message.take() {
generic_message::Message::BftMessage(msg) => { Some(generic_message::Message::ChainSpecific(raw)) => {
trace!(target: "p_net", "Polkadot BFT message from {}: {:?}", who, msg);
// TODO: check signature here? what if relevant block is unknown?
self.consensus_gossip.on_bft_message(ctx, who, msg)
}
generic_message::Message::ChainSpecific(raw) => {
match Message::decode(&mut raw.as_slice()) { match Message::decode(&mut raw.as_slice()) {
Some(msg) => self.on_polkadot_message(ctx, who, raw, msg), Some(msg) => self.on_polkadot_message(ctx, who, msg),
None => { None => {
trace!(target: "p_net", "Bad message from {}", who); trace!(target: "p_net", "Bad message from {}", who);
ctx.report_peer(who, Severity::Bad("Invalid polkadot protocol message format")); ctx.report_peer(who, Severity::Bad("Invalid polkadot protocol message format"));
*message = Some(generic_message::Message::ChainSpecific(raw));
} }
} }
} }
Some(other) => *message = Some(other),
_ => {} _ => {}
} }
} }
fn on_abort(&mut self) { fn on_abort(&mut self) { }
self.consensus_gossip.abort();
}
fn maintain_peers(&mut self, ctx: &mut Context<Block>) { fn maintain_peers(&mut self, ctx: &mut Context<Block>) {
self.consensus_gossip.collect_garbage(None);
self.collators.collect_garbage(None); self.collators.collect_garbage(None);
self.local_collations.collect_garbage(None); self.local_collations.collect_garbage(None);
self.dispatch_pending_requests(ctx); self.dispatch_pending_requests(ctx);
+50 -27
View File
@@ -22,11 +22,12 @@
//! the `TableRouter` trait from `polkadot-consensus`, which is expected to call into a shared statement table //! the `TableRouter` trait from `polkadot-consensus`, which is expected to call into a shared statement table
//! and dispatch evaluation work as necessary when new statements come in. //! and dispatch evaluation work as necessary when new statements come in.
use polkadot_api::{PolkadotApi, LocalPolkadotApi}; use sr_primitives::traits::{ProvideRuntimeApi, BlakeTwo256, Hash as HashT};
use polkadot_consensus::{SharedTable, TableRouter, SignedStatement, GenericStatement, StatementProducer}; use polkadot_consensus::{SharedTable, TableRouter, SignedStatement, GenericStatement, StatementProducer};
use polkadot_primitives::{Hash, BlockId, SessionKey}; use polkadot_primitives::{Block, Hash, BlockId, SessionKey};
use polkadot_primitives::parachain::{BlockData, Extrinsic, CandidateReceipt}; use polkadot_primitives::parachain::{BlockData, Extrinsic, CandidateReceipt, ParachainHost};
use codec::Encode;
use futures::prelude::*; use futures::prelude::*;
use tokio::runtime::TaskExecutor; use tokio::runtime::TaskExecutor;
use parking_lot::Mutex; use parking_lot::Mutex;
@@ -37,18 +38,26 @@ use std::sync::Arc;
use super::{NetworkService, Knowledge}; use super::{NetworkService, Knowledge};
fn attestation_topic(parent_hash: Hash) -> Hash {
let mut v = parent_hash.as_ref().to_vec();
v.extend(b"attestations");
BlakeTwo256::hash(&v[..])
}
/// Table routing implementation. /// Table routing implementation.
pub struct Router<P: PolkadotApi> { pub struct Router<P> {
table: Arc<SharedTable>, table: Arc<SharedTable>,
network: Arc<NetworkService>, network: Arc<NetworkService>,
api: Arc<P>, api: Arc<P>,
task_executor: TaskExecutor, task_executor: TaskExecutor,
parent_hash: Hash, parent_hash: Hash,
attestation_topic: Hash,
knowledge: Arc<Mutex<Knowledge>>, knowledge: Arc<Mutex<Knowledge>>,
deferred_statements: Arc<Mutex<DeferredStatements>>, deferred_statements: Arc<Mutex<DeferredStatements>>,
} }
impl<P: PolkadotApi> Router<P> { impl<P> Router<P> {
pub(crate) fn new( pub(crate) fn new(
table: Arc<SharedTable>, table: Arc<SharedTable>,
network: Arc<NetworkService>, network: Arc<NetworkService>,
@@ -63,17 +72,19 @@ impl<P: PolkadotApi> Router<P> {
api, api,
task_executor, task_executor,
parent_hash, parent_hash,
attestation_topic: attestation_topic(parent_hash),
knowledge, knowledge,
deferred_statements: Arc::new(Mutex::new(DeferredStatements::new())), deferred_statements: Arc::new(Mutex::new(DeferredStatements::new())),
} }
} }
pub(crate) fn session_key(&self) -> SessionKey { /// Get the attestation topic for gossip.
self.table.session_key() pub(crate) fn gossip_topic(&self) -> Hash {
self.attestation_topic
} }
} }
impl<P: PolkadotApi> Clone for Router<P> { impl<P> Clone for Router<P> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Router { Router {
table: self.table.clone(), table: self.table.clone(),
@@ -81,13 +92,16 @@ impl<P: PolkadotApi> Clone for Router<P> {
api: self.api.clone(), api: self.api.clone(),
task_executor: self.task_executor.clone(), task_executor: self.task_executor.clone(),
parent_hash: self.parent_hash.clone(), parent_hash: self.parent_hash.clone(),
attestation_topic: self.attestation_topic.clone(),
deferred_statements: self.deferred_statements.clone(), deferred_statements: self.deferred_statements.clone(),
knowledge: self.knowledge.clone(), knowledge: self.knowledge.clone(),
} }
} }
} }
impl<P: LocalPolkadotApi + Send + Sync + 'static> Router<P> { impl<P: ProvideRuntimeApi + Send + Sync + 'static> Router<P>
where P::Api: ParachainHost<Block>
{
/// Import a statement whose signature has been checked already. /// Import a statement whose signature has been checked already.
pub(crate) fn import_statement(&self, statement: SignedStatement) { pub(crate) fn import_statement(&self, statement: SignedStatement) {
trace!(target: "p_net", "importing consensus statement {:?}", statement.statement); trace!(target: "p_net", "importing consensus statement {:?}", statement.statement);
@@ -156,6 +170,7 @@ impl<P: LocalPolkadotApi + Send + Sync + 'static> Router<P> {
let table = self.table.clone(); let table = self.table.clone();
let network = self.network.clone(); let network = self.network.clone();
let knowledge = self.knowledge.clone(); let knowledge = self.knowledge.clone();
let attestation_topic = self.attestation_topic.clone();
let work = producer.prime(validate) let work = producer.prime(validate)
.map(move |produced| { .map(move |produced| {
@@ -166,15 +181,26 @@ impl<P: LocalPolkadotApi + Send + Sync + 'static> Router<P> {
produced.extrinsic produced.extrinsic
); );
if produced.validity.is_none() && produced.availability.is_none() {
return
}
let mut gossip = network.consensus_gossip().write();
// propagate the statements // propagate the statements
// consider something more targeted than gossip in the future.
if let Some(validity) = produced.validity { if let Some(validity) = produced.validity {
let signed = table.sign_and_import(validity.clone()).0; let signed = table.sign_and_import(validity.clone()).0;
network.with_spec(|spec, ctx| spec.gossip_statement(ctx, parent_hash, signed)); network.with_spec(|_, ctx|
gossip.multicast(ctx, attestation_topic, signed.encode())
);
} }
if let Some(availability) = produced.availability { if let Some(availability) = produced.availability {
let signed = table.sign_and_import(availability).0; let signed = table.sign_and_import(availability).0;
network.with_spec(|spec, ctx| spec.gossip_statement(ctx, parent_hash, signed)); network.with_spec(|_, ctx|
gossip.multicast(ctx, attestation_topic, signed.encode())
);
} }
}) })
.map_err(|e| debug!(target: "p_net", "Failed to produce statements: {:?}", e)); .map_err(|e| debug!(target: "p_net", "Failed to produce statements: {:?}", e));
@@ -183,7 +209,9 @@ impl<P: LocalPolkadotApi + Send + Sync + 'static> Router<P> {
} }
} }
impl<P: LocalPolkadotApi + Send> TableRouter for Router<P> { impl<P: ProvideRuntimeApi + Send> TableRouter for Router<P>
where P::Api: ParachainHost<Block>
{
type Error = io::Error; type Error = io::Error;
type FetchCandidate = BlockDataReceiver; type FetchCandidate = BlockDataReceiver;
type FetchExtrinsic = Result<Extrinsic, Self::Error>; type FetchExtrinsic = Result<Extrinsic, Self::Error>;
@@ -194,10 +222,11 @@ impl<P: LocalPolkadotApi + Send> TableRouter for Router<P> {
let (candidate, availability) = self.table.sign_and_import(GenericStatement::Candidate(receipt)); let (candidate, availability) = self.table.sign_and_import(GenericStatement::Candidate(receipt));
self.knowledge.lock().note_candidate(hash, Some(block_data), Some(extrinsic)); self.knowledge.lock().note_candidate(hash, Some(block_data), Some(extrinsic));
self.network.with_spec(|spec, ctx| { let mut gossip = self.network.consensus_gossip().write();
spec.gossip_statement(ctx, self.parent_hash, candidate); self.network.with_spec(|_spec, ctx| {
gossip.multicast(ctx, self.attestation_topic, candidate.encode());
if let Some(availability) = availability { if let Some(availability) = availability {
spec.gossip_statement(ctx, self.parent_hash, availability); gossip.multicast(ctx, self.attestation_topic, availability.encode());
} }
}); });
} }
@@ -215,7 +244,7 @@ impl<P: LocalPolkadotApi + Send> TableRouter for Router<P> {
/// Receiver for block data. /// Receiver for block data.
pub struct BlockDataReceiver { pub struct BlockDataReceiver {
inner: Option<::futures::sync::oneshot::Receiver<BlockData>>, inner: ::futures::sync::oneshot::Receiver<BlockData>,
} }
impl Future for BlockDataReceiver { impl Future for BlockDataReceiver {
@@ -223,16 +252,10 @@ impl Future for BlockDataReceiver {
type Error = io::Error; type Error = io::Error;
fn poll(&mut self) -> Poll<BlockData, io::Error> { fn poll(&mut self) -> Poll<BlockData, io::Error> {
match self.inner { self.inner.poll().map_err(|_| io::Error::new(
Some(ref mut inner) => inner.poll().map_err(|_| io::Error::new( io::ErrorKind::Other,
io::ErrorKind::Other, "Sending end of channel hung up",
"Sending end of channel hung up", ))
)),
None => return Err(io::Error::new(
io::ErrorKind::Other,
"Network service is unavailable",
)),
}
} }
} }
@@ -303,7 +326,7 @@ mod tests {
fn deferred_statements_works() { fn deferred_statements_works() {
let mut deferred = DeferredStatements::new(); let mut deferred = DeferredStatements::new();
let hash = [1; 32].into(); let hash = [1; 32].into();
let sig = H512([2; 64]).into(); let sig = H512::from([2; 64]).into();
let sender = [255; 32].into(); let sender = [255; 32].into();
let statement = SignedStatement { let statement = SignedStatement {
+6 -2
View File
@@ -24,7 +24,11 @@ use polkadot_primitives::{Block, Hash, SessionKey};
use polkadot_primitives::parachain::{CandidateReceipt, HeadData, BlockData}; use polkadot_primitives::parachain::{CandidateReceipt, HeadData, BlockData};
use substrate_primitives::H512; use substrate_primitives::H512;
use codec::Encode; use codec::Encode;
use substrate_network::{Severity, NodeIndex, PeerInfo, ClientHandle, Context, Roles, message::Message as SubstrateMessage, specialization::Specialization, generic_message::Message as GenericMessage}; use substrate_network::{
Severity, NodeIndex, PeerInfo, ClientHandle, Context, config::Roles,
message::Message as SubstrateMessage, specialization::NetworkSpecialization,
generic_message::Message as GenericMessage
};
use std::sync::Arc; use std::sync::Arc;
use futures::Future; use futures::Future;
@@ -93,7 +97,7 @@ fn make_consensus(parent_hash: Hash, local_key: SessionKey) -> (CurrentConsensus
fn on_message(protocol: &mut PolkadotProtocol, ctx: &mut TestContext, from: NodeIndex, message: Message) { fn on_message(protocol: &mut PolkadotProtocol, ctx: &mut TestContext, from: NodeIndex, message: Message) {
let encoded = message.encode(); let encoded = message.encode();
protocol.on_message(ctx, from, GenericMessage::ChainSpecific(encoded)); protocol.on_message(ctx, from, &mut Some(GenericMessage::ChainSpecific(encoded)));
} }
#[test] #[test]
+2 -2
View File
@@ -5,8 +5,8 @@ authors = ["Parity Technologies <admin@parity.io>"]
description = "Types and utilities for creating and working with parachains" description = "Types and utilities for creating and working with parachains"
[dependencies] [dependencies]
parity-codec = { git = "https://github.com/paritytech/substrate", default-features = false } parity-codec = { version = "2.1", default-features = false }
parity-codec-derive = { git = "https://github.com/paritytech/substrate", default-features = false } parity-codec-derive = { version = "2.1", default-features = false }
wasmi = { version = "0.4", optional = true } wasmi = { version = "0.4", optional = true }
error-chain = { version = "0.12", optional = true } error-chain = { version = "0.12", optional = true }
Binary file not shown.
+11 -6
View File
@@ -4,13 +4,15 @@ version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
[dependencies] [dependencies]
serde = { version = "1.0", default_features = false } serde = { version = "1.0", default-features = false }
serde_derive = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true }
parity-codec = { git = "https://github.com/paritytech/substrate", default_features = false } parity-codec = { version = "2.1", default-features = false }
parity-codec-derive = { git = "https://github.com/paritytech/substrate", default_features = false } parity-codec-derive = { version = "2.1", default-features = false }
substrate-primitives = { git = "https://github.com/paritytech/substrate", default_features = false } substrate-primitives = { git = "https://github.com/paritytech/substrate", default-features = false }
sr-std = { git = "https://github.com/paritytech/substrate", default_features = false } substrate-client = { git = "https://github.com/paritytech/substrate", default-features = false }
sr-primitives = { git = "https://github.com/paritytech/substrate", default_features = false } sr-version = { git = "https://github.com/paritytech/substrate", default-features = false }
sr-std = { git = "https://github.com/paritytech/substrate", default-features = false }
sr-primitives = { git = "https://github.com/paritytech/substrate", default-features = false }
[dev-dependencies] [dev-dependencies]
substrate-serializer = { git = "https://github.com/paritytech/substrate" } substrate-serializer = { git = "https://github.com/paritytech/substrate" }
@@ -20,8 +22,11 @@ pretty_assertions = "0.4"
default = ["std"] default = ["std"]
std = [ std = [
"parity-codec/std", "parity-codec/std",
"parity-codec-derive/std",
"substrate-primitives/std", "substrate-primitives/std",
"substrate-client/std",
"sr-std/std", "sr-std/std",
"sr-version/std",
"sr-primitives/std", "sr-primitives/std",
"serde_derive", "serde_derive",
"serde/std", "serde/std",
+12 -5
View File
@@ -25,6 +25,7 @@ extern crate parity_codec as codec;
extern crate substrate_primitives as primitives; extern crate substrate_primitives as primitives;
extern crate sr_primitives as runtime_primitives; extern crate sr_primitives as runtime_primitives;
extern crate sr_std as rstd; extern crate sr_std as rstd;
extern crate sr_version;
#[cfg(test)] #[cfg(test)]
extern crate substrate_serializer; extern crate substrate_serializer;
@@ -39,10 +40,16 @@ extern crate serde_derive;
#[cfg(feature = "std")] #[cfg(feature = "std")]
extern crate serde; extern crate serde;
#[macro_use]
extern crate substrate_client;
use rstd::prelude::*; use rstd::prelude::*;
use runtime_primitives::{generic, traits::BlakeTwo256}; use runtime_primitives::{generic, traits::{Extrinsic, BlakeTwo256}};
pub mod parachain; pub mod parachain;
pub use codec::Compact;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use primitives::bytes; use primitives::bytes;
@@ -76,7 +83,7 @@ pub type Index = u32;
pub type Signature = runtime_primitives::Ed25519Signature; pub type Signature = runtime_primitives::Ed25519Signature;
/// A timestamp: seconds since the unix epoch. /// A timestamp: seconds since the unix epoch.
pub type Timestamp = u64; pub type Timestamp = Compact<u64>;
/// The balance of an account. /// The balance of an account.
/// 128-bits (or 38 significant decimal figures) will allow for 10m currency (10^7) at a resolution /// 128-bits (or 38 significant decimal figures) will allow for 10m currency (10^7) at a resolution
@@ -88,7 +95,7 @@ pub type Timestamp = u64;
pub type Balance = u128; pub type Balance = u128;
/// Header type. /// Header type.
pub type Header = generic::Header<BlockNumber, BlakeTwo256, generic::DigestItem<()>>; pub type Header = generic::Header<BlockNumber, BlakeTwo256, generic::DigestItem<Hash, AccountId>>;
/// Block type. /// Block type.
pub type Block = generic::Block<Header, UncheckedExtrinsic>; pub type Block = generic::Block<Header, UncheckedExtrinsic>;
/// Block ID. /// Block ID.
@@ -99,6 +106,8 @@ pub type BlockId = generic::BlockId<Block>;
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub struct UncheckedExtrinsic(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>); pub struct UncheckedExtrinsic(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
impl Extrinsic for UncheckedExtrinsic {}
/// Inherent data to include in a block. /// Inherent data to include in a block.
#[derive(Encode, Decode)] #[derive(Encode, Decode)]
pub struct InherentData { pub struct InherentData {
@@ -106,6 +115,4 @@ pub struct InherentData {
pub timestamp: Timestamp, pub timestamp: Timestamp,
/// Parachain heads update. /// Parachain heads update.
pub parachain_heads: Vec<::parachain::CandidateReceipt>, pub parachain_heads: Vec<::parachain::CandidateReceipt>,
/// Indices of offline validators.
pub offline_indices: Vec<u32>,
} }
+27 -1
View File
@@ -20,6 +20,8 @@ use rstd::prelude::*;
use rstd::cmp::Ordering; use rstd::cmp::Ordering;
use super::Hash; use super::Hash;
use {AccountId};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use primitives::bytes; use primitives::bytes;
@@ -110,7 +112,7 @@ impl CandidateReceipt {
pub fn check_signature(&self) -> Result<(), ()> { pub fn check_signature(&self) -> Result<(), ()> {
use runtime_primitives::traits::Verify; use runtime_primitives::traits::Verify;
if self.signature.verify(&self.block_data_hash.0[..], &self.collator) { if self.signature.verify(self.block_data_hash.as_ref(), &self.collator) {
Ok(()) Ok(())
} else { } else {
Err(()) Err(())
@@ -205,3 +207,27 @@ pub enum Statement {
/// Vote to advance round after inactive primary. /// Vote to advance round after inactive primary.
Available(Hash), Available(Hash),
} }
decl_runtime_apis! {
/// The API for querying the state of parachains on-chain.
pub trait ParachainHost {
/// Get the current validators.
fn validators() -> Vec<AccountId>;
/// Get the current duty roster.
fn duty_roster() -> DutyRoster;
/// Get the currently active parachains.
fn active_parachains() -> Vec<Id>;
/// Get the given parachain's head data blob.
fn parachain_head(id: Id) -> Option<Vec<u8>>;
/// Get the given parachain's head code blob.
fn parachain_code(id: Id) -> Option<Vec<u8>>;
}
}
/// Runtime ID module.
pub mod id {
use sr_version::ApiId;
/// Parachain host runtime API id.
pub const PARACHAIN_HOST: ApiId = *b"parahost";
}
+6 -5
View File
@@ -6,18 +6,19 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies] [dependencies]
rustc-hex = "1.0" rustc-hex = "1.0"
log = { version = "0.3", optional = true } log = { version = "0.3", optional = true }
serde = { version = "1.0", default_features = false } serde = { version = "1.0", default-features = false }
serde_derive = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true }
safe-mix = { version = "1.0", default_features = false} safe-mix = { version = "1.0", default-features = false}
polkadot-primitives = { path = "../primitives", default_features = false } polkadot-primitives = { path = "../primitives", default-features = false }
parity-codec = { git = "https://github.com/paritytech/substrate" } parity-codec = "2.1"
parity-codec-derive = { git = "https://github.com/paritytech/substrate" } parity-codec-derive = "2.1"
substrate-serializer = { git = "https://github.com/paritytech/substrate" } substrate-serializer = { git = "https://github.com/paritytech/substrate" }
sr-std = { git = "https://github.com/paritytech/substrate" } sr-std = { git = "https://github.com/paritytech/substrate" }
sr-io = { git = "https://github.com/paritytech/substrate" } sr-io = { git = "https://github.com/paritytech/substrate" }
srml-support = { git = "https://github.com/paritytech/substrate" } srml-support = { git = "https://github.com/paritytech/substrate" }
substrate-primitives = { git = "https://github.com/paritytech/substrate" } substrate-primitives = { git = "https://github.com/paritytech/substrate" }
substrate-keyring = { git = "https://github.com/paritytech/substrate" } substrate-keyring = { git = "https://github.com/paritytech/substrate" }
substrate-client = { git = "https://github.com/paritytech/substrate" }
srml-balances = { git = "https://github.com/paritytech/substrate" } srml-balances = { git = "https://github.com/paritytech/substrate" }
srml-consensus = { git = "https://github.com/paritytech/substrate" } srml-consensus = { git = "https://github.com/paritytech/substrate" }
srml-council = { git = "https://github.com/paritytech/substrate" } srml-council = { git = "https://github.com/paritytech/substrate" }
-118
View File
@@ -1,118 +0,0 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Typesafe block interaction.
use super::{Call, Block, TIMESTAMP_SET_POSITION, PARACHAINS_SET_POSITION, NOTE_OFFLINE_POSITION};
use timestamp::Call as TimestampCall;
use parachains::Call as ParachainsCall;
use consensus::Call as ConsensusCall;
use primitives::parachain::CandidateReceipt;
/// Provides a type-safe wrapper around a structurally valid block.
pub struct CheckedBlock {
inner: Block,
file_line: Option<(&'static str, u32)>,
}
impl CheckedBlock {
/// Create a new checked block. Fails if the block is not structurally valid.
pub fn new(block: Block) -> Result<Self, Block> {
let has_timestamp = block.extrinsics.get(TIMESTAMP_SET_POSITION as usize).map_or(false, |xt| {
!xt.is_signed() && match xt.function {
Call::Timestamp(TimestampCall::set(_)) => true,
_ => false,
}
});
if !has_timestamp { return Err(block) }
let has_heads = block.extrinsics.get(PARACHAINS_SET_POSITION as usize).map_or(false, |xt| {
!xt.is_signed() && match xt.function {
Call::Parachains(ParachainsCall::set_heads(_)) => true,
_ => false,
}
});
if !has_heads { return Err(block) }
Ok(CheckedBlock {
inner: block,
file_line: None,
})
}
// Creates a new checked block, asserting that it is valid.
#[doc(hidden)]
pub fn new_unchecked(block: Block, file: &'static str, line: u32) -> Self {
CheckedBlock {
inner: block,
file_line: Some((file, line)),
}
}
/// Extract the timestamp from the block.
pub fn timestamp(&self) -> ::primitives::Timestamp {
let x = self.inner.extrinsics.get(TIMESTAMP_SET_POSITION as usize).and_then(|xt| match xt.function {
Call::Timestamp(TimestampCall::set(x)) => Some(x),
_ => None
});
match x {
Some(x) => x,
None => panic!("Invalid polkadot block asserted at {:?}", self.file_line),
}
}
/// Extract the parachain heads from the block.
pub fn parachain_heads(&self) -> &[CandidateReceipt] {
let x = self.inner.extrinsics.get(PARACHAINS_SET_POSITION as usize).and_then(|xt| match xt.function {
Call::Parachains(ParachainsCall::set_heads(ref x)) => Some(&x[..]),
_ => None
});
match x {
Some(x) => x,
None => panic!("Invalid polkadot block asserted at {:?}", self.file_line),
}
}
/// Extract the noted missed proposal validator indices (if any) from the block.
pub fn noted_offline(&self) -> &[u32] {
self.inner.extrinsics.get(NOTE_OFFLINE_POSITION as usize).and_then(|xt| match xt.function {
Call::Consensus(ConsensusCall::note_offline(ref x)) => Some(&x[..]),
_ => None,
}).unwrap_or(&[])
}
/// Convert into inner block.
pub fn into_inner(self) -> Block { self.inner }
}
impl ::std::ops::Deref for CheckedBlock {
type Target = Block;
fn deref(&self) -> &Block { &self.inner }
}
/// Assert that a block is structurally valid. May lead to panic in the future
/// in case it isn't.
#[macro_export]
macro_rules! assert_polkadot_block {
($block: expr) => {
$crate::CheckedBlock::new_unchecked($block, file!(), line!())
}
}
+325 -315
View File
@@ -17,39 +17,28 @@
//! The Polkadot runtime. This can be compiled with ``#[no_std]`, ready for Wasm. //! The Polkadot runtime. This can be compiled with ``#[no_std]`, ready for Wasm.
#![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.
#[cfg(feature = "std")] #![recursion_limit="256"]
#[macro_use]
extern crate serde_derive;
#[cfg(feature = "std")]
extern crate serde;
#[macro_use] #[macro_use]
extern crate sr_io as runtime_io; extern crate parity_codec_derive;
extern crate parity_codec as codec;
#[macro_use]
extern crate srml_support;
#[macro_use]
extern crate sr_primitives as runtime_primitives;
#[cfg(test)]
#[macro_use]
extern crate hex_literal;
#[cfg(test)]
extern crate substrate_serializer;
extern crate substrate_primitives; extern crate substrate_primitives;
#[macro_use]
extern crate substrate_client as client;
#[macro_use] #[macro_use]
extern crate sr_std as rstd; extern crate sr_std as rstd;
#[cfg(test)]
extern crate sr_io;
#[macro_use] #[macro_use]
extern crate parity_codec_derive; extern crate sr_version as version;
#[macro_use]
extern crate sr_primitives;
extern crate polkadot_primitives as primitives; #[macro_use]
extern crate parity_codec as codec; extern crate srml_support;
extern crate srml_balances as balances; extern crate srml_balances as balances;
extern crate srml_consensus as consensus; extern crate srml_consensus as consensus;
extern crate srml_council as council; extern crate srml_council as council;
@@ -60,69 +49,78 @@ extern crate srml_staking as staking;
extern crate srml_system as system; extern crate srml_system as system;
extern crate srml_timestamp as timestamp; extern crate srml_timestamp as timestamp;
extern crate srml_treasury as treasury; extern crate srml_treasury as treasury;
#[macro_use]
extern crate sr_version as version;
#[cfg(feature = "std")] extern crate polkadot_primitives as primitives;
mod checked_block;
mod parachains; mod parachains;
mod utils;
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use checked_block::CheckedBlock; use codec::{Encode, Decode};
pub use utils::{inherent_extrinsics, check_extrinsic};
pub use balances::address::Address as RawAddress;
use rstd::prelude::*; use rstd::prelude::*;
use codec::{Encode, Decode, Input};
use substrate_primitives::u32_trait::{_2, _4}; use substrate_primitives::u32_trait::{_2, _4};
use primitives::{AccountId, AccountIndex, Balance, BlockNumber, Hash, Index, SessionKey, Signature}; use primitives::{
use runtime_primitives::{generic, traits::{Convert, BlakeTwo256, DigestItem}}; AccountId, AccountIndex, Balance, BlockNumber, Hash, Index, SessionKey, Signature,
parachain, parachain::runtime::ParachainHost, parachain::id::PARACHAIN_HOST,
};
#[cfg(feature = "std")]
use primitives::Block as GBlock;
use client::{block_builder::api::runtime::*, runtime_api::{runtime::*, id::*}};
#[cfg(feature = "std")]
use client::runtime_api::ApiExt;
use sr_primitives::ApplyResult;
use sr_primitives::transaction_validity::TransactionValidity;
use sr_primitives::generic;
use sr_primitives::traits::{Convert, BlakeTwo256, Block as BlockT};
#[cfg(feature = "std")]
use sr_primitives::traits::ApiRef;
#[cfg(feature = "std")]
use substrate_primitives::AuthorityId;
use version::RuntimeVersion; use version::RuntimeVersion;
use council::{motions as council_motions, voting as council_voting}; use council::{motions as council_motions, voting as council_voting};
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use runtime_primitives::BuildStorage; use council::seats as council_seats;
#[cfg(any(feature = "std", test))]
use version::NativeVersion;
use substrate_primitives::OpaqueMetadata;
#[cfg(any(feature = "std", test))]
pub use sr_primitives::BuildStorage;
pub use consensus::Call as ConsensusCall; pub use consensus::Call as ConsensusCall;
pub use timestamp::Call as TimestampCall; pub use timestamp::Call as TimestampCall;
pub use balances::Call as BalancesCall;
pub use parachains::Call as ParachainsCall; pub use parachains::Call as ParachainsCall;
pub use sr_primitives::{Permill, Perbill};
pub use timestamp::BlockPeriod;
pub use srml_support::{StorageValue, RuntimeMetadata};
/// The position of the timestamp set extrinsic. const TIMESTAMP_SET_POSITION: u32 = 0;
pub const TIMESTAMP_SET_POSITION: u32 = 0; const NOTE_OFFLINE_POSITION: u32 = 1;
/// The position of the parachains set extrinsic. const PARACHAINS_SET_POSITION: u32 = 2;
pub const PARACHAINS_SET_POSITION: u32 = 1;
/// The position of the note_offline in the block, if it exists.
pub const NOTE_OFFLINE_POSITION: u32 = 2;
/// Block header type as expected by this runtime. /// Runtime version.
pub type Header = generic::Header<BlockNumber, BlakeTwo256, Log>;
/// The address format for describing accounts.
pub type Address = balances::Address<Runtime>;
/// Block Id type for this block.
pub type BlockId = generic::BlockId<Block>;
/// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Index, Call, Signature>;
/// Extrinsic type that has already been checked.
pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Index, Call>;
/// Block type as expected by this runtime.
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
/// Runtime runtime type used to parameterize the various modules.
// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
pub struct Runtime;
/// Polkadot runtime version.
pub const VERSION: RuntimeVersion = RuntimeVersion { pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: ver_str!("polkadot"), spec_name: ver_str!("polkadot"),
impl_name: ver_str!("parity-polkadot"), impl_name: ver_str!("parity-polkadot"),
authoring_version: 1, authoring_version: 1,
spec_version: 101, spec_version: 101,
impl_version: 0, impl_version: 0,
apis: apis_vec!([
(BLOCK_BUILDER, 1),
(TAGGED_TRANSACTION_QUEUE, 1),
(METADATA, 1),
(PARACHAIN_HOST, 1),
]),
}; };
/// Native version.
#[cfg(any(feature = "std", test))]
pub fn native_version() -> NativeVersion {
NativeVersion {
runtime_version: VERSION,
can_author_with: Default::default(),
}
}
impl system::Trait for Runtime { impl system::Trait for Runtime {
type Origin = Origin; type Origin = Origin;
type Index = Index; type Index = Index;
@@ -131,11 +129,10 @@ impl system::Trait for Runtime {
type Hashing = BlakeTwo256; type Hashing = BlakeTwo256;
type Digest = generic::Digest<Log>; type Digest = generic::Digest<Log>;
type AccountId = AccountId; type AccountId = AccountId;
type Header = Header; type Header = generic::Header<BlockNumber, BlakeTwo256, Log>;
type Event = Event; type Event = Event;
type Log = Log;
} }
/// System module for this concrete runtime.
pub type System = system::Module<Runtime>;
impl balances::Trait for Runtime { impl balances::Trait for Runtime {
type Balance = Balance; type Balance = Balance;
@@ -144,8 +141,6 @@ impl balances::Trait for Runtime {
type EnsureAccountLiquid = Staking; type EnsureAccountLiquid = Staking;
type Event = Event; type Event = Event;
} }
/// Staking module for this concrete runtime.
pub type Balances = balances::Module<Runtime>;
impl consensus::Trait for Runtime { impl consensus::Trait for Runtime {
const NOTE_OFFLINE_POSITION: u32 = NOTE_OFFLINE_POSITION; const NOTE_OFFLINE_POSITION: u32 = NOTE_OFFLINE_POSITION;
@@ -153,21 +148,17 @@ impl consensus::Trait for Runtime {
type SessionKey = SessionKey; type SessionKey = SessionKey;
type OnOfflineValidator = Staking; type OnOfflineValidator = Staking;
} }
/// Consensus module for this concrete runtime.
pub type Consensus = consensus::Module<Runtime>;
impl timestamp::Trait for Runtime { impl timestamp::Trait for Runtime {
const TIMESTAMP_SET_POSITION: u32 = TIMESTAMP_SET_POSITION; const TIMESTAMP_SET_POSITION: u32 = TIMESTAMP_SET_POSITION;
type Moment = u64; type Moment = u64;
} }
/// Timestamp module for this concrete runtime.
pub type Timestamp = timestamp::Module<Runtime>;
/// Session key conversion. /// Session key conversion.
pub struct SessionKeyConversion; pub struct SessionKeyConversion;
impl Convert<AccountId, SessionKey> for SessionKeyConversion { impl Convert<AccountId, SessionKey> for SessionKeyConversion {
fn convert(a: AccountId) -> SessionKey { fn convert(a: AccountId) -> SessionKey {
a.0.into() a.to_fixed_bytes().into()
} }
} }
@@ -176,297 +167,316 @@ impl session::Trait for Runtime {
type OnSessionChange = Staking; type OnSessionChange = Staking;
type Event = Event; type Event = Event;
} }
/// Session module for this concrete runtime.
pub type Session = session::Module<Runtime>;
impl staking::Trait for Runtime { impl staking::Trait for Runtime {
type OnRewardMinted = Treasury; type OnRewardMinted = Treasury;
type Event = Event; type Event = Event;
} }
/// Staking module for this concrete runtime.
pub type Staking = staking::Module<Runtime>;
impl democracy::Trait for Runtime { impl democracy::Trait for Runtime {
type Proposal = Call; type Proposal = Call;
type Event = Event; type Event = Event;
} }
/// Democracy module for this concrete runtime.
pub type Democracy = democracy::Module<Runtime>;
impl council::Trait for Runtime { impl council::Trait for Runtime {
type Event = Event; type Event = Event;
} }
/// Council module for this concrete runtime.
pub type Council = council::Module<Runtime>;
impl council::voting::Trait for Runtime { impl council::voting::Trait for Runtime {
type Event = Event; type Event = Event;
} }
/// Council voting module for this concrete runtime.
pub type CouncilVoting = council::voting::Module<Runtime>;
impl council::motions::Trait for Runtime { impl council::motions::Trait for Runtime {
type Origin = Origin; type Origin = Origin;
type Proposal = Call; type Proposal = Call;
type Event = Event; type Event = Event;
} }
/// Council motions module for this concrete runtime.
pub type CouncilMotions = council_motions::Module<Runtime>;
impl treasury::Trait for Runtime { impl treasury::Trait for Runtime {
type ApproveOrigin = council_motions::EnsureMembers<_4>; type ApproveOrigin = council_motions::EnsureMembers<_4>;
type RejectOrigin = council_motions::EnsureMembers<_2>; type RejectOrigin = council_motions::EnsureMembers<_2>;
type Event = Event; type Event = Event;
} }
/// Treasury module for this concrete runtime.
pub type Treasury = treasury::Module<Runtime>;
impl parachains::Trait for Runtime { impl parachains::Trait for Runtime {
const SET_POSITION: u32 = PARACHAINS_SET_POSITION; const SET_POSITION: u32 = PARACHAINS_SET_POSITION;
} }
pub type Parachains = parachains::Module<Runtime>;
impl_outer_event! { construct_runtime!(
pub enum Event for Runtime { pub enum Runtime with Log(InternalLog: DigestItem<Hash, SessionKey>) where
//consensus, Block = Block,
balances, UncheckedExtrinsic = UncheckedExtrinsic
//timetstamp, {
session, System: system::{default, Log(ChangesTrieRoot)},
staking, Timestamp: timestamp::{Module, Call, Storage, Config<T>, Inherent},
democracy, Consensus: consensus::{Module, Call, Storage, Config<T>, Log(AuthoritiesChange), Inherent},
council, Balances: balances,
council_voting, Session: session,
council_motions, Staking: staking,
treasury Democracy: democracy,
Council: council::{Module, Call, Storage, Event<T>},
CouncilVoting: council_voting,
CouncilMotions: council_motions::{Module, Call, Storage, Event<T>, Origin},
CouncilSeats: council_seats::{Config<T>},
Treasury: treasury,
Parachains: parachains::{Module, Call, Storage, Config<T>, Inherent},
} }
}
impl_outer_log! {
pub enum Log(InternalLog: DigestItem<SessionKey>) for Runtime {
consensus(AuthoritiesChange)
}
}
impl_outer_origin! {
pub enum Origin for Runtime {
council_motions
}
}
impl_outer_dispatch! {
/// Call type for polkadot transactions.
pub enum Call where origin: <Runtime as system::Trait>::Origin {
Consensus,
Balances,
Session,
Staking,
Timestamp,
Democracy,
Council,
CouncilVoting,
CouncilMotions,
Parachains,
Treasury,
}
}
impl_outer_config! {
pub struct GenesisConfig for Runtime {
ConsensusConfig => consensus,
SystemConfig => system,
BalancesConfig => balances,
SessionConfig => session,
StakingConfig => staking,
DemocracyConfig => democracy,
CouncilConfig => council,
TimestampConfig => timestamp,
TreasuryConfig => treasury,
ParachainsConfig => parachains,
}
}
type AllModules = (
Consensus,
Balances,
Session,
Staking,
Timestamp,
Democracy,
Council,
CouncilVoting,
CouncilMotions,
Parachains,
Treasury,
); );
impl_json_metadata!( /// The address format for describing accounts.
for Runtime with modules pub use balances::address::Address as RawAddress;
system::Module with Storage, /// The address format for describing accounts.
consensus::Module with Storage, pub type Address = balances::Address<Runtime>;
balances::Module with Storage, /// Block header type as expected by this runtime.
timestamp::Module with Storage, pub type Header = generic::Header<BlockNumber, BlakeTwo256, Log>;
session::Module with Storage, /// Block type as expected by this runtime.
staking::Module with Storage, pub type Block = generic::Block<Header, UncheckedExtrinsic>;
democracy::Module with Storage, /// A Block signed with a Justification
council::Module with Storage, pub type SignedBlock = generic::SignedBlock<Block>;
council_voting::Module with Storage, /// BlockId type as expected by this runtime.
council_motions::Module with Storage, pub type BlockId = generic::BlockId<Block>;
treasury::Module with Storage, /// Unchecked extrinsic type as expected by this runtime.
parachains::Module with Storage, pub type UncheckedExtrinsic = generic::UncheckedMortalExtrinsic<Address, Index, Call, Signature>;
); /// Extrinsic type that has already been checked.
pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Index, Call>;
/// Executive: handles dispatch to the various modules.
pub type Executive = executive::Executive<Runtime, Block, balances::ChainContext<Runtime>, Balances, AllModules>;
impl DigestItem for Log { #[cfg(feature = "std")]
type AuthorityId = SessionKey; pub struct ClientWithApi {
call: ::std::ptr::NonNull<client::runtime_api::CallApiAt<GBlock>>,
commit_on_success: ::std::cell::RefCell<bool>,
initialised_block: ::std::cell::RefCell<Option<GBlockId>>,
changes: ::std::cell::RefCell<client::runtime_api::OverlayedChanges>,
}
fn as_authorities_change(&self) -> Option<&[Self::AuthorityId]> { #[cfg(feature = "std")]
match self.0 { unsafe impl Send for ClientWithApi {}
InternalLog::consensus(ref item) => item.as_authorities_change(), #[cfg(feature = "std")]
unsafe impl Sync for ClientWithApi {}
#[cfg(feature = "std")]
impl ApiExt for ClientWithApi {
fn map_api_result<F: FnOnce(&Self) -> Result<R, E>, R, E>(&self, map_call: F) -> Result<R, E> {
*self.commit_on_success.borrow_mut() = false;
let res = map_call(self);
*self.commit_on_success.borrow_mut() = true;
self.commit_on_ok(&res);
res
}
}
#[cfg(feature = "std")]
impl client::runtime_api::ConstructRuntimeApi<GBlock> for ClientWithApi {
fn construct_runtime_api<'a, T: client::runtime_api::CallApiAt<GBlock>>(call: &'a T) -> ApiRef<'a, Self> {
ClientWithApi {
call: unsafe {
::std::ptr::NonNull::new_unchecked(
::std::mem::transmute(
call as &client::runtime_api::CallApiAt<GBlock>
)
)
},
commit_on_success: true.into(),
initialised_block: None.into(),
changes: Default::default(),
}.into()
}
}
#[cfg(feature = "std")]
impl ClientWithApi {
fn call_api_at<A: Encode, R: Decode>(
&self,
at: &GBlockId,
function: &'static str,
args: &A
) -> client::error::Result<R> {
let res = unsafe {
self.call.as_ref().call_api_at(
at,
function,
args.encode(),
&mut *self.changes.borrow_mut(),
&mut *self.initialised_block.borrow_mut()
).and_then(|r|
R::decode(&mut &r[..])
.ok_or_else(||
client::error::ErrorKind::CallResultDecode(function).into()
)
)
};
self.commit_on_ok(&res);
res
}
fn commit_on_ok<R, E>(&self, res: &Result<R, E>) {
if *self.commit_on_success.borrow() {
if res.is_err() {
self.changes.borrow_mut().discard_prospective();
} else {
self.changes.borrow_mut().commit_prospective();
}
} }
} }
} }
/// Executive: handles dispatch to the various modules. #[cfg(feature = "std")]
pub type Executive = executive::Executive<Runtime, Block, Balances, Balances, AllModules>; type GBlockId = generic::BlockId<GBlock>;
pub mod api { #[cfg(feature = "std")]
impl_stubs!( impl client::runtime_api::Core<GBlock> for ClientWithApi {
version => |()| super::VERSION, fn version(&self, at: &GBlockId) -> Result<RuntimeVersion, client::error::Error> {
json_metadata => |()| super::Runtime::json_metadata(), self.call_api_at(at, "version", &())
authorities => |()| super::Consensus::authorities(),
initialise_block => |header| super::Executive::initialise_block(&header),
apply_extrinsic => |extrinsic| super::Executive::apply_extrinsic(extrinsic),
execute_block => |block| super::Executive::execute_block(block),
finalise_block => |()| super::Executive::finalise_block(),
inherent_extrinsics => |(inherent, spec_version)| super::inherent_extrinsics(inherent, spec_version),
validator_count => |()| super::Session::validator_count(),
validators => |()| super::Session::validators(),
timestamp => |()| super::Timestamp::get(),
random_seed => |()| super::System::random_seed(),
account_nonce => |account| super::System::account_nonce(&account),
lookup_address => |address| super::Balances::lookup_address(address),
duty_roster => |()| super::Parachains::calculate_duty_roster(),
active_parachains => |()| super::Parachains::active_parachains(),
parachain_head => |id| super::Parachains::parachain_head(&id),
parachain_code => |id| super::Parachains::parachain_code(&id)
);
}
#[cfg(test)]
mod tests {
use super::*;
use substrate_primitives as primitives;
use codec::{Encode, Decode};
use substrate_primitives::hexdisplay::HexDisplay;
use substrate_serializer as ser;
use runtime_primitives::traits::Header as HeaderT;
type Digest = generic::Digest<Log>;
#[test]
fn test_header_serialization() {
let header = Header {
parent_hash: 5.into(),
number: 67,
state_root: 3.into(),
extrinsics_root: 6.into(),
digest: Digest::default(),
};
assert_eq!(ser::to_string_pretty(&header), r#"{
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000005",
"number": 67,
"stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000003",
"extrinsicsRoot": "0x0000000000000000000000000000000000000000000000000000000000000006",
"digest": {
"logs": []
}
}"#);
let v = header.encode();
assert_eq!(Header::decode(&mut &v[..]).unwrap(), header);
} }
#[test] fn authorities(&self, at: &GBlockId) -> Result<Vec<AuthorityId>, client::error::Error> {
fn block_encoding_round_trip() { self.call_api_at(at, "authorities", &())
let mut block = Block {
header: Header::new(1, Default::default(), Default::default(), Default::default(), Default::default()),
extrinsics: vec![
UncheckedExtrinsic::new_unsigned(
Default::default(),
Call::Timestamp(timestamp::Call::set(100_000_000))
)
],
};
let raw = block.encode();
let decoded = Block::decode(&mut &raw[..]).unwrap();
assert_eq!(block, decoded);
block.extrinsics.push(UncheckedExtrinsic::new_unsigned(
10101,
Call::Staking(staking::Call::stake())
));
let raw = block.encode();
let decoded = Block::decode(&mut &raw[..]).unwrap();
assert_eq!(block, decoded);
} }
#[test] fn execute_block(&self, at: &GBlockId, block: &GBlock) -> Result<(), client::error::Error> {
fn block_encoding_substrate_round_trip() { self.call_api_at(at, "execute_block", block)
let mut block = Block {
header: Header::new(1, Default::default(), Default::default(), Default::default(), Default::default()),
extrinsics: vec![
UncheckedExtrinsic::new_unsigned(
Default::default(),
Call::Timestamp(timestamp::Call::set(100_000_000))
)
],
};
block.extrinsics.push(UncheckedExtrinsic::new_unsigned(
10101,
Call::Staking(staking::Call::stake())
));
let raw = block.encode();
let decoded_primitive = ::primitives::Block::decode(&mut &raw[..]).unwrap();
let encoded_primitive = decoded_primitive.encode();
let decoded = Block::decode(&mut &encoded_primitive[..]).unwrap();
assert_eq!(block, decoded);
} }
#[test] fn initialise_block(&self, at: &GBlockId, header: &<GBlock as BlockT>::Header) -> Result<(), client::error::Error> {
fn serialize_unchecked() { self.call_api_at(at, "initialise_block", header)
let tx = UncheckedExtrinsic::new_signed(
999,
Call::Timestamp(TimestampCall::set(135135)),
AccountId::from([1; 32]).into(),
runtime_primitives::Ed25519Signature(primitives::hash::H512([0; 64])).into()
);
// 6f000000
// ff0101010101010101010101010101010101010101010101010101010101010101
// e7030000
// 0300
// df0f0200
// 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
let v = Encode::encode(&tx);
assert_eq!(&v[..], &hex!["7000000001ff010101010101010101010101010101010101010101010101010101010101010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e70300000400df0f020000000000"][..]);
println!("{}", HexDisplay::from(&v));
assert_eq!(UncheckedExtrinsic::decode(&mut &v[..]).unwrap(), tx);
}
#[test]
fn parachain_calls_are_privcall() {
let _register = Call::Parachains(parachains::Call::register_parachain(0.into(), vec![1, 2, 3], vec![]));
let _deregister = Call::Parachains(parachains::Call::deregister_parachain(0.into()));
} }
} }
#[cfg(feature = "std")]
impl client::block_builder::api::BlockBuilder<GBlock> for ClientWithApi {
fn apply_extrinsic(&self, at: &GBlockId, extrinsic: &<GBlock as BlockT>::Extrinsic) -> Result<ApplyResult, client::error::Error> {
self.call_api_at(at, "apply_extrinsic", extrinsic)
}
fn finalise_block(&self, at: &GBlockId) -> Result<<GBlock as BlockT>::Header, client::error::Error> {
self.call_api_at(at, "finalise_block", &())
}
fn inherent_extrinsics<Inherent: Decode + Encode, Unchecked: Decode + Encode>(
&self, at: &GBlockId, inherent: &Inherent
) -> Result<Vec<Unchecked>, client::error::Error> {
self.call_api_at(at, "inherent_extrinsics", inherent)
}
fn check_inherents<Inherent: Decode + Encode, Error: Decode + Encode>(&self, at: &GBlockId, block: &GBlock, inherent: &Inherent) -> Result<Result<(), Error>, client::error::Error> {
self.call_api_at(at, "check_inherents", &(block, inherent))
}
fn random_seed(&self, at: &GBlockId) -> Result<<GBlock as BlockT>::Hash, client::error::Error> {
self.call_api_at(at, "random_seed", &())
}
}
#[cfg(feature = "std")]
impl client::runtime_api::TaggedTransactionQueue<GBlock> for ClientWithApi {
fn validate_transaction(
&self,
at: &GBlockId,
utx: &<GBlock as BlockT>::Extrinsic
) -> Result<TransactionValidity, client::error::Error> {
self.call_api_at(at, "validate_transaction", utx)
}
}
#[cfg(feature = "std")]
impl client::runtime_api::Metadata<GBlock> for ClientWithApi {
fn metadata(&self, at: &GBlockId) -> Result<OpaqueMetadata, client::error::Error> {
self.call_api_at(at, "metadata", &())
}
}
#[cfg(feature = "std")]
impl ::primitives::parachain::ParachainHost<GBlock> for ClientWithApi {
fn validators(&self, at: &GBlockId) -> Result<Vec<primitives::AccountId>, client::error::Error> {
self.call_api_at(at, "validators", &())
}
fn duty_roster(&self, at: &GBlockId) -> Result<primitives::parachain::DutyRoster, client::error::Error> {
self.call_api_at(at, "calculate_duty_roster", &())
}
fn active_parachains(&self, at: &GBlockId) -> Result<Vec<parachain::Id>, client::error::Error> {
self.call_api_at(at, "active_parachains", &())
}
fn parachain_head(&self, at: &GBlockId, id: &parachain::Id) -> Result<Option<Vec<u8>>, client::error::Error> {
self.call_api_at(at, "parachain_head", &id)
}
fn parachain_code(&self, at: &GBlockId, id: &parachain::Id) -> Result<Option<Vec<u8>>, client::error::Error> {
self.call_api_at(at, "parachain_code", &id)
}
}
impl_runtime_apis! {
impl Core<Block> for Runtime {
fn version() -> RuntimeVersion {
VERSION
}
fn authorities() -> Vec<SessionKey> {
Consensus::authorities()
}
fn execute_block(block: Block) {
Executive::execute_block(block)
}
fn initialise_block(header: <Block as BlockT>::Header) {
Executive::initialise_block(&header)
}
}
impl Metadata for Runtime {
fn metadata() -> OpaqueMetadata {
Runtime::metadata().into()
}
}
impl BlockBuilder<Block, InherentData, UncheckedExtrinsic, InherentData, InherentError> for Runtime {
fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyResult {
Executive::apply_extrinsic(extrinsic)
}
fn finalise_block() -> <Block as BlockT>::Header {
Executive::finalise_block()
}
fn inherent_extrinsics(data: InherentData) -> Vec<UncheckedExtrinsic> {
data.create_inherent_extrinsics()
}
fn check_inherents(block: Block, data: InherentData) -> Result<(), InherentError> {
data.check_inherents(block)
}
fn random_seed() -> <Block as BlockT>::Hash {
System::random_seed()
}
}
impl TaggedTransactionQueue<Block> for Runtime {
fn validate_transaction(tx: <Block as BlockT>::Extrinsic) -> TransactionValidity {
Executive::validate_transaction(tx)
}
}
impl ParachainHost for Runtime {
fn validators() -> Vec<AccountId> {
Session::validators()
}
fn duty_roster() -> parachain::DutyRoster {
Parachains::calculate_duty_roster()
}
fn active_parachains() -> Vec<parachain::Id> {
Parachains::active_parachains()
}
fn parachain_head(id: parachain::Id) -> Option<Vec<u8>> {
Parachains::parachain_head(&id)
}
fn parachain_code(id: parachain::Id) -> Option<Vec<u8>> {
Parachains::parachain_code(&id)
}
}
}
+173 -153
View File
@@ -19,7 +19,8 @@
use rstd::prelude::*; use rstd::prelude::*;
use codec::Decode; use codec::Decode;
use runtime_primitives::traits::{Hash, BlakeTwo256, OnFinalise}; use sr_primitives::{RuntimeString, traits::{Extrinsic, Block as BlockT,
Hash, BlakeTwo256, ProvideInherent}};
use primitives::parachain::{Id, Chain, DutyRoster, CandidateReceipt}; use primitives::parachain::{Id, Chain, DutyRoster, CandidateReceipt};
use {system, session}; use {system, session};
@@ -27,43 +28,133 @@ use srml_support::{StorageValue, StorageMap};
use srml_support::dispatch::Result; use srml_support::dispatch::Result;
#[cfg(any(feature = "std", test))] #[cfg(any(feature = "std", test))]
use rstd::marker::PhantomData; use sr_primitives::{self, ChildrenStorageMap};
#[cfg(any(feature = "std", test))] use system::ensure_inherent;
use runtime_primitives;
#[cfg(any(feature = "std", test))] pub trait Trait: session::Trait {
use std::collections::HashMap;
use system::{ensure_root, ensure_inherent};
pub trait Trait: system::Trait<Hash = ::primitives::Hash> + session::Trait {
/// The position of the set_heads call in the block. /// The position of the set_heads call in the block.
const SET_POSITION: u32; const SET_POSITION: u32;
} }
decl_storage! {
trait Store for Module<T: Trait> as Parachains {
// Vector of all parachain IDs.
pub Parachains get(active_parachains): Vec<Id>;
// The parachains registered at present.
pub Code get(parachain_code): map Id => Option<Vec<u8>>;
// The heads of the parachains registered at present. these are kept sorted.
pub Heads get(parachain_head): map Id => Option<Vec<u8>>;
// Did the parachain heads get updated in this block?
DidUpdate: bool;
}
add_extra_genesis {
config(parachains): Vec<(Id, Vec<u8>, Vec<u8>)>;
build(|storage: &mut sr_primitives::StorageMap, _: &mut ChildrenStorageMap, config: &GenesisConfig<T>| {
use codec::Encode;
let mut p = config.parachains.clone();
p.sort_unstable_by_key(|&(ref id, _, _)| id.clone());
p.dedup_by_key(|&mut (ref id, _, _)| id.clone());
let only_ids: Vec<_> = p.iter().map(|&(ref id, _, _)| id).cloned().collect();
storage.insert(GenesisConfig::<T>::hash(<Parachains<T>>::key()).to_vec(), only_ids.encode());
for (id, code, genesis) in p {
let code_key = GenesisConfig::<T>::hash(&<Code<T>>::key_for(&id)).to_vec();
let head_key = GenesisConfig::<T>::hash(&<Heads<T>>::key_for(&id)).to_vec();
storage.insert(code_key, code.encode());
storage.insert(head_key, genesis.encode());
}
});
}
}
decl_module! { decl_module! {
/// Parachains module. /// Parachains module.
pub struct Module<T: Trait> for enum Call where origin: T::Origin { pub struct Module<T: Trait> for enum Call where origin: T::Origin {
/// Provide candidate receipts for parachains, in ascending order by id. /// Provide candidate receipts for parachains, in ascending order by id.
fn set_heads(origin, heads: Vec<CandidateReceipt>) -> Result; fn set_heads(origin, heads: Vec<CandidateReceipt>) -> Result {
ensure_inherent(origin)?;
ensure!(!<DidUpdate<T>>::exists(), "Parachain heads must be updated only once in the block");
ensure!(
<system::Module<T>>::extrinsic_index() == Some(T::SET_POSITION),
"Parachain heads update extrinsic must be at position {} in the block"
// , T::SET_POSITION
);
fn register_parachain(origin, id: Id, code: Vec<u8>, initial_head_data: Vec<u8>) -> Result; let active_parachains = Self::active_parachains();
fn deregister_parachain(origin, id: Id) -> Result;
}
}
decl_storage! { // perform integrity checks before writing to storage.
trait Store for Module<T: Trait> as Parachains { {
// Vector of all parachain IDs. let n_parachains = active_parachains.len();
pub Parachains get(active_parachains): default Vec<Id>; ensure!(heads.len() <= n_parachains, "Too many parachain candidates");
// The parachains registered at present.
pub Code get(parachain_code): map [ Id => Vec<u8> ];
// The heads of the parachains registered at present. these are kept sorted.
pub Heads get(parachain_head): map [ Id => Vec<u8> ];
// Did the parachain heads get updated in this block? let mut last_id = None;
DidUpdate: default bool; let mut iter = active_parachains.iter();
for head in &heads {
// proposed heads must be ascending order by parachain ID without duplicate.
ensure!(
last_id.as_ref().map_or(true, |x| x < &head.parachain_index),
"Parachain candidates out of order by ID"
);
// must be unknown since active parachains are always sorted.
ensure!(
iter.find(|x| x == &&head.parachain_index).is_some(),
"Submitted candidate for unregistered or out-of-order parachain {}"
);
last_id = Some(head.parachain_index);
}
}
for head in heads {
let id = head.parachain_index.clone();
<Heads<T>>::insert(id, head.head_data.0);
}
<DidUpdate<T>>::put(true);
Ok(())
}
/// Register a parachain with given code.
/// Fails if given ID is already used.
pub fn register_parachain(id: Id, code: Vec<u8>, initial_head_data: Vec<u8>) -> Result {
let mut parachains = Self::active_parachains();
match parachains.binary_search(&id) {
Ok(_) => fail!("Parachain already exists"),
Err(idx) => parachains.insert(idx, id),
}
<Code<T>>::insert(id, code);
<Parachains<T>>::put(parachains);
<Heads<T>>::insert(id, initial_head_data);
Ok(())
}
/// Deregister a parachain with given id
pub fn deregister_parachain(id: Id) -> Result {
let mut parachains = Self::active_parachains();
match parachains.binary_search(&id) {
Ok(idx) => { parachains.remove(idx); }
Err(_) => {}
}
<Code<T>>::remove(id);
<Heads<T>>::remove(id);
<Parachains<T>>::put(parachains);
Ok(())
}
fn on_finalise(_n: T::BlockNumber) {
assert!(<Self as Store>::DidUpdate::take(), "Parachain heads must be updated once in the block");
}
} }
} }
@@ -85,7 +176,7 @@ impl<T: Trait> Module<T> {
let mut roles_gua = roles_val.clone(); let mut roles_gua = roles_val.clone();
let mut random_seed = system::Module::<T>::random_seed().to_vec(); let mut random_seed = system::Module::<T>::random_seed().as_ref().to_vec();
random_seed.extend(b"validator_role_pairs"); random_seed.extend(b"validator_role_pairs");
let mut seed = BlakeTwo256::hash(&random_seed); let mut seed = BlakeTwo256::hash(&random_seed);
@@ -103,7 +194,7 @@ impl<T: Trait> Module<T> {
if offset == 24 { if offset == 24 {
// into the last 8 bytes - rehash to gather new entropy // into the last 8 bytes - rehash to gather new entropy
seed = BlakeTwo256::hash(&seed); seed = BlakeTwo256::hash(seed.as_ref());
} }
// exchange last item with randomly chosen first. // exchange last item with randomly chosen first.
@@ -117,134 +208,60 @@ impl<T: Trait> Module<T> {
} }
} }
/// Register a parachain with given code. /*
/// Fails if given ID is already used. // TODO: Consider integrating if needed.
pub fn register_parachain(origin: T::Origin, id: Id, code: Vec<u8>, initial_head_data: Vec<u8>) -> Result { /// Extract the parachain heads from the block.
ensure_root(origin)?; pub fn parachain_heads(&self) -> &[CandidateReceipt] {
let mut parachains = Self::active_parachains(); let x = self.inner.extrinsics.get(PARACHAINS_SET_POSITION as usize).and_then(|xt| match xt.function {
match parachains.binary_search(&id) { Call::Parachains(ParachainsCall::set_heads(ref x)) => Some(&x[..]),
Ok(_) => fail!("Parachain already exists"), _ => None
Err(idx) => parachains.insert(idx, id), });
}
<Code<T>>::insert(id, code); match x {
<Parachains<T>>::put(parachains); Some(x) => x,
<Heads<T>>::insert(id, initial_head_data); None => panic!("Invalid polkadot block asserted at {:?}", self.file_line),
}
}
*/
}
impl<T: Trait> ProvideInherent for Module<T> {
type Inherent = Vec<CandidateReceipt>;
type Call = Call<T>;
type Error = RuntimeString;
fn create_inherent_extrinsics(data: Self::Inherent) -> Vec<(u32, Self::Call)> {
vec![(T::SET_POSITION, Call::set_heads(data))]
}
fn check_inherent<Block: BlockT, F: Fn(&Block::Extrinsic) -> Option<&Self::Call>>(
block: &Block, _data: Self::Inherent, extract_function: &F
) -> ::rstd::result::Result<(), Self::Error> {
let has_heads = block
.extrinsics()
.get(T::SET_POSITION as usize)
.map_or(false, |xt| {
xt.is_signed() == Some(true) && match extract_function(&xt) {
Some(Call::set_heads(_)) => true,
_ => false,
}
});
if !has_heads { return Err("No valid parachains inherent in block".into()) }
Ok(()) Ok(())
} }
/// Deregister a parachain with given id
pub fn deregister_parachain(origin: T::Origin, id: Id) -> Result {
ensure_root(origin)?;
let mut parachains = Self::active_parachains();
match parachains.binary_search(&id) {
Ok(idx) => { parachains.remove(idx); }
Err(_) => {}
}
<Code<T>>::remove(id);
<Heads<T>>::remove(id);
<Parachains<T>>::put(parachains);
Ok(())
}
fn set_heads(origin: T::Origin, heads: Vec<CandidateReceipt>) -> Result {
ensure_inherent(origin)?;
ensure!(!<DidUpdate<T>>::exists(), "Parachain heads must be updated only once in the block");
ensure!(
<system::Module<T>>::extrinsic_index() == Some(T::SET_POSITION),
"Parachain heads update extrinsic must be at position {} in the block"
// , T::SET_POSITION
);
let active_parachains = Self::active_parachains();
let mut iter = active_parachains.iter();
// perform this check before writing to storage.
for head in &heads {
ensure!(
iter.find(|&p| p == &head.parachain_index).is_some(),
"Submitted candidate for unregistered or out-of-order parachain {}"
// , head.parachain_index.into_inner()
);
}
for head in heads {
let id = head.parachain_index.clone();
<Heads<T>>::insert(id, head.head_data.0);
}
<DidUpdate<T>>::put(true);
Ok(())
}
}
impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> {
fn on_finalise(_n: T::BlockNumber) {
assert!(<Self as Store>::DidUpdate::take(), "Parachain heads must be updated once in the block");
}
}
/// Parachains module genesis configuration.
#[cfg(any(feature = "std", test))]
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
pub struct GenesisConfig<T: Trait> {
/// The initial parachains, mapped to code and initial head data
pub parachains: Vec<(Id, Vec<u8>, Vec<u8>)>,
/// Phantom data.
#[serde(skip)]
pub phantom: PhantomData<T>,
}
#[cfg(any(feature = "std", test))]
impl<T: Trait> Default for GenesisConfig<T> {
fn default() -> Self {
GenesisConfig {
parachains: Vec::new(),
phantom: PhantomData,
}
}
}
#[cfg(any(feature = "std", test))]
impl<T: Trait> runtime_primitives::BuildStorage for GenesisConfig<T>
{
fn build_storage(mut self) -> ::std::result::Result<HashMap<Vec<u8>, Vec<u8>>, String> {
use codec::Encode;
self.parachains.sort_unstable_by_key(|&(ref id, _, _)| id.clone());
self.parachains.dedup_by_key(|&mut (ref id, _, _)| id.clone());
let only_ids: Vec<_> = self.parachains.iter().map(|&(ref id, _, _)| id).cloned().collect();
let mut map: HashMap<_, _> = map![
Self::hash(<Parachains<T>>::key()).to_vec() => only_ids.encode()
];
for (id, code, genesis) in self.parachains {
let code_key = Self::hash(&<Code<T>>::key_for(&id)).to_vec();
let head_key = Self::hash(&<Heads<T>>::key_for(&id)).to_vec();
map.insert(code_key, code.encode());
map.insert(head_key, genesis.encode());
}
Ok(map)
}
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use runtime_io::{TestExternalities, with_externalities}; use rstd::marker::PhantomData;
use sr_io::{TestExternalities, with_externalities};
use substrate_primitives::{H256, Blake2Hasher}; use substrate_primitives::{H256, Blake2Hasher};
use runtime_primitives::BuildStorage; use sr_primitives::BuildStorage;
use runtime_primitives::traits::{Identity, BlakeTwo256}; use sr_primitives::traits::{Identity, BlakeTwo256};
use runtime_primitives::testing::{Digest, Header}; use sr_primitives::testing::{Digest, Header, DigestItem};
use {consensus, timestamp}; use {consensus, timestamp};
impl_outer_origin! { impl_outer_origin! {
@@ -257,7 +274,7 @@ mod tests {
const NOTE_OFFLINE_POSITION: u32 = 1; const NOTE_OFFLINE_POSITION: u32 = 1;
type SessionKey = u64; type SessionKey = u64;
type OnOfflineValidator = (); type OnOfflineValidator = ();
type Log = u64; type Log = DigestItem;
} }
impl system::Trait for Test { impl system::Trait for Test {
type Origin = Origin; type Origin = Origin;
@@ -269,6 +286,7 @@ mod tests {
type AccountId = u64; type AccountId = u64;
type Header = Header; type Header = Header;
type Event = (); type Event = ();
type Log = DigestItem;
} }
impl session::Trait for Test { impl session::Trait for Test {
type ConvertAccountIdToSessionKey = Identity; type ConvertAccountIdToSessionKey = Identity;
@@ -286,19 +304,21 @@ mod tests {
type Parachains = Module<Test>; type Parachains = Module<Test>;
fn new_test_ext(parachains: Vec<(Id, Vec<u8>, Vec<u8>)>) -> TestExternalities<Blake2Hasher> { fn new_test_ext(parachains: Vec<(Id, Vec<u8>, Vec<u8>)>) -> TestExternalities<Blake2Hasher> {
let mut t = system::GenesisConfig::<Test>::default().build_storage().unwrap(); let mut t = system::GenesisConfig::<Test>::default().build_storage().unwrap().0;
t.extend(consensus::GenesisConfig::<Test>{ t.extend(consensus::GenesisConfig::<Test>{
code: vec![], code: vec![],
authorities: vec![1, 2, 3], authorities: vec![1, 2, 3],
}.build_storage().unwrap()); _genesis_phantom_data: PhantomData,
}.build_storage().unwrap().0);
t.extend(session::GenesisConfig::<Test>{ t.extend(session::GenesisConfig::<Test>{
session_length: 1000, session_length: 1000,
validators: vec![1, 2, 3, 4, 5, 6, 7, 8], validators: vec![1, 2, 3, 4, 5, 6, 7, 8],
}.build_storage().unwrap()); _genesis_phantom_data: PhantomData,
}.build_storage().unwrap().0);
t.extend(GenesisConfig::<Test>{ t.extend(GenesisConfig::<Test>{
parachains: parachains, parachains: parachains,
phantom: PhantomData, _genesis_phantom_data: PhantomData,
}.build_storage().unwrap()); }.build_storage().unwrap().0);
t.into() t.into()
} }
@@ -329,12 +349,12 @@ mod tests {
assert_eq!(Parachains::parachain_code(&5u32.into()), Some(vec![1,2,3])); assert_eq!(Parachains::parachain_code(&5u32.into()), Some(vec![1,2,3]));
assert_eq!(Parachains::parachain_code(&100u32.into()), Some(vec![4,5,6])); assert_eq!(Parachains::parachain_code(&100u32.into()), Some(vec![4,5,6]));
assert_ok!(Parachains::register_parachain(Origin::ROOT, 99u32.into(), vec![7,8,9], vec![1, 1, 1])); assert_ok!(Parachains::register_parachain(99u32.into(), vec![7,8,9], vec![1, 1, 1]));
assert_eq!(Parachains::active_parachains(), vec![5u32.into(), 99u32.into(), 100u32.into()]); assert_eq!(Parachains::active_parachains(), vec![5u32.into(), 99u32.into(), 100u32.into()]);
assert_eq!(Parachains::parachain_code(&99u32.into()), Some(vec![7,8,9])); assert_eq!(Parachains::parachain_code(&99u32.into()), Some(vec![7,8,9]));
assert_ok!(Parachains::deregister_parachain(Origin::ROOT, 5u32.into())); assert_ok!(Parachains::deregister_parachain(5u32.into()));
assert_eq!(Parachains::active_parachains(), vec![99u32.into(), 100u32.into()]); assert_eq!(Parachains::active_parachains(), vec![99u32.into(), 100u32.into()]);
assert_eq!(Parachains::parachain_code(&5u32.into()), None); assert_eq!(Parachains::parachain_code(&5u32.into()), None);
-47
View File
@@ -1,47 +0,0 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Utils for block interaction.
use rstd::prelude::*;
use super::{Call, UncheckedExtrinsic, Balances};
use runtime_primitives::traits::{Checkable, Lookup};
use timestamp::Call as TimestampCall;
use parachains::Call as ParachainsCall;
use consensus::Call as ConsensusCall;
/// Produces the list of inherent extrinsics.
pub fn inherent_extrinsics(data: ::primitives::InherentData, spec_version: u32) -> Vec<UncheckedExtrinsic> {
let make_inherent = |function| UncheckedExtrinsic::new_unsigned(0, function);
let mut inherent = vec![
make_inherent(Call::Timestamp(TimestampCall::set(data.timestamp))),
make_inherent(Call::Parachains(ParachainsCall::set_heads(data.parachain_heads))),
];
if !data.offline_indices.is_empty() && spec_version == 5 {
inherent.push(make_inherent(
Call::Consensus(ConsensusCall::note_offline(data.offline_indices))
));
}
inherent
}
/// Checks an unchecked extrinsic for validity.
pub fn check_extrinsic(xt: UncheckedExtrinsic) -> bool {
xt.check_with(Balances::lookup).is_ok()
}
+189 -160
View File
@@ -3,12 +3,12 @@ name = "arrayvec"
version = "0.4.7" version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.2.6" version = "1.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@@ -17,14 +17,30 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "fixed-hash" name = "crunchy"
version = "0.2.2" version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "hashdb" name = "fixed-hash"
version = "0.2.1" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hash-db"
version = "0.9.0"
source = "git+https://github.com/paritytech/trie#2616db2a2529098949e5d39aa06dd4e502a9e5f7"
[[package]]
name = "hash256-std-hasher"
version = "0.9.0"
source = "git+https://github.com/paritytech/trie#2616db2a2529098949e5d39aa06dd4e502a9e5f7"
dependencies = [
"crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "hex-literal" name = "hex-literal"
@@ -32,7 +48,7 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@@ -40,7 +56,7 @@ name = "hex-literal-impl"
version = "0.1.1" version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@@ -48,51 +64,68 @@ name = "integer-sqrt"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/paritytech/integer-sqrt-rs.git#886e9cb983c46498003878afe965d55caa762025" source = "git+https://github.com/paritytech/integer-sqrt-rs.git#886e9cb983c46498003878afe965d55caa762025"
[[package]]
name = "integer-sqrt"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "mashup"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"mashup-impl 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mashup-impl"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "nodrop" name = "nodrop"
version = "0.1.12" version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.5" version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "parity-codec" name = "parity-codec"
version = "0.1.0" version = "2.1.5"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "parity-codec-derive" name = "parity-codec-derive"
version = "0.1.0" version = "2.1.0"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357"
dependencies = [
"proc-macro2 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "plain_hasher"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "polkadot-primitives" name = "polkadot-primitives"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"parity-codec 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec-derive 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-std 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-std 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-version 0.1.0 (git+https://github.com/paritytech/substrate)",
"substrate-client 0.1.0 (git+https://github.com/paritytech/substrate)",
"substrate-primitives 0.1.0 (git+https://github.com/paritytech/substrate)", "substrate-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
] ]
@@ -101,8 +134,8 @@ name = "polkadot-runtime"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"integer-sqrt 0.1.0 (git+https://github.com/paritytech/integer-sqrt-rs.git)", "integer-sqrt 0.1.0 (git+https://github.com/paritytech/integer-sqrt-rs.git)",
"parity-codec 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec-derive 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"polkadot-primitives 0.1.0", "polkadot-primitives 0.1.0",
"safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-io 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-io 0.1.0 (git+https://github.com/paritytech/substrate)",
@@ -120,50 +153,37 @@ dependencies = [
"srml-system 0.1.0 (git+https://github.com/paritytech/substrate)", "srml-system 0.1.0 (git+https://github.com/paritytech/substrate)",
"srml-timestamp 0.1.0 (git+https://github.com/paritytech/substrate)", "srml-timestamp 0.1.0 (git+https://github.com/paritytech/substrate)",
"srml-treasury 0.1.0 (git+https://github.com/paritytech/substrate)", "srml-treasury 0.1.0 (git+https://github.com/paritytech/substrate)",
"substrate-client 0.1.0 (git+https://github.com/paritytech/substrate)",
"substrate-primitives 0.1.0 (git+https://github.com/paritytech/substrate)", "substrate-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
] ]
[[package]] [[package]]
name = "proc-macro-hack" name = "proc-macro-hack"
version = "0.4.0" version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "proc-macro-hack-impl" name = "proc-macro-hack-impl"
version = "0.4.0" version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "0.4.15" version = "0.4.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "pwasm-alloc"
version = "0.1.0"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357"
dependencies = [
"pwasm-libc 0.1.0 (git+https://github.com/paritytech/substrate)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pwasm-libc"
version = "0.1.0"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357"
[[package]] [[package]]
name = "quote" name = "quote"
version = "0.6.8" version = "0.6.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@@ -202,16 +222,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.75" version = "1.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "sr-io" name = "sr-io"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357" source = "git+https://github.com/paritytech/substrate#c10123e41c2f4bfa7aa82f65c229920111c66d19"
dependencies = [ dependencies = [
"hashdb 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "hash-db 0.9.0 (git+https://github.com/paritytech/trie)",
"parity-codec 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-std 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-std 0.1.0 (git+https://github.com/paritytech/substrate)",
"substrate-primitives 0.1.0 (git+https://github.com/paritytech/substrate)", "substrate-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
@@ -220,24 +240,12 @@ dependencies = [
[[package]] [[package]]
name = "sr-primitives" name = "sr-primitives"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357" source = "git+https://github.com/paritytech/substrate#c10123e41c2f4bfa7aa82f65c229920111c66d19"
dependencies = [ dependencies = [
"integer-sqrt 0.1.0 (git+https://github.com/paritytech/integer-sqrt-rs.git)", "integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec-derive 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-io 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-std 0.1.0 (git+https://github.com/paritytech/substrate)",
"substrate-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
]
[[package]]
name = "sr-sandbox"
version = "0.1.0"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357"
dependencies = [
"parity-codec 0.1.0 (git+https://github.com/paritytech/substrate)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-io 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-io 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-std 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-std 0.1.0 (git+https://github.com/paritytech/substrate)",
"substrate-primitives 0.1.0 (git+https://github.com/paritytech/substrate)", "substrate-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
@@ -246,34 +254,33 @@ dependencies = [
[[package]] [[package]]
name = "sr-std" name = "sr-std"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357" source = "git+https://github.com/paritytech/substrate#c10123e41c2f4bfa7aa82f65c229920111c66d19"
dependencies = [ dependencies = [
"pwasm-alloc 0.1.0 (git+https://github.com/paritytech/substrate)",
"pwasm-libc 0.1.0 (git+https://github.com/paritytech/substrate)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "sr-version" name = "sr-version"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357" source = "git+https://github.com/paritytech/substrate#c10123e41c2f4bfa7aa82f65c229920111c66d19"
dependencies = [ dependencies = [
"parity-codec 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec-derive 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-std 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-std 0.1.0 (git+https://github.com/paritytech/substrate)",
] ]
[[package]] [[package]]
name = "srml-balances" name = "srml-balances"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357" source = "git+https://github.com/paritytech/substrate#c10123e41c2f4bfa7aa82f65c229920111c66d19"
dependencies = [ dependencies = [
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec-derive 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-io 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-io 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-std 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-std 0.1.0 (git+https://github.com/paritytech/substrate)",
@@ -285,12 +292,12 @@ dependencies = [
[[package]] [[package]]
name = "srml-consensus" name = "srml-consensus"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357" source = "git+https://github.com/paritytech/substrate#c10123e41c2f4bfa7aa82f65c229920111c66d19"
dependencies = [ dependencies = [
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec-derive 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-io 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-io 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-std 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-std 0.1.0 (git+https://github.com/paritytech/substrate)",
@@ -302,19 +309,17 @@ dependencies = [
[[package]] [[package]]
name = "srml-council" name = "srml-council"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357" source = "git+https://github.com/paritytech/substrate#c10123e41c2f4bfa7aa82f65c229920111c66d19"
dependencies = [ dependencies = [
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"integer-sqrt 0.1.0 (git+https://github.com/paritytech/integer-sqrt-rs.git)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec-derive 0.1.0 (git+https://github.com/paritytech/substrate)",
"safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-io 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-io 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-std 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-std 0.1.0 (git+https://github.com/paritytech/substrate)",
"srml-balances 0.1.0 (git+https://github.com/paritytech/substrate)", "srml-balances 0.1.0 (git+https://github.com/paritytech/substrate)",
"srml-consensus 0.1.0 (git+https://github.com/paritytech/substrate)",
"srml-democracy 0.1.0 (git+https://github.com/paritytech/substrate)", "srml-democracy 0.1.0 (git+https://github.com/paritytech/substrate)",
"srml-support 0.1.0 (git+https://github.com/paritytech/substrate)", "srml-support 0.1.0 (git+https://github.com/paritytech/substrate)",
"srml-system 0.1.0 (git+https://github.com/paritytech/substrate)", "srml-system 0.1.0 (git+https://github.com/paritytech/substrate)",
@@ -324,18 +329,17 @@ dependencies = [
[[package]] [[package]]
name = "srml-democracy" name = "srml-democracy"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357" source = "git+https://github.com/paritytech/substrate#c10123e41c2f4bfa7aa82f65c229920111c66d19"
dependencies = [ dependencies = [
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec-derive 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-io 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-io 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-std 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-std 0.1.0 (git+https://github.com/paritytech/substrate)",
"srml-balances 0.1.0 (git+https://github.com/paritytech/substrate)", "srml-balances 0.1.0 (git+https://github.com/paritytech/substrate)",
"srml-consensus 0.1.0 (git+https://github.com/paritytech/substrate)",
"srml-support 0.1.0 (git+https://github.com/paritytech/substrate)", "srml-support 0.1.0 (git+https://github.com/paritytech/substrate)",
"srml-system 0.1.0 (git+https://github.com/paritytech/substrate)", "srml-system 0.1.0 (git+https://github.com/paritytech/substrate)",
"substrate-primitives 0.1.0 (git+https://github.com/paritytech/substrate)", "substrate-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
@@ -344,11 +348,12 @@ dependencies = [
[[package]] [[package]]
name = "srml-executive" name = "srml-executive"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357" source = "git+https://github.com/paritytech/substrate#c10123e41c2f4bfa7aa82f65c229920111c66d19"
dependencies = [ dependencies = [
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-io 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-io 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-std 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-std 0.1.0 (git+https://github.com/paritytech/substrate)",
@@ -356,16 +361,27 @@ dependencies = [
"srml-system 0.1.0 (git+https://github.com/paritytech/substrate)", "srml-system 0.1.0 (git+https://github.com/paritytech/substrate)",
] ]
[[package]]
name = "srml-metadata"
version = "0.1.0"
source = "git+https://github.com/paritytech/substrate#c10123e41c2f4bfa7aa82f65c229920111c66d19"
dependencies = [
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-std 0.1.0 (git+https://github.com/paritytech/substrate)",
"substrate-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
]
[[package]] [[package]]
name = "srml-session" name = "srml-session"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357" source = "git+https://github.com/paritytech/substrate#c10123e41c2f4bfa7aa82f65c229920111c66d19"
dependencies = [ dependencies = [
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec-derive 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-io 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-io 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-std 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-std 0.1.0 (git+https://github.com/paritytech/substrate)",
@@ -379,16 +395,15 @@ dependencies = [
[[package]] [[package]]
name = "srml-staking" name = "srml-staking"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357" source = "git+https://github.com/paritytech/substrate#c10123e41c2f4bfa7aa82f65c229920111c66d19"
dependencies = [ dependencies = [
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec-derive 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-io 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-io 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-sandbox 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-std 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-std 0.1.0 (git+https://github.com/paritytech/substrate)",
"srml-balances 0.1.0 (git+https://github.com/paritytech/substrate)", "srml-balances 0.1.0 (git+https://github.com/paritytech/substrate)",
"srml-consensus 0.1.0 (git+https://github.com/paritytech/substrate)", "srml-consensus 0.1.0 (git+https://github.com/paritytech/substrate)",
@@ -402,26 +417,27 @@ dependencies = [
[[package]] [[package]]
name = "srml-support" name = "srml-support"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357" source = "git+https://github.com/paritytech/substrate#c10123e41c2f4bfa7aa82f65c229920111c66d19"
dependencies = [ dependencies = [
"parity-codec 0.1.0 (git+https://github.com/paritytech/substrate)", "mashup 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-io 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-io 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-std 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-std 0.1.0 (git+https://github.com/paritytech/substrate)",
"substrate-metadata 0.1.0 (git+https://github.com/paritytech/substrate)", "srml-metadata 0.1.0 (git+https://github.com/paritytech/substrate)",
"substrate-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
] ]
[[package]] [[package]]
name = "srml-system" name = "srml-system"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357" source = "git+https://github.com/paritytech/substrate#c10123e41c2f4bfa7aa82f65c229920111c66d19"
dependencies = [ dependencies = [
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec-derive 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-io 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-io 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-std 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-std 0.1.0 (git+https://github.com/paritytech/substrate)",
@@ -432,11 +448,12 @@ dependencies = [
[[package]] [[package]]
name = "srml-timestamp" name = "srml-timestamp"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357" source = "git+https://github.com/paritytech/substrate#c10123e41c2f4bfa7aa82f65c229920111c66d19"
dependencies = [ dependencies = [
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-io 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-io 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-std 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-std 0.1.0 (git+https://github.com/paritytech/substrate)",
@@ -449,12 +466,12 @@ dependencies = [
[[package]] [[package]]
name = "srml-treasury" name = "srml-treasury"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357" source = "git+https://github.com/paritytech/substrate#c10123e41c2f4bfa7aa82f65c229920111c66d19"
dependencies = [ dependencies = [
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec-derive 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-io 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-io 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-std 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-std 0.1.0 (git+https://github.com/paritytech/substrate)",
@@ -465,29 +482,38 @@ dependencies = [
] ]
[[package]] [[package]]
name = "substrate-metadata" name = "static_assertions"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "substrate-client"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357" source = "git+https://github.com/paritytech/substrate#c10123e41c2f4bfa7aa82f65c229920111c66d19"
dependencies = [ dependencies = [
"parity-codec 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-std 0.1.0 (git+https://github.com/paritytech/substrate)",
"sr-version 0.1.0 (git+https://github.com/paritytech/substrate)",
"substrate-primitives 0.1.0 (git+https://github.com/paritytech/substrate)",
] ]
[[package]] [[package]]
name = "substrate-primitives" name = "substrate-primitives"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/paritytech/substrate#b9849fe33203fd34105452ca8e8e638f3918d357" source = "git+https://github.com/paritytech/substrate#c10123e41c2f4bfa7aa82f65c229920111c66d19"
dependencies = [ dependencies = [
"byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "crunchy 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fixed-hash 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "fixed-hash 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hashdb 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "hash-db 0.9.0 (git+https://github.com/paritytech/trie)",
"parity-codec 0.1.0 (git+https://github.com/paritytech/substrate)", "hash256-std-hasher 0.9.0 (git+https://github.com/paritytech/trie)",
"parity-codec-derive 0.1.0 (git+https://github.com/paritytech/substrate)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"plain_hasher 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-std 0.1.0 (git+https://github.com/paritytech/substrate)", "sr-std 0.1.0 (git+https://github.com/paritytech/substrate)",
"uint 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "uint 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@@ -495,18 +521,18 @@ name = "syn"
version = "0.14.9" version = "0.14.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "uint" name = "uint"
version = "0.4.1" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "crunchy 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -517,33 +543,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata] [metadata]
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
"checksum byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90492c5858dd7d2e78691cfb89f90d273a2800fc11d98f60786e5d87e2f83781" "checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
"checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" "checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda"
"checksum fixed-hash 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d5ec8112f00ea8a483e04748a85522184418fd1cf02890b626d8fc28683f7de" "checksum crunchy 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c240f247c278fa08a6d4820a6a222bfc6e0d999e51ba67be94f44c905b2161f2"
"checksum hashdb 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f1c71fc577cde89b3345d5f2880fecaf462a32e96c619f431279bdaf1ba5ddb1" "checksum fixed-hash 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a557e80084b05c32b455963ff565a9de6f2866da023d6671705c6aff6f65e01c"
"checksum hash-db 0.9.0 (git+https://github.com/paritytech/trie)" = "<none>"
"checksum hash256-std-hasher 0.9.0 (git+https://github.com/paritytech/trie)" = "<none>"
"checksum hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4da5f0e01bd8a71a224a4eedecaacfcabda388dbb7a80faf04d3514287572d95" "checksum hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4da5f0e01bd8a71a224a4eedecaacfcabda388dbb7a80faf04d3514287572d95"
"checksum hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1d340b6514f232f6db1bd16db65302a5278a04fef9ce867cb932e7e5fa21130a" "checksum hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1d340b6514f232f6db1bd16db65302a5278a04fef9ce867cb932e7e5fa21130a"
"checksum integer-sqrt 0.1.0 (git+https://github.com/paritytech/integer-sqrt-rs.git)" = "<none>" "checksum integer-sqrt 0.1.0 (git+https://github.com/paritytech/integer-sqrt-rs.git)" = "<none>"
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ea155abb3ba6f382a75f1418988c05fe82959ed9ce727de427f9cfd425b0c903"
"checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe" "checksum mashup 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f2d82b34c7fb11bb41719465c060589e291d505ca4735ea30016a91f6fc79c3b"
"checksum parity-codec 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>" "checksum mashup-impl 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "aa607bfb674b4efb310512527d64266b065de3f894fc52f84efcbf7eaa5965fb"
"checksum parity-codec-derive 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
"checksum plain_hasher 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "95fa6386b1d34aaf0adb9b7dd2885dbe7c34190e6263785e5a7ec2b19044a90f" "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
"checksum proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ba8d4f9257b85eb6cdf13f055cea3190520aab1409ca2ab43493ea4820c25f0" "checksum parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "dca389ea5e1632c89b2ce54f7e2b4a8a8c9d278042222a91e0bf95451218cb4c"
"checksum proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5cb6f960ad471404618e9817c0e5d10b1ae74cfdf01fab89ea0641fe7fb2892" "checksum parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffa42c2cb493b60b12c75b26e8c94cb734af4df4d7f2cc229dc04c1953dac189"
"checksum proc-macro2 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)" = "295af93acfb1d5be29c16ca5b3f82d863836efd9cb0c14fd83811eb9a110e452" "checksum proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c725b36c99df7af7bf9324e9c999b9e37d92c8f8caf106d82e1d7953218d2d8"
"checksum pwasm-alloc 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>" "checksum proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2b753ad9ed99dd8efeaa7d2fb8453c8f6bc3e54b97966d35f1bc77ca6865254a"
"checksum pwasm-libc 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>" "checksum proc-macro2 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)" = "88dae56b29da695d783ea7fc5a90de281f79eb38407e77f6d674dd8befc4ac47"
"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" "checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
"checksum rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "403bb3a286107a04825a5f82e1270acc1e14028d3d554d7a1e08914549575ab8" "checksum rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "403bb3a286107a04825a5f82e1270acc1e14028d3d554d7a1e08914549575ab8"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f7bf422d23a88c16d5090d455f182bc99c60af4df6a345c63428acf5129e347" "checksum safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f7bf422d23a88c16d5090d455f182bc99c60af4df6a345c63428acf5129e347"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)" = "22d340507cea0b7e6632900a176101fea959c7065d93ba555072da90aaaafc87" "checksum serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "15c141fc7027dd265a47c090bf864cf62b42c4d228bbcf4e51a0c9e2b0d3f7ef"
"checksum sr-io 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>" "checksum sr-io 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>"
"checksum sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>" "checksum sr-primitives 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>"
"checksum sr-sandbox 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>"
"checksum sr-std 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>" "checksum sr-std 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>"
"checksum sr-version 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>" "checksum sr-version 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>"
"checksum srml-balances 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>" "checksum srml-balances 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>"
@@ -551,14 +578,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum srml-council 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>" "checksum srml-council 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>"
"checksum srml-democracy 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>" "checksum srml-democracy 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>"
"checksum srml-executive 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>" "checksum srml-executive 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>"
"checksum srml-metadata 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>"
"checksum srml-session 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>" "checksum srml-session 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>"
"checksum srml-staking 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>" "checksum srml-staking 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>"
"checksum srml-support 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>" "checksum srml-support 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>"
"checksum srml-system 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>" "checksum srml-system 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>"
"checksum srml-timestamp 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>" "checksum srml-timestamp 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>"
"checksum srml-treasury 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>" "checksum srml-treasury 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>"
"checksum substrate-metadata 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>" "checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5"
"checksum substrate-client 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>"
"checksum substrate-primitives 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>" "checksum substrate-primitives 0.1.0 (git+https://github.com/paritytech/substrate)" = "<none>"
"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" "checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
"checksum uint 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "754ba11732b9161b94c41798e5197e5e75388d012f760c42adb5000353e98646" "checksum uint 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "082df6964410f6aa929a61ddfafc997e4f32c62c22490e439ac351cec827f436"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
+3 -2
View File
@@ -10,9 +10,10 @@ crate-type = ["cdylib"]
integer-sqrt = { git = "https://github.com/paritytech/integer-sqrt-rs.git", branch = "master" } integer-sqrt = { git = "https://github.com/paritytech/integer-sqrt-rs.git", branch = "master" }
polkadot-primitives = { path = "../../primitives", default-features = false } polkadot-primitives = { path = "../../primitives", default-features = false }
safe-mix = { version = "1.0", default-features = false } safe-mix = { version = "1.0", default-features = false }
parity-codec = { git = "https://github.com/paritytech/substrate", default-features = false } parity-codec = { version = "2.1", default-features = false }
parity-codec-derive = { git = "https://github.com/paritytech/substrate", default-features = false } parity-codec-derive = { version = "2.1", default-features = false }
substrate-primitives = { git = "https://github.com/paritytech/substrate", default-features = false } substrate-primitives = { git = "https://github.com/paritytech/substrate", default-features = false }
substrate-client = { git = "https://github.com/paritytech/substrate", default-features = false }
sr-std = { git = "https://github.com/paritytech/substrate", default-features = false } sr-std = { git = "https://github.com/paritytech/substrate", default-features = false }
sr-io = { git = "https://github.com/paritytech/substrate", default-features = false } sr-io = { git = "https://github.com/paritytech/substrate", default-features = false }
srml-support = { git = "https://github.com/paritytech/substrate", default-features = false } srml-support = { git = "https://github.com/paritytech/substrate", default-features = false }
+4 -4
View File
@@ -14,14 +14,14 @@ hex-literal = "0.1"
polkadot-availability-store = { path = "../availability-store" } polkadot-availability-store = { path = "../availability-store" }
polkadot-primitives = { path = "../primitives" } polkadot-primitives = { path = "../primitives" }
polkadot-runtime = { path = "../runtime" } polkadot-runtime = { path = "../runtime" }
polkadot-consensus = { path = "../consensus" }
polkadot-executor = { path = "../executor" } polkadot-executor = { path = "../executor" }
polkadot-api = { path = "../api" } polkadot-network = { path = "../network" }
polkadot-transaction-pool = { path = "../transaction-pool" }
polkadot-network = { path = "../network" }
sr-io = { git = "https://github.com/paritytech/substrate" } sr-io = { git = "https://github.com/paritytech/substrate" }
sr-primitives = { git = "https://github.com/paritytech/substrate" }
substrate-primitives = { git = "https://github.com/paritytech/substrate" } substrate-primitives = { git = "https://github.com/paritytech/substrate" }
substrate-network = { git = "https://github.com/paritytech/substrate" } substrate-network = { git = "https://github.com/paritytech/substrate" }
substrate-client = { git = "https://github.com/paritytech/substrate" } substrate-client = { git = "https://github.com/paritytech/substrate" }
substrate-consensus-aura = { git = "https://github.com/paritytech/substrate" }
substrate-service = { git = "https://github.com/paritytech/substrate" } substrate-service = { git = "https://github.com/paritytech/substrate" }
substrate-telemetry = { git = "https://github.com/paritytech/substrate" } substrate-telemetry = { git = "https://github.com/paritytech/substrate" }
substrate-transaction-pool = { git = "https://github.com/paritytech/substrate" }
+66 -20
View File
@@ -17,13 +17,16 @@
//! Polkadot chain configurations. //! Polkadot chain configurations.
use primitives::{AuthorityId, ed25519}; use primitives::{AuthorityId, ed25519};
use polkadot_runtime::{GenesisConfig, ConsensusConfig, CouncilConfig, DemocracyConfig, use polkadot_runtime::{GenesisConfig, ConsensusConfig, CouncilSeatsConfig, DemocracyConfig,
SessionConfig, StakingConfig, TimestampConfig, BalancesConfig}; SessionConfig, StakingConfig, TimestampConfig, BalancesConfig, Perbill, CouncilVotingConfig};
use service::ChainSpec;
const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";
const DEFAULT_PROTOCOL_ID: &str = "dot";
pub fn poc_1_testnet_config() -> Result<ChainSpec<GenesisConfig>, String> { /// Specialised `ChainSpec`.
pub type ChainSpec = ::service::ChainSpec<GenesisConfig>;
pub fn poc_1_testnet_config() -> Result<ChainSpec, String> {
ChainSpec::from_embedded(include_bytes!("../res/krummelanke.json")) ChainSpec::from_embedded(include_bytes!("../res/krummelanke.json"))
} }
@@ -41,6 +44,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
consensus: Some(ConsensusConfig { consensus: Some(ConsensusConfig {
code: include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm").to_vec(), // TODO change code: include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm").to_vec(), // TODO change
authorities: initial_authorities.clone(), authorities: initial_authorities.clone(),
_genesis_phantom_data: Default::default(),
}), }),
system: None, system: None,
balances: Some(BalancesConfig { balances: Some(BalancesConfig {
@@ -51,28 +55,34 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
creation_fee: 0, creation_fee: 0,
reclaim_rebate: 0, reclaim_rebate: 0,
balances: endowed_accounts.iter().map(|&k|(k, 1u128 << 60)).collect(), balances: endowed_accounts.iter().map(|&k|(k, 1u128 << 60)).collect(),
_genesis_phantom_data: Default::default(),
}), }),
session: Some(SessionConfig { session: Some(SessionConfig {
validators: initial_authorities.iter().cloned().map(Into::into).collect(), validators: initial_authorities.iter().cloned().map(Into::into).collect(),
session_length: 60, // that's 5 minutes per session. session_length: 60, // that's 5 minutes per session.
_genesis_phantom_data: Default::default(),
}), }),
staking: Some(StakingConfig { staking: Some(StakingConfig {
current_era: 0, current_era: 0,
intentions: initial_authorities.iter().cloned().map(Into::into).collect(), intentions: initial_authorities.iter().cloned().map(Into::into).collect(),
offline_slash: 10000, offline_slash: Perbill::from_billionths(1_000_000),
session_reward: 100, session_reward: Perbill::from_billionths(60),
current_offline_slash: 0,
current_session_reward: 0,
validator_count: 12, validator_count: 12,
sessions_per_era: 12, // 1 hour per era sessions_per_era: 12, // 1 hour per era
bonding_duration: 24 * 60 * 12, // 1 day per bond. bonding_duration: 24 * 60 * 12, // 1 day per bond.
offline_slash_grace: 4, offline_slash_grace: 4,
minimum_validator_count: 4, minimum_validator_count: 4,
_genesis_phantom_data: Default::default(),
}), }),
democracy: Some(DemocracyConfig { democracy: Some(DemocracyConfig {
launch_period: 12 * 60 * 24, // 1 day per public referendum launch_period: 12 * 60 * 24, // 1 day per public referendum
voting_period: 12 * 60 * 24 * 3, // 3 days to discuss & vote on an active referendum voting_period: 12 * 60 * 24 * 3, // 3 days to discuss & vote on an active referendum
minimum_deposit: 5000, // 12000 as the minimum deposit for a referendum minimum_deposit: 5000, // 12000 as the minimum deposit for a referendum
_genesis_phantom_data: Default::default(),
}), }),
council: Some(CouncilConfig { council_seats: Some(CouncilSeatsConfig {
active_council: vec![], active_council: vec![],
candidacy_bond: 5000, // 5000 to become a council candidate candidacy_bond: 5000, // 5000 to become a council candidate
voter_bond: 1000, // 1000 down to vote for a candidate voter_bond: 1000, // 1000 down to vote for a candidate
@@ -83,20 +93,24 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
term_duration: 12 * 60 * 24 * 24, // 24 day term duration for the council. term_duration: 12 * 60 * 24 * 24, // 24 day term duration for the council.
desired_seats: 0, // start with no council: we'll raise this once the stake has been dispersed a bit. desired_seats: 0, // start with no council: we'll raise this once the stake has been dispersed a bit.
inactive_grace_period: 1, // one addition vote should go by before an inactive voter can be reaped. inactive_grace_period: 1, // one addition vote should go by before an inactive voter can be reaped.
_genesis_phantom_data: Default::default(),
cooloff_period: 12 * 60 * 24 * 4, // 4 day cooling off period if council member vetoes a proposal. }),
voting_period: 12 * 60 * 24, // 1 day voting period for council members. council_voting: Some(CouncilVotingConfig {
cooloff_period: 75,
voting_period: 20,
_genesis_phantom_data: Default::default(),
}), }),
parachains: Some(Default::default()), parachains: Some(Default::default()),
timestamp: Some(TimestampConfig { timestamp: Some(TimestampConfig {
period: 5, // 5 second block time. period: 5, // 5 second block time.
_genesis_phantom_data: Default::default(),
}), }),
treasury: Some(Default::default()), treasury: Some(Default::default()),
} }
} }
/// Staging testnet config. /// Staging testnet config.
pub fn staging_testnet_config() -> ChainSpec<GenesisConfig> { pub fn staging_testnet_config() -> ChainSpec {
let boot_nodes = vec![]; let boot_nodes = vec![];
ChainSpec::from_genesis( ChainSpec::from_genesis(
"Staging Testnet", "Staging Testnet",
@@ -104,6 +118,9 @@ pub fn staging_testnet_config() -> ChainSpec<GenesisConfig> {
staging_testnet_config_genesis, staging_testnet_config_genesis,
boot_nodes, boot_nodes,
Some(STAGING_TELEMETRY_URL.into()), Some(STAGING_TELEMETRY_URL.into()),
Some(DEFAULT_PROTOCOL_ID),
None,
None,
) )
} }
@@ -120,6 +137,7 @@ fn testnet_genesis(initial_authorities: Vec<AuthorityId>) -> GenesisConfig {
consensus: Some(ConsensusConfig { consensus: Some(ConsensusConfig {
code: include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm").to_vec(), code: include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm").to_vec(),
authorities: initial_authorities.clone(), authorities: initial_authorities.clone(),
_genesis_phantom_data: Default::default(),
}), }),
system: None, system: None,
balances: Some(BalancesConfig { balances: Some(BalancesConfig {
@@ -130,10 +148,12 @@ fn testnet_genesis(initial_authorities: Vec<AuthorityId>) -> GenesisConfig {
creation_fee: 0, creation_fee: 0,
reclaim_rebate: 0, reclaim_rebate: 0,
balances: endowed_accounts.iter().map(|&k|(k, (1u128 << 60))).collect(), balances: endowed_accounts.iter().map(|&k|(k, (1u128 << 60))).collect(),
_genesis_phantom_data: Default::default(),
}), }),
session: Some(SessionConfig { session: Some(SessionConfig {
validators: initial_authorities.iter().cloned().map(Into::into).collect(), validators: initial_authorities.iter().cloned().map(Into::into).collect(),
session_length: 10, session_length: 10,
_genesis_phantom_data: Default::default(),
}), }),
staking: Some(StakingConfig { staking: Some(StakingConfig {
current_era: 0, current_era: 0,
@@ -142,17 +162,21 @@ fn testnet_genesis(initial_authorities: Vec<AuthorityId>) -> GenesisConfig {
validator_count: 2, validator_count: 2,
sessions_per_era: 5, sessions_per_era: 5,
bonding_duration: 2 * 60 * 12, bonding_duration: 2 * 60 * 12,
offline_slash: 0, offline_slash: Perbill::zero(),
session_reward: 0, session_reward: Perbill::zero(),
current_offline_slash: 0,
current_session_reward: 0,
offline_slash_grace: 0, offline_slash_grace: 0,
_genesis_phantom_data: Default::default(),
}), }),
democracy: Some(DemocracyConfig { democracy: Some(DemocracyConfig {
launch_period: 9, launch_period: 9,
voting_period: 18, voting_period: 18,
minimum_deposit: 10, minimum_deposit: 10,
_genesis_phantom_data: Default::default(),
}), }),
council: Some(CouncilConfig { council_seats: Some(CouncilSeatsConfig {
active_council: endowed_accounts.iter().filter(|a| initial_authorities.iter().find(|&b| a.0 == b.0).is_none()).map(|a| (a.clone(), 1000000)).collect(), active_council: endowed_accounts.iter().filter(|a| initial_authorities.iter().find(|&b| a[..] == b.0).is_none()).map(|a| (a.clone(), 1000000)).collect(),
candidacy_bond: 10, candidacy_bond: 10,
voter_bond: 2, voter_bond: 2,
present_slash_per_voter: 1, present_slash_per_voter: 1,
@@ -162,13 +186,17 @@ fn testnet_genesis(initial_authorities: Vec<AuthorityId>) -> GenesisConfig {
term_duration: 1000000, term_duration: 1000000,
desired_seats: (endowed_accounts.len() - initial_authorities.len()) as u32, desired_seats: (endowed_accounts.len() - initial_authorities.len()) as u32,
inactive_grace_period: 1, inactive_grace_period: 1,
_genesis_phantom_data: Default::default(),
}),
council_voting: Some(CouncilVotingConfig {
cooloff_period: 75, cooloff_period: 75,
voting_period: 20, voting_period: 20,
_genesis_phantom_data: Default::default(),
}), }),
parachains: Some(Default::default()), parachains: Some(Default::default()),
timestamp: Some(TimestampConfig { timestamp: Some(TimestampConfig {
period: 5, // 5 second block time. period: 5, // 5 second block time.
_genesis_phantom_data: Default::default(),
}), }),
treasury: Some(Default::default()), treasury: Some(Default::default()),
} }
@@ -181,8 +209,17 @@ fn development_config_genesis() -> GenesisConfig {
} }
/// Development config (single validator Alice) /// Development config (single validator Alice)
pub fn development_config() -> ChainSpec<GenesisConfig> { pub fn development_config() -> ChainSpec {
ChainSpec::from_genesis("Development", "development", development_config_genesis, vec![], None) ChainSpec::from_genesis(
"Development",
"development",
development_config_genesis,
vec![],
None,
Some(DEFAULT_PROTOCOL_ID),
None,
None,
)
} }
fn local_testnet_genesis() -> GenesisConfig { fn local_testnet_genesis() -> GenesisConfig {
@@ -193,6 +230,15 @@ fn local_testnet_genesis() -> GenesisConfig {
} }
/// Local testnet config (multivalidator Alice + Bob) /// Local testnet config (multivalidator Alice + Bob)
pub fn local_testnet_config() -> ChainSpec<GenesisConfig> { pub fn local_testnet_config() -> ChainSpec {
ChainSpec::from_genesis("Local Testnet", "local_testnet", local_testnet_genesis, vec![], None) ChainSpec::from_genesis(
"Local Testnet",
"local_testnet",
local_testnet_genesis,
vec![],
None,
Some(DEFAULT_PROTOCOL_ID),
None,
None,
)
} }
+125 -193
View File
@@ -22,14 +22,16 @@ extern crate polkadot_availability_store as av_store;
extern crate polkadot_primitives; extern crate polkadot_primitives;
extern crate polkadot_runtime; extern crate polkadot_runtime;
extern crate polkadot_executor; extern crate polkadot_executor;
extern crate polkadot_api;
extern crate polkadot_consensus as consensus;
extern crate polkadot_transaction_pool as transaction_pool;
extern crate polkadot_network; extern crate polkadot_network;
extern crate sr_primitives;
extern crate substrate_primitives as primitives; extern crate substrate_primitives as primitives;
#[macro_use]
extern crate substrate_network as network; extern crate substrate_network as network;
extern crate substrate_client as client; extern crate substrate_client as client;
#[macro_use]
extern crate substrate_service as service; extern crate substrate_service as service;
extern crate substrate_consensus_aura as consensus;
extern crate substrate_transaction_pool as transaction_pool;
extern crate tokio; extern crate tokio;
#[macro_use] #[macro_use]
@@ -40,51 +42,27 @@ extern crate hex_literal;
pub mod chain_spec; pub mod chain_spec;
use std::sync::Arc; use std::sync::Arc;
use tokio::prelude::{Stream, Future}; use polkadot_primitives::{parachain, AccountId, Block};
use transaction_pool::TransactionPool; use polkadot_runtime::{GenesisConfig, ClientWithApi};
use polkadot_api::{PolkadotApi, light::RemotePolkadotApiWrapper};
use polkadot_primitives::{parachain, AccountId, Block, BlockId, Hash};
use polkadot_runtime::GenesisConfig;
use client::{Client, BlockchainEvents};
use polkadot_network::{PolkadotProtocol, consensus::ConsensusNetwork};
use tokio::runtime::TaskExecutor; use tokio::runtime::TaskExecutor;
use service::FactoryFullConfiguration; use service::{FactoryFullConfiguration, FullBackend, LightBackend, FullExecutor, LightExecutor};
use primitives::{Blake2Hasher, RlpCodec}; use transaction_pool::txpool::{Pool as TransactionPool};
use consensus::{import_queue, start_aura, Config as AuraConfig, AuraImportQueue, NothingExtra};
pub use service::{Roles, PruningMode, ExtrinsicPoolOptions, pub use service::{
ErrorKind, Error, ComponentBlock, LightComponents, FullComponents}; Roles, PruningMode, TransactionPoolOptions, ComponentClient,
pub use client::ExecutionStrategy; ErrorKind, Error, ComponentBlock, LightComponents, FullComponents,
FullClient, LightClient, Components, Service, ServiceFactory
};
pub use service::config::full_version_from_strs;
pub use client::{backend::Backend, runtime_api::Core as CoreApi, ExecutionStrategy};
pub use polkadot_network::{PolkadotProtocol, NetworkService};
pub use polkadot_primitives::parachain::ParachainHost;
pub use primitives::{Blake2Hasher};
pub use sr_primitives::traits::ProvideRuntimeApi;
pub use chain_spec::ChainSpec;
/// Specialised polkadot `ChainSpec`. const AURA_SLOT_DURATION: u64 = 6;
pub type ChainSpec = service::ChainSpec<GenesisConfig>;
/// Polkadot client type for specialised `Components`.
pub type ComponentClient<C> = Client<<C as Components>::Backend, <C as Components>::Executor, Block>;
pub type NetworkService = network::Service<Block, <Factory as service::ServiceFactory>::NetworkProtocol, Hash>;
/// A collection of type to generalise Polkadot specific components over full / light client.
pub trait Components: service::Components {
/// Polkadot API.
type Api: 'static + PolkadotApi + Send + Sync;
/// Client backend.
type Backend: 'static + client::backend::Backend<Block, Blake2Hasher, RlpCodec>;
/// Client executor.
type Executor: 'static + client::CallExecutor<Block, Blake2Hasher, RlpCodec> + Send + Sync;
}
impl Components for service::LightComponents<Factory> {
type Api = RemotePolkadotApiWrapper<
<service::LightComponents<Factory> as service::Components>::Backend,
<service::LightComponents<Factory> as service::Components>::Executor,
>;
type Executor = service::LightExecutor<Factory>;
type Backend = service::LightBackend<Factory>;
}
impl Components for service::FullComponents<Factory> {
type Api = service::FullClient<Factory>;
type Executor = service::FullExecutor<Factory>;
type Backend = service::FullBackend<Factory>;
}
/// All configuration for the polkadot node. /// All configuration for the polkadot node.
pub type Configuration = FactoryFullConfiguration<Factory>; pub type Configuration = FactoryFullConfiguration<Factory>;
@@ -97,169 +75,123 @@ pub struct CustomConfiguration {
pub collating_for: Option<(AccountId, parachain::Id)>, pub collating_for: Option<(AccountId, parachain::Id)>,
} }
/// Polkadot config for the substrate service. /// Chain API type for the transaction pool.
pub struct Factory; pub type TxChainApi<Backend, Executor> = transaction_pool::ChainApi<
client::Client<Backend, Executor, Block, ClientWithApi>,
Block,
>;
impl service::ServiceFactory for Factory { /// Provides polkadot types.
type Block = Block; pub trait PolkadotService {
type ExtrinsicHash = Hash; /// The client's backend type.
type NetworkProtocol = PolkadotProtocol; type Backend: 'static + client::backend::Backend<Block, Blake2Hasher>;
type RuntimeDispatch = polkadot_executor::Executor; /// The client's call executor type.
type FullExtrinsicPoolApi = transaction_pool::ChainApi<service::FullClient<Self>>; type Executor: 'static + client::CallExecutor<Block, Blake2Hasher> + Send + Sync + Clone;
type LightExtrinsicPoolApi = transaction_pool::ChainApi<
RemotePolkadotApiWrapper<service::LightBackend<Self>, service::LightExecutor<Self>>
>;
type Genesis = GenesisConfig;
type Configuration = CustomConfiguration;
const NETWORK_PROTOCOL_ID: network::ProtocolId = ::polkadot_network::DOT_PROTOCOL_ID; /// Get a handle to the client.
fn client(&self) -> Arc<client::Client<Self::Backend, Self::Executor, Block, ClientWithApi>>;
fn build_full_extrinsic_pool(config: ExtrinsicPoolOptions, client: Arc<service::FullClient<Self>>) /// Get a handle to the network.
-> Result<TransactionPool<service::FullClient<Self>>, Error> fn network(&self) -> Arc<NetworkService>;
{
let api = client.clone(); /// Get a handle to the transaction pool.
Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(api))) fn transaction_pool(&self) -> Arc<TransactionPool<TxChainApi<Self::Backend, Self::Executor>>>;
}
impl PolkadotService for Service<FullComponents<Factory>> {
type Backend = <FullComponents<Factory> as Components>::Backend;
type Executor = <FullComponents<Factory> as Components>::Executor;
fn client(&self) -> Arc<client::Client<Self::Backend, Self::Executor, Block, ClientWithApi>> {
Service::client(self)
}
fn network(&self) -> Arc<NetworkService> {
Service::network(self)
} }
fn build_light_extrinsic_pool(config: ExtrinsicPoolOptions, client: Arc<service::LightClient<Self>>) fn transaction_pool(&self) -> Arc<TransactionPool<TxChainApi<Self::Backend, Self::Executor>>> {
-> Result<TransactionPool<RemotePolkadotApiWrapper<service::LightBackend<Self>, service::LightExecutor<Self>>>, Error> Service::transaction_pool(self)
{
let api = Arc::new(RemotePolkadotApiWrapper(client.clone()));
Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(api)))
}
fn build_network_protocol(config: &Configuration)
-> Result<PolkadotProtocol, Error>
{
if let Some((_, ref para_id)) = config.custom.collating_for {
info!("Starting network in Collator mode for parachain {:?}", para_id);
}
Ok(PolkadotProtocol::new(config.custom.collating_for))
} }
} }
/// Polkadot service. impl PolkadotService for Service<LightComponents<Factory>> {
pub struct Service<C: Components> { type Backend = <LightComponents<Factory> as Components>::Backend;
inner: service::Service<C>, type Executor = <LightComponents<Factory> as Components>::Executor;
client: Arc<ComponentClient<C>>,
network: Arc<NetworkService>,
api: Arc<<C as Components>::Api>,
_consensus: Option<consensus::Service>,
}
impl <C: Components> Service<C> { fn client(&self) -> Arc<client::Client<Self::Backend, Self::Executor, Block, ClientWithApi>> {
pub fn client(&self) -> Arc<ComponentClient<C>> { Service::client(self)
self.client.clone() }
fn network(&self) -> Arc<NetworkService> {
Service::network(self)
} }
pub fn network(&self) -> Arc<NetworkService> { fn transaction_pool(&self) -> Arc<TransactionPool<TxChainApi<Self::Backend, Self::Executor>>> {
self.network.clone() Service::transaction_pool(self)
}
pub fn api(&self) -> Arc<<C as Components>::Api> {
self.api.clone()
} }
} }
/// Creates light client and register protocol with the network service construct_service_factory! {
pub fn new_light(config: Configuration, executor: TaskExecutor) struct Factory {
-> Result<Service<LightComponents<Factory>>, Error> Block = Block,
{ RuntimeApi = ClientWithApi,
let service = service::Service::<LightComponents<Factory>>::new(config, executor.clone())?; NetworkProtocol = PolkadotProtocol { |config: &Configuration| Ok(PolkadotProtocol::new(config.custom.collating_for)) },
let api = Arc::new(RemotePolkadotApiWrapper(service.client())); RuntimeDispatch = polkadot_executor::Executor,
let pool = service.extrinsic_pool(); FullTransactionPoolApi = TxChainApi<FullBackend<Self>, FullExecutor<Self>>
let events = service.client().import_notification_stream() { |config, client| Ok(TransactionPool::new(config, TxChainApi::new(client))) },
.for_each(move |notification| { LightTransactionPoolApi = TxChainApi<LightBackend<Self>, LightExecutor<Self>>
// re-verify all transactions without the sender. { |config, client| Ok(TransactionPool::new(config, TxChainApi::new(client))) },
pool.retry_verification(&BlockId::hash(notification.hash), None) Genesis = GenesisConfig,
.map_err(|e| warn!("Error re-verifying transactions: {:?}", e))?; Configuration = CustomConfiguration,
Ok(()) FullService = FullComponents<Self>
}) { |config: FactoryFullConfiguration<Self>, executor: TaskExecutor| {
.then(|_| Ok(())); let is_auth = config.roles == Roles::AUTHORITY;
executor.spawn(events); FullComponents::<Factory>::new(config, executor.clone()).map(move |service|{
Ok(Service { if is_auth {
client: service.client(), if let Ok(Some(Ok(key))) = service.keystore().contents()
network: service.network(), .map(|keys| keys.get(0).map(|k| service.keystore().load(k, "")))
api: api, {
inner: service, info!("Using authority key {}", key.public());
_consensus: None, let task = start_aura(
}) AuraConfig {
} local_key: Some(Arc::new(key)),
slot_duration: AURA_SLOT_DURATION,
},
service.client(),
service.proposer(),
service.network(),
);
/// Creates full client and register protocol with the network service executor.spawn(task);
pub fn new_full(config: Configuration, executor: TaskExecutor) }
-> Result<Service<FullComponents<Factory>>, Error> }
{
// open availability store.
let av_store = {
use std::path::PathBuf;
let mut path = PathBuf::from(config.database_path.clone()); service
path.push("availability"); })
}
::av_store::Store::new(::av_store::Config { },
cache_size: None, AuthoritySetup = { |service, _, _| Ok(service) },
path, LightService = LightComponents<Self>
})? { |config, executor| <LightComponents<Factory>>::new(config, executor) },
}; FullImportQueue = AuraImportQueue<Self::Block, FullClient<Self>, NothingExtra>
{ |config, client| Ok(import_queue(
let is_validator = (config.roles & Roles::AUTHORITY) == Roles::AUTHORITY; AuraConfig {
let service = service::Service::<FullComponents<Factory>>::new(config, executor.clone())?; local_key: None,
let pool = service.extrinsic_pool(); slot_duration: 5
let events = service.client().import_notification_stream() },
.for_each(move |notification| { client,
// re-verify all transactions without the sender. NothingExtra,
pool.retry_verification(&BlockId::hash(notification.hash), None) ))
.map_err(|e| warn!("Error re-verifying transactions: {:?}", e))?; },
Ok(()) LightImportQueue = AuraImportQueue<Self::Block, LightClient<Self>, NothingExtra>
}) { |config, client| Ok(import_queue(
.then(|_| Ok(())); AuraConfig {
executor.spawn(events); local_key: None,
// Spin consensus service if configured slot_duration: 5
let consensus = if is_validator { },
// Load the first available key client,
let key = service.keystore().load(&service.keystore().contents()?[0], "")?; NothingExtra,
info!("Using authority key {}", key.public()); ))
},
let client = service.client();
let consensus_net = ConsensusNetwork::new(service.network(), client.clone());
Some(consensus::Service::new(
client.clone(),
client.clone(),
consensus_net,
service.extrinsic_pool(),
executor,
::std::time::Duration::from_secs(4), // TODO: dynamic
key,
av_store.clone(),
))
} else {
None
};
service.network().with_spec(|spec, _| spec.register_availability_store(av_store));
Ok(Service {
client: service.client(),
network: service.network(),
api: service.client(),
inner: service,
_consensus: consensus,
})
}
/// Creates bare client without any networking.
pub fn new_client(config: Configuration)
-> Result<Arc<service::ComponentClient<FullComponents<Factory>>>, Error>
{
service::new_client::<Factory>(config)
}
impl<C: Components> ::std::ops::Deref for Service<C> {
type Target = service::Service<C>;
fn deref(&self) -> &Self::Target {
&self.inner
} }
} }
+2 -2
View File
@@ -25,7 +25,7 @@ extern crate futures;
#[macro_use] #[macro_use]
extern crate error_chain; extern crate error_chain;
use cli::{ServiceComponents, Service, VersionInfo}; use cli::{PolkadotService, VersionInfo};
use futures::sync::oneshot; use futures::sync::oneshot;
use futures::{future, Future}; use futures::{future, Future};
@@ -57,7 +57,7 @@ impl cli::IntoExit for Worker {
impl cli::Worker for Worker { impl cli::Worker for Worker {
type Work = <Self as cli::IntoExit>::Exit; type Work = <Self as cli::IntoExit>::Exit;
fn work<C: ServiceComponents>(self, _service: &Service<C>) -> Self::Work { fn work<S: PolkadotService>(self, _service: &S) -> Self::Work {
use cli::IntoExit; use cli::IntoExit;
self.into_exit() self.into_exit()
} }
+2 -2
View File
@@ -4,7 +4,7 @@ version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
[dependencies] [dependencies]
parity-codec = { git = "https://github.com/paritytech/substrate" } parity-codec = "2.1"
parity-codec-derive = { git = "https://github.com/paritytech/substrate" } parity-codec-derive = "2.1"
substrate-primitives = { git = "https://github.com/paritytech/substrate" } substrate-primitives = { git = "https://github.com/paritytech/substrate" }
polkadot-primitives = { path = "../primitives" } polkadot-primitives = { path = "../primitives" }
+2 -1
View File
@@ -6,5 +6,6 @@ description = "Test parachain which adds to a number as its state transition"
[dependencies] [dependencies]
polkadot-parachain = { path = "../../parachain/", default-features = false } polkadot-parachain = { path = "../../parachain/", default-features = false }
parity-codec-derive = { git = "https://github.com/paritytech/substrate", default-features = false } parity-codec = { version = "2.1", default-features = false }
parity-codec-derive = { version = "2.1", default-features = false }
tiny-keccak = "1.4" tiny-keccak = "1.4"
+2 -2
View File
@@ -20,11 +20,11 @@
#[macro_use] #[macro_use]
extern crate parity_codec_derive; extern crate parity_codec_derive;
extern crate parity_codec;
extern crate polkadot_parachain as parachain; extern crate polkadot_parachain as parachain;
extern crate tiny_keccak; extern crate tiny_keccak;
use parachain::codec::{self, Encode}; use parity_codec::Encode;
/// Head data for this parachain. /// Head data for this parachain.
#[derive(Default, Clone, Hash, Eq, PartialEq, Encode, Decode)] #[derive(Default, Clone, Hash, Eq, PartialEq, Encode, Decode)]
-18
View File
@@ -1,18 +0,0 @@
[package]
name = "polkadot-transaction-pool"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
log = "0.3.0"
error-chain = "0.12"
parking_lot = "0.4"
polkadot-api = { path = "../api" }
polkadot-primitives = { path = "../primitives" }
polkadot-runtime = { path = "../runtime" }
substrate-client = { git = "https://github.com/paritytech/substrate" }
parity-codec = { git = "https://github.com/paritytech/substrate" }
substrate-keyring = { git = "https://github.com/paritytech/substrate" }
substrate-extrinsic-pool = { git = "https://github.com/paritytech/substrate" }
substrate-primitives = { git = "https://github.com/paritytech/substrate" }
sr-primitives = { git = "https://github.com/paritytech/substrate" }
-5
View File
@@ -1,5 +0,0 @@
= Polkadot Transactin pool
placeholder
//TODO Write content :)
-73
View File
@@ -1,73 +0,0 @@
// Copyright 2018 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use extrinsic_pool;
use polkadot_api;
use primitives::Hash;
use runtime::{Address, UncheckedExtrinsic};
error_chain! {
links {
Pool(extrinsic_pool::Error, extrinsic_pool::ErrorKind);
Api(polkadot_api::Error, polkadot_api::ErrorKind);
}
errors {
/// Unexpected extrinsic format submitted
InvalidExtrinsicFormat {
description("Invalid extrinsic format."),
display("Invalid extrinsic format."),
}
/// Attempted to queue an inherent transaction.
IsInherent(xt: UncheckedExtrinsic) {
description("Inherent transactions cannot be queued."),
display("Inherent transactions cannot be queued."),
}
/// Attempted to queue a transaction with bad signature.
BadSignature(e: &'static str) {
description("Transaction had bad signature."),
display("Transaction had bad signature: {}", e),
}
/// Attempted to queue a transaction that is already in the pool.
AlreadyImported(hash: Hash) {
description("Transaction is already in the pool."),
display("Transaction {:?} is already in the pool.", hash),
}
/// Import error.
Import(err: Box<::std::error::Error + Send>) {
description("Error importing transaction"),
display("Error importing transaction: {}", err.description()),
}
/// Runtime failure.
UnrecognisedAddress(who: Address) {
description("Unrecognised address in extrinsic"),
display("Unrecognised address in extrinsic: {}", who),
}
/// Extrinsic too large
TooLarge(got: usize, max: usize) {
description("Extrinsic too large"),
display("Extrinsic is too large ({} > {})", got, max),
}
}
}
impl extrinsic_pool::IntoPoolError for Error {
fn into_pool_error(self) -> ::std::result::Result<extrinsic_pool::Error, Self> {
match self {
Error(ErrorKind::Pool(e), c) => Ok(extrinsic_pool::Error(e, c)),
e => Err(e),
}
}
}
-579
View File
@@ -1,579 +0,0 @@
// Copyright 2018 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
extern crate substrate_client as client;
extern crate parity_codec as codec;
extern crate substrate_extrinsic_pool as extrinsic_pool;
extern crate substrate_primitives;
extern crate sr_primitives;
extern crate polkadot_runtime as runtime;
extern crate polkadot_primitives as primitives;
extern crate polkadot_api;
extern crate parking_lot;
#[cfg(test)]
extern crate substrate_keyring;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate log;
mod error;
use std::{
cmp::Ordering,
collections::HashMap,
sync::Arc,
};
use codec::{Decode, Encode};
use extrinsic_pool::{Readiness, scoring::{Change, Choice}, VerifiedFor, ExtrinsicFor};
use polkadot_api::PolkadotApi;
use primitives::{AccountId, BlockId, Block, Hash, Index};
use runtime::{Address, UncheckedExtrinsic};
use sr_primitives::traits::{Bounded, Checkable, Hash as HashT, BlakeTwo256};
pub use extrinsic_pool::{Options, Status, LightStatus, VerifiedTransaction as VerifiedTransactionOps};
pub use error::{Error, ErrorKind, Result};
/// Maximal size of a single encoded extrinsic.
///
/// See also polkadot-consensus::MAX_TRANSACTIONS_SIZE
const MAX_TRANSACTION_SIZE: usize = 4 * 1024 * 1024;
/// Type alias for convenience.
pub type CheckedExtrinsic = <UncheckedExtrinsic as Checkable<fn(Address) -> std::result::Result<AccountId, &'static str>>>::Checked;
/// Type alias for polkadot transaction pool.
pub type TransactionPool<A> = extrinsic_pool::Pool<ChainApi<A>>;
/// A verified transaction which should be includable and non-inherent.
#[derive(Clone, Debug)]
pub struct VerifiedTransaction {
inner: Option<CheckedExtrinsic>,
sender: Option<AccountId>,
hash: Hash,
encoded_size: usize,
index: Index,
}
impl VerifiedTransaction {
/// Consume the verified transaction, yielding the checked counterpart.
pub fn into_inner(self) -> Option<CheckedExtrinsic> {
self.inner
}
/// Get the 256-bit hash of this transaction.
pub fn hash(&self) -> &Hash {
&self.hash
}
/// Get the account ID of the sender of this transaction.
pub fn sender(&self) -> Option<AccountId> {
self.sender
}
/// Get the account ID of the sender of this transaction.
pub fn index(&self) -> Index {
self.index
}
/// Get encoded size of the transaction.
pub fn encoded_size(&self) -> usize {
self.encoded_size
}
/// Returns `true` if the transaction is not yet fully verified.
pub fn is_fully_verified(&self) -> bool {
self.inner.is_some()
}
}
impl extrinsic_pool::VerifiedTransaction for VerifiedTransaction {
type Hash = Hash;
type Sender = Option<AccountId>;
fn hash(&self) -> &Self::Hash {
&self.hash
}
fn sender(&self) -> &Self::Sender {
&self.sender
}
fn mem_usage(&self) -> usize {
self.encoded_size // TODO
}
}
/// The polkadot transaction pool logic.
pub struct ChainApi<A> {
api: Arc<A>,
}
impl<A> ChainApi<A> where
A: PolkadotApi,
{
const NO_ACCOUNT: &'static str = "Account not found.";
/// Create a new instance.
pub fn new(api: Arc<A>) -> Self {
ChainApi {
api,
}
}
fn lookup(&self, at: &BlockId, address: Address) -> ::std::result::Result<AccountId, &'static str> {
// TODO [ToDr] Consider introducing a cache for this.
match self.api.lookup(at, address.clone()) {
Ok(Some(address)) => Ok(address),
Ok(None) => Err(Self::NO_ACCOUNT.into()),
Err(e) => {
error!("Error looking up address: {:?}: {:?}", address, e);
Err("API error.")
},
}
}
}
impl<A> extrinsic_pool::ChainApi for ChainApi<A> where
A: PolkadotApi + Send + Sync,
{
type Block = Block;
type Hash = Hash;
type Sender = Option<AccountId>;
type VEx = VerifiedTransaction;
type Ready = HashMap<AccountId, u32>;
type Error = Error;
type Score = u64;
type Event = ();
fn verify_transaction(&self, at: &BlockId, xt: &ExtrinsicFor<Self>) -> Result<Self::VEx> {
let encoded = xt.encode();
let uxt = UncheckedExtrinsic::decode(&mut encoded.as_slice()).ok_or_else(|| ErrorKind::InvalidExtrinsicFormat)?;
if !uxt.is_signed() {
bail!(ErrorKind::IsInherent(uxt))
}
let (encoded_size, hash) = (encoded.len(), BlakeTwo256::hash(&encoded));
if encoded_size > MAX_TRANSACTION_SIZE {
bail!(ErrorKind::TooLarge(encoded_size, MAX_TRANSACTION_SIZE));
}
debug!(target: "transaction-pool", "Transaction submitted: {}", ::substrate_primitives::hexdisplay::HexDisplay::from(&encoded));
let inner = match uxt.clone().check_with(|a| self.lookup(at, a)) {
Ok(xt) => Some(xt),
// keep the transaction around in the future pool and attempt to promote it later.
Err(Self::NO_ACCOUNT) => None,
Err(e) => bail!(e),
};
let sender = match inner.as_ref() {
Some(cxt) => match cxt.signed {
Some(ref sender) => Some(sender.clone()),
None => bail!(ErrorKind::IsInherent(uxt))
},
None => None,
};
if encoded_size < 1024 {
debug!(target: "transaction-pool", "Transaction verified: {} => {:?}", hash, uxt);
} else {
debug!(target: "transaction-pool", "Transaction verified: {} ({} bytes is too large to display)", hash, encoded_size);
}
Ok(VerifiedTransaction {
index: uxt.index,
inner,
sender,
hash,
encoded_size,
})
}
fn ready(&self) -> Self::Ready {
HashMap::default()
}
fn is_ready(&self, at: &BlockId, known_nonces: &mut Self::Ready, xt: &VerifiedFor<Self>) -> Readiness {
let sender = match xt.verified.sender() {
Some(sender) => sender,
None => return Readiness::Future
};
trace!(target: "transaction-pool", "Checking readiness of {} (from {})", xt.verified.hash, Hash::from(sender));
// TODO: find a way to handle index error properly -- will need changes to
// transaction-pool trait.
let api = &self.api;
let next_index = known_nonces.entry(sender)
.or_insert_with(|| api.index(at, sender).ok().unwrap_or_else(Bounded::max_value));
trace!(target: "transaction-pool", "Next index for sender is {}; xt index is {}", next_index, xt.verified.index);
let result = match xt.verified.index.cmp(&next_index) {
// TODO: this won't work perfectly since accounts can now be killed, returning the nonce
// to zero.
// We should detect if the index was reset and mark all transactions as `Stale` for cull to work correctly.
// Otherwise those transactions will keep occupying the queue.
// Perhaps we could mark as stale if `index - state_index` > X?
Ordering::Greater => Readiness::Future,
Ordering::Equal => Readiness::Ready,
// TODO [ToDr] Should mark transactions referencing too old blockhash as `Stale` as well.
Ordering::Less => Readiness::Stale,
};
// remember to increment `next_index`
*next_index = next_index.saturating_add(1);
result
}
fn compare(old: &VerifiedFor<Self>, other: &VerifiedFor<Self>) -> Ordering {
old.verified.index().cmp(&other.verified.index())
}
fn choose(old: &VerifiedFor<Self>, new: &VerifiedFor<Self>) -> Choice {
if old.verified.is_fully_verified() {
assert!(new.verified.is_fully_verified(), "Scoring::choose called with transactions from different senders");
if old.verified.index() == new.verified.index() {
return Choice::ReplaceOld;
}
}
// This will keep both transactions, even though they have the same indices.
// It's fine for not fully verified transactions, we might also allow it for
// verified transactions but it would mean that only one of the two is actually valid
// (most likely the first to be included in the block).
Choice::InsertNew
}
fn update_scores(
xts: &[extrinsic_pool::Transaction<VerifiedFor<Self>>],
scores: &mut [Self::Score],
_change: Change<()>
) {
for i in 0..xts.len() {
if !xts[i].verified.is_fully_verified() {
scores[i] = 0;
} else {
// all the same score since there are no fees.
// TODO: prioritize things like misbehavior or fishermen reports
scores[i] = 1;
}
}
}
fn should_replace(old: &VerifiedFor<Self>, _new: &VerifiedFor<Self>) -> Choice {
if old.verified.is_fully_verified() {
// Don't allow new transactions if we are reaching the limit.
Choice::RejectNew
} else {
// Always replace not fully verified transactions.
Choice::ReplaceOld
}
}
}
#[cfg(test)]
mod tests {
use std::sync::{atomic::{self, AtomicBool}, Arc};
use substrate_keyring::Keyring::{self, *};
use codec::{Decode, Encode};
use polkadot_api::{PolkadotApi, BlockBuilder, Result};
use primitives::{AccountId, AccountIndex, Block, BlockId, Hash, Index, SessionKey,
UncheckedExtrinsic as FutureProofUncheckedExtrinsic};
use runtime::{RawAddress, Call, TimestampCall, UncheckedExtrinsic};
use primitives::parachain::{DutyRoster, Id as ParaId};
use sr_primitives::generic;
use extrinsic_pool::Pool;
use super::ChainApi;
struct TestBlockBuilder;
impl BlockBuilder for TestBlockBuilder {
fn push_extrinsic(&mut self, _extrinsic: FutureProofUncheckedExtrinsic) -> Result<()> { unimplemented!() }
fn bake(self) -> Result<Block> { unimplemented!() }
}
fn number_of(at: &BlockId) -> u32 {
match at {
generic::BlockId::Number(n) => *n as u32,
_ => 0,
}
}
#[derive(Default, Clone)]
struct TestPolkadotApi {
no_lookup: Arc<AtomicBool>,
}
impl TestPolkadotApi {
fn without_lookup() -> Self {
TestPolkadotApi {
no_lookup: Arc::new(AtomicBool::new(true)),
}
}
pub fn enable_lookup(&self) {
self.no_lookup.store(false, atomic::Ordering::SeqCst);
}
}
impl PolkadotApi for TestPolkadotApi {
type BlockBuilder = TestBlockBuilder;
fn session_keys(&self, _at: &BlockId) -> Result<Vec<SessionKey>> { unimplemented!() }
fn validators(&self, _at: &BlockId) -> Result<Vec<AccountId>> { unimplemented!() }
fn random_seed(&self, _at: &BlockId) -> Result<Hash> { unimplemented!() }
fn duty_roster(&self, _at: &BlockId) -> Result<DutyRoster> { unimplemented!() }
fn timestamp(&self, _at: &BlockId) -> Result<u64> { unimplemented!() }
fn evaluate_block(&self, _at: &BlockId, _block: Block) -> Result<bool> { unimplemented!() }
fn active_parachains(&self, _at: &BlockId) -> Result<Vec<ParaId>> { unimplemented!() }
fn parachain_code(&self, _at: &BlockId, _parachain: ParaId) -> Result<Option<Vec<u8>>> { unimplemented!() }
fn parachain_head(&self, _at: &BlockId, _parachain: ParaId) -> Result<Option<Vec<u8>>> { unimplemented!() }
fn build_block(&self, _at: &BlockId, _inherent: ::primitives::InherentData) -> Result<Self::BlockBuilder> { unimplemented!() }
fn inherent_extrinsics(&self, _at: &BlockId, _inherent: ::primitives::InherentData) -> Result<Vec<::primitives::UncheckedExtrinsic>> { unimplemented!() }
fn index(&self, _at: &BlockId, _account: AccountId) -> Result<Index> {
Ok((_account[0] as u32) + number_of(_at))
}
fn lookup(&self, _at: &BlockId, _address: RawAddress<AccountId, AccountIndex>) -> Result<Option<AccountId>> {
match _address {
RawAddress::Id(i) => Ok(Some(i)),
RawAddress::Index(_) if self.no_lookup.load(atomic::Ordering::SeqCst) => Ok(None),
RawAddress::Index(i) => Ok(match (i < 8, i + (number_of(_at) as u64) % 8) {
(false, _) => None,
(_, 0) => Some(Alice.to_raw_public().into()),
(_, 1) => Some(Bob.to_raw_public().into()),
(_, 2) => Some(Charlie.to_raw_public().into()),
(_, 3) => Some(Dave.to_raw_public().into()),
(_, 4) => Some(Eve.to_raw_public().into()),
(_, 5) => Some(Ferdie.to_raw_public().into()),
(_, 6) => Some(One.to_raw_public().into()),
(_, 7) => Some(Two.to_raw_public().into()),
_ => None,
}),
}
}
}
fn uxt(who: Keyring, nonce: Index, use_id: bool) -> FutureProofUncheckedExtrinsic {
let sxt = (nonce, Call::Timestamp(TimestampCall::set(0)));
let sig = sxt.using_encoded(|e| who.sign(e));
let signed = who.to_raw_public().into();
let sender = if use_id { RawAddress::Id(signed) } else { RawAddress::Index(
match who {
Alice => 0,
Bob => 1,
Charlie => 2,
Dave => 3,
Eve => 4,
Ferdie => 5,
One => 6,
Two => 7,
}
)};
UncheckedExtrinsic::new_signed(sxt.0, sxt.1, sender, sig.into())
.using_encoded(|e| FutureProofUncheckedExtrinsic::decode(&mut &e[..]))
.unwrap()
}
fn pool(api: &TestPolkadotApi) -> Pool<ChainApi<TestPolkadotApi>> {
Pool::new(Default::default(), ChainApi { api: Arc::new(api.clone()) })
}
#[test]
fn id_submission_should_work() {
let api = TestPolkadotApi::default();
let pool = pool(&api);
pool.submit_one(&BlockId::number(0), uxt(Alice, 209, true)).unwrap();
let pending: Vec<_> = pool.cull_and_get_pending(&BlockId::number(0), |p| p.map(|a| (a.verified.sender(), a.verified.index())).collect()).unwrap();
assert_eq!(pending, vec![(Some(Alice.to_raw_public().into()), 209)]);
}
#[test]
fn index_submission_should_work() {
let api = TestPolkadotApi::default();
let pool = pool(&api);
pool.submit_one(&BlockId::number(0), uxt(Alice, 209, false)).unwrap();
let pending: Vec<_> = pool.cull_and_get_pending(&BlockId::number(0), |p| p.map(|a| (a.verified.sender(), a.verified.index())).collect()).unwrap();
assert_eq!(pending, vec![(Some(Alice.to_raw_public().into()), 209)]);
}
#[test]
fn multiple_id_submission_should_work() {
let api = TestPolkadotApi::default();
let pool = pool(&api);
pool.submit_one(&BlockId::number(0), uxt(Alice, 209, true)).unwrap();
pool.submit_one(&BlockId::number(0), uxt(Alice, 210, true)).unwrap();
let pending: Vec<_> = pool.cull_and_get_pending(&BlockId::number(0), |p| p.map(|a| (a.verified.sender(), a.verified.index())).collect()).unwrap();
assert_eq!(pending, vec![(Some(Alice.to_raw_public().into()), 209), (Some(Alice.to_raw_public().into()), 210)]);
}
#[test]
fn multiple_index_submission_should_work() {
let api = TestPolkadotApi::default();
let pool = pool(&api);
pool.submit_one(&BlockId::number(0), uxt(Alice, 209, false)).unwrap();
pool.submit_one(&BlockId::number(0), uxt(Alice, 210, false)).unwrap();
let pending: Vec<_> = pool.cull_and_get_pending(&BlockId::number(0), |p| p.map(|a| (a.verified.sender(), a.verified.index())).collect()).unwrap();
assert_eq!(pending, vec![(Some(Alice.to_raw_public().into()), 209), (Some(Alice.to_raw_public().into()), 210)]);
}
#[test]
fn id_based_early_nonce_should_be_culled() {
let api = TestPolkadotApi::default();
let pool = pool(&api);
pool.submit_one(&BlockId::number(0), uxt(Alice, 208, true)).unwrap();
let pending: Vec<_> = pool.cull_and_get_pending(&BlockId::number(0), |p| p.map(|a| (a.verified.sender(), a.verified.index())).collect()).unwrap();
assert_eq!(pending, vec![]);
}
#[test]
fn index_based_early_nonce_should_be_culled() {
let api = TestPolkadotApi::default();
let pool = pool(&api);
pool.submit_one(&BlockId::number(0), uxt(Alice, 208, false)).unwrap();
let pending: Vec<_> = pool.cull_and_get_pending(&BlockId::number(0), |p| p.map(|a| (a.verified.sender(), a.verified.index())).collect()).unwrap();
assert_eq!(pending, vec![]);
}
#[test]
fn id_based_late_nonce_should_be_queued() {
let api = TestPolkadotApi::default();
let pool = pool(&api);
pool.submit_one(&BlockId::number(0), uxt(Alice, 210, true)).unwrap();
let pending: Vec<_> = pool.cull_and_get_pending(&BlockId::number(0), |p| p.map(|a| (a.verified.sender(), a.verified.index())).collect()).unwrap();
assert_eq!(pending, vec![]);
pool.submit_one(&BlockId::number(0), uxt(Alice, 209, true)).unwrap();
let pending: Vec<_> = pool.cull_and_get_pending(&BlockId::number(0), |p| p.map(|a| (a.verified.sender(), a.verified.index())).collect()).unwrap();
assert_eq!(pending, vec![(Some(Alice.to_raw_public().into()), 209), (Some(Alice.to_raw_public().into()), 210)]);
}
#[test]
fn index_based_late_nonce_should_be_queued() {
let api = TestPolkadotApi::default();
let pool = pool(&api);
pool.submit_one(&BlockId::number(0), uxt(Alice, 210, false)).unwrap();
let pending: Vec<_> = pool.cull_and_get_pending(&BlockId::number(0), |p| p.map(|a| (a.verified.sender(), a.verified.index())).collect()).unwrap();
assert_eq!(pending, vec![]);
pool.submit_one(&BlockId::number(0), uxt(Alice, 209, false)).unwrap();
let pending: Vec<_> = pool.cull_and_get_pending(&BlockId::number(0), |p| p.map(|a| (a.verified.sender(), a.verified.index())).collect()).unwrap();
assert_eq!(pending, vec![(Some(Alice.to_raw_public().into()), 209), (Some(Alice.to_raw_public().into()), 210)]);
}
#[test]
fn index_then_id_submission_should_make_progress() {
let api = TestPolkadotApi::without_lookup();
let pool = pool(&api);
pool.submit_one(&BlockId::number(0), uxt(Alice, 209, false)).unwrap();
pool.submit_one(&BlockId::number(0), uxt(Alice, 210, true)).unwrap();
let pending: Vec<_> = pool.cull_and_get_pending(&BlockId::number(0), |p| p.map(|a| (a.verified.sender(), a.verified.index())).collect()).unwrap();
assert_eq!(pending, vec![]);
api.enable_lookup();
pool.retry_verification(&BlockId::number(0), None).unwrap();
let pending: Vec<_> = pool.cull_and_get_pending(&BlockId::number(0), |p| p.map(|a| (a.verified.sender(), a.verified.index())).collect()).unwrap();
assert_eq!(pending, vec![
(Some(Alice.to_raw_public().into()), 209),
(Some(Alice.to_raw_public().into()), 210)
]);
}
#[test]
fn retrying_verification_might_not_change_anything() {
let api = TestPolkadotApi::without_lookup();
let pool = pool(&api);
pool.submit_one(&BlockId::number(0), uxt(Alice, 209, false)).unwrap();
pool.submit_one(&BlockId::number(0), uxt(Alice, 210, true)).unwrap();
let pending: Vec<_> = pool.cull_and_get_pending(&BlockId::number(0), |p| p.map(|a| (a.verified.sender(), a.verified.index())).collect()).unwrap();
assert_eq!(pending, vec![]);
pool.retry_verification(&BlockId::number(1), None).unwrap();
let pending: Vec<_> = pool.cull_and_get_pending(&BlockId::number(0), |p| p.map(|a| (a.verified.sender(), a.verified.index())).collect()).unwrap();
assert_eq!(pending, vec![]);
}
#[test]
fn id_then_index_submission_should_make_progress() {
let api = TestPolkadotApi::without_lookup();
let pool = pool(&api);
pool.submit_one(&BlockId::number(0), uxt(Alice, 209, true)).unwrap();
pool.submit_one(&BlockId::number(0), uxt(Alice, 210, false)).unwrap();
let pending: Vec<_> = pool.cull_and_get_pending(&BlockId::number(0), |p| p.map(|a| (a.verified.sender(), a.verified.index())).collect()).unwrap();
assert_eq!(pending, vec![
(Some(Alice.to_raw_public().into()), 209)
]);
// when
api.enable_lookup();
pool.retry_verification(&BlockId::number(0), None).unwrap();
let pending: Vec<_> = pool.cull_and_get_pending(&BlockId::number(0), |p| p.map(|a| (a.verified.sender(), a.verified.index())).collect()).unwrap();
assert_eq!(pending, vec![
(Some(Alice.to_raw_public().into()), 209),
(Some(Alice.to_raw_public().into()), 210)
]);
}
#[test]
fn index_change_should_result_in_second_tx_culled_or_future() {
let api = TestPolkadotApi::default();
let pool = pool(&api);
let block = BlockId::number(0);
pool.submit_one(&block, uxt(Alice, 209, false)).unwrap();
let hash = *pool.submit_one(&block, uxt(Alice, 210, false)).unwrap().verified.hash();
let pending: Vec<_> = pool.cull_and_get_pending(&block, |p| p.map(|a| (a.verified.sender(), a.verified.index())).collect()).unwrap();
assert_eq!(pending, vec![
(Some(Alice.to_raw_public().into()), 209),
(Some(Alice.to_raw_public().into()), 210)
]);
// first xt is mined, but that has a side-effect of switching index 0 from Alice to Bob.
// second xt now invalid signature, so it fails.
// there is no way of reporting this back to the queue right now (TODO). this should cause
// the queue to flush all information regarding the sender index/account.
// after this, a re-evaluation of the second's readiness should result in it being thrown
// out (or maybe placed in future queue).
let err = pool.reverify_transaction(&BlockId::number(1), hash).unwrap_err();
match *err.kind() {
::error::ErrorKind::Msg(ref m) if m == "bad signature in extrinsic" => {},
ref e => assert!(false, "The transaction should be rejected with BadSignature error, got: {:?}", e),
}
let pending: Vec<_> = pool.cull_and_get_pending(&BlockId::number(1), |p| p.map(|a| (a.verified.sender(), a.verified.index())).collect()).unwrap();
assert_eq!(pending, vec![]);
}
}