Repot and introduce keccak-256 external.

This commit is contained in:
Gav
2018-01-17 11:45:36 +01:00
parent 17c8bad87c
commit 98faf54ec4
24 changed files with 88 additions and 117 deletions
+3
View File
@@ -687,8 +687,10 @@ dependencies = [
"polkadot-primitives 0.1.0",
"polkadot-serializer 0.1.0",
"polkadot-state-machine 0.1.0",
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
"tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -841,6 +843,7 @@ dependencies = [
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"polkadot-state-machine 0.1.0",
"tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+2
View File
@@ -12,6 +12,8 @@ serde = "1.0"
serde_derive = "1.0"
parity-wasm = "0.15.0"
byteorder = "1.1"
tiny-keccak = "1.3"
rustc-hex = "1.0.0"
[dev-dependencies]
assert_matches = "1.1"
+2
View File
@@ -33,6 +33,8 @@ extern crate polkadot_state_machine as state_machine;
extern crate serde;
extern crate parity_wasm;
extern crate byteorder;
extern crate tiny_keccak;
extern crate rustc_hex;
#[macro_use]
extern crate error_chain;
+31 -36
View File
@@ -26,6 +26,7 @@ use state_machine::{Externalities, CodeExecutor};
use error::{Error, ErrorKind, Result};
use wasm_utils::{MemoryInstance, UserDefinedElements,
AddModuleWithoutFullDependentInstance};
use tiny_keccak;
struct Heap {
end: u32,
@@ -138,6 +139,15 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
},
ext_chain_id() -> u64 => {
this.ext.chain_id()
},
ext_keccak256(data: *const u8, len: u32, out: *mut u8) => {
let result =
if let Ok(value) = this.memory.get(data, len as usize) {
tiny_keccak::keccak256(&value)
} else {
[0; 32]
};
let _ = this.memory.set(out, &result);
}
=> <'e, E: Externalities + 'e>
);
@@ -193,6 +203,7 @@ impl CodeExecutor for WasmExecutor {
mod tests {
use super::*;
use rustc_hex::FromHex;
#[derive(Debug, Default)]
struct TestExternalities {
@@ -213,50 +224,34 @@ mod tests {
}
#[test]
fn should_pass_externalities_at_call() {
fn storage_should_work() {
let mut ext = TestExternalities::default();
ext.set_storage(b"\0code".to_vec(), b"The code".to_vec());
ext.set_storage(b"foo".to_vec(), b"bar".to_vec());
let test_code = include_bytes!("../../wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm");
let program = ProgramInstance::new().unwrap();
let test_module = include_bytes!("../../wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm");
let module = deserialize_buffer(test_module.to_vec()).expect("Failed to load module");
let module = program.add_module_by_sigs("test", module, map!["env" => FunctionExecutor::<TestExternalities>::SIGNATURES]).expect("Failed to initialize module");
let output = {
let memory = module.memory(ItemIndex::Internal(0)).unwrap();
let mut fec = FunctionExecutor::new(&memory, &mut ext);
let data = b"Hello world";
let size = data.len() as u32;
let offset = fec.heap.allocate(size);
memory.set(offset, data).unwrap();
let returned = program
.params_with_external("env", &mut fec)
.map(|p| p
.add_argument(I32(offset as i32))
.add_argument(I32(size as i32)))
.and_then(|p| module.execute_export("test_data_in", p))
.map_err(|_| -> Error { ErrorKind::Runtime.into() }).expect("function should be callable");
if let Some(I64(r)) = returned {
println!("returned {:?} ({:?}, {:?})", r, r as u32, (r >> 32) as u32 as usize);
memory.get(r as u32, (r >> 32) as u32 as usize).expect("memory address should be reasonable.")
} else {
panic!("bad return value, not u64");
}
};
let output = WasmExecutor.call(&mut ext, &test_code[..], "test_data_in", &CallData(b"Hello world".to_vec())).unwrap();
assert_eq!(output, b"all ok!".to_vec());
let expected: HashMap<_, _> = map![
b"\0code".to_vec() => b"Hello world".to_vec(),
b"input".to_vec() => b"Hello world".to_vec(),
b"code".to_vec() => b"The code".to_vec(),
b"\0authority_count".to_vec() => vec![1],
b"\0authority".to_vec() => b"Hello world".to_vec()
b"foo".to_vec() => b"bar".to_vec(),
b"baz".to_vec() => b"bar".to_vec()
];
assert_eq!(expected, ext.storage);
}
#[test]
fn keccak256_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_keccak256", &CallData(b"".to_vec())).unwrap(),
FromHex::from_hex("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").unwrap()
);
assert_eq!(
WasmExecutor.call(&mut ext, &test_code[..], "test_keccak256", &CallData(b"Hello world!".to_vec())).unwrap(),
FromHex::from_hex("ecd0e108a98e192af1d2c25055f4e3bed784b5c877204e73219a5203251feaab").unwrap()
);
}
}
@@ -11,3 +11,4 @@ lazy_static = "1.0.0"
parking_lot = "0.5"
polkadot-state-machine = { path = "../../state_machine" , version = "0.1" }
environmental = { path = "../../environmental", version = "0.1.0" }
tiny-keccak = "1.3"
@@ -1,6 +1,7 @@
#[macro_use]
extern crate environmental;
extern crate polkadot_state_machine;
extern crate tiny_keccak;
pub use std::vec::Vec;
pub use std::rc::Rc;
@@ -75,6 +76,9 @@ pub fn chain_id() -> u64 {
).unwrap_or(0)
}
/// Conduct a Keccak-256 hash of the given data.
pub use tiny_keccak::keccak256;
/// Execute the given closure with global function available whose functionality routes into the
/// externalities `ext`. Forwards the value that the closure returns.
pub fn with_externalities<R, F: FnOnce() -> R>(ext: &mut Externalities<Error=NoError>, f: F) -> R {
@@ -0,0 +1,5 @@
pub mod endiansensitive;
pub mod streamreader;
pub mod joiner;
pub mod slicable;
pub mod keyedvec;
+7 -13
View File
@@ -4,20 +4,14 @@
#[macro_use]
extern crate runtime_support;
mod codec;
mod support;
pub use support::{endiansensitive, streamreader, joiner, slicable, primitives, keyedvec, function,
environment, storage};
mod runtime;
pub use codec::{endiansensitive, streamreader, joiner, slicable, keyedvec};
pub use support::{primitives, function, environment, storage};
#[cfg(test)]
pub use support::testing;
#[allow(unused)]
mod system;
#[allow(unused)]
mod consensus;
#[allow(unused)]
mod staking;
#[allow(unused)]
mod timestamp;
#[allow(unused_imports)] // TODO: remove in due course
use runtime_support::Vec;
use slicable::Slicable;
@@ -29,11 +23,11 @@ use primitives::{Block, Transaction};
// - ECDSA-recover (or some better sig scheme)
pub fn execute_block(input: Vec<u8>) -> Vec<u8> {
system::execute_block(Block::from_slice(&input).unwrap())
runtime::system::execute_block(Block::from_slice(&input).unwrap())
}
pub fn execute_transaction(input: Vec<u8>) -> Vec<u8> {
system::execute_transaction(&Transaction::from_slice(&input).unwrap())
runtime::system::execute_transaction(&Transaction::from_slice(&input).unwrap())
}
impl_stubs!(execute_block, execute_transaction);
@@ -0,0 +1,8 @@
#[allow(unused)]
pub mod system;
#[allow(unused)]
pub mod consensus;
#[allow(unused)]
pub mod staking;
#[allow(unused)]
pub mod timestamp;
@@ -1,7 +1,7 @@
use keyedvec::KeyedVec;
use storage::{Storage, storage_into};
use primitives::{BlockNumber, Balance, AccountID};
use consensus;
use runtime::consensus;
/// The length of a staking era in blocks.
pub fn era_length() -> BlockNumber {
@@ -68,7 +68,7 @@ mod tests {
use runtime_support::with_externalities;
use testing::TestExternalities;
use primitives::{AccountID};
use staking;
use runtime::staking;
macro_rules! map {
($( $name:expr => $value:expr ),*) => (
@@ -1,8 +1,8 @@
use primitives::{Block, BlockNumber, Hash, Transaction};
use runtime_support::{Vec, swap};
use environment::with_env;
use staking;
use runtime_support;
use runtime::staking;
/// The current block number being processed. Set by `execute_block`.
pub fn block_number() -> BlockNumber {
@@ -79,8 +79,7 @@ mod tests {
use std::collections::HashMap;
use runtime_support::{NoError, with_externalities, Externalities};
use primitives::{AccountID, Transaction};
use system;
use staking;
use runtime::{system, staking};
#[derive(Debug, Default)]
struct TestExternalities {
@@ -1,5 +1,4 @@
use staking;
use consensus;
use runtime::{staking, consensus};
use primitives::AccountID;
use streamreader::StreamReader;
@@ -1,9 +1,4 @@
pub mod endiansensitive;
pub mod streamreader;
pub mod joiner;
pub mod slicable;
pub mod primitives;
pub mod keyedvec;
pub mod function;
pub mod environment;
pub mod storage;
+11
View File
@@ -29,6 +29,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) -> u32;
fn ext_chain_id() -> u64;
fn ext_keccak256(data: *const u8, len: u32, out: *mut u8);
}
pub fn storage(key: &[u8]) -> Vec<u8> {
@@ -78,6 +79,16 @@ pub fn chain_id() -> u64 {
}
}
/// Conduct a keccak256 hash.
pub fn keccak256(data: &[u8]) -> [u8; 32] {
unsafe {
let mut result: [u8; 32] = uninitialized();
// guaranteed to write into result.
ext_keccak256(&data[0], data.len() as u32, &mut result[0]);
result
}
}
pub trait Printable {
fn print(self);
}
+9 -56
View File
@@ -8,72 +8,25 @@ use alloc::vec::Vec;
#[macro_use]
extern crate runtime_support;
use runtime_support::{set_storage, storage, print};
use runtime_support::{set_storage, storage, print, keccak256};
pub fn code() -> Vec<u8> {
storage(b"\0code")
fn test_keccak256(input: Vec<u8>) -> Vec<u8> {
keccak256(&input).to_vec()
}
pub fn set_code(new: &[u8]) {
set_storage(b"\0code", new)
}
fn value_vec(mut value: usize, initial: Vec<u8>) -> Vec<u8> {
let mut acc = initial;
while value > 0 {
acc.push(value as u8);
value /= 256;
}
acc
}
pub fn set_authority(index: usize, authority: &[u8]) {
set_storage(&value_vec(index, b"\0authority".to_vec()), authority);
}
pub fn authority(index: usize) -> Vec<u8> {
storage(&value_vec(index, b"\0authority".to_vec()))
}
pub fn set_authority_count(count: usize) {
(count..authority_count()).for_each(|i| set_authority(i, &[]));
set_storage(b"\0authority_count", &value_vec(count, Vec::new()));
}
pub fn authority_count() -> usize {
storage(b"\0authority_count").into_iter().rev().fold(0, |acc, i| (acc << 8) + (i as usize))
}
pub fn authorities() -> Vec<Vec<u8>> {
(0..authority_count()).into_iter().map(authority).collect()
}
pub fn set_authorities(authorities: &[&[u8]]) {
set_authority_count(authorities.len());
authorities.iter().enumerate().for_each(|(v, i)| set_authority(v, i));
}
impl_stubs!(test_data_in);
fn test_data_in(input: Vec<u8>) -> Vec<u8> {
print(b"set_storage" as &[u8]);
set_storage(b"input", &input);
print(b"code" as &[u8]);
set_storage(b"code", &code());
print(b"set_code" as &[u8]);
set_code(&input);
print(b"storage" as &[u8]);
let copy = storage(b"input");
let foo = storage(b"foo");
print(b"authorities" as &[u8]);
let mut v = authorities();
v.push(copy);
print(b"set_authorities" as &[u8]);
set_authorities(&v.iter().map(Vec::as_slice).collect::<Vec<_>>());
print(b"set_storage" as &[u8]);
set_storage(b"baz", &foo);
print(b"finished!" as &[u8]);
b"all ok!".to_vec()
}
impl_stubs!(test_data_in, test_keccak256);