diff --git a/Cargo.lock b/Cargo.lock index cc7801f0653..a09c26aa9cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3501,7 +3501,7 @@ dependencies = [ [[package]] name = "wasm-utils" version = "0.1.0" -source = "git+https://github.com/paritytech/wasm-utils#492761a00573c25b37e09cbc81909e0280fe332f" +source = "git+https://github.com/paritytech/wasm-utils#32d54c85409be92fca5cb5a3d0190224a39e0146" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3515,7 +3515,7 @@ dependencies = [ [[package]] name = "wasmi" version = "0.0.0" -source = "git+https://github.com/pepyakin/wasmi#6b6961bcb62fd837ed2950ea15e274ff87f1c0cf" +source = "git+https://github.com/pepyakin/wasmi#f1a3f06d5e49798e2aa28150e863af1c7910bfc2" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ethcore/vm/src/schedule.rs b/ethcore/vm/src/schedule.rs index cc184825c8c..9997e749447 100644 --- a/ethcore/vm/src/schedule.rs +++ b/ethcore/vm/src/schedule.rs @@ -119,8 +119,8 @@ pub struct Schedule { /// Wasm cost table pub struct WasmCosts { - /// Arena allocator cost, per byte - pub alloc: u32, + /// Default opcode cost + pub regular: u32, /// Div operations multiplier. pub div: u32, /// Div operations multiplier. @@ -145,7 +145,7 @@ pub struct WasmCosts { impl Default for WasmCosts { fn default() -> Self { WasmCosts { - alloc: 2, + regular: 1, div: 16, mul: 4, mem: 2, diff --git a/ethcore/wasm/src/lib.rs b/ethcore/wasm/src/lib.rs index e07d3eee9a2..1bc34420cc5 100644 --- a/ethcore/wasm/src/lib.rs +++ b/ethcore/wasm/src/lib.rs @@ -53,6 +53,12 @@ impl From for Error { } } +impl From for Error { + fn from(e: Trap) -> Self { + Error::Trap(e) + } +} + impl From for vm::Error { fn from(e: Error) -> Self { match e { @@ -122,31 +128,25 @@ impl vm::Vm for WasmInterpreter { let module_instance = module_instance.run_start(&mut runtime).map_err(Error::Trap)?; - match module_instance.invoke_export("call", &[], &mut runtime) { - Ok(_) => { }, - Err(InterpreterError::Host(boxed)) => { - match boxed.downcast_ref::() { - None => { - return Err(vm::Error::Wasm("Invalid user error used in interpreter".to_owned())); - } - Some(runtime_err) => { - match *runtime_err { - runtime::Error::Suicide => { - // Suicide uses trap to break execution - } - ref any_err => { - trace!(target: "wasm", "Error executing contract: {:?}", boxed); - return Err(vm::Error::from(Error::from(InterpreterError::Host(Box::new(any_err.clone()))))); - } - } - } - } - }, - Err(err) => { - trace!(target: "wasm", "Error executing contract: {:?}", err); - return Err(vm::Error::from(Error::from(err))) + let invoke_result = module_instance.invoke_export("call", &[], &mut runtime); + + let mut suicide = false; + if let Err(InterpreterError::Trap(ref trap)) = invoke_result { + if let wasmi::TrapKind::Host(ref boxed) = *trap.kind() { + let ref runtime_err = boxed.downcast_ref::() + .expect("Host errors other than runtime::Error never produced; qed"); + + if let runtime::Error::Suicide = **runtime_err { suicide = true; } } } + + if !suicide { + if let Err(e) = invoke_result { + trace!(target: "wasm", "Error executing contract: {:?}", e); + return Err(vm::Error::from(Error::from(e))); + } + } + ( runtime.gas_left().expect("Cannot fail since it was not updated since last charge"), runtime.into_result(), diff --git a/ethcore/wasm/src/parser.rs b/ethcore/wasm/src/parser.rs index d76b5d038fa..738dc660285 100644 --- a/ethcore/wasm/src/parser.rs +++ b/ethcore/wasm/src/parser.rs @@ -23,7 +23,7 @@ use parity_wasm::peek_size; fn gas_rules(wasm_costs: &vm::WasmCosts) -> rules::Set { rules::Set::new( - 1, + wasm_costs.regular, { let mut vals = ::std::collections::HashMap::with_capacity(8); vals.insert(rules::InstructionType::Load, rules::Metering::Fixed(wasm_costs.mem as u32)); @@ -77,8 +77,6 @@ pub fn payload<'a>(params: &'a vm::ActionParams, wasm_costs: &vm::WasmCosts) &gas_rules(wasm_costs), ).map_err(|_| vm::Error::Wasm(format!("Wasm contract error: bytecode invalid")))?; - ::parity_wasm::elements::serialize_to_file("./debug.wasm", contract_module.clone()); - let data = match params.params_type { vm::ParamsType::Embedded => { if data_position < code.len() { &code[data_position..] } else { &[] } diff --git a/ethcore/wasm/src/runtime.rs b/ethcore/wasm/src/runtime.rs index 01cb521002d..e577cc27785 100644 --- a/ethcore/wasm/src/runtime.rs +++ b/ethcore/wasm/src/runtime.rs @@ -1,6 +1,6 @@ use ethereum_types::{U256, H256, Address}; use vm::{self, CallType}; -use wasmi::{self, MemoryRef, RuntimeArgs, RuntimeValue, Error as InterpreterError, Trap}; +use wasmi::{self, MemoryRef, RuntimeArgs, RuntimeValue, Error as InterpreterError, Trap, TrapKind}; use super::panic_payload; pub struct RuntimeContext { @@ -52,6 +52,16 @@ pub enum Error { Other, /// Syscall signature mismatch InvalidSyscall, + /// Unreachable instruction encountered + Unreachable, + /// Invalid virtual call + InvalidVirtualCall, + /// Division by zero + DivisionByZero, + /// Invalid conversion to integer + InvalidConversionToInt, + /// Stack overflow + StackOverflow, /// Panic with message Panic(String), } @@ -60,7 +70,16 @@ impl wasmi::HostError for Error { } impl From for Error { fn from(trap: Trap) -> Self { - Error::Other + match *trap.kind() { + TrapKind::Unreachable => Error::Unreachable, + TrapKind::MemoryAccessOutOfBounds => Error::MemoryAccessViolation, + TrapKind::TableAccessOutOfBounds | TrapKind::ElemUninitialized => Error::InvalidVirtualCall, + TrapKind::DivisionByZero => Error::DivisionByZero, + TrapKind::InvalidConversionToInt => Error::InvalidConversionToInt, + TrapKind::UnexpectedSignature => Error::InvalidVirtualCall, + TrapKind::StackOverflow => Error::StackOverflow, + TrapKind::Host(_) => Error::Other, + } } } @@ -91,6 +110,11 @@ impl ::std::fmt::Display for Error { Error::Log => write!(f, "Error occured while logging an event"), Error::InvalidSyscall => write!(f, "Invalid syscall signature encountered at runtime"), Error::Other => write!(f, "Other unspecified error"), + Error::Unreachable => write!(f, "Unreachable instruction encountered"), + Error::InvalidVirtualCall => write!(f, "Invalid virtual call"), + Error::DivisionByZero => write!(f, "Division by zero"), + Error::StackOverflow => write!(f, "Stack overflow"), + Error::InvalidConversionToInt => write!(f, "Invalid conversion to integer"), Error::Panic(ref msg) => write!(f, "Panic: {}", msg), } } @@ -649,7 +673,7 @@ impl<'a> Runtime<'a> { mod ext_impl { - use wasmi::{Externals, RuntimeArgs, RuntimeValue, Error, Trap}; + use wasmi::{Externals, RuntimeArgs, RuntimeValue, Trap}; use env::ids::*; macro_rules! void {