From 37acb90847cdb6c2c391516693bee20e66c8b0c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 19 Jun 2019 15:08:59 +0200 Subject: [PATCH] Remove `UserError` and switch to `error::Error` (#2899) * Remove `UserError` and switch to `error::Error` * More cleanup * Update core/executor/src/error.rs Co-Authored-By: Sergei Pepyakin * Fix typo * Update core/executor/src/allocator.rs Co-Authored-By: Stanislav Tkach --- substrate/core/executor/src/allocator.rs | 77 ++-- substrate/core/executor/src/error.rs | 21 +- substrate/core/executor/src/sandbox.rs | 83 ++-- substrate/core/executor/src/wasm_executor.rs | 405 ++++++++++--------- substrate/core/executor/src/wasm_utils.rs | 106 +++-- 5 files changed, 378 insertions(+), 314 deletions(-) diff --git a/substrate/core/executor/src/allocator.rs b/substrate/core/executor/src/allocator.rs index bf01dd2e90..9e61a2c6ef 100644 --- a/substrate/core/executor/src/allocator.rs +++ b/substrate/core/executor/src/allocator.rs @@ -17,9 +17,8 @@ //! This module implements a freeing-bump allocator. //! See more details at https://github.com/paritytech/substrate/issues/1615. -use crate::wasm_utils::UserError; +use crate::error::{Error, Result}; use log::trace; -use wasmi::Error; use wasmi::MemoryRef; use wasmi::memory_units::Bytes; @@ -34,9 +33,6 @@ const ALIGNMENT: u32 = 8; const N: usize = 22; const MAX_POSSIBLE_ALLOCATION: u32 = 16777216; // 2^24 bytes -pub const OUT_OF_SPACE: &str = "Requested allocation size does not fit into remaining heap space"; -pub const REQUESTED_SIZE_TOO_LARGE: &str = "Requested size to allocate is too large"; - pub struct FreeingBumpHeapAllocator { bumper: u32, heads: [u32; N], @@ -46,8 +42,12 @@ pub struct FreeingBumpHeapAllocator { total_size: u32, } -impl FreeingBumpHeapAllocator { +/// Create an allocator error. +fn error(msg: &'static str) -> Error { + Error::Allocator(msg) +} +impl FreeingBumpHeapAllocator { /// Creates a new allocation heap which follows a freeing-bump strategy. /// The maximum size which can be allocated at once is 16 MiB. /// @@ -87,23 +87,22 @@ impl FreeingBumpHeapAllocator { /// Gets requested number of bytes to allocate and returns a pointer. /// The maximum size which can be allocated at once is 16 MiB. - pub fn allocate(&mut self, size: u32) -> Result { + pub fn allocate(&mut self, size: u32) -> Result { if size > MAX_POSSIBLE_ALLOCATION { - return Err(UserError(REQUESTED_SIZE_TOO_LARGE)); + return Err(Error::RequestedAllocationTooLarge); } let size = size.max(8); let item_size = size.next_power_of_two(); if item_size + 8 + self.total_size > self.max_heap_size { - return Err(UserError(OUT_OF_SPACE)); + return Err(Error::AllocatorOutOfSpace); } let list_index = (item_size.trailing_zeros() - 3) as usize; let ptr: u32 = if self.heads[list_index] != 0 { // Something from the free list let item = self.heads[list_index]; - let four_bytes = self.get_heap_4bytes(item) - .map_err(|_| UserError("Unable to get bytes at pointer taken from list of free items"))?; + let four_bytes = self.get_heap_4bytes(item)?; self.heads[list_index] = FreeingBumpHeapAllocator::le_bytes_to_u32(four_bytes); item + 8 } else { @@ -111,13 +110,9 @@ impl FreeingBumpHeapAllocator { self.bump(item_size + 8) + 8 }; - for i in 1..8 { - self.set_heap(ptr - i, 255) - .map_err(|_| UserError("Unable to successively write bytes into heap at pointer prefix"))?; - } + (1..8).try_for_each(|i| self.set_heap(ptr - i, 255))?; - self.set_heap(ptr - 8, list_index as u8) - .map_err(|_| UserError("Unable to write byte into heap at pointer prefix"))?; + self.set_heap(ptr - 8, list_index as u8)?; self.total_size = self.total_size + item_size + 8; trace!(target: "wasm-heap", "Heap size is {} bytes after allocation", self.total_size); @@ -126,31 +121,24 @@ impl FreeingBumpHeapAllocator { } /// Deallocates the space which was allocated for a pointer. - pub fn deallocate(&mut self, ptr: u32) -> Result<(), UserError> { + pub fn deallocate(&mut self, ptr: u32) -> Result<()> { let ptr = ptr - self.ptr_offset; if ptr < 8 { - return Err(UserError("Invalid pointer for deallocation")); + return Err(error("Invalid pointer for deallocation")); } - let list_index = self.get_heap_byte(ptr - 8) - .map_err(|_| UserError("Unable to access pointer prefix"))? as usize; - for i in 1..8 { - let heap_byte = self.get_heap_byte(ptr - i) - .map_err(|_| UserError("Unable to write single bytes into heap at pointer"))?; - debug_assert!(heap_byte == 255) - } + let list_index = usize::from(self.get_heap_byte(ptr - 8)?); + (1..8).try_for_each(|i| self.get_heap_byte(ptr - i).map(|byte| assert!(byte == 255)))?; let tail = self.heads[list_index]; self.heads[list_index] = ptr - 8; - let mut slice = self.get_heap_4bytes(ptr - 8) - .map_err(|_| UserError("Unable to get 4 bytes from heap at pointer prefix"))?; + let mut slice = self.get_heap_4bytes(ptr - 8)?; FreeingBumpHeapAllocator::write_u32_into_le_bytes(tail, &mut slice); - self.set_heap_4bytes(ptr - 8, slice) - .map_err(|_| UserError("Unable to write 4 bytes into heap at pointer prefix"))?; + self.set_heap_4bytes(ptr - 8, slice)?; let item_size = FreeingBumpHeapAllocator::get_item_size_from_index(list_index); self.total_size = self.total_size.checked_sub(item_size as u32 + 8) - .ok_or_else(|| UserError("Unable to subtract from total heap size without overflow"))?; + .ok_or_else(|| error("Unable to subtract from total heap size without overflow"))?; trace!(target: "wasm-heap", "Heap size is {} bytes after deallocation", self.total_size); Ok(()) @@ -176,24 +164,24 @@ impl FreeingBumpHeapAllocator { 1 << 3 << index } - fn get_heap_4bytes(&mut self, ptr: u32) -> Result<[u8; 4], Error> { + fn get_heap_4bytes(&mut self, ptr: u32) -> Result<[u8; 4]> { let mut arr = [0u8; 4]; self.heap.get_into(self.ptr_offset + ptr, &mut arr)?; Ok(arr) } - fn get_heap_byte(&mut self, ptr: u32) -> Result { + fn get_heap_byte(&mut self, ptr: u32) -> Result { let mut arr = [0u8; 1]; self.heap.get_into(self.ptr_offset + ptr, &mut arr)?; Ok(arr[0]) } - fn set_heap(&mut self, ptr: u32, value: u8) -> Result<(), Error> { - self.heap.set(self.ptr_offset + ptr, &[value]) + fn set_heap(&mut self, ptr: u32, value: u8) -> Result<()> { + self.heap.set(self.ptr_offset + ptr, &[value]).map_err(Into::into) } - fn set_heap_4bytes(&mut self, ptr: u32, value: [u8; 4]) -> Result<(), Error> { - self.heap.set(self.ptr_offset + ptr, &value) + fn set_heap_4bytes(&mut self, ptr: u32, value: [u8; 4]) -> Result<()> { + self.heap.set(self.ptr_offset + ptr, &value).map_err(Into::into) } } @@ -353,7 +341,10 @@ mod tests { // then assert_eq!(ptr.is_err(), true); if let Err(err) = ptr { - assert_eq!(err, UserError(OUT_OF_SPACE)); + match err { + Error::AllocatorOutOfSpace => {}, + _ => panic!("Expected out of space error"), + } } } @@ -372,7 +363,10 @@ mod tests { // there is no room for another half page incl. its 8 byte prefix assert_eq!(ptr2.is_err(), true); if let Err(err) = ptr2 { - assert_eq!(err, UserError(OUT_OF_SPACE)); + match err { + Error::AllocatorOutOfSpace => {}, + _ => panic!("Expected out of space error"), + } } } @@ -402,7 +396,10 @@ mod tests { // then assert_eq!(ptr.is_err(), true); if let Err(err) = ptr { - assert_eq!(err, UserError(REQUESTED_SIZE_TOO_LARGE)); + match err { + Error::RequestedAllocationTooLarge => {}, + e => panic!("Expected out of space error, got: {:?}", e), + } } } diff --git a/substrate/core/executor/src/error.rs b/substrate/core/executor/src/error.rs index fdcb6cbc0e..a81fc1b148 100644 --- a/substrate/core/executor/src/error.rs +++ b/substrate/core/executor/src/error.rs @@ -55,9 +55,20 @@ pub enum Error { /// Runtime failed. #[display(fmt="Runtime error")] Runtime, - /// Runtime failed. + /// Invalid memory reference. #[display(fmt="Invalid memory reference")] InvalidMemoryReference, + /// Some other error occurred + Other(&'static str), + /// Some error occurred in the allocator + #[display(fmt="Error in allocator: {}", _0)] + Allocator(&'static str), + /// The allocator run out of space. + #[display(fmt="Allocator run out of space")] + AllocatorOutOfSpace, + /// Someone tried to allocate more memory than the allowed maximum per allocation. + #[display(fmt="Requested allocation size is too large")] + RequestedAllocationTooLarge, } impl std::error::Error for Error { @@ -72,3 +83,11 @@ impl std::error::Error for Error { } impl state_machine::Error for Error {} + +impl wasmi::HostError for Error {} + +impl From<&'static str> for Error { + fn from(err: &'static str) -> Error { + Error::Other(err) + } +} diff --git a/substrate/core/executor/src/sandbox.rs b/substrate/core/executor/src/sandbox.rs index 377294f7b1..ceb5f44a26 100644 --- a/substrate/core/executor/src/sandbox.rs +++ b/substrate/core/executor/src/sandbox.rs @@ -18,16 +18,13 @@ //! This module implements sandboxing support in the runtime. -use std::collections::HashMap; -use std::rc::Rc; +use crate::error::{Result, Error}; +use std::{collections::HashMap, rc::Rc}; use parity_codec::{Decode, Encode}; use primitives::sandbox as sandbox_primitives; -use crate::wasm_utils::UserError; -use wasmi; -use wasmi::memory_units::Pages; use wasmi::{ Externals, FuncRef, ImportResolver, MemoryInstance, MemoryRef, Module, ModuleInstance, - ModuleRef, RuntimeArgs, RuntimeValue, Trap, TrapKind + ModuleRef, RuntimeArgs, RuntimeValue, Trap, TrapKind, memory_units::Pages, }; /// Index of a function inside the supervisor. @@ -75,18 +72,18 @@ impl ImportResolver for Imports { module_name: &str, field_name: &str, signature: &::wasmi::Signature, - ) -> Result { + ) -> std::result::Result { let key = ( module_name.as_bytes().to_owned(), field_name.as_bytes().to_owned(), ); let idx = *self.func_map.get(&key).ok_or_else(|| { - ::wasmi::Error::Instantiation(format!( + wasmi::Error::Instantiation(format!( "Export {}:{} not found", module_name, field_name )) })?; - Ok(::wasmi::FuncInstance::alloc_host(signature.clone(), idx.0)) + Ok(wasmi::FuncInstance::alloc_host(signature.clone(), idx.0)) } fn resolve_memory( @@ -94,7 +91,7 @@ impl ImportResolver for Imports { module_name: &str, field_name: &str, _memory_type: &::wasmi::MemoryDescriptor, - ) -> Result { + ) -> std::result::Result { let key = ( module_name.as_bytes().to_vec(), field_name.as_bytes().to_vec(), @@ -102,7 +99,7 @@ impl ImportResolver for Imports { let mem = self.memories_map .get(&key) .ok_or_else(|| { - ::wasmi::Error::Instantiation(format!( + wasmi::Error::Instantiation(format!( "Export {}:{} not found", module_name, field_name )) @@ -116,8 +113,8 @@ impl ImportResolver for Imports { module_name: &str, field_name: &str, _global_type: &::wasmi::GlobalDescriptor, - ) -> Result<::wasmi::GlobalRef, ::wasmi::Error> { - Err(::wasmi::Error::Instantiation(format!( + ) -> std::result::Result { + Err(wasmi::Error::Instantiation(format!( "Export {}:{} not found", module_name, field_name ))) @@ -128,8 +125,8 @@ impl ImportResolver for Imports { module_name: &str, field_name: &str, _table_type: &::wasmi::TableDescriptor, - ) -> Result<::wasmi::TableRef, ::wasmi::Error> { - Err(::wasmi::Error::Instantiation(format!( + ) -> std::result::Result { + Err(wasmi::Error::Instantiation(format!( "Export {}:{} not found", module_name, field_name ))) @@ -153,7 +150,7 @@ pub trait SandboxCapabilities { /// Returns `Err` if allocation not possible or errors during heap management. /// /// Returns pointer to the allocated block. - fn allocate(&mut self, len: u32) -> Result; + fn allocate(&mut self, len: u32) -> Result; /// Deallocate space specified by the pointer that was previously returned by [`allocate`]. /// @@ -162,21 +159,21 @@ pub trait SandboxCapabilities { /// Returns `Err` if deallocation not possible or because of errors in heap management. /// /// [`allocate`]: #tymethod.allocate - fn deallocate(&mut self, ptr: u32) -> Result<(), UserError>; + fn deallocate(&mut self, ptr: u32) -> Result<()>; /// Write `data` into the supervisor memory at offset specified by `ptr`. /// /// # Errors /// /// Returns `Err` if `ptr + data.len()` is out of bounds. - fn write_memory(&mut self, ptr: u32, data: &[u8]) -> Result<(), UserError>; + fn write_memory(&mut self, ptr: u32, data: &[u8]) -> Result<()>; /// Read `len` bytes from the supervisor memory. /// /// # Errors /// /// Returns `Err` if `ptr + len` is out of bounds. - fn read_memory(&self, ptr: u32, len: u32) -> Result, UserError>; + fn read_memory(&self, ptr: u32, len: u32) -> Result>; } /// Implementation of [`Externals`] that allows execution of guest module with @@ -190,12 +187,12 @@ pub struct GuestExternals<'a, FE: SandboxCapabilities + Externals + 'a> { } fn trap(msg: &'static str) -> Trap { - TrapKind::Host(Box::new(UserError(msg))).into() + TrapKind::Host(Box::new(Error::Other(msg))).into() } -fn deserialize_result(serialized_result: &[u8]) -> Result, Trap> { +fn deserialize_result(serialized_result: &[u8]) -> std::result::Result, Trap> { use self::sandbox_primitives::{HostError, ReturnValue}; - let result_val = Result::::decode(&mut &serialized_result[..]) + let result_val = std::result::Result::::decode(&mut &serialized_result[..]) .ok_or_else(|| trap("Decoding Result failed!"))?; match result_val { @@ -212,7 +209,7 @@ impl<'a, FE: SandboxCapabilities + Externals + 'a> Externals for GuestExternals< &mut self, index: usize, args: RuntimeArgs, - ) -> Result, Trap> { + ) -> std::result::Result, Trap> { // Make `index` typesafe again. let index = GuestFuncIndex(index); @@ -331,7 +328,7 @@ impl SandboxInstance { args: &[RuntimeValue], supervisor_externals: &mut FE, state: u32, - ) -> Result, wasmi::Error> { + ) -> std::result::Result, wasmi::Error> { with_guest_externals( supervisor_externals, self, @@ -362,7 +359,7 @@ pub enum InstantiationError { fn decode_environment_definition( raw_env_def: &[u8], memories: &[Option], -) -> Result<(Imports, GuestToSupervisorFunctionMapping), InstantiationError> { +) -> std::result::Result<(Imports, GuestToSupervisorFunctionMapping), InstantiationError> { let env_def = sandbox_primitives::EnvironmentDefinition::decode(&mut &raw_env_def[..]) .ok_or_else(|| InstantiationError::EnvironmentDefintionCorrupted)?; @@ -420,7 +417,7 @@ pub fn instantiate( wasm: &[u8], raw_env_def: &[u8], state: u32, -) -> Result { +) -> std::result::Result { let (imports, guest_to_supervisor_mapping) = decode_environment_definition(raw_env_def, &supervisor_externals.store().memories)?; @@ -476,7 +473,7 @@ impl Store { /// /// Returns `Err` if the memory couldn't be created. /// Typically happens if `initial` is more than `maximum`. - pub fn new_memory(&mut self, initial: u32, maximum: u32) -> Result { + pub fn new_memory(&mut self, initial: u32, maximum: u32) -> Result { let maximum = match maximum { sandbox_primitives::MEM_UNLIMITED => None, specified_limit => Some(Pages(specified_limit as usize)), @@ -486,8 +483,7 @@ impl Store { MemoryInstance::alloc( Pages(initial as usize), maximum, - ) - .map_err(|_| UserError("Sandboxed memory allocation error"))?; + )?; let mem_idx = self.memories.len(); self.memories.push(Some(mem)); @@ -500,12 +496,12 @@ impl Store { /// /// Returns `Err` If `instance_idx` isn't a valid index of an instance or /// instance is already torndown. - pub fn instance(&self, instance_idx: u32) -> Result, UserError> { + pub fn instance(&self, instance_idx: u32) -> Result> { self.instances .get(instance_idx as usize) .cloned() - .ok_or_else(|| UserError("Trying to access a non-existent instance"))? - .ok_or_else(|| UserError("Trying to access a torndown instance")) + .ok_or_else(|| "Trying to access a non-existent instance")? + .ok_or_else(|| "Trying to access a torndown instance".into()) } /// Returns reference to a memory instance by `memory_idx`. @@ -514,12 +510,12 @@ impl Store { /// /// Returns `Err` If `memory_idx` isn't a valid index of an memory or /// if memory has been torn down. - pub fn memory(&self, memory_idx: u32) -> Result { + pub fn memory(&self, memory_idx: u32) -> Result { self.memories .get(memory_idx as usize) .cloned() - .ok_or_else(|| UserError("Trying to access a non-existent sandboxed memory"))? - .ok_or_else(|| UserError("Trying to access a torndown sandboxed memory")) + .ok_or_else(|| "Trying to access a non-existent sandboxed memory")? + .ok_or_else(|| "Trying to access a torndown sandboxed memory".into()) } /// Tear down the memory at the specified index. @@ -528,10 +524,10 @@ impl Store { /// /// Returns `Err` if `memory_idx` isn't a valid index of an memory or /// if it has been torn down. - pub fn memory_teardown(&mut self, memory_idx: u32) -> Result<(), UserError> { + pub fn memory_teardown(&mut self, memory_idx: u32) -> Result<()> { match self.memories.get_mut(memory_idx as usize) { - None => Err(UserError("Trying to teardown a non-existent sandboxed memory")), - Some(None) => Err(UserError("Double teardown of a sandboxed memory")), + None => Err("Trying to teardown a non-existent sandboxed memory".into()), + Some(None) => Err("Double teardown of a sandboxed memory".into()), Some(memory) => { *memory = None; Ok(()) @@ -545,10 +541,10 @@ impl Store { /// /// Returns `Err` if `instance_idx` isn't a valid index of an instance or /// if it has been torn down. - pub fn instance_teardown(&mut self, instance_idx: u32) -> Result<(), UserError> { + pub fn instance_teardown(&mut self, instance_idx: u32) -> Result<()> { match self.instances.get_mut(instance_idx as usize) { - None => Err(UserError("Trying to teardown a non-existent instance")), - Some(None) => Err(UserError("Double teardown of an instance")), + None => Err("Trying to teardown a non-existent instance".into()), + Some(None) => Err("Double teardown of an instance".into()), Some(instance) => { *instance = None; Ok(()) @@ -565,9 +561,8 @@ impl Store { #[cfg(test)] mod tests { + use super::*; use primitives::{Blake2Hasher}; - use crate::allocator; - use crate::sandbox::trap; use crate::wasm_executor::WasmExecutor; use state_machine::TestExternalities as CoreTestExternalities; use wabt; @@ -647,7 +642,7 @@ mod tests { if let Err(err) = res { assert_eq!( format!("{}", err), - format!("{}", wasmi::Error::Trap(trap(allocator::OUT_OF_SPACE))) + format!("{}", wasmi::Error::Trap(Error::AllocatorOutOfSpace.into())) ); } } diff --git a/substrate/core/executor/src/wasm_executor.rs b/substrate/core/executor/src/wasm_executor.rs index 22a871bf2f..cbb47195de 100644 --- a/substrate/core/executor/src/wasm_executor.rs +++ b/substrate/core/executor/src/wasm_executor.rs @@ -16,20 +16,16 @@ //! Rust implementation of Substrate contracts. -use std::collections::HashMap; -use std::convert::TryFrom; -use std::str; +use std::{collections::HashMap, convert::TryFrom, str}; use tiny_keccak; use secp256k1; use wasmi::{ Module, ModuleInstance, MemoryInstance, MemoryRef, TableRef, ImportsBuilder, ModuleRef, + memory_units::Pages, RuntimeValue::{I32, I64, self}, }; -use wasmi::RuntimeValue::{I32, I64, self}; -use wasmi::memory_units::{Pages}; use state_machine::{Externalities, ChildStorageKey}; use crate::error::{Error, Result}; -use crate::wasm_utils::UserError; use primitives::{blake2_128, blake2_256, twox_64, twox_128, twox_256, ed25519, sr25519, Pair}; use primitives::offchain; use primitives::hexdisplay::HexDisplay; @@ -78,42 +74,41 @@ impl<'e, E: Externalities> sandbox::SandboxCapabilities for Functi fn store_mut(&mut self) -> &mut sandbox::Store { &mut self.sandbox_store } - fn allocate(&mut self, len: u32) -> ::std::result::Result { + fn allocate(&mut self, len: u32) -> Result { self.heap.allocate(len) } - fn deallocate(&mut self, ptr: u32) -> ::std::result::Result<(), UserError> { + fn deallocate(&mut self, ptr: u32) -> Result<()> { self.heap.deallocate(ptr) } - fn write_memory(&mut self, ptr: u32, data: &[u8]) -> ::std::result::Result<(), UserError> { - self.memory.set(ptr, data).map_err(|_| UserError("Invalid attempt to write_memory")) + fn write_memory(&mut self, ptr: u32, data: &[u8]) -> Result<()> { + self.memory.set(ptr, data).map_err(Into::into) } - fn read_memory(&self, ptr: u32, len: u32) -> ::std::result::Result, UserError> { - self.memory.get(ptr, len as usize).map_err(|_| UserError("Invalid attempt to write_memory")) + fn read_memory(&self, ptr: u32, len: u32) -> Result> { + self.memory.get(ptr, len as usize).map_err(Into::into) } } trait WritePrimitive { - fn write_primitive(&self, offset: u32, t: T) -> ::std::result::Result<(), UserError>; + fn write_primitive(&self, offset: u32, t: T) -> Result<()>; } impl WritePrimitive for MemoryInstance { - fn write_primitive(&self, offset: u32, t: u32) -> ::std::result::Result<(), UserError> { + fn write_primitive(&self, offset: u32, t: u32) -> Result<()> { use byteorder::{LittleEndian, ByteOrder}; let mut r = [0u8; 4]; LittleEndian::write_u32(&mut r, t); - self.set(offset, &r).map_err(|_| UserError("Invalid attempt to write_primitive")) + self.set(offset, &r).map_err(Into::into) } } trait ReadPrimitive { - fn read_primitive(&self, offset: u32) -> ::std::result::Result; + fn read_primitive(&self, offset: u32) -> Result; } impl ReadPrimitive for MemoryInstance { - fn read_primitive(&self, offset: u32) -> ::std::result::Result { + fn read_primitive(&self, offset: u32) -> Result { use byteorder::{LittleEndian, ByteOrder}; - let result = self.get(offset, 4) - .map_err(|_| UserError("Invalid attempt to read_primitive"))?; + let result = self.get(offset, 4)?; Ok(LittleEndian::read_u32(&result)) } } @@ -167,14 +162,14 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, }, ext_set_storage(key_data: *const u8, key_len: u32, value_data: *const u8, value_len: u32) => { let key = this.memory.get(key_data, key_len as usize) - .map_err(|_| UserError("Invalid attempt to determine key in ext_set_storage"))?; + .map_err(|_| "Invalid attempt to determine key in ext_set_storage")?; let value = this.memory.get(value_data, value_len as usize) - .map_err(|_| UserError("Invalid attempt to determine value in ext_set_storage"))?; + .map_err(|_| "Invalid attempt to determine value in ext_set_storage")?; if let Some(_preimage) = this.hash_lookup.get(&key) { debug_trace!( target: "wasm-trace", "*** Setting storage: %{} -> {} [k={}]", - ::primitives::hexdisplay::ascii_format(&_preimage), + primitives::hexdisplay::ascii_format(&_preimage), HexDisplay::from(&value), HexDisplay::from(&key), ); @@ -182,7 +177,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, debug_trace!( target: "wasm-trace", "*** Setting storage: {} -> {} [k={}]", - ::primitives::hexdisplay::ascii_format(&key), + primitives::hexdisplay::ascii_format(&key), HexDisplay::from(&value), HexDisplay::from(&key), ); @@ -199,32 +194,30 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, value_len: u32 ) => { let storage_key = this.memory.get(storage_key_data, storage_key_len as usize) - .map_err(|_| UserError("Invalid attempt to determine storage_key in ext_set_child_storage"))?; + .map_err(|_| "Invalid attempt to determine storage_key in ext_set_child_storage")?; let key = this.memory.get(key_data, key_len as usize) - .map_err(|_| UserError("Invalid attempt to determine key in ext_set_child_storage"))?; + .map_err(|_| "Invalid attempt to determine key in ext_set_child_storage")?; let value = this.memory.get(value_data, value_len as usize) - .map_err(|_| UserError("Invalid attempt to determine value in ext_set_child_storage"))?; + .map_err(|_| "Invalid attempt to determine value in ext_set_child_storage")?; if let Some(_preimage) = this.hash_lookup.get(&key) { debug_trace!( target: "wasm-trace", "*** Setting child storage: {} -> %{} -> {} [k={}]", - ::primitives::hexdisplay::ascii_format(&storage_key), - ::primitives::hexdisplay::ascii_format(&_preimage), + primitives::hexdisplay::ascii_format(&storage_key), + primitives::hexdisplay::ascii_format(&_preimage), HexDisplay::from(&value), HexDisplay::from(&key) ); } else { debug_trace!( target: "wasm-trace", "*** Setting child storage: {} -> {} -> {} [k={}]", - ::primitives::hexdisplay::ascii_format(&storage_key), - ::primitives::hexdisplay::ascii_format(&key), + primitives::hexdisplay::ascii_format(&storage_key), + primitives::hexdisplay::ascii_format(&key), HexDisplay::from(&value), HexDisplay::from(&key) ); } let storage_key = ChildStorageKey::from_vec(storage_key) - .ok_or_else(|| - UserError("ext_set_child_storage: child storage key is invalid") - )?; + .ok_or_else(|| "ext_set_child_storage: child storage key is invalid")?; this.ext.set_child_storage(storage_key, key, value); Ok(()) }, @@ -237,39 +230,43 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, let storage_key = this.memory.get( storage_key_data, storage_key_len as usize - ).map_err(|_| UserError("Invalid attempt to determine storage_key in ext_clear_child_storage"))?; + ).map_err(|_| "Invalid attempt to determine storage_key in ext_clear_child_storage")?; let key = this.memory.get(key_data, key_len as usize) - .map_err(|_| UserError("Invalid attempt to determine key in ext_clear_child_storage"))?; - debug_trace!(target: "wasm-trace", "*** Clearing child storage: {} -> {} [k={}]", - ::primitives::hexdisplay::ascii_format(&storage_key), + .map_err(|_| "Invalid attempt to determine key in ext_clear_child_storage")?; + debug_trace!( + target: "wasm-trace", "*** Clearing child storage: {} -> {} [k={}]", + primitives::hexdisplay::ascii_format(&storage_key), if let Some(_preimage) = this.hash_lookup.get(&key) { - format!("%{}", ::primitives::hexdisplay::ascii_format(&_preimage)) + format!("%{}", primitives::hexdisplay::ascii_format(&_preimage)) } else { - format!(" {}", ::primitives::hexdisplay::ascii_format(&key)) - }, HexDisplay::from(&key) + format!(" {}", primitives::hexdisplay::ascii_format(&key)) + }, + HexDisplay::from(&key) ); let storage_key = ChildStorageKey::from_vec(storage_key) - .ok_or_else(|| - UserError("ext_clear_child_storage: child storage key is not valid") - )?; + .ok_or_else(|| "ext_clear_child_storage: child storage key is not valid")?; + this.ext.clear_child_storage(storage_key, &key); Ok(()) }, ext_clear_storage(key_data: *const u8, key_len: u32) => { let key = this.memory.get(key_data, key_len as usize) - .map_err(|_| UserError("Invalid attempt to determine key in ext_clear_storage"))?; - debug_trace!(target: "wasm-trace", "*** Clearing storage: {} [k={}]", + .map_err(|_| "Invalid attempt to determine key in ext_clear_storage")?; + debug_trace!( + target: "wasm-trace", "*** Clearing storage: {} [k={}]", if let Some(_preimage) = this.hash_lookup.get(&key) { format!("%{}", ::primitives::hexdisplay::ascii_format(&_preimage)) } else { format!(" {}", ::primitives::hexdisplay::ascii_format(&key)) - }, HexDisplay::from(&key)); + }, + HexDisplay::from(&key) + ); this.ext.clear_storage(&key); Ok(()) }, ext_exists_storage(key_data: *const u8, key_len: u32) -> u32 => { let key = this.memory.get(key_data, key_len as usize) - .map_err(|_| UserError("Invalid attempt to determine key in ext_exists_storage"))?; + .map_err(|_| "Invalid attempt to determine key in ext_exists_storage")?; Ok(if this.ext.exists_storage(&key) { 1 } else { 0 }) }, ext_exists_child_storage( @@ -281,18 +278,16 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, let storage_key = this.memory.get( storage_key_data, storage_key_len as usize - ).map_err(|_| UserError("Invalid attempt to determine storage_key in ext_exists_child_storage"))?; + ).map_err(|_| "Invalid attempt to determine storage_key in ext_exists_child_storage")?; let key = this.memory.get(key_data, key_len as usize) - .map_err(|_| UserError("Invalid attempt to determine key in ext_exists_child_storage"))?; + .map_err(|_| "Invalid attempt to determine key in ext_exists_child_storage")?; let storage_key = ChildStorageKey::from_vec(storage_key) - .ok_or_else(|| - UserError("ext_exists_child_storage: child storage key is not valid") - )?; + .ok_or_else(|| "ext_exists_child_storage: child storage key is not valid")?; Ok(if this.ext.exists_child_storage(storage_key, &key) { 1 } else { 0 }) }, ext_clear_prefix(prefix_data: *const u8, prefix_len: u32) => { let prefix = this.memory.get(prefix_data, prefix_len as usize) - .map_err(|_| UserError("Invalid attempt to determine prefix in ext_clear_prefix"))?; + .map_err(|_| "Invalid attempt to determine prefix in ext_clear_prefix")?; this.ext.clear_prefix(&prefix); Ok(()) }, @@ -300,11 +295,9 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, let storage_key = this.memory.get( storage_key_data, storage_key_len as usize - ).map_err(|_| UserError("Invalid attempt to determine storage_key in ext_kill_child_storage"))?; + ).map_err(|_| "Invalid attempt to determine storage_key in ext_kill_child_storage")?; let storage_key = ChildStorageKey::from_vec(storage_key) - .ok_or_else(|| - UserError("ext_exists_child_storage: child storage key is not valid") - )?; + .ok_or_else(|| "ext_exists_child_storage: child storage key is not valid")?; this.ext.kill_child_storage(storage_key); Ok(()) }, @@ -313,10 +306,11 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, let key = this.memory.get( key_data, key_len as usize - ).map_err(|_| UserError("Invalid attempt to determine key in ext_get_allocated_storage"))?; + ).map_err(|_| "Invalid attempt to determine key in ext_get_allocated_storage")?; let maybe_value = this.ext.storage(&key); - debug_trace!(target: "wasm-trace", "*** Getting storage: {} == {} [k={}]", + debug_trace!( + target: "wasm-trace", "*** Getting storage: {} == {} [k={}]", if let Some(_preimage) = this.hash_lookup.get(&key) { format!("%{}", ::primitives::hexdisplay::ascii_format(&_preimage)) } else { @@ -327,19 +321,19 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, } else { "" }, - HexDisplay::from(&key) + HexDisplay::from(&key), ); if let Some(value) = maybe_value { let offset = this.heap.allocate(value.len() as u32)? as u32; this.memory.set(offset, &value) - .map_err(|_| UserError("Invalid attempt to set memory in ext_get_allocated_storage"))?; + .map_err(|_| "Invalid attempt to set memory in ext_get_allocated_storage")?; this.memory.write_primitive(written_out, value.len() as u32) - .map_err(|_| UserError("Invalid attempt to write written_out in ext_get_allocated_storage"))?; + .map_err(|_| "Invalid attempt to write written_out in ext_get_allocated_storage")?; Ok(offset) } else { this.memory.write_primitive(written_out, u32::max_value()) - .map_err(|_| UserError("Invalid attempt to write failed written_out in ext_get_allocated_storage"))?; + .map_err(|_| "Invalid attempt to write failed written_out in ext_get_allocated_storage")?; Ok(0) } }, @@ -354,22 +348,21 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, let storage_key = this.memory.get( storage_key_data, storage_key_len as usize - ).map_err(|_| UserError("Invalid attempt to determine storage_key in ext_get_allocated_child_storage"))?; + ).map_err(|_| "Invalid attempt to determine storage_key in ext_get_allocated_child_storage")?; let key = this.memory.get( key_data, key_len as usize - ).map_err(|_| UserError("Invalid attempt to determine key in ext_get_allocated_child_storage"))?; + ).map_err(|_| "Invalid attempt to determine key in ext_get_allocated_child_storage")?; let maybe_value = { let storage_key = ChildStorageKey::from_slice(&storage_key) - .ok_or_else(|| - UserError("ext_get_allocated_child_storage: child storage key is not valid") - )?; + .ok_or_else(|| "ext_get_allocated_child_storage: child storage key is not valid")?; this.ext.child_storage(storage_key, &key) }; - debug_trace!(target: "wasm-trace", "*** Getting child storage: {} -> {} == {} [k={}]", - ::primitives::hexdisplay::ascii_format(&storage_key), + debug_trace!( + target: "wasm-trace", "*** Getting child storage: {} -> {} == {} [k={}]", + primitives::hexdisplay::ascii_format(&storage_key), if let Some(_preimage) = this.hash_lookup.get(&key) { format!("%{}", ::primitives::hexdisplay::ascii_format(&_preimage)) } else { @@ -380,19 +373,19 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, } else { "" }, - HexDisplay::from(&key) + HexDisplay::from(&key), ); if let Some(value) = maybe_value { let offset = this.heap.allocate(value.len() as u32)? as u32; this.memory.set(offset, &value) - .map_err(|_| UserError("Invalid attempt to set memory in ext_get_allocated_child_storage"))?; + .map_err(|_| "Invalid attempt to set memory in ext_get_allocated_child_storage")?; this.memory.write_primitive(written_out, value.len() as u32) - .map_err(|_| UserError("Invalid attempt to write written_out in ext_get_allocated_child_storage"))?; + .map_err(|_| "Invalid attempt to write written_out in ext_get_allocated_child_storage")?; Ok(offset) } else { this.memory.write_primitive(written_out, u32::max_value()) - .map_err(|_| UserError("Invalid attempt to write failed written_out in ext_get_allocated_child_storage"))?; + .map_err(|_| "Invalid attempt to write failed written_out in ext_get_allocated_child_storage")?; Ok(0) } }, @@ -405,27 +398,28 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, value_offset: u32 ) -> u32 => { let key = this.memory.get(key_data, key_len as usize) - .map_err(|_| UserError("Invalid attempt to get key in ext_get_storage_into"))?; + .map_err(|_| "Invalid attempt to get key in ext_get_storage_into")?; let maybe_value = this.ext.storage(&key); - debug_trace!(target: "wasm-trace", "*** Getting storage: {} == {} [k={}]", + debug_trace!( + target: "wasm-trace", "*** Getting storage: {} == {} [k={}]", if let Some(_preimage) = this.hash_lookup.get(&key) { - format!("%{}", ::primitives::hexdisplay::ascii_format(&_preimage)) + format!("%{}", primitives::hexdisplay::ascii_format(&_preimage)) } else { - format!(" {}", ::primitives::hexdisplay::ascii_format(&key)) + format!(" {}", primitives::hexdisplay::ascii_format(&key)) }, if let Some(ref b) = maybe_value { &format!("{}", HexDisplay::from(b)) } else { "" }, - HexDisplay::from(&key) + HexDisplay::from(&key), ); if let Some(value) = maybe_value { let value = &value[value_offset as usize..]; - let written = ::std::cmp::min(value_len as usize, value.len()); + let written = std::cmp::min(value_len as usize, value.len()); this.memory.set(value_data, &value[..written]) - .map_err(|_| UserError("Invalid attempt to set value in ext_get_storage_into"))?; + .map_err(|_| "Invalid attempt to set value in ext_get_storage_into")?; Ok(written as u32) } else { Ok(u32::max_value()) @@ -444,21 +438,20 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, let storage_key = this.memory.get( storage_key_data, storage_key_len as usize - ).map_err(|_| UserError("Invalid attempt to determine storage_key in ext_get_child_storage_into"))?; + ).map_err(|_| "Invalid attempt to determine storage_key in ext_get_child_storage_into")?; let key = this.memory.get( key_data, key_len as usize - ).map_err(|_| UserError("Invalid attempt to get key in ext_get_child_storage_into"))?; + ).map_err(|_| "Invalid attempt to get key in ext_get_child_storage_into")?; let maybe_value = { let storage_key = ChildStorageKey::from_slice(&*storage_key) - .ok_or_else(|| - UserError("ext_get_child_storage_into: child storage key is not valid") - )?; + .ok_or_else(|| "ext_get_child_storage_into: child storage key is not valid")?; this.ext.child_storage(storage_key, &key) }; - debug_trace!(target: "wasm-trace", "*** Getting storage: {} -> {} == {} [k={}]", - ::primitives::hexdisplay::ascii_format(&storage_key), + debug_trace!( + target: "wasm-trace", "*** Getting storage: {} -> {} == {} [k={}]", + primitives::hexdisplay::ascii_format(&storage_key), if let Some(_preimage) = this.hash_lookup.get(&key) { format!("%{}", ::primitives::hexdisplay::ascii_format(&_preimage)) } else { @@ -469,14 +462,14 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, } else { "" }, - HexDisplay::from(&key) + HexDisplay::from(&key), ); if let Some(value) = maybe_value { 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(|_| UserError("Invalid attempt to set value in ext_get_child_storage_into"))?; + .map_err(|_| "Invalid attempt to set value in ext_get_child_storage_into")?; Ok(written as u32) } else { Ok(u32::max_value()) @@ -485,7 +478,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, ext_storage_root(result: *mut u8) => { let r = this.ext.storage_root(); this.memory.set(result, r.as_ref()) - .map_err(|_| UserError("Invalid attempt to set memory in ext_storage_root"))?; + .map_err(|_| "Invalid attempt to set memory in ext_storage_root")?; Ok(()) }, ext_child_storage_root( @@ -494,33 +487,31 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, written_out: *mut u32 ) -> *mut u8 => { let storage_key = this.memory.get(storage_key_data, storage_key_len as usize) - .map_err(|_| UserError("Invalid attempt to determine storage_key in ext_child_storage_root"))?; + .map_err(|_| "Invalid attempt to determine storage_key in ext_child_storage_root")?; let storage_key = ChildStorageKey::from_slice(&*storage_key) - .ok_or_else(|| - UserError("ext_child_storage_root: child storage key is not valid") - )?; + .ok_or_else(|| "ext_child_storage_root: child storage key is not valid")?; let value = this.ext.child_storage_root(storage_key); let offset = this.heap.allocate(value.len() as u32)? as u32; this.memory.set(offset, &value) - .map_err(|_| UserError("Invalid attempt to set memory in ext_child_storage_root"))?; + .map_err(|_| "Invalid attempt to set memory in ext_child_storage_root")?; this.memory.write_primitive(written_out, value.len() as u32) - .map_err(|_| UserError("Invalid attempt to write written_out in ext_child_storage_root"))?; + .map_err(|_| "Invalid attempt to write written_out in ext_child_storage_root")?; Ok(offset) }, ext_storage_changes_root(parent_hash_data: *const u8, parent_hash_len: u32, result: *mut u8) -> u32 => { let mut parent_hash = H256::default(); if parent_hash_len != parent_hash.as_ref().len() as u32 { - return Err(UserError("Invalid parent_hash_len in ext_storage_changes_root").into()); + return Err("Invalid parent_hash_len in ext_storage_changes_root".into()); } let raw_parent_hash = this.memory.get(parent_hash_data, parent_hash_len as usize) - .map_err(|_| UserError("Invalid attempt to get parent_hash in ext_storage_changes_root"))?; + .map_err(|_| "Invalid attempt to get parent_hash in ext_storage_changes_root")?; parent_hash.as_mut().copy_from_slice(&raw_parent_hash[..]); let r = this.ext.storage_changes_root(parent_hash) - .map_err(|_| UserError("Invaid parent_hash passed to ext_storage_changes_root"))?; + .map_err(|_| "Invaid parent_hash passed to ext_storage_changes_root")?; if let Some(r) = r { this.memory.set(result, &r[..]) - .map_err(|_| UserError("Invalid attempt to set memory in ext_storage_changes_root"))?; + .map_err(|_| "Invalid attempt to set memory in ext_storage_changes_root")?; Ok(1) } else { Ok(0) @@ -534,17 +525,21 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, ) => { let values = (0..lens_len) .map(|i| this.memory.read_primitive(lens_data + i * 4)) - .collect::<::std::result::Result, UserError>>()? + .collect::>>()? .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(|_| UserError("Invalid attempt to get memory in ext_blake2_256_enumerated_trie_root")) + .map_err(|_| + Error::from( + "Invalid attempt to get memory in ext_blake2_256_enumerated_trie_root" + ) + ) ) - .collect::<::std::result::Result, UserError>>()?; + .collect::>>()?; let r = ordered_trie_root::(values.into_iter()); this.memory.set(result, &r[..]) - .map_err(|_| UserError("Invalid attempt to set memory in ext_blake2_256_enumerated_trie_root"))?; + .map_err(|_| "Invalid attempt to set memory in ext_blake2_256_enumerated_trie_root")?; Ok(()) }, ext_chain_id() -> u64 => { @@ -558,22 +553,24 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, hashed } else { let key = this.memory.get(data, len as usize) - .map_err(|_| UserError("Invalid attempt to get key in ext_twox_64"))?; + .map_err(|_| "Invalid attempt to get key in ext_twox_64")?; let hashed_key = twox_64(&key); - debug_trace!(target: "xxhash", "XXhash: {} -> {}", + + debug_trace!( + target: "xxhash", "XXhash: {} -> {}", if let Ok(_skey) = str::from_utf8(&key) { _skey } else { &format!("{}", HexDisplay::from(&key)) }, - HexDisplay::from(&hashed_key) + HexDisplay::from(&hashed_key), ); + this.hash_lookup.insert(hashed_key.to_vec(), key); hashed_key }; - this.memory.set(out, &result) - .map_err(|_| UserError("Invalid attempt to set result in ext_twox_64"))?; + this.memory.set(out, &result).map_err(|_| "Invalid attempt to set result in ext_twox_64")?; Ok(()) }, ext_twox_128(data: *const u8, len: u32, out: *mut u8) => { @@ -584,22 +581,23 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, hashed } else { let key = this.memory.get(data, len as usize) - .map_err(|_| UserError("Invalid attempt to get key in ext_twox_128"))?; + .map_err(|_| "Invalid attempt to get key in ext_twox_128")?; let hashed_key = twox_128(&key); - debug_trace!(target: "xxhash", "XXhash: {} -> {}", + debug_trace!( + target: "xxhash", "XXhash: {} -> {}", &if let Ok(_skey) = str::from_utf8(&key) { *_skey } else { format!("{}", HexDisplay::from(&key)) }, - HexDisplay::from(&hashed_key) + HexDisplay::from(&hashed_key), ); this.hash_lookup.insert(hashed_key.to_vec(), key); hashed_key }; this.memory.set(out, &result) - .map_err(|_| UserError("Invalid attempt to set result in ext_twox_128"))?; + .map_err(|_| "Invalid attempt to set result in ext_twox_128")?; Ok(()) }, ext_twox_256(data: *const u8, len: u32, out: *mut u8) => { @@ -607,11 +605,10 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, twox_256(&[0u8; 0]) } else { let mem = this.memory.get(data, len as usize) - .map_err(|_| UserError("Invalid attempt to get data in ext_twox_256"))?; + .map_err(|_| "Invalid attempt to get data in ext_twox_256")?; twox_256(&mem) }; - this.memory.set(out, &result) - .map_err(|_| UserError("Invalid attempt to set result in ext_twox_256"))?; + this.memory.set(out, &result).map_err(|_| "Invalid attempt to set result in ext_twox_256")?; Ok(()) }, ext_blake2_128(data: *const u8, len: u32, out: *mut u8) => { @@ -621,14 +618,14 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, hashed } else { let key = this.memory.get(data, len as usize) - .map_err(|_| UserError("Invalid attempt to get key in ext_blake2_128"))?; + .map_err(|_| "Invalid attempt to get key in ext_blake2_128")?; let hashed_key = blake2_128(&key); this.hash_lookup.insert(hashed_key.to_vec(), key); hashed_key }; this.memory.set(out, &result) - .map_err(|_| UserError("Invalid attempt to set result in ext_blake2_128"))?; + .map_err(|_| "Invalid attempt to set result in ext_blake2_128")?; Ok(()) }, ext_blake2_256(data: *const u8, len: u32, out: *mut u8) => { @@ -636,11 +633,10 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, blake2_256(&[0u8; 0]) } else { let mem = this.memory.get(data, len as usize) - .map_err(|_| UserError("Invalid attempt to get data in ext_blake2_256"))?; + .map_err(|_| "Invalid attempt to get data in ext_blake2_256")?; blake2_256(&mem) }; - this.memory.set(out, &result) - .map_err(|_| UserError("Invalid attempt to set result in ext_blake2_256"))?; + this.memory.set(out, &result).map_err(|_| "Invalid attempt to set result in ext_blake2_256")?; Ok(()) }, ext_keccak_256(data: *const u8, len: u32, out: *mut u8) => { @@ -648,22 +644,21 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, tiny_keccak::keccak256(&[0u8; 0]) } else { let mem = this.memory.get(data, len as usize) - .map_err(|_| UserError("Invalid attempt to get data in ext_keccak_256"))?; + .map_err(|_| "Invalid attempt to get data in ext_keccak_256")?; tiny_keccak::keccak256(&mem) }; - this.memory.set(out, &result) - .map_err(|_| UserError("Invalid attempt to set result in ext_keccak_256"))?; + this.memory.set(out, &result).map_err(|_| "Invalid attempt to set result in ext_keccak_256")?; Ok(()) }, ext_ed25519_verify(msg_data: *const u8, msg_len: u32, sig_data: *const u8, pubkey_data: *const u8) -> u32 => { let mut sig = [0u8; 64]; this.memory.get_into(sig_data, &mut sig[..]) - .map_err(|_| UserError("Invalid attempt to get signature in ext_ed25519_verify"))?; + .map_err(|_| "Invalid attempt to get signature in ext_ed25519_verify")?; let mut pubkey = [0u8; 32]; this.memory.get_into(pubkey_data, &mut pubkey[..]) - .map_err(|_| UserError("Invalid attempt to get pubkey in ext_ed25519_verify"))?; + .map_err(|_| "Invalid attempt to get pubkey in ext_ed25519_verify")?; let msg = this.memory.get(msg_data, msg_len as usize) - .map_err(|_| UserError("Invalid attempt to get message in ext_ed25519_verify"))?; + .map_err(|_| "Invalid attempt to get message in ext_ed25519_verify")?; Ok(if ed25519::Pair::verify_weak(&sig, &msg, &pubkey) { 0 @@ -674,12 +669,12 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, ext_sr25519_verify(msg_data: *const u8, msg_len: u32, sig_data: *const u8, pubkey_data: *const u8) -> u32 => { let mut sig = [0u8; 64]; this.memory.get_into(sig_data, &mut sig[..]) - .map_err(|_| UserError("Invalid attempt to get signature in ext_sr25519_verify"))?; + .map_err(|_| "Invalid attempt to get signature in ext_sr25519_verify")?; let mut pubkey = [0u8; 32]; this.memory.get_into(pubkey_data, &mut pubkey[..]) - .map_err(|_| UserError("Invalid attempt to get pubkey in ext_sr25519_verify"))?; + .map_err(|_| "Invalid attempt to get pubkey in ext_sr25519_verify")?; let msg = this.memory.get(msg_data, msg_len as usize) - .map_err(|_| UserError("Invalid attempt to get message in ext_sr25519_verify"))?; + .map_err(|_| "Invalid attempt to get message in ext_sr25519_verify")?; Ok(if sr25519::Pair::verify_weak(&sig, &msg, &pubkey) { 0 @@ -690,7 +685,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, ext_secp256k1_ecdsa_recover(msg_data: *const u8, sig_data: *const u8, pubkey_data: *mut u8) -> u32 => { let mut sig = [0u8; 65]; this.memory.get_into(sig_data, &mut sig[..]) - .map_err(|_| UserError("Invalid attempt to get signature in ext_secp256k1_ecdsa_recover"))?; + .map_err(|_| "Invalid attempt to get signature in ext_secp256k1_ecdsa_recover")?; let rs = match secp256k1::Signature::parse_slice(&sig[0..64]) { Ok(rs) => rs, _ => return Ok(1), @@ -703,7 +698,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, let mut msg = [0u8; 32]; this.memory.get_into(msg_data, &mut msg[..]) - .map_err(|_| UserError("Invalid attempt to get message in ext_secp256k1_ecdsa_recover"))?; + .map_err(|_| "Invalid attempt to get message in ext_secp256k1_ecdsa_recover")?; let pubkey = match secp256k1::recover(&secp256k1::Message::parse(&msg), &rs, &v) { Ok(pk) => pk, @@ -711,27 +706,27 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, }; this.memory.set(pubkey_data, &pubkey.serialize()[1..65]) - .map_err(|_| UserError("Invalid attempt to set pubkey in ext_secp256k1_ecdsa_recover"))?; + .map_err(|_| "Invalid attempt to set pubkey in ext_secp256k1_ecdsa_recover")?; Ok(0) }, ext_submit_transaction(msg_data: *const u8, len: u32) -> u32 => { let extrinsic = this.memory.get(msg_data, len as usize) - .map_err(|_| UserError("OOB while ext_submit_transaction: wasm"))?; + .map_err(|_| "OOB while ext_submit_transaction: wasm")?; let res = this.ext.offchain() .map(|api| api.submit_transaction(extrinsic)) - .ok_or_else(|| UserError("Calling unavailable API ext_submit_transaction: wasm"))?; + .ok_or_else(|| "Calling unavailable API ext_submit_transaction: wasm")?; Ok(if res.is_ok() { 0 } else { 1 }) }, ext_new_crypto_key(crypto: u32) -> u32 => { let kind = offchain::CryptoKind::try_from(crypto) - .map_err(|_| UserError("crypto kind OOB while ext_new_crypto_key: wasm"))?; + .map_err(|_| "crypto kind OOB while ext_new_crypto_key: wasm")?; let res = this.ext.offchain() .map(|api| api.new_crypto_key(kind)) - .ok_or_else(|| UserError("Calling unavailable API ext_new_crypto_key: wasm"))?; + .ok_or_else(|| "Calling unavailable API ext_new_crypto_key: wasm")?; match res { Ok(key_id) => Ok(key_id.0 as u32), @@ -740,79 +735,79 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, }, ext_encrypt(key: u32, data: *const u8, data_len: u32, msg_len: *mut u32) -> *mut u8 => { let key = u32_to_key(key) - .map_err(|_| UserError("key OOB while ext_encrypt: wasm"))?; + .map_err(|_| "Key OOB while ext_encrypt: wasm")?; let message = this.memory.get(data, data_len as usize) - .map_err(|_| UserError("OOB while ext_encrypt: wasm"))?; + .map_err(|_| "OOB while ext_encrypt: wasm")?; let res = this.ext.offchain() .map(|api| api.encrypt(key, &*message)) - .ok_or_else(|| UserError("Calling unavailable API ext_encrypt: wasm"))?; + .ok_or_else(|| "Calling unavailable API ext_encrypt: wasm")?; let (offset,len) = match res { Ok(encrypted) => { let len = encrypted.len() as u32; let offset = this.heap.allocate(len)? as u32; this.memory.set(offset, &encrypted) - .map_err(|_| UserError("Invalid attempt to set memory in ext_encrypt"))?; + .map_err(|_| "Invalid attempt to set memory in ext_encrypt")?; (offset, len) }, Err(()) => (0, u32::max_value()), }; this.memory.write_primitive(msg_len, len) - .map_err(|_| UserError("Invalid attempt to write msg_len in ext_encrypt"))?; + .map_err(|_| "Invalid attempt to write msg_len in ext_encrypt")?; Ok(offset) }, ext_decrypt(key: u32, data: *const u8, data_len: u32, msg_len: *mut u32) -> *mut u8 => { let key = u32_to_key(key) - .map_err(|_| UserError("key OOB while ext_decrypt: wasm"))?; + .map_err(|_| "Key OOB while ext_decrypt: wasm")?; let message = this.memory.get(data, data_len as usize) - .map_err(|_| UserError("OOB while ext_decrypt: wasm"))?; + .map_err(|_| "OOB while ext_decrypt: wasm")?; let res = this.ext.offchain() .map(|api| api.decrypt(key, &*message)) - .ok_or_else(|| UserError("Calling unavailable API ext_decrypt: wasm"))?; + .ok_or_else(|| "Calling unavailable API ext_decrypt: wasm")?; let (offset,len) = match res { Ok(decrypted) => { let len = decrypted.len() as u32; let offset = this.heap.allocate(len)? as u32; this.memory.set(offset, &decrypted) - .map_err(|_| UserError("Invalid attempt to set memory in ext_decrypt"))?; + .map_err(|_| "Invalid attempt to set memory in ext_decrypt")?; (offset, len) }, Err(()) => (0, u32::max_value()), }; this.memory.write_primitive(msg_len, len) - .map_err(|_| UserError("Invalid attempt to write msg_len in ext_decrypt"))?; + .map_err(|_| "Invalid attempt to write msg_len in ext_decrypt")?; Ok(offset) }, ext_sign(key: u32, data: *const u8, data_len: u32, sig_data_len: *mut u32) -> *mut u8 => { let key = u32_to_key(key) - .map_err(|_| UserError("key OOB while ext_sign: wasm"))?; + .map_err(|_| "Key OOB while ext_sign: wasm")?; let message = this.memory.get(data, data_len as usize) - .map_err(|_| UserError("OOB while ext_sign: wasm"))?; + .map_err(|_| "OOB while ext_sign: wasm")?; let res = this.ext.offchain() .map(|api| api.sign(key, &*message)) - .ok_or_else(|| UserError("Calling unavailable API ext_sign: wasm"))?; + .ok_or_else(|| "Calling unavailable API ext_sign: wasm")?; let (offset,len) = match res { Ok(signature) => { let len = signature.len() as u32; let offset = this.heap.allocate(len)? as u32; this.memory.set(offset, &signature) - .map_err(|_| UserError("Invalid attempt to set memory in ext_sign"))?; + .map_err(|_| "Invalid attempt to set memory in ext_sign")?; (offset, len) }, Err(()) => (0, u32::max_value()), }; this.memory.write_primitive(sig_data_len, len) - .map_err(|_| UserError("Invalid attempt to write sig_data_len in ext_sign"))?; + .map_err(|_| "Invalid attempt to write sig_data_len in ext_sign")?; Ok(offset) }, @@ -824,15 +819,15 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, signature_len: u32 ) -> u32 => { let key = u32_to_key(key) - .map_err(|_| UserError("key OOB while ext_verify: wasm"))?; + .map_err(|_| "Key OOB while ext_verify: wasm")?; let message = this.memory.get(msg, msg_len as usize) - .map_err(|_| UserError("OOB while ext_verify: wasm"))?; + .map_err(|_| "OOB while ext_verify: wasm")?; let signature = this.memory.get(signature, signature_len as usize) - .map_err(|_| UserError("OOB while ext_verify: wasm"))?; + .map_err(|_| "OOB while ext_verify: wasm")?; let res = this.ext.offchain() .map(|api| api.verify(key, &*message, &*signature)) - .ok_or_else(|| UserError("Calling unavailable API ext_verify: wasm"))?; + .ok_or_else(|| "Calling unavailable API ext_verify: wasm")?; match res { Ok(true) => Ok(0), @@ -843,56 +838,56 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, ext_timestamp() -> u64 => { let timestamp = this.ext.offchain() .map(|api| api.timestamp()) - .ok_or_else(|| UserError("Calling unavailable API ext_timestamp: wasm"))?; + .ok_or_else(|| "Calling unavailable API ext_timestamp: wasm")?; Ok(timestamp.unix_millis()) }, ext_sleep_until(deadline: u64) => { this.ext.offchain() .map(|api| api.sleep_until(offchain::Timestamp::from_unix_millis(deadline))) - .ok_or_else(|| UserError("Calling unavailable API ext_sleep_until: wasm"))?; + .ok_or_else(|| "Calling unavailable API ext_sleep_until: wasm")?; Ok(()) }, ext_random_seed(seed_data: *mut u8) => { // NOTE the runtime as assumptions about seed size. let seed: [u8; 32] = this.ext.offchain() .map(|api| api.random_seed()) - .ok_or_else(|| UserError("Calling unavailable API ext_random_seed: wasm"))?; + .ok_or_else(|| "Calling unavailable API ext_random_seed: wasm")?; this.memory.set(seed_data, &seed) - .map_err(|_| UserError("Invalid attempt to set value in ext_random_seed"))?; + .map_err(|_| "Invalid attempt to set value in ext_random_seed")?; Ok(()) }, ext_local_storage_set(key: *const u8, key_len: u32, value: *const u8, value_len: u32) => { let key = this.memory.get(key, key_len as usize) - .map_err(|_| UserError("OOB while ext_local_storage_set: wasm"))?; + .map_err(|_| "OOB while ext_local_storage_set: wasm")?; let value = this.memory.get(value, value_len as usize) - .map_err(|_| UserError("OOB while ext_local_storage_set: wasm"))?; + .map_err(|_| "OOB while ext_local_storage_set: wasm")?; this.ext.offchain() .map(|api| api.local_storage_set(&key, &value)) - .ok_or_else(|| UserError("Calling unavailable API ext_local_storage_set: wasm"))?; + .ok_or_else(|| "Calling unavailable API ext_local_storage_set: wasm")?; Ok(()) }, ext_local_storage_get(key: *const u8, key_len: u32, value_len: *mut u32) -> *mut u8 => { let key = this.memory.get(key, key_len as usize) - .map_err(|_| UserError("OOB while ext_local_storage_get: wasm"))?; + .map_err(|_| "OOB while ext_local_storage_get: wasm")?; let maybe_value = this.ext.offchain() .map(|api| api.local_storage_get(&key)) - .ok_or_else(|| UserError("Calling unavailable API ext_local_storage_get: wasm"))?; + .ok_or_else(|| "Calling unavailable API ext_local_storage_get: wasm")?; let (offset, len) = if let Some(value) = maybe_value { let offset = this.heap.allocate(value.len() as u32)? as u32; this.memory.set(offset, &value) - .map_err(|_| UserError("Invalid attempt to set memory in ext_local_storage_get"))?; + .map_err(|_| "Invalid attempt to set memory in ext_local_storage_get")?; (offset, value.len() as u32) } else { (0, u32::max_value()) }; this.memory.write_primitive(value_len, len) - .map_err(|_| UserError("Invalid attempt to write value_len in ext_local_storage_get"))?; + .map_err(|_| "Invalid attempt to write value_len in ext_local_storage_get")?; Ok(offset) }, @@ -905,20 +900,20 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, meta_len: u32 ) -> u32 => { let method = this.memory.get(method, method_len as usize) - .map_err(|_| UserError("OOB while ext_http_request_start: wasm"))?; + .map_err(|_| "OOB while ext_http_request_start: wasm")?; let url = this.memory.get(url, url_len as usize) - .map_err(|_| UserError("OOB while ext_http_request_start: wasm"))?; + .map_err(|_| "OOB while ext_http_request_start: wasm")?; let meta = this.memory.get(meta, meta_len as usize) - .map_err(|_| UserError("OOB while ext_http_request_start: wasm"))?; + .map_err(|_| "OOB while ext_http_request_start: wasm")?; let method_str = str::from_utf8(&method) - .map_err(|_| UserError("invalid str while ext_http_request_start: wasm"))?; + .map_err(|_| "invalid str while ext_http_request_start: wasm")?; let url_str = str::from_utf8(&url) - .map_err(|_| UserError("invalid str while ext_http_request_start: wasm"))?; + .map_err(|_| "invalid str while ext_http_request_start: wasm")?; let id = this.ext.offchain() .map(|api| api.http_request_start(method_str, url_str, &*meta)) - .ok_or_else(|| UserError("Calling unavailable API ext_http_request_start: wasm"))?; + .ok_or_else(|| "Calling unavailable API ext_http_request_start: wasm")?; if let Ok(id) = id { Ok(id.0 as u32) @@ -934,14 +929,14 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, value_len: u32 ) -> u32 => { let name = this.memory.get(name, name_len as usize) - .map_err(|_| UserError("OOB while ext_http_request_add_header: wasm"))?; + .map_err(|_| "OOB while ext_http_request_add_header: wasm")?; let value = this.memory.get(value, value_len as usize) - .map_err(|_| UserError("OOB while ext_http_request_add_header: wasm"))?; + .map_err(|_| "OOB while ext_http_request_add_header: wasm")?; let name_str = str::from_utf8(&name) - .map_err(|_| UserError("invalid str while ext_http_request_add_header: wasm"))?; + .map_err(|_| "Invalid str while ext_http_request_add_header: wasm")?; let value_str = str::from_utf8(&value) - .map_err(|_| UserError("invalid str while ext_http_request_add_header: wasm"))?; + .map_err(|_| "Invalid str while ext_http_request_add_header: wasm")?; let res = this.ext.offchain() .map(|api| api.http_request_add_header( @@ -949,7 +944,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, &name_str, &value_str, )) - .ok_or_else(|| UserError("Calling unavailable API ext_http_request_add_header: wasm"))?; + .ok_or_else(|| "Calling unavailable API ext_http_request_add_header: wasm")?; Ok(if res.is_ok() { 0 } else { 1 }) }, @@ -960,7 +955,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, deadline: u64 ) -> u32 => { let chunk = this.memory.get(chunk, chunk_len as usize) - .map_err(|_| UserError("OOB while ext_http_request_write_body: wasm"))?; + .map_err(|_| "OOB while ext_http_request_write_body: wasm")?; let res = this.ext.offchain() .map(|api| api.http_request_write_body( @@ -968,7 +963,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, &chunk, deadline_to_timestamp(deadline) )) - .ok_or_else(|| UserError("Calling unavailable API ext_http_request_write_body: wasm"))?; + .ok_or_else(|| "Calling unavailable API ext_http_request_write_body: wasm")?; Ok(match res { Ok(()) => 0, @@ -985,13 +980,13 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, .map(|i| this.memory.read_primitive(ids + i * 4) .map(|id: u32| offchain::HttpRequestId(id as u16)) - .map_err(|_| UserError("OOB while ext_http_response_wait: wasm")) + .map_err(|_| "OOB while ext_http_response_wait: wasm") ) .collect::<::std::result::Result, _>>()?; let res = this.ext.offchain() .map(|api| api.http_response_wait(&ids, deadline_to_timestamp(deadline))) - .ok_or_else(|| UserError("Calling unavailable API ext_http_response_wait: wasm"))? + .ok_or_else(|| "Calling unavailable API ext_http_response_wait: wasm")? .into_iter() .map(|status| status.into()) .enumerate() @@ -1000,7 +995,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, for (i, status) in res { this.memory.write_primitive(statuses + i as u32 * 4, status) - .map_err(|_| UserError("Invalid attempt to set memory in ext_http_response_wait"))?; + .map_err(|_| "Invalid attempt to set memory in ext_http_response_wait")?; } Ok(()) @@ -1013,15 +1008,15 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, let headers = this.ext.offchain() .map(|api| api.http_response_headers(offchain::HttpRequestId(request_id as u16))) - .ok_or_else(|| UserError("Calling unavailable API ext_http_response_headers: wasm"))?; + .ok_or_else(|| "Calling unavailable API ext_http_response_headers: wasm")?; let encoded = headers.encode(); let len = encoded.len() as u32; let offset = this.heap.allocate(len)? as u32; this.memory.set(offset, &encoded) - .map_err(|_| UserError("Invalid attempt to set memory in ext_http_response_headers"))?; + .map_err(|_| "Invalid attempt to set memory in ext_http_response_headers")?; this.memory.write_primitive(written_out, len) - .map_err(|_| UserError("Invalid attempt to write written_out in ext_http_response_headers"))?; + .map_err(|_| "Invalid attempt to write written_out in ext_http_response_headers")?; Ok(offset) }, @@ -1040,12 +1035,12 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, &mut internal_buffer, deadline_to_timestamp(deadline), )) - .ok_or_else(|| UserError("Calling unavailable API ext_http_response_read_body: wasm"))?; + .ok_or_else(|| "Calling unavailable API ext_http_response_read_body: wasm")?; Ok(match res { Ok(read) => { this.memory.set(buffer, &internal_buffer[..read]) - .map_err(|_| UserError("Invalid attempt to set memory in ext_http_response_read_body"))?; + .map_err(|_| "Invalid attempt to set memory in ext_http_response_read_body")?; read as u32 }, @@ -1063,17 +1058,17 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, state: usize ) -> u32 => { let wasm = this.memory.get(wasm_ptr, wasm_len as usize) - .map_err(|_| UserError("OOB while ext_sandbox_instantiate: wasm"))?; + .map_err(|_| "OOB while ext_sandbox_instantiate: wasm")?; let raw_env_def = this.memory.get(imports_ptr, imports_len as usize) - .map_err(|_| UserError("OOB while ext_sandbox_instantiate: imports"))?; + .map_err(|_| "OOB while ext_sandbox_instantiate: imports")?; // Extract a dispatch thunk from instance's table by the specified index. let dispatch_thunk = { let table = this.table.as_ref() - .ok_or_else(|| UserError("Runtime doesn't have a table; sandbox is unavailable"))?; + .ok_or_else(|| "Runtime doesn't have a table; sandbox is unavailable")?; table.get(dispatch_thunk_idx) - .map_err(|_| UserError("dispatch_thunk_idx is out of the table bounds"))? - .ok_or_else(|| UserError("dispatch_thunk_idx points on an empty table entry"))? + .map_err(|_| "dispatch_thunk_idx is out of the table bounds")? + .ok_or_else(|| "dispatch_thunk_idx points on an empty table entry")? .clone() }; @@ -1104,17 +1099,17 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, trace!(target: "sr-sandbox", "invoke, instance_idx={}", instance_idx); let export = this.memory.get(export_ptr, export_len as usize) - .map_err(|_| UserError("OOB while ext_sandbox_invoke: export")) + .map_err(|_| "OOB while ext_sandbox_invoke: export") .and_then(|b| String::from_utf8(b) - .map_err(|_| UserError("export name should be a valid utf-8 sequence")) + .map_err(|_| "Export name should be a valid utf-8 sequence") )?; // Deserialize arguments and convert them into wasmi types. let serialized_args = this.memory.get(args_ptr, args_len as usize) - .map_err(|_| UserError("OOB while ext_sandbox_invoke: args"))?; + .map_err(|_| "OOB while ext_sandbox_invoke: args")?; let args = Vec::::decode(&mut &serialized_args[..]) - .ok_or_else(|| UserError("Can't decode serialized arguments for the invocation"))? + .ok_or_else(|| "Can't decode serialized arguments for the invocation")? .into_iter() .map(Into::into) .collect::>(); @@ -1128,11 +1123,11 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, // Serialize return value and write it back into the memory. sandbox_primitives::ReturnValue::Value(val.into()).using_encoded(|val| { if val.len() > return_val_len as usize { - Err(UserError("Return value buffer is too small"))?; + Err("Return value buffer is too small")?; } this.memory .set(return_val_ptr, val) - .map_err(|_| UserError("Return value buffer is OOB"))?; + .map_err(|_| "Return value buffer is OOB")?; Ok(sandbox_primitives::ERR_OK) }) } @@ -1228,7 +1223,13 @@ impl WasmExecutor { ) -> Result { let module = wasmi::Module::from_buffer(code)?; let module = self.prepare_module(ext, heap_pages, &module)?; - self.call_in_wasm_module_with_custom_signature(ext, &module, method, create_parameters, filter_result) + self.call_in_wasm_module_with_custom_signature( + ext, + &module, + method, + create_parameters, + filter_result, + ) } fn get_mem_instance(module: &ModuleRef) -> Result { @@ -1293,7 +1294,7 @@ impl WasmExecutor { let used_mem = memory.used_size(); let mut fec = FunctionExecutor::new(memory.clone(), table, ext)?; let parameters = create_parameters(&mut |data: &[u8]| { - let offset = fec.heap.allocate(data.len() as u32).map_err(|_| Error::Runtime)?; + let offset = fec.heap.allocate(data.len() as u32)?; memory.set(offset, &data)?; Ok(offset) })?; diff --git a/substrate/core/executor/src/wasm_utils.rs b/substrate/core/executor/src/wasm_utils.rs index 7384f91944..47867f7b48 100644 --- a/substrate/core/executor/src/wasm_utils.rs +++ b/substrate/core/executor/src/wasm_utils.rs @@ -16,31 +16,73 @@ //! Rust implementation of Substrate contracts. -use wasmi::{ValueType, RuntimeValue, HostError}; +use wasmi::{ValueType, RuntimeValue}; use wasmi::nan_preserving_float::{F32, F64}; -use std::fmt; -#[derive(Debug, PartialEq)] -pub struct UserError(pub &'static str); -impl fmt::Display for UserError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "UserError: {}", self.0) - } -} -impl HostError for UserError { +pub trait ConvertibleToWasm { + const VALUE_TYPE: ValueType; + type NativeType; fn to_runtime_value(self) -> RuntimeValue; } -pub trait ConvertibleToWasm { const VALUE_TYPE: ValueType; type NativeType; fn to_runtime_value(self) -> RuntimeValue; } -impl ConvertibleToWasm for i32 { type NativeType = i32; const VALUE_TYPE: ValueType = ValueType::I32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self) } } -impl ConvertibleToWasm for u32 { type NativeType = u32; const VALUE_TYPE: ValueType = ValueType::I32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as i32) } } -impl ConvertibleToWasm for i64 { type NativeType = i64; const VALUE_TYPE: ValueType = ValueType::I64; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I64(self) } } -impl ConvertibleToWasm for u64 { type NativeType = u64; const VALUE_TYPE: ValueType = ValueType::I64; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I64(self as i64) } } -impl ConvertibleToWasm for F32 { type NativeType = F32; const VALUE_TYPE: ValueType = ValueType::F32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::F32(self) } } -impl ConvertibleToWasm for F64 { type NativeType = F64; const VALUE_TYPE: ValueType = ValueType::F64; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::F64(self) } } -impl ConvertibleToWasm for isize { type NativeType = i32; const VALUE_TYPE: ValueType = ValueType::I32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as i32) } } -impl ConvertibleToWasm for usize { type NativeType = u32; const VALUE_TYPE: ValueType = ValueType::I32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as u32 as i32) } } -impl ConvertibleToWasm for *const T { type NativeType = u32; const VALUE_TYPE: ValueType = ValueType::I32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as isize as i32) } } -impl ConvertibleToWasm for *mut T { type NativeType = u32; const VALUE_TYPE: ValueType = ValueType::I32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as isize as i32) } } +impl ConvertibleToWasm for i32 { + type NativeType = i32; + const VALUE_TYPE: ValueType = ValueType::I32; + fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self) } +} + +impl ConvertibleToWasm for u32 { + type NativeType = u32; + const VALUE_TYPE: ValueType = ValueType::I32; + fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as i32) } +} + +impl ConvertibleToWasm for i64 { + type NativeType = i64; + const VALUE_TYPE: ValueType = ValueType::I64; + fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I64(self) } +} + +impl ConvertibleToWasm for u64 { + type NativeType = u64; + const VALUE_TYPE: ValueType = ValueType::I64; + fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I64(self as i64) } +} + +impl ConvertibleToWasm for F32 { + type NativeType = F32; + const VALUE_TYPE: ValueType = ValueType::F32; + fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::F32(self) } +} + +impl ConvertibleToWasm for F64 { + type NativeType = F64; + const VALUE_TYPE: ValueType = ValueType::F64; + fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::F64(self) } +} + +impl ConvertibleToWasm for isize { + type NativeType = i32; + const VALUE_TYPE: ValueType = ValueType::I32; + fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as i32) } +} + +impl ConvertibleToWasm for usize { + type NativeType = u32; + const VALUE_TYPE: ValueType = ValueType::I32; + fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as u32 as i32) } +} + +impl ConvertibleToWasm for *const T { + type NativeType = u32; + const VALUE_TYPE: ValueType = ValueType::I32; + fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as isize as i32) } +} + +impl ConvertibleToWasm for *mut T { + type NativeType = u32; + const VALUE_TYPE: ValueType = ValueType::I32; + fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as isize as i32) } +} /// Converts arguments into respective WASM types. #[macro_export] @@ -118,7 +160,7 @@ macro_rules! unmarshall_args { #[inline(always)] pub fn constrain_closure(f: F) -> F where - F: FnOnce() -> Result + F: FnOnce() -> Result { f } @@ -132,14 +174,14 @@ macro_rules! marshall { >(|| { unmarshall_args!($body, $objectname, $args_iter, $( $names : $params ),*) }); - let r = body()?; + let r = body().map_err(wasmi::Trap::from)?; return Ok(Some({ use $crate::wasm_utils::ConvertibleToWasm; r.to_runtime_value() })) }); ( $args_iter:ident, $objectname:ident, ( $( $names:ident : $params:ty ),* ) => $body:tt ) => ({ let body = $crate::wasm_utils::constrain_closure::<(), _>(|| { unmarshall_args!($body, $objectname, $args_iter, $( $names : $params ),*) }); - body()?; + body().map_err(wasmi::Trap::from)?; return Ok(None) }) } @@ -154,7 +196,13 @@ macro_rules! dispatch_fn { panic!("fn with index {} is undefined", $index); }; - ( @iter $index:expr, $index_ident:ident, $objectname:ident, $args_iter:ident, $name:ident ( $( $names:ident : $params:ty ),* ) $( -> $returns:ty )* => $body:tt $($tail:tt)*) => ( + (@iter + $index:expr, + $index_ident:ident, + $objectname:ident, + $args_iter:ident, + $name:ident ( $( $names:ident : $params:ty ),* ) $( -> $returns:ty )* => $body:tt $($tail:tt)* + ) => ( if $index_ident == $index { { marshall!($args_iter, $objectname, ( $( $names : $params ),* ) $( -> $returns )* => $body) } } @@ -177,7 +225,11 @@ macro_rules! impl_function_executor { fn resolver() -> &'static dyn $crate::wasmi::ModuleImportResolver { struct Resolver; impl $crate::wasmi::ModuleImportResolver for Resolver { - fn resolve_func(&self, name: &str, signature: &$crate::wasmi::Signature) -> ::std::result::Result<$crate::wasmi::FuncRef, $crate::wasmi::Error> { + fn resolve_func( + &self, + name: &str, + signature: &$crate::wasmi::Signature + ) -> std::result::Result<$crate::wasmi::FuncRef, $crate::wasmi::Error> { resolve_fn!(signature, name, $( $name( $( $params ),* ) $( -> $returns )* => )*); Err($crate::wasmi::Error::Instantiation( @@ -194,7 +246,7 @@ macro_rules! impl_function_executor { &mut self, index: usize, args: $crate::wasmi::RuntimeArgs, - ) -> ::std::result::Result, $crate::wasmi::Trap> { + ) -> std::result::Result, $crate::wasmi::Trap> { let $objectname = self; let mut args = args.as_ref().iter(); dispatch_fn!(index, $objectname, args, $( $name( $( $names : $params ),* ) $( -> $returns )* => $body ),*);