mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-10 17:11:03 +00:00
Merge pull request #52 from paritytech/gav-storage-root-verify
Verify the storage root and tx trie root in runtime
This commit is contained in:
Generated
+38
-1
@@ -470,6 +470,23 @@ dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex-literal"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"hex-literal-impl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex-literal-impl"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.2.3"
|
||||
@@ -768,6 +785,7 @@ dependencies = [
|
||||
name = "native-runtime"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"runtime-std 0.1.0",
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -968,7 +986,6 @@ 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)",
|
||||
"libc 0.2.33 (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",
|
||||
@@ -978,6 +995,7 @@ dependencies = [
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"triehash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1061,6 +1079,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hashdb 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memorydb 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"patricia-trie 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"polkadot-primitives 0.1.0",
|
||||
@@ -1086,6 +1105,19 @@ dependencies = [
|
||||
"difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack-impl"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.3.15"
|
||||
@@ -1203,6 +1235,7 @@ dependencies = [
|
||||
"parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"polkadot-primitives 0.1.0",
|
||||
"polkadot-state-machine 0.1.0",
|
||||
"triehash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1705,6 +1738,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum globset 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90d069fe6beb9be359ef505650b3f73228c5591a3c4b1f32be2f4f44459ffa3a"
|
||||
"checksum hashdb 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d97be07c358c5b461268b4ce60304024c5fa5acfd4bd8cd743639f0252003cf5"
|
||||
"checksum heapsize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "54fab2624374e5137ae4df13bf32b0b269cb804df42d13a51221bbd431d1a237"
|
||||
"checksum hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd546ef520ab3745f1aae5f2cdc6de9e6498e94d1ab138b9eb3ddfbf335847fb"
|
||||
"checksum hex-literal-impl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2ea76da4c7f1a54d01d54985566d3fdd960b2bbd7b970da024821c883c2d9631"
|
||||
"checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07"
|
||||
"checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2"
|
||||
"checksum hyper 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)" = "4959ca95f55df4265bff2ad63066147255e6fa733682cf6d1cb5eaff6e53324b"
|
||||
@@ -1753,6 +1788,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum plain_hasher 0.1.0 (git+https://github.com/paritytech/parity.git)" = "<none>"
|
||||
"checksum plain_hasher 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83ae80873992f511142c07d0ec6c44de5636628fdb7e204abd655932ea79d995"
|
||||
"checksum pretty_assertions 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94b6bbc8a323d89a019c4cdde21850522fb8405e97add70827177fc2f86c1495"
|
||||
"checksum proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ba8d4f9257b85eb6cdf13f055cea3190520aab1409ca2ab43493ea4820c25f0"
|
||||
"checksum proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5cb6f960ad471404618e9817c0e5d10b1ae74cfdf01fab89ea0641fe7fb2892"
|
||||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||
"checksum rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6475140dfd8655aeb72e1fd4b7a1cc1c202be65d71669476e392fe62532b9edd"
|
||||
"checksum rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b614fe08b6665cb9a231d07ac1364b0ef3cb3698f1239ee0c4c3a88a524f54c8"
|
||||
|
||||
@@ -15,7 +15,7 @@ byteorder = "1.1"
|
||||
rustc-hex = "1.0.0"
|
||||
native-runtime = { path = "../native-runtime", version = "0.1" }
|
||||
runtime-std = { path = "../native-runtime/std", version = "0.1" }
|
||||
libc = { version = "0.2.33" }
|
||||
triehash = "0.1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
assert_matches = "1.1"
|
||||
|
||||
@@ -36,7 +36,7 @@ extern crate byteorder;
|
||||
extern crate rustc_hex;
|
||||
extern crate native_runtime;
|
||||
extern crate runtime_std;
|
||||
extern crate libc;
|
||||
extern crate triehash;
|
||||
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
|
||||
@@ -41,8 +41,9 @@ impl CodeExecutor for NativeExecutor {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use runtime_std::TestExternalities;
|
||||
use native_runtime::codec::KeyedVec;
|
||||
use native_runtime::support::{TestExternalities, one, two, StaticHexInto};
|
||||
use native_runtime::support::{one, two, StaticHexInto};
|
||||
use native_runtime::runtime::staking::balance;
|
||||
use primitives::twox_128;
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ use wasm_utils::{MemoryInstance, UserDefinedElements,
|
||||
AddModuleWithoutFullDependentInstance};
|
||||
use primitives::{ed25519, blake2_256, twox_128, twox_256};
|
||||
use primitives::hexdisplay::HexDisplay;
|
||||
use triehash::ordered_trie_root;
|
||||
|
||||
struct Heap {
|
||||
end: u32,
|
||||
@@ -66,15 +67,26 @@ impl<'e, E: Externalities> FunctionExecutor<'e, E> {
|
||||
}
|
||||
|
||||
trait WritePrimitive<T: Sized> {
|
||||
fn write_primitive(&self, offset: u32, t: T);
|
||||
fn write_primitive(&self, offset: u32, t: T) -> ::std::result::Result<(), DummyUserError>;
|
||||
}
|
||||
|
||||
impl WritePrimitive<u32> for MemoryInstance {
|
||||
fn write_primitive(&self, offset: u32, t: u32) {
|
||||
fn write_primitive(&self, offset: u32, t: u32) -> ::std::result::Result<(), DummyUserError> {
|
||||
use byteorder::{LittleEndian, ByteOrder};
|
||||
let mut r = [0u8; 4];
|
||||
LittleEndian::write_u32(&mut r, t);
|
||||
let _ = self.set(offset, &r);
|
||||
self.set(offset, &r).map_err(|_| DummyUserError)
|
||||
}
|
||||
}
|
||||
|
||||
trait ReadPrimitive<T: Sized> {
|
||||
fn read_primitive(&self, offset: u32) -> ::std::result::Result<T, DummyUserError>;
|
||||
}
|
||||
|
||||
impl ReadPrimitive<u32> for MemoryInstance {
|
||||
fn read_primitive(&self, offset: u32) -> ::std::result::Result<u32, DummyUserError> {
|
||||
use byteorder::{LittleEndian, ByteOrder};
|
||||
Ok(LittleEndian::read_u32(&self.get(offset, 4).map_err(|_| DummyUserError)?))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,29 +107,29 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
|
||||
println!("Runtime: {}", number);
|
||||
},
|
||||
ext_memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 => {
|
||||
if let (Ok(sl1), Ok(sl2))
|
||||
= (this.memory.get(s1, n as usize), this.memory.get(s2, n as usize)) {
|
||||
match sl1.cmp(&sl2) {
|
||||
Ordering::Greater => 1,
|
||||
Ordering::Less => -1,
|
||||
Ordering::Equal => 0,
|
||||
}
|
||||
} else {
|
||||
return Err(DummyUserError.into());
|
||||
let sl1 = this.memory.get(s1, n as usize).map_err(|_| DummyUserError)?;
|
||||
let sl2 = this.memory.get(s2, n as usize).map_err(|_| DummyUserError)?;
|
||||
match sl1.cmp(&sl2) {
|
||||
Ordering::Greater => 1,
|
||||
Ordering::Less => -1,
|
||||
Ordering::Equal => 0,
|
||||
}
|
||||
},
|
||||
ext_memcpy(dest: *mut u8, src: *const u8, count: usize) -> *mut u8 => {
|
||||
let _ = this.memory.copy_nonoverlapping(src as usize, dest as usize, count as usize);
|
||||
this.memory.copy_nonoverlapping(src as usize, dest as usize, count as usize)
|
||||
.map_err(|_| DummyUserError)?;
|
||||
println!("memcpy {} from {}, {} bytes", dest, src, count);
|
||||
dest
|
||||
},
|
||||
ext_memmove(dest: *mut u8, src: *const u8, count: usize) -> *mut u8 => {
|
||||
let _ = this.memory.copy(src as usize, dest as usize, count as usize);
|
||||
this.memory.copy(src as usize, dest as usize, count as usize)
|
||||
.map_err(|_| DummyUserError)?;
|
||||
println!("memmove {} from {}, {} bytes", dest, src, count);
|
||||
dest
|
||||
},
|
||||
ext_memset(dest: *mut u8, val: u32, count: usize) -> *mut u8 => {
|
||||
let _ = this.memory.clear(dest as usize, val as u8, count as usize);
|
||||
this.memory.clear(dest as usize, val as u8, count as usize)
|
||||
.map_err(|_| DummyUserError)?;
|
||||
println!("memset {} with {}, {} bytes", dest, val, count);
|
||||
dest
|
||||
},
|
||||
@@ -136,90 +148,80 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
|
||||
}
|
||||
},
|
||||
ext_get_allocated_storage(key_data: *const u8, key_len: u32, written_out: *mut u32) -> *mut u8 => {
|
||||
let (offset, written) = if let Ok(key) = this.memory.get(key_data, key_len as usize) {
|
||||
if let Ok(value) = this.ext.storage(&key) {
|
||||
let offset = this.heap.allocate(value.len() as u32) as u32;
|
||||
let _ = this.memory.set(offset, &value);
|
||||
(offset, value.len() as u32)
|
||||
} else { (0, 0) }
|
||||
} else { (0, 0) };
|
||||
let key = this.memory.get(key_data, key_len as usize).map_err(|_| DummyUserError)?;
|
||||
let value = this.ext.storage(&key).map_err(|_| DummyUserError)?;
|
||||
|
||||
this.memory.write_primitive(written_out, written);
|
||||
offset as u32
|
||||
let offset = this.heap.allocate(value.len() as u32) as u32;
|
||||
this.memory.set(offset, &value).map_err(|_| DummyUserError)?;
|
||||
|
||||
this.memory.write_primitive(written_out, value.len() as u32)?;
|
||||
offset
|
||||
},
|
||||
ext_get_storage_into(key_data: *const u8, key_len: u32, value_data: *mut u8, value_len: u32, value_offset: u32) -> u32 => {
|
||||
if let Ok(key) = this.memory.get(key_data, key_len as usize) {
|
||||
if let Ok(value) = this.ext.storage(&key) {
|
||||
let value = &value[value_offset as usize..];
|
||||
let written = ::std::cmp::min(value_len as usize, value.len());
|
||||
let _ = this.memory.set(value_data, &value[..written]);
|
||||
written as u32
|
||||
} else { 0 }
|
||||
} else { 0 }
|
||||
let key = this.memory.get(key_data, key_len as usize).map_err(|_| DummyUserError)?;
|
||||
let value = this.ext.storage(&key).map_err(|_| DummyUserError)?;
|
||||
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)?;
|
||||
written as u32
|
||||
},
|
||||
ext_storage_root(result: *mut u8) => {
|
||||
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) => {
|
||||
let values = (0..lens_len)
|
||||
.map(|i| this.memory.read_primitive(lens_data + i * 4))
|
||||
.collect::<::std::result::Result<Vec<u32>, DummyUserError>>()?
|
||||
.into_iter()
|
||||
.scan(0u32, |acc, v| { let o = *acc; *acc += v; Some((o, v)) })
|
||||
.map(|(offset, len)|
|
||||
this.memory.get(values_data + offset, len as usize)
|
||||
.map_err(|_| DummyUserError)
|
||||
)
|
||||
.collect::<::std::result::Result<Vec<_>, DummyUserError>>()?;
|
||||
let r = ordered_trie_root(values.into_iter());
|
||||
this.memory.set(result, &r[..]).map_err(|_| DummyUserError)?;
|
||||
},
|
||||
ext_chain_id() -> u64 => {
|
||||
this.ext.chain_id()
|
||||
},
|
||||
ext_twox_128(data: *const u8, len: u32, out: *mut u8) => {
|
||||
let maybe_value = if len == 0 {
|
||||
Ok(vec![])
|
||||
let result = if len == 0 {
|
||||
twox_128(&[0u8; 0])
|
||||
} else {
|
||||
this.memory.get(data, len as usize)
|
||||
twox_128(&this.memory.get(data, len as usize).map_err(|_| DummyUserError)?)
|
||||
};
|
||||
let result = if let Ok(value) = maybe_value {
|
||||
twox_128(&value)
|
||||
} else {
|
||||
[0; 16]
|
||||
};
|
||||
let _ = this.memory.set(out, &result);
|
||||
this.memory.set(out, &result).map_err(|_| DummyUserError)?;
|
||||
},
|
||||
ext_twox_256(data: *const u8, len: u32, out: *mut u8) => {
|
||||
let maybe_value = if len == 0 {
|
||||
Ok(vec![])
|
||||
let result = if len == 0 {
|
||||
twox_256(&[0u8; 0])
|
||||
} else {
|
||||
this.memory.get(data, len as usize)
|
||||
twox_256(&this.memory.get(data, len as usize).map_err(|_| DummyUserError)?)
|
||||
};
|
||||
let result = if let Ok(value) = maybe_value {
|
||||
twox_256(&value)
|
||||
} else {
|
||||
[0; 32]
|
||||
};
|
||||
let _ = this.memory.set(out, &result);
|
||||
this.memory.set(out, &result).map_err(|_| DummyUserError)?;
|
||||
},
|
||||
ext_blake2_256(data: *const u8, len: u32, out: *mut u8) => {
|
||||
let maybe_value = if len == 0 {
|
||||
Ok(vec![])
|
||||
let result = if len == 0 {
|
||||
blake2_256(&[0u8; 0])
|
||||
} else {
|
||||
this.memory.get(data, len as usize)
|
||||
blake2_256(&this.memory.get(data, len as usize).map_err(|_| DummyUserError)?)
|
||||
};
|
||||
let result = if let Ok(value) = maybe_value {
|
||||
blake2_256(&value)
|
||||
} else {
|
||||
[0; 32]
|
||||
};
|
||||
let _ = this.memory.set(out, &result);
|
||||
this.memory.set(out, &result).map_err(|_| DummyUserError)?;
|
||||
},
|
||||
ext_ed25519_verify(msg_data: *const u8, msg_len: u32, sig_data: *const u8, pubkey_data: *const u8) -> u32 => {
|
||||
(||{
|
||||
let mut sig = [0u8; 64];
|
||||
if let Err(_) = this.memory.get_into(sig_data, &mut sig[..]) {
|
||||
return 2;
|
||||
};
|
||||
let mut pubkey = [0u8; 32];
|
||||
if let Err(_) = this.memory.get_into(pubkey_data, &mut pubkey[..]) {
|
||||
return 3;
|
||||
};
|
||||
let mut sig = [0u8; 64];
|
||||
this.memory.get_into(sig_data, &mut sig[..]).map_err(|_| DummyUserError)?;
|
||||
let mut pubkey = [0u8; 32];
|
||||
this.memory.get_into(pubkey_data, &mut pubkey[..]).map_err(|_| DummyUserError)?;
|
||||
let msg = this.memory.get(msg_data, msg_len as usize).map_err(|_| DummyUserError)?;
|
||||
|
||||
if let Ok(msg) = this.memory.get(msg_data, msg_len as usize) {
|
||||
if ed25519::Signature::from(sig).verify(&msg, &ed25519::Public::from(pubkey)) {
|
||||
0
|
||||
} else {
|
||||
5
|
||||
}
|
||||
} else {
|
||||
4
|
||||
}
|
||||
})()
|
||||
if ed25519::Signature::from(sig).verify(&msg, &ed25519::Public::from(pubkey)) {
|
||||
0
|
||||
} else {
|
||||
5
|
||||
}
|
||||
}
|
||||
=> <'e, E: Externalities + 'e>
|
||||
);
|
||||
@@ -279,8 +281,8 @@ mod tests {
|
||||
use super::*;
|
||||
use rustc_hex::FromHex;
|
||||
use primitives::{blake2_256, twox_128};
|
||||
use runtime_std;
|
||||
use native_runtime::support::{one, two, StaticHexInto, TestExternalities};
|
||||
use runtime_std::{self, TestExternalities};
|
||||
use native_runtime::support::{one, two, StaticHexInto};
|
||||
use native_runtime::codec::KeyedVec;
|
||||
use native_runtime::runtime::staking::balance;
|
||||
|
||||
@@ -380,6 +382,16 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enumerated_trie_root_should_work() {
|
||||
let mut ext = TestExternalities::default();
|
||||
let test_code = include_bytes!("../../wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm");
|
||||
assert_eq!(
|
||||
WasmExecutor.call(&mut ext, &test_code[..], "test_enumerated_trie_root", &CallData(vec![])).unwrap(),
|
||||
ordered_trie_root(vec![b"zero".to_vec(), b"one".to_vec(), b"two".to_vec()]).0.to_vec()
|
||||
);
|
||||
}
|
||||
|
||||
fn tx() -> Vec<u8> { "679fcf0a846b4224c84ecad7d91a26241c46d00cb53d6480a363274e8965ee34b0b80b4b2e3836d3d8f8f12c0c1aef7350af587d9aee3883561d11726068ac0a2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000228000000d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000".convert() }
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -11,3 +11,4 @@ without-std = []
|
||||
[dependencies]
|
||||
runtime-std = { path = "./std", version = "0.1" }
|
||||
rustc-hex = "1.0"
|
||||
hex-literal = "0.1.0"
|
||||
|
||||
@@ -12,3 +12,4 @@ parking_lot = "0.5"
|
||||
polkadot-state-machine = { path = "../../state_machine" , version = "0.1" }
|
||||
environmental = { path = "../../environmental", version = "0.1.0" }
|
||||
polkadot-primitives = { path = "../../primitives", version = "0.1.0" }
|
||||
triehash = "0.1.0"
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
extern crate environmental;
|
||||
extern crate polkadot_state_machine;
|
||||
extern crate polkadot_primitives as primitives;
|
||||
extern crate triehash;
|
||||
|
||||
use std::fmt;
|
||||
use primitives::ed25519;
|
||||
@@ -39,7 +40,7 @@ pub mod prelude {
|
||||
pub use std::boxed::Box;
|
||||
}
|
||||
|
||||
pub use polkadot_state_machine::{Externalities, ExternalitiesError};
|
||||
pub use polkadot_state_machine::{Externalities, ExternalitiesError, TestExternalities};
|
||||
use primitives::hexdisplay::HexDisplay;
|
||||
|
||||
// TODO: use the real error, not NoError.
|
||||
@@ -92,6 +93,18 @@ pub fn chain_id() -> u64 {
|
||||
).unwrap_or(0)
|
||||
}
|
||||
|
||||
/// "Commit" all existing operations and get the resultant storage root.
|
||||
pub fn storage_root() -> [u8; 32] {
|
||||
ext::with(|ext|
|
||||
ext.storage_root()
|
||||
).unwrap_or([0u8; 32])
|
||||
}
|
||||
|
||||
/// "Commit" all existing operations and get the resultant storage root.
|
||||
pub fn enumerated_trie_root(serialised_values: &[&[u8]]) -> [u8; 32] {
|
||||
triehash::ordered_trie_root(serialised_values.iter().map(|s| s.to_vec())).0
|
||||
}
|
||||
|
||||
/// Conduct a Keccak-256 hash of the given data.
|
||||
pub use primitives::{blake2_256, twox_128, twox_256};
|
||||
|
||||
@@ -140,23 +153,6 @@ macro_rules! impl_stubs {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct TestExternalities {
|
||||
storage: HashMap<Vec<u8>, Vec<u8>>,
|
||||
}
|
||||
impl Externalities for TestExternalities {
|
||||
fn storage(&self, key: &[u8]) -> Result<&[u8], ExternalitiesError> {
|
||||
Ok(self.storage.get(&key.to_vec()).map_or(&[] as &[u8], Vec::as_slice))
|
||||
}
|
||||
|
||||
fn set_storage(&mut self, key: Vec<u8>, value: Vec<u8>) {
|
||||
self.storage.insert(key, value);
|
||||
}
|
||||
|
||||
fn chain_id(&self) -> u64 { 42 }
|
||||
}
|
||||
|
||||
macro_rules! map {
|
||||
($( $name:expr => $value:expr ),*) => (
|
||||
|
||||
@@ -11,3 +11,4 @@ patricia-trie = "0.1.0"
|
||||
memorydb = "0.1.1"
|
||||
triehash = "0.1"
|
||||
byteorder = "1.1"
|
||||
hex-literal = "0.1.0"
|
||||
|
||||
@@ -40,6 +40,9 @@ pub trait Backend {
|
||||
/// Commit updates to the backend and get new state.
|
||||
fn commit<I>(&mut self, changes: I) -> Committed
|
||||
where I: IntoIterator<Item=Update>;
|
||||
|
||||
/// Get all key/value pairs into a Vec.
|
||||
fn pairs(&self) -> Vec<(&[u8], &[u8])>;
|
||||
}
|
||||
|
||||
/// Error impossible.
|
||||
@@ -64,6 +67,18 @@ 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 {
|
||||
InMemory {
|
||||
inner: MemoryState {
|
||||
storage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Backend for InMemory {
|
||||
type Error = Void;
|
||||
|
||||
@@ -87,6 +102,10 @@ impl Backend for InMemory {
|
||||
storage_tree_root,
|
||||
}
|
||||
}
|
||||
|
||||
fn pairs(&self) -> Vec<(&[u8], &[u8])> {
|
||||
self.inner.storage.iter().map(|(k, v)| (&k[..], &v[..])).collect()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: DB-based backend
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
//! Conrete externalities implementation.
|
||||
|
||||
use std::{error, fmt};
|
||||
|
||||
use triehash::trie_root;
|
||||
use backend::Backend;
|
||||
use {Externalities, ExternalitiesError, OverlayedChanges};
|
||||
|
||||
@@ -75,4 +75,15 @@ impl<'a, B: 'a> Externalities for Ext<'a, B>
|
||||
fn chain_id(&self) -> u64 {
|
||||
42
|
||||
}
|
||||
|
||||
fn storage_root(&self) -> [u8; 32] {
|
||||
let mut all_pairs = self.backend.pairs();
|
||||
all_pairs.extend(
|
||||
self.overlay.committed.storage.iter()
|
||||
.chain(self.overlay.prospective.storage.iter())
|
||||
.map(|(k, v)| (&k[..], &v[..]))
|
||||
);
|
||||
|
||||
trie_root(all_pairs.into_iter().map(|(k, v)| (k.to_vec(), v.to_vec()))).0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#![warn(missing_docs)]
|
||||
|
||||
extern crate polkadot_primitives as primitives;
|
||||
#[macro_use]
|
||||
extern crate hex_literal;
|
||||
|
||||
extern crate hashdb;
|
||||
extern crate memorydb;
|
||||
@@ -35,6 +37,9 @@ use primitives::contract::{CallData};
|
||||
|
||||
pub mod backend;
|
||||
mod ext;
|
||||
mod testing;
|
||||
|
||||
pub use testing::TestExternalities;
|
||||
|
||||
/// Updates to be committed to the state.
|
||||
pub enum Update {
|
||||
@@ -141,6 +146,9 @@ pub trait Externalities {
|
||||
/// Get the identity of the chain.
|
||||
fn chain_id(&self) -> u64;
|
||||
|
||||
/// Get the trie root of the current storage map.
|
||||
fn storage_root(&self) -> [u8; 32];
|
||||
|
||||
/// Get the current set of authorities from storage.
|
||||
fn authorities(&self) -> Result<Vec<&[u8]>, ExternalitiesError> {
|
||||
(0..self.storage(b"con:aut:len")?.into_iter()
|
||||
@@ -210,8 +218,9 @@ pub fn execute<B: backend::Backend, Exec: CodeExecutor>(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashMap;
|
||||
use super::{OverlayedChanges, Externalities, ExternalitiesError};
|
||||
use super::*;
|
||||
use super::backend::InMemory;
|
||||
use super::ext::Ext;
|
||||
|
||||
#[test]
|
||||
fn overlayed_storage_works() {
|
||||
@@ -238,22 +247,6 @@ mod tests {
|
||||
assert!(overlayed.storage(&key).is_none());
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct TestExternalities {
|
||||
storage: HashMap<Vec<u8>, Vec<u8>>,
|
||||
}
|
||||
impl Externalities for TestExternalities {
|
||||
fn storage(&self, key: &[u8]) -> Result<&[u8], ExternalitiesError> {
|
||||
Ok(self.storage.get(&key.to_vec()).map_or(&[] as &[u8], Vec::as_slice))
|
||||
}
|
||||
|
||||
fn set_storage(&mut self, key: Vec<u8>, value: Vec<u8>) {
|
||||
self.storage.insert(key, value);
|
||||
}
|
||||
|
||||
fn chain_id(&self) -> u64 { 42 }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn authorities_call_works() {
|
||||
let mut ext = TestExternalities::default();
|
||||
@@ -273,4 +266,34 @@ mod tests {
|
||||
ext.set_storage(b"con:aut:\x01\0\0\0".to_vec(), b"second".to_vec());
|
||||
assert_eq!(ext.authorities(), Ok(vec![&b"first"[..], &b"second"[..]]));
|
||||
}
|
||||
|
||||
macro_rules! map {
|
||||
($( $name:expr => $value:expr ),*) => (
|
||||
vec![ $( ( $name, $value ) ),* ].into_iter().collect()
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn overlayed_storage_root_works() {
|
||||
let mut backend = InMemory::from(map![
|
||||
b"doe".to_vec() => b"reindeer".to_vec(),
|
||||
b"dog".to_vec() => b"puppyXXX".to_vec(),
|
||||
b"dogglesworth".to_vec() => b"catXXX".to_vec()
|
||||
]);
|
||||
let mut overlay = OverlayedChanges {
|
||||
committed: MemoryState { storage: map![
|
||||
b"dog".to_vec() => b"puppy".to_vec(),
|
||||
b"dogglesworth".to_vec() => b"catYYY".to_vec()
|
||||
], },
|
||||
prospective: MemoryState { storage: map![
|
||||
b"dogglesworth".to_vec() => b"cat".to_vec()
|
||||
], },
|
||||
};
|
||||
let ext = Ext {
|
||||
backend: &mut backend,
|
||||
overlay: &mut overlay,
|
||||
};
|
||||
const ROOT: [u8; 32] = hex!("8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3");
|
||||
assert_eq!(ext.storage_root(), ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// 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/>.
|
||||
|
||||
//! Test implementation for Externalities.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use super::{Externalities, ExternalitiesError};
|
||||
use triehash::trie_root;
|
||||
|
||||
/// Simple HashMap based Externalities impl.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TestExternalities {
|
||||
/// The storage.
|
||||
pub storage: HashMap<Vec<u8>, Vec<u8>>,
|
||||
}
|
||||
|
||||
impl TestExternalities {
|
||||
/// Create a new instance with empty storage.
|
||||
pub fn new() -> Self {
|
||||
TestExternalities {
|
||||
storage: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Externalities for TestExternalities {
|
||||
fn storage(&self, key: &[u8]) -> Result<&[u8], ExternalitiesError> {
|
||||
Ok(self.storage.get(&key.to_vec()).map_or(&[] as &[u8], Vec::as_slice))
|
||||
}
|
||||
|
||||
fn set_storage(&mut self, key: Vec<u8>, value: Vec<u8>) {
|
||||
self.storage.insert(key, value);
|
||||
}
|
||||
|
||||
fn chain_id(&self) -> u64 { 42 }
|
||||
|
||||
fn storage_root(&self) -> [u8; 32] {
|
||||
trie_root(self.storage.clone()).0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn commit_should_work() {
|
||||
let mut ext = TestExternalities::new();
|
||||
ext.set_storage(b"doe".to_vec(), b"reindeer".to_vec());
|
||||
ext.set_storage(b"dog".to_vec(), b"puppy".to_vec());
|
||||
ext.set_storage(b"dogglesworth".to_vec(), b"cat".to_vec());
|
||||
const ROOT: [u8; 32] = hex!("8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3");
|
||||
assert_eq!(ext.storage_root(), ROOT);
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,10 @@ extern crate runtime_std;
|
||||
#[cfg(feature = "with-std")]
|
||||
extern crate rustc_hex;
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
extern crate hex_literal;
|
||||
|
||||
pub mod codec;
|
||||
#[macro_use]
|
||||
pub mod support;
|
||||
|
||||
@@ -114,9 +114,9 @@ pub mod internal {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use runtime_std::{with_externalities, twox_128};
|
||||
use runtime_std::{with_externalities, twox_128, TestExternalities};
|
||||
use codec::{KeyedVec, Joiner};
|
||||
use support::{one, two, TestExternalities, with_env};
|
||||
use support::{one, two, with_env};
|
||||
use primitives::{AccountID, InternalFunction};
|
||||
use runtime::{staking, session};
|
||||
|
||||
|
||||
@@ -132,9 +132,9 @@ mod tests {
|
||||
use super::public::*;
|
||||
use super::privileged::*;
|
||||
use super::internal::*;
|
||||
use runtime_std::{with_externalities, twox_128};
|
||||
use runtime_std::{with_externalities, twox_128, TestExternalities};
|
||||
use codec::{KeyedVec, Joiner};
|
||||
use support::{one, two, TestExternalities, with_env};
|
||||
use support::{one, two, with_env};
|
||||
use primitives::AccountID;
|
||||
use runtime::{consensus, session};
|
||||
|
||||
|
||||
@@ -206,9 +206,9 @@ mod tests {
|
||||
use super::public::*;
|
||||
use super::privileged::*;
|
||||
|
||||
use runtime_std::{with_externalities, twox_128};
|
||||
use runtime_std::{with_externalities, twox_128, TestExternalities};
|
||||
use codec::{KeyedVec, Joiner};
|
||||
use support::{one, two, TestExternalities, with_env};
|
||||
use support::{one, two, with_env};
|
||||
use primitives::AccountID;
|
||||
use runtime::{staking, session};
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
//! and depositing logs.
|
||||
|
||||
use runtime_std::prelude::*;
|
||||
use runtime_std::{mem, print};
|
||||
use codec::KeyedVec;
|
||||
use runtime_std::{mem, print, storage_root, enumerated_trie_root};
|
||||
use codec::{KeyedVec, Slicable};
|
||||
use support::{Hashable, storage, with_env};
|
||||
use primitives::{Block, BlockNumber, Hash, UncheckedTransaction, TxOrder};
|
||||
use runtime::{staking, session};
|
||||
@@ -74,13 +74,11 @@ pub mod internal {
|
||||
"Parent hash should be valid."
|
||||
);
|
||||
|
||||
// TODO: check transaction trie root represents the transactions.
|
||||
// this requires non-trivial changes to the externals API or compiling trie rooting into wasm
|
||||
// so will wait until a little later.
|
||||
|
||||
// store the header hash in storage.
|
||||
let header_hash_key = header.number.to_keyed_vec(BLOCK_HASH_AT);
|
||||
storage::put(&header_hash_key, &header.blake2_256());
|
||||
// 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));
|
||||
assert!(header.transaction_root == txs_root, "Transaction trie root must be valid.");
|
||||
|
||||
// execute transactions
|
||||
block.transactions.iter().for_each(execute_transaction);
|
||||
@@ -91,9 +89,14 @@ pub mod internal {
|
||||
// any final checks
|
||||
final_checks(&block);
|
||||
|
||||
// TODO: check storage root.
|
||||
// this requires non-trivial changes to the externals API or compiling trie rooting into wasm
|
||||
// so will wait until a little later.
|
||||
|
||||
// check 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());
|
||||
}
|
||||
|
||||
/// Execute a given transaction.
|
||||
@@ -127,10 +130,10 @@ mod tests {
|
||||
use super::*;
|
||||
use super::internal::*;
|
||||
|
||||
use runtime_std::{with_externalities, twox_128};
|
||||
use runtime_std::{with_externalities, twox_128, TestExternalities};
|
||||
use codec::{Joiner, KeyedVec, Slicable};
|
||||
use support::{StaticHexInto, TestExternalities, HexDisplay, one, two};
|
||||
use primitives::{UncheckedTransaction, Transaction, Function};
|
||||
use support::{StaticHexInto, HexDisplay, one, two};
|
||||
use primitives::{UncheckedTransaction, Transaction, Function, Header, Digest};
|
||||
use runtime::staking;
|
||||
|
||||
#[test]
|
||||
@@ -162,4 +165,105 @@ mod tests {
|
||||
assert_eq!(staking::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]
|
||||
], }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_import_works() {
|
||||
let one = one();
|
||||
let two = two();
|
||||
|
||||
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"),
|
||||
digest: Digest { logs: vec![], },
|
||||
};
|
||||
|
||||
let b = Block {
|
||||
header: h,
|
||||
transactions: vec![tx],
|
||||
};
|
||||
|
||||
with_externalities(&mut t, || {
|
||||
execute_block(b);
|
||||
assert_eq!(staking::balance(&one), 42);
|
||||
assert_eq!(staking::balance(&two), 69);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn block_import_of_bad_state_root_fails() {
|
||||
let one = one();
|
||||
let two = two();
|
||||
|
||||
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.
|
||||
digest: Digest { logs: vec![], },
|
||||
};
|
||||
|
||||
let b = Block {
|
||||
header: h,
|
||||
transactions: vec![tx],
|
||||
};
|
||||
|
||||
with_externalities(&mut t, || {
|
||||
execute_block(b);
|
||||
assert_eq!(staking::balance(&one), 42);
|
||||
assert_eq!(staking::balance(&two), 69);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,10 +42,9 @@ mod tests {
|
||||
use super::*;
|
||||
use super::public::*;
|
||||
|
||||
use runtime_std::{with_externalities, twox_128};
|
||||
use runtime_std::{with_externalities, twox_128, TestExternalities};
|
||||
use runtime::timestamp;
|
||||
use codec::{Joiner, KeyedVec};
|
||||
use support::TestExternalities;
|
||||
|
||||
#[test]
|
||||
fn timestamp_works() {
|
||||
|
||||
@@ -31,4 +31,4 @@ pub use self::hashable::Hashable;
|
||||
#[cfg(feature = "with-std")]
|
||||
pub use self::statichex::{StaticHexConversion, StaticHexInto};
|
||||
#[cfg(feature = "with-std")]
|
||||
pub use self::testing::{AsBytesRef, HexDisplay, TestExternalities, one, two};
|
||||
pub use self::testing::{AsBytesRef, HexDisplay, one, two};
|
||||
|
||||
@@ -146,9 +146,8 @@ pub trait StorageVec {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::collections::HashMap;
|
||||
use runtime_std::with_externalities;
|
||||
use support::{TestExternalities, HexDisplay};
|
||||
use runtime_std::{storage, twox_128};
|
||||
use support::HexDisplay;
|
||||
use runtime_std::{storage, twox_128, TestExternalities, with_externalities};
|
||||
|
||||
#[test]
|
||||
fn integers_can_be_stored() {
|
||||
|
||||
@@ -16,30 +16,9 @@
|
||||
|
||||
//! Testing helpers.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use runtime_std::{Externalities, ExternalitiesError};
|
||||
use primitives::AccountID;
|
||||
use super::statichex::StaticHexInto;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
/// Simple externaties implementation.
|
||||
pub struct TestExternalities {
|
||||
/// The storage map.
|
||||
pub storage: HashMap<Vec<u8>, Vec<u8>>,
|
||||
}
|
||||
|
||||
impl Externalities for TestExternalities {
|
||||
fn storage(&self, key: &[u8]) -> Result<&[u8], ExternalitiesError> {
|
||||
Ok(self.storage.get(&key.to_vec()).map_or(&[] as &[u8], Vec::as_slice))
|
||||
}
|
||||
|
||||
fn set_storage(&mut self, key: Vec<u8>, value: Vec<u8>) {
|
||||
self.storage.insert(key, value);
|
||||
}
|
||||
|
||||
fn chain_id(&self) -> u64 { 42 }
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! map {
|
||||
($( $name:expr => $value:expr ),*) => (
|
||||
|
||||
@@ -42,6 +42,8 @@ extern "C" {
|
||||
fn ext_set_storage(key_data: *const u8, key_len: u32, value_data: *const u8, value_len: u32);
|
||||
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_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);
|
||||
@@ -72,6 +74,30 @@ pub fn read_storage(key: &[u8], value_out: &mut [u8], value_offset: usize) -> us
|
||||
}
|
||||
}
|
||||
|
||||
/// The current storage's root.
|
||||
pub fn storage_root() -> [u8; 32] {
|
||||
let mut result: [u8; 32] = Default::default();
|
||||
unsafe {
|
||||
ext_storage_root(result.as_mut_ptr());
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// A trie root calculated from enumerated values.
|
||||
pub fn enumerated_trie_root(values: &[&[u8]]) -> [u8; 32] {
|
||||
let lens = values.iter().map(|v| (v.len() as u32).to_le()).collect::<Vec<_>>();
|
||||
let values = values.iter().fold(Vec::new(), |mut acc, sl| { acc.extend_from_slice(sl); acc });
|
||||
let mut result: [u8; 32] = Default::default();
|
||||
unsafe {
|
||||
ext_enumerated_trie_root(
|
||||
values.as_ptr(), values.len() as u32,
|
||||
lens.as_ptr(), lens.len() as u32,
|
||||
result.as_mut_ptr()
|
||||
);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// The current relay chain identifier.
|
||||
pub fn chain_id() -> u64 {
|
||||
unsafe {
|
||||
@@ -82,7 +108,6 @@ pub fn chain_id() -> u64 {
|
||||
/// Conduct a 256-bit Blake2 hash.
|
||||
pub fn blake2_256(data: &[u8]) -> [u8; 32] {
|
||||
let mut result: [u8; 32] = Default::default();
|
||||
// guaranteed to write into result.
|
||||
unsafe {
|
||||
ext_blake2_256(data.as_ptr(), data.len() as u32, result.as_mut_ptr());
|
||||
}
|
||||
@@ -92,7 +117,6 @@ pub fn blake2_256(data: &[u8]) -> [u8; 32] {
|
||||
/// Conduct four XX hashes to give a 256-bit result.
|
||||
pub fn twox_256(data: &[u8]) -> [u8; 32] {
|
||||
let mut result: [u8; 32] = Default::default();
|
||||
// guaranteed to write into result.
|
||||
unsafe {
|
||||
ext_twox_256(data.as_ptr(), data.len() as u32, result.as_mut_ptr());
|
||||
}
|
||||
@@ -102,7 +126,6 @@ pub fn twox_256(data: &[u8]) -> [u8; 32] {
|
||||
/// Conduct two XX hashes to give a 128-bit result.
|
||||
pub fn twox_128(data: &[u8]) -> [u8; 16] {
|
||||
let mut result: [u8; 16] = Default::default();
|
||||
// guaranteed to write into result.
|
||||
unsafe {
|
||||
ext_twox_128(data.as_ptr(), data.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.
@@ -8,7 +8,8 @@ use alloc::vec::Vec;
|
||||
|
||||
#[macro_use]
|
||||
extern crate runtime_std;
|
||||
use runtime_std::{set_storage, storage, print, blake2_256, twox_128, twox_256, ed25519_verify};
|
||||
use runtime_std::{set_storage, storage, print, blake2_256, twox_128, twox_256, ed25519_verify,
|
||||
enumerated_trie_root};
|
||||
|
||||
fn test_blake2_256(input: &[u8]) -> Vec<u8> {
|
||||
blake2_256(&input).to_vec()
|
||||
@@ -29,6 +30,10 @@ fn test_ed25519_verify(input: &[u8]) -> Vec<u8> {
|
||||
[ed25519_verify(sig, &msg[..], pubkey) as u8].to_vec()
|
||||
}
|
||||
|
||||
fn test_enumerated_trie_root(_input: &[u8]) -> Vec<u8> {
|
||||
enumerated_trie_root(&[&b"zero"[..], &b"one"[..], &b"two"[..]]).to_vec()
|
||||
}
|
||||
|
||||
fn test_data_in(input: &[u8]) -> Vec<u8> {
|
||||
print("set_storage");
|
||||
set_storage(b"input", &input);
|
||||
@@ -59,4 +64,4 @@ fn test_conditional_panic(input: &[u8]) -> Vec<u8> {
|
||||
}
|
||||
|
||||
impl_stubs!(test_data_in, test_empty_return, test_panic, test_conditional_panic,
|
||||
test_blake2_256, test_twox_256, test_twox_128, test_ed25519_verify);
|
||||
test_blake2_256, test_twox_256, test_twox_128, test_ed25519_verify, test_enumerated_trie_root);
|
||||
|
||||
Reference in New Issue
Block a user