WASM gas schedule (#6638)
* some failing tests * finalize * fallable -> fallible * alter mul/div/static_i64 * Update schedule.rs * to u32 * balance charge also * review fixes * remove redundant line
This commit is contained in:
parent
8d1964bc3b
commit
1601030081
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -3539,8 +3539,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-utils"
|
name = "wasm-utils"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/paritytech/wasm-utils#a6b6d75be0680568209813924a5ec0ad89e86697"
|
source = "git+https://github.com/paritytech/wasm-utils#6a39db802eb6b67a0c4e5cf50741f965e217335a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -113,6 +113,49 @@ pub struct Schedule {
|
|||||||
pub kill_dust: CleanDustMode,
|
pub kill_dust: CleanDustMode,
|
||||||
/// Enable EIP-86 rules
|
/// Enable EIP-86 rules
|
||||||
pub eip86: bool,
|
pub eip86: bool,
|
||||||
|
/// Wasm extra schedule settings
|
||||||
|
pub wasm: WasmCosts,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wasm cost table
|
||||||
|
pub struct WasmCosts {
|
||||||
|
/// Arena allocator cost, per byte
|
||||||
|
pub alloc: u32,
|
||||||
|
/// Div operations multiplier.
|
||||||
|
pub div: u32,
|
||||||
|
/// Div operations multiplier.
|
||||||
|
pub mul: u32,
|
||||||
|
/// Memory (load/store) operations multiplier.
|
||||||
|
pub mem: u32,
|
||||||
|
/// Memory copy operation.
|
||||||
|
pub mem_copy: u32,
|
||||||
|
/// Static region charge, per byte.
|
||||||
|
pub static_region: u32,
|
||||||
|
/// General static query of u64 value from env-info
|
||||||
|
pub static_u64: u32,
|
||||||
|
/// General static query of U256 value from env-info
|
||||||
|
pub static_u256: u32,
|
||||||
|
/// General static query of Address value from env-info
|
||||||
|
pub static_address: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for WasmCosts {
|
||||||
|
fn default() -> Self {
|
||||||
|
WasmCosts {
|
||||||
|
alloc: 2,
|
||||||
|
div: 16,
|
||||||
|
mul: 4,
|
||||||
|
mem: 2,
|
||||||
|
mem_copy: 1,
|
||||||
|
static_region: 1,
|
||||||
|
|
||||||
|
// due to runtime issues, this can be slow
|
||||||
|
static_u64: 32,
|
||||||
|
|
||||||
|
static_u256: 64,
|
||||||
|
static_address: 40,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dust accounts cleanup mode.
|
/// Dust accounts cleanup mode.
|
||||||
@ -187,6 +230,7 @@ impl Schedule {
|
|||||||
have_static_call: false,
|
have_static_call: false,
|
||||||
kill_dust: CleanDustMode::Off,
|
kill_dust: CleanDustMode::Off,
|
||||||
eip86: false,
|
eip86: false,
|
||||||
|
wasm: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,6 +293,7 @@ impl Schedule {
|
|||||||
have_static_call: false,
|
have_static_call: false,
|
||||||
kill_dust: CleanDustMode::Off,
|
kill_dust: CleanDustMode::Off,
|
||||||
eip86: false,
|
eip86: false,
|
||||||
|
wasm: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,9 +122,18 @@ impl vm::Vm for WasmInterpreter {
|
|||||||
&mut cursor
|
&mut cursor
|
||||||
).map_err(|err| {
|
).map_err(|err| {
|
||||||
vm::Error::Wasm(format!("Error deserializing contract code ({:?})", err))
|
vm::Error::Wasm(format!("Error deserializing contract code ({:?})", err))
|
||||||
})?
|
})?,
|
||||||
|
runtime.gas_rules(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let data_section_length = contract_module.data_section()
|
||||||
|
.map(|section| section.entries().iter().fold(0, |sum, entry| sum + entry.value().len()))
|
||||||
|
.unwrap_or(0)
|
||||||
|
as u64;
|
||||||
|
|
||||||
|
let static_segment_cost = data_section_length * runtime.ext().schedule().wasm.static_region as u64;
|
||||||
|
runtime.charge(|_| static_segment_cost).map_err(Error)?;
|
||||||
|
|
||||||
let d_ptr = runtime.write_descriptor(¶ms.data.unwrap_or_default())
|
let d_ptr = runtime.write_descriptor(¶ms.data.unwrap_or_default())
|
||||||
.map_err(Error)?;
|
.map_err(Error)?;
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ use byteorder::{LittleEndian, ByteOrder};
|
|||||||
|
|
||||||
use vm;
|
use vm;
|
||||||
use parity_wasm::interpreter;
|
use parity_wasm::interpreter;
|
||||||
|
use wasm_utils::rules;
|
||||||
use bigint::prelude::U256;
|
use bigint::prelude::U256;
|
||||||
use bigint::hash::H256;
|
use bigint::hash::H256;
|
||||||
use util::Address;
|
use util::Address;
|
||||||
@ -111,6 +112,7 @@ pub struct Runtime<'a, 'b> {
|
|||||||
memory: Arc<InterpreterMemoryInstance>,
|
memory: Arc<InterpreterMemoryInstance>,
|
||||||
context: RuntimeContext,
|
context: RuntimeContext,
|
||||||
instance: &'b InterpreterProgramInstance,
|
instance: &'b InterpreterProgramInstance,
|
||||||
|
gas_rules: rules::Set,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> Runtime<'a, 'b> {
|
impl<'a, 'b> Runtime<'a, 'b> {
|
||||||
@ -123,6 +125,20 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
|||||||
context: RuntimeContext,
|
context: RuntimeContext,
|
||||||
program_instance: &'d InterpreterProgramInstance,
|
program_instance: &'d InterpreterProgramInstance,
|
||||||
) -> Runtime<'c, 'd> {
|
) -> Runtime<'c, 'd> {
|
||||||
|
|
||||||
|
let rules = {
|
||||||
|
let schedule = ext.schedule();
|
||||||
|
|
||||||
|
rules::Set::new({
|
||||||
|
let mut vals = ::std::collections::HashMap::with_capacity(4);
|
||||||
|
vals.insert(rules::InstructionType::Load, schedule.wasm.mem as u32);
|
||||||
|
vals.insert(rules::InstructionType::Store, schedule.wasm.mem as u32);
|
||||||
|
vals.insert(rules::InstructionType::Div, schedule.wasm.div as u32);
|
||||||
|
vals.insert(rules::InstructionType::Mul, schedule.wasm.mul as u32);
|
||||||
|
vals
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
Runtime {
|
Runtime {
|
||||||
gas_counter: 0,
|
gas_counter: 0,
|
||||||
gas_limit: gas_limit,
|
gas_limit: gas_limit,
|
||||||
@ -131,6 +147,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
|||||||
ext: ext,
|
ext: ext,
|
||||||
context: context,
|
context: context,
|
||||||
instance: program_instance,
|
instance: program_instance,
|
||||||
|
gas_rules: rules,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,6 +160,8 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
|||||||
let key = self.pop_h256(&mut context)?;
|
let key = self.pop_h256(&mut context)?;
|
||||||
trace!(target: "wasm", "storage_write: value {} at @{}", &val, &key);
|
trace!(target: "wasm", "storage_write: value {} at @{}", &val, &key);
|
||||||
|
|
||||||
|
self.charge(|schedule| schedule.sstore_set_gas as u64)?;
|
||||||
|
|
||||||
self.ext.set_storage(key, val).map_err(|_| UserTrap::StorageUpdateError)?;
|
self.ext.set_storage(key, val).map_err(|_| UserTrap::StorageUpdateError)?;
|
||||||
|
|
||||||
Ok(Some(0i32.into()))
|
Ok(Some(0i32.into()))
|
||||||
@ -155,9 +174,10 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
|||||||
let mut context = context;
|
let mut context = context;
|
||||||
let val_ptr = context.value_stack.pop_as::<i32>()?;
|
let val_ptr = context.value_stack.pop_as::<i32>()?;
|
||||||
let key = self.pop_h256(&mut context)?;
|
let key = self.pop_h256(&mut context)?;
|
||||||
|
|
||||||
let val = self.ext.storage_at(&key).map_err(|_| UserTrap::StorageReadError)?;
|
let val = self.ext.storage_at(&key).map_err(|_| UserTrap::StorageReadError)?;
|
||||||
|
|
||||||
|
self.charge(|schedule| schedule.sload_gas as u64)?;
|
||||||
|
|
||||||
self.memory.set(val_ptr as u32, &*val)?;
|
self.memory.set(val_ptr as u32, &*val)?;
|
||||||
|
|
||||||
Ok(Some(0.into()))
|
Ok(Some(0.into()))
|
||||||
@ -170,6 +190,9 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
|||||||
let mut context = context;
|
let mut context = context;
|
||||||
let return_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
let return_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
let address = self.pop_address(&mut context)?;
|
let address = self.pop_address(&mut context)?;
|
||||||
|
|
||||||
|
self.charge(|schedule| schedule.balance_gas as u64)?;
|
||||||
|
|
||||||
let balance = self.ext.balance(&address).map_err(|_| UserTrap::BalanceQueryError)?;
|
let balance = self.ext.balance(&address).map_err(|_| UserTrap::BalanceQueryError)?;
|
||||||
let value: H256 = balance.into();
|
let value: H256 = balance.into();
|
||||||
self.memory.set(return_ptr, &*value)?;
|
self.memory.set(return_ptr, &*value)?;
|
||||||
@ -183,12 +206,32 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
|||||||
let mut context = context;
|
let mut context = context;
|
||||||
let refund_address = self.pop_address(&mut context)?;
|
let refund_address = self.pop_address(&mut context)?;
|
||||||
|
|
||||||
|
if self.ext.exists(&refund_address).map_err(|_| UserTrap::SuicideAbort)? {
|
||||||
|
trace!(target: "wasm", "Suicide: refund to existing address {}", refund_address);
|
||||||
|
self.charge(|schedule| schedule.suicide_gas as u64)?;
|
||||||
|
} else {
|
||||||
|
trace!(target: "wasm", "Suicide: refund to new address {}", refund_address);
|
||||||
|
self.charge(|schedule| schedule.suicide_to_new_account_cost as u64)?;
|
||||||
|
}
|
||||||
|
|
||||||
self.ext.suicide(&refund_address).map_err(|_| UserTrap::SuicideAbort)?;
|
self.ext.suicide(&refund_address).map_err(|_| UserTrap::SuicideAbort)?;
|
||||||
|
|
||||||
// We send trap to interpreter so it should abort further execution
|
// We send trap to interpreter so it should abort further execution
|
||||||
Err(UserTrap::Suicide.into())
|
Err(UserTrap::Suicide.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Charge gas according to closure
|
||||||
|
pub fn charge<F>(&mut self, f: F) -> Result<(), InterpreterError>
|
||||||
|
where F: FnOnce(&vm::Schedule) -> u64
|
||||||
|
{
|
||||||
|
let amount = f(self.ext.schedule());
|
||||||
|
if !self.charge_gas(amount as u64) {
|
||||||
|
Err(UserTrap::GasLimit.into())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Invoke create in the state runtime
|
/// Invoke create in the state runtime
|
||||||
pub fn create(&mut self, context: InterpreterCallerContext)
|
pub fn create(&mut self, context: InterpreterCallerContext)
|
||||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||||
@ -211,6 +254,9 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
|||||||
|
|
||||||
let code = self.memory.get(code_ptr, code_len as usize)?;
|
let code = self.memory.get(code_ptr, code_len as usize)?;
|
||||||
|
|
||||||
|
self.charge(|schedule| schedule.create_gas as u64)?;
|
||||||
|
self.charge(|schedule| schedule.create_data_gas as u64 * code.len() as u64)?;
|
||||||
|
|
||||||
let gas_left = self.gas_left()
|
let gas_left = self.gas_left()
|
||||||
.map_err(|_| UserTrap::InvalidGasState)?
|
.map_err(|_| UserTrap::InvalidGasState)?
|
||||||
.into();
|
.into();
|
||||||
@ -312,6 +358,8 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.charge(|schedule| schedule.call_gas as u64)?;
|
||||||
|
|
||||||
let mut result = Vec::with_capacity(result_alloc_len as usize);
|
let mut result = Vec::with_capacity(result_alloc_len as usize);
|
||||||
result.resize(result_alloc_len as usize, 0);
|
result.resize(result_alloc_len as usize, 0);
|
||||||
let gas = self.gas_left()
|
let gas = self.gas_left()
|
||||||
@ -369,6 +417,9 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
|||||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||||
{
|
{
|
||||||
let amount = context.value_stack.pop_as::<i32>()? as u32;
|
let amount = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
|
|
||||||
|
self.charge(|schedule| schedule.wasm.alloc as u64 * amount as u64)?;
|
||||||
|
|
||||||
let previous_top = self.dynamic_top;
|
let previous_top = self.dynamic_top;
|
||||||
self.dynamic_top = previous_top + amount;
|
self.dynamic_top = previous_top + amount;
|
||||||
Ok(Some((previous_top as i32).into()))
|
Ok(Some((previous_top as i32).into()))
|
||||||
@ -492,13 +543,15 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
|||||||
&*self.memory
|
&*self.memory
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mem_copy(&self, context: InterpreterCallerContext)
|
fn mem_copy(&mut self, context: InterpreterCallerContext)
|
||||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||||
{
|
{
|
||||||
let len = context.value_stack.pop_as::<i32>()? as u32;
|
let len = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
let dst = context.value_stack.pop_as::<i32>()? as u32;
|
let dst = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
let src = context.value_stack.pop_as::<i32>()? as u32;
|
let src = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
|
|
||||||
|
self.charge(|schedule| schedule.wasm.mem_copy as u64 * len as u64)?;
|
||||||
|
|
||||||
let mem = self.memory().get(src, len as usize)?;
|
let mem = self.memory().get(src, len as usize)?;
|
||||||
self.memory().set(dst, &mem)?;
|
self.memory().set(dst, &mem)?;
|
||||||
|
|
||||||
@ -542,6 +595,8 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
|||||||
let block_hi = context.value_stack.pop_as::<i32>()? as u32;
|
let block_hi = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
let block_lo = context.value_stack.pop_as::<i32>()? as u32;
|
let block_lo = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
|
|
||||||
|
self.charge(|schedule| schedule.blockhash_gas as u64)?;
|
||||||
|
|
||||||
let block_num = (block_hi as u64) << 32 | block_lo as u64;
|
let block_num = (block_hi as u64) << 32 | block_lo as u64;
|
||||||
|
|
||||||
trace!("Requesting block hash for block #{}", block_num);
|
trace!("Requesting block hash for block #{}", block_num);
|
||||||
@ -552,44 +607,72 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
|||||||
Ok(Some(0i32.into()))
|
Ok(Some(0i32.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn return_address_ptr(&mut self, ptr: u32, val: Address) -> Result<(), InterpreterError>
|
||||||
|
{
|
||||||
|
self.charge(|schedule| schedule.wasm.static_address as u64)?;
|
||||||
|
self.memory.set(ptr, &*val)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn return_u256_ptr(&mut self, ptr: u32, val: U256) -> Result<(), InterpreterError> {
|
||||||
|
let value: H256 = val.into();
|
||||||
|
self.charge(|schedule| schedule.wasm.static_u256 as u64)?;
|
||||||
|
self.memory.set(ptr, &*value)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn coinbase(&mut self, context: InterpreterCallerContext)
|
fn coinbase(&mut self, context: InterpreterCallerContext)
|
||||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||||
{
|
{
|
||||||
let return_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
let author = self.ext.env_info().author;
|
||||||
self.memory.set(return_ptr, &*self.ext.env_info().author)?;
|
self.return_address_ptr(
|
||||||
|
context.value_stack.pop_as::<i32>()? as u32,
|
||||||
|
author,
|
||||||
|
)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sender(&mut self, context: InterpreterCallerContext)
|
fn sender(&mut self, context: InterpreterCallerContext)
|
||||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||||
{
|
{
|
||||||
let return_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
let sender = self.context.sender;
|
||||||
self.memory.set(return_ptr, &*self.context.sender)?;
|
self.return_address_ptr(
|
||||||
|
context.value_stack.pop_as::<i32>()? as u32,
|
||||||
|
sender,
|
||||||
|
)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn address(&mut self, context: InterpreterCallerContext)
|
fn address(&mut self, context: InterpreterCallerContext)
|
||||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||||
{
|
{
|
||||||
let return_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
let addr = self.context.address;
|
||||||
self.memory.set(return_ptr, &*self.context.address)?;
|
self.return_address_ptr(
|
||||||
|
context.value_stack.pop_as::<i32>()? as u32,
|
||||||
|
addr,
|
||||||
|
)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn origin(&mut self, context: InterpreterCallerContext)
|
fn origin(&mut self, context: InterpreterCallerContext)
|
||||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||||
{
|
{
|
||||||
let return_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
let origin = self.context.origin;
|
||||||
self.memory.set(return_ptr, &*self.context.origin)?;
|
self.return_address_ptr(
|
||||||
|
context.value_stack.pop_as::<i32>()? as u32,
|
||||||
|
origin,
|
||||||
|
)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn value(&mut self, context: InterpreterCallerContext)
|
fn value(&mut self, context: InterpreterCallerContext)
|
||||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||||
{
|
{
|
||||||
let return_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
let value = self.context.value;
|
||||||
let value: H256 = self.context.value.clone().into();
|
self.return_u256_ptr(
|
||||||
self.memory.set(return_ptr, &*value)?;
|
context.value_stack.pop_as::<i32>()? as u32,
|
||||||
|
value,
|
||||||
|
)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -610,22 +693,28 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
|||||||
fn difficulty(&mut self, context: InterpreterCallerContext)
|
fn difficulty(&mut self, context: InterpreterCallerContext)
|
||||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||||
{
|
{
|
||||||
let return_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
let difficulty = self.ext.env_info().difficulty;
|
||||||
let difficulty: H256 = self.ext.env_info().difficulty.into();
|
self.return_u256_ptr(
|
||||||
self.memory.set(return_ptr, &*difficulty)?;
|
context.value_stack.pop_as::<i32>()? as u32,
|
||||||
|
difficulty,
|
||||||
|
)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ext_gas_limit(&mut self, context: InterpreterCallerContext)
|
fn ext_gas_limit(&mut self, context: InterpreterCallerContext)
|
||||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||||
{
|
{
|
||||||
let return_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
let gas_limit = self.ext.env_info().gas_limit;
|
||||||
let gas_limit: H256 = self.ext.env_info().gas_limit.into();
|
self.return_u256_ptr(
|
||||||
self.memory.set(return_ptr, &*gas_limit)?;
|
context.value_stack.pop_as::<i32>()? as u32,
|
||||||
|
gas_limit,
|
||||||
|
)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn return_i64(&mut self, val: i64) -> Result<Option<interpreter::RuntimeValue>, InterpreterError> {
|
fn return_i64(&mut self, val: i64) -> Result<Option<interpreter::RuntimeValue>, InterpreterError> {
|
||||||
|
self.charge(|schedule| schedule.wasm.static_u64 as u64)?;
|
||||||
|
|
||||||
let uval = val as u64;
|
let uval = val as u64;
|
||||||
let hi = (uval >> 32) as i32;
|
let hi = (uval >> 32) as i32;
|
||||||
let lo = (uval << 32 >> 32) as i32;
|
let lo = (uval << 32 >> 32) as i32;
|
||||||
@ -656,6 +745,14 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn gas_rules(&self) -> &rules::Set {
|
||||||
|
&self.gas_rules
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ext(&mut self) -> &mut vm::Ext {
|
||||||
|
self.ext
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> interpreter::UserFunctionExecutor<UserTrap> for Runtime<'a, 'b> {
|
impl<'a, 'b> interpreter::UserFunctionExecutor<UserTrap> for Runtime<'a, 'b> {
|
||||||
|
@ -60,7 +60,7 @@ fn empty() {
|
|||||||
test_finalize(interpreter.exec(params, &mut ext)).unwrap()
|
test_finalize(interpreter.exec(params, &mut ext)).unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(99_992));
|
assert_eq!(gas_left, U256::from(99_976));
|
||||||
}
|
}
|
||||||
|
|
||||||
// This test checks if the contract deserializes payload header properly.
|
// This test checks if the contract deserializes payload header properly.
|
||||||
@ -68,6 +68,8 @@ fn empty() {
|
|||||||
// logger.wasm writes all these provided fixed header fields to some arbitrary storage keys.
|
// logger.wasm writes all these provided fixed header fields to some arbitrary storage keys.
|
||||||
#[test]
|
#[test]
|
||||||
fn logger() {
|
fn logger() {
|
||||||
|
::ethcore_logger::init_log();
|
||||||
|
|
||||||
let code = load_sample!("logger.wasm");
|
let code = load_sample!("logger.wasm");
|
||||||
let address: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
|
let address: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
|
||||||
let sender: Address = "0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d".parse().unwrap();
|
let sender: Address = "0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d".parse().unwrap();
|
||||||
@ -87,8 +89,7 @@ fn logger() {
|
|||||||
test_finalize(interpreter.exec(params, &mut ext)).unwrap()
|
test_finalize(interpreter.exec(params, &mut ext)).unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("ext.store: {:?}", ext.store);
|
assert_eq!(gas_left, U256::from(15_177));
|
||||||
assert_eq!(gas_left, U256::from(98_731));
|
|
||||||
let address_val: H256 = address.into();
|
let address_val: H256 = address.into();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ext.store.get(&"0100000000000000000000000000000000000000000000000000000000000000".parse().unwrap()).expect("storage key to exist"),
|
ext.store.get(&"0100000000000000000000000000000000000000000000000000000000000000".parse().unwrap()).expect("storage key to exist"),
|
||||||
@ -141,7 +142,7 @@ fn identity() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(99_812));
|
assert_eq!(gas_left, U256::from(99_695));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Address::from_slice(&result),
|
Address::from_slice(&result),
|
||||||
@ -175,7 +176,7 @@ fn dispersion() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(99_474));
|
assert_eq!(gas_left, U256::from(96_543));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result,
|
result,
|
||||||
@ -204,7 +205,7 @@ fn suicide_not() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(99_691));
|
assert_eq!(gas_left, U256::from(96_822));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result,
|
result,
|
||||||
@ -214,6 +215,8 @@ fn suicide_not() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn suicide() {
|
fn suicide() {
|
||||||
|
::ethcore_logger::init_log();
|
||||||
|
|
||||||
let code = load_sample!("suicidal.wasm");
|
let code = load_sample!("suicidal.wasm");
|
||||||
|
|
||||||
let refund: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap();
|
let refund: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap();
|
||||||
@ -238,7 +241,7 @@ fn suicide() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(99_490));
|
assert_eq!(gas_left, U256::from(96_580));
|
||||||
assert!(ext.suicides.contains(&refund));
|
assert!(ext.suicides.contains(&refund));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,7 +272,7 @@ fn create() {
|
|||||||
assert!(ext.calls.contains(
|
assert!(ext.calls.contains(
|
||||||
&FakeCall {
|
&FakeCall {
|
||||||
call_type: FakeCallType::Create,
|
call_type: FakeCallType::Create,
|
||||||
gas: U256::from(99_144),
|
gas: U256::from(62_324),
|
||||||
sender_address: None,
|
sender_address: None,
|
||||||
receive_address: None,
|
receive_address: None,
|
||||||
value: Some(1_000_000_000.into()),
|
value: Some(1_000_000_000.into()),
|
||||||
@ -277,7 +280,7 @@ fn create() {
|
|||||||
code_address: None,
|
code_address: None,
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
assert_eq!(gas_left, U256::from(99_113));
|
assert_eq!(gas_left, U256::from(62_289));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -311,7 +314,7 @@ fn call_code() {
|
|||||||
assert!(ext.calls.contains(
|
assert!(ext.calls.contains(
|
||||||
&FakeCall {
|
&FakeCall {
|
||||||
call_type: FakeCallType::Call,
|
call_type: FakeCallType::Call,
|
||||||
gas: U256::from(99_138),
|
gas: U256::from(95_585),
|
||||||
sender_address: Some(sender),
|
sender_address: Some(sender),
|
||||||
receive_address: Some(receiver),
|
receive_address: Some(receiver),
|
||||||
value: None,
|
value: None,
|
||||||
@ -319,7 +322,7 @@ fn call_code() {
|
|||||||
code_address: Some("0d13710000000000000000000000000000000000".parse().unwrap()),
|
code_address: Some("0d13710000000000000000000000000000000000".parse().unwrap()),
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
assert_eq!(gas_left, U256::from(94_269));
|
assert_eq!(gas_left, U256::from(90_665));
|
||||||
|
|
||||||
// siphash result
|
// siphash result
|
||||||
let res = LittleEndian::read_u32(&result[..]);
|
let res = LittleEndian::read_u32(&result[..]);
|
||||||
@ -356,7 +359,7 @@ fn call_static() {
|
|||||||
assert!(ext.calls.contains(
|
assert!(ext.calls.contains(
|
||||||
&FakeCall {
|
&FakeCall {
|
||||||
call_type: FakeCallType::Call,
|
call_type: FakeCallType::Call,
|
||||||
gas: U256::from(99_138),
|
gas: U256::from(95_585),
|
||||||
sender_address: Some(sender),
|
sender_address: Some(sender),
|
||||||
receive_address: Some(receiver),
|
receive_address: Some(receiver),
|
||||||
value: None,
|
value: None,
|
||||||
@ -364,7 +367,7 @@ fn call_static() {
|
|||||||
code_address: Some("13077bfb00000000000000000000000000000000".parse().unwrap()),
|
code_address: Some("13077bfb00000000000000000000000000000000".parse().unwrap()),
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
assert_eq!(gas_left, U256::from(94_269));
|
assert_eq!(gas_left, U256::from(90_665));
|
||||||
|
|
||||||
// siphash result
|
// siphash result
|
||||||
let res = LittleEndian::read_u32(&result[..]);
|
let res = LittleEndian::read_u32(&result[..]);
|
||||||
@ -390,7 +393,7 @@ fn realloc() {
|
|||||||
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
assert_eq!(gas_left, U256::from(99_614));
|
assert_eq!(gas_left, U256::from(96_811));
|
||||||
assert_eq!(result, vec![0u8; 2]);
|
assert_eq!(result, vec![0u8; 2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,7 +419,7 @@ fn storage_read() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(99_695));
|
assert_eq!(gas_left, U256::from(96_645));
|
||||||
assert_eq!(Address::from(&result[12..32]), address);
|
assert_eq!(Address::from(&result[12..32]), address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -443,7 +446,7 @@ fn keccak() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
|
assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
|
||||||
assert_eq!(gas_left, U256::from(84_026));
|
assert_eq!(gas_left, U256::from(80_452));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -497,7 +500,7 @@ fn math_add() {
|
|||||||
}
|
}
|
||||||
).expect("Interpreter to execute without any errors");
|
).expect("Interpreter to execute without any errors");
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(98_241));
|
assert_eq!(gas_left, U256::from(94_666));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
U256::from_dec_str("1888888888888888888888888888887").unwrap(),
|
U256::from_dec_str("1888888888888888888888888888887").unwrap(),
|
||||||
(&result[..]).into()
|
(&result[..]).into()
|
||||||
@ -519,7 +522,7 @@ fn math_mul() {
|
|||||||
}
|
}
|
||||||
).expect("Interpreter to execute without any errors");
|
).expect("Interpreter to execute without any errors");
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(97_390));
|
assert_eq!(gas_left, U256::from(93_719));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
U256::from_dec_str("888888888888888888888888888887111111111111111111111111111112").unwrap(),
|
U256::from_dec_str("888888888888888888888888888887111111111111111111111111111112").unwrap(),
|
||||||
(&result[..]).into()
|
(&result[..]).into()
|
||||||
@ -541,7 +544,7 @@ fn math_sub() {
|
|||||||
}
|
}
|
||||||
).expect("Interpreter to execute without any errors");
|
).expect("Interpreter to execute without any errors");
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(98_285));
|
assert_eq!(gas_left, U256::from(94_718));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
U256::from_dec_str("111111111111111111111111111111").unwrap(),
|
U256::from_dec_str("111111111111111111111111111111").unwrap(),
|
||||||
(&result[..]).into()
|
(&result[..]).into()
|
||||||
@ -580,7 +583,7 @@ fn math_div() {
|
|||||||
}
|
}
|
||||||
).expect("Interpreter to execute without any errors");
|
).expect("Interpreter to execute without any errors");
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(91_574));
|
assert_eq!(gas_left, U256::from(86_996));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
U256::from_dec_str("1125000").unwrap(),
|
U256::from_dec_str("1125000").unwrap(),
|
||||||
(&result[..]).into()
|
(&result[..]).into()
|
||||||
@ -672,5 +675,5 @@ fn externs() {
|
|||||||
"Gas limit requested and returned does not match"
|
"Gas limit requested and returned does not match"
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(96_284));
|
assert_eq!(gas_left, U256::from(91_857));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user