diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index ad94382aa2..bf903c9e45 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -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", diff --git a/substrate/client/Cargo.toml b/substrate/client/Cargo.toml index 524429d1af..8e2f3f699b 100644 --- a/substrate/client/Cargo.toml +++ b/substrate/client/Cargo.toml @@ -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" diff --git a/substrate/client/src/genesis.rs b/substrate/client/src/genesis.rs index 8aa6d9409a..9e7974abb5 100644 --- a/substrate/client/src/genesis.rs +++ b/substrate/client/src/genesis.rs @@ -35,3 +35,87 @@ pub fn construct_genesis_block(storage: &HashMap, Vec>) -> 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 { + 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) -> (Vec, 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::>(); + + 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, 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(); + } +} diff --git a/substrate/client/src/lib.rs b/substrate/client/src/lib.rs index 13f881167b..c20c01e44e 100644 --- a/substrate/client/src/lib.rs +++ b/substrate/client/src/lib.rs @@ -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; diff --git a/substrate/state_machine/src/backend.rs b/substrate/state_machine/src/backend.rs index 4f5ff5d18f..3efaf67953 100644 --- a/substrate/state_machine/src/backend.rs +++ b/substrate/state_machine/src/backend.rs @@ -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>) -> Self { diff --git a/substrate/state_machine/src/lib.rs b/substrate/state_machine/src/lib.rs index e497a20474..f5db302063 100644 --- a/substrate/state_machine/src/lib.rs +++ b/substrate/state_machine/src/lib.rs @@ -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, 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( }; // make a copy. let code = externalities.storage(b":code").unwrap_or(&[]).to_vec(); + use primitives::hexdisplay::HexDisplay; exec.call( &mut externalities, diff --git a/substrate/wasm-runtime/polkadot/src/runtime/consensus.rs b/substrate/wasm-runtime/polkadot/src/runtime/consensus.rs index 51666666cf..abaa24b240 100644 --- a/substrate/wasm-runtime/polkadot/src/runtime/consensus.rs +++ b/substrate/wasm-runtime/polkadot/src/runtime/consensus.rs @@ -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 {} diff --git a/substrate/wasm-runtime/polkadot/src/runtime/genesismap.rs b/substrate/wasm-runtime/polkadot/src/runtime/genesismap.rs index e10b5e4557..20448eb093 100644 --- a/substrate/wasm-runtime/polkadot/src/runtime/genesismap.rs +++ b/substrate/wasm-runtime/polkadot/src/runtime/genesismap.rs @@ -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> { - 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, Vec>, ()> { - 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> { + use codec::Slicable; + map![ + twox_128(&0u64.to_keyed_vec(b"sys:old:")).to_vec() => genesis_block.header.blake2_256().to_vec() + ] } diff --git a/substrate/wasm-runtime/polkadot/src/runtime/system.rs b/substrate/wasm-runtime/polkadot/src/runtime/system.rs index a3d3a3a03b..3bad541362 100644 --- a/substrate/wasm-runtime/polkadot/src/runtime/system.rs +++ b/substrate/wasm-runtime/polkadot/src/runtime/system.rs @@ -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); } } diff --git a/substrate/wasm-runtime/polkadot/src/support/storage.rs b/substrate/wasm-runtime/polkadot/src/support/storage.rs index a0f2a93b49..aada8c8ae0 100644 --- a/substrate/wasm-runtime/polkadot/src/support/storage.rs +++ b/substrate/wasm-runtime/polkadot/src/support/storage.rs @@ -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(key: &[u8]) -> Option { + 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(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(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>(key: &[u8], default_value: F) -> T { + get(key).unwrap_or_else(default_value) + } + + /// Please `value` in storage under `key`. + pub fn put(key: &[u8], value: &T) { + value.as_slice_then(|slice| runtime_std::set_storage(key, slice)); + } + + /// Please `value` in storage under `key`. + pub fn place(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(key: &[u8]) -> Option { + 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(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(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>(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 { + 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 { + (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::*; diff --git a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm index 745c95ccf5..16c8ade8e3 100644 Binary files a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm and b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm differ diff --git a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm index afb2e94711..9aa3668406 100644 Binary files a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm and b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm differ