initial merge

This commit is contained in:
Robert Habermeier
2018-02-06 14:12:54 +01:00
21 changed files with 839 additions and 191 deletions
+24 -4
View File
@@ -38,7 +38,7 @@ pub mod runtime;
use runtime_std::prelude::*;
use codec::Slicable;
use primitives::transaction::UncheckedTransaction;
use primitives::block::Block;
use primitives::block::{Header, Block};
/// Execute a block, with `input` being the canonical serialisation of the block. Returns the
/// empty vector.
@@ -49,9 +49,29 @@ pub fn execute_block(mut input: &[u8]) -> Vec<u8> {
/// Execute a given, serialised, transaction. Returns the empty vector.
pub fn execute_transaction(mut input: &[u8]) -> Vec<u8> {
let header = Header::from_slice(&mut input).unwrap();
let utx = UncheckedTransaction::from_slice(&mut input).unwrap();
runtime::system::internal::execute_transaction(utx);
Vec::new()
let header = runtime::system::internal::execute_transaction(utx, header);
header.to_vec()
}
impl_stubs!(execute_block, execute_transaction);
/// Execute a given, serialised, transaction. Returns the empty vector.
pub fn finalise_block(mut input: &[u8]) -> Vec<u8> {
let header = Header::from_slice(&mut input).unwrap();
let header = runtime::system::internal::finalise_block(header);
header.to_vec()
}
/// Run whatever tests we have.
pub fn run_tests(mut input: &[u8]) -> Vec<u8> {
use runtime_std::print;
print("run_tests...");
let block = Block::from_slice(&mut input).unwrap();
print("deserialised block.");
let stxs = block.transactions.iter().map(Slicable::to_vec).collect::<Vec<_>>();
print("reserialised transactions.");
[stxs.len() as u8].to_vec()
}
impl_stubs!(execute_block, execute_transaction, finalise_block, run_tests);
@@ -17,13 +17,13 @@
//! Conensus module for runtime; manages the authority set ready for the native code.
use runtime_std::prelude::*;
use support::StorageVec;
use support::storage::unhashed::StorageVec;
use primitives::SessionKey;
struct AuthorityStorageVec {}
impl StorageVec for AuthorityStorageVec {
type Item = SessionKey;
const PREFIX: &'static[u8] = b"con:aut:";
const PREFIX: &'static[u8] = b":auth:";
}
/// Get the current set of authorities. These are the session keys.
@@ -0,0 +1,91 @@
// 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 std::collections::HashMap;
use runtime_std::twox_128;
use codec::{KeyedVec, Joiner};
use support::Hashable;
use primitives::{AccountID, BlockNumber, Block};
use runtime::staking::Balance;
/// 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-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm").to_vec();
vec![
(&b"gov:apr"[..], vec![].join(&self.approval_ratio)),
(&b"ses:len"[..], vec![].join(&self.session_length)),
(&b"ses:val:len"[..], vec![].join(&(self.validators.len() as u32))),
(&b"sta:wil:len"[..], vec![].join(&0u32)),
(&b"sta:spe"[..], vec![].join(&self.sessions_per_era)),
(&b"sta:vac"[..], vec![].join(&(self.validators.len() as u32))),
(&b"sta:era"[..], vec![].join(&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![].join(account)))
).chain(self.authorities.iter()
.enumerate()
.map(|(i, account)| ((i as u32).to_keyed_vec(b":auth:"), vec![].join(account)))
).chain(self.balances.iter()
.map(|&(account, balance)| (account.to_keyed_vec(b"sta:bal:"), vec![].join(&balance)))
)
.map(|(k, v)| (twox_128(&k[..])[..].to_vec(), v.to_vec()))
.chain(vec![
(b":code"[..].into(), wasm_runtime),
(b":auth:len"[..].into(), vec![].join(&(self.authorities.len() as u32))),
].into_iter())
.chain(self.authorities.iter()
.enumerate()
.map(|(i, account)| ((i as u32).to_keyed_vec(b":auth:"), vec![].join(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().to_vec()
]
}
@@ -31,3 +31,7 @@ pub mod governance;
// TODO: polkadao
// TODO: parachains
#[cfg(feature = "std")]
pub mod genesismap;
@@ -78,6 +78,11 @@ pub mod privileged {
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)
@@ -146,9 +151,9 @@ mod tests {
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, ...)
twox_128(b"con:aut:len").to_vec() => vec![].join(&2u32),
twox_128(&0u32.to_keyed_vec(b"con:aut:")).to_vec() => vec![11; 32],
twox_128(&1u32.to_keyed_vec(b"con:aut:")).to_vec() => vec![21; 32]
b":auth:len".to_vec() => vec![].join(&2u32),
0u32.to_keyed_vec(b":auth:") => vec![11; 32],
1u32.to_keyed_vec(b":auth:") => vec![21; 32]
], }
}
@@ -18,6 +18,7 @@
use runtime_std::prelude::*;
use runtime_std::cell::RefCell;
use runtime_std::print;
use codec::KeyedVec;
use support::{storage, StorageVec};
use primitives::{BlockNumber, AccountId};
@@ -150,6 +151,12 @@ pub mod privileged {
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 {
@@ -18,15 +18,16 @@
//! and depositing logs.
use runtime_std::prelude::*;
use runtime_std::{mem, print, storage_root, enumerated_trie_root};
use runtime_std::{mem, storage_root, enumerated_trie_root};
use codec::{KeyedVec, Slicable};
use support::{Hashable, storage, with_env};
use primitives::{AccountId, Hash, TxOrder};
use primitives::block::{Block, Number as BlockNumber};
use primitives::{AccountId, Hash, H256, TxOrder};
use primitives::block::{Block, Header, Number as BlockNumber};
use primitives::transaction::UncheckedTransaction;
use primitives::runtime_function::Function;
use runtime::{staking, session};
const NONCE_OF: &[u8] = b"sys:non:";
const BLOCK_HASH_AT: &[u8] = b"sys:old:";
const CODE: &[u8] = b"sys:cod";
@@ -45,7 +46,7 @@ pub mod privileged {
/// Set the new code.
pub fn set_code(new: &[u8]) {
storage::put_raw(CODE, new);
storage::unhashed::put_raw(b":code", new);
}
}
@@ -55,11 +56,8 @@ pub mod internal {
struct CheckedTransaction(UncheckedTransaction);
/// Deposits a log and ensures it matches the blocks log data.
pub fn deposit_log(log: &[u8]) {
with_env(|e| {
assert_eq!(log, &e.digest.logs[e.next_log_index].0[..]);
e.next_log_index += 1;
});
pub fn deposit_log(log: ::primitives::block::Log) {
with_env(|e| e.digest.logs.push(log));
}
/// Actually execute all transitioning for `block`.
@@ -67,8 +65,6 @@ pub mod internal {
// populate environment from header.
with_env(|e| {
e.block_number = block.header.number;
mem::swap(&mut e.digest, &mut block.header.digest);
e.next_log_index = 0;
});
let ref header = block.header;
@@ -81,11 +77,15 @@ pub mod internal {
// check transaction trie root represents the transactions.
let txs = block.transactions.iter().map(Slicable::to_vec).collect::<Vec<_>>();
let txs_root = enumerated_trie_root(&txs.iter().map(Vec::as_slice).collect::<Vec<_>>());
assert!(header.transaction_root.0 == txs_root, "Transaction trie root must be valid.");
let txs = txs.iter().map(Vec::as_slice).collect::<Vec<_>>();
let txs_root = H256(enumerated_trie_root(&txs));
debug_assert_hash(&header.transaction_root, &txs_root);
assert!(header.transaction_root == txs_root, "Transaction trie root must be valid.");
// execute transactions
block.transactions.iter().cloned().for_each(execute_transaction);
for tx in &block.transactions {
super::execute_transaction(tx.clone());
}
staking::internal::check_new_era();
session::internal::check_rotate_session();
@@ -93,39 +93,50 @@ pub mod internal {
// any final checks
final_checks(&block);
// check storage root.
assert!(header.state_root.0 == storage_root(), "Storage root must match that calculated.");
let storage_root = H256(storage_root());
debug_assert_hash(&header.state_root, &storage_root);
assert!(header.state_root == storage_root, "Storage root must match that calculated.");
// store the header hash in storage; we can't do it before otherwise there would be a
// cyclic dependency.
let header_hash_key = header.number.to_keyed_vec(BLOCK_HASH_AT);
storage::put(&header_hash_key, &header.blake2_256());
// any stuff that we do after taking the storage root.
post_finalise(header);
}
/// Execute a given transaction.
pub fn execute_transaction(utx: UncheckedTransaction) {
use runtime_std::transaction;
/// Execute a transaction outside of the block execution function.
/// This doesn't attempt to validate anything regarding the block.
pub fn execute_transaction(utx: UncheckedTransaction, mut header: Header) -> Header {
// populate environment from header.
with_env(|e| {
e.block_number = header.number;
mem::swap(&mut header.digest, &mut e.digest);
});
// Verify the signature is good.
let tx = match transaction::check(utx) {
Ok(tx) => tx,
Err(_) => panic!("All transactions should be properly signed"),
};
super::execute_transaction(utx);
// check nonce
let nonce_key = tx.signed.to_keyed_vec(b"sys:non:");
let expected_nonce: TxOrder = storage::get_or_default(&nonce_key);
assert!(tx.nonce == expected_nonce, "All transactions should have the correct nonce");
// increment nonce in storage
storage::put(&nonce_key, &(expected_nonce + 1));
// decode parameters and dispatch
dispatch_function(&tx.function, &tx.signed);
with_env(|e| {
mem::swap(&mut header.digest, &mut e.digest);
});
header
}
fn dispatch_function(function: &Function, transactor: &AccountId) {
/// 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 {
staking::internal::check_new_era();
session::internal::check_rotate_session();
header.state_root = H256(storage_root());
with_env(|e| {
mem::swap(&mut header.digest, &mut e.digest);
});
post_finalise(&header);
header
}
/// Dispatch a function.
pub fn dispatch_function(function: &Function, transactor: &AccountId) {
match *function {
Function::StakingStake => {
::runtime::staking::public::stake(transactor);
@@ -150,14 +161,52 @@ pub mod internal {
}
}
}
#[cfg(feature = "with-std")]
fn debug_assert_hash(given: &Hash, expected: &Hash) {
use support::HexDisplay;
if given != expected {
println!("Hash: given={}, expected={}", HexDisplay::from(given), HexDisplay::from(expected));
}
}
#[cfg(not(feature = "with-std"))]
fn debug_assert_hash(_given: &Hash, _expected: &Hash) {}
}
fn execute_transaction(utx: UncheckedTransaction) {
use runtime_std::transaction;
// Verify the signature is good.
let tx = match transaction::check(utx) {
Ok(tx) => tx,
Err(_) => panic!("All transactions should be properly signed"),
};
// check nonce
let nonce_key = tx.signed.to_keyed_vec(NONCE_OF);
let expected_nonce: TxOrder = storage::get_or(&nonce_key, 0);
assert!(tx.nonce == expected_nonce, "All transactions should have the correct nonce");
// increment nonce in storage
storage::put(&nonce_key, &(expected_nonce + 1));
// decode parameters and dispatch
internal::dispatch_function(&tx.function, &tx.signed);
}
fn final_checks(_block: &Block) {
with_env(|e| {
assert_eq!(e.next_log_index, e.digest.logs.len());
assert!(_block.header.digest == e.digest);
});
}
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(test)]
mod tests {
use super::*;
@@ -193,7 +242,7 @@ mod tests {
// sig: b543b41e4b7a0270eddf57ed6c435df04bb63f71c79f6ae2530ab26c734bb4e8cd57b1c190c41d5791bcdea66a16c7339b1e883e5d0538ea2d9acea800d60a00
with_externalities(&mut t, || {
execute_transaction(tx);
internal::execute_transaction(tx, Header::from_block_number(1));
assert_eq!(staking::balance(&one), 42);
assert_eq!(staking::balance(&two), 69);
});
@@ -230,15 +279,6 @@ mod tests {
let mut t = new_test_ext();
let tx = UncheckedTransaction {
transaction: Transaction {
signed: one.clone(),
nonce: 0,
function: Function::StakingTransfer(two, 69),
},
signature: "b543b41e4b7a0270eddf57ed6c435df04bb63f71c79f6ae2530ab26c734bb4e8cd57b1c190c41d5791bcdea66a16c7339b1e883e5d0538ea2d9acea800d60a00".parse().unwrap(),
};
let h = Header {
parent_hash: H256([69u8; 32]),
number: 1,
@@ -249,13 +289,11 @@ mod tests {
let b = Block {
header: h,
transactions: vec![tx],
transactions: vec![],
};
with_externalities(&mut t, || {
execute_block(b);
assert_eq!(staking::balance(&one), 42);
assert_eq!(staking::balance(&two), 69);
});
}
@@ -267,34 +305,47 @@ mod tests {
let mut t = new_test_ext();
let tx = UncheckedTransaction {
transaction: Transaction {
signed: one.clone(),
nonce: 0,
function: Function::StakingTransfer(two, 69),
},
signature: "b543b41e4b7a0270eddf57ed6c435df04bb63f71c79f6ae2530ab26c734bb4e8cd57b1c190c41d5791bcdea66a16c7339b1e883e5d0538ea2d9acea800d60a00".parse().unwrap(),
};
// tx: 2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000228000000d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000
// sig: b543b41e4b7a0270eddf57ed6c435df04bb63f71c79f6ae2530ab26c734bb4e8cd57b1c190c41d5791bcdea66a16c7339b1e883e5d0538ea2d9acea800d60a00
let h = Header {
parent_hash: H256([69u8; 32]),
parent_hash: [69u8; 32],
number: 1,
state_root: H256([0u8; 32]),
transaction_root: H256([0u8; 32]), // Unchecked currently.
state_root: [0u8; 32],
transaction_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"),
digest: Digest { logs: vec![], },
};
let b = Block {
header: h,
transactions: vec![tx],
transactions: vec![],
};
with_externalities(&mut t, || {
execute_block(b);
});
}
#[test]
#[should_panic]
fn block_import_of_bad_transaction_root_fails() {
let one = one();
let two = two();
let mut t = new_test_ext();
let h = Header {
parent_hash: H256([69u8; 32]),
number: 1,
state_root: H256(hex!("1ab2dbb7d4868a670b181327b0b6a58dc64b10cfb9876f737a5aa014b8da31e0")),
transaction_root: H256([0u8; 32]),
digest: Digest { logs: vec![], },
};
let b = Block {
header: h,
transactions: vec![],
};
with_externalities(&mut t, || {
execute_block(b);
assert_eq!(staking::balance(&one), 42);
assert_eq!(staking::balance(&two), 69);
});
}
}
@@ -30,8 +30,6 @@ pub struct Environment {
pub block_number: BlockNumber,
/// The current block digest.
pub digest: Digest,
/// The number of log items in this block that have been accounted for so far.
pub next_log_index: usize,
}
/// Do something with the environment and return its value. Keep the function short.
@@ -141,6 +141,129 @@ pub trait StorageVec {
}
}
pub mod unhashed {
use super::{runtime_std, Slicable, KeyedVec, Vec};
/// Return the value of the item in storage under `key`, or `None` if there is no explicit entry.
pub fn get<T: Slicable + Sized>(key: &[u8]) -> Option<T> {
let raw = runtime_std::storage(key);
T::from_slice(&mut &raw[..])
}
/// Return the value of the item in storage under `key`, or the type's default if there is no
/// explicit entry.
pub fn get_or_default<T: Slicable + Sized + Default>(key: &[u8]) -> T {
get(key).unwrap_or_else(Default::default)
}
/// Return the value of the item in storage under `key`, or `default_value` if there is no
/// explicit entry.
pub fn get_or<T: Slicable + Sized>(key: &[u8], default_value: T) -> T {
get(key).unwrap_or(default_value)
}
/// Return the value of the item in storage under `key`, or `default_value()` if there is no
/// explicit entry.
pub fn get_or_else<T: Slicable + Sized, F: FnOnce() -> T>(key: &[u8], default_value: F) -> T {
get(key).unwrap_or_else(default_value)
}
/// Please `value` in storage under `key`.
pub fn put<T: Slicable>(key: &[u8], value: &T) {
value.as_slice_then(|slice| runtime_std::set_storage(key, slice));
}
/// Please `value` in storage under `key`.
pub fn place<T: Slicable>(key: &[u8], value: T) {
value.as_slice_then(|slice| runtime_std::set_storage(key, slice));
}
/// Remove `key` from storage, returning its value if it had an explicit entry or `None` otherwise.
pub fn take<T: Slicable + Sized>(key: &[u8]) -> Option<T> {
let r = get(key);
if r.is_some() {
kill(key);
}
r
}
/// Remove `key` from storage, returning its value, or, if there was no explicit entry in storage,
/// the default for its type.
pub fn take_or_default<T: Slicable + Sized + Default>(key: &[u8]) -> T {
take(key).unwrap_or_else(Default::default)
}
/// Return the value of the item in storage under `key`, or `default_value` if there is no
/// explicit entry. Ensure there is no explicit entry on return.
pub fn take_or<T: Slicable + Sized>(key: &[u8], default_value: T) -> T {
take(key).unwrap_or(default_value)
}
/// Return the value of the item in storage under `key`, or `default_value()` if there is no
/// explicit entry. Ensure there is no explicit entry on return.
pub fn take_or_else<T: Slicable + Sized, F: FnOnce() -> T>(key: &[u8], default_value: F) -> T {
take(key).unwrap_or_else(default_value)
}
/// Check to see if `key` has an explicit entry in storage.
pub fn exists(key: &[u8]) -> bool {
let mut x = [0u8; 1];
runtime_std::read_storage(key, &mut x[..], 0) >= 1
}
/// Ensure `key` has no explicit entry in storage.
pub fn kill(key: &[u8]) {
runtime_std::set_storage(key, b"");
}
/// Get a Vec of bytes from storage.
pub fn get_raw(key: &[u8]) -> Vec<u8> {
runtime_std::storage(key)
}
/// Put a raw byte slice into storage.
pub fn put_raw(key: &[u8], value: &[u8]) {
runtime_std::set_storage(key, value)
}
/// A trait to conveniently store a vector of storable data.
// TODO: add iterator support
pub trait StorageVec {
type Item: Default + Sized + Slicable;
const PREFIX: &'static [u8];
/// Get the current set of items.
fn items() -> Vec<Self::Item> {
(0..Self::count()).into_iter().map(Self::item).collect()
}
/// Set the current set of items.
fn set_items(items: &[Self::Item]) {
Self::set_count(items.len() as u32);
items.iter().enumerate().for_each(|(v, ref i)| Self::set_item(v as u32, i));
}
fn set_item(index: u32, item: &Self::Item) {
if index < Self::count() {
put(&index.to_keyed_vec(Self::PREFIX), item);
}
}
fn item(index: u32) -> Self::Item {
get_or_default(&index.to_keyed_vec(Self::PREFIX))
}
fn set_count(count: u32) {
(count..Self::count()).for_each(|i| Self::set_item(i, &Self::Item::default()));
put(&b"len".to_keyed_vec(Self::PREFIX), &count);
}
fn count() -> u32 {
get_or_default(&b"len".to_keyed_vec(Self::PREFIX))
}
}
}
#[cfg(test)]
mod tests {
use super::*;