[stable] Backports (#8133)
* updater: apply exponential backoff after download failure (#8059)
* updater: apply exponential backoff after download failure
* updater: reset backoff on new release
* Limit incoming connections. (#8060)
* Limit ingress connections
* Optimized handshakes logging
* Max code size on Kovan (#8067)
* Enable code size limit on kovan
* Fix formatting.
* add some dos protection (#8084)
* more dos protection (#8104)
* Const time comparison (#8113)
* Use `subtle::slices_equal` for constant time comparison.
Also update the existing version of subtle in `ethcrypto` from
0.1 to 0.5
* Test specifically for InvalidPassword error.
* revert removing blooms (#8066)
* Revert "fix traces, removed bloomchain crate, closes #7228, closes #7167"
This reverts commit 1bf62038678295e5586f02a38a0c5aab9a9efe62.
* Revert "fixed broken logs (#7934)"
This reverts commit f8a2e53f3e.
* fixed broken logs
* bring back old lock order
* remove migration v13
* revert CURRENT_VERSION to 12 in migration.rs
* Fix compilation.
* Check one step deeper if we're on release track branches
* add missing pr
* Fix blooms?
* Fix tests compiilation.
* Fix size.
This commit is contained in:
committed by
Marek Kotewicz
parent
3c15a501ca
commit
feef2f8791
@@ -19,7 +19,7 @@
|
||||
use std::cell::RefCell;
|
||||
use wasmi::{
|
||||
self, Signature, Error, FuncRef, FuncInstance, MemoryDescriptor,
|
||||
MemoryRef, MemoryInstance,
|
||||
MemoryRef, MemoryInstance, memory_units,
|
||||
};
|
||||
|
||||
/// Internal ids all functions runtime supports. This is just a glue for wasmi interpreter
|
||||
@@ -219,7 +219,10 @@ impl ImportResolver {
|
||||
let mut mem_ref = self.memory.borrow_mut();
|
||||
if mem_ref.is_none() {
|
||||
*mem_ref = Some(
|
||||
MemoryInstance::alloc(0, Some(0)).expect("Memory allocation (0, 0) should not fail; qed")
|
||||
MemoryInstance::alloc(
|
||||
memory_units::Pages(0),
|
||||
Some(memory_units::Pages(0)),
|
||||
).expect("Memory allocation (0, 0) should not fail; qed")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -229,7 +232,7 @@ impl ImportResolver {
|
||||
|
||||
/// Returns memory size module initially requested
|
||||
pub fn memory_size(&self) -> Result<u32, Error> {
|
||||
Ok(self.memory_ref().size())
|
||||
Ok(self.memory_ref().current_size().0 as u32)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,7 +284,10 @@ impl wasmi::ModuleImportResolver for ImportResolver {
|
||||
{
|
||||
Err(Error::Instantiation("Module requested too much memory".to_owned()))
|
||||
} else {
|
||||
let mem = MemoryInstance::alloc(descriptor.initial(), descriptor.maximum())?;
|
||||
let mem = MemoryInstance::alloc(
|
||||
memory_units::Pages(descriptor.initial() as usize),
|
||||
descriptor.maximum().map(|x| memory_units::Pages(x as usize)),
|
||||
)?;
|
||||
*self.memory.borrow_mut() = Some(mem.clone());
|
||||
Ok(mem)
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ mod panic_payload;
|
||||
mod parser;
|
||||
|
||||
use vm::{GasLeft, ReturnData, ActionParams};
|
||||
use wasmi::Error as InterpreterError;
|
||||
use wasmi::{Error as InterpreterError, Trap};
|
||||
|
||||
use runtime::{Runtime, RuntimeContext};
|
||||
|
||||
@@ -43,17 +43,29 @@ use bigint::uint::U256;
|
||||
|
||||
/// Wrapped interpreter error
|
||||
#[derive(Debug)]
|
||||
pub struct Error(InterpreterError);
|
||||
pub enum Error {
|
||||
Interpreter(InterpreterError),
|
||||
Trap(Trap),
|
||||
}
|
||||
|
||||
impl From<InterpreterError> for Error {
|
||||
fn from(e: InterpreterError) -> Self {
|
||||
Error(e)
|
||||
Error::Interpreter(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Trap> for Error {
|
||||
fn from(e: Trap) -> Self {
|
||||
Error::Trap(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for vm::Error {
|
||||
fn from(e: Error) -> Self {
|
||||
vm::Error::Wasm(format!("Wasm runtime error: {:?}", e.0))
|
||||
match e {
|
||||
Error::Interpreter(e) => vm::Error::Wasm(format!("Wasm runtime error: {:?}", e)),
|
||||
Error::Trap(e) => vm::Error::Wasm(format!("Wasm contract trap: {:?}", e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,19 +78,25 @@ impl From<runtime::Error> for vm::Error {
|
||||
}
|
||||
}
|
||||
|
||||
enum ExecutionOutcome {
|
||||
Suicide,
|
||||
Return,
|
||||
NotSpecial,
|
||||
}
|
||||
|
||||
impl vm::Vm for WasmInterpreter {
|
||||
|
||||
fn exec(&mut self, params: ActionParams, ext: &mut vm::Ext) -> vm::Result<GasLeft> {
|
||||
let (module, data) = parser::payload(¶ms, ext.schedule().wasm())?;
|
||||
|
||||
let loaded_module = wasmi::Module::from_parity_wasm_module(module).map_err(Error)?;
|
||||
let loaded_module = wasmi::Module::from_parity_wasm_module(module).map_err(Error::Interpreter)?;
|
||||
|
||||
let instantiation_resolover = env::ImportResolver::with_limit(16);
|
||||
let instantiation_resolver = env::ImportResolver::with_limit(16);
|
||||
|
||||
let module_instance = wasmi::ModuleInstance::new(
|
||||
&loaded_module,
|
||||
&wasmi::ImportsBuilder::new().with_resolver("env", &instantiation_resolover)
|
||||
).map_err(Error)?;
|
||||
&wasmi::ImportsBuilder::new().with_resolver("env", &instantiation_resolver)
|
||||
).map_err(Error::Interpreter)?;
|
||||
|
||||
let adjusted_gas = params.gas * U256::from(ext.schedule().wasm().opcodes_div) /
|
||||
U256::from(ext.schedule().wasm().opcodes_mul);
|
||||
@@ -88,13 +106,13 @@ impl vm::Vm for WasmInterpreter {
|
||||
return Err(vm::Error::Wasm("Wasm interpreter cannot run contracts with gas (wasm adjusted) >= 2^64".to_owned()));
|
||||
}
|
||||
|
||||
let initial_memory = instantiation_resolover.memory_size().map_err(Error)?;
|
||||
let initial_memory = instantiation_resolver.memory_size().map_err(Error::Interpreter)?;
|
||||
trace!(target: "wasm", "Contract requested {:?} pages of initial memory", initial_memory);
|
||||
|
||||
let (gas_left, result) = {
|
||||
let mut runtime = Runtime::with_params(
|
||||
ext,
|
||||
instantiation_resolover.memory_ref(),
|
||||
instantiation_resolver.memory_ref(),
|
||||
// cannot overflow, checked above
|
||||
adjusted_gas.low_u64(),
|
||||
data.to_vec(),
|
||||
@@ -115,33 +133,29 @@ impl vm::Vm for WasmInterpreter {
|
||||
assert!(runtime.schedule().wasm().initial_mem < 1 << 16);
|
||||
runtime.charge(|s| initial_memory as u64 * s.wasm().initial_mem as u64)?;
|
||||
|
||||
let module_instance = module_instance.run_start(&mut runtime).map_err(Error)?;
|
||||
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::<runtime::Error>() {
|
||||
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())))));
|
||||
}
|
||||
}
|
||||
}
|
||||
let invoke_result = module_instance.invoke_export("call", &[], &mut runtime);
|
||||
|
||||
let mut execution_outcome = ExecutionOutcome::NotSpecial;
|
||||
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::<runtime::Error>()
|
||||
.expect("Host errors other than runtime::Error never produced; qed");
|
||||
|
||||
match **runtime_err {
|
||||
runtime::Error::Suicide => { execution_outcome = ExecutionOutcome::Suicide; },
|
||||
runtime::Error::Return => { execution_outcome = ExecutionOutcome::Return; },
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
trace!(target: "wasm", "Error executing contract: {:?}", err);
|
||||
return Err(vm::Error::from(Error::from(err)))
|
||||
}
|
||||
}
|
||||
|
||||
if let (ExecutionOutcome::NotSpecial, Err(e)) = (execution_outcome, 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(),
|
||||
|
||||
@@ -22,14 +22,18 @@ use parity_wasm::elements::{self, Deserialize};
|
||||
use parity_wasm::peek_size;
|
||||
|
||||
fn gas_rules(wasm_costs: &vm::WasmCosts) -> rules::Set {
|
||||
rules::Set::new({
|
||||
let mut vals = ::std::collections::HashMap::with_capacity(4);
|
||||
vals.insert(rules::InstructionType::Load, wasm_costs.mem as u32);
|
||||
vals.insert(rules::InstructionType::Store, wasm_costs.mem as u32);
|
||||
vals.insert(rules::InstructionType::Div, wasm_costs.div as u32);
|
||||
vals.insert(rules::InstructionType::Mul, wasm_costs.mul as u32);
|
||||
vals
|
||||
}).with_grow_cost(wasm_costs.grow_mem)
|
||||
rules::Set::new(
|
||||
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));
|
||||
vals.insert(rules::InstructionType::Store, rules::Metering::Fixed(wasm_costs.mem as u32));
|
||||
vals.insert(rules::InstructionType::Div, rules::Metering::Fixed(wasm_costs.div as u32));
|
||||
vals.insert(rules::InstructionType::Mul, rules::Metering::Fixed(wasm_costs.mul as u32));
|
||||
vals
|
||||
})
|
||||
.with_grow_cost(wasm_costs.grow_mem)
|
||||
.with_forbidden_floats()
|
||||
}
|
||||
|
||||
/// Splits payload to code and data according to params.params_type, also
|
||||
@@ -71,7 +75,12 @@ pub fn payload<'a>(params: &'a vm::ActionParams, wasm_costs: &vm::WasmCosts)
|
||||
let contract_module = wasm_utils::inject_gas_counter(
|
||||
deserialized_module,
|
||||
&gas_rules(wasm_costs),
|
||||
);
|
||||
).map_err(|_| vm::Error::Wasm(format!("Wasm contract error: bytecode invalid")))?;
|
||||
|
||||
let contract_module = wasm_utils::stack_height::inject_limiter(
|
||||
contract_module,
|
||||
wasm_costs.max_stack_height,
|
||||
).map_err(|_| vm::Error::Wasm(format!("Wasm contract error: stack limiter failure")))?;
|
||||
|
||||
let data = match params.params_type {
|
||||
vm::ParamsType::Embedded => {
|
||||
|
||||
@@ -20,7 +20,7 @@ use util::Address;
|
||||
use bigint::prelude::U256;
|
||||
use bigint::hash::H256;
|
||||
use vm::{self, CallType};
|
||||
use wasmi::{self, MemoryRef, RuntimeArgs, RuntimeValue, Error as InterpreterError};
|
||||
use wasmi::{self, MemoryRef, RuntimeArgs, RuntimeValue, Error as InterpreterError, Trap, TrapKind};
|
||||
use super::panic_payload;
|
||||
|
||||
pub struct RuntimeContext {
|
||||
@@ -52,6 +52,8 @@ pub enum Error {
|
||||
MemoryAccessViolation,
|
||||
/// Native code resulted in suicide
|
||||
Suicide,
|
||||
/// Native code requested execution to finish
|
||||
Return,
|
||||
/// Suicide was requested but coudn't complete
|
||||
SuicideAbort,
|
||||
/// Invalid gas state inside interpreter
|
||||
@@ -72,15 +74,40 @@ 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),
|
||||
}
|
||||
|
||||
impl wasmi::HostError for Error { }
|
||||
|
||||
impl From<Trap> for Error {
|
||||
fn from(trap: Trap) -> Self {
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InterpreterError> for Error {
|
||||
fn from(interpreter_err: InterpreterError) -> Self {
|
||||
match interpreter_err {
|
||||
fn from(err: InterpreterError) -> Self {
|
||||
match err {
|
||||
InterpreterError::Value(_) => Error::InvalidSyscall,
|
||||
InterpreterError::Memory(_) => Error::MemoryAccessViolation,
|
||||
_ => Error::Other,
|
||||
@@ -98,6 +125,7 @@ impl ::std::fmt::Display for Error {
|
||||
Error::InvalidGasState => write!(f, "Invalid gas state"),
|
||||
Error::BalanceQueryError => write!(f, "Balance query resulted in an error"),
|
||||
Error::Suicide => write!(f, "Suicide result"),
|
||||
Error::Return => write!(f, "Return result"),
|
||||
Error::Unknown => write!(f, "Unknown runtime function invoked"),
|
||||
Error::AllocationFailed => write!(f, "Memory allocation failed (OOM)"),
|
||||
Error::BadUtf8 => write!(f, "String encoding is bad utf-8 sequence"),
|
||||
@@ -105,6 +133,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),
|
||||
}
|
||||
}
|
||||
@@ -161,12 +194,14 @@ impl<'a> Runtime<'a> {
|
||||
/// Intuition about the return value sense is to aswer the question 'are we allowed to continue?'
|
||||
fn charge_gas(&mut self, amount: u64) -> bool {
|
||||
let prev = self.gas_counter;
|
||||
if prev + amount > self.gas_limit {
|
||||
// exceeds gas
|
||||
false
|
||||
} else {
|
||||
self.gas_counter = prev + amount;
|
||||
true
|
||||
match prev.checked_add(amount) {
|
||||
// gas charge overflow protection
|
||||
None => false,
|
||||
Some(val) if val > self.gas_limit => false,
|
||||
Some(_) => {
|
||||
self.gas_counter = prev + amount;
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,8 +255,8 @@ impl<'a> Runtime<'a> {
|
||||
/// Read from the storage to wasm memory.
|
||||
pub fn storage_read(&mut self, args: RuntimeArgs) -> Result<()>
|
||||
{
|
||||
let key = self.h256_at(args.nth(0)?)?;
|
||||
let val_ptr: u32 = args.nth(1)?;
|
||||
let key = self.h256_at(args.nth_checked(0)?)?;
|
||||
let val_ptr: u32 = args.nth_checked(1)?;
|
||||
|
||||
let val = self.ext.storage_at(&key).map_err(|_| Error::StorageReadError)?;
|
||||
|
||||
@@ -235,8 +270,8 @@ impl<'a> Runtime<'a> {
|
||||
/// Write to storage from wasm memory.
|
||||
pub fn storage_write(&mut self, args: RuntimeArgs) -> Result<()>
|
||||
{
|
||||
let key = self.h256_at(args.nth(0)?)?;
|
||||
let val_ptr: u32 = args.nth(1)?;
|
||||
let key = self.h256_at(args.nth_checked(0)?)?;
|
||||
let val_ptr: u32 = args.nth_checked(1)?;
|
||||
|
||||
let val = self.h256_at(val_ptr)?;
|
||||
let former_val = self.ext.storage_at(&key).map_err(|_| Error::StorageUpdateError)?;
|
||||
@@ -264,14 +299,14 @@ impl<'a> Runtime<'a> {
|
||||
/// Return. Syscall takes 2 arguments - pointer in sandboxed memory where result is and
|
||||
/// the length of the result.
|
||||
pub fn ret(&mut self, args: RuntimeArgs) -> Result<()> {
|
||||
let ptr: u32 = args.nth(0)?;
|
||||
let len: u32 = args.nth(1)?;
|
||||
let ptr: u32 = args.nth_checked(0)?;
|
||||
let len: u32 = args.nth_checked(1)?;
|
||||
|
||||
trace!(target: "wasm", "Contract ret: {} bytes @ {}", len, ptr);
|
||||
|
||||
self.result = self.memory.get(ptr, len as usize)?;
|
||||
|
||||
Ok(())
|
||||
Err(Error::Return)
|
||||
}
|
||||
|
||||
/// Destroy the runtime, returning currently recorded result of the execution.
|
||||
@@ -287,7 +322,7 @@ impl<'a> Runtime<'a> {
|
||||
|
||||
/// Report gas cost with the params passed in wasm stack
|
||||
fn gas(&mut self, args: RuntimeArgs) -> Result<()> {
|
||||
let amount: u32 = args.nth(0)?;
|
||||
let amount: u32 = args.nth_checked(0)?;
|
||||
if self.charge_gas(amount as u64) {
|
||||
Ok(())
|
||||
} else {
|
||||
@@ -302,7 +337,10 @@ impl<'a> Runtime<'a> {
|
||||
|
||||
/// Write input bytes to the memory location using the passed pointer
|
||||
fn fetch_input(&mut self, args: RuntimeArgs) -> Result<()> {
|
||||
let ptr: u32 = args.nth(0)?;
|
||||
let args_len = self.args.len() as u64;
|
||||
self.charge(|s| args_len * s.wasm().memcpy as u64)?;
|
||||
|
||||
let ptr: u32 = args.nth_checked(0)?;
|
||||
self.memory.set(ptr, &self.args[..])?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -310,8 +348,8 @@ impl<'a> Runtime<'a> {
|
||||
/// User panic. Contract can invoke this when he encounters unrecoverable error.
|
||||
fn panic(&mut self, args: RuntimeArgs) -> Result<()>
|
||||
{
|
||||
let payload_ptr: u32 = args.nth(0)?;
|
||||
let payload_len: u32 = args.nth(1)?;
|
||||
let payload_ptr: u32 = args.nth_checked(0)?;
|
||||
let payload_len: u32 = args.nth_checked(1)?;
|
||||
|
||||
let raw_payload = self.memory.get(payload_ptr, payload_len as usize)?;
|
||||
let payload = panic_payload::decode(&raw_payload);
|
||||
@@ -345,26 +383,26 @@ impl<'a> Runtime<'a> {
|
||||
{
|
||||
trace!(target: "wasm", "runtime: CALL({:?})", call_type);
|
||||
|
||||
let gas: u64 = args.nth(0)?;
|
||||
let gas: u64 = args.nth_checked(0)?;
|
||||
trace!(target: "wasm", " gas: {:?}", gas);
|
||||
|
||||
let address = self.address_at(args.nth(1)?)?;
|
||||
let address = self.address_at(args.nth_checked(1)?)?;
|
||||
trace!(target: "wasm", " address: {:?}", address);
|
||||
|
||||
let vofs = if use_val { 1 } else { 0 };
|
||||
let val = if use_val { Some(self.u256_at(args.nth(2)?)?) } else { None };
|
||||
let val = if use_val { Some(self.u256_at(args.nth_checked(2)?)?) } else { None };
|
||||
trace!(target: "wasm", " val: {:?}", val);
|
||||
|
||||
let input_ptr: u32 = args.nth(2 + vofs)?;
|
||||
let input_ptr: u32 = args.nth_checked(2 + vofs)?;
|
||||
trace!(target: "wasm", " input_ptr: {:?}", input_ptr);
|
||||
|
||||
let input_len: u32 = args.nth(3 + vofs)?;
|
||||
let input_len: u32 = args.nth_checked(3 + vofs)?;
|
||||
trace!(target: "wasm", " input_len: {:?}", input_len);
|
||||
|
||||
let result_ptr: u32 = args.nth(4 + vofs)?;
|
||||
let result_ptr: u32 = args.nth_checked(4 + vofs)?;
|
||||
trace!(target: "wasm", " result_ptr: {:?}", result_ptr);
|
||||
|
||||
let result_alloc_len: u32 = args.nth(5 + vofs)?;
|
||||
let result_alloc_len: u32 = args.nth_checked(5 + vofs)?;
|
||||
trace!(target: "wasm", " result_len: {:?}", result_alloc_len);
|
||||
|
||||
if let Some(ref val) = val {
|
||||
@@ -464,7 +502,7 @@ impl<'a> Runtime<'a> {
|
||||
|
||||
pub fn value(&mut self, args: RuntimeArgs) -> Result<()> {
|
||||
let val = self.context.value;
|
||||
self.return_u256_ptr(args.nth(0)?, val)
|
||||
self.return_u256_ptr(args.nth_checked(0)?, val)
|
||||
}
|
||||
|
||||
pub fn create(&mut self, args: RuntimeArgs) -> Result<RuntimeValue>
|
||||
@@ -474,13 +512,13 @@ impl<'a> Runtime<'a> {
|
||||
// fn create(endowment: *const u8, code_ptr: *const u8, code_len: u32, result_ptr: *mut u8) -> i32;
|
||||
//
|
||||
trace!(target: "wasm", "runtime: CREATE");
|
||||
let endowment = self.u256_at(args.nth(0)?)?;
|
||||
let endowment = self.u256_at(args.nth_checked(0)?)?;
|
||||
trace!(target: "wasm", " val: {:?}", endowment);
|
||||
let code_ptr: u32 = args.nth(1)?;
|
||||
let code_ptr: u32 = args.nth_checked(1)?;
|
||||
trace!(target: "wasm", " code_ptr: {:?}", code_ptr);
|
||||
let code_len: u32 = args.nth(2)?;
|
||||
let code_len: u32 = args.nth_checked(2)?;
|
||||
trace!(target: "wasm", " code_len: {:?}", code_len);
|
||||
let result_ptr: u32 = args.nth(3)?;
|
||||
let result_ptr: u32 = args.nth_checked(3)?;
|
||||
trace!(target: "wasm", "result_ptr: {:?}", result_ptr);
|
||||
|
||||
let code = self.memory.get(code_ptr, code_len as usize)?;
|
||||
@@ -522,13 +560,13 @@ impl<'a> Runtime<'a> {
|
||||
|
||||
fn debug(&mut self, args: RuntimeArgs) -> Result<()>
|
||||
{
|
||||
let msg_ptr: u32 = args.nth(0)?;
|
||||
let msg_len: u32 = args.nth(1)?;
|
||||
trace!(target: "wasm", "Contract debug message: {}", {
|
||||
let msg_ptr: u32 = args.nth_checked(0)?;
|
||||
let msg_len: u32 = args.nth_checked(1)?;
|
||||
|
||||
let msg = String::from_utf8(self.memory.get(msg_ptr, msg_len as usize)?)
|
||||
.map_err(|_| Error::BadUtf8)?;
|
||||
|
||||
trace!(target: "wasm", "Contract debug message: {}", msg);
|
||||
String::from_utf8(self.memory.get(msg_ptr, msg_len as usize)?)
|
||||
.map_err(|_| Error::BadUtf8)?
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -536,7 +574,7 @@ impl<'a> Runtime<'a> {
|
||||
/// Pass suicide to state runtime
|
||||
pub fn suicide(&mut self, args: RuntimeArgs) -> Result<()>
|
||||
{
|
||||
let refund_address = self.address_at(args.nth(0)?)?;
|
||||
let refund_address = self.address_at(args.nth_checked(0)?)?;
|
||||
|
||||
if self.ext.exists(&refund_address).map_err(|_| Error::SuicideAbort)? {
|
||||
trace!(target: "wasm", "Suicide: refund to existing address {}", refund_address);
|
||||
@@ -554,8 +592,8 @@ impl<'a> Runtime<'a> {
|
||||
|
||||
pub fn blockhash(&mut self, args: RuntimeArgs) -> Result<()> {
|
||||
self.adjusted_charge(|schedule| schedule.blockhash_gas as u64)?;
|
||||
let hash = self.ext.blockhash(&U256::from(args.nth::<u64>(0)?));
|
||||
self.memory.set(args.nth(1)?, &*hash)?;
|
||||
let hash = self.ext.blockhash(&U256::from(args.nth_checked::<u64>(0)?));
|
||||
self.memory.set(args.nth_checked(1)?, &*hash)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -566,32 +604,32 @@ impl<'a> Runtime<'a> {
|
||||
|
||||
pub fn coinbase(&mut self, args: RuntimeArgs) -> Result<()> {
|
||||
let coinbase = self.ext.env_info().author;
|
||||
self.return_address_ptr(args.nth(0)?, coinbase)
|
||||
self.return_address_ptr(args.nth_checked(0)?, coinbase)
|
||||
}
|
||||
|
||||
pub fn difficulty(&mut self, args: RuntimeArgs) -> Result<()> {
|
||||
let difficulty = self.ext.env_info().difficulty;
|
||||
self.return_u256_ptr(args.nth(0)?, difficulty)
|
||||
self.return_u256_ptr(args.nth_checked(0)?, difficulty)
|
||||
}
|
||||
|
||||
pub fn gaslimit(&mut self, args: RuntimeArgs) -> Result<()> {
|
||||
let gas_limit = self.ext.env_info().gas_limit;
|
||||
self.return_u256_ptr(args.nth(0)?, gas_limit)
|
||||
self.return_u256_ptr(args.nth_checked(0)?, gas_limit)
|
||||
}
|
||||
|
||||
pub fn address(&mut self, args: RuntimeArgs) -> Result<()> {
|
||||
let address = self.context.address;
|
||||
self.return_address_ptr(args.nth(0)?, address)
|
||||
self.return_address_ptr(args.nth_checked(0)?, address)
|
||||
}
|
||||
|
||||
pub fn sender(&mut self, args: RuntimeArgs) -> Result<()> {
|
||||
let sender = self.context.sender;
|
||||
self.return_address_ptr(args.nth(0)?, sender)
|
||||
self.return_address_ptr(args.nth_checked(0)?, sender)
|
||||
}
|
||||
|
||||
pub fn origin(&mut self, args: RuntimeArgs) -> Result<()> {
|
||||
let origin = self.context.origin;
|
||||
self.return_address_ptr(args.nth(0)?, origin)
|
||||
self.return_address_ptr(args.nth_checked(0)?, origin)
|
||||
}
|
||||
|
||||
pub fn timestamp(&mut self) -> Result<RuntimeValue> {
|
||||
@@ -601,12 +639,10 @@ impl<'a> Runtime<'a> {
|
||||
|
||||
pub fn elog(&mut self, args: RuntimeArgs) -> Result<()>
|
||||
{
|
||||
// signature is:
|
||||
// pub fn elog(topic_ptr: *const u8, topic_count: u32, data_ptr: *const u8, data_len: u32);
|
||||
let topic_ptr: u32 = args.nth(0)?;
|
||||
let topic_count: u32 = args.nth(1)?;
|
||||
let data_ptr: u32 = args.nth(2)?;
|
||||
let data_len: u32 = args.nth(3)?;
|
||||
let topic_ptr: u32 = args.nth_checked(0)?;
|
||||
let topic_count: u32 = args.nth_checked(1)?;
|
||||
let data_ptr: u32 = args.nth_checked(2)?;
|
||||
let data_len: u32 = args.nth_checked(3)?;
|
||||
|
||||
if topic_count > 4 {
|
||||
return Err(Error::Log.into());
|
||||
@@ -639,7 +675,7 @@ impl<'a> Runtime<'a> {
|
||||
|
||||
mod ext_impl {
|
||||
|
||||
use wasmi::{Externals, RuntimeArgs, RuntimeValue, Error};
|
||||
use wasmi::{Externals, RuntimeArgs, RuntimeValue, Trap};
|
||||
use env::ids::*;
|
||||
|
||||
macro_rules! void {
|
||||
@@ -659,7 +695,7 @@ mod ext_impl {
|
||||
&mut self,
|
||||
index: usize,
|
||||
args: RuntimeArgs,
|
||||
) -> Result<Option<RuntimeValue>, Error> {
|
||||
) -> Result<Option<RuntimeValue>, Trap> {
|
||||
match index {
|
||||
STORAGE_WRITE_FUNC => void!(self.storage_write(args)),
|
||||
STORAGE_READ_FUNC => void!(self.storage_read(args)),
|
||||
|
||||
@@ -209,7 +209,7 @@ fn dispersion() {
|
||||
result,
|
||||
vec![0u8, 0, 125, 11, 197, 7, 255, 8, 19, 0]
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(93_972));
|
||||
assert_eq!(gas_left, U256::from(94_013));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -237,7 +237,7 @@ fn suicide_not() {
|
||||
result,
|
||||
vec![0u8]
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(94_970));
|
||||
assert_eq!(gas_left, U256::from(94_984));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -269,7 +269,7 @@ fn suicide() {
|
||||
};
|
||||
|
||||
assert!(ext.suicides.contains(&refund));
|
||||
assert_eq!(gas_left, U256::from(94_933));
|
||||
assert_eq!(gas_left, U256::from(94_925));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -299,7 +299,7 @@ fn create() {
|
||||
assert!(ext.calls.contains(
|
||||
&FakeCall {
|
||||
call_type: FakeCallType::Create,
|
||||
gas: U256::from(60_917),
|
||||
gas: U256::from(60_914),
|
||||
sender_address: None,
|
||||
receive_address: None,
|
||||
value: Some(1_000_000_000.into()),
|
||||
@@ -307,7 +307,7 @@ fn create() {
|
||||
code_address: None,
|
||||
}
|
||||
));
|
||||
assert_eq!(gas_left, U256::from(60_903));
|
||||
assert_eq!(gas_left, U256::from(60_900));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -467,7 +467,7 @@ fn realloc() {
|
||||
}
|
||||
};
|
||||
assert_eq!(result, vec![0u8; 2]);
|
||||
assert_eq!(gas_left, U256::from(94_352));
|
||||
assert_eq!(gas_left, U256::from(94_372));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -543,7 +543,7 @@ fn keccak() {
|
||||
};
|
||||
|
||||
assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
|
||||
assert_eq!(gas_left, U256::from(84_223));
|
||||
assert_eq!(gas_left, U256::from(84_240));
|
||||
}
|
||||
|
||||
// math_* tests check the ability of wasm contract to perform big integer operations
|
||||
@@ -572,7 +572,7 @@ fn math_add() {
|
||||
U256::from_dec_str("1888888888888888888888888888887").unwrap(),
|
||||
(&result[..]).into()
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(93_818));
|
||||
assert_eq!(gas_left, U256::from(93_814));
|
||||
}
|
||||
|
||||
// multiplication
|
||||
@@ -594,7 +594,7 @@ fn math_mul() {
|
||||
U256::from_dec_str("888888888888888888888888888887111111111111111111111111111112").unwrap(),
|
||||
(&result[..]).into()
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(93_304));
|
||||
assert_eq!(gas_left, U256::from(93_300));
|
||||
}
|
||||
|
||||
// subtraction
|
||||
@@ -616,7 +616,7 @@ fn math_sub() {
|
||||
U256::from_dec_str("111111111111111111111111111111").unwrap(),
|
||||
(&result[..]).into()
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(93_831));
|
||||
assert_eq!(gas_left, U256::from(93_826));
|
||||
}
|
||||
|
||||
// subtraction with overflow
|
||||
@@ -658,7 +658,7 @@ fn math_div() {
|
||||
U256::from_dec_str("1125000").unwrap(),
|
||||
(&result[..]).into()
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(90_607));
|
||||
assert_eq!(gas_left, U256::from(90_603));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -686,7 +686,7 @@ fn storage_metering() {
|
||||
};
|
||||
|
||||
// 0 -> not 0
|
||||
assert_eq!(gas_left, U256::from(74_410));
|
||||
assert_eq!(gas_left, U256::from(74_338));
|
||||
|
||||
// #2
|
||||
|
||||
@@ -705,7 +705,7 @@ fn storage_metering() {
|
||||
};
|
||||
|
||||
// not 0 -> not 0
|
||||
assert_eq!(gas_left, U256::from(89_410));
|
||||
assert_eq!(gas_left, U256::from(89_338));
|
||||
}
|
||||
|
||||
// This test checks the ability of wasm contract to invoke
|
||||
@@ -793,7 +793,7 @@ fn externs() {
|
||||
"Gas limit requested and returned does not match"
|
||||
);
|
||||
|
||||
assert_eq!(gas_left, U256::from(92_089));
|
||||
assert_eq!(gas_left, U256::from(92_110));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -819,7 +819,7 @@ fn embedded_keccak() {
|
||||
};
|
||||
|
||||
assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
|
||||
assert_eq!(gas_left, U256::from(84_223));
|
||||
assert_eq!(gas_left, U256::from(84_240));
|
||||
}
|
||||
|
||||
/// This test checks the correctness of log extern
|
||||
@@ -854,5 +854,5 @@ fn events() {
|
||||
assert_eq!(&log_entry.data, b"gnihtemos");
|
||||
|
||||
assert_eq!(&result, b"gnihtemos");
|
||||
assert_eq!(gas_left, U256::from(81_235));
|
||||
assert_eq!(gas_left, U256::from(81_292));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user