diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index d0eee3e39a..2ac1c11912 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -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]] diff --git a/substrate/executor/Cargo.toml b/substrate/executor/Cargo.toml index 8aa72f4327..2d124f60ac 100644 --- a/substrate/executor/Cargo.toml +++ b/substrate/executor/Cargo.toml @@ -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" diff --git a/substrate/executor/src/lib.rs b/substrate/executor/src/lib.rs index 8bf7f42b62..3c54d25efb 100644 --- a/substrate/executor/src/lib.rs +++ b/substrate/executor/src/lib.rs @@ -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; diff --git a/substrate/executor/src/wasm_executor.rs b/substrate/executor/src/wasm_executor.rs index b12986e975..8597656c51 100644 --- a/substrate/executor/src/wasm_executor.rs +++ b/substrate/executor/src/wasm_executor.rs @@ -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::::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() + ); + } } diff --git a/substrate/native-runtime/support/Cargo.toml b/substrate/native-runtime/support/Cargo.toml index 3f979bd4ff..185dea5f92 100644 --- a/substrate/native-runtime/support/Cargo.toml +++ b/substrate/native-runtime/support/Cargo.toml @@ -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" diff --git a/substrate/native-runtime/support/src/lib.rs b/substrate/native-runtime/support/src/lib.rs index 498081cd33..a2fe13eb10 100644 --- a/substrate/native-runtime/support/src/lib.rs +++ b/substrate/native-runtime/support/src/lib.rs @@ -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>(ext: &mut Externalities, f: F) -> R { diff --git a/substrate/wasm-runtime/polkadot/src/support/endiansensitive.rs b/substrate/wasm-runtime/polkadot/src/codec/endiansensitive.rs similarity index 100% rename from substrate/wasm-runtime/polkadot/src/support/endiansensitive.rs rename to substrate/wasm-runtime/polkadot/src/codec/endiansensitive.rs diff --git a/substrate/wasm-runtime/polkadot/src/support/joiner.rs b/substrate/wasm-runtime/polkadot/src/codec/joiner.rs similarity index 100% rename from substrate/wasm-runtime/polkadot/src/support/joiner.rs rename to substrate/wasm-runtime/polkadot/src/codec/joiner.rs diff --git a/substrate/wasm-runtime/polkadot/src/support/keyedvec.rs b/substrate/wasm-runtime/polkadot/src/codec/keyedvec.rs similarity index 100% rename from substrate/wasm-runtime/polkadot/src/support/keyedvec.rs rename to substrate/wasm-runtime/polkadot/src/codec/keyedvec.rs diff --git a/substrate/wasm-runtime/polkadot/src/codec/mod.rs b/substrate/wasm-runtime/polkadot/src/codec/mod.rs new file mode 100644 index 0000000000..5350dc05c1 --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/codec/mod.rs @@ -0,0 +1,5 @@ +pub mod endiansensitive; +pub mod streamreader; +pub mod joiner; +pub mod slicable; +pub mod keyedvec; diff --git a/substrate/wasm-runtime/polkadot/src/support/slicable.rs b/substrate/wasm-runtime/polkadot/src/codec/slicable.rs similarity index 100% rename from substrate/wasm-runtime/polkadot/src/support/slicable.rs rename to substrate/wasm-runtime/polkadot/src/codec/slicable.rs diff --git a/substrate/wasm-runtime/polkadot/src/support/streamreader.rs b/substrate/wasm-runtime/polkadot/src/codec/streamreader.rs similarity index 100% rename from substrate/wasm-runtime/polkadot/src/support/streamreader.rs rename to substrate/wasm-runtime/polkadot/src/codec/streamreader.rs diff --git a/substrate/wasm-runtime/polkadot/src/lib.rs b/substrate/wasm-runtime/polkadot/src/lib.rs index 680116b3d9..52b29b05cf 100644 --- a/substrate/wasm-runtime/polkadot/src/lib.rs +++ b/substrate/wasm-runtime/polkadot/src/lib.rs @@ -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) -> Vec { - system::execute_block(Block::from_slice(&input).unwrap()) + runtime::system::execute_block(Block::from_slice(&input).unwrap()) } pub fn execute_transaction(input: Vec) -> Vec { - system::execute_transaction(&Transaction::from_slice(&input).unwrap()) + runtime::system::execute_transaction(&Transaction::from_slice(&input).unwrap()) } impl_stubs!(execute_block, execute_transaction); diff --git a/substrate/wasm-runtime/polkadot/src/consensus.rs b/substrate/wasm-runtime/polkadot/src/runtime/consensus.rs similarity index 100% rename from substrate/wasm-runtime/polkadot/src/consensus.rs rename to substrate/wasm-runtime/polkadot/src/runtime/consensus.rs diff --git a/substrate/wasm-runtime/polkadot/src/runtime/mod.rs b/substrate/wasm-runtime/polkadot/src/runtime/mod.rs new file mode 100644 index 0000000000..c73e338a91 --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/runtime/mod.rs @@ -0,0 +1,8 @@ +#[allow(unused)] +pub mod system; +#[allow(unused)] +pub mod consensus; +#[allow(unused)] +pub mod staking; +#[allow(unused)] +pub mod timestamp; diff --git a/substrate/wasm-runtime/polkadot/src/staking.rs b/substrate/wasm-runtime/polkadot/src/runtime/staking.rs similarity index 98% rename from substrate/wasm-runtime/polkadot/src/staking.rs rename to substrate/wasm-runtime/polkadot/src/runtime/staking.rs index d8903504d2..ca37e7f6fe 100644 --- a/substrate/wasm-runtime/polkadot/src/staking.rs +++ b/substrate/wasm-runtime/polkadot/src/runtime/staking.rs @@ -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 ),*) => ( diff --git a/substrate/wasm-runtime/polkadot/src/system.rs b/substrate/wasm-runtime/polkadot/src/runtime/system.rs similarity index 98% rename from substrate/wasm-runtime/polkadot/src/system.rs rename to substrate/wasm-runtime/polkadot/src/runtime/system.rs index de8b814bcf..27c5eb4fd9 100644 --- a/substrate/wasm-runtime/polkadot/src/system.rs +++ b/substrate/wasm-runtime/polkadot/src/runtime/system.rs @@ -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 { diff --git a/substrate/wasm-runtime/polkadot/src/timestamp.rs b/substrate/wasm-runtime/polkadot/src/runtime/timestamp.rs similarity index 100% rename from substrate/wasm-runtime/polkadot/src/timestamp.rs rename to substrate/wasm-runtime/polkadot/src/runtime/timestamp.rs diff --git a/substrate/wasm-runtime/polkadot/src/support/function.rs b/substrate/wasm-runtime/polkadot/src/support/function.rs index 3f6845bfe6..ff54938d47 100644 --- a/substrate/wasm-runtime/polkadot/src/support/function.rs +++ b/substrate/wasm-runtime/polkadot/src/support/function.rs @@ -1,5 +1,4 @@ -use staking; -use consensus; +use runtime::{staking, consensus}; use primitives::AccountID; use streamreader::StreamReader; diff --git a/substrate/wasm-runtime/polkadot/src/support/mod.rs b/substrate/wasm-runtime/polkadot/src/support/mod.rs index 47b29194dc..aa14ad2f5d 100644 --- a/substrate/wasm-runtime/polkadot/src/support/mod.rs +++ b/substrate/wasm-runtime/polkadot/src/support/mod.rs @@ -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; diff --git a/substrate/wasm-runtime/support/src/lib.rs b/substrate/wasm-runtime/support/src/lib.rs index 308ab6dd9e..ae3feb14c9 100644 --- a/substrate/wasm-runtime/support/src/lib.rs +++ b/substrate/wasm-runtime/support/src/lib.rs @@ -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 { @@ -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); } diff --git a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm index bac77de7ff..f4c438ec10 100644 Binary files a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm and b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm differ diff --git a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.wasm b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.wasm index 9f8b8bc2e8..7e0366cd99 100644 Binary files a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.wasm and b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.wasm differ diff --git a/substrate/wasm-runtime/test/src/lib.rs b/substrate/wasm-runtime/test/src/lib.rs index e95844fdb0..a24de0219d 100644 --- a/substrate/wasm-runtime/test/src/lib.rs +++ b/substrate/wasm-runtime/test/src/lib.rs @@ -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 { - storage(b"\0code") +fn test_keccak256(input: Vec) -> Vec { + keccak256(&input).to_vec() } -pub fn set_code(new: &[u8]) { - set_storage(b"\0code", new) -} - -fn value_vec(mut value: usize, initial: Vec) -> Vec { - 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 { - 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> { - (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) -> Vec { 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::>()); + 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);