diff --git a/Cargo.lock b/Cargo.lock
index c139749441f71..8291eb6d15c1e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -964,11 +964,15 @@ 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",
+ "triehash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -986,6 +990,8 @@ dependencies = [
"assert_matches 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"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",
"parity-wasm 0.15.4 (registry+https://github.com/rust-lang/crates.io-index)",
"polkadot-primitives 0.1.0",
diff --git a/client/Cargo.toml b/client/Cargo.toml
index 468cf42de10c8..8e2f3f699ba3d 100644
--- a/client/Cargo.toml
+++ b/client/Cargo.toml
@@ -10,3 +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/client/src/genesis.rs b/client/src/genesis.rs
new file mode 100644
index 0000000000000..cb6f5a6df3a0c
--- /dev/null
+++ b/client/src/genesis.rs
@@ -0,0 +1,142 @@
+// 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 .
+
+//! Tool for creating the genesis block.
+
+use std::collections::HashMap;
+use native_runtime::primitives::{Block, Header};
+use triehash::trie_root;
+
+/// Create a genesis block, given the initial storage.
+pub fn construct_genesis_block(storage: &HashMap, Vec>) -> Block {
+ let state_root = trie_root(storage.clone().into_iter()).0;
+ let header = Header {
+ parent_hash: Default::default(),
+ number: 0,
+ state_root,
+ transaction_root: trie_root(vec![].into_iter()).0,
+ digest: Default::default(),
+ };
+ Block {
+ header,
+ 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(backend: &InMemory, 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 mut header = Header {
+ parent_hash,
+ number,
+ state_root,
+ transaction_root,
+ digest: Digest { logs: vec![], },
+ };
+ let hash = header.blake2_256();
+
+ let mut overlay = OverlayedChanges::default();
+
+ for tx in transactions.iter() {
+ header = Header::from_slice(&execute(
+ backend,
+ &mut overlay,
+ &executor(),
+ "execute_transaction",
+ &CallData(vec![].join(&header).join(tx))
+ ).unwrap()).unwrap();
+ }
+
+ header = Header::from_slice(&execute(
+ backend,
+ &mut overlay,
+ &executor(),
+ "finalise_block",
+ &CallData(vec![].join(&header))
+ ).unwrap()).unwrap();
+
+ (vec![].join(&Block { header, transactions }), hash)
+ }
+
+ fn block1(genesis_hash: Hash, backend: &InMemory) -> (Vec, Hash) {
+ construct_block(
+ backend,
+ 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, &backend);
+
+ let _ = execute(
+ &backend,
+ &mut overlay,
+ &executor(),
+ "execute_block",
+ &CallData(b1data)
+ ).unwrap();
+ }
+}
diff --git a/client/src/lib.rs b/client/src/lib.rs
index 2773085ecee54..c20c01e44e925 100644
--- a/client/src/lib.rs
+++ b/client/src/lib.rs
@@ -21,16 +21,24 @@
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;
pub mod backend;
pub mod in_mem;
+mod genesis;
+
+pub use genesis::construct_genesis_block;
+
pub use blockchain::Info as ChainInfo;
pub use blockchain::BlockId;
diff --git a/executor/Cargo.toml b/executor/Cargo.toml
index 41fdef97057f6..0e535f1eba9f0 100644
--- a/executor/Cargo.toml
+++ b/executor/Cargo.toml
@@ -16,6 +16,8 @@ rustc-hex = "1.0.0"
native-runtime = { path = "../native-runtime", version = "0.1" }
runtime-std = { path = "../native-runtime/std", version = "0.1" }
triehash = "0.1.0"
+hex-literal = "0.1.0"
+log = "0.3"
[dev-dependencies]
assert_matches = "1.1"
diff --git a/executor/src/lib.rs b/executor/src/lib.rs
index e4ed7f95b0e8a..d93f46052a197 100644
--- a/executor/src/lib.rs
+++ b/executor/src/lib.rs
@@ -37,6 +37,11 @@ extern crate rustc_hex;
extern crate native_runtime;
extern crate runtime_std;
extern crate triehash;
+#[macro_use] extern crate log;
+
+#[cfg(test)]
+#[macro_use]
+extern crate hex_literal;
#[macro_use]
extern crate error_chain;
diff --git a/executor/src/native_executor.rs b/executor/src/native_executor.rs
index 6cf7ac6c313c6..d45efd9031dc4 100644
--- a/executor/src/native_executor.rs
+++ b/executor/src/native_executor.rs
@@ -29,6 +29,7 @@ impl CodeExecutor for NativeExecutor {
runtime_std::with_externalities(ext, || match method {
"execute_block" => safe_call(|| runtime::execute_block(&data.0)),
"execute_transaction" => safe_call(|| runtime::execute_transaction(&data.0)),
+ "finalise_block" => safe_call(|| runtime::finalise_block(&data.0)),
_ => Err(ErrorKind::MethodNotFound(method.to_owned()).into()),
})
} else {
@@ -42,14 +43,26 @@ impl CodeExecutor for NativeExecutor {
mod tests {
use super::*;
use runtime_std::TestExternalities;
- use native_runtime::codec::KeyedVec;
- use native_runtime::support::{one, two, StaticHexInto};
+ use native_runtime::codec::{KeyedVec, Joiner, Slicable};
+ use native_runtime::support::{one, two, Hashable};
+ use native_runtime::primitives::*;
use native_runtime::runtime::staking::balance;
use primitives::twox_128;
const BLOATY_CODE: &[u8] = include_bytes!("../../wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm");
const COMPACT_CODE: &[u8] = include_bytes!("../../wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm");
- fn tx() -> Vec { "679fcf0a846b4224c84ecad7d91a26241c46d00cb53d6480a363274e8965ee34b0b80b4b2e3836d3d8f8f12c0c1aef7350af587d9aee3883561d11726068ac0a2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000228000000d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000".convert() }
+ fn tx() -> UncheckedTransaction {
+ let transaction = Transaction {
+ signed: one(),
+ nonce: 0,
+ function: Function::StakingTransfer,
+ input_data: two().to_vec().join(&69u64),
+ };
+ let signature = secret_for(&transaction.signed).unwrap()
+ .sign(&transaction.to_vec())
+ .inner();
+ UncheckedTransaction { transaction, signature }
+ }
#[test]
fn panic_execution_with_foreign_code_gives_error() {
@@ -58,7 +71,7 @@ mod tests {
twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0]
], };
- let r = NativeExecutor.call(&mut t, BLOATY_CODE, "execute_transaction", &CallData(tx()));
+ let r = NativeExecutor.call(&mut t, BLOATY_CODE, "execute_transaction", &CallData(vec![].join(&Header::from_block_number(1u64)).join(&tx())));
assert!(r.is_err());
}
@@ -69,7 +82,7 @@ mod tests {
twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0]
], };
- let r = NativeExecutor.call(&mut t, COMPACT_CODE, "execute_transaction", &CallData(tx()));
+ let r = NativeExecutor.call(&mut t, COMPACT_CODE, "execute_transaction", &CallData(vec![].join(&Header::from_block_number(1u64)).join(&tx())));
assert!(r.is_err());
}
@@ -82,7 +95,7 @@ mod tests {
twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0]
], };
- let r = NativeExecutor.call(&mut t, COMPACT_CODE, "execute_transaction", &CallData(tx()));
+ let r = NativeExecutor.call(&mut t, COMPACT_CODE, "execute_transaction", &CallData(vec![].join(&Header::from_block_number(1u64)).join(&tx())));
assert!(r.is_ok());
runtime_std::with_externalities(&mut t, || {
@@ -100,7 +113,7 @@ mod tests {
twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0]
], };
- let r = NativeExecutor.call(&mut t, BLOATY_CODE, "execute_transaction", &CallData(tx()));
+ let r = NativeExecutor.call(&mut t, BLOATY_CODE, "execute_transaction", &CallData(vec![].join(&Header::from_block_number(1u64)).join(&tx())));
assert!(r.is_ok());
runtime_std::with_externalities(&mut t, || {
@@ -108,4 +121,143 @@ mod tests {
assert_eq!(balance(&two), 69);
});
}
+
+ fn new_test_ext() -> TestExternalities {
+ let one = one();
+ let two = two();
+ let three = [3u8; 32];
+
+ TestExternalities { storage: map![
+ twox_128(&0u64.to_keyed_vec(b"sys:old:")).to_vec() => [69u8; 32].to_vec(),
+ twox_128(b"gov:apr").to_vec() => vec![].join(&667u32),
+ twox_128(b"ses:len").to_vec() => vec![].join(&2u64),
+ twox_128(b"ses:val:len").to_vec() => vec![].join(&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![].join(&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![].join(&2u64),
+ twox_128(b"sta:vac").to_vec() => vec![].join(&3u64),
+ twox_128(b"sta:era").to_vec() => vec![].join(&0u64),
+ twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0]
+ ], }
+ }
+
+ 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() -> (Vec, Hash) {
+ construct_block(
+ 1,
+ [69u8; 32],
+ hex!("2481853da20b9f4322f34650fea5f240dcbfb266d02db94bfa0153c31f4a29db"),
+ vec![Transaction {
+ signed: one(),
+ nonce: 0,
+ function: Function::StakingTransfer,
+ input_data: vec![].join(&two()).join(&69u64),
+ }]
+ )
+ }
+
+ fn block2() -> (Vec, Hash) {
+ construct_block(
+ 2,
+ block1().1,
+ hex!("2e69e4405a13981224078ad5355c68401bf56d0fe3f14a3536734666e6a8a047"),
+ vec![
+ Transaction {
+ signed: two(),
+ nonce: 0,
+ function: Function::StakingTransfer,
+ input_data: vec![].join(&one()).join(&5u64),
+ },
+ Transaction {
+ signed: one(),
+ nonce: 1,
+ function: Function::StakingTransfer,
+ input_data: vec![].join(&two()).join(&15u64),
+ }
+ ]
+ )
+ }
+
+ #[test]
+ fn test_execution_works() {
+ let mut t = new_test_ext();
+ println!("Testing Wasm...");
+ let r = WasmExecutor.call(&mut t, COMPACT_CODE, "run_tests", &CallData(block2().0));
+ assert!(r.is_ok());
+ }
+
+ #[test]
+ fn full_native_block_import_works() {
+ let mut t = new_test_ext();
+
+ NativeExecutor.call(&mut t, COMPACT_CODE, "execute_block", &CallData(block1().0)).unwrap();
+
+ runtime_std::with_externalities(&mut t, || {
+ assert_eq!(balance(&one()), 42);
+ assert_eq!(balance(&two()), 69);
+ });
+
+ NativeExecutor.call(&mut t, COMPACT_CODE, "execute_block", &CallData(block2().0)).unwrap();
+
+ runtime_std::with_externalities(&mut t, || {
+ assert_eq!(balance(&one()), 32);
+ assert_eq!(balance(&two()), 79);
+ });
+ }
+
+ #[test]
+ fn full_wasm_block_import_works() {
+ let mut t = new_test_ext();
+
+ WasmExecutor.call(&mut t, COMPACT_CODE, "execute_block", &CallData(block1().0)).unwrap();
+
+ runtime_std::with_externalities(&mut t, || {
+ assert_eq!(balance(&one()), 42);
+ assert_eq!(balance(&two()), 69);
+ });
+
+ WasmExecutor.call(&mut t, COMPACT_CODE, "execute_block", &CallData(block2().0)).unwrap();
+
+ runtime_std::with_externalities(&mut t, || {
+ assert_eq!(balance(&one()), 32);
+ assert_eq!(balance(&two()), 79);
+ });
+ }
}
diff --git a/executor/src/wasm_executor.rs b/executor/src/wasm_executor.rs
index e1e4f0b6d9273..6ad896dfbea6c 100644
--- a/executor/src/wasm_executor.rs
+++ b/executor/src/wasm_executor.rs
@@ -38,7 +38,7 @@ struct Heap {
impl Heap {
fn new() -> Self {
Heap {
- end: 1024,
+ end: 32768,
}
}
fn allocate(&mut self, size: u32) -> u32 {
@@ -94,17 +94,17 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
ext_print_utf8(utf8_data: *const u8, utf8_len: u32) => {
if let Ok(utf8) = this.memory.get(utf8_data, utf8_len as usize) {
if let Ok(message) = String::from_utf8(utf8) {
- println!("Runtime: {}", message);
+ info!(target: "runtime", "{}", message);
}
}
},
ext_print_hex(data: *const u8, len: u32) => {
if let Ok(hex) = this.memory.get(data, len as usize) {
- println!("Runtime: {}", HexDisplay::from(&hex));
+ info!(target: "runtime", "{}", HexDisplay::from(&hex));
}
},
ext_print_num(number: u64) => {
- println!("Runtime: {}", number);
+ info!(target: "runtime", "{}", number);
},
ext_memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 => {
let sl1 = this.memory.get(s1, n as usize).map_err(|_| DummyUserError)?;
@@ -118,34 +118,35 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
ext_memcpy(dest: *mut u8, src: *const u8, count: usize) -> *mut u8 => {
this.memory.copy_nonoverlapping(src as usize, dest as usize, count as usize)
.map_err(|_| DummyUserError)?;
- println!("memcpy {} from {}, {} bytes", dest, src, count);
+ trace!(target: "runtime-std", "memcpy {} from {}, {} bytes", dest, src, count);
dest
},
ext_memmove(dest: *mut u8, src: *const u8, count: usize) -> *mut u8 => {
this.memory.copy(src as usize, dest as usize, count as usize)
.map_err(|_| DummyUserError)?;
- println!("memmove {} from {}, {} bytes", dest, src, count);
+ trace!(target: "runtime-std", "memmove {} from {}, {} bytes", dest, src, count);
dest
},
ext_memset(dest: *mut u8, val: u32, count: usize) -> *mut u8 => {
this.memory.clear(dest as usize, val as u8, count as usize)
.map_err(|_| DummyUserError)?;
- println!("memset {} with {}, {} bytes", dest, val, count);
+ trace!(target: "runtime-std", "memset {} with {}, {} bytes", dest, val, count);
dest
},
ext_malloc(size: usize) -> *mut u8 => {
let r = this.heap.allocate(size);
- println!("malloc {} bytes at {}", size, r);
+ trace!(target: "runtime-std", "malloc {} bytes at {}", size, r);
r
},
ext_free(addr: *mut u8) => {
this.heap.deallocate(addr);
- println!("free {}", addr)
+ trace!(target: "runtime-std", "free {}", addr)
},
ext_set_storage(key_data: *const u8, key_len: u32, value_data: *const u8, value_len: u32) => {
- if let (Ok(key), Ok(value)) = (this.memory.get(key_data, key_len as usize), this.memory.get(value_data, value_len as usize)) {
- this.ext.set_storage(key, value);
- }
+ let key = this.memory.get(key_data, key_len as usize).map_err(|_| DummyUserError)?;
+ let value = this.memory.get(value_data, value_len as usize).map_err(|_| DummyUserError)?;
+ info!(target: "runtime", "Setting storage: {} -> {}", HexDisplay::from(&key), HexDisplay::from(&value));
+ this.ext.set_storage(key, value);
},
ext_get_allocated_storage(key_data: *const u8, key_len: u32, written_out: *mut u32) -> *mut u8 => {
let key = this.memory.get(key_data, key_len as usize).map_err(|_| DummyUserError)?;
@@ -160,6 +161,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
ext_get_storage_into(key_data: *const u8, key_len: u32, value_data: *mut u8, value_len: u32, value_offset: u32) -> u32 => {
let key = this.memory.get(key_data, key_len as usize).map_err(|_| DummyUserError)?;
let value = this.ext.storage(&key).map_err(|_| DummyUserError)?;
+ info!(target: "runtime", "Getting storage: {} ( -> {})", HexDisplay::from(&key), HexDisplay::from(&value));
let value = &value[value_offset as usize..];
let written = ::std::cmp::min(value_len as usize, value.len());
this.memory.set(value_data, &value[..written]).map_err(|_| DummyUserError)?;
@@ -169,7 +171,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
let r = this.ext.storage_root();
this.memory.set(result, &r[..]).map_err(|_| DummyUserError)?;
},
- ext_enumerated_trie_root(values_data: *const u8, values_len: u32, lens_data: *const u32, lens_len: u32, result: *mut u8) => {
+ ext_enumerated_trie_root(values_data: *const u8, lens_data: *const u32, lens_len: u32, result: *mut u8) => {
let values = (0..lens_len)
.map(|i| this.memory.read_primitive(lens_data + i * 4))
.collect::<::std::result::Result, DummyUserError>>()?
@@ -188,9 +190,17 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
},
ext_twox_128(data: *const u8, len: u32, out: *mut u8) => {
let result = if len == 0 {
+ info!(target: "runtime", "XXhash: ''");
twox_128(&[0u8; 0])
} else {
- twox_128(&this.memory.get(data, len as usize).map_err(|_| DummyUserError)?)
+ let key = this.memory.get(data, len as usize).map_err(|_| DummyUserError)?;
+ let hashed_key = twox_128(&key);
+ if let Ok(skey) = ::std::str::from_utf8(&key) {
+ info!(target: "runtime", "XXhash: {} -> {}", skey, HexDisplay::from(&hashed_key));
+ } else {
+ info!(target: "runtime", "XXhash: {} -> {}", HexDisplay::from(&key), HexDisplay::from(&hashed_key));
+ }
+ hashed_key
};
this.memory.set(out, &result).map_err(|_| DummyUserError)?;
},
@@ -282,8 +292,9 @@ mod tests {
use rustc_hex::FromHex;
use primitives::{blake2_256, twox_128};
use runtime_std::{self, TestExternalities};
- use native_runtime::support::{one, two, StaticHexInto};
- use native_runtime::codec::KeyedVec;
+ use native_runtime::support::{one, two};
+ use native_runtime::primitives::{UncheckedTransaction, AccountID, Header};
+ use native_runtime::codec::{Joiner, KeyedVec};
use native_runtime::runtime::staking::balance;
#[test]
@@ -392,7 +403,30 @@ mod tests {
);
}
- fn tx() -> Vec { "679fcf0a846b4224c84ecad7d91a26241c46d00cb53d6480a363274e8965ee34b0b80b4b2e3836d3d8f8f12c0c1aef7350af587d9aee3883561d11726068ac0a2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000228000000d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000".convert() }
+ 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 tx() -> UncheckedTransaction {
+ use native_runtime::codec::{Joiner, Slicable};
+ use native_runtime::support::{one, two};
+ use native_runtime::primitives::*;
+ let transaction = Transaction {
+ signed: one(),
+ nonce: 0,
+ function: Function::StakingTransfer,
+ input_data: two().to_vec().join(&69u64),
+ };
+ let signature = secret_for(&transaction.signed).unwrap()
+ .sign(&transaction.to_vec())
+ .inner();
+ UncheckedTransaction { transaction, signature }
+ }
#[test]
fn panic_execution_gives_error() {
@@ -402,7 +436,7 @@ mod tests {
], };
let foreign_code = include_bytes!("../../wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm");
- let r = WasmExecutor.call(&mut t, &foreign_code[..], "execute_transaction", &CallData(tx()));
+ let r = WasmExecutor.call(&mut t, &foreign_code[..], "execute_transaction", &CallData(vec![].join(&Header::from_block_number(1u64)).join(&tx())));
assert!(r.is_err());
}
@@ -416,7 +450,7 @@ mod tests {
], };
let foreign_code = include_bytes!("../../wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm");
- let r = WasmExecutor.call(&mut t, &foreign_code[..], "execute_transaction", &CallData(tx()));
+ let r = WasmExecutor.call(&mut t, &foreign_code[..], "execute_transaction", &CallData(vec![].join(&Header::from_block_number(1u64)).join(&tx())));
assert!(r.is_ok());
runtime_std::with_externalities(&mut t, || {
diff --git a/primitives/src/ed25519.rs b/primitives/src/ed25519.rs
index b28e0bde6e2cc..5bfffc2411d43 100644
--- a/primitives/src/ed25519.rs
+++ b/primitives/src/ed25519.rs
@@ -55,6 +55,11 @@ impl Signature {
r.copy_from_slice(data);
Signature(r)
}
+
+ /// Get the inner part.
+ pub fn inner(self) -> [u8; 64] {
+ self.0
+ }
}
impl AsRef<[u8; 64]> for Signature {
@@ -219,17 +224,12 @@ mod test {
let public = pair.public();
assert_eq!(public, "2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee".into());
let message = b"Something important";
- let signature = pair.sign(&message[..]);
- assert!(signature.verify(&message[..], &public));
- }
-
- #[test]
- fn can_sign_transaction() {
- let pair = Pair::from_seed(b"12345678901234567890123456789012");
let public = pair.public();
assert_eq!(public, "2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee".into());
- let message = FromHex::from_hex("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000228000000d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000").unwrap();
+ let message = FromHex::from_hex("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000002228000000d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000").unwrap();
let signature = pair.sign(&message[..]);
+ use hexdisplay::HexDisplay;
+ println!("Correct signature: {}", HexDisplay::from(&signature.0));
assert!(signature.verify(&message[..], &public));
}
}
diff --git a/state_machine/src/backend.rs b/state_machine/src/backend.rs
index 5057339ce943e..3efaf67953c70 100644
--- a/state_machine/src/backend.rs
+++ b/state_machine/src/backend.rs
@@ -23,10 +23,7 @@ use triehash::sec_trie_root;
use super::{Update, MemoryState};
/// Output of a commit.
-pub struct Committed {
- /// Root of the storage tree after changes committed.
- pub storage_tree_root: H256,
-}
+pub struct Committed {}
/// A state backend is used to read state data and can have changes committed
/// to it.
@@ -67,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 {
@@ -90,17 +86,7 @@ impl Backend for InMemory {
where I: IntoIterator-
{
self.inner.update(changes);
-
- // fully recalculate trie roots.
- let storage_tree_root = H256(sec_trie_root(
- self.inner.storage.iter()
- .map(|(k, v)| (k.to_vec(), v.clone()))
- .collect()
- ).0);
-
- Committed {
- storage_tree_root,
- }
+ Committed {}
}
fn pairs(&self) -> Vec<(&[u8], &[u8])> {
diff --git a/state_machine/src/lib.rs b/state_machine/src/lib.rs
index e497a20474b55..dcb8a3b4c88d6 100644
--- a/state_machine/src/lib.rs
+++ b/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":auth: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":auth:".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,
@@ -253,17 +260,17 @@ mod tests {
assert_eq!(ext.authorities(), Ok(vec![]));
- ext.set_storage(b"con:aut:len".to_vec(), vec![0u8; 4]);
+ ext.set_storage(b":auth:len".to_vec(), vec![0u8; 4]);
assert_eq!(ext.authorities(), Ok(vec![]));
- ext.set_storage(b"con:aut:len".to_vec(), vec![1u8, 0, 0, 0]);
+ ext.set_storage(b":auth:len".to_vec(), vec![1u8, 0, 0, 0]);
assert_eq!(ext.authorities(), Ok(vec![&[][..]]));
- ext.set_storage(b"con:aut:\0\0\0\0".to_vec(), b"first".to_vec());
+ ext.set_storage(b":auth:\0\0\0\0".to_vec(), b"first".to_vec());
assert_eq!(ext.authorities(), Ok(vec![&b"first"[..]]));
- ext.set_storage(b"con:aut:len".to_vec(), vec![2u8, 0, 0, 0]);
- ext.set_storage(b"con:aut:\x01\0\0\0".to_vec(), b"second".to_vec());
+ ext.set_storage(b":auth:len".to_vec(), vec![2u8, 0, 0, 0]);
+ ext.set_storage(b":auth:\x01\0\0\0".to_vec(), b"second".to_vec());
assert_eq!(ext.authorities(), Ok(vec![&b"first"[..], &b"second"[..]]));
}
diff --git a/wasm-runtime/polkadot/src/codec/slicable.rs b/wasm-runtime/polkadot/src/codec/slicable.rs
index 0f1ef812a67a9..8f062bc6541f8 100644
--- a/wasm-runtime/polkadot/src/codec/slicable.rs
+++ b/wasm-runtime/polkadot/src/codec/slicable.rs
@@ -84,7 +84,8 @@ impl Slicable for Vec {
fn set_as_slice bool>(fill_slice: &F) -> Option {
u32::set_as_slice(fill_slice).and_then(|len| {
let mut v = Vec::with_capacity(len as usize);
- unsafe { v.set_len(len as usize); }
+ v.resize(len as usize, 0);
+// unsafe { v.set_len(len as usize); }
if fill_slice(&mut v, 4) {
Some(v)
} else {
@@ -106,7 +107,7 @@ impl NonTrivialSlicable for Vec where Vec: Slicable {}
impl Slicable for Vec {
fn from_slice(value: &[u8]) -> Option {
- let len = Self::size_of(&value[0..4])?;
+ let len = Self::size_of(value)?;
let mut off = 4;
let mut r = Vec::new();
while off < len {
diff --git a/wasm-runtime/polkadot/src/lib.rs b/wasm-runtime/polkadot/src/lib.rs
index 677272e93f472..eefa6e44a875b 100644
--- a/wasm-runtime/polkadot/src/lib.rs
+++ b/wasm-runtime/polkadot/src/lib.rs
@@ -36,8 +36,9 @@ pub mod primitives;
pub mod runtime;
use runtime_std::prelude::*;
-use codec::Slicable;
-use primitives::{Block, UncheckedTransaction};
+use codec::{Slicable, Joiner};
+use runtime_std::print;
+use primitives::{Block, Header, UncheckedTransaction};
/// Execute a block, with `input` being the canonical serialisation of the block. Returns the
/// empty vector.
@@ -48,9 +49,27 @@ pub fn execute_block(input: &[u8]) -> Vec {
/// Execute a given, serialised, transaction. Returns the empty vector.
pub fn execute_transaction(input: &[u8]) -> Vec {
- let utx = UncheckedTransaction::from_slice(input).unwrap();
- runtime::system::internal::execute_transaction(&utx);
- Vec::new()
+ let header = Header::from_slice(input).unwrap();
+ let utx = UncheckedTransaction::from_slice(&input[Header::size_of(input).unwrap()..]).unwrap();
+ let header = runtime::system::internal::execute_transaction(&utx, header);
+ Vec::new().join(&header)
+}
+
+/// Execute a given, serialised, transaction. Returns the empty vector.
+pub fn finalise_block(input: &[u8]) -> Vec {
+ let header = Header::from_slice(input).unwrap();
+ let header = runtime::system::internal::finalise_block(header);
+ Vec::new().join(&header)
+}
+
+/// Run whatever tests we have.
+pub fn run_tests(input: &[u8]) -> Vec {
+ print("run_tests...");
+ let block = Block::from_slice(input).unwrap();
+ print("deserialised block.");
+ let stxs = block.transactions.iter().map(Slicable::to_vec).collect::>();
+ print("reserialised transactions.");
+ [stxs.len() as u8].to_vec()
}
-impl_stubs!(execute_block, execute_transaction);
+impl_stubs!(execute_block, execute_transaction, finalise_block, run_tests);
diff --git a/wasm-runtime/polkadot/src/primitives/digest.rs b/wasm-runtime/polkadot/src/primitives/digest.rs
index 18107460b0771..5ce92774200a3 100644
--- a/wasm-runtime/polkadot/src/primitives/digest.rs
+++ b/wasm-runtime/polkadot/src/primitives/digest.rs
@@ -18,8 +18,8 @@
use runtime_std::prelude::*;
-#[derive(Clone, Default)]
-#[cfg_attr(feature = "with-std", derive(PartialEq, Debug))]
+#[derive(Clone, Default, PartialEq)]
+#[cfg_attr(feature = "with-std", derive(Debug))]
/// The digest of a block, useful for light-clients.
pub struct Digest {
/// All logs that have happened in the block.
diff --git a/wasm-runtime/polkadot/src/primitives/function.rs b/wasm-runtime/polkadot/src/primitives/function.rs
index e906cdc7186aa..8d45a71df79d2 100644
--- a/wasm-runtime/polkadot/src/primitives/function.rs
+++ b/wasm-runtime/polkadot/src/primitives/function.rs
@@ -25,13 +25,13 @@ use runtime::{staking, session, timestamp, governance};
#[cfg_attr(feature = "with-std", derive(PartialEq, Debug))]
#[repr(u8)]
pub enum Function {
- StakingStake = 0,
- StakingUnstake = 1,
- StakingTransfer = 2,
- SessionSetKey = 3,
- TimestampSet = 4,
- GovernancePropose = 5,
- GovernanceApprove = 6,
+ TimestampSet = 0x00,
+ SessionSetKey = 0x10,
+ StakingStake = 0x20,
+ StakingUnstake = 0x21,
+ StakingTransfer = 0x22,
+ GovernancePropose = 0x30,
+ GovernanceApprove = 0x31,
}
impl Function {
@@ -41,11 +41,7 @@ impl Function {
let functions = [Function::StakingStake, Function::StakingUnstake,
Function::StakingTransfer, Function::SessionSetKey, Function::TimestampSet,
Function::GovernancePropose, Function::GovernanceApprove];
- if (value as usize) < functions.len() {
- Some(functions[value as usize])
- } else {
- None
- }
+ functions.iter().map(|&f| f).find(|&f| value == f as u8)
}
}
diff --git a/wasm-runtime/polkadot/src/primitives/header.rs b/wasm-runtime/polkadot/src/primitives/header.rs
index c97d5ebf29743..2f624cadd6fab 100644
--- a/wasm-runtime/polkadot/src/primitives/header.rs
+++ b/wasm-runtime/polkadot/src/primitives/header.rs
@@ -37,6 +37,19 @@ pub struct Header {
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: BlockNumber) -> Self {
+ Header {
+ parent_hash: Default::default(),
+ number,
+ state_root: Default::default(),
+ transaction_root: Default::default(),
+ digest: Default::default(),
+ }
+ }
+}
+
impl Slicable for Header {
fn from_slice(value: &[u8]) -> Option {
let mut reader = StreamReader::new(value);
diff --git a/wasm-runtime/polkadot/src/primitives/proposal.rs b/wasm-runtime/polkadot/src/primitives/proposal.rs
index 1b8aa6b13e7d3..d6b26bb8e327c 100644
--- a/wasm-runtime/polkadot/src/primitives/proposal.rs
+++ b/wasm-runtime/polkadot/src/primitives/proposal.rs
@@ -27,12 +27,17 @@ use runtime::{system, governance, staking, session};
#[cfg_attr(feature = "with-std", derive(PartialEq, Debug))]
#[repr(u8)]
pub enum InternalFunction {
- SystemSetCode = 0,
- StakingSetSessionsPerEra = 1,
- StakingSetBondingDuration = 2,
- StakingSetValidatorCount = 3,
- GovernanceSetApprovalPpmRequired = 4,
- SessionSetLength = 5,
+ SystemSetCode = 0x00,
+
+ SessionSetLength = 0x10,
+ SessionForceNewSession = 0x11,
+
+ StakingSetSessionsPerEra = 0x20,
+ StakingSetBondingDuration = 0x21,
+ StakingSetValidatorCount = 0x22,
+ StakingForceNewEra = 0x23,
+
+ GovernanceSetApprovalPpmRequired = 0x30,
}
impl InternalFunction {
@@ -41,17 +46,15 @@ impl InternalFunction {
use self::*;
let functions = [
InternalFunction::SystemSetCode,
+ InternalFunction::SessionSetLength,
+ InternalFunction::SessionForceNewSession,
InternalFunction::StakingSetSessionsPerEra,
InternalFunction::StakingSetBondingDuration,
InternalFunction::StakingSetValidatorCount,
+ InternalFunction::StakingForceNewEra,
InternalFunction::GovernanceSetApprovalPpmRequired,
- InternalFunction::SessionSetLength
];
- if (value as usize) < functions.len() {
- Some(functions[value as usize])
- } else {
- None
- }
+ functions.iter().map(|&f| f).find(|&f| value == f as u8)
}
}
@@ -93,6 +96,13 @@ impl Proposal {
let code: Vec = params.read().unwrap();
system::privileged::set_code(&code);
}
+ InternalFunction::SessionSetLength => {
+ let value = params.read().unwrap();
+ session::privileged::set_length(value);
+ }
+ InternalFunction::SessionForceNewSession => {
+ session::privileged::force_new_session();
+ }
InternalFunction::StakingSetSessionsPerEra => {
let value = params.read().unwrap();
staking::privileged::set_sessions_per_era(value);
@@ -105,14 +115,13 @@ impl Proposal {
let value = params.read().unwrap();
staking::privileged::set_validator_count(value);
}
+ InternalFunction::StakingForceNewEra => {
+ staking::privileged::force_new_era();
+ }
InternalFunction::GovernanceSetApprovalPpmRequired => {
let value = params.read().unwrap();
governance::privileged::set_approval_ppm_required(value);
}
- InternalFunction::SessionSetLength => {
- let value = params.read().unwrap();
- session::privileged::set_length(value);
- }
}
}
}
diff --git a/wasm-runtime/polkadot/src/primitives/tests.rs b/wasm-runtime/polkadot/src/primitives/tests.rs
index fdb600a5bbd29..9b17672eb1b7e 100644
--- a/wasm-runtime/polkadot/src/primitives/tests.rs
+++ b/wasm-runtime/polkadot/src/primitives/tests.rs
@@ -35,7 +35,7 @@ fn serialise_transaction_works() {
assert_eq!(serialised, vec![
1u8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
69, 0, 0, 0, 0, 0, 0, 0,
- 2,
+ 34,
40, 0, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
69, 0, 0, 0, 0, 0, 0, 0
@@ -55,7 +55,7 @@ fn deserialise_transaction_works() {
let data = [
1u8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
69, 0, 0, 0, 0, 0, 0, 0,
- 2,
+ 34,
40, 0, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
69, 0, 0, 0, 0, 0, 0, 0
@@ -162,7 +162,7 @@ fn serialise_block_works() {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
69, 0, 0, 0, 0, 0, 0, 0,
- 2,
+ 34,
40, 0, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
69, 0, 0, 0, 0, 0, 0, 0,
@@ -170,7 +170,7 @@ fn serialise_block_works() {
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
42, 0, 0, 0, 0, 0, 0, 0,
- 0,
+ 32,
0, 0, 0, 0
]);
}
@@ -225,7 +225,7 @@ fn deserialise_block_works() {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
69, 0, 0, 0, 0, 0, 0, 0,
- 2,
+ 34,
40, 0, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
69, 0, 0, 0, 0, 0, 0, 0,
@@ -233,7 +233,7 @@ fn deserialise_block_works() {
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
42, 0, 0, 0, 0, 0, 0, 0,
- 0,
+ 32,
0, 0, 0, 0
];
let deserialised = Block::from_slice(&data).unwrap();
diff --git a/wasm-runtime/polkadot/src/runtime/consensus.rs b/wasm-runtime/polkadot/src/runtime/consensus.rs
index 51666666cf165..83e59d0684025 100644
--- a/wasm-runtime/polkadot/src/runtime/consensus.rs
+++ b/wasm-runtime/polkadot/src/runtime/consensus.rs
@@ -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.
diff --git a/wasm-runtime/polkadot/src/runtime/genesismap.rs b/wasm-runtime/polkadot/src/runtime/genesismap.rs
new file mode 100644
index 0000000000000..a56d03bd044b7
--- /dev/null
+++ b/wasm-runtime/polkadot/src/runtime/genesismap.rs
@@ -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 .
+
+//! 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,
+ pub authorities: Vec,
+ 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, 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> {
+ 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> {
+ 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/wasm-runtime/polkadot/src/runtime/mod.rs b/wasm-runtime/polkadot/src/runtime/mod.rs
index 9befa9bd42df8..664cbac8c095b 100644
--- a/wasm-runtime/polkadot/src/runtime/mod.rs
+++ b/wasm-runtime/polkadot/src/runtime/mod.rs
@@ -31,3 +31,7 @@ pub mod governance;
// TODO: polkadao
// TODO: parachains
+
+
+#[cfg(feature = "with-std")]
+pub mod genesismap;
diff --git a/wasm-runtime/polkadot/src/runtime/session.rs b/wasm-runtime/polkadot/src/runtime/session.rs
index 6cda783beb608..5ebc444f8f3b4 100644
--- a/wasm-runtime/polkadot/src/runtime/session.rs
+++ b/wasm-runtime/polkadot/src/runtime/session.rs
@@ -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]
], }
}
diff --git a/wasm-runtime/polkadot/src/runtime/staking.rs b/wasm-runtime/polkadot/src/runtime/staking.rs
index df8d4d632fe5f..5f71b608f2660 100644
--- a/wasm-runtime/polkadot/src/runtime/staking.rs
+++ b/wasm-runtime/polkadot/src/runtime/staking.rs
@@ -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: usize) {
storage::put(VALIDATOR_COUNT, &(new as u32));
}
+
+ /// 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 {
diff --git a/wasm-runtime/polkadot/src/runtime/system.rs b/wasm-runtime/polkadot/src/runtime/system.rs
index 8df20f138e7eb..5daf530cb4707 100644
--- a/wasm-runtime/polkadot/src/runtime/system.rs
+++ b/wasm-runtime/polkadot/src/runtime/system.rs
@@ -18,12 +18,13 @@
//! 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::{Block, BlockNumber, Hash, UncheckedTransaction, TxOrder};
+use primitives::{Block, BlockNumber, Header, Hash, UncheckedTransaction, TxOrder};
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";
@@ -42,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);
}
}
@@ -50,11 +51,8 @@ pub mod internal {
use super::*;
/// 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][..]);
- e.next_log_index += 1;
- });
+ pub fn deposit_log(log: Vec) {
+ with_env(|e| e.digest.logs.push(log));
}
/// Actually execute all transitioning for `block`.
@@ -62,8 +60,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;
@@ -76,12 +72,15 @@ pub mod internal {
// check transaction trie root represents the transactions.
let txs = block.transactions.iter().map(Slicable::to_vec).collect::>();
- let txs_root = enumerated_trie_root(&txs.iter().map(Vec::as_slice).collect::>());
-// println!("TR: {}", ::support::HexDisplay::from(&txs_root));
+ let txs = txs.iter().map(Vec::as_slice).collect::>();
+ let txs_root = 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().for_each(execute_transaction);
+ for tx in &block.transactions {
+ super::execute_transaction(tx);
+ }
staking::internal::check_new_era();
session::internal::check_rotate_session();
@@ -89,42 +88,90 @@ pub mod internal {
// any final checks
final_checks(&block);
-
// check storage root.
- assert!(header.state_root == storage_root(), "Storage root must match that calculated.");
+ let storage_root = 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) {
- // Verify the signature is good.
- assert!(utx.ed25519_verify(), "All transactions should be properly signed");
+ /// 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);
+ });
- let ref tx = utx.transaction;
+ 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");
+ with_env(|e| {
+ mem::swap(&mut header.digest, &mut e.digest);
+ });
+ header
+ }
- // increment nonce in storage
- storage::put(&nonce_key, &(expected_nonce + 1));
+ /// 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 = storage_root();
+ with_env(|e| {
+ mem::swap(&mut header.digest, &mut e.digest);
+ });
+
+ post_finalise(&header);
+
+ header
+ }
- // decode parameters and dispatch
- tx.function.dispatch(&tx.signed, &tx.input_data);
+ #[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) {
+ // Verify the signature is good.
+ assert!(utx.ed25519_verify(), "All transactions should be properly signed");
+
+ let ref tx = utx.transaction;
+
+ // 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
+ tx.function.dispatch(&tx.signed, &tx.input_data);
}
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::*;
@@ -152,15 +199,13 @@ mod tests {
function: Function::StakingTransfer,
input_data: vec![].join(&two).join(&69u64),
},
- signature: "679fcf0a846b4224c84ecad7d91a26241c46d00cb53d6480a363274e8965ee34b0b80b4b2e3836d3d8f8f12c0c1aef7350af587d9aee3883561d11726068ac0a".convert(),
+ signature: "13590ae48241e29780407687b86c331a9f40f3ab7f2cc2441787628bcafab6645dc81863b138a358e2a1ed1ffa940a4584ba94837f022f0cd162791530320904".convert(),
};
- // tx: 2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000228000000d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000
- // sig: 679fcf0a846b4224c84ecad7d91a26241c46d00cb53d6480a363274e8965ee34b0b80b4b2e3836d3d8f8f12c0c1aef7350af587d9aee3883561d11726068ac0a
println!("tx is {}", HexDisplay::from(&tx.transaction.to_vec()));
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);
});
@@ -197,33 +242,21 @@ mod tests {
let mut t = new_test_ext();
- let tx = UncheckedTransaction {
- transaction: Transaction {
- signed: one.clone(),
- nonce: 0,
- function: Function::StakingTransfer,
- input_data: vec![].join(&two).join(&69u64),
- },
- signature: "679fcf0a846b4224c84ecad7d91a26241c46d00cb53d6480a363274e8965ee34b0b80b4b2e3836d3d8f8f12c0c1aef7350af587d9aee3883561d11726068ac0a".convert(),
- };
-
let h = Header {
parent_hash: [69u8; 32],
number: 1,
- state_root: hex!("2481853da20b9f4322f34650fea5f240dcbfb266d02db94bfa0153c31f4a29db"),
- transaction_root: hex!("91fab88ad8c30a6d05ad8e0cf9ab139bf1b8cdddc69abd51cdfa6d2699038af1"),
+ state_root: hex!("1ab2dbb7d4868a670b181327b0b6a58dc64b10cfb9876f737a5aa014b8da31e0"),
+ 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);
- assert_eq!(staking::balance(&one), 42);
- assert_eq!(staking::balance(&two), 69);
});
}
@@ -235,35 +268,47 @@ mod tests {
let mut t = new_test_ext();
- let tx = UncheckedTransaction {
- transaction: Transaction {
- signed: one.clone(),
- nonce: 0,
- function: Function::StakingTransfer,
- input_data: vec![].join(&two).join(&69u64),
- },
- signature: "679fcf0a846b4224c84ecad7d91a26241c46d00cb53d6480a363274e8965ee34b0b80b4b2e3836d3d8f8f12c0c1aef7350af587d9aee3883561d11726068ac0a".convert(),
+ let h = Header {
+ parent_hash: [69u8; 32],
+ number: 1,
+ state_root: [0u8; 32],
+ transaction_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"),
+ digest: Digest { logs: vec![], },
+ };
+
+ let b = Block {
+ header: h,
+ transactions: vec![],
};
- // tx: 2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000228000000d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000
- // sig: 679fcf0a846b4224c84ecad7d91a26241c46d00cb53d6480a363274e8965ee34b0b80b4b2e3836d3d8f8f12c0c1aef7350af587d9aee3883561d11726068ac0a
+
+ 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: [69u8; 32],
number: 1,
- state_root: [0u8; 32],
- transaction_root: [0u8; 32], // Unchecked currently.
+ state_root: hex!("1ab2dbb7d4868a670b181327b0b6a58dc64b10cfb9876f737a5aa014b8da31e0"),
+ transaction_root: [0u8; 32],
digest: Digest { logs: vec![], },
};
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);
});
}
}
diff --git a/wasm-runtime/polkadot/src/support/environment.rs b/wasm-runtime/polkadot/src/support/environment.rs
index 7670a4801f29a..3f652530a2b3e 100644
--- a/wasm-runtime/polkadot/src/support/environment.rs
+++ b/wasm-runtime/polkadot/src/support/environment.rs
@@ -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.
diff --git a/wasm-runtime/polkadot/src/support/storage.rs b/wasm-runtime/polkadot/src/support/storage.rs
index a0f2a93b495b6..aada8c8ae0546 100644
--- a/wasm-runtime/polkadot/src/support/storage.rs
+++ b/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/wasm-runtime/std/src/lib.rs b/wasm-runtime/std/src/lib.rs
index 3feb8c5544644..d04fbd532d220 100644
--- a/wasm-runtime/std/src/lib.rs
+++ b/wasm-runtime/std/src/lib.rs
@@ -4,6 +4,8 @@
#![feature(alloc)]
#![cfg_attr(feature = "strict", deny(warnings))]
+#[macro_use]
+#[macro_export]
extern crate alloc;
pub use alloc::vec;
@@ -43,7 +45,7 @@ extern "C" {
fn ext_get_allocated_storage(key_data: *const u8, key_len: u32, written_out: *mut u32) -> *mut u8;
fn ext_get_storage_into(key_data: *const u8, key_len: u32, value_data: *mut u8, value_len: u32, value_offset: u32) -> u32;
fn ext_storage_root(result: *mut u8);
- fn ext_enumerated_trie_root(values_data: *const u8, values_len: u32, lens_data: *const u32, lens_len: u32, result: *mut u8);
+ fn ext_enumerated_trie_root(values_data: *const u8, lens_data: *const u32, lens_len: u32, result: *mut u8);
fn ext_chain_id() -> u64;
fn ext_blake2_256(data: *const u8, len: u32, out: *mut u8);
fn ext_twox_128(data: *const u8, len: u32, out: *mut u8);
@@ -90,7 +92,7 @@ pub fn enumerated_trie_root(values: &[&[u8]]) -> [u8; 32] {
let mut result: [u8; 32] = Default::default();
unsafe {
ext_enumerated_trie_root(
- values.as_ptr(), values.len() as u32,
+ values.as_ptr(),
lens.as_ptr(), lens.len() as u32,
result.as_mut_ptr()
);
diff --git a/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm b/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm
index 36fe893442dab..c1b383b49ecab 100644
Binary files a/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm and b/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm differ
diff --git a/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm b/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm
index bd48f63571704..10c2c86ab173d 100644
Binary files a/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm and b/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm differ
diff --git a/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm b/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm
index 3905e9d911395..fde5fdad98d95 100644
Binary files a/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm and b/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm differ
diff --git a/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.wasm b/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.wasm
index 3a909f06b3487..3011f185a3443 100644
Binary files a/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.wasm and b/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.wasm differ