diff --git a/substrate/executor/src/wasm_executor.rs b/substrate/executor/src/wasm_executor.rs index 1039a20654..a741a7b07b 100644 --- a/substrate/executor/src/wasm_executor.rs +++ b/substrate/executor/src/wasm_executor.rs @@ -66,15 +66,15 @@ impl<'e, E: Externalities> FunctionExecutor<'e, E> { } trait WritePrimitive { - fn write_primitive(&self, offset: u32, t: T); + fn write_primitive(&self, offset: u32, t: T) -> ::std::result::Result<(), DummyUserError>; } impl WritePrimitive 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) } } @@ -95,29 +95,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 +136,66 @@ 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_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> ); diff --git a/substrate/wasm-runtime/polkadot/src/runtime/system.rs b/substrate/wasm-runtime/polkadot/src/runtime/system.rs index 2be96b19e3..8ca1704c20 100644 --- a/substrate/wasm-runtime/polkadot/src/runtime/system.rs +++ b/substrate/wasm-runtime/polkadot/src/runtime/system.rs @@ -18,7 +18,7 @@ //! and depositing logs. use runtime_std::prelude::*; -use runtime_std::{mem, print}; +use runtime_std::{mem, print, storage_root}; use codec::KeyedVec; use support::{Hashable, storage, with_env}; use primitives::{Block, BlockNumber, Hash, UncheckedTransaction, TxOrder}; @@ -91,9 +91,8 @@ 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."); } /// Execute a given transaction. diff --git a/substrate/wasm-runtime/std/src/lib.rs b/substrate/wasm-runtime/std/src/lib.rs index 9b7d385e69..13df07c49f 100644 --- a/substrate/wasm-runtime/std/src/lib.rs +++ b/substrate/wasm-runtime/std/src/lib.rs @@ -42,6 +42,7 @@ 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_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 +73,15 @@ 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 +} + /// The current relay chain identifier. pub fn chain_id() -> u64 { unsafe { @@ -82,7 +92,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 +101,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 +110,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()); } 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 0bd07dc534..efedffaadf 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 1e4d2fb99b..c4e00c3e3e 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