Merge pull request #53 from paritytech/gav-genesis

The genesis block initialisation logic
This commit is contained in:
Gav Wood
2018-02-05 14:02:57 +01:00
committed by GitHub
31 changed files with 841 additions and 181 deletions
+6
View File
@@ -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",
+4
View File
@@ -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"
+142
View File
@@ -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 <http://www.gnu.org/licenses/>.
//! 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<u8>, Vec<u8>>) -> 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<Pair> {
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<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 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<u8>, 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();
}
}
+8
View File
@@ -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;
+2
View File
@@ -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"
+5
View File
@@ -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;
+159 -7
View File
@@ -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<u8> { "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<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() -> (Vec<u8>, 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<u8>, 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);
});
}
}
+53 -19
View File
@@ -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<Vec<u32>, 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<u8> { "679fcf0a846b4224c84ecad7d91a26241c46d00cb53d6480a363274e8965ee34b0b80b4b2e3836d3d8f8f12c0c1aef7350af587d9aee3883561d11726068ac0a2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000228000000d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000".convert() }
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 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, || {
+8 -8
View File
@@ -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));
}
}
+2 -16
View File
@@ -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<u8>, Vec<u8>>) -> Self {
@@ -90,17 +86,7 @@ impl Backend for InMemory {
where I: IntoIterator<Item=Update>
{
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])> {
+15 -8
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":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<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,
@@ -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"[..]]));
}
@@ -84,7 +84,8 @@ impl Slicable for Vec<u8> {
fn set_as_slice<F: Fn(&mut [u8], usize) -> bool>(fill_slice: &F) -> Option<Self> {
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<T: Slicable> NonTrivialSlicable for Vec<T> where Vec<T>: Slicable {}
impl<T: NonTrivialSlicable> Slicable for Vec<T> {
fn from_slice(value: &[u8]) -> Option<Self> {
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 {
+25 -6
View File
@@ -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<u8> {
/// Execute a given, serialised, transaction. Returns the empty vector.
pub fn execute_transaction(input: &[u8]) -> Vec<u8> {
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)
}
impl_stubs!(execute_block, execute_transaction);
/// Execute a given, serialised, transaction. Returns the empty vector.
pub fn finalise_block(input: &[u8]) -> Vec<u8> {
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<u8> {
print("run_tests...");
let block = Block::from_slice(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);
@@ -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.
@@ -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)
}
}
@@ -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<Self> {
let mut reader = StreamReader::new(value);
@@ -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<u8> = 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);
}
}
}
}
@@ -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();
@@ -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 = "with-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: 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 {
@@ -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<u8>) {
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::<Vec<_>>();
let txs_root = enumerated_trie_root(&txs.iter().map(Vec::as_slice).collect::<Vec<_>>());
// println!("TR: {}", ::support::HexDisplay::from(&txs_root));
let txs = txs.iter().map(Vec::as_slice).collect::<Vec<_>>();
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");
// increment nonce in storage
storage::put(&nonce_key, &(expected_nonce + 1));
// decode parameters and dispatch
tx.function.dispatch(&tx.signed, &tx.input_data);
with_env(|e| {
mem::swap(&mut header.digest, &mut e.digest);
});
header
}
/// Finalise the block - it is up the caller to ensure that all header fields are valid
/// except state-root.
pub fn finalise_block(mut header: Header) -> Header {
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
}
#[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(),
};
// tx: 2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000228000000d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000
// sig: 679fcf0a846b4224c84ecad7d91a26241c46d00cb53d6480a363274e8965ee34b0b80b4b2e3836d3d8f8f12c0c1aef7350af587d9aee3883561d11726068ac0a
let h = Header {
parent_hash: [69u8; 32],
number: 1,
state_root: [0u8; 32],
transaction_root: [0u8; 32], // Unchecked currently.
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: [69u8; 32],
number: 1,
state_root: hex!("1ab2dbb7d4868a670b181327b0b6a58dc64b10cfb9876f737a5aa014b8da31e0"),
transaction_root: [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.
@@ -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::*;
+4 -2
View File
@@ -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()
);