mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-23 09:41:07 +00:00
Merge pull request #53 from paritytech/gav-genesis
The genesis block initialisation logic
This commit is contained in:
Generated
+6
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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, || {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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])> {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,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()
|
||||
);
|
||||
|
||||
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user