diff --git a/substrate/executor/src/native_executor.rs b/substrate/executor/src/native_executor.rs index 79e6af2ea9..2f050f77b7 100644 --- a/substrate/executor/src/native_executor.rs +++ b/substrate/executor/src/native_executor.rs @@ -99,7 +99,6 @@ mod tests { let foreign_code = include_bytes!("../../wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm"); let r = NativeExecutor.call(&mut t, &foreign_code[..], "execute_transaction", &CallData(tx())); - println!("{:?}", r); assert!(r.is_ok()); runtime_support::with_externalities(&mut t, || { diff --git a/substrate/executor/src/wasm_executor.rs b/substrate/executor/src/wasm_executor.rs index 05cb5580eb..2269de51d4 100644 --- a/substrate/executor/src/wasm_executor.rs +++ b/substrate/executor/src/wasm_executor.rs @@ -27,6 +27,7 @@ use error::{Error, ErrorKind, Result}; use wasm_utils::{MemoryInstance, UserDefinedElements, AddModuleWithoutFullDependentInstance}; use primitives::{ed25519, blake2_256, twox_128, twox_256}; +use primitives::hexdisplay::HexDisplay; struct Heap { end: u32, @@ -151,47 +152,63 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, this.ext.chain_id() }, ext_twox_128(data: *const u8, len: u32, out: *mut u8) => { - let result = - if let Ok(value) = this.memory.get(data, len as usize) { - twox_128(&value) - } else { - [0; 16] - }; + let maybe_value = if len == 0 { + Ok(vec![]) + } else { + this.memory.get(data, len as usize) + }; + let result = if let Ok(value) = maybe_value { + twox_128(&value) + } else { + [0; 16] + }; let _ = this.memory.set(out, &result); }, ext_twox_256(data: *const u8, len: u32, out: *mut u8) => { - let result = - if let Ok(value) = this.memory.get(data, len as usize) { - twox_256(&value) - } else { - [0; 32] - }; + let maybe_value = if len == 0 { + Ok(vec![]) + } else { + this.memory.get(data, len as usize) + }; + let result = if let Ok(value) = maybe_value { + twox_256(&value) + } else { + [0; 32] + }; let _ = this.memory.set(out, &result); }, ext_blake2_256(data: *const u8, len: u32, out: *mut u8) => { - let result = - if let Ok(value) = this.memory.get(data, len as usize) { - blake2_256(&value) - } else { - [0; 32] - }; + let maybe_value = if len == 0 { + Ok(vec![]) + } else { + this.memory.get(data, len as usize) + }; + let result = if let Ok(value) = maybe_value { + blake2_256(&value) + } else { + [0; 32] + }; let _ = this.memory.set(out, &result); }, 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 0; + return 2; }; let mut pubkey = [0u8; 32]; if let Err(_) = this.memory.get_into(pubkey_data, &mut pubkey[..]) { - return 0; + return 3; }; if let Ok(msg) = this.memory.get(msg_data, msg_len as usize) { - if ed25519::Signature::from(sig).verify(&msg, &ed25519::Public::from(pubkey)) { 1 } else { 0 } + if ed25519::Signature::from(sig).verify(&msg, &ed25519::Public::from(pubkey)) { + 0 + } else { + 5 + } } else { - 0 + 4 } })() } @@ -253,6 +270,7 @@ mod tests { use super::*; use rustc_hex::FromHex; use native_runtime::testing::TestExternalities; + use primitives::hashing::blake2_256; #[test] fn returning_should_work() { @@ -299,11 +317,11 @@ mod tests { 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_blake2_256", &CallData(b"".to_vec())).unwrap(), - FromHex::from_hex("0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8").unwrap() + blake2_256(&b""[..]).to_vec() ); assert_eq!( WasmExecutor.call(&mut ext, &test_code[..], "test_blake2_256", &CallData(b"Hello world!".to_vec())).unwrap(), - FromHex::from_hex("3fbc092db9350757e2ab4f7ee9792bfcd2f5220ada5a4bc684487f60c6034369").unwrap() + blake2_256(&b"Hello world!"[..]).to_vec() ); } @@ -346,7 +364,47 @@ mod tests { calldata.extend_from_slice(sig.as_ref()); assert_eq!( WasmExecutor.call(&mut ext, &test_code[..], "test_ed25519_verify", &CallData(calldata)).unwrap(), - vec![1] + vec![0] ); } + + use primitives::twox_128; + use native_runtime::testing::{one, two}; + use native_runtime::statichex::StaticHexInto; + use native_runtime::keyedvec::KeyedVec; + use native_runtime::runtime::staking::balance; + use runtime_support; + + fn tx() -> Vec { "679fcf0a846b4224c84ecad7d91a26241c46d00cb53d6480a363274e8965ee34b0b80b4b2e3836d3d8f8f12c0c1aef7350af587d9aee3883561d11726068ac0a2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000228000000d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000".convert() } + + #[test] + fn panic_execution_gives_error() { + let one = one(); + let mut t = TestExternalities { storage: map![ + twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0] + ], }; + + 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())); + assert!(r.is_err()); + } + + #[test] + fn successful_execution_gives_ok() { + let one = one(); + let two = two(); + + let mut t = TestExternalities { storage: map![ + twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0] + ], }; + + 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())); + assert!(r.is_ok()); + + runtime_support::with_externalities(&mut t, || { + assert_eq!(balance(&one), 42); + assert_eq!(balance(&two), 69); + }); + } } diff --git a/substrate/native-runtime/support/src/lib.rs b/substrate/native-runtime/support/src/lib.rs index fc5a99ac48..4d665fc0de 100644 --- a/substrate/native-runtime/support/src/lib.rs +++ b/substrate/native-runtime/support/src/lib.rs @@ -105,6 +105,28 @@ pub fn with_externalities R>(ext: &mut Externalities, f: F) -> ext::using(ext, f) } +pub trait Printable { + fn print(self); +} + +impl<'a> Printable for &'a [u8] { + fn print(self) { + if let Ok(s) = ::std::str::from_utf8(self) { + println!("Runtime: {}", s); + } + } +} + +impl Printable for u64 { + fn print(self) { + println!("Runtime: {}", self); + } +} + +pub fn print(value: T) { + value.print(); +} + #[macro_export] macro_rules! impl_stubs { ($( $name:ident ),*) => {} diff --git a/substrate/wasm-runtime/polkadot/src/lib.rs b/substrate/wasm-runtime/polkadot/src/lib.rs index c03fcc83c5..c23622cec8 100644 --- a/substrate/wasm-runtime/polkadot/src/lib.rs +++ b/substrate/wasm-runtime/polkadot/src/lib.rs @@ -47,12 +47,9 @@ pub fn execute_block(input: &[u8]) -> Vec { /// Execute a given, serialised, transaction. Returns the empty vector. pub fn execute_transaction(input: &[u8]) -> Vec { - if input.len() == 0 { - panic!("no transaction data given!"); - } let utx = UncheckedTransaction::from_slice(input).unwrap(); runtime::system::execute_transaction(&utx); - input.to_vec()//Vec::new() + Vec::new() } impl_stubs!(execute_block, execute_transaction); diff --git a/substrate/wasm-runtime/polkadot/src/runtime/system.rs b/substrate/wasm-runtime/polkadot/src/runtime/system.rs index 042d1af2d7..2749c3ad9f 100644 --- a/substrate/wasm-runtime/polkadot/src/runtime/system.rs +++ b/substrate/wasm-runtime/polkadot/src/runtime/system.rs @@ -20,6 +20,7 @@ use primitives::{Block, BlockNumber, Hash, UncheckedTransaction, TxOrder, Hashable}; use runtime_support::mem; use runtime_support::prelude::*; +use runtime_support::print; use storable::Storable; use keyedvec::KeyedVec; use environment::with_env; @@ -84,6 +85,7 @@ pub fn execute_block(mut block: Block) { /// Execute a given transaction. pub fn execute_transaction(utx: &UncheckedTransaction) { + print(&b"HERE"[..]); // Verify the signature is good. assert!(utx.ed25519_verify(), "All transactions should be properly signed"); diff --git a/substrate/wasm-runtime/support/src/lib.rs b/substrate/wasm-runtime/support/src/lib.rs index 1f71973c18..454ba8507f 100644 --- a/substrate/wasm-runtime/support/src/lib.rs +++ b/substrate/wasm-runtime/support/src/lib.rs @@ -1,9 +1,9 @@ #![no_std] #![feature(lang_items)] +#![feature(core_intrinsics)] #![feature(alloc)] #![cfg_attr(feature = "strict", deny(warnings))] -#![feature(alloc)] extern crate alloc; pub use alloc::vec; @@ -26,8 +26,13 @@ extern crate pwasm_alloc; #[lang = "panic_fmt"] #[no_mangle] -pub fn panic_fmt() -> ! { - loop {} +pub extern fn panic_fmt(_fmt: ::core::fmt::Arguments, _file: &'static str, _line: u32, _col: u32) { + unsafe { + ext_print(_file.as_ptr() as *const u8, _file.len() as u32); + ext_print_num(_line as u64); + ext_print_num(_col as u64); + ::core::intrinsics::abort() + } } extern "C" { @@ -46,7 +51,7 @@ extern "C" { pub fn storage(key: &[u8]) -> Vec { let mut length: u32 = 0; unsafe { - let ptr = ext_get_allocated_storage(&key[0], key.len() as u32, &mut length); + let ptr = ext_get_allocated_storage(key.as_ptr(), key.len() as u32, &mut length); Vec::from_raw_parts(ptr, length as usize, length as usize) } } @@ -54,15 +59,15 @@ pub fn storage(key: &[u8]) -> Vec { pub fn set_storage(key: &[u8], value: &[u8]) { unsafe { ext_set_storage( - &key[0] as *const u8, key.len() as u32, - &value[0] as *const u8, value.len() as u32 + key.as_ptr(), key.len() as u32, + value.as_ptr(), value.len() as u32 ); } } pub fn read_storage(key: &[u8], value_out: &mut [u8], value_offset: usize) -> usize { unsafe { - ext_get_storage_into(&key[0], key.len() as u32, &mut value_out[0], value_out.len() as u32, value_offset as u32) as usize + ext_get_storage_into(key.as_ptr(), key.len() as u32, value_out.as_mut_ptr(), value_out.len() as u32, value_offset as u32) as usize } } @@ -72,41 +77,61 @@ pub fn chain_id() -> u64 { ext_chain_id() } } +/* +trait AsPtr { + fn ptr(self) -> *const u8; +} +impl<'a> AsPtr for &'a[u8] { + fn ptr(self) -> *const u8 { + if self.len() > 0 { &self[0] } else { 0 as *const u8 } + } +} + +trait AsPtrMut { + fn ptr(self) -> *mut u8; +} + +impl<'a> AsPtrMut for &'a mut [u8] { + fn ptr(self) -> *mut u8 { + if self.len() > 0 { &mut self[0] } else { 0 as *mut u8 } + } +} +*/ /// 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 { - let mut result: [u8; 32] = Default::default(); - // guaranteed to write into result. - ext_blake2_256(&data[0], data.len() as u32, &mut result[0]); - result + ext_blake2_256(data.as_ptr(), data.len() as u32, result.as_mut_ptr()); } + result } /// 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 { - let mut result: [u8; 32] = Default::default(); - // guaranteed to write into result. - ext_twox_256(&data[0], data.len() as u32, &mut result[0]); - result + ext_twox_256(data.as_ptr(), data.len() as u32, result.as_mut_ptr()); } + result } /// Conduct two XX hashes to give a 256-bit result. pub fn twox_128(data: &[u8]) -> [u8; 16] { + let mut result: [u8; 16] = Default::default(); + // guaranteed to write into result. unsafe { - let mut result: [u8; 16] = Default::default(); - // guaranteed to write into result. - ext_twox_128(&data[0], data.len() as u32, &mut result[0]); - result + ext_twox_128(data.as_ptr(), data.len() as u32, result.as_mut_ptr()); } + result } /// Verify a ed25519 signature. pub fn ed25519_verify(sig: &[u8], msg: &[u8], pubkey: &[u8]) -> bool { sig.len() != 64 || pubkey.len() != 32 || unsafe { - ext_ed25519_verify(&msg[0], msg.len() as u32, &sig[0], &pubkey[0]) + ext_ed25519_verify(msg.as_ptr(), msg.len() as u32, sig.as_ptr(), pubkey.as_ptr()) } == 0 } @@ -150,11 +175,7 @@ macro_rules! impl_stubs { let output = super::$name(&input[..]); // things break if we try to take the address of an unallocated vec, so we // shortcircuit the empty output case. - if output.len() > 0 { - &output[0] as *const u8 as u64 + ((output.len() as u64) << 32) - } else { - 0 - } + output.as_ptr() as u64 + ((output.len() as u64) << 32) } )* } diff --git a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm index 68996e2c26..9a03a7370d 100644 Binary files a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm and b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm differ diff --git a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm index 0deae851a2..7c56e0c5d7 100644 Binary files a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm and b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm differ 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 d5026fc30a..2e00c051fd 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 df28ddb3cb..e8be4d6d0c 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