Make Polkadot use the Substrate traity libraries (#105)

* Initial stuff.

* Various fixes.

* Fix tests.

* Fix another test

* Fix another test.

* Docs in polkadot runtime.

* Fix up ser/de tests.

* Update god keys

* Syntax

* Fix

* Merge remote-tracking branch 'origin/master' into gav-merge-runtime

* Permissions on init.sh

* Port-over the whitespace from @rphmeier

* Rename

* Merge branch 'master' into gav-merge-runtime

* Fix typo.

* Fix grumbles.

* Make more idiomatic.

* Move `Ed25519Signature` out of traits.
This commit is contained in:
Gav Wood
2018-04-05 17:13:12 +02:00
committed by Robert Habermeier
parent ef939ed2f6
commit 6a99c9a43d
34 changed files with 1076 additions and 3517 deletions
+3
View File
@@ -8,7 +8,10 @@ error-chain = "0.11"
polkadot-executor = { path = "../executor" } polkadot-executor = { path = "../executor" }
polkadot-runtime = { path = "../runtime" } polkadot-runtime = { path = "../runtime" }
polkadot-primitives = { path = "../primitives" } polkadot-primitives = { path = "../primitives" }
substrate-codec = { path = "../../substrate/codec" }
substrate-runtime-io = { path = "../../substrate/runtime-io" }
substrate-client = { path = "../../substrate/client" } substrate-client = { path = "../../substrate/client" }
substrate-primitives = { path = "../../substrate/primitives" }
substrate-executor = { path = "../../substrate/executor" } substrate-executor = { path = "../../substrate/executor" }
substrate-state-machine = { path = "../../substrate/state-machine" } substrate-state-machine = { path = "../../substrate/state-machine" }
+107 -69
View File
@@ -18,10 +18,13 @@
//! runtime. //! runtime.
extern crate polkadot_executor; extern crate polkadot_executor;
extern crate polkadot_runtime; extern crate polkadot_runtime as runtime;
extern crate polkadot_primitives as primitives; extern crate polkadot_primitives as primitives;
extern crate substrate_codec as codec;
extern crate substrate_runtime_io as runtime_io;
extern crate substrate_client as client; extern crate substrate_client as client;
extern crate substrate_executor as substrate_executor; extern crate substrate_executor as substrate_executor;
extern crate substrate_primitives;
extern crate substrate_state_machine as state_machine; extern crate substrate_state_machine as state_machine;
#[macro_use] #[macro_use]
@@ -32,14 +35,12 @@ extern crate substrate_keyring as keyring;
use client::backend::Backend; use client::backend::Backend;
use client::Client; use client::Client;
use polkadot_runtime::runtime;
use polkadot_executor::Executor as LocalDispatch; use polkadot_executor::Executor as LocalDispatch;
use substrate_executor::{NativeExecutionDispatch, NativeExecutor}; use substrate_executor::{NativeExecutionDispatch, NativeExecutor};
use state_machine::OverlayedChanges; use state_machine::OverlayedChanges;
use primitives::{AccountId, SessionKey, Timestamp, TxOrder}; use primitives::{AccountId, BlockId, Index, SessionKey, Timestamp};
use primitives::block::{Id as BlockId, Block, Header, Body};
use primitives::transaction::UncheckedTransaction;
use primitives::parachain::DutyRoster; use primitives::parachain::DutyRoster;
use runtime::{Block, Header, UncheckedExtrinsic, Extrinsic, Call, TimestampCall};
error_chain! { error_chain! {
errors { errors {
@@ -53,15 +54,15 @@ error_chain! {
description("Unknown block") description("Unknown block")
display("Unknown block") display("Unknown block")
} }
/// Attempted to push an inherent transaction manually. /// Attempted to push an inherent extrinsic manually.
PushedInherentTransaction(tx: UncheckedTransaction) { PushedInherentTransaction(xt: UncheckedExtrinsic) {
description("Attempted to push an inherent transaction to a block."), description("Attempted to push an inherent extrinsic to a block."),
display("Pushed inherent transaction to a block: {:?}", tx), display("Pushed inherent extrinsic to a block: {:?}", xt),
} }
/// Badly-formed transaction. /// Badly-formed extrinsic.
BadlyFormedTransaction(tx: UncheckedTransaction) { BadlyFormedTransaction(xt: UncheckedExtrinsic) {
description("Attempted to push a badly-formed transaction to a block."), description("Attempted to push a badly-formed extrinsic to a block."),
display("Pushed badly-formed transaction to a block: {:?}", tx), display("Pushed badly-formed extrinsic to a block: {:?}", xt),
} }
/// Some other error. /// Some other error.
// TODO: allow to be specified as associated type of PolkadotApi // TODO: allow to be specified as associated type of PolkadotApi
@@ -87,8 +88,8 @@ impl From<client::error::Error> for Error {
/// A builder for blocks. /// A builder for blocks.
pub trait BlockBuilder: Sized { pub trait BlockBuilder: Sized {
/// Push a non-inherent transaction. /// Push a non-inherent extrinsic.
fn push_transaction(&mut self, transaction: UncheckedTransaction) -> Result<()>; fn push_extrinsic(&mut self, extrinsic: UncheckedExtrinsic) -> Result<()>;
/// Finalise the block. /// Finalise the block.
fn bake(self) -> Block; fn bake(self) -> Block;
@@ -127,8 +128,8 @@ pub trait PolkadotApi {
/// Get the timestamp registered at a block. /// Get the timestamp registered at a block.
fn timestamp(&self, at: &Self::CheckedBlockId) -> Result<Timestamp>; fn timestamp(&self, at: &Self::CheckedBlockId) -> Result<Timestamp>;
/// Get the nonce of an account at a block. /// Get the index of an account at a block.
fn nonce(&self, at: &Self::CheckedBlockId, account: AccountId) -> Result<TxOrder>; fn index(&self, at: &Self::CheckedBlockId, account: AccountId) -> Result<Index>;
/// Evaluate a block and see if it gives an error. /// Evaluate a block and see if it gives an error.
@@ -179,27 +180,27 @@ impl<B: Backend> PolkadotApi for Client<B, NativeExecutor<LocalDispatch>>
} }
fn session_keys(&self, at: &CheckedId) -> Result<Vec<SessionKey>> { fn session_keys(&self, at: &CheckedId) -> Result<Vec<SessionKey>> {
with_runtime!(self, at, ::runtime::consensus::authorities) with_runtime!(self, at, ::runtime::Consensus::authorities)
} }
fn validators(&self, at: &CheckedId) -> Result<Vec<AccountId>> { fn validators(&self, at: &CheckedId) -> Result<Vec<AccountId>> {
with_runtime!(self, at, ::runtime::session::validators) with_runtime!(self, at, ::runtime::Session::validators)
} }
fn duty_roster(&self, at: &CheckedId) -> Result<DutyRoster> { fn duty_roster(&self, at: &CheckedId) -> Result<DutyRoster> {
with_runtime!(self, at, ::runtime::parachains::calculate_duty_roster) with_runtime!(self, at, ::runtime::Parachains::calculate_duty_roster)
} }
fn timestamp(&self, at: &CheckedId) -> Result<Timestamp> { fn timestamp(&self, at: &CheckedId) -> Result<Timestamp> {
with_runtime!(self, at, ::runtime::timestamp::get) with_runtime!(self, at, ::runtime::Timestamp::now)
} }
fn evaluate_block(&self, at: &CheckedId, block: Block) -> Result<()> { fn evaluate_block(&self, at: &CheckedId, block: Block) -> Result<()> {
with_runtime!(self, at, || ::runtime::system::internal::execute_block(block)) with_runtime!(self, at, || ::runtime::Executive::execute_block(block))
} }
fn nonce(&self, at: &Self::CheckedBlockId, account: AccountId) -> Result<TxOrder> { fn index(&self, at: &Self::CheckedBlockId, account: AccountId) -> Result<Index> {
with_runtime!(self, at, || ::runtime::system::nonce(account)) with_runtime!(self, at, || ::runtime::System::account_index(account))
} }
fn build_block(&self, parent: &CheckedId, timestamp: Timestamp) -> Result<Self::BlockBuilder> { fn build_block(&self, parent: &CheckedId, timestamp: Timestamp) -> Result<Self::BlockBuilder> {
@@ -208,14 +209,20 @@ impl<B: Backend> PolkadotApi for Client<B, NativeExecutor<LocalDispatch>>
parent_hash: self.block_hash_from_id(parent)?.ok_or(ErrorKind::UnknownBlock(*parent))?, parent_hash: self.block_hash_from_id(parent)?.ok_or(ErrorKind::UnknownBlock(*parent))?,
number: self.block_number_from_id(parent)?.ok_or(ErrorKind::UnknownBlock(*parent))? + 1, number: self.block_number_from_id(parent)?.ok_or(ErrorKind::UnknownBlock(*parent))? + 1,
state_root: Default::default(), state_root: Default::default(),
transaction_root: Default::default(), extrinsics_root: Default::default(),
digest: Default::default(), digest: Default::default(),
}; };
let body = Body { let extrinsics = vec![
timestamp: timestamp, UncheckedExtrinsic {
transactions: Vec::new(), extrinsic: Extrinsic {
}; signed: Default::default(),
index: Default::default(),
function: Call::Timestamp(TimestampCall::set(timestamp)),
},
signature: Default::default(),
}
];
let mut builder = ClientBlockBuilder { let mut builder = ClientBlockBuilder {
parent: *parent, parent: *parent,
@@ -223,11 +230,13 @@ impl<B: Backend> PolkadotApi for Client<B, NativeExecutor<LocalDispatch>>
state: self.state_at(parent)?, state: self.state_at(parent)?,
header, header,
timestamp, timestamp,
transactions: Vec::new(), extrinsics: extrinsics.clone(),
}; };
for inherent in body.inherent_transactions() { builder.initialise_block()?;
builder.execute_transaction(inherent)?;
for inherent in extrinsics {
builder.apply_extrinsic(inherent)?;
} }
Ok(builder) Ok(builder)
@@ -242,34 +251,53 @@ pub struct ClientBlockBuilder<S> {
state: S, state: S,
header: Header, header: Header,
timestamp: Timestamp, timestamp: Timestamp,
transactions: Vec<UncheckedTransaction>, extrinsics: Vec<UncheckedExtrinsic>,
} }
impl<S: state_machine::Backend> ClientBlockBuilder<S> impl<S: state_machine::Backend> ClientBlockBuilder<S>
where S::Error: Into<client::error::Error> where S::Error: Into<client::error::Error>
{ {
// executes a transaction, inherent or otherwise, without appending to the list // executes a extrinsic, inherent or otherwise, without appending to the list
fn execute_transaction(&mut self, transaction: UncheckedTransaction) -> Result<()> { fn initialise_block(&mut self) -> Result<()> {
if !transaction.is_well_formed() {
bail!(ErrorKind::BadlyFormedTransaction(transaction));
}
let mut ext = state_machine::Ext { let mut ext = state_machine::Ext {
overlay: &mut self.changes, overlay: &mut self.changes,
backend: &self.state, backend: &self.state,
}; };
// TODO: avoid clone let h = self.header.clone();
let header = self.header.clone();
let result = ::substrate_executor::with_native_environment( let result = ::substrate_executor::with_native_environment(
&mut ext, &mut ext,
move || runtime::system::internal::execute_transaction(transaction, header), || runtime::Executive::initialise_block(&h),
).map_err(Into::into); ).map_err(Into::into);
match result { match result {
Ok(header) => { Ok(_) => {
ext.overlay.commit_prospective();
Ok(())
}
Err(e) => {
ext.overlay.discard_prospective();
Err(e)
}
}
}
// executes a extrinsic, inherent or otherwise, without appending to the list
fn apply_extrinsic(&mut self, extrinsic: UncheckedExtrinsic) -> Result<()> {
let mut ext = state_machine::Ext {
overlay: &mut self.changes,
backend: &self.state,
};
let result = ::substrate_executor::with_native_environment(
&mut ext,
move || runtime::Executive::apply_extrinsic(extrinsic),
).map_err(Into::into);
match result {
Ok(_) => {
ext.overlay.commit_prospective(); ext.overlay.commit_prospective();
self.header = header;
Ok(()) Ok(())
} }
Err(e) => { Err(e) => {
@@ -283,12 +311,13 @@ impl<S: state_machine::Backend> ClientBlockBuilder<S>
impl<S: state_machine::Backend> BlockBuilder for ClientBlockBuilder<S> impl<S: state_machine::Backend> BlockBuilder for ClientBlockBuilder<S>
where S::Error: Into<client::error::Error> where S::Error: Into<client::error::Error>
{ {
fn push_transaction(&mut self, transaction: UncheckedTransaction) -> Result<()> { fn push_extrinsic(&mut self, extrinsic: UncheckedExtrinsic) -> Result<()> {
if transaction.transaction.function.is_inherent() { // Check that this is not an "inherent" extrinsic.
bail!(ErrorKind::PushedInherentTransaction(transaction)); if extrinsic.signature == Default::default() {
bail!(ErrorKind::PushedInherentTransaction(extrinsic));
} else { } else {
self.execute_transaction(transaction.clone())?; self.apply_extrinsic(extrinsic.clone())?;
self.transactions.push(transaction); self.extrinsics.push(extrinsic);
Ok(()) Ok(())
} }
} }
@@ -299,18 +328,14 @@ impl<S: state_machine::Backend> BlockBuilder for ClientBlockBuilder<S>
backend: &self.state, backend: &self.state,
}; };
let old_header = self.header;
let final_header = ::substrate_executor::with_native_environment( let final_header = ::substrate_executor::with_native_environment(
&mut ext, &mut ext,
move || runtime::system::internal::finalise_block(old_header) move || runtime::Executive::finalise_block()
).expect("all inherent transactions pushed; all other transactions executed correctly; qed"); ).expect("all inherent extrinsics pushed; all other extrinsics executed correctly; qed");
Block { Block {
header: final_header, header: final_header,
body: Body { extrinsics: self.extrinsics,
timestamp: self.timestamp,
transactions: self.transactions,
}
} }
} }
} }
@@ -318,10 +343,12 @@ impl<S: state_machine::Backend> BlockBuilder for ClientBlockBuilder<S>
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use client::in_mem::Backend as InMemory; use runtime_io::with_externalities;
use polkadot_runtime::genesismap::{additional_storage_with_genesis, GenesisConfig};
use substrate_executor::NativeExecutionDispatch;
use keyring::Keyring; use keyring::Keyring;
use codec::Slicable;
use client::in_mem::Backend as InMemory;
use substrate_executor::NativeExecutionDispatch;
use runtime::{GenesisConfig, ConsensusConfig, SessionConfig, BuildExternalities};
fn validators() -> Vec<AccountId> { fn validators() -> Vec<AccountId> {
vec![ vec![
@@ -331,20 +358,31 @@ mod tests {
} }
fn client() -> Client<InMemory, NativeExecutor<LocalDispatch>> { fn client() -> Client<InMemory, NativeExecutor<LocalDispatch>> {
let genesis_config = GenesisConfig {
consensus: Some(ConsensusConfig {
code: LocalDispatch::native_equivalent().to_vec(),
authorities: validators(),
}),
system: None,
session: Some(SessionConfig {
validators: validators(),
session_length: 100,
}),
council: Some(Default::default()),
democracy: Some(Default::default()),
parachains: Some(Default::default()),
staking: Some(Default::default()),
};
::client::new_in_mem( ::client::new_in_mem(
LocalDispatch::new(), LocalDispatch::new(),
|| { || {
let config = GenesisConfig::new_simple(validators(), 100); let mut storage = genesis_config.build_externalities();
let block = ::client::genesis::construct_genesis_block(&storage);
// override code entry. with_externalities(&mut storage, ||
let mut storage = config.genesis_map(); // TODO: use api.rs to dispatch instead
storage.insert(b":code".to_vec(), LocalDispatch::native_equivalent().to_vec()); runtime::System::initialise_genesis_state(&block.header)
let block = ::client::genesis::construct_genesis_block(
&config.genesis_map()
); );
storage.extend(additional_storage_with_genesis(&block)); (substrate_primitives::block::Header::decode(&mut block.header.encode().as_ref()).expect("to_vec() always gives a valid serialisation; qed"), storage.into_iter().collect())
(block.header, storage.into_iter().collect())
} }
).unwrap() ).unwrap()
} }
+1
View File
@@ -13,6 +13,7 @@ log = "0.4"
polkadot-api = { path = "../api" } polkadot-api = { path = "../api" }
polkadot-collator = { path = "../collator" } polkadot-collator = { path = "../collator" }
polkadot-primitives = { path = "../primitives" } polkadot-primitives = { path = "../primitives" }
polkadot-runtime = { path = "../runtime" }
polkadot-statement-table = { path = "../statement-table" } polkadot-statement-table = { path = "../statement-table" }
polkadot-transaction-pool = { path = "../transaction-pool" } polkadot-transaction-pool = { path = "../transaction-pool" }
substrate-bft = { path = "../../substrate/bft" } substrate-bft = { path = "../../substrate/bft" }
+26 -29
View File
@@ -38,6 +38,7 @@ extern crate polkadot_collator as collator;
extern crate polkadot_statement_table as table; extern crate polkadot_statement_table as table;
extern crate polkadot_primitives; extern crate polkadot_primitives;
extern crate polkadot_transaction_pool as transaction_pool; extern crate polkadot_transaction_pool as transaction_pool;
extern crate polkadot_runtime;
extern crate substrate_bft as bft; extern crate substrate_bft as bft;
extern crate substrate_codec as codec; extern crate substrate_codec as codec;
extern crate substrate_primitives as primitives; extern crate substrate_primitives as primitives;
@@ -62,11 +63,11 @@ use table::generic::Statement as GenericStatement;
use runtime_support::Hashable; use runtime_support::Hashable;
use polkadot_api::{PolkadotApi, BlockBuilder}; use polkadot_api::{PolkadotApi, BlockBuilder};
use polkadot_primitives::{Hash, Timestamp}; use polkadot_primitives::{Hash, Timestamp};
use polkadot_primitives::block::Block as PolkadotBlock;
use polkadot_primitives::parachain::{Id as ParaId, DutyRoster, BlockData, Extrinsic, CandidateReceipt}; use polkadot_primitives::parachain::{Id as ParaId, DutyRoster, BlockData, Extrinsic, CandidateReceipt};
use polkadot_runtime::Block as PolkadotGenericBlock;
use primitives::block::{Block as SubstrateBlock, Header as SubstrateHeader, HeaderHash, Id as BlockId, Number as BlockNumber}; use primitives::block::{Block as SubstrateBlock, Header as SubstrateHeader, HeaderHash, Id as BlockId, Number as BlockNumber};
use primitives::AuthorityId; use primitives::AuthorityId;
use transaction_pool::{Ready, TransactionPool}; use transaction_pool::{Ready, TransactionPool, PolkadotBlock};
use futures::prelude::*; use futures::prelude::*;
use futures::future; use futures::future;
@@ -152,7 +153,7 @@ impl TableContext {
} }
fn sign_statement(&self, statement: table::Statement) -> table::SignedStatement { fn sign_statement(&self, statement: table::Statement) -> table::SignedStatement {
let signature = sign_table_statement(&statement, &self.key, &self.parent_hash); let signature = sign_table_statement(&statement, &self.key, &self.parent_hash).into();
let local_id = self.key.public().0; let local_id = self.key.public().0;
table::SignedStatement { table::SignedStatement {
@@ -552,7 +553,7 @@ impl<C: PolkadotApi, R: TableRouter> bft::Proposer for Proposer<C, R> {
if pending_size + pending.encoded_size() >= MAX_TRANSACTIONS_SIZE { break } if pending_size + pending.encoded_size() >= MAX_TRANSACTIONS_SIZE { break }
match block_builder.push_transaction(pending.as_transaction().clone()) { match block_builder.push_extrinsic(pending.as_transaction().clone()) {
Ok(()) => { Ok(()) => {
pending_size += pending.encoded_size(); pending_size += pending.encoded_size();
} }
@@ -582,23 +583,23 @@ impl<C: PolkadotApi, R: TableRouter> bft::Proposer for Proposer<C, R> {
fn import_misbehavior(&self, misbehavior: Vec<(AuthorityId, bft::Misbehavior)>) { fn import_misbehavior(&self, misbehavior: Vec<(AuthorityId, bft::Misbehavior)>) {
use bft::generic::Misbehavior as GenericMisbehavior; use bft::generic::Misbehavior as GenericMisbehavior;
use primitives::bft::{MisbehaviorKind, MisbehaviorReport}; use primitives::bft::{MisbehaviorKind, MisbehaviorReport};
use polkadot_primitives::transaction::{Function, Transaction, UncheckedTransaction}; use polkadot_runtime::{Call, Extrinsic, UncheckedExtrinsic, ConsensusCall};
let local_id = self.local_key.public().0; let local_id = self.local_key.public().0;
let mut pool = self.transaction_pool.lock(); let mut pool = self.transaction_pool.lock();
let mut next_nonce = { let mut next_index = {
let readiness_evaluator = Ready::create(self.parent_id.clone(), &*self.client); let readiness_evaluator = Ready::create(self.parent_id.clone(), &*self.client);
let cur_nonce = pool.pending(readiness_evaluator) let cur_index = pool.pending(readiness_evaluator)
.filter(|tx| tx.as_transaction().transaction.signed == local_id) .filter(|tx| tx.as_ref().as_ref().signed == local_id)
.last() .last()
.map(|tx| Ok(tx.as_transaction().transaction.nonce)) .map(|tx| Ok(tx.as_ref().as_ref().index))
.unwrap_or_else(|| self.client.nonce(&self.parent_id, local_id)); .unwrap_or_else(|| self.client.index(&self.parent_id, local_id));
match cur_nonce { match cur_index {
Ok(cur_nonce) => cur_nonce + 1, Ok(cur_index) => cur_index + 1,
Err(e) => { Err(e) => {
warn!(target: "consensus", "Error computing next transaction nonce: {}", e); warn!(target: "consensus", "Error computing next transaction index: {}", e);
return; return;
} }
} }
@@ -618,23 +619,18 @@ impl<C: PolkadotApi, R: TableRouter> bft::Proposer for Proposer<C, R> {
=> MisbehaviorKind::BftDoubleCommit(round as u32, (h1, s1.signature), (h2, s2.signature)), => MisbehaviorKind::BftDoubleCommit(round as u32, (h1, s1.signature), (h2, s2.signature)),
} }
}; };
let extrinsic = Extrinsic {
let tx = Transaction {
signed: local_id, signed: local_id,
nonce: next_nonce, index: next_index,
function: Function::ReportMisbehavior(report), function: Call::Consensus(ConsensusCall::report_misbehavior(report)),
}; };
next_nonce += 1; next_index += 1;
let message = tx.encode(); let signature = self.local_key.sign(&extrinsic.encode()).into();
let signature = self.local_key.sign(&message); let uxt = UncheckedExtrinsic { extrinsic, signature };
let tx = UncheckedTransaction {
transaction: tx,
signature,
};
pool.import(tx).expect("locally signed transaction is valid; qed"); pool.import(uxt).expect("locally signed extrinsic is valid; qed");
} }
} }
} }
@@ -649,10 +645,11 @@ fn evaluate_proposal<C: PolkadotApi>(
const MAX_TIMESTAMP_DRIFT: Timestamp = 4; const MAX_TIMESTAMP_DRIFT: Timestamp = 4;
let encoded = Slicable::encode(proposal); let encoded = Slicable::encode(proposal);
let proposal = PolkadotBlock::decode(&mut &encoded[..]) let proposal = PolkadotGenericBlock::decode(&mut &encoded[..])
.and_then(|b| PolkadotBlock::from(b).ok())
.ok_or_else(|| ErrorKind::ProposalNotForPolkadot)?; .ok_or_else(|| ErrorKind::ProposalNotForPolkadot)?;
let transactions_size = proposal.body.transactions.iter().fold(0, |a, tx| { let transactions_size = proposal.extrinsics.iter().fold(0, |a, tx| {
a + Slicable::encode(tx).len() a + Slicable::encode(tx).len()
}); });
@@ -668,7 +665,7 @@ fn evaluate_proposal<C: PolkadotApi>(
// a) we assume the parent is valid. // a) we assume the parent is valid.
// b) the runtime checks that `proposal.parent_hash` == `block_hash(proposal.number - 1)` // b) the runtime checks that `proposal.parent_hash` == `block_hash(proposal.number - 1)`
let block_timestamp = proposal.body.timestamp; let block_timestamp = proposal.timestamp();
// TODO: just defer using `tokio_timer` to delay prepare vote. // TODO: just defer using `tokio_timer` to delay prepare vote.
if block_timestamp > now + MAX_TIMESTAMP_DRIFT { if block_timestamp > now + MAX_TIMESTAMP_DRIFT {
@@ -676,6 +673,6 @@ fn evaluate_proposal<C: PolkadotApi>(
} }
// execute the block. // execute the block.
client.evaluate_block(parent_id, proposal)?; client.evaluate_block(parent_id, proposal.into())?;
Ok(true) Ok(true)
} }
-278
View File
@@ -27,282 +27,4 @@ extern crate polkadot_primitives as polkadot_primitives;
extern crate ed25519; extern crate ed25519;
extern crate triehash; extern crate triehash;
#[cfg(test)] extern crate substrate_keyring as keyring;
#[cfg(test)] extern crate substrate_runtime_support as runtime_support;
#[cfg(test)] #[macro_use] extern crate hex_literal;
native_executor_instance!(pub Executor, polkadot_runtime::api::dispatch, include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm")); native_executor_instance!(pub Executor, polkadot_runtime::api::dispatch, include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm"));
#[cfg(test)]
mod tests {
use runtime_io;
use super::Executor;
use substrate_executor::WasmExecutor;
use codec::{KeyedVec, Slicable, Joiner};
use keyring::Keyring;
use runtime_support::Hashable;
use polkadot_runtime::runtime::staking::balance;
use state_machine::{CodeExecutor, TestExternalities};
use primitives::twox_128;
use polkadot_primitives::{
Hash, Header, Body, BlockNumber, Block, Digest, Transaction,
UncheckedTransaction, Function, InherentFunction,
};
use ed25519::{Public, Pair};
const BLOATY_CODE: &[u8] = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm");
const COMPACT_CODE: &[u8] = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm");
// TODO: move into own crate.
macro_rules! map {
($( $name:expr => $value:expr ),*) => (
vec![ $( ( $name, $value ) ),* ].into_iter().collect()
)
}
fn new_test_ext() -> TestExternalities {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let three = [3u8; 32];
map![
twox_128(&0u64.to_keyed_vec(b"sys:old:")).to_vec() => [69u8; 32].encode(),
twox_128(b"gov:apr").to_vec() => vec![].and(&667u32),
twox_128(b"ses:len").to_vec() => vec![].and(&2u64),
twox_128(b"ses:val:len").to_vec() => vec![].and(&3u32),
twox_128(&0u32.to_keyed_vec(b"ses:val:")).to_vec() => one.to_vec(),
twox_128(&1u32.to_keyed_vec(b"ses:val:")).to_vec() => two.to_vec(),
twox_128(&2u32.to_keyed_vec(b"ses:val:")).to_vec() => three.to_vec(),
twox_128(b"sta:wil:len").to_vec() => vec![].and(&3u32),
twox_128(&0u32.to_keyed_vec(b"sta:wil:")).to_vec() => one.to_vec(),
twox_128(&1u32.to_keyed_vec(b"sta:wil:")).to_vec() => two.to_vec(),
twox_128(&2u32.to_keyed_vec(b"sta:wil:")).to_vec() => three.to_vec(),
twox_128(b"sta:spe").to_vec() => vec![].and(&2u64),
twox_128(b"sta:vac").to_vec() => vec![].and(&3u64),
twox_128(b"sta:era").to_vec() => vec![].and(&0u64),
twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0]
]
}
fn set_timestamp(timestamp: u64) -> UncheckedTransaction {
UncheckedTransaction::inherent(InherentFunction::TimestampSet(timestamp))
}
fn tx() -> UncheckedTransaction {
let transaction = Transaction {
signed: Keyring::One.to_raw_public(),
nonce: 0,
function: Function::StakingTransfer(Keyring::Two.to_raw_public(), 69),
};
let signature = Keyring::from_raw_public(transaction.signed).unwrap()
.sign(&transaction.encode());
UncheckedTransaction { transaction, signature }
}
fn execute_tx_on<C>(executor: C, ext: &mut TestExternalities, code: &[u8], tx: UncheckedTransaction, header: Header)
-> Result<Vec<u8>, C::Error>
where C: CodeExecutor
{
let next_header = executor.call(ext, code, "execute_transaction", &vec![].and(&header).and(&set_timestamp(100_000))).unwrap();
let next_input = next_header.and(&tx);
executor.call(ext, code, "execute_transaction", &next_input[..])
}
fn construct_block(number: BlockNumber, parent_hash: Hash, state_root: Hash, timestamp: u64, txs: Vec<Transaction>) -> (Vec<u8>, Hash) {
use triehash::ordered_trie_root;
let transactions = txs.into_iter().map(|transaction| {
let signature = Pair::from(Keyring::from_public(Public::from_raw(transaction.signed)).unwrap())
.sign(&transaction.encode());
UncheckedTransaction { transaction, signature }
}).collect();
let header = Header {
parent_hash,
number,
state_root,
transaction_root: Default::default(),
digest: Digest { logs: vec![], },
};
let mut block = Block {
header,
body: Body { timestamp, transactions },
};
let transaction_root = ordered_trie_root(block.all_transactions().map(|tx| Slicable::encode(&tx))).0.into();
block.header.transaction_root = transaction_root;
let hash = block.header.blake2_256();
(block.encode(), hash.into())
}
fn block1() -> (Vec<u8>, Hash) {
construct_block(
1,
[69u8; 32].into(),
hex!("3df569d47a0d7f4a448486f04fba4eea3e9dfca001319c609f88b3a67b0dd1ea").into(),
100_000,
vec![
Transaction {
signed: Keyring::One.to_raw_public(),
nonce: 0,
function: Function::StakingTransfer(Keyring::Two.to_raw_public(), 69),
}
]
)
}
fn block2() -> (Vec<u8>, Hash) {
construct_block(
2,
block1().1,
hex!("5604fe023cd6effd93aec9b4a008398abdd32afb3fec988a19aa853ab0424a7c").into(),
200_000,
vec![
Transaction {
signed: Keyring::Two.to_raw_public(),
nonce: 0,
function: Function::StakingTransfer(Keyring::One.to_raw_public(), 5),
},
Transaction {
signed: Keyring::One.to_raw_public(),
nonce: 1,
function: Function::StakingTransfer(Keyring::Two.to_raw_public(), 15),
}
]
)
}
#[test]
fn panic_execution_with_foreign_code_gives_error() {
let one = Keyring::One.to_raw_public();
let mut t: TestExternalities = map![
twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0]
];
let r = execute_tx_on(Executor::new(), &mut t, BLOATY_CODE, tx(), Header::from_block_number(1));
assert!(r.is_err());
}
#[test]
fn panic_execution_with_native_equivalent_code_gives_error() {
let one = Keyring::One.to_raw_public();
let mut t: TestExternalities = map![
twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0]
];
let r = execute_tx_on(Executor::new(), &mut t, COMPACT_CODE, tx(), Header::from_block_number(1));
assert!(r.is_err());
}
#[test]
fn successful_execution_with_native_equivalent_code_gives_ok() {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let mut t: TestExternalities = map![
twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0]
];
let r = execute_tx_on(Executor::new(), &mut t, COMPACT_CODE, tx(), Header::from_block_number(1));
assert!(r.is_ok());
runtime_io::with_externalities(&mut t, || {
assert_eq!(balance(&one), 42);
assert_eq!(balance(&two), 69);
});
}
#[test]
fn successful_execution_with_foreign_code_gives_ok() {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let mut t: TestExternalities = map![
twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0]
];
let r = execute_tx_on(Executor::new(), &mut t, BLOATY_CODE, tx(), Header::from_block_number(1));
assert!(r.is_ok());
runtime_io::with_externalities(&mut t, || {
assert_eq!(balance(&one), 42);
assert_eq!(balance(&two), 69);
});
}
#[test]
fn full_native_block_import_works() {
let mut t = new_test_ext();
Executor::new().call(&mut t, COMPACT_CODE, "execute_block", &block1().0).unwrap();
runtime_io::with_externalities(&mut t, || {
assert_eq!(balance(&Keyring::One.to_raw_public()), 42);
assert_eq!(balance(&Keyring::Two.to_raw_public()), 69);
});
Executor::new().call(&mut t, COMPACT_CODE, "execute_block", &block2().0).unwrap();
runtime_io::with_externalities(&mut t, || {
assert_eq!(balance(&Keyring::One.to_raw_public()), 32);
assert_eq!(balance(&Keyring::Two.to_raw_public()), 79);
});
}
#[test]
fn full_wasm_block_import_works() {
let mut t = new_test_ext();
WasmExecutor.call(&mut t, COMPACT_CODE, "execute_block", &block1().0).unwrap();
runtime_io::with_externalities(&mut t, || {
assert_eq!(balance(&Keyring::One.to_raw_public()), 42);
assert_eq!(balance(&Keyring::Two.to_raw_public()), 69);
});
WasmExecutor.call(&mut t, COMPACT_CODE, "execute_block", &block2().0).unwrap();
runtime_io::with_externalities(&mut t, || {
assert_eq!(balance(&Keyring::One.to_raw_public()), 32);
assert_eq!(balance(&Keyring::Two.to_raw_public()), 79);
});
}
#[test]
fn panic_execution_gives_error() {
let one = Keyring::One.to_raw_public();
let mut t: TestExternalities = map![
twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0]
];
let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm");
let r = execute_tx_on(WasmExecutor, &mut t, &foreign_code[..], tx(), Header::from_block_number(1));
assert!(r.is_err());
}
#[test]
fn successful_execution_gives_ok() {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let mut t: TestExternalities = map![
twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0]
];
let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm");
let r = execute_tx_on(WasmExecutor, &mut t, &foreign_code[..], tx(), Header::from_block_number(1));
assert!(r.is_ok());
runtime_io::with_externalities(&mut t, || {
assert_eq!(balance(&one), 42);
assert_eq!(balance(&two), 69);
});
}
}
+2
View File
@@ -9,6 +9,7 @@ serde_derive = { version = "1.0", optional = true }
substrate-codec = { path = "../../substrate/codec", default_features = false } substrate-codec = { path = "../../substrate/codec", default_features = false }
substrate-primitives = { path = "../../substrate/primitives", default_features = false } substrate-primitives = { path = "../../substrate/primitives", default_features = false }
substrate-runtime-std = { path = "../../substrate/runtime-std", default_features = false } substrate-runtime-std = { path = "../../substrate/runtime-std", default_features = false }
substrate-runtime-primitives = { path = "../../substrate/runtime/primitives", default_features = false }
[dev-dependencies] [dev-dependencies]
substrate-serializer = { path = "../../substrate/serializer" } substrate-serializer = { path = "../../substrate/serializer" }
@@ -20,6 +21,7 @@ std = [
"substrate-codec/std", "substrate-codec/std",
"substrate-primitives/std", "substrate-primitives/std",
"substrate-runtime-std/std", "substrate-runtime-std/std",
"substrate-runtime-primitives/std",
"serde_derive", "serde_derive",
"serde/std", "serde/std",
] ]
-375
View File
@@ -1,375 +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/>.
//! Block and header type definitions.
#[cfg(feature = "std")]
use primitives::bytes;
use primitives::H256;
use rstd::vec::Vec;
use codec::{Input, Slicable};
use transaction::{UncheckedTransaction, Function, InherentFunction};
pub use primitives::block::Id;
/// Used to refer to a block number.
pub type Number = u64;
/// Hash used to refer to a block hash.
pub type HeaderHash = H256;
/// Hash used to refer to a transaction hash.
pub type TransactionHash = H256;
/// Execution log (event)
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub struct Log(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
impl Slicable for Log {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Vec::<u8>::decode(input).map(Log)
}
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
self.0.using_encoded(f)
}
}
/// The digest of a block, useful for light-clients.
#[derive(Clone, Default, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub struct Digest {
/// All logs that have happened in the block.
pub logs: Vec<Log>,
}
impl Slicable for Digest {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Vec::<Log>::decode(input).map(|logs| Digest { logs })
}
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
self.logs.using_encoded(f)
}
}
/// Iterator over all inherent transactions.
pub struct InherentTransactions<'a> {
number: u64,
body: &'a Body,
}
impl<'a> Iterator for InherentTransactions<'a> {
type Item = UncheckedTransaction;
fn next(&mut self) -> Option<UncheckedTransaction> {
if self.number == InherentFunction::count() {
return None
}
self.number += 1;
let function = match self.number {
1 => Some(InherentFunction::TimestampSet(self.body.timestamp)),
_ => None,
};
function.map(UncheckedTransaction::inherent)
}
}
/// Type alias for an iterator over all transactions in a block.
pub type AllTransactions<'a> = ::rstd::iter::Chain<
InherentTransactions<'a>,
::rstd::iter::Cloned<::rstd::slice::Iter<'a, UncheckedTransaction>>,
>;
/// The block body. Contains timestamp and transactions.
// TODO: add candidates update as well.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct Body {
/// The timestamp of the block.
pub timestamp: u64,
/// The transactions in the block.
pub transactions: Vec<UncheckedTransaction>,
}
impl Body {
/// Get an iterator over all inherent transactions of the body.
pub fn inherent_transactions(&self) -> InherentTransactions {
InherentTransactions {
number: 0,
body: self,
}
}
/// Get an iterator over all transactions in a block.
pub fn all_transactions(&self) -> AllTransactions {
self.inherent_transactions().chain(self.transactions.iter().cloned())
}
}
/// A Polkadot relay chain block.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub struct Block {
/// The block header.
pub header: Header,
/// The block body.
pub body: Body,
}
impl Block {
/// Get an iterator over all inherent transactions of the body.
pub fn inherent_transactions(&self) -> InherentTransactions {
self.body.inherent_transactions()
}
/// Get an iterator over all transactions in a block.
pub fn all_transactions(&self) -> AllTransactions {
self.body.all_transactions()
}
}
impl Slicable for Block {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
let header = try_opt!(Slicable::decode(input));
let transactions_len: u32 = try_opt!(Slicable::decode(input));
let regular_transactions_len = try_opt!(transactions_len.checked_sub(InherentFunction::count() as u32));
let timestamp_tx = try_opt!(UncheckedTransaction::decode(input));
let timestamp = match timestamp_tx.transaction.function {
Function::Inherent(InherentFunction::TimestampSet(ref t)) if timestamp_tx.is_well_formed() => { t.clone() }
_ => return None,
};
let transactions: Option<Vec<_>> = (0..regular_transactions_len)
.map(|_| UncheckedTransaction::decode(input))
.filter(|tx| tx.as_ref().map_or(true, |tx| tx.is_well_formed()))
.collect();
let body = Body {
timestamp,
transactions: try_opt!(transactions),
};
Some(Block { header, body })
}
fn encode(&self) -> Vec<u8> {
let mut v = Vec::new();
v.extend(self.header.encode());
// encode inherent transactions before non-inherent.
let transactions_len = self.body.transactions.len() as u64 + InherentFunction::count();
(transactions_len as u32).using_encoded(|s| v.extend(s));
let timestamp_set_tx = UncheckedTransaction::inherent(
InherentFunction::TimestampSet(self.body.timestamp)
);
v.extend(timestamp_set_tx.encode());
for non_inherent_transaction in &self.body.transactions {
v.extend(non_inherent_transaction.encode());
}
v
}
}
/// A relay chain block header.
///
/// https://github.com/w3f/polkadot-spec/blob/master/spec.md#header
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct Header {
/// Block parent's hash.
pub parent_hash: HeaderHash,
/// Block number.
pub number: Number,
/// State root after this transition.
pub state_root: H256,
/// The root of the trie that represents this block's transactions, indexed by a 32-byte integer.
pub transaction_root: H256,
/// The digest of activity on the block.
pub digest: Digest,
}
impl Header {
/// Create a new instance with default fields except `number`, which is given as an argument.
pub fn from_block_number(number: Number) -> Self {
Header {
parent_hash: Default::default(),
number,
state_root: Default::default(),
transaction_root: Default::default(),
digest: Default::default(),
}
}
}
impl Slicable for Header {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(Header {
parent_hash: try_opt!(Slicable::decode(input)),
number: try_opt!(Slicable::decode(input)),
state_root: try_opt!(Slicable::decode(input)),
transaction_root: try_opt!(Slicable::decode(input)),
digest: try_opt!(Slicable::decode(input)),
})
}
fn encode(&self) -> Vec<u8> {
let mut v = Vec::new();
self.parent_hash.using_encoded(|s| v.extend(s));
self.number.using_encoded(|s| v.extend(s));
self.state_root.using_encoded(|s| v.extend(s));
self.transaction_root.using_encoded(|s| v.extend(s));
self.digest.using_encoded(|s| v.extend(s));
v
}
}
#[cfg(test)]
mod tests {
use super::*;
use codec::Slicable;
use substrate_serializer as ser;
#[test]
fn test_header_serialization() {
let header = Header {
parent_hash: 5.into(),
number: 67,
state_root: 3.into(),
transaction_root: 6.into(),
digest: Digest { logs: vec![Log(vec![1])] },
};
assert_eq!(ser::to_string_pretty(&header), r#"{
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000005",
"number": 67,
"stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000003",
"transactionRoot": "0x0000000000000000000000000000000000000000000000000000000000000006",
"digest": {
"logs": [
"0x01"
]
}
}"#);
let v = header.encode();
assert_eq!(Header::decode(&mut &v[..]).unwrap(), header);
}
#[test]
fn block_encoding_round_trip() {
let mut block = Block {
header: Header::from_block_number(1),
body: Body {
timestamp: 100_000_000,
transactions: Vec::new(),
}
};
let raw = block.encode();
let decoded = Block::decode(&mut &raw[..]).unwrap();
assert_eq!(block, decoded);
block.body.transactions.push(UncheckedTransaction {
transaction: ::transaction::Transaction {
function: Function::StakingStake,
signed: Default::default(),
nonce: 10101,
},
signature: Default::default(),
});
let raw = block.encode();
let decoded = Block::decode(&mut &raw[..]).unwrap();
assert_eq!(block, decoded);
}
#[test]
fn block_encoding_substrate_round_trip() {
let mut block = Block {
header: Header::from_block_number(1),
body: Body {
timestamp: 100_000_000,
transactions: Vec::new(),
}
};
block.body.transactions.push(UncheckedTransaction {
transaction: ::transaction::Transaction {
function: Function::StakingStake,
signed: Default::default(),
nonce: 10101,
},
signature: Default::default(),
});
let raw = block.encode();
let decoded_substrate = ::primitives::block::Block::decode(&mut &raw[..]).unwrap();
let encoded_substrate = decoded_substrate.encode();
let decoded = Block::decode(&mut &encoded_substrate[..]).unwrap();
assert_eq!(block, decoded);
}
#[test]
fn decode_body_without_inherents_fails() {
let substrate_blank = ::primitives::block::Block {
header: ::primitives::block::Header::from_block_number(1),
transactions: Vec::new(),
};
let encoded_substrate = substrate_blank.encode();
assert!(Block::decode(&mut &encoded_substrate[..]).is_none());
}
#[test]
fn inherent_transactions_iter_contains_all_inherent() {
let block = Block {
header: Header::from_block_number(1),
body: Body {
timestamp: 10101,
transactions: Vec::new(),
}
};
let mut iter = block.inherent_transactions();
assert_eq!(InherentFunction::count(), 1); // following depends on this assertion.
assert_eq!(iter.next().unwrap(), UncheckedTransaction::inherent(InherentFunction::TimestampSet(10101)));
assert!(iter.next().is_none());
}
}
+13 -22
View File
@@ -21,7 +21,6 @@
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), feature(alloc))] #![cfg_attr(not(feature = "std"), feature(alloc))]
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[macro_use] #[macro_use]
extern crate serde_derive; extern crate serde_derive;
@@ -30,34 +29,29 @@ extern crate serde;
extern crate substrate_runtime_std as rstd; extern crate substrate_runtime_std as rstd;
extern crate substrate_primitives as primitives; extern crate substrate_primitives as primitives;
extern crate substrate_runtime_primitives as runtime_primitives;
#[cfg(test)] #[cfg(test)]
extern crate substrate_serializer; extern crate substrate_serializer;
extern crate substrate_codec as codec; extern crate substrate_codec as codec;
macro_rules! try_opt {
($e: expr) => {
match $e {
Some(x) => x,
None => return None,
}
}
}
pub mod parachain; pub mod parachain;
pub mod validator; pub mod validator;
pub mod block;
pub mod transaction;
pub use self::block::{Header, Body, Block, Log, Digest};
pub use self::block::Number as BlockNumber;
pub use self::transaction::{Transaction, UncheckedTransaction, Function, InherentFunction, Proposal};
/// Virtual account ID that represents the idea of a dispatch/statement being signed by everybody /// Virtual account ID that represents the idea of a dispatch/statement being signed by everybody
/// (who matters). Essentially this means that a majority of validators have decided it is /// (who matters). Essentially this means that a majority of validators have decided it is
/// "correct". /// "correct".
pub const EVERYBODY: AccountId = [255u8; 32]; pub const EVERYBODY: AccountId = [255u8; 32];
/// Something that identifies a block.
pub use primitives::block::Id as BlockId;
/// The type of digest item.
pub use primitives::block::Log as Log;
/// An index to a block.
pub type BlockNumber = u64;
/// Alias to Ed25519 pubkey that identifies an account on the relay chain. This will almost /// Alias to Ed25519 pubkey that identifies an account on the relay chain. This will almost
/// certainly continue to be the same as the substrate's `AuthorityId`. /// certainly continue to be the same as the substrate's `AuthorityId`.
pub type AccountId = primitives::AuthorityId; pub type AccountId = primitives::AuthorityId;
@@ -67,22 +61,19 @@ pub type AccountId = primitives::AuthorityId;
pub type SessionKey = primitives::AuthorityId; pub type SessionKey = primitives::AuthorityId;
/// Indentifier for a chain. /// Indentifier for a chain.
pub type ChainID = u64; pub type ChainId = u64;
/// Index of a transaction in the relay chain. /// Index of a transaction in the relay chain.
pub type TxOrder = u64; pub type Index = u64;
/// A hash of some data used by the relay chain. /// A hash of some data used by the relay chain.
pub type Hash = primitives::H256; pub type Hash = primitives::H256;
/// Alias to 512-bit hash when used in the context of a signature on the relay chain. /// Alias to 512-bit hash when used in the context of a signature on the relay chain.
pub type Signature = primitives::hash::H512; 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 = u64;
/// The balance of an account. /// The balance of an account.
pub type Balance = u64; pub type Balance = u64;
/// The amount of bonding period left in an account. Measured in eras.
pub type Bondage = u64;
+21 -21
View File
@@ -26,7 +26,7 @@ use ::Hash;
/// Unique identifier of a parachain. /// Unique identifier of a parachain.
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[cfg_attr(feature = "std", derive(Serialize, Debug))]
pub struct Id(u32); pub struct Id(u32);
impl From<Id> for u32 { impl From<Id> for u32 {
@@ -63,7 +63,7 @@ impl Slicable for Chain {
match disc { match disc {
0 => Some(Chain::Relay), 0 => Some(Chain::Relay),
1 => Some(Chain::Parachain(try_opt!(Slicable::decode(input)))), 1 => Some(Chain::Parachain(Slicable::decode(input)?)),
_ => None, _ => None,
} }
} }
@@ -102,8 +102,8 @@ pub struct DutyRoster {
impl Slicable for DutyRoster { impl Slicable for DutyRoster {
fn decode<I: Input>(input: &mut I) -> Option<Self> { fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(DutyRoster { Some(DutyRoster {
validator_duty: try_opt!(Slicable::decode(input)), validator_duty: Slicable::decode(input)?,
guarantor_duty: try_opt!(Slicable::decode(input)), guarantor_duty: Slicable::decode(input)?,
}) })
} }
@@ -123,7 +123,7 @@ impl Slicable for DutyRoster {
/// Extrinsic data for a parachain. /// Extrinsic data for a parachain.
#[derive(PartialEq, Eq, Clone)] #[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[cfg_attr(feature = "std", derive(Serialize, Debug))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))] #[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct Extrinsic; pub struct Extrinsic;
@@ -132,7 +132,7 @@ pub struct Extrinsic;
/// ///
/// https://github.com/w3f/polkadot-spec/blob/master/spec.md#candidate-para-chain-block /// https://github.com/w3f/polkadot-spec/blob/master/spec.md#candidate-para-chain-block
#[derive(PartialEq, Eq, Clone)] #[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[cfg_attr(feature = "std", derive(Serialize, Debug))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))] #[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct Candidate { pub struct Candidate {
@@ -150,7 +150,7 @@ pub struct Candidate {
/// Candidate receipt type. /// Candidate receipt type.
#[derive(PartialEq, Eq, Clone)] #[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] #[cfg_attr(feature = "std", derive(Debug, Serialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))] #[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct CandidateReceipt { pub struct CandidateReceipt {
@@ -184,12 +184,12 @@ impl Slicable for CandidateReceipt {
fn decode<I: Input>(input: &mut I) -> Option<Self> { fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(CandidateReceipt { Some(CandidateReceipt {
parachain_index: try_opt!(Slicable::decode(input)), parachain_index: Slicable::decode(input)?,
collator: try_opt!(Slicable::decode(input)), collator: Slicable::decode(input)?,
head_data: try_opt!(Slicable::decode(input).map(HeadData)), head_data: Slicable::decode(input).map(HeadData)?,
balance_uploads: try_opt!(Slicable::decode(input)), balance_uploads: Slicable::decode(input)?,
egress_queue_roots: try_opt!(Slicable::decode(input)), egress_queue_roots: Slicable::decode(input)?,
fees: try_opt!(Slicable::decode(input)), fees: Slicable::decode(input)?,
}) })
} }
} }
@@ -219,7 +219,7 @@ impl Ord for CandidateReceipt {
/// Parachain ingress queue message. /// Parachain ingress queue message.
#[derive(PartialEq, Eq, Clone)] #[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[cfg_attr(feature = "std", derive(Serialize, Debug))]
pub struct Message(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>); pub struct Message(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
/// Consolidated ingress queue data. /// Consolidated ingress queue data.
@@ -227,34 +227,34 @@ pub struct Message(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>
/// This is just an ordered vector of other parachains' egress queues, /// This is just an ordered vector of other parachains' egress queues,
/// obtained according to the routing rules. /// obtained according to the routing rules.
#[derive(Default, PartialEq, Eq, Clone)] #[derive(Default, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[cfg_attr(feature = "std", derive(Serialize, Debug))]
pub struct ConsolidatedIngress(pub Vec<(Id, Vec<Message>)>); pub struct ConsolidatedIngress(pub Vec<(Id, Vec<Message>)>);
/// Parachain block data. /// Parachain block data.
/// ///
/// contains everything required to validate para-block, may contain block and witness data /// contains everything required to validate para-block, may contain block and witness data
#[derive(PartialEq, Eq, Clone)] #[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[cfg_attr(feature = "std", derive(Serialize, Debug))]
pub struct BlockData(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>); pub struct BlockData(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
/// Parachain header raw bytes wrapper type. /// Parachain header raw bytes wrapper type.
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[cfg_attr(feature = "std", derive(Serialize, Debug))]
pub struct Header(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>); pub struct Header(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
/// Parachain head data included in the chain. /// Parachain head data included in the chain.
#[derive(PartialEq, Eq, Clone, PartialOrd, Ord)] #[derive(PartialEq, Eq, Clone, PartialOrd, Ord)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[cfg_attr(feature = "std", derive(Serialize, Debug))]
pub struct HeadData(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>); pub struct HeadData(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
/// Parachain validation code. /// Parachain validation code.
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[cfg_attr(feature = "std", derive(Serialize, Debug))]
pub struct ValidationCode(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>); pub struct ValidationCode(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
/// Activitiy bit field /// Activitiy bit field
#[derive(PartialEq, Eq, Clone, Default)] #[derive(PartialEq, Eq, Clone, Default)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[cfg_attr(feature = "std", derive(Serialize, Debug))]
pub struct Activity(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>); pub struct Activity(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
impl Slicable for Activity { impl Slicable for Activity {
@@ -344,7 +344,7 @@ mod tests {
fn test_candidate() { fn test_candidate() {
assert_eq!(ser::to_string_pretty(&Candidate { assert_eq!(ser::to_string_pretty(&Candidate {
parachain_index: 5.into(), parachain_index: 5.into(),
collator_signature: 10.into(), collator_signature: primitives::hash::H512::from(10).into(),
unprocessed_ingress: ConsolidatedIngress(vec![ unprocessed_ingress: ConsolidatedIngress(vec![
(Id(1), vec![Message(vec![2])]), (Id(1), vec![Message(vec![2])]),
(Id(2), vec![Message(vec![2]), Message(vec![3])]), (Id(2), vec![Message(vec![2]), Message(vec![3])]),
-487
View File
@@ -1,487 +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/>.
//! Transaction type.
use rstd::vec::Vec;
use codec::{Input, Slicable};
use primitives::bft::MisbehaviorReport;
use ::Signature;
#[cfg(feature = "std")]
use std::fmt;
use block::Number as BlockNumber;
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[repr(u8)]
enum InternalFunctionId {
/// Set the system's code.
SystemSetCode = 0x00,
/// Set the session length.
SessionSetLength = 0x10,
/// Force a new session.
SessionForceNewSession = 0x11,
/// Set the number of sessions per era.
StakingSetSessionsPerEra = 0x20,
/// Set the minimum bonding duration for staking.
StakingSetBondingDuration = 0x21,
/// Set the validator count for staking.
StakingSetValidatorCount = 0x22,
/// Force a new staking era.
StakingForceNewEra = 0x23,
/// Set the per-mille of validator approval required for governance changes.
GovernanceSetApprovalPpmRequired = 0x30,
}
impl InternalFunctionId {
/// Derive `Some` value from a `u8`, or `None` if it's invalid.
fn from_u8(value: u8) -> Option<InternalFunctionId> {
let functions = [
InternalFunctionId::SystemSetCode,
InternalFunctionId::SessionSetLength,
InternalFunctionId::SessionForceNewSession,
InternalFunctionId::StakingSetSessionsPerEra,
InternalFunctionId::StakingSetBondingDuration,
InternalFunctionId::StakingSetValidatorCount,
InternalFunctionId::StakingForceNewEra,
InternalFunctionId::GovernanceSetApprovalPpmRequired,
];
functions.iter().map(|&f| f).find(|&f| value == f as u8)
}
}
/// Internal functions that can be dispatched to.
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub enum Proposal {
/// Set the system's code.
SystemSetCode(Vec<u8>),
/// Set the session length.
SessionSetLength(BlockNumber),
/// Force a new session.
SessionForceNewSession,
/// Set the number of sessions per era.
StakingSetSessionsPerEra(BlockNumber),
/// Set the minimum bonding duration for staking.
StakingSetBondingDuration(BlockNumber),
/// Set the validator count for staking.
StakingSetValidatorCount(u32),
/// Force a new staking era.
StakingForceNewEra,
/// Set the per-mille of validator approval required for governance changes.
GovernanceSetApprovalPpmRequired(u32),
}
impl Slicable for Proposal {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
let id = InternalFunctionId::from_u8(input.read_byte()?)?;
let function = match id {
InternalFunctionId::SystemSetCode =>
Proposal::SystemSetCode(try_opt!(Slicable::decode(input))),
InternalFunctionId::SessionSetLength =>
Proposal::SessionSetLength(try_opt!(Slicable::decode(input))),
InternalFunctionId::SessionForceNewSession => Proposal::SessionForceNewSession,
InternalFunctionId::StakingSetSessionsPerEra =>
Proposal::StakingSetSessionsPerEra(try_opt!(Slicable::decode(input))),
InternalFunctionId::StakingSetBondingDuration =>
Proposal::StakingSetBondingDuration(try_opt!(Slicable::decode(input))),
InternalFunctionId::StakingSetValidatorCount =>
Proposal::StakingSetValidatorCount(try_opt!(Slicable::decode(input))),
InternalFunctionId::StakingForceNewEra => Proposal::StakingForceNewEra,
InternalFunctionId::GovernanceSetApprovalPpmRequired =>
Proposal::GovernanceSetApprovalPpmRequired(try_opt!(Slicable::decode(input))),
};
Some(function)
}
fn encode(&self) -> Vec<u8> {
let mut v = Vec::new();
match *self {
Proposal::SystemSetCode(ref data) => {
v.push(InternalFunctionId::SystemSetCode as u8);
data.using_encoded(|s| v.extend(s));
}
Proposal::SessionSetLength(ref data) => {
v.push(InternalFunctionId::SessionSetLength as u8);
data.using_encoded(|s| v.extend(s));
}
Proposal::SessionForceNewSession => {
v.push(InternalFunctionId::SessionForceNewSession as u8);
}
Proposal::StakingSetSessionsPerEra(ref data) => {
v.push(InternalFunctionId::StakingSetSessionsPerEra as u8);
data.using_encoded(|s| v.extend(s));
}
Proposal::StakingSetBondingDuration(ref data) => {
v.push(InternalFunctionId::StakingSetBondingDuration as u8);
data.using_encoded(|s| v.extend(s));
}
Proposal::StakingSetValidatorCount(ref data) => {
v.push(InternalFunctionId::StakingSetValidatorCount as u8);
data.using_encoded(|s| v.extend(s));
}
Proposal::StakingForceNewEra => {
v.push(InternalFunctionId::StakingForceNewEra as u8);
}
Proposal::GovernanceSetApprovalPpmRequired(ref data) => {
v.push(InternalFunctionId::GovernanceSetApprovalPpmRequired as u8);
data.using_encoded(|s| v.extend(s));
}
}
v
}
}
/// Public functions that can be dispatched to.
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[repr(u8)]
enum FunctionId {
/// Set the timestamp.
TimestampSet = 0x00,
/// Set temporary session key as a validator.
SessionSetKey = 0x10,
/// Staking subsystem: begin staking.
StakingStake = 0x20,
/// Staking subsystem: stop staking.
StakingUnstake = 0x21,
/// Staking subsystem: transfer stake.
StakingTransfer = 0x22,
/// Report misbehavior.
StakingReportMisbehavior = 0x23,
/// Make a proposal for the governance system.
GovernancePropose = 0x30,
/// Approve a proposal for the governance system.
GovernanceApprove = 0x31,
}
impl FunctionId {
/// Derive `Some` value from a `u8`, or `None` if it's invalid.
fn from_u8(value: u8) -> Option<FunctionId> {
use self::*;
let functions = [
FunctionId::StakingStake,
FunctionId::StakingUnstake,
FunctionId::StakingTransfer,
FunctionId::StakingReportMisbehavior,
FunctionId::SessionSetKey,
FunctionId::TimestampSet,
FunctionId::GovernancePropose,
FunctionId::GovernanceApprove,
];
functions.iter().map(|&f| f).find(|&f| value == f as u8)
}
}
/// Inherent functions on the runtime.
/// These must be called each block by the `EVERYBODY` account.
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub enum InherentFunction {
/// Set the timestamp.
TimestampSet(u64),
}
impl InherentFunction {
/// Get the number of inherent functions.
pub fn count() -> u64 {
1
}
/// Get the index.
pub fn index(&self) -> u64 {
match *self {
InherentFunction::TimestampSet(_) => 0,
}
}
}
/// Functions on the runtime.
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub enum Function {
/// An inherent function.
Inherent(InherentFunction),
/// Set temporary session key as a validator.
SessionSetKey(::SessionKey),
/// Staking subsystem: begin staking.
StakingStake,
/// Staking subsystem: stop staking.
StakingUnstake,
/// Staking subsystem: transfer stake.
StakingTransfer(::AccountId, u64),
/// Staking subsystem: report misbehavior of a validator.
ReportMisbehavior(MisbehaviorReport),
/// Make a proposal for the governance system.
GovernancePropose(Proposal),
/// Approve a proposal for the governance system.
GovernanceApprove(BlockNumber),
}
impl Function {
/// The number of inherent functions.
pub fn inherent_functions() -> u64 { InherentFunction::count() }
/// Whether this function is "inherent": that it must be part of every
/// block at the given index and no other.
///
/// Transactions containing inherent functions should not be signed.
pub fn is_inherent(&self) -> bool {
match *self {
Function::Inherent(_) => true,
_ => false,
}
}
/// If this function is inherent, returns the index it should occupy
/// in the block. Otherwise returns `None`.
pub fn inherent_index(&self) -> Option<u64> {
match *self {
Function::Inherent(ref inner) => Some(inner.index()),
_ => None,
}
}
}
impl Slicable for Function {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
let id = FunctionId::from_u8(input.read_byte()?)?;
Some(match id {
FunctionId::TimestampSet =>
Function::Inherent(InherentFunction::TimestampSet(try_opt!(Slicable::decode(input)))),
FunctionId::SessionSetKey =>
Function::SessionSetKey(try_opt!(Slicable::decode(input))),
FunctionId::StakingStake => Function::StakingStake,
FunctionId::StakingUnstake => Function::StakingUnstake,
FunctionId::StakingTransfer => {
let to = try_opt!(Slicable::decode(input));
let amount = try_opt!(Slicable::decode(input));
Function::StakingTransfer(to, amount)
}
FunctionId::StakingReportMisbehavior => Function::ReportMisbehavior(MisbehaviorReport::decode(input)?),
FunctionId::GovernancePropose =>
Function::GovernancePropose(try_opt!(Slicable::decode(input))),
FunctionId::GovernanceApprove =>
Function::GovernanceApprove(try_opt!(Slicable::decode(input))),
})
}
fn encode(&self) -> Vec<u8> {
let mut v = Vec::new();
match *self {
Function::Inherent(InherentFunction::TimestampSet(ref data)) => {
v.push(FunctionId::TimestampSet as u8);
data.using_encoded(|s| v.extend(s));
}
Function::SessionSetKey(ref data) => {
v.push(FunctionId::SessionSetKey as u8);
data.using_encoded(|s| v.extend(s));
}
Function::StakingStake => {
v.push(FunctionId::StakingStake as u8);
}
Function::StakingUnstake => {
v.push(FunctionId::StakingUnstake as u8);
}
Function::ReportMisbehavior(ref report) => {
v.push(FunctionId::StakingReportMisbehavior as u8);
report.using_encoded(|s| v.extend(s));
}
Function::StakingTransfer(ref to, ref amount) => {
v.push(FunctionId::StakingTransfer as u8);
to.using_encoded(|s| v.extend(s));
amount.using_encoded(|s| v.extend(s));
}
Function::GovernancePropose(ref data) => {
v.push(FunctionId::GovernancePropose as u8);
data.using_encoded(|s| v.extend(s));
}
Function::GovernanceApprove(ref data) => {
v.push(FunctionId::GovernanceApprove as u8);
data.using_encoded(|s| v.extend(s));
}
}
v
}
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
f(self.encode().as_slice())
}
}
/// A vetted and verified transaction from the external world.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub struct Transaction {
/// Who signed it (note this is not a signature).
pub signed: super::AccountId,
/// The number of transactions have come before from the same signer.
pub nonce: super::TxOrder,
/// The function that should be called.
pub function: Function,
}
impl Slicable for Transaction {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(Transaction {
signed: try_opt!(Slicable::decode(input)),
nonce: try_opt!(Slicable::decode(input)),
function: try_opt!(Slicable::decode(input)),
})
}
fn encode(&self) -> Vec<u8> {
let mut v = Vec::new();
self.signed.using_encoded(|s| v.extend(s));
self.nonce.using_encoded(|s| v.extend(s));
self.function.using_encoded(|s| v.extend(s));
v
}
}
/// A transactions right from the external world. Unchecked.
#[derive(Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct UncheckedTransaction {
/// The actual transaction information.
pub transaction: Transaction,
/// The signature; should be an Ed25519 signature applied to the serialised `transaction` field.
pub signature: Signature,
}
impl UncheckedTransaction {
/// Whether the transaction is well-formed. In particular checks that
/// inherent transactions have the correct signed and signature fields.
///
/// Does not check signatures on other transactions.
pub fn is_well_formed(&self) -> bool {
if self.transaction.function.is_inherent() {
self.transaction.signed == ::EVERYBODY && self.signature == Signature::zero()
} else {
true
}
}
/// Whether this transaction invokes an inherent function.
pub fn is_inherent(&self) -> bool {
self.transaction.function.is_inherent()
}
/// Create a new inherent-style transaction from the given function.
pub fn inherent(function: InherentFunction) -> Self {
UncheckedTransaction {
transaction: Transaction {
function: Function::Inherent(function),
nonce: 0,
signed: ::EVERYBODY
},
signature: Signature::zero(),
}
}
}
impl Slicable for UncheckedTransaction {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
// This is a little more complicated than usual since the binary format must be compatible
// with substrate's generic `Vec<u8>` type. Basically this just means accepting that there
// will be a prefix of u32, which has the total number of bytes following (we don't need
// to use this).
let _length_do_not_remove_me_see_above: u32 = try_opt!(Slicable::decode(input));
Some(UncheckedTransaction {
transaction: try_opt!(Slicable::decode(input)),
signature: try_opt!(Slicable::decode(input)),
})
}
fn encode(&self) -> Vec<u8> {
let mut v = Vec::new();
// need to prefix with the total length as u32 to ensure it's binary comptible with
// Vec<u8>. we'll make room for it here, then overwrite once we know the length.
v.extend(&[0u8; 4]);
self.transaction.signed.using_encoded(|s| v.extend(s));
self.transaction.nonce.using_encoded(|s| v.extend(s));
self.transaction.function.using_encoded(|s| v.extend(s));
self.signature.using_encoded(|s| v.extend(s));
let length = (v.len() - 4) as u32;
length.using_encoded(|s| v[0..4].copy_from_slice(s));
v
}
}
impl PartialEq for UncheckedTransaction {
fn eq(&self, other: &Self) -> bool {
self.signature.iter().eq(other.signature.iter()) && self.transaction == other.transaction
}
}
#[cfg(feature = "std")]
impl fmt::Debug for UncheckedTransaction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "UncheckedTransaction({:?})", self.transaction)
}
}
#[cfg(test)]
mod tests {
use super::*;
use primitives;
use ::codec::Slicable;
use primitives::hexdisplay::HexDisplay;
#[test]
fn serialize_unchecked() {
let tx = UncheckedTransaction {
transaction: Transaction {
signed: [1; 32],
nonce: 999u64,
function: Function::Inherent(InherentFunction::TimestampSet(135135)),
},
signature: primitives::hash::H512([0; 64]),
};
// 71000000
// 0101010101010101010101010101010101010101010101010101010101010101
// e703000000000000
// 00
// df0f0200
// 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
let v = Slicable::encode(&tx);
println!("{}", HexDisplay::from(&v));
assert_eq!(UncheckedTransaction::decode(&mut &v[..]).unwrap(), tx);
}
}
+4 -4
View File
@@ -23,22 +23,22 @@ use parachain;
/// Parachain outgoing message. /// Parachain outgoing message.
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[cfg_attr(feature = "std", derive(Serialize, Debug))]
pub struct EgressPost(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>); pub struct EgressPost(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
/// Balance upload. /// Balance upload.
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[cfg_attr(feature = "std", derive(Serialize, Debug))]
pub struct BalanceUpload(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>); pub struct BalanceUpload(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
/// Balance download. /// Balance download.
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[cfg_attr(feature = "std", derive(Serialize, Debug))]
pub struct BalanceDownload(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>); pub struct BalanceDownload(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
/// The result of parachain validation. /// The result of parachain validation.
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[cfg_attr(feature = "std", derive(Serialize, Debug))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))] #[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct ValidationResult { pub struct ValidationResult {
+28 -7
View File
@@ -7,26 +7,47 @@ authors = ["Parity Technologies <admin@parity.io>"]
rustc-hex = "1.0" rustc-hex = "1.0"
hex-literal = "0.1.0" hex-literal = "0.1.0"
log = { version = "0.3", optional = true } log = { version = "0.3", optional = true }
serde = { version = "1.0", default_features = false }
serde_derive = { version = "1.0", optional = true }
safe-mix = { path = "../../safe-mix", default_features = false}
substrate-codec = { path = "../../substrate/codec" } substrate-codec = { path = "../../substrate/codec" }
substrate-serializer = { path = "../../substrate/serializer" }
substrate-runtime-std = { path = "../../substrate/runtime-std" } substrate-runtime-std = { path = "../../substrate/runtime-std" }
substrate-runtime-io = { path = "../../substrate/runtime-io" } substrate-runtime-io = { path = "../../substrate/runtime-io" }
substrate-runtime-support = { path = "../../substrate/runtime-support" } substrate-runtime-support = { path = "../../substrate/runtime-support" }
substrate-primitives = { path = "../../substrate/primitives" } substrate-primitives = { path = "../../substrate/primitives" }
substrate-misbehavior-check = { path = "../../substrate/misbehavior-check" }
polkadot-primitives = { path = "../primitives" }
[dev-dependencies]
substrate-keyring = { path = "../../substrate/keyring" } substrate-keyring = { path = "../../substrate/keyring" }
substrate-runtime-consensus = { path = "../../substrate/runtime/consensus" }
substrate-runtime-council = { path = "../../substrate/runtime/council" }
substrate-runtime-democracy = { path = "../../substrate/runtime/democracy" }
substrate-runtime-executive = { path = "../../substrate/runtime/executive" }
substrate-runtime-primitives = { path = "../../substrate/runtime/primitives" }
substrate-runtime-session = { path = "../../substrate/runtime/session" }
substrate-runtime-staking = { path = "../../substrate/runtime/staking" }
substrate-runtime-system = { path = "../../substrate/runtime/system" }
substrate-runtime-timestamp = { path = "../../substrate/runtime/timestamp" }
polkadot-primitives = { path = "../primitives" }
[features] [features]
default = ["std"] default = ["std"]
std = [ std = [
"substrate-codec/std", "substrate-codec/std",
"substrate-primitives/std",
"substrate-runtime-std/std", "substrate-runtime-std/std",
"substrate-runtime-io/std", "substrate-runtime-io/std",
"substrate-runtime-support/std", "substrate-runtime-support/std",
"substrate-primitives/std", "substrate-runtime-consensus/std",
"substrate-misbehavior-check/std", "substrate-runtime-council/std",
"substrate-runtime-democracy/std",
"substrate-runtime-executive/std",
"substrate-runtime-primitives/std",
"substrate-runtime-session/std",
"substrate-runtime-staking/std",
"substrate-runtime-system/std",
"substrate-runtime-timestamp/std",
"polkadot-primitives/std", "polkadot-primitives/std",
"log" "serde_derive",
"serde/std",
"log",
"safe-mix/std"
] ]
-29
View File
@@ -1,29 +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/>.
use runtime::{system, parachains, consensus, session};
impl_stubs!(
execute_block => |block| system::internal::execute_block(block),
execute_transaction => |(header, utx)| system::internal::execute_transaction(utx, header),
finalise_block => |header| system::internal::finalise_block(header),
validator_count => |()| session::validator_count(),
validators => |()| session::validators(),
authorities => |()| consensus::authorities(),
duty_roster => |()| parachains::calculate_duty_roster(),
timestamp => |()| ::runtime::timestamp::get(),
nonce => |account_id| system::nonce(account_id)
);
-81
View File
@@ -1,81 +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/>.
//! Environment API: Allows certain information to be accessed throughout the runtime.
use rstd::boxed::Box;
use rstd::cell::RefCell;
use rstd::rc::Rc;
use polkadot_primitives::{BlockNumber, Digest, Hash};
#[derive(Default)]
/// The information that can be accessed globally.
pub struct Environment {
/// The current block number.
pub block_number: BlockNumber,
/// The current block's parent hash.
pub parent_hash: Hash,
/// The current block digest.
pub digest: Digest,
}
/// Do something with the environment and return its value. Keep the function short.
pub fn with_env<T, F: FnOnce(&mut Environment) -> T>(f: F) -> T {
let e = env();
let mut eb = e.borrow_mut();
f(&mut *eb)
}
#[cfg(target_arch = "wasm32")]
fn env() -> Rc<RefCell<Environment>> {
// Initialize it to a null value
static mut SINGLETON: *const Rc<RefCell<Environment>> = 0 as *const Rc<RefCell<Environment>>;
unsafe {
if SINGLETON == 0 as *const Rc<RefCell<Environment>> {
// Make it
let singleton: Rc<RefCell<Environment>> = Rc::new(RefCell::new(Default::default()));
// Put it in the heap so it can outlive this call
SINGLETON = Box::into_raw(Box::new(singleton)) as *const _;
}
// Now we give out a copy of the data that is safe to use concurrently.
(*SINGLETON).clone()
}
}
#[cfg(not(target_arch = "wasm32"))]
fn env() -> Rc<RefCell<Environment>> {
// Initialize it to a null value
thread_local!{
static SINGLETON: RefCell<*const Rc<RefCell<Environment>>> = RefCell::new(0 as *const Rc<RefCell<Environment>>);
}
SINGLETON.with(|s| unsafe {
if *s.borrow() == 0 as *const Rc<RefCell<Environment>> {
// Make it
let singleton: Rc<RefCell<Environment>> = Rc::new(RefCell::new(Default::default()));
// Put it in the heap so it can outlive this call
*s.borrow_mut() = Box::into_raw(Box::new(singleton)) as *const _;
}
// Now we give out a copy of the data that is safe to use concurrently.
(**s.borrow()).clone()
})
}
-91
View File
@@ -1,91 +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/>.
//! Tool for creating the genesis block.
use codec::{KeyedVec, Joiner};
use std::collections::HashMap;
use runtime_io::twox_128;
use runtime_support::Hashable;
use primitives::Block;
use polkadot_primitives::{Balance, BlockNumber, AccountId};
/// Configuration of a general Polkadot genesis block.
pub struct GenesisConfig {
pub validators: Vec<AccountId>,
pub authorities: Vec<AccountId>,
pub balances: Vec<(AccountId, Balance)>,
pub block_time: u64,
pub session_length: BlockNumber,
pub sessions_per_era: BlockNumber,
pub bonding_duration: BlockNumber,
pub approval_ratio: u32,
}
impl GenesisConfig {
pub fn new_simple(authorities_validators: Vec<AccountId>, balance: Balance) -> Self {
GenesisConfig {
validators: authorities_validators.clone(),
authorities: authorities_validators.clone(),
balances: authorities_validators.iter().map(|v| (v.clone(), balance)).collect(),
block_time: 5, // 5 second block time.
session_length: 720, // that's 1 hour per session.
sessions_per_era: 24, // 24 hours per era.
bonding_duration: 90, // 90 days per bond.
approval_ratio: 667, // 66.7% approvals required for legislation.
}
}
pub fn genesis_map(&self) -> HashMap<Vec<u8>, Vec<u8>> {
let wasm_runtime = include_bytes!("../wasm/genesis.wasm").to_vec();
vec![
(&b"gov:apr"[..], vec![].and(&self.approval_ratio)),
(&b"ses:len"[..], vec![].and(&self.session_length)),
(&b"ses:val:len"[..], vec![].and(&(self.validators.len() as u32))),
(&b"sta:wil:len"[..], vec![].and(&0u32)),
(&b"sta:spe"[..], vec![].and(&self.sessions_per_era)),
(&b"sta:vac"[..], vec![].and(&(self.validators.len() as u32))),
(&b"sta:era"[..], vec![].and(&0u64)),
].into_iter()
.map(|(k, v)| (k.into(), v))
.chain(self.validators.iter()
.enumerate()
.map(|(i, account)| ((i as u32).to_keyed_vec(b"ses:val:"), vec![].and(account)))
).chain(self.authorities.iter()
.enumerate()
.map(|(i, account)| ((i as u32).to_keyed_vec(b":auth:"), vec![].and(account)))
).chain(self.balances.iter()
.map(|&(account, balance)| (account.to_keyed_vec(b"sta:bal:"), vec![].and(&balance)))
)
.map(|(k, v)| (twox_128(&k[..])[..].to_vec(), v.to_vec()))
.chain(vec![
(b":code"[..].into(), wasm_runtime),
(b":auth:len"[..].into(), vec![].and(&(self.authorities.len() as u32))),
].into_iter())
.chain(self.authorities.iter()
.enumerate()
.map(|(i, account)| ((i as u32).to_keyed_vec(b":auth:"), vec![].and(account)))
)
.collect()
}
}
pub fn additional_storage_with_genesis(genesis_block: &Block) -> HashMap<Vec<u8>, Vec<u8>> {
use codec::Slicable;
map![
twox_128(&0u64.to_keyed_vec(b"sys:old:")).to_vec() => genesis_block.header.blake2_256().encode()
]
}
+269 -65
View File
@@ -14,84 +14,288 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>. // along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! 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)]
extern crate substrate_runtime_std as rstd;
extern crate substrate_runtime_support as runtime_support;
extern crate substrate_codec as codec;
extern crate substrate_misbehavior_check as misbehavior_check;
extern crate polkadot_primitives;
#[cfg(all(feature = "std", test))]
extern crate substrate_keyring as keyring;
#[cfg(feature = "std")]
extern crate rustc_hex;
#[cfg_attr(any(test, feature = "std"), macro_use)]
extern crate substrate_primitives as primitives;
#[macro_use] #[macro_use]
extern crate substrate_runtime_io as runtime_io; extern crate substrate_runtime_io as runtime_io;
#[cfg(test)]
#[macro_use] #[macro_use]
extern crate hex_literal; extern crate substrate_runtime_support as runtime_support;
pub mod api; #[macro_use]
pub mod environment; extern crate substrate_runtime_primitives as runtime_primitives;
pub mod runtime;
#[cfg(feature = "std")] #[cfg(test)]
pub mod genesismap; extern crate substrate_serializer;
/// Type definitions and helpers for transactions. #[cfg_attr(feature = "std", macro_use)]
pub mod transaction { extern crate substrate_primitives;
use rstd::ops;
use polkadot_primitives::Signature;
pub use polkadot_primitives::{Transaction, Function, UncheckedTransaction};
/// A type-safe indicator that a transaction has been checked. extern crate substrate_runtime_std as rstd;
#[derive(PartialEq, Eq, Clone)] extern crate substrate_codec as codec;
#[cfg_attr(feature = "std", derive(Debug))] extern crate substrate_runtime_consensus as consensus;
pub struct CheckedTransaction(UncheckedTransaction); extern crate substrate_runtime_council as council;
extern crate substrate_runtime_democracy as democracy;
extern crate substrate_runtime_executive as executive;
extern crate substrate_runtime_session as session;
extern crate substrate_runtime_staking as staking;
extern crate substrate_runtime_system as system;
extern crate substrate_runtime_timestamp as timestamp;
extern crate polkadot_primitives;
impl CheckedTransaction { mod parachains;
/// Get a reference to the checked signature.
pub fn signature(&self) -> &Signature { use runtime_io::BlakeTwo256;
&self.0.signature use polkadot_primitives::{AccountId, Balance, BlockNumber, Hash, Index, Log, SessionKey, Signature};
} use runtime_primitives::generic;
use runtime_primitives::traits::{Identity, HasPublicAux};
#[cfg(feature = "std")] pub use runtime_primitives::BuildExternalities;
/// Concrete runtime type used to parameterize the various modules.
pub struct Concrete;
impl HasPublicAux for Concrete {
type PublicAux = AccountId; // TODO: Option<AccountId>
}
impl system::Trait for Concrete {
type Index = Index;
type BlockNumber = BlockNumber;
type Hash = Hash;
type Hashing = BlakeTwo256;
type Digest = generic::Digest<Log>;
type AccountId = AccountId;
type Header = generic::Header<BlockNumber, Hash, Log>;
}
/// System module for this concrete runtime.
pub type System = system::Module<Concrete>;
impl consensus::Trait for Concrete {
type PublicAux = <Self as HasPublicAux>::PublicAux;
type SessionKey = SessionKey;
}
/// Consensus module for this concrete runtime.
pub type Consensus = consensus::Module<Concrete>;
pub use consensus::Call as ConsensusCall;
impl timestamp::Trait for Concrete {
type Value = u64;
}
/// Timestamp module for this concrete runtime.
pub type Timestamp = timestamp::Module<Concrete>;
pub use timestamp::Call as TimestampCall;
impl session::Trait for Concrete {
type ConvertAccountIdToSessionKey = Identity;
}
/// Session module for this concrete runtime.
pub type Session = session::Module<Concrete>;
impl staking::Trait for Concrete {
type Balance = Balance;
type DetermineContractAddress = BlakeTwo256;
}
/// Staking module for this concrete runtime.
pub type Staking = staking::Module<Concrete>;
impl democracy::Trait for Concrete {
type Proposal = PrivCall;
}
/// Democracy module for this concrete runtime.
pub type Democracy = democracy::Module<Concrete>;
impl council::Trait for Concrete {}
/// Council module for this concrete runtime.
pub type Council = council::Module<Concrete>;
/// Council voting module for this concrete runtime.
pub type CouncilVoting = council::voting::Module<Concrete>;
impl parachains::Trait for Concrete {}
pub type Parachains = parachains::Module<Concrete>;
impl_outer_dispatch! {
pub enum Call where aux: <Concrete as HasPublicAux>::PublicAux {
Consensus = 0,
Session = 1,
Staking = 2,
Timestamp = 3,
Democracy = 5,
Council = 6,
CouncilVoting = 7,
} }
impl ops::Deref for CheckedTransaction { pub enum PrivCall {
type Target = Transaction; Consensus = 0,
Session = 1,
fn deref(&self) -> &Transaction { Staking = 2,
&self.0.transaction Democracy = 5,
} Council = 6,
} CouncilVoting = 7,
}
/// Check the validity of a transaction: whether it can appear at the given index }
/// and whether it is correctly authenticated.
pub fn check(tx: UncheckedTransaction, index: u64) -> Result<CheckedTransaction, UncheckedTransaction> { /// Block header type as expected by this runtime.
match tx.transaction.function.inherent_index() { pub type Header = generic::Header<BlockNumber, Hash, Log>;
Some(correct_index) => { /// Block type as expected by this runtime.
if index != correct_index || !tx.is_well_formed() { return Err(tx) } pub type Block = generic::Block<BlockNumber, Hash, Log, AccountId, Index, Call, Signature>;
return Ok(CheckedTransaction(tx)); /// Unchecked extrinsic type as expected by this runtime.
} pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<AccountId, Index, Call, Signature>;
None => { /// Extrinsic type as expected by this runtime.
// non-inherent functions must appear after inherent. pub type Extrinsic = generic::Extrinsic<AccountId, Index, Call>;
if index < Function::inherent_functions() { return Err(tx) } /// Executive: handles dispatch to the various modules.
} pub type Executive = executive::Executive<Concrete, Block, Staking,
} ((((((), Parachains), Council), Democracy), Staking), Session)>;
let msg = ::codec::Slicable::encode(&tx.transaction); impl_outer_config! {
if ::runtime_io::ed25519_verify(&tx.signature.0, &msg, &tx.transaction.signed) { pub struct GenesisConfig for Concrete {
Ok(CheckedTransaction(tx)) ConsensusConfig => consensus,
} else { SystemConfig => system,
Err(tx) SessionConfig => session,
} StakingConfig => staking,
DemocracyConfig => democracy,
CouncilConfig => council,
ParachainsConfig => parachains,
}
}
pub mod api {
impl_stubs!(
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(),
validator_count => |()| super::Session::validator_count(),
validators => |()| super::Session::validators()
);
}
#[cfg(test)]
mod tests {
use super::*;
use substrate_primitives as primitives;
use ::codec::Slicable;
use substrate_primitives::hexdisplay::HexDisplay;
use substrate_serializer as ser;
use runtime_primitives::traits::{Digest as DigestT, 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: { let mut d = Digest::default(); d.push(Log(vec![1])); d },
};
assert_eq!(ser::to_string_pretty(&header), r#"{
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000005",
"number": 67,
"stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000003",
"extrinsicsRoot": "0x0000000000000000000000000000000000000000000000000000000000000006",
"digest": {
"logs": [
"0x01"
]
}
}"#);
let v = header.encode();
assert_eq!(Header::decode(&mut &v[..]).unwrap(), header);
}
#[test]
fn block_encoding_round_trip() {
let mut block = Block {
header: Header::new(1, Default::default(), Default::default(), Default::default(), Default::default()),
extrinsics: vec![
UncheckedExtrinsic {
extrinsic: Extrinsic {
function: Call::Timestamp(timestamp::Call::set(100_000_000)),
signed: Default::default(),
index: Default::default(),
},
signature: Default::default(),
}
],
};
let raw = block.encode();
let decoded = Block::decode(&mut &raw[..]).unwrap();
assert_eq!(block, decoded);
block.extrinsics.push(UncheckedExtrinsic {
extrinsic: Extrinsic {
function: Call::Staking(staking::Call::stake()),
signed: Default::default(),
index: 10101,
},
signature: Default::default(),
});
let raw = block.encode();
let decoded = Block::decode(&mut &raw[..]).unwrap();
assert_eq!(block, decoded);
}
#[test]
fn block_encoding_substrate_round_trip() {
let mut block = Block {
header: Header::new(1, Default::default(), Default::default(), Default::default(), Default::default()),
extrinsics: vec![
UncheckedExtrinsic {
extrinsic: Extrinsic {
function: Call::Timestamp(timestamp::Call::set(100_000_000)),
signed: Default::default(),
index: Default::default(),
},
signature: Default::default(),
}
],
};
block.extrinsics.push(UncheckedExtrinsic {
extrinsic: Extrinsic {
function: Call::Staking(staking::Call::stake()),
signed: Default::default(),
index: 10101,
},
signature: Default::default(),
});
let raw = block.encode();
let decoded_substrate = primitives::block::Block::decode(&mut &raw[..]).unwrap();
let encoded_substrate = decoded_substrate.encode();
let decoded = Block::decode(&mut &encoded_substrate[..]).unwrap();
assert_eq!(block, decoded);
}
#[test]
fn serialize_unchecked() {
let tx = UncheckedExtrinsic {
extrinsic: Extrinsic {
signed: [1; 32],
index: 999u64,
function: Call::Timestamp(TimestampCall::set(135135)),
},
signature: primitives::hash::H512([0; 64]).into(),
};
// 71000000
// 0101010101010101010101010101010101010101010101010101010101010101
// e703000000000000
// 00
// df0f0200
// 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
let v = Slicable::encode(&tx);
println!("{}", HexDisplay::from(&v));
assert_eq!(UncheckedExtrinsic::decode(&mut &v[..]).unwrap(), tx);
} }
} }
+210
View File
@@ -0,0 +1,210 @@
// 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/>.
//! Main parachains logic. For now this is just the determination of which validators do what.
use polkadot_primitives;
#[cfg(any(feature = "std", test))] use {runtime_io, runtime_primitives};
use rstd::prelude::*;
#[cfg(any(feature = "std", test))] use rstd::marker::PhantomData;
use codec::{Slicable, Joiner};
use runtime_support::Hashable;
#[cfg(any(feature = "std", test))] use runtime_support::StorageValue;
use runtime_primitives::traits::Executable;
use polkadot_primitives::parachain::{Id, Chain, DutyRoster};
use {system, session};
pub trait Trait: system::Trait<Hash = polkadot_primitives::Hash> + session::Trait {}
decl_module! {
pub struct Module<T: Trait>;
}
decl_storage! {
pub trait Store for Module<T: Trait>;
// The number of parachains registered at present.
pub Count get(count): b"para:count" => default u32;
}
impl<T: Trait> Module<T> {
/// Calculate the current block's duty roster.
pub fn calculate_duty_roster() -> DutyRoster {
let parachain_count = Self::count();
let validator_count = <session::Module<T>>::validator_count();
let validators_per_parachain = (validator_count - 1) / parachain_count;
let mut roles_val = (0..validator_count).map(|i| match i {
i if i < parachain_count * validators_per_parachain =>
Chain::Parachain(Id::from(i / validators_per_parachain as u32)),
_ => Chain::Relay,
}).collect::<Vec<_>>();
let mut roles_gua = roles_val.clone();
let h = <system::Module<T>>::random_seed();
let mut seed = h.to_vec().and(b"validator_role_pairs").blake2_256();
// shuffle
for i in 0..(validator_count - 1) {
// 8 bytes of entropy used per cycle, 32 bytes entropy per hash
let offset = (i * 8 % 32) as usize;
// number of roles remaining to select from.
let remaining = (validator_count - i) as usize;
// 4 * 2 32-bit ints per 256-bit seed.
let val_index = u32::decode(&mut &seed[offset..offset + 4]).expect("using 4 bytes for a 32-bit quantity") as usize % remaining;
let gua_index = u32::decode(&mut &seed[offset + 4..offset + 8]).expect("using 4 bytes for a 32-bit quantity") as usize % remaining;
if offset == 24 {
// into the last 8 bytes - rehash to gather new entropy
seed = seed.blake2_256();
}
// exchange last item with randomly chosen first.
roles_val.swap(remaining - 1, val_index);
roles_gua.swap(remaining - 1, gua_index);
}
DutyRoster {
validator_duty: roles_val,
guarantor_duty: roles_gua,
}
}
}
impl<T: Trait> Executable for Module<T> {
fn execute() {
}
}
#[cfg(any(feature = "std", test))]
pub struct GenesisConfig<T: Trait> {
pub count: u32,
pub phantom: PhantomData<T>,
}
#[cfg(any(feature = "std", test))]
impl<T: Trait> Default for GenesisConfig<T> {
fn default() -> Self {
GenesisConfig {
count: 0,
phantom: PhantomData,
}
}
}
#[cfg(any(feature = "std", test))]
impl<T: Trait> runtime_primitives::BuildExternalities for GenesisConfig<T>
{
fn build_externalities(self) -> runtime_io::TestExternalities {
use runtime_io::twox_128;
use codec::Slicable;
map![
twox_128(<Count<T>>::key()).to_vec() => self.count.encode()
]
}
}
#[cfg(test)]
mod tests {
use super::*;
use runtime_io::with_externalities;
use substrate_primitives::H256;
use runtime_primitives::BuildExternalities;
use runtime_primitives::traits::{HasPublicAux, Identity};
use runtime_primitives::testing::{Digest, Header};
use consensus;
pub struct Test;
impl HasPublicAux for Test {
type PublicAux = u64;
}
impl consensus::Trait for Test {
type PublicAux = <Self as HasPublicAux>::PublicAux;
type SessionKey = u64;
}
impl system::Trait for Test {
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
type Hashing = runtime_io::BlakeTwo256;
type Digest = Digest;
type AccountId = u64;
type Header = Header;
}
impl session::Trait for Test {
type ConvertAccountIdToSessionKey = Identity;
}
impl Trait for Test {}
type System = system::Module<Test>;
type Parachains = Module<Test>;
fn new_test_ext() -> runtime_io::TestExternalities {
let mut t = system::GenesisConfig::<Test>::default().build_externalities();
t.extend(consensus::GenesisConfig::<Test>{
code: vec![],
authorities: vec![1, 2, 3],
}.build_externalities());
t.extend(session::GenesisConfig::<Test>{
session_length: 1000,
validators: vec![1, 2, 3, 4, 5, 6, 7, 8],
}.build_externalities());
t.extend(GenesisConfig::<Test>{
count: 2,
phantom: PhantomData,
}.build_externalities());
t
}
#[test]
fn simple_setup_should_work() {
with_externalities(&mut new_test_ext(), || {
assert_eq!(Parachains::count(), 2);
});
}
#[test]
fn should_work() {
with_externalities(&mut new_test_ext(), || {
let check_roster = |duty_roster: &DutyRoster| {
assert_eq!(duty_roster.validator_duty.len(), 8);
assert_eq!(duty_roster.guarantor_duty.len(), 8);
for i in (0..2).map(Id::from) {
assert_eq!(duty_roster.validator_duty.iter().filter(|&&j| j == Chain::Parachain(i)).count(), 3);
assert_eq!(duty_roster.guarantor_duty.iter().filter(|&&j| j == Chain::Parachain(i)).count(), 3);
}
assert_eq!(duty_roster.validator_duty.iter().filter(|&&j| j == Chain::Relay).count(), 2);
assert_eq!(duty_roster.guarantor_duty.iter().filter(|&&j| j == Chain::Relay).count(), 2);
};
System::set_random_seed([0u8; 32].into());
let duty_roster_0 = Parachains::calculate_duty_roster();
check_roster(&duty_roster_0);
System::set_random_seed([1u8; 32].into());
let duty_roster_1 = Parachains::calculate_duty_roster();
check_roster(&duty_roster_1);
assert!(duty_roster_0 != duty_roster_1);
System::set_random_seed([2u8; 32].into());
let duty_roster_2 = Parachains::calculate_duty_roster();
check_roster(&duty_roster_2);
assert!(duty_roster_0 != duty_roster_2);
assert!(duty_roster_1 != duty_roster_2);
});
}
}
-48
View File
@@ -1,48 +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/>.
//! Conensus module for runtime; manages the authority set ready for the native code.
use rstd::prelude::*;
use runtime_support::storage::unhashed::StorageVec;
use polkadot_primitives::SessionKey;
struct AuthorityStorageVec {}
impl StorageVec for AuthorityStorageVec {
type Item = SessionKey;
const PREFIX: &'static [u8] = b":auth:";
}
/// Get the current set of authorities. These are the session keys.
pub fn authorities() -> Vec<SessionKey> {
AuthorityStorageVec::items()
}
pub mod internal {
use super::*;
/// Set the current set of authorities' session keys.
///
/// Called by `next_session` only.
pub fn set_authorities<'a, I: IntoIterator<Item=&'a SessionKey>>(authorities: I) {
AuthorityStorageVec::set_items(authorities);
}
/// Set a single authority by index.
pub fn set_authority(index: u32, key: &SessionKey) {
AuthorityStorageVec::set_item(index, key);
}
}
-371
View File
@@ -1,371 +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/>.
//! Governance system: Handles administration and dispatch of sensitive operations including
//! setting new code, minting new tokens and changing parameters.
//!
//! For now this is limited to a simple qualified majority vote (whose parameter is retrieved from
//! storage) between validators. A single vote may be proposed per era, and at most one approval
//! vote may be cast by each validator. The tally is maintained through a simple tag in storage for
//! each validator that has approved.
//!
//! At the end of the era, all validators approvals are tallied and if there are sufficient to pass
//! the proposal then it is enacted. All items in storage concerning the proposal are reset.
use rstd::prelude::*;
use codec::KeyedVec;
use runtime_support::storage;
use polkadot_primitives::{Proposal, AccountId, Hash, BlockNumber};
use runtime::{staking, system, session};
const APPROVALS_REQUIRED: &[u8] = b"gov:apr";
const CURRENT_PROPOSAL: &[u8] = b"gov:pro";
const APPROVAL_OF: &[u8] = b"gov:app:";
/// The proportion of validators required for a propsal to be approved measured as the number out
/// of 1000.
pub fn approval_ppm_required() -> u32 {
storage::get_or(APPROVALS_REQUIRED, 1000)
}
/// The number of concrete validator approvals required for a proposal to pass.
pub fn approvals_required() -> u32 {
approval_ppm_required() * session::validator_count() / 1000
}
pub mod public {
use super::*;
/// Propose a sensitive action to be taken. Any action that is enactable by `Proposal` is valid.
/// Proposal is by the `transactor` and will automatically count as an approval. Transactor must
/// be a current validator. It is illegal to propose when there is already a proposal in effect.
pub fn propose(validator: &AccountId, proposal: &Proposal) {
if storage::exists(CURRENT_PROPOSAL) {
panic!("there may only be one proposal per era.");
}
storage::put(CURRENT_PROPOSAL, proposal);
approve(validator, staking::current_era());
}
/// Approve the current era's proposal. Transactor must be a validator. This may not be done more
/// than once for any validator in an era.
pub fn approve(validator: &AccountId, era_index: BlockNumber) {
if era_index != staking::current_era() {
panic!("approval vote applied on non-current era.")
}
if !storage::exists(CURRENT_PROPOSAL) {
panic!("there must be a proposal in order to approve.");
}
if session::validators().into_iter().position(|v| &v == validator).is_none() {
panic!("transactor must be a validator to approve.");
}
let key = validator.to_keyed_vec(APPROVAL_OF);
if storage::exists(&key) {
panic!("transactor may not approve a proposal twice in one era.");
}
storage::put(&key, &true);
}
}
pub mod privileged {
use super::*;
/// Set the proportion of validators that must approve for a proposal to be enacted at the end of
/// its era. The value, `ppm`, is measured as a fraction of 1000 rounded down to the nearest whole
/// validator. `1000` would require the approval of all validators; `667` would require two-thirds
/// (or there abouts) of validators.
pub fn set_approval_ppm_required(ppm: u32) {
storage::put(APPROVALS_REQUIRED, &ppm);
}
}
pub mod internal {
use super::*;
use polkadot_primitives::Proposal;
/// Current era is ending; we should finish up any proposals.
pub fn end_of_an_era() {
// tally up votes for the current proposal, if any. enact if there are sufficient approvals.
if let Some(proposal) = storage::take::<Proposal>(CURRENT_PROPOSAL) {
let approvals_required = approvals_required();
let approved = session::validators().into_iter()
.filter_map(|v| storage::take::<bool>(&v.to_keyed_vec(APPROVAL_OF)))
.take(approvals_required as usize)
.count() as u32;
if approved == approvals_required {
enact_proposal(proposal);
}
}
}
fn enact_proposal(proposal: Proposal) {
match proposal {
Proposal::SystemSetCode(code) => {
system::privileged::set_code(&code);
}
Proposal::SessionSetLength(value) => {
session::privileged::set_length(value);
}
Proposal::SessionForceNewSession => {
session::privileged::force_new_session();
}
Proposal::StakingSetSessionsPerEra(value) => {
staking::privileged::set_sessions_per_era(value);
}
Proposal::StakingSetBondingDuration(value) => {
staking::privileged::set_bonding_duration(value);
}
Proposal::StakingSetValidatorCount(value) => {
staking::privileged::set_validator_count(value);
}
Proposal::StakingForceNewEra => {
staking::privileged::force_new_era()
}
Proposal::GovernanceSetApprovalPpmRequired(value) => {
self::privileged::set_approval_ppm_required(value);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use runtime_io::{with_externalities, twox_128, TestExternalities};
use codec::{KeyedVec, Joiner};
use keyring::Keyring;
use environment::with_env;
use polkadot_primitives::{AccountId, Proposal};
use runtime::{staking, session};
fn new_test_ext() -> TestExternalities {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let three = [3u8; 32];
map![
twox_128(APPROVALS_REQUIRED).to_vec() => vec![].and(&667u32),
twox_128(b"ses:len").to_vec() => vec![].and(&1u64),
twox_128(b"ses:val:len").to_vec() => vec![].and(&3u32),
twox_128(&0u32.to_keyed_vec(b"ses:val:")).to_vec() => one.to_vec(),
twox_128(&1u32.to_keyed_vec(b"ses:val:")).to_vec() => two.to_vec(),
twox_128(&2u32.to_keyed_vec(b"ses:val:")).to_vec() => three.to_vec(),
twox_128(b"sta:wil:len").to_vec() => vec![].and(&3u32),
twox_128(&0u32.to_keyed_vec(b"sta:wil:")).to_vec() => one.to_vec(),
twox_128(&1u32.to_keyed_vec(b"sta:wil:")).to_vec() => two.to_vec(),
twox_128(&2u32.to_keyed_vec(b"sta:wil:")).to_vec() => three.to_vec(),
twox_128(b"sta:spe").to_vec() => vec![].and(&1u64),
twox_128(b"sta:vac").to_vec() => vec![].and(&3u64),
twox_128(b"sta:era").to_vec() => vec![].and(&1u64)
]
}
#[test]
fn majority_voting_should_work() {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let three = [3u8; 32];
let mut t = new_test_ext();
with_externalities(&mut t, || {
assert_eq!(staking::era_length(), 1u64);
assert_eq!(staking::current_era(), 1u64);
assert_eq!(session::validator_count(), 3u32);
assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());
// Block 1: Make proposal. Approve it. Era length changes.
system::testing::set_block_number(1);
public::propose(&one, &Proposal::StakingSetSessionsPerEra(2));
public::approve(&two, 1);
staking::internal::check_new_era();
assert_eq!(staking::era_length(), 2);
});
}
#[test]
fn majority_voting_should_work_after_unsuccessful_previous() {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let three = [3u8; 32];
let mut t = new_test_ext();
with_externalities(&mut t, || {
assert_eq!(staking::era_length(), 1u64);
assert_eq!(staking::current_era(), 1u64);
assert_eq!(session::validator_count(), 3u32);
assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());
// Block 1: Make proposal. Fail it.
system::testing::set_block_number(1);
public::propose(&one, &Proposal::StakingSetSessionsPerEra(2));
staking::internal::check_new_era();
assert_eq!(staking::era_length(), 1);
// Block 2: Make proposal. Approve it. It should change era length.
system::testing::set_block_number(2);
public::propose(&one, &Proposal::StakingSetSessionsPerEra(2));
public::approve(&two, 2);
staking::internal::check_new_era();
assert_eq!(staking::era_length(), 2);
});
}
#[test]
fn minority_voting_should_not_succeed() {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let three = [3u8; 32];
let mut t = new_test_ext();
with_externalities(&mut t, || {
assert_eq!(staking::era_length(), 1u64);
assert_eq!(staking::current_era(), 1u64);
assert_eq!(session::validator_count(), 3u32);
assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());
// Block 1: Make proposal. Will have only 1 vote. No change.
system::testing::set_block_number(1);
public::propose(&one, &Proposal::StakingSetSessionsPerEra(2));
staking::internal::check_new_era();
assert_eq!(staking::era_length(), 1);
});
}
#[test]
#[should_panic]
fn old_voting_should_be_illegal() {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let three = [3u8; 32];
let mut t = new_test_ext();
with_externalities(&mut t, || {
assert_eq!(staking::era_length(), 1u64);
assert_eq!(staking::current_era(), 1u64);
assert_eq!(session::validator_count(), 3u32);
assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());
// Block 1: Make proposal. Will have only 1 vote. No change.
system::testing::set_block_number(1);
public::propose(&one, &Proposal::StakingSetSessionsPerEra(2));
public::approve(&two, 0);
staking::internal::check_new_era();
assert_eq!(staking::era_length(), 1);
});
}
#[test]
#[should_panic]
fn double_voting_should_be_illegal() {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let three = [3u8; 32];
let mut t = new_test_ext();
with_externalities(&mut t, || {
assert_eq!(staking::era_length(), 1u64);
assert_eq!(staking::current_era(), 1u64);
assert_eq!(session::validator_count(), 3u32);
assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());
// Block 1: Make proposal. Will have only 1 vote. No change.
system::testing::set_block_number(1);
public::propose(&one, &Proposal::StakingSetSessionsPerEra(2));
public::approve(&two, 1);
public::approve(&two, 1);
staking::internal::check_new_era();
assert_eq!(staking::era_length(), 1);
});
}
#[test]
#[should_panic]
fn over_proposing_should_be_illegal() {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let three = [3u8; 32];
let mut t = new_test_ext();
with_externalities(&mut t, || {
assert_eq!(staking::era_length(), 1u64);
assert_eq!(staking::current_era(), 1u64);
assert_eq!(session::validator_count(), 3u32);
assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());
// Block 1: Make proposal. Will have only 1 vote. No change.
system::testing::set_block_number(1);
public::propose(&one, &Proposal::StakingSetSessionsPerEra(2));
public::propose(&two, &Proposal::StakingSetSessionsPerEra(2));
staking::internal::check_new_era();
assert_eq!(staking::era_length(), 1);
});
}
#[test]
#[should_panic]
fn approving_without_proposal_should_be_illegal() {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let three = [3u8; 32];
let mut t = new_test_ext();
with_externalities(&mut t, || {
assert_eq!(staking::era_length(), 1u64);
assert_eq!(staking::current_era(), 1u64);
assert_eq!(session::validator_count(), 3u32);
assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());
// Block 1: Make proposal. Will have only 1 vote. No change.
system::testing::set_block_number(1);
public::approve(&two, 1);
staking::internal::check_new_era();
assert_eq!(staking::era_length(), 1);
});
}
#[test]
#[should_panic]
fn non_validator_approving_should_be_illegal() {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let three = [3u8; 32];
let four = [4u8; 32];
let mut t = new_test_ext();
with_externalities(&mut t, || {
assert_eq!(staking::era_length(), 1u64);
assert_eq!(staking::current_era(), 1u64);
assert_eq!(session::validator_count(), 3u32);
assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());
// Block 1: Make proposal. Will have only 1 vote. No change.
system::testing::set_block_number(1);
public::propose(&one, &Proposal::StakingSetSessionsPerEra(2));
public::approve(&four, 1);
staking::internal::check_new_era();
assert_eq!(staking::era_length(), 1);
});
}
}
-34
View File
@@ -1,34 +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/>.
//! The Polkadot runtime.
#[allow(unused)]
pub mod system;
#[allow(unused)]
pub mod consensus;
#[allow(unused)]
pub mod staking;
#[allow(unused)]
pub mod timestamp;
#[allow(unused)]
pub mod session;
#[allow(unused)]
pub mod governance;
#[allow(unused)]
pub mod parachains;
// TODO: polkadao
-123
View File
@@ -1,123 +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/>.
//! Main parachains logic. For now this is just the determination of which validators do what.
use rstd::prelude::*;
use codec::{Slicable, Joiner};
use runtime_support::{Hashable, storage};
use environment::with_env;
use runtime::session;
use polkadot_primitives::parachain::{Id, Chain, DutyRoster};
const PARACHAIN_COUNT: &[u8] = b"par:cou";
/// Get the number of parachains registered at present.
pub fn parachain_count() -> u32 {
storage::get_or(PARACHAIN_COUNT, 0)
}
/// Calculate the current block's duty roster.
pub fn calculate_duty_roster() -> DutyRoster {
let parachain_count = parachain_count();
let validator_count = session::validator_count() as u32;
let validators_per_parachain = (validator_count - 1) / parachain_count;
let mut roles_val = (0..validator_count).map(|i| match i {
i if i < parachain_count * validators_per_parachain =>
Chain::Parachain(Id::from(i / validators_per_parachain as u32)),
_ => Chain::Relay,
}).collect::<Vec<_>>();
let mut roles_gua = roles_val.clone();
let h = with_env(|e| e.parent_hash.clone());
let mut seed = Vec::<u8>::new().and(&h).and(b"validator_role_pairs").blake2_256();
// shuffle
for i in 0..(validator_count - 1) {
// 8 bytes of entropy used per cycle, 32 bytes entropy per hash
let offset = (i * 8 % 32) as usize;
// number of roles remaining to select from.
let remaining = (validator_count - i) as usize;
// 4 * 2 32-bit ints per 256-bit seed.
let val_index = u32::decode(&mut &seed[offset..offset + 4]).expect("using 4 bytes for a 32-bit quantity") as usize % remaining;
let gua_index = u32::decode(&mut &seed[offset + 4..offset + 8]).expect("using 4 bytes for a 32-bit quantity") as usize % remaining;
if offset == 24 {
// into the last 8 bytes - rehash to gather new entropy
seed = seed.blake2_256();
}
// exchange last item with randomly chosen first.
roles_val.swap(remaining - 1, val_index);
roles_gua.swap(remaining - 1, gua_index);
}
DutyRoster {
validator_duty: roles_val,
guarantor_duty: roles_gua,
}
}
#[cfg(test)]
mod tests {
use super::*;
use runtime_io::{with_externalities, twox_128, TestExternalities};
use codec::{KeyedVec, Joiner};
use keyring::Keyring;
use runtime::{consensus, session};
fn simple_setup() -> TestExternalities {
map![
twox_128(b"ses:val:len").to_vec() => vec![].and(&8u32),
twox_128(b"par:cou").to_vec() => vec![].and(&2u32)
]
}
#[test]
fn should_work() {
let mut t = simple_setup();
with_externalities(&mut t, || {
let check_roster = |duty_roster: &DutyRoster| {
assert_eq!(duty_roster.validator_duty.len(), 8);
assert_eq!(duty_roster.guarantor_duty.len(), 8);
for i in (0..2).map(Id::from) {
assert_eq!(duty_roster.validator_duty.iter().filter(|&&j| j == Chain::Parachain(i)).count(), 3);
assert_eq!(duty_roster.guarantor_duty.iter().filter(|&&j| j == Chain::Parachain(i)).count(), 3);
}
assert_eq!(duty_roster.validator_duty.iter().filter(|&&j| j == Chain::Relay).count(), 2);
assert_eq!(duty_roster.guarantor_duty.iter().filter(|&&j| j == Chain::Relay).count(), 2);
};
with_env(|e| e.parent_hash = [0u8; 32].into());
let duty_roster_0 = calculate_duty_roster();
check_roster(&duty_roster_0);
with_env(|e| e.parent_hash = [1u8; 32].into());
let duty_roster_1 = calculate_duty_roster();
check_roster(&duty_roster_1);
assert!(duty_roster_0 != duty_roster_1);
with_env(|e| e.parent_hash = [2u8; 32].into());
let duty_roster_2 = calculate_duty_roster();
check_roster(&duty_roster_2);
assert!(duty_roster_0 != duty_roster_2);
assert!(duty_roster_1 != duty_roster_2);
});
}
}
-294
View File
@@ -1,294 +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/>.
//! Session manager: is told the validators and allows them to manage their session keys for the
//! consensus module.
use rstd::prelude::*;
use codec::KeyedVec;
use runtime_support::{storage, StorageVec};
use polkadot_primitives::{AccountId, SessionKey, BlockNumber};
use runtime::{system, staking, consensus};
const SESSION_LENGTH: &[u8] = b"ses:len";
const CURRENT_INDEX: &[u8] = b"ses:ind";
const CURRENT_SESSION_START: &[u8] = b"ses:sta";
const LAST_SESSION_START: &[u8] = b"ses:lst";
const LAST_LENGTH_CHANGE: &[u8] = b"ses:llc";
const NEXT_KEY_FOR: &[u8] = b"ses:nxt:";
const NEXT_SESSION_LENGTH: &[u8] = b"ses:nln";
struct ValidatorStorageVec;
impl StorageVec for ValidatorStorageVec {
type Item = AccountId;
const PREFIX: &'static [u8] = b"ses:val:";
}
// the session keys before the previous.
struct LastValidators;
impl StorageVec for LastValidators {
type Item = (AccountId, SessionKey);
const PREFIX: &'static [u8] = b"ses:old:";
}
/// Get the current set of validators.
pub fn validators() -> Vec<AccountId> {
ValidatorStorageVec::items()
}
/// The number of blocks in each session.
pub fn length() -> BlockNumber {
storage::get_or(SESSION_LENGTH, 0)
}
/// The number of validators currently.
pub fn validator_count() -> u32 {
ValidatorStorageVec::count() as u32
}
/// The current session index.
pub fn current_index() -> BlockNumber {
storage::get_or(CURRENT_INDEX, 0)
}
/// Get the starting block of the current session.
pub fn current_start_block() -> BlockNumber {
// this seems like it's computable just by examining the current block number, session length,
// and last length change, but it's not simple to tell whether we are before or after
// a session rotation on a block which will have one.
storage::get_or(CURRENT_SESSION_START, 0)
}
/// Get the last session's validators, paired with their authority keys.
pub fn last_session_keys() -> Vec<(AccountId, SessionKey)> {
LastValidators::items()
}
/// Get the start block of the last session.
/// In general this is computable from the session length,
/// but when the current session is the first with a new length it is uncomputable.
pub fn last_session_start() -> Option<BlockNumber> {
storage::get(LAST_SESSION_START)
}
/// The block number at which the era length last changed.
pub fn last_length_change() -> BlockNumber {
storage::get_or(LAST_LENGTH_CHANGE, 0)
}
pub mod public {
use super::*;
/// Sets the session key of `_validator` to `_key`. This doesn't take effect until the next
/// session.
pub fn set_key(validator: &AccountId, key: &SessionKey) {
// set new value for next session
storage::put(&validator.to_keyed_vec(NEXT_KEY_FOR), key);
}
}
pub mod privileged {
use super::*;
/// Set a new era length. Won't kick in until the next era change (at current length).
pub fn set_length(new: BlockNumber) {
storage::put(NEXT_SESSION_LENGTH, &new);
}
/// Forces a new session.
pub fn force_new_session() {
rotate_session();
}
}
// INTERNAL API (available to other runtime modules)
pub mod internal {
use super::*;
/// Transition to a new era, with a new set of valiators.
///
/// Called by staking::next_era() only. `next_session` should be called after this in order to
/// update the session keys to the next validator set.
pub fn set_validators(new: &[AccountId]) {
LastValidators::set_items(
new.iter().cloned().zip(consensus::authorities())
);
ValidatorStorageVec::set_items(new);
consensus::internal::set_authorities(new);
}
/// Hook to be called after transaction processing.
pub fn check_rotate_session() {
// do this last, after the staking system has had chance to switch out the authorities for the
// new set.
// check block number and call next_session if necessary.
if (system::block_number() - last_length_change()) % length() == 0 {
rotate_session();
}
}
}
/// Move onto next session: register the new authority set.
fn rotate_session() {
// Increment current session index.
storage::put(CURRENT_INDEX, &(current_index() + 1));
// Enact era length change.
if let Some(next_len) = storage::get::<u64>(NEXT_SESSION_LENGTH) {
storage::put(SESSION_LENGTH, &next_len);
storage::put(LAST_LENGTH_CHANGE, &system::block_number());
storage::kill(NEXT_SESSION_LENGTH);
}
let validators = validators();
storage::put(LAST_SESSION_START, &current_start_block());
storage::put(CURRENT_SESSION_START, &system::block_number());
LastValidators::set_items(
validators.iter()
.cloned()
.zip(consensus::authorities())
);
// Update any changes in session keys.
validators.iter().enumerate().for_each(|(i, v)| {
let k = v.to_keyed_vec(NEXT_KEY_FOR);
if let Some(n) = storage::take(&k) {
// this is fine because the authorities vector currently
// matches the validators length perfectly.
consensus::internal::set_authority(i as u32, &n);
}
});
}
#[cfg(test)]
mod tests {
use super::*;
use super::public::*;
use super::privileged::*;
use super::internal::*;
use runtime_io::{with_externalities, twox_128, TestExternalities};
use codec::{KeyedVec, Joiner};
use keyring::Keyring;
use environment::with_env;
use polkadot_primitives::AccountId;
use runtime::{consensus, session};
fn simple_setup() -> TestExternalities {
map![
twox_128(SESSION_LENGTH).to_vec() => vec![].and(&2u64),
// the validators (10, 20, ...)
twox_128(b"ses:val:len").to_vec() => vec![].and(&2u32),
twox_128(&0u32.to_keyed_vec(ValidatorStorageVec::PREFIX)).to_vec() => vec![10; 32],
twox_128(&1u32.to_keyed_vec(ValidatorStorageVec::PREFIX)).to_vec() => vec![20; 32],
// initial session keys (11, 21, ...)
b":auth:len".to_vec() => vec![].and(&2u32),
0u32.to_keyed_vec(b":auth:") => vec![11; 32],
1u32.to_keyed_vec(b":auth:") => vec![21; 32]
]
}
#[test]
fn simple_setup_should_work() {
let mut t = simple_setup();
with_externalities(&mut t, || {
assert_eq!(consensus::authorities(), vec![[11u8; 32], [21u8; 32]]);
assert_eq!(length(), 2u64);
assert_eq!(validators(), vec![[10u8; 32], [20u8; 32]]);
});
}
#[test]
fn session_length_change_should_work() {
let mut t = simple_setup();
with_externalities(&mut t, || {
// Block 1: Change to length 3; no visible change.
system::testing::set_block_number(1);
set_length(3);
check_rotate_session();
assert_eq!(length(), 2);
assert_eq!(current_index(), 0);
// Block 2: Length now changed to 3. Index incremented.
system::testing::set_block_number(2);
set_length(3);
check_rotate_session();
assert_eq!(length(), 3);
assert_eq!(current_index(), 1);
// Block 3: Length now changed to 3. Index incremented.
system::testing::set_block_number(3);
check_rotate_session();
assert_eq!(length(), 3);
assert_eq!(current_index(), 1);
// Block 4: Change to length 2; no visible change.
system::testing::set_block_number(4);
set_length(2);
check_rotate_session();
assert_eq!(length(), 3);
assert_eq!(current_index(), 1);
// Block 5: Length now changed to 2. Index incremented.
system::testing::set_block_number(5);
check_rotate_session();
assert_eq!(length(), 2);
assert_eq!(current_index(), 2);
// Block 6: No change.
system::testing::set_block_number(6);
check_rotate_session();
assert_eq!(length(), 2);
assert_eq!(current_index(), 2);
// Block 7: Next index.
system::testing::set_block_number(7);
check_rotate_session();
assert_eq!(length(), 2);
assert_eq!(current_index(), 3);
});
}
#[test]
fn session_change_should_work() {
let mut t = simple_setup();
with_externalities(&mut t, || {
// Block 1: No change
system::testing::set_block_number(1);
check_rotate_session();
assert_eq!(consensus::authorities(), vec![[11u8; 32], [21u8; 32]]);
// Block 2: Session rollover, but no change.
system::testing::set_block_number(2);
check_rotate_session();
assert_eq!(consensus::authorities(), vec![[11u8; 32], [21u8; 32]]);
// Block 3: Set new key for validator 2; no visible change.
system::testing::set_block_number(3);
set_key(&[20; 32], &[22; 32]);
assert_eq!(consensus::authorities(), vec![[11u8; 32], [21u8; 32]]);
check_rotate_session();
assert_eq!(consensus::authorities(), vec![[11u8; 32], [21u8; 32]]);
// Block 4: Session rollover, authority 2 changes.
system::testing::set_block_number(4);
check_rotate_session();
assert_eq!(consensus::authorities(), vec![[11u8; 32], [22u8; 32]]);
});
}
}
-496
View File
@@ -1,496 +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/>.
//! Staking manager: Handles balances and periodically determines the best set of validators.
use rstd::prelude::*;
use rstd::cell::RefCell;
use runtime_io::print;
use codec::KeyedVec;
use runtime_support::{storage, StorageVec};
use polkadot_primitives::{BlockNumber, AccountId};
use primitives::bft::{MisbehaviorReport, MisbehaviorKind};
use runtime::{system, session, governance, consensus};
type Balance = u64;
type Bondage = u64;
struct IntentionStorageVec {}
impl StorageVec for IntentionStorageVec {
type Item = AccountId;
const PREFIX: &'static [u8] = b"sta:wil:";
}
const BONDING_DURATION: &[u8] = b"sta:loc";
const VALIDATOR_COUNT: &[u8] = b"sta:vac";
const SESSIONS_PER_ERA: &[u8] = b"sta:spe";
const NEXT_SESSIONS_PER_ERA: &[u8] = b"sta:nse";
const CURRENT_ERA: &[u8] = b"sta:era";
const LAST_ERA_LENGTH_CHANGE: &[u8] = b"sta:lec";
const TOTAL_STAKE: &[u8] = b"sta:tot";
const BALANCE_OF: &[u8] = b"sta:bal:";
const BONDAGE_OF: &[u8] = b"sta:bon:";
/// The length of the bonding duration in eras.
pub fn bonding_duration() -> BlockNumber {
storage::get_or_default(BONDING_DURATION)
}
/// The length of a staking era in sessions.
pub fn validator_count() -> usize {
storage::get_or_default::<u32>(VALIDATOR_COUNT) as usize
}
/// The length of a staking era in blocks.
pub fn era_length() -> BlockNumber {
sessions_per_era() * session::length()
}
/// The length of a staking era in sessions.
pub fn sessions_per_era() -> BlockNumber {
storage::get_or_default(SESSIONS_PER_ERA)
}
/// The current era index.
pub fn current_era() -> BlockNumber {
storage::get_or_default(CURRENT_ERA)
}
/// The block number at which the era length last changed.
pub fn last_era_length_change() -> BlockNumber {
storage::get_or_default(LAST_ERA_LENGTH_CHANGE)
}
/// The balance of a given account.
pub fn balance(who: &AccountId) -> Balance {
storage::get_or_default(&who.to_keyed_vec(BALANCE_OF))
}
/// Gives the index of the era where the account's balance will no longer
/// be bonded.
pub fn bondage(who: &AccountId) -> Bondage {
storage::get_or_default(&who.to_keyed_vec(BONDAGE_OF))
}
fn set_balance(who: &AccountId, amount: Balance) {
storage::put(&who.to_keyed_vec(BALANCE_OF), &amount)
}
// Each identity's stake may be in one of three bondage states, given by an integer:
// - n | n <= current_era(): inactive: free to be transferred.
// - ~0: active: currently representing a validator.
// - n | n > current_era(): deactivating: recently representing a validator and not yet
// ready for transfer.
pub mod public {
use super::*;
/// Transfer some unlocked staking balance to another staker.
pub fn transfer(transactor: &AccountId, dest: &AccountId, value: Balance) {
let from_key = transactor.to_keyed_vec(BALANCE_OF);
let from_balance = storage::get_or_default::<Balance>(&from_key);
assert!(from_balance >= value);
let to_key = dest.to_keyed_vec(BALANCE_OF);
let to_balance: Balance = storage::get_or_default(&to_key);
assert!(bondage(transactor) <= bondage(dest));
assert!(to_balance + value > to_balance); // no overflow
storage::put(&from_key, &(from_balance - value));
storage::put(&to_key, &(to_balance + value));
}
/// Declare the desire to stake for the transactor.
///
/// Effects will be felt at the beginning of the next era.
pub fn stake(transactor: &AccountId) {
let mut intentions = IntentionStorageVec::items();
// can't be in the list twice.
assert!(intentions.iter().find(|t| t == &transactor).is_none(), "Cannot stake if already staked.");
intentions.push(transactor.clone());
IntentionStorageVec::set_items(&intentions);
storage::put(&transactor.to_keyed_vec(BONDAGE_OF), &u64::max_value());
}
/// Retract the desire to stake for the transactor.
///
/// Effects will be felt at the beginning of the next era.
pub fn unstake(transactor: &AccountId) {
let mut intentions = IntentionStorageVec::items();
if let Some(position) = intentions.iter().position(|t| t == transactor) {
intentions.swap_remove(position);
} else {
panic!("Cannot unstake if not already staked.");
}
IntentionStorageVec::set_items(&intentions);
storage::put(&transactor.to_keyed_vec(BONDAGE_OF), &(current_era() + bonding_duration()));
}
/// Report misbehavior. Only validators may do this, signing under
/// the authority key of the session the report corresponds to.
///
/// Reports older than one session in the past will be ignored.
pub fn report_misbehavior(transactor: &AccountId, report: &MisbehaviorReport) {
let (validators, authorities) = if report.parent_number < session::last_session_start().unwrap_or(0) {
panic!("report is too old");
} else if report.parent_number < session::current_start_block() {
session::last_session_keys().into_iter().unzip()
} else {
(session::validators(), consensus::authorities())
};
if report.parent_hash != system::block_hash(report.parent_number) {
// report out of chain.
panic!("report not from this blockchain");
}
let reporting_validator = match authorities.iter().position(|x| x == transactor) {
None => panic!("only validators may report"),
Some(pos) => validators.get(pos).expect("validators and authorities have same cardinality; qed"),
};
// any invalidity beyond this point is actually its own misbehavior.
let target = match authorities.iter().position(|x| x == &report.target) {
None => {
slash(reporting_validator, None);
return;
}
Some(pos) => validators.get(pos).expect("validators and authorities have same cardinality; qed"),
};
let misbehaved = ::misbehavior_check::evaluate_misbehavior(&report.target, report.parent_hash, &report.misbehavior);
if misbehaved {
slash(target, Some(reporting_validator))
} else {
slash(reporting_validator, None);
}
}
}
pub mod privileged {
use super::*;
/// Set the number of sessions in an era.
pub fn set_sessions_per_era(new: BlockNumber) {
storage::put(NEXT_SESSIONS_PER_ERA, &new);
}
/// The length of the bonding duration in eras.
pub fn set_bonding_duration(new: BlockNumber) {
storage::put(BONDING_DURATION, &new);
}
/// The length of a staking era in sessions.
pub fn set_validator_count(new: u32) {
storage::put(VALIDATOR_COUNT, &new);
}
/// Force there to be a new era. This also forces a new session immediately after.
pub fn force_new_era() {
new_era();
session::privileged::force_new_session();
}
}
pub mod internal {
use super::*;
/// Hook to be called after to transaction processing.
pub fn check_new_era() {
// check block number and call new_era if necessary.
if (system::block_number() - last_era_length_change()) % era_length() == 0 {
new_era();
}
}
}
/// Slash a validator, with an optional benefactor.
fn slash(who: &AccountId, benefactor: Option<&AccountId>) {
// the reciprocal of the proportion of the amount slashed to give
// to the benefactor.
const SLASH_REWARD_DENOMINATOR: Balance = 10;
let slashed = balance(who);
set_balance(who, 0);
if let Some(benefactor) = benefactor {
let reward = slashed / SLASH_REWARD_DENOMINATOR;
let prior = balance(benefactor);
set_balance(benefactor, prior + reward);
}
}
/// The era has changed - enact new staking set.
///
/// NOTE: This always happens immediately before a session change to ensure that new validators
/// get a chance to set their session keys.
fn new_era() {
// Inform governance module that it's the end of an era
governance::internal::end_of_an_era();
// Increment current era.
storage::put(CURRENT_ERA, &(current_era() + 1));
// Enact era length change.
let next_spe: u64 = storage::get_or_default(NEXT_SESSIONS_PER_ERA);
if next_spe > 0 && next_spe != sessions_per_era() {
storage::put(SESSIONS_PER_ERA, &next_spe);
storage::put(LAST_ERA_LENGTH_CHANGE, &system::block_number());
}
// evaluate desired staking amounts and nominations and optimise to find the best
// combination of validators, then use session::internal::set_validators().
// for now, this just orders would-be stakers by their balances and chooses the top-most
// validator_count() of them.
let mut intentions = IntentionStorageVec::items()
.into_iter()
.map(|v| (balance(&v), v))
.collect::<Vec<_>>();
intentions.sort_unstable_by(|&(b1, _), &(b2, _)| b2.cmp(&b1));
session::internal::set_validators(
&intentions.into_iter()
.map(|(_, v)| v)
.take(validator_count())
.collect::<Vec<_>>()
);
}
#[cfg(test)]
mod tests {
use super::*;
use super::internal::*;
use super::public::*;
use super::privileged::*;
use runtime_io::{with_externalities, twox_128, TestExternalities};
use codec::{KeyedVec, Joiner};
use keyring::Keyring;
use environment::with_env;
use polkadot_primitives::AccountId;
use runtime::{staking, session};
#[test]
fn staking_should_work() {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let three = [3u8; 32];
let four = [4u8; 32];
let mut t: TestExternalities = map![
twox_128(b"ses:len").to_vec() => vec![].and(&1u64),
twox_128(b"ses:val:len").to_vec() => vec![].and(&2u32),
twox_128(&0u32.to_keyed_vec(b"ses:val:")).to_vec() => vec![10; 32],
twox_128(&1u32.to_keyed_vec(b"ses:val:")).to_vec() => vec![20; 32],
twox_128(SESSIONS_PER_ERA).to_vec() => vec![].and(&2u64),
twox_128(VALIDATOR_COUNT).to_vec() => vec![].and(&2u32),
twox_128(BONDING_DURATION).to_vec() => vec![].and(&3u64),
twox_128(TOTAL_STAKE).to_vec() => vec![].and(&100u64),
twox_128(&one.to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&10u64),
twox_128(&two.to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&20u64),
twox_128(&three.to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&30u64),
twox_128(&four.to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&40u64)
];
with_externalities(&mut t, || {
assert_eq!(era_length(), 2u64);
assert_eq!(validator_count(), 2usize);
assert_eq!(bonding_duration(), 3u64);
assert_eq!(session::validators(), vec![[10u8; 32], [20u8; 32]]);
// Block 1: Add three validators. No obvious change.
system::testing::set_block_number(1);
stake(&one);
stake(&two);
stake(&four);
check_new_era();
assert_eq!(session::validators(), vec![[10u8; 32], [20u8; 32]]);
// Block 2: New validator set now.
system::testing::set_block_number(2);
check_new_era();
assert_eq!(session::validators(), vec![four.clone(), two.clone()]);
// Block 3: Unstake highest, introduce another staker. No change yet.
system::testing::set_block_number(3);
stake(&three);
unstake(&four);
check_new_era();
// Block 4: New era - validators change.
system::testing::set_block_number(4);
check_new_era();
assert_eq!(session::validators(), vec![three.clone(), two.clone()]);
// Block 5: Transfer stake from highest to lowest. No change yet.
system::testing::set_block_number(5);
transfer(&four, &one, 40);
check_new_era();
// Block 6: Lowest now validator.
system::testing::set_block_number(6);
check_new_era();
assert_eq!(session::validators(), vec![one.clone(), three.clone()]);
// Block 7: Unstake three. No change yet.
system::testing::set_block_number(7);
unstake(&three);
check_new_era();
assert_eq!(session::validators(), vec![one.clone(), three.clone()]);
// Block 8: Back to one and two.
system::testing::set_block_number(8);
check_new_era();
assert_eq!(session::validators(), vec![one.clone(), two.clone()]);
});
}
#[test]
fn staking_eras_work() {
let mut t: TestExternalities = map![
twox_128(b"ses:len").to_vec() => vec![].and(&1u64),
twox_128(SESSIONS_PER_ERA).to_vec() => vec![].and(&2u64)
];
with_externalities(&mut t, || {
assert_eq!(era_length(), 2u64);
assert_eq!(sessions_per_era(), 2u64);
assert_eq!(last_era_length_change(), 0u64);
assert_eq!(current_era(), 0u64);
// Block 1: No change.
system::testing::set_block_number(1);
check_new_era();
assert_eq!(sessions_per_era(), 2u64);
assert_eq!(last_era_length_change(), 0u64);
assert_eq!(current_era(), 0u64);
// Block 2: Simple era change.
system::testing::set_block_number(2);
check_new_era();
assert_eq!(sessions_per_era(), 2u64);
assert_eq!(last_era_length_change(), 0u64);
assert_eq!(current_era(), 1u64);
// Block 3: Schedule an era length change; no visible changes.
system::testing::set_block_number(3);
set_sessions_per_era(3);
check_new_era();
assert_eq!(sessions_per_era(), 2u64);
assert_eq!(last_era_length_change(), 0u64);
assert_eq!(current_era(), 1u64);
// Block 4: Era change kicks in.
system::testing::set_block_number(4);
check_new_era();
assert_eq!(sessions_per_era(), 3u64);
assert_eq!(last_era_length_change(), 4u64);
assert_eq!(current_era(), 2u64);
// Block 5: No change.
system::testing::set_block_number(5);
check_new_era();
assert_eq!(sessions_per_era(), 3u64);
assert_eq!(last_era_length_change(), 4u64);
assert_eq!(current_era(), 2u64);
// Block 6: No change.
system::testing::set_block_number(6);
check_new_era();
assert_eq!(sessions_per_era(), 3u64);
assert_eq!(last_era_length_change(), 4u64);
assert_eq!(current_era(), 2u64);
// Block 7: Era increment.
system::testing::set_block_number(7);
check_new_era();
assert_eq!(sessions_per_era(), 3u64);
assert_eq!(last_era_length_change(), 4u64);
assert_eq!(current_era(), 3u64);
});
}
#[test]
fn staking_balance_works() {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let mut t: TestExternalities = map![
twox_128(&one.to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&42u64)
];
with_externalities(&mut t, || {
assert_eq!(balance(&one), 42);
assert_eq!(balance(&two), 0);
});
}
#[test]
fn staking_balance_transfer_works() {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let mut t: TestExternalities = map![
twox_128(&one.to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&111u64)
];
with_externalities(&mut t, || {
transfer(&one, &two, 69);
assert_eq!(balance(&one), 42);
assert_eq!(balance(&two), 69);
});
}
#[test]
#[should_panic]
fn staking_balance_transfer_when_bonded_doesnt_work() {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let mut t: TestExternalities = map![
twox_128(&one.to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&111u64)
];
with_externalities(&mut t, || {
stake(&one);
transfer(&one, &two, 69);
});
}
#[test]
#[should_panic]
fn misbehavior_report_by_non_validator_panics() {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let mut t: TestExternalities = map![
twox_128(&one.to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&111u64)
];
with_externalities(&mut t, || {
// the misbehavior report here is invalid, but that
// actually doesn't panic; instead it would slash the bad
// reporter.
report_misbehavior(&one, &MisbehaviorReport {
parent_hash: [0; 32].into(),
parent_number: 0,
target: two,
misbehavior: MisbehaviorKind::BftDoubleCommit(
2,
([1; 32].into(), [2; 64].into()),
([3; 32].into(), [4; 64].into()),
),
})
});
}
}
-450
View File
@@ -1,450 +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/>.
//! System manager: Handles all of the top-level stuff; executing block/transaction, setting code
//! and depositing logs.
use rstd::mem;
use rstd::prelude::*;
use codec::{KeyedVec, Slicable};
use environment::with_env;
use polkadot_primitives::{
AccountId, Hash, TxOrder, BlockNumber, Block, Header,
UncheckedTransaction, Function, InherentFunction, Log
};
use runtime_io::{print, storage_root, enumerated_trie_root};
use runtime_support::{Hashable, storage};
use runtime::{staking, session};
/// Prefixes account ID and stores u64 nonce.
pub const NONCE_OF: &[u8] = b"sys:non:";
/// Prefixes block number and stores hash of that block.
pub const BLOCK_HASH_AT: &[u8] = b"sys:old:";
/// Stores the temporary current transaction number.
pub const TEMP_TRANSACTION_NUMBER: &[u8] = b"temp:txcount";
/// The current block number being processed. Set by `execute_block`.
pub fn block_number() -> BlockNumber {
with_env(|e| e.block_number)
}
/// Get the block hash of a given block (uses storage).
pub fn block_hash(number: BlockNumber) -> Hash {
storage::get_or_default(&number.to_keyed_vec(BLOCK_HASH_AT))
}
pub mod privileged {
use super::*;
/// Set the new code.
pub fn set_code(new: &[u8]) {
storage::unhashed::put_raw(b":code", new);
}
}
pub mod internal {
use super::*;
/// Deposits a log and ensures it matches the blocks log data.
pub fn deposit_log(log: Log) {
with_env(|e| e.digest.logs.push(log));
}
/// Actually execute all transitioning for `block`.
pub fn execute_block(mut block: Block) {
// populate environment from header.
with_env(|e| {
e.block_number = block.header.number;
e.parent_hash = block.header.parent_hash;
});
// any initial checks
initial_checks(&block);
// execute all transactions, inherent or otherwise.
for (tx_num, tx) in block.all_transactions().enumerate() {
super::execute_transaction(tx, tx_num as u64);
}
// post-transactional book-keeping.
staking::internal::check_new_era();
session::internal::check_rotate_session();
// any final checks
final_checks(&block);
// any stuff that we do after taking the storage root.
post_finalise(&block.header);
}
/// Execute a transaction outside of the block execution function.
/// This doesn't attempt to validate anything regarding the block.
/// Note that when building a block transaction by transaction, the
/// inherent methods must be called manually.
pub fn execute_transaction(utx: UncheckedTransaction, mut header: Header) -> Header {
// populate environment from header.
with_env(|e| {
e.block_number = header.number;
e.parent_hash = header.parent_hash;
mem::swap(&mut header.digest, &mut e.digest);
});
let tx_num: u64 = storage::get_or_default(TEMP_TRANSACTION_NUMBER);
super::execute_transaction(utx, tx_num);
with_env(|e| {
mem::swap(&mut header.digest, &mut e.digest);
});
storage::put(TEMP_TRANSACTION_NUMBER, &(tx_num + 1));
header
}
/// Finalise the block - it is up the caller to ensure that all header fields are valid
/// except state-root.
pub fn finalise_block(mut header: Header) -> Header {
// populate environment from header.
with_env(|e| {
e.block_number = header.number;
e.parent_hash = header.parent_hash;
mem::swap(&mut header.digest, &mut e.digest);
});
let tx_count: u64 = storage::take_or_default(TEMP_TRANSACTION_NUMBER);
if tx_count < Function::inherent_functions() {
panic!("Not enough transactions provided to fulfill all inherent functions.");
}
staking::internal::check_new_era();
session::internal::check_rotate_session();
header.state_root = storage_root().into();
with_env(|e| {
mem::swap(&mut header.digest, &mut e.digest);
});
post_finalise(&header);
header
}
}
/// Get an account's current nonce.
pub fn nonce(account: AccountId) -> TxOrder {
let nonce_key = account.to_keyed_vec(NONCE_OF);
storage::get_or(&nonce_key, 0)
}
/// Dispatch a function.
fn dispatch_function(function: &Function, transactor: &AccountId) {
match *function {
Function::Inherent(InherentFunction::TimestampSet(t)) => {
::runtime::timestamp::public::set(t);
}
Function::StakingStake => {
::runtime::staking::public::stake(transactor);
}
Function::StakingUnstake => {
::runtime::staking::public::unstake(transactor);
}
Function::StakingTransfer(dest, value) => {
::runtime::staking::public::transfer(transactor, &dest, value);
}
Function::ReportMisbehavior(ref report) => {
::runtime::staking::public::report_misbehavior(transactor, report)
}
Function::SessionSetKey(session) => {
::runtime::session::public::set_key(transactor, &session);
}
Function::GovernancePropose(ref proposal) => {
::runtime::governance::public::propose(transactor, proposal);
}
Function::GovernanceApprove(era_index) => {
::runtime::governance::public::approve(transactor, era_index);
}
}
}
fn execute_transaction(utx: UncheckedTransaction, tx_num: u64) {
use ::transaction;
// Verify the transaction is authenticated at its position.
let tx = match transaction::check(utx, tx_num) {
Ok(tx) => tx,
Err(_) => panic!("Transaction at index {} not properly authenticated", tx_num),
};
// check nonce
let nonce_key = tx.signed.to_keyed_vec(NONCE_OF);
let (expected_nonce, increment_nonce) = if !tx.function.is_inherent() {
(storage::get_or(&nonce_key, 0), true)
} else {
(0, false)
};
assert!(tx.nonce == expected_nonce, "All transactions should have the correct nonce");
// increment nonce in storage, unless it's the EVERYBODY account.
if increment_nonce {
storage::put(&nonce_key, &(expected_nonce + 1));
}
// decode parameters and dispatch
dispatch_function(&tx.function, &tx.signed);
}
fn initial_checks(block: &Block) {
let ref header = block.header;
// check parent_hash is correct.
assert!(
header.number > 0 && block_hash(header.number - 1) == header.parent_hash,
"Parent hash should be valid."
);
// check transaction trie root represents the transactions.
let txs = block.all_transactions().map(|tx| Slicable::encode(&tx)).collect::<Vec<_>>();
let txs = txs.iter().map(Vec::as_slice).collect::<Vec<_>>();
let txs_root = enumerated_trie_root(&txs).into();
info_expect_equal_hash(&header.transaction_root, &txs_root);
assert!(header.transaction_root == txs_root, "Transaction trie root must be valid.");
}
fn final_checks(block: &Block) {
let ref header = block.header;
// check digest
with_env(|e| {
assert!(header.digest == e.digest);
});
// check storage root.
let storage_root = storage_root().into();
info_expect_equal_hash(&header.state_root, &storage_root);
assert!(header.state_root == storage_root, "Storage root must match that calculated.");
}
fn post_finalise(header: &Header) {
// store the header hash in storage; we can't do it before otherwise there would be a
// cyclic dependency.
storage::put(&header.number.to_keyed_vec(BLOCK_HASH_AT), &header.blake2_256());
}
#[cfg(feature = "std")]
fn info_expect_equal_hash(given: &Hash, expected: &Hash) {
use primitives::hexdisplay::HexDisplay;
if given != expected {
println!("Hash: given={}, expected={}", HexDisplay::from(&given.0), HexDisplay::from(&expected.0));
}
}
#[cfg(not(feature = "std"))]
fn info_expect_equal_hash(given: &Hash, expected: &Hash) {
if given != expected {
print("Hash not equal");
print(&given.0[..]);
print(&expected.0[..]);
}
}
#[cfg(any(feature = "std", test))]
pub mod testing {
use super::*;
pub fn set_block_number(n: BlockNumber) {
with_env(|e| e.block_number = n);
}
}
#[cfg(test)]
mod tests {
use super::*;
use super::internal::*;
use runtime_io::{with_externalities, twox_128, TestExternalities};
use codec::{Joiner, KeyedVec, Slicable};
use keyring::Keyring;
use environment::with_env;
use primitives::hexdisplay::HexDisplay;
use polkadot_primitives::{Header, Body, Digest, UncheckedTransaction, Transaction, Function, InherentFunction};
use runtime::staking;
fn set_timestamp() -> UncheckedTransaction {
UncheckedTransaction::inherent(InherentFunction::TimestampSet(100_000))
}
#[test]
#[should_panic]
fn fails_if_first_not_timestamp_set() {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let mut t: TestExternalities = map![
twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0]
];
let tx = UncheckedTransaction {
transaction: Transaction {
signed: one.clone(),
nonce: 0,
function: Function::StakingTransfer(two, 69),
},
signature: hex!("5f9832c5a4a39e2dd4a3a0c5b400e9836beb362cb8f7d845a8291a2ae6fe366612e080e4acd0b5a75c3d0b6ee69614a68fb63698c1e76bf1f2dcd8fa617ddf05").into(),
};
with_externalities(&mut t, || {
internal::execute_transaction(tx, Header::from_block_number(1));
});
}
#[test]
fn staking_balance_transfer_dispatch_works() {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let mut t: TestExternalities = map![
twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0]
];
let tx = UncheckedTransaction {
transaction: Transaction {
signed: one.clone(),
nonce: 0,
function: Function::StakingTransfer(two, 69),
},
signature: hex!("5f9832c5a4a39e2dd4a3a0c5b400e9836beb362cb8f7d845a8291a2ae6fe366612e080e4acd0b5a75c3d0b6ee69614a68fb63698c1e76bf1f2dcd8fa617ddf05").into(),
};
with_externalities(&mut t, || {
let header = Header::from_block_number(1);
let header = internal::execute_transaction(set_timestamp(), header);
internal::execute_transaction(tx, header);
assert_eq!(staking::balance(&one), 42);
assert_eq!(staking::balance(&two), 69);
});
}
fn new_test_ext() -> TestExternalities {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let three = [3u8; 32];
map![
twox_128(&0u64.to_keyed_vec(b"sys:old:")).to_vec() => [69u8; 32].encode(),
twox_128(b"gov:apr").to_vec() => vec![].and(&667u32),
twox_128(b"ses:len").to_vec() => vec![].and(&2u64),
twox_128(b"ses:val:len").to_vec() => vec![].and(&3u32),
twox_128(&0u32.to_keyed_vec(b"ses:val:")).to_vec() => one.to_vec(),
twox_128(&1u32.to_keyed_vec(b"ses:val:")).to_vec() => two.to_vec(),
twox_128(&2u32.to_keyed_vec(b"ses:val:")).to_vec() => three.to_vec(),
twox_128(b"sta:wil:len").to_vec() => vec![].and(&3u32),
twox_128(&0u32.to_keyed_vec(b"sta:wil:")).to_vec() => one.to_vec(),
twox_128(&1u32.to_keyed_vec(b"sta:wil:")).to_vec() => two.to_vec(),
twox_128(&2u32.to_keyed_vec(b"sta:wil:")).to_vec() => three.to_vec(),
twox_128(b"sta:spe").to_vec() => vec![].and(&2u64),
twox_128(b"sta:vac").to_vec() => vec![].and(&3u64),
twox_128(b"sta:era").to_vec() => vec![].and(&0u64),
twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0]
]
}
#[test]
fn block_import_works() {
let mut t = new_test_ext();
let h = Header {
parent_hash: [69u8; 32].into(),
number: 1,
state_root: hex!("aa4fbcdc09b21e4366aebccd9b9ec0831a8a2765c712d3397f121ff8e60e21e2").into(),
transaction_root: hex!("328ae80be3adf358d2a2e188cbe1bfd3f8cd5b15a2e7666e2b4eccf7450efc32").into(),
digest: Digest { logs: vec![], },
};
let b = Block {
header: h,
body: Body {
timestamp: 100_000,
transactions: vec![]
}
};
with_externalities(&mut t, || {
execute_block(b);
});
}
#[test]
#[should_panic]
fn block_import_of_bad_state_root_fails() {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let mut t = new_test_ext();
let h = Header {
parent_hash: [69u8; 32].into(),
number: 1,
state_root: [0u8; 32].into(),
transaction_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(),
digest: Digest { logs: vec![], },
};
let b = Block {
header: h,
body: Body {
timestamp: 100_000,
transactions: vec![],
}
};
with_externalities(&mut t, || {
execute_block(b);
});
}
#[test]
#[should_panic]
fn block_import_of_bad_transaction_root_fails() {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let mut t = new_test_ext();
let h = Header {
parent_hash: [69u8; 32].into(),
number: 1,
state_root: hex!("1ab2dbb7d4868a670b181327b0b6a58dc64b10cfb9876f737a5aa014b8da31e0").into(),
transaction_root: [0u8; 32].into(),
digest: Digest { logs: vec![], },
};
let b = Block {
header: h,
body: Body {
timestamp: 100_000,
transactions: vec![],
}
};
with_externalities(&mut t, || {
execute_block(b);
});
}
}
-63
View File
@@ -1,63 +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/>.
//! Timestamp manager: just handles the current timestamp.
use runtime_support::storage;
use polkadot_primitives::Timestamp;
const CURRENT_TIMESTAMP: &[u8] = b"tim:val";
/// Get the current time.
pub fn get() -> Timestamp {
storage::get_or_default(CURRENT_TIMESTAMP)
}
pub mod public {
use super::*;
/// Set the current time.
pub fn set(now: Timestamp) {
if super::get() > now {
panic!("last timestamp less than now");
}
storage::put(CURRENT_TIMESTAMP, &now);
}
}
#[cfg(test)]
mod tests {
use super::*;
use super::public::*;
use runtime_io::{with_externalities, twox_128, TestExternalities};
use runtime::timestamp;
use codec::{Joiner, KeyedVec};
#[test]
fn timestamp_works() {
let mut t: TestExternalities = map![
twox_128(CURRENT_TIMESTAMP).to_vec() => vec![].and(&42u64)
];
with_externalities(&mut t, || {
assert_eq!(get(), 42);
set(69);
assert_eq!(get(), 69);
});
}
}
+193 -5
View File
@@ -220,6 +220,16 @@ dependencies = [
"proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "integer-sqrt"
version = "0.1.0"
source = "git+https://github.com/paritytech/integer-sqrt-rs.git#f4cf61482096dc98c1273f46a10849d182b4c23c"
[[package]]
name = "integer-sqrt"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "isatty" name = "isatty"
version = "0.1.6" version = "0.1.6"
@@ -308,6 +318,11 @@ name = "nodrop"
version = "0.1.12" version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "num-traits"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "num_cpus" name = "num_cpus"
version = "1.8.0" version = "1.8.0"
@@ -383,6 +398,7 @@ dependencies = [
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"substrate-codec 0.1.0", "substrate-codec 0.1.0",
"substrate-primitives 0.1.0", "substrate-primitives 0.1.0",
"substrate-runtime-primitives 0.1.0",
"substrate-runtime-std 0.1.0", "substrate-runtime-std 0.1.0",
] ]
@@ -390,13 +406,23 @@ dependencies = [
name = "polkadot-runtime" 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)",
"polkadot-primitives 0.1.0", "polkadot-primitives 0.1.0",
"safe-mix 0.1.0",
"substrate-codec 0.1.0", "substrate-codec 0.1.0",
"substrate-misbehavior-check 0.1.0",
"substrate-primitives 0.1.0", "substrate-primitives 0.1.0",
"substrate-runtime-consensus 0.1.0",
"substrate-runtime-council 0.1.0",
"substrate-runtime-democracy 0.1.0",
"substrate-runtime-executive 0.1.0",
"substrate-runtime-io 0.1.0", "substrate-runtime-io 0.1.0",
"substrate-runtime-primitives 0.1.0",
"substrate-runtime-session 0.1.0",
"substrate-runtime-staking 0.1.0",
"substrate-runtime-std 0.1.0", "substrate-runtime-std 0.1.0",
"substrate-runtime-support 0.1.0", "substrate-runtime-support 0.1.0",
"substrate-runtime-system 0.1.0",
"substrate-runtime-timestamp 0.1.0",
] ]
[[package]] [[package]]
@@ -541,6 +567,13 @@ dependencies = [
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "safe-mix"
version = "0.1.0"
dependencies = [
"rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "0.3.3" version = "0.3.3"
@@ -601,12 +634,12 @@ dependencies = [
] ]
[[package]] [[package]]
name = "substrate-misbehavior-check" name = "substrate-keyring"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"substrate-codec 0.1.0", "ed25519 0.1.0",
"substrate-primitives 0.1.0", "hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"substrate-runtime-io 0.1.0", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@@ -626,6 +659,76 @@ dependencies = [
"uint 0.1.2 (git+https://github.com/rphmeier/primitives.git?branch=compile-for-wasm)", "uint 0.1.2 (git+https://github.com/rphmeier/primitives.git?branch=compile-for-wasm)",
] ]
[[package]]
name = "substrate-runtime-consensus"
version = "0.1.0"
dependencies = [
"hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"substrate-codec 0.1.0",
"substrate-primitives 0.1.0",
"substrate-runtime-io 0.1.0",
"substrate-runtime-primitives 0.1.0",
"substrate-runtime-std 0.1.0",
"substrate-runtime-support 0.1.0",
"substrate-runtime-system 0.1.0",
]
[[package]]
name = "substrate-runtime-council"
version = "0.1.0"
dependencies = [
"hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"integer-sqrt 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"safe-mix 0.1.0",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"substrate-codec 0.1.0",
"substrate-keyring 0.1.0",
"substrate-primitives 0.1.0",
"substrate-runtime-consensus 0.1.0",
"substrate-runtime-democracy 0.1.0",
"substrate-runtime-io 0.1.0",
"substrate-runtime-primitives 0.1.0",
"substrate-runtime-session 0.1.0",
"substrate-runtime-staking 0.1.0",
"substrate-runtime-std 0.1.0",
"substrate-runtime-support 0.1.0",
"substrate-runtime-system 0.1.0",
]
[[package]]
name = "substrate-runtime-democracy"
version = "0.1.0"
dependencies = [
"hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"safe-mix 0.1.0",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"substrate-codec 0.1.0",
"substrate-primitives 0.1.0",
"substrate-runtime-consensus 0.1.0",
"substrate-runtime-io 0.1.0",
"substrate-runtime-primitives 0.1.0",
"substrate-runtime-session 0.1.0",
"substrate-runtime-staking 0.1.0",
"substrate-runtime-std 0.1.0",
"substrate-runtime-support 0.1.0",
"substrate-runtime-system 0.1.0",
]
[[package]]
name = "substrate-runtime-executive"
version = "0.1.0"
dependencies = [
"hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"substrate-codec 0.1.0",
"substrate-runtime-io 0.1.0",
"substrate-runtime-primitives 0.1.0",
"substrate-runtime-std 0.1.0",
"substrate-runtime-support 0.1.0",
"substrate-runtime-system 0.1.0",
]
[[package]] [[package]]
name = "substrate-runtime-io" name = "substrate-runtime-io"
version = "0.1.0" version = "0.1.0"
@@ -640,6 +743,58 @@ dependencies = [
"triehash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "triehash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "substrate-runtime-primitives"
version = "0.1.0"
dependencies = [
"integer-sqrt 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"substrate-codec 0.1.0",
"substrate-primitives 0.1.0",
"substrate-runtime-io 0.1.0",
"substrate-runtime-std 0.1.0",
"substrate-runtime-support 0.1.0",
]
[[package]]
name = "substrate-runtime-session"
version = "0.1.0"
dependencies = [
"hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"safe-mix 0.1.0",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"substrate-codec 0.1.0",
"substrate-keyring 0.1.0",
"substrate-primitives 0.1.0",
"substrate-runtime-consensus 0.1.0",
"substrate-runtime-io 0.1.0",
"substrate-runtime-primitives 0.1.0",
"substrate-runtime-std 0.1.0",
"substrate-runtime-support 0.1.0",
"substrate-runtime-system 0.1.0",
]
[[package]]
name = "substrate-runtime-staking"
version = "0.1.0"
dependencies = [
"hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"safe-mix 0.1.0",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"substrate-codec 0.1.0",
"substrate-keyring 0.1.0",
"substrate-primitives 0.1.0",
"substrate-runtime-consensus 0.1.0",
"substrate-runtime-io 0.1.0",
"substrate-runtime-primitives 0.1.0",
"substrate-runtime-session 0.1.0",
"substrate-runtime-std 0.1.0",
"substrate-runtime-support 0.1.0",
"substrate-runtime-system 0.1.0",
]
[[package]] [[package]]
name = "substrate-runtime-std" name = "substrate-runtime-std"
version = "0.1.0" version = "0.1.0"
@@ -663,6 +818,36 @@ dependencies = [
"substrate-runtime-std 0.1.0", "substrate-runtime-std 0.1.0",
] ]
[[package]]
name = "substrate-runtime-system"
version = "0.1.0"
dependencies = [
"hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"safe-mix 0.1.0",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"substrate-codec 0.1.0",
"substrate-primitives 0.1.0",
"substrate-runtime-io 0.1.0",
"substrate-runtime-primitives 0.1.0",
"substrate-runtime-std 0.1.0",
"substrate-runtime-support 0.1.0",
]
[[package]]
name = "substrate-runtime-timestamp"
version = "0.1.0"
dependencies = [
"hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"substrate-codec 0.1.0",
"substrate-primitives 0.1.0",
"substrate-runtime-io 0.1.0",
"substrate-runtime-primitives 0.1.0",
"substrate-runtime-std 0.1.0",
"substrate-runtime-support 0.1.0",
"substrate-runtime-system 0.1.0",
]
[[package]] [[package]]
name = "substrate-state-machine" name = "substrate-state-machine"
version = "0.1.0" version = "0.1.0"
@@ -841,6 +1026,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461" "checksum heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461"
"checksum hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd546ef520ab3745f1aae5f2cdc6de9e6498e94d1ab138b9eb3ddfbf335847fb" "checksum hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd546ef520ab3745f1aae5f2cdc6de9e6498e94d1ab138b9eb3ddfbf335847fb"
"checksum hex-literal-impl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2ea76da4c7f1a54d01d54985566d3fdd960b2bbd7b970da024821c883c2d9631" "checksum hex-literal-impl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2ea76da4c7f1a54d01d54985566d3fdd960b2bbd7b970da024821c883c2d9631"
"checksum integer-sqrt 0.1.0 (git+https://github.com/paritytech/integer-sqrt-rs.git)" = "<none>"
"checksum integer-sqrt 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7536fe7f78abedb82f609d87f46f0e0ca0ad31e84597deb8dabd8ed9ad047257"
"checksum isatty 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f2a233726c7bb76995cec749d59582e5664823b7245d4970354408f1d79a7a2" "checksum isatty 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f2a233726c7bb76995cec749d59582e5664823b7245d4970354408f1d79a7a2"
"checksum keccak-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f300c1f149cd9ca5214eed24f6e713a597517420fb8b15499824aa916259ec1" "checksum keccak-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f300c1f149cd9ca5214eed24f6e713a597517420fb8b15499824aa916259ec1"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
@@ -852,6 +1039,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
"checksum memorydb 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "013b7e4c5e10c764936ebc6bd3662d8e3c92292d267bf6a42ef3f5cad9c793ee" "checksum memorydb 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "013b7e4c5e10c764936ebc6bd3662d8e3c92292d267bf6a42ef3f5cad9c793ee"
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
"checksum num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dee092fcdf725aee04dd7da1d21debff559237d49ef1cb3e69bcb8ece44c7364"
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
"checksum odds 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)" = "4eae0151b9dacf24fcc170d9995e511669a082856a91f958a2fe380bfab3fb22" "checksum odds 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)" = "4eae0151b9dacf24fcc170d9995e511669a082856a91f958a2fe380bfab3fb22"
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
+25 -6
View File
@@ -7,23 +7,42 @@ authors = ["Parity Technologies <admin@parity.io>"]
crate-type = ["cdylib"] crate-type = ["cdylib"]
[dependencies] [dependencies]
integer-sqrt = { git = "https://github.com/paritytech/integer-sqrt-rs.git", branch = "master" }
safe-mix = { path = "../../../safe-mix", default-features = false }
substrate-codec = { path = "../../../substrate/codec", default-features = false } substrate-codec = { path = "../../../substrate/codec", default-features = false }
substrate-primitives = { path = "../../../substrate/primitives", default-features = false }
substrate-runtime-std = { path = "../../../substrate/runtime-std", default-features = false } substrate-runtime-std = { path = "../../../substrate/runtime-std", default-features = false }
substrate-runtime-io = { path = "../../../substrate/runtime-io", default-features = false } substrate-runtime-io = { path = "../../../substrate/runtime-io", default-features = false }
substrate-runtime-support = { path = "../../../substrate/runtime-support", default-features = false } substrate-runtime-support = { path = "../../../substrate/runtime-support", default-features = false }
substrate-primitives = { path = "../../../substrate/primitives", default-features = false } substrate-runtime-consensus = { path = "../../../substrate/runtime/consensus", default-features = false }
substrate-misbehavior-check = { path = "../../../substrate/misbehavior-check", default-features = false } substrate-runtime-council = { path = "../../../substrate/runtime/council", default-features = false }
substrate-runtime-democracy = { path = "../../../substrate/runtime/democracy", default-features = false }
substrate-runtime-executive = { path = "../../../substrate/runtime/executive", default-features = false }
substrate-runtime-primitives = { path = "../../../substrate/runtime/primitives", default-features = false }
substrate-runtime-session = { path = "../../../substrate/runtime/session", default-features = false }
substrate-runtime-staking = { path = "../../../substrate/runtime/staking", default-features = false }
substrate-runtime-system = { path = "../../../substrate/runtime/system", default-features = false }
substrate-runtime-timestamp = { path = "../../../substrate/runtime/timestamp", default-features = false }
polkadot-primitives = { path = "../../primitives", default-features = false } polkadot-primitives = { path = "../../primitives", default-features = false }
[features] [features]
default = [] default = []
std = [ std = [
"safe-mix/std",
"substrate-codec/std", "substrate-codec/std",
"substrate-runtime-io/std",
"substrate-runtime-std/std",
"substrate-runtime-support/std",
"substrate-primitives/std", "substrate-primitives/std",
"substrate-misbehavior-check/std", "substrate-runtime-std/std",
"substrate-runtime-io/std",
"substrate-runtime-support/std",
"substrate-runtime-consensus/std",
"substrate-runtime-council/std",
"substrate-runtime-democracy/std",
"substrate-runtime-executive/std",
"substrate-runtime-primitives/std",
"substrate-runtime-session/std",
"substrate-runtime-staking/std",
"substrate-runtime-system/std",
"substrate-runtime-timestamp/std",
"polkadot-primitives/std", "polkadot-primitives/std",
] ]
Binary file not shown.
Binary file not shown.
+3 -2
View File
@@ -7,10 +7,11 @@ authors = ["Parity Technologies <admin@parity.io>"]
futures = "0.1.17" futures = "0.1.17"
parking_lot = "0.4" parking_lot = "0.4"
tokio-timer = "0.1.2" tokio-timer = "0.1.2"
ed25519 = { path = "../../substrate/ed25519" } hex-literal = "0.1"
error-chain = "0.11" error-chain = "0.11"
log = "0.4" log = "0.4"
tokio-core = "0.1.12" tokio-core = "0.1.12"
ed25519 = { path = "../../substrate/ed25519" }
polkadot-primitives = { path = "../primitives" } polkadot-primitives = { path = "../primitives" }
polkadot-runtime = { path = "../runtime" } polkadot-runtime = { path = "../runtime" }
polkadot-consensus = { path = "../consensus" } polkadot-consensus = { path = "../consensus" }
@@ -18,9 +19,9 @@ polkadot-executor = { path = "../executor" }
polkadot-api = { path = "../api" } polkadot-api = { path = "../api" }
polkadot-transaction-pool = { path = "../transaction-pool" } polkadot-transaction-pool = { path = "../transaction-pool" }
polkadot-keystore = { path = "../keystore" } polkadot-keystore = { path = "../keystore" }
substrate-runtime-io = { path = "../../substrate/runtime-io" }
substrate-primitives = { path = "../../substrate/primitives" } substrate-primitives = { path = "../../substrate/primitives" }
substrate-network = { path = "../../substrate/network" } substrate-network = { path = "../../substrate/network" }
substrate-client = { path = "../../substrate/client" } substrate-client = { path = "../../substrate/client" }
substrate-keyring = { path = "../../substrate/keyring" }
substrate-codec = { path = "../../substrate/codec" } substrate-codec = { path = "../../substrate/codec" }
substrate-executor = { path = "../../substrate/executor" } substrate-executor = { path = "../../substrate/executor" }
+53 -17
View File
@@ -28,15 +28,17 @@ extern crate polkadot_api;
extern crate polkadot_consensus as consensus; extern crate polkadot_consensus as consensus;
extern crate polkadot_transaction_pool as transaction_pool; extern crate polkadot_transaction_pool as transaction_pool;
extern crate polkadot_keystore as keystore; extern crate polkadot_keystore as keystore;
extern crate substrate_runtime_io as runtime_io;
extern crate substrate_primitives as primitives; extern crate substrate_primitives as primitives;
extern crate substrate_network as network; extern crate substrate_network as network;
extern crate substrate_codec as codec; extern crate substrate_codec as codec;
extern crate substrate_executor; extern crate substrate_executor;
extern crate tokio_core; extern crate tokio_core;
extern crate substrate_keyring;
extern crate substrate_client as client; extern crate substrate_client as client;
#[macro_use]
extern crate hex_literal;
#[macro_use] #[macro_use]
extern crate error_chain; extern crate error_chain;
#[macro_use] #[macro_use]
@@ -51,14 +53,15 @@ use futures::prelude::*;
use parking_lot::Mutex; use parking_lot::Mutex;
use tokio_core::reactor::Core; use tokio_core::reactor::Core;
use codec::Slicable; use codec::Slicable;
use runtime_io::with_externalities;
use primitives::block::{Id as BlockId, TransactionHash}; use primitives::block::{Id as BlockId, TransactionHash};
use transaction_pool::TransactionPool; use transaction_pool::TransactionPool;
use substrate_keyring::Keyring;
use substrate_executor::NativeExecutor; use substrate_executor::NativeExecutor;
use polkadot_executor::Executor as LocalDispatch; use polkadot_executor::Executor as LocalDispatch;
use keystore::Store as Keystore; use keystore::Store as Keystore;
use polkadot_api::PolkadotApi; use polkadot_api::PolkadotApi;
use polkadot_runtime::genesismap::{additional_storage_with_genesis, GenesisConfig}; use polkadot_runtime::{GenesisConfig, ConsensusConfig, CouncilConfig, DemocracyConfig,
SessionConfig, StakingConfig, BuildExternalities};
use client::{genesis, BlockchainEvents}; use client::{genesis, BlockchainEvents};
use client::in_mem::Backend as InMemory; use client::in_mem::Backend as InMemory;
use network::ManageNetwork; use network::ManageNetwork;
@@ -137,26 +140,60 @@ impl Service {
info!("Generated a new keypair: {:?}", key.public()); info!("Generated a new keypair: {:?}", key.public());
} }
let god_keys = vec![
hex!["f09c0d1467d6952c92c343672bfb06a24560f400af8cf98b93df7d40b4efe1b6"],
hex!["84718cd2894bcda83beeca3a7842caf269fe93cacde0bdee0e3cbce6de253f0e"]
];
let genesis_config = GenesisConfig { let genesis_config = GenesisConfig {
validators: vec![Keyring::Alice.into(), Keyring::Bob.into(), Keyring::Charlie.into()], consensus: Some(ConsensusConfig {
authorities: vec![Keyring::Alice.into(), Keyring::Bob.into(), Keyring::Charlie.into()], code: include_bytes!("../../runtime/wasm/genesis.wasm").to_vec(),
balances: vec![ authorities: god_keys.clone(),
(Keyring::One.into(), 1u64 << 63), }),
(Keyring::Two.into(), 1u64 << 63), system: None,
(Keyring::Alice.into(), 1u64 << 63), // block_time: 5, // 5 second block time.
(Keyring::Bob.into(), 1u64 << 63), session: Some(SessionConfig {
(Keyring::Charlie.into(), 1u64 << 63), validators: god_keys.clone(),
].into_iter().collect(),
block_time: 5, // 5 second block time.
session_length: 720, // that's 1 hour per session. session_length: 720, // that's 1 hour per session.
}),
staking: Some(StakingConfig {
current_era: 0,
intentions: vec![],
transaction_fee: 100,
balances: god_keys.iter().map(|&k|(k, 1u64 << 60)).collect(),
validator_count: 12,
sessions_per_era: 24, // 24 hours per era. sessions_per_era: 24, // 24 hours per era.
bonding_duration: 90, // 90 days per bond. bonding_duration: 90, // 90 days per bond.
approval_ratio: 667, // 66.7% approvals required for legislation. }),
democracy: Some(DemocracyConfig {
launch_period: 120 * 24 * 14, // 2 weeks per public referendum
voting_period: 120 * 24 * 28, // 4 weeks to discuss & vote on an active referendum
minimum_deposit: 1000, // 1000 as the minimum deposit for a referendum
}),
council: Some(CouncilConfig {
active_council: vec![],
candidacy_bond: 1000, // 1000 to become a council candidate
voter_bond: 100, // 100 down to vote for a candidate
present_slash_per_voter: 1, // slash by 1 per voter for an invalid presentation.
carry_count: 24, // carry over the 24 runners-up to the next council election
presentation_duration: 120 * 24, // one day for presenting winners.
approval_voting_period: 7 * 120 * 24, // one week period between possible council elections.
term_duration: 180 * 120 * 24, // 180 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.
inactive_grace_period: 1, // one addition vote should go by before an inactive voter can be reaped.
cooloff_period: 90 * 120 * 24, // 90 day cooling off period if council member vetoes a proposal.
voting_period: 7 * 120 * 24, // 7 day voting period for council members.
}),
parachains: Some(Default::default()),
}; };
let prepare_genesis = || { let prepare_genesis = || {
storage = genesis_config.genesis_map(); storage = genesis_config.build_externalities();
let block = genesis::construct_genesis_block(&storage); let block = genesis::construct_genesis_block(&storage);
storage.extend(additional_storage_with_genesis(&block)); with_externalities(&mut storage, ||
// TODO: use api.rs to dispatch instead
polkadot_runtime::System::initialise_genesis_state(&block.header)
);
(primitives::block::Header::decode(&mut block.header.encode().as_ref()).expect("to_vec() always gives a valid serialisation; qed"), storage.into_iter().collect()) (primitives::block::Header::decode(&mut block.header.encode().as_ref()).expect("to_vec() always gives a valid serialisation; qed"), storage.into_iter().collect())
}; };
@@ -236,4 +273,3 @@ impl Drop for Service {
} }
} }
} }
+2
View File
@@ -8,7 +8,9 @@ transaction-pool = "1.9.0"
error-chain = "0.11" error-chain = "0.11"
polkadot-api = { path = "../api" } polkadot-api = { path = "../api" }
polkadot-primitives = { path = "../primitives" } polkadot-primitives = { path = "../primitives" }
polkadot-runtime = { path = "../runtime" }
substrate-primitives = { path = "../../substrate/primitives" } substrate-primitives = { path = "../../substrate/primitives" }
substrate-runtime-primitives = { path = "../../substrate/runtime/primitives" }
substrate-codec = { path = "../../substrate/codec" } substrate-codec = { path = "../../substrate/codec" }
ed25519 = { path = "../../substrate/ed25519" } ed25519 = { path = "../../substrate/ed25519" }
ethereum-types = "0.2" ethereum-types = "0.2"
+105 -39
View File
@@ -14,13 +14,15 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>. // along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
extern crate transaction_pool;
extern crate polkadot_api;
extern crate polkadot_primitives as primitives;
extern crate substrate_primitives as substrate_primitives;
extern crate substrate_codec as codec;
extern crate ed25519; extern crate ed25519;
extern crate ethereum_types; extern crate ethereum_types;
extern crate substrate_codec as codec;
extern crate substrate_primitives as substrate_primitives;
extern crate substrate_runtime_primitives as substrate_runtime_primitives;
extern crate polkadot_runtime as runtime;
extern crate polkadot_primitives as primitives;
extern crate polkadot_api;
extern crate transaction_pool;
#[macro_use] #[macro_use]
extern crate error_chain; extern crate error_chain;
@@ -30,8 +32,9 @@ use std::cmp::Ordering;
use std::sync::Arc; use std::sync::Arc;
use polkadot_api::PolkadotApi; use polkadot_api::PolkadotApi;
use primitives::AccountId; use primitives::{AccountId, Timestamp};
use primitives::transaction::UncheckedTransaction; use runtime::{Block, UncheckedExtrinsic, TimestampCall, Call};
use substrate_runtime_primitives::traits::Checkable;
use transaction_pool::{Pool, Readiness}; use transaction_pool::{Pool, Readiness};
use transaction_pool::scoring::{Change, Choice}; use transaction_pool::scoring::{Change, Choice};
@@ -44,6 +47,68 @@ pub fn truncate_id(id: &AccountId) -> TruncatedAccountId {
TruncatedAccountId::from_slice(&id[..20]) TruncatedAccountId::from_slice(&id[..20])
} }
/// Useful functions for working with Polkadot blocks.
pub struct PolkadotBlock {
block: Block,
location: Option<(&'static str, usize)>,
}
impl PolkadotBlock {
/// Create a new block, checking high-level well-formedness.
pub fn from(unchecked: Block) -> ::std::result::Result<Self, Block> {
if unchecked.extrinsics.len() < 1 {
return Err(unchecked);
}
if unchecked.extrinsics[0].is_signed() {
return Err(unchecked);
}
match unchecked.extrinsics[0].extrinsic.function {
Call::Timestamp(TimestampCall::set(_)) => return Err(unchecked),
_ => {}
}
// any further checks...
Ok(PolkadotBlock { block: unchecked, location: None })
}
/// Create a new block, skipping any high-level well-formedness checks. WARNING: This could
/// result in internal functions panicking if the block is, in fact, not well-formed.
pub fn force_from(known_good: Block, file: &'static str, line: usize) -> Self {
PolkadotBlock { block: known_good, location: Some((file, line)) }
}
/// Retrieve the timestamp of a Polkadot block.
pub fn timestamp(&self) -> Timestamp {
if let Call::Timestamp(TimestampCall::set(t)) = self.block.extrinsics[0].extrinsic.function {
t
} else {
if let Some((file, line)) = self.location {
panic!("Invalid block used in `PolkadotBlock::force_from` at {}:{}", file, line);
} else {
panic!("Invalid block made it through the PolkadotBlock verification!?");
}
}
}
}
#[macro_export]
macro_rules! assert_polkadot_block {
($known_good:expr) => ( PolkadotBlock::force_from(known_good, file!(), line!()) )
}
impl ::std::ops::Deref for PolkadotBlock {
type Target = Block;
fn deref(&self) -> &Block {
&self.block
}
}
impl From<PolkadotBlock> for Block {
fn from(pd: PolkadotBlock) -> Self {
pd.block
}
}
/// Iterator over pending transactions. /// Iterator over pending transactions.
pub type PendingIterator<'a, C> = pub type PendingIterator<'a, C> =
transaction_pool::PendingIterator<'a, VerifiedTransaction, Ready<'a, C>, Scoring, NoopListener>; transaction_pool::PendingIterator<'a, VerifiedTransaction, Ready<'a, C>, Scoring, NoopListener>;
@@ -51,12 +116,12 @@ pub type PendingIterator<'a, C> =
error_chain! { error_chain! {
errors { errors {
/// Attempted to queue an inherent transaction. /// Attempted to queue an inherent transaction.
IsInherent(tx: UncheckedTransaction) { IsInherent(xt: UncheckedExtrinsic) {
description("Inherent transactions cannot be queued."), description("Inherent transactions cannot be queued."),
display("Inehrent transactions cannot be queued."), display("Inehrent transactions cannot be queued."),
} }
/// Attempted to queue a transaction with bad signature. /// Attempted to queue a transaction with bad signature.
BadSignature(tx: UncheckedTransaction) { BadSignature(xt: UncheckedExtrinsic) {
description("Transaction had bad signature."), description("Transaction had bad signature."),
display("Transaction had bad signature."), display("Transaction had bad signature."),
} }
@@ -76,7 +141,7 @@ error_chain! {
/// A verified transaction which should be includable and non-inherent. /// A verified transaction which should be includable and non-inherent.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct VerifiedTransaction { pub struct VerifiedTransaction {
inner: UncheckedTransaction, inner: <UncheckedExtrinsic as Checkable>::Checked,
hash: TransactionHash, hash: TransactionHash,
address: TruncatedAccountId, address: TruncatedAccountId,
insertion_id: u64, insertion_id: u64,
@@ -85,35 +150,36 @@ pub struct VerifiedTransaction {
impl VerifiedTransaction { impl VerifiedTransaction {
/// Attempt to verify a transaction. /// Attempt to verify a transaction.
fn create(tx: UncheckedTransaction, insertion_id: u64) -> Result<Self> { fn create(xt: UncheckedExtrinsic, insertion_id: u64) -> Result<Self> {
if tx.is_inherent() { if !xt.is_signed() {
bail!(ErrorKind::IsInherent(tx)) bail!(ErrorKind::IsInherent(xt))
} }
let message = codec::Slicable::encode(&tx); let message = codec::Slicable::encode(&xt);
if ed25519::verify(&*tx.signature, &message, &tx.transaction.signed[..]) { match xt.check() {
Ok(xt) => {
// TODO: make transaction-pool use generic types. // TODO: make transaction-pool use generic types.
let hash = substrate_primitives::hashing::blake2_256(&message); let hash = substrate_primitives::hashing::blake2_256(&message);
let address = truncate_id(&tx.transaction.signed); let address = truncate_id(&xt.signed);
Ok(VerifiedTransaction { Ok(VerifiedTransaction {
inner: tx, inner: xt,
hash: hash.into(), hash: hash.into(),
encoded_size: message.len(), encoded_size: message.len(),
address, address,
insertion_id, insertion_id,
}) })
} else { }
Err(ErrorKind::BadSignature(tx).into()) Err(xt) => Err(ErrorKind::BadSignature(xt).into()),
} }
} }
/// Access the underlying transaction. /// Access the underlying transaction.
pub fn as_transaction(&self) -> &UncheckedTransaction { pub fn as_transaction(&self) -> &UncheckedExtrinsic {
self.as_ref() self.as_ref().as_unchecked()
} }
/// Consume the verified transaciton, yielding the unchecked counterpart. /// Consume the verified transaciton, yielding the unchecked counterpart.
pub fn into_inner(self) -> UncheckedTransaction { pub fn into_inner(self) -> <UncheckedExtrinsic as Checkable>::Checked {
self.inner self.inner
} }
@@ -133,8 +199,8 @@ impl VerifiedTransaction {
} }
} }
impl AsRef<UncheckedTransaction> for VerifiedTransaction { impl AsRef< <UncheckedExtrinsic as Checkable>::Checked > for VerifiedTransaction {
fn as_ref(&self) -> &UncheckedTransaction { fn as_ref(&self) -> &<UncheckedExtrinsic as Checkable>::Checked {
&self.inner &self.inner
} }
} }
@@ -164,7 +230,7 @@ impl transaction_pool::Scoring<VerifiedTransaction> for Scoring {
type Score = u64; type Score = u64;
fn compare(&self, old: &VerifiedTransaction, other: &VerifiedTransaction) -> Ordering { fn compare(&self, old: &VerifiedTransaction, other: &VerifiedTransaction) -> Ordering {
old.inner.transaction.nonce.cmp(&other.inner.transaction.nonce) old.inner.index.cmp(&other.inner.index)
} }
fn choose(&self, _old: &VerifiedTransaction, _new: &VerifiedTransaction) -> Choice { fn choose(&self, _old: &VerifiedTransaction, _new: &VerifiedTransaction) -> Choice {
@@ -173,11 +239,11 @@ impl transaction_pool::Scoring<VerifiedTransaction> for Scoring {
fn update_scores( fn update_scores(
&self, &self,
txs: &[Arc<VerifiedTransaction>], xts: &[Arc<VerifiedTransaction>],
scores: &mut [Self::Score], scores: &mut [Self::Score],
_change: Change _change: Change
) { ) {
for i in 0..txs.len() { for i in 0..xts.len() {
// all the same score since there are no fees. // all the same score since there are no fees.
// TODO: prioritize things like misbehavior or fishermen reports // TODO: prioritize things like misbehavior or fishermen reports
scores[i] = 1; scores[i] = 1;
@@ -192,7 +258,7 @@ impl transaction_pool::Scoring<VerifiedTransaction> for Scoring {
pub struct Ready<'a, T: 'a + PolkadotApi> { pub struct Ready<'a, T: 'a + PolkadotApi> {
at_block: T::CheckedBlockId, at_block: T::CheckedBlockId,
api_handle: &'a T, api_handle: &'a T,
known_nonces: HashMap<AccountId, ::primitives::TxOrder>, known_indices: HashMap<AccountId, ::primitives::Index>,
} }
impl<'a, T: 'a + PolkadotApi> Clone for Ready<'a, T> { impl<'a, T: 'a + PolkadotApi> Clone for Ready<'a, T> {
@@ -200,7 +266,7 @@ impl<'a, T: 'a + PolkadotApi> Clone for Ready<'a, T> {
Ready { Ready {
at_block: self.at_block.clone(), at_block: self.at_block.clone(),
api_handle: self.api_handle, api_handle: self.api_handle,
known_nonces: self.known_nonces.clone(), known_indices: self.known_indices.clone(),
} }
} }
} }
@@ -212,24 +278,24 @@ impl<'a, T: 'a + PolkadotApi> Ready<'a, T> {
Ready { Ready {
at_block: at, at_block: at,
api_handle: client, api_handle: client,
known_nonces: HashMap::new(), known_indices: HashMap::new(),
} }
} }
} }
impl<'a, T: 'a + PolkadotApi> transaction_pool::Ready<VerifiedTransaction> for Ready<'a, T> { impl<'a, T: 'a + PolkadotApi> transaction_pool::Ready<VerifiedTransaction> for Ready<'a, T> {
fn is_ready(&mut self, tx: &VerifiedTransaction) -> Readiness { fn is_ready(&mut self, xt: &VerifiedTransaction) -> Readiness {
let sender = tx.inner.transaction.signed; let sender = xt.inner.signed;
// TODO: find a way to handle nonce error properly -- will need changes to // TODO: find a way to handle index error properly -- will need changes to
// transaction-pool trait. // transaction-pool trait.
let (api_handle, at_block) = (&self.api_handle, &self.at_block); let (api_handle, at_block) = (&self.api_handle, &self.at_block);
let next_nonce = self.known_nonces.entry(sender) let next_index = self.known_indices.entry(sender)
.or_insert_with(|| api_handle.nonce(at_block, sender).ok().unwrap_or_else(u64::max_value)); .or_insert_with(|| api_handle.index(at_block, sender).ok().unwrap_or_else(u64::max_value));
*next_nonce += 1; *next_index += 1;
match tx.inner.transaction.nonce.cmp(&next_nonce) { match xt.inner.index.cmp(&next_index) {
Ordering::Greater => Readiness::Future, Ordering::Greater => Readiness::Future,
Ordering::Equal => Readiness::Ready, Ordering::Equal => Readiness::Ready,
Ordering::Less => Readiness::Stalled, Ordering::Less => Readiness::Stalled,
@@ -255,11 +321,11 @@ impl TransactionPool {
} }
/// Verify and import a transaction into the pool. /// Verify and import a transaction into the pool.
pub fn import(&mut self, tx: UncheckedTransaction) -> Result<Arc<VerifiedTransaction>> { pub fn import(&mut self, xt: UncheckedExtrinsic) -> Result<Arc<VerifiedTransaction>> {
let insertion_index = self.insertion_index; let insertion_index = self.insertion_index;
self.insertion_index += 1; self.insertion_index += 1;
let verified = VerifiedTransaction::create(tx, insertion_index)?; let verified = VerifiedTransaction::create(xt, insertion_index)?;
// TODO: just use a foreign link when the error type is made public. // TODO: just use a foreign link when the error type is made public.
let hash = verified.hash.clone(); let hash = verified.hash.clone();