Genesis block builder and test.

This commit is contained in:
Gav
2018-02-03 19:00:23 +01:00
parent 4c70c2058d
commit e0c1d13be6
12 changed files with 253 additions and 27 deletions
+2
View File
@@ -964,9 +964,11 @@ name = "polkadot-client"
version = "0.1.0"
dependencies = [
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"native-runtime 0.1.0",
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"polkadot-executor 0.1.0",
"polkadot-primitives 0.1.0",
"polkadot-serializer 0.1.0",
"polkadot-state-machine 0.1.0",
+2
View File
@@ -10,5 +10,7 @@ parking_lot = "0.4"
polkadot-primitives = { path = "../primitives", version = "0.1" }
polkadot-state-machine = { path = "../state_machine", version = "0.1" }
polkadot-serializer = { path = "../serializer" }
polkadot-executor = { path = "../executor" }
native-runtime = { path = "../native-runtime" }
triehash = "0.1"
hex-literal = "0.1"
+84
View File
@@ -35,3 +35,87 @@ pub fn construct_genesis_block(storage: &HashMap<Vec<u8>, Vec<u8>>) -> Block {
transactions: vec![],
}
}
#[cfg(test)]
mod tests {
use super::*;
use native_runtime::codec::{Slicable, Joiner};
use native_runtime::support::{one, two, Hashable};
use native_runtime::runtime::genesismap::{GenesisConfig, additional_storage_with_genesis};
use native_runtime::primitives::{AccountID, Hash, BlockNumber, Transaction,
UncheckedTransaction, Digest, Function};
use state_machine::execute;
use state_machine::OverlayedChanges;
use state_machine::backend::InMemory;
use polkadot_executor::executor;
use primitives::contract::CallData;
use primitives::ed25519::Pair;
fn secret_for(who: &AccountID) -> Option<Pair> {
match who {
x if *x == one() => Some(Pair::from_seed(b"12345678901234567890123456789012")),
x if *x == two() => Some("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60".into()),
_ => None,
}
}
fn construct_block(number: BlockNumber, parent_hash: Hash, state_root: Hash, txs: Vec<Transaction>) -> (Vec<u8>, Hash) {
use triehash::ordered_trie_root;
let transactions = txs.into_iter().map(|transaction| {
let signature = secret_for(&transaction.signed).unwrap()
.sign(&transaction.to_vec())
.inner();
UncheckedTransaction { transaction, signature }
}).collect::<Vec<_>>();
let transaction_root = ordered_trie_root(transactions.iter().map(Slicable::to_vec)).0;
let header = Header {
parent_hash,
number,
state_root,
transaction_root,
digest: Digest { logs: vec![], },
};
let hash = header.blake2_256();
(Block { header, transactions }.to_vec(), hash)
}
fn block1(genesis_hash: Hash) -> (Vec<u8>, Hash) {
construct_block(
1,
genesis_hash,
hex!("25e5b37074063ab75c889326246640729b40d0c86932edc527bc80db0e04fe5c"),
vec![Transaction {
signed: one(),
nonce: 0,
function: Function::StakingTransfer,
input_data: vec![].join(&two()).join(&69u64),
}]
)
}
#[test]
fn construct_genesis_should_work() {
let mut storage = GenesisConfig::new_simple(
vec![one(), two()], 1000
).genesis_map();
let block = construct_genesis_block(&storage);
let genesis_hash = block.header.blake2_256();
storage.extend(additional_storage_with_genesis(&block).into_iter());
let mut overlay = OverlayedChanges::default();
let backend = InMemory::from(storage);
let (b1data, _b1hash) = block1(genesis_hash);
let _ = execute(
&backend,
&mut overlay,
&executor(),
"execute_block",
&CallData(b1data)
).unwrap();
}
}
+2
View File
@@ -21,12 +21,14 @@
extern crate polkadot_primitives as primitives;
extern crate polkadot_state_machine as state_machine;
extern crate polkadot_serializer as ser;
extern crate polkadot_executor;
extern crate native_runtime;
extern crate triehash;
extern crate parking_lot;
#[macro_use] extern crate error_chain;
#[macro_use] extern crate log;
#[macro_use] extern crate hex_literal;
pub mod error;
pub mod blockchain;
-1
View File
@@ -64,7 +64,6 @@ pub struct InMemory {
inner: MemoryState, // keeps all the state in memory.
}
#[cfg(test)]
impl InMemory {
/// Create a new instance from a given storage map.
pub fn from(storage: ::std::collections::HashMap<Vec<u8>, Vec<u8>>) -> Self {
+10 -3
View File
@@ -33,13 +33,14 @@ extern crate byteorder;
use std::collections::HashMap;
use std::fmt;
use primitives::contract::{CallData};
use primitives::contract::CallData;
pub mod backend;
mod ext;
mod testing;
pub use testing::TestExternalities;
pub use ext::Ext;
/// Updates to be committed to the state.
pub enum Update {
@@ -151,12 +152,17 @@ pub trait Externalities {
/// Get the current set of authorities from storage.
fn authorities(&self) -> Result<Vec<&[u8]>, ExternalitiesError> {
(0..self.storage(b"con:aut:len")?.into_iter()
(0..self.storage(b":aut:len")?.into_iter()
.rev()
.fold(0, |acc, &i| (acc << 8) + (i as u32)))
.map(|i| self.storage(&to_keyed_vec(i, b"con:aut:".to_vec())))
.map(|i| self.storage(&to_keyed_vec(i, b":aut:".to_vec())))
.collect()
}
/// Get the runtime code.
fn code(&self) -> Result<&[u8], ExternalitiesError> {
self.storage(b":code")
}
}
/// Code execution engine.
@@ -195,6 +201,7 @@ pub fn execute<B: backend::Backend, Exec: CodeExecutor>(
};
// make a copy.
let code = externalities.storage(b":code").unwrap_or(&[]).to_vec();
use primitives::hexdisplay::HexDisplay;
exec.call(
&mut externalities,
@@ -17,7 +17,7 @@
//! 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 {}
@@ -18,7 +18,7 @@
use std::collections::HashMap;
use runtime_std::twox_128;
use codec::{KeyedVec, Slicable};
use codec::{KeyedVec, Joiner};
use support::Hashable;
use primitives::{AccountID, BlockNumber, Block};
use runtime::staking::Balance;
@@ -31,7 +31,7 @@ pub struct GenesisConfig {
pub block_time: u64,
pub session_length: BlockNumber,
pub sessions_per_era: BlockNumber,
pub bonding_duration: u64,
pub bonding_duration: BlockNumber,
pub approval_ratio: u32,
}
@@ -50,36 +50,42 @@ impl GenesisConfig {
}
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");
let wasm_runtime = include_bytes!("../../../../wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm").to_vec();
vec![
(&b":code"[..], wasm_runtime.to_vec()),
(&b"gov:apr"[..], self.approval_ratio.to_vec()),
(&b"ses:len"[..], self.session_length.to_vec()),
(&b"ses:val:len"[..], (self.validators.len() as u32).to_vec()),
(&b"con:aut:len"[..], (self.authorities.len() as u32).to_vec()),
(&b"sta:wil:len"[..], 0u32.to_vec()),
(&b"sta:spe"[..], self.sessions_per_era.to_vec()),
(&b"sta:vac"[..], (self.validators.len() as u32).to_vec()),
(&b"sta:era"[..], 0u64.to_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.to_vec(), v))
.map(|(k, v)| (k.into(), v))
.chain(self.validators.iter()
.enumerate()
.map(|(i, account)| ((i as u32).to_keyed_vec(b"ses:val:"), account.to_vec()))
.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"con:aut:"), account.to_vec()))
.map(|(i, account)| ((i as u32).to_keyed_vec(b"con:aut:"), vec![].join(account)))
).chain(self.balances.iter()
.map(|&(account, balance)| (account.to_keyed_vec(b"sta:bal:"), balance.to_vec()))
.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"con:aut: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"con:aut:"), vec![].join(account)))
)
.collect()
}
}
pub fn additional_storage_with_genesis(genesis_block: &[u8]) -> Result<HashMap<Vec<u8>, Vec<u8>>, ()> {
let h = Block::from_slice(genesis_block).ok_or(())?.header.blake2_256();
Ok(map![
twox_128(&0u64.to_keyed_vec(b"sys:old:")).to_vec() => h.to_vec()
])
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()
]
}
@@ -43,7 +43,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);
}
}
@@ -142,6 +142,130 @@ 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> {
Slicable::set_as_slice(&|out, offset|
runtime_std::read_storage(key, out, offset) >= out.len()
)
}
/// 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::*;