Reformat the source code
This commit is contained in:
@@ -19,189 +19,111 @@
|
||||
use std::cell::RefCell;
|
||||
use vm::WasmCosts;
|
||||
use wasmi::{
|
||||
self, Signature, Error, FuncRef, FuncInstance, MemoryDescriptor,
|
||||
MemoryRef, MemoryInstance, memory_units,
|
||||
self, memory_units, Error, FuncInstance, FuncRef, MemoryDescriptor, MemoryInstance, MemoryRef,
|
||||
Signature,
|
||||
};
|
||||
|
||||
/// Internal ids all functions runtime supports. This is just a glue for wasmi interpreter
|
||||
/// that lacks high-level api and later will be factored out
|
||||
pub mod ids {
|
||||
pub const STORAGE_WRITE_FUNC: usize = 0;
|
||||
pub const STORAGE_READ_FUNC: usize = 10;
|
||||
pub const RET_FUNC: usize = 20;
|
||||
pub const GAS_FUNC: usize = 30;
|
||||
pub const FETCH_INPUT_FUNC: usize = 40;
|
||||
pub const INPUT_LENGTH_FUNC: usize = 50;
|
||||
pub const CCALL_FUNC: usize = 60;
|
||||
pub const SCALL_FUNC: usize = 70;
|
||||
pub const DCALL_FUNC: usize = 80;
|
||||
pub const VALUE_FUNC: usize = 90;
|
||||
pub const CREATE_FUNC: usize = 100;
|
||||
pub const SUICIDE_FUNC: usize = 110;
|
||||
pub const BLOCKHASH_FUNC: usize = 120;
|
||||
pub const BLOCKNUMBER_FUNC: usize = 130;
|
||||
pub const COINBASE_FUNC: usize = 140;
|
||||
pub const DIFFICULTY_FUNC: usize = 150;
|
||||
pub const GASLIMIT_FUNC: usize = 160;
|
||||
pub const TIMESTAMP_FUNC: usize = 170;
|
||||
pub const ADDRESS_FUNC: usize = 180;
|
||||
pub const SENDER_FUNC: usize = 190;
|
||||
pub const ORIGIN_FUNC: usize = 200;
|
||||
pub const ELOG_FUNC: usize = 210;
|
||||
pub const CREATE2_FUNC: usize = 220;
|
||||
pub const GASLEFT_FUNC: usize = 230;
|
||||
pub const STORAGE_WRITE_FUNC: usize = 0;
|
||||
pub const STORAGE_READ_FUNC: usize = 10;
|
||||
pub const RET_FUNC: usize = 20;
|
||||
pub const GAS_FUNC: usize = 30;
|
||||
pub const FETCH_INPUT_FUNC: usize = 40;
|
||||
pub const INPUT_LENGTH_FUNC: usize = 50;
|
||||
pub const CCALL_FUNC: usize = 60;
|
||||
pub const SCALL_FUNC: usize = 70;
|
||||
pub const DCALL_FUNC: usize = 80;
|
||||
pub const VALUE_FUNC: usize = 90;
|
||||
pub const CREATE_FUNC: usize = 100;
|
||||
pub const SUICIDE_FUNC: usize = 110;
|
||||
pub const BLOCKHASH_FUNC: usize = 120;
|
||||
pub const BLOCKNUMBER_FUNC: usize = 130;
|
||||
pub const COINBASE_FUNC: usize = 140;
|
||||
pub const DIFFICULTY_FUNC: usize = 150;
|
||||
pub const GASLIMIT_FUNC: usize = 160;
|
||||
pub const TIMESTAMP_FUNC: usize = 170;
|
||||
pub const ADDRESS_FUNC: usize = 180;
|
||||
pub const SENDER_FUNC: usize = 190;
|
||||
pub const ORIGIN_FUNC: usize = 200;
|
||||
pub const ELOG_FUNC: usize = 210;
|
||||
pub const CREATE2_FUNC: usize = 220;
|
||||
pub const GASLEFT_FUNC: usize = 230;
|
||||
|
||||
pub const PANIC_FUNC: usize = 1000;
|
||||
pub const DEBUG_FUNC: usize = 1010;
|
||||
pub const PANIC_FUNC: usize = 1000;
|
||||
pub const DEBUG_FUNC: usize = 1010;
|
||||
}
|
||||
|
||||
/// Signatures of all functions runtime supports. The actual dispatch happens at
|
||||
/// impl runtime::Runtime methods.
|
||||
pub mod signatures {
|
||||
use wasmi::{self, ValueType};
|
||||
use wasmi::ValueType::*;
|
||||
use wasmi::{self, ValueType, ValueType::*};
|
||||
|
||||
pub struct StaticSignature(pub &'static [ValueType], pub Option<ValueType>);
|
||||
pub struct StaticSignature(pub &'static [ValueType], pub Option<ValueType>);
|
||||
|
||||
pub const STORAGE_READ: StaticSignature = StaticSignature(
|
||||
&[I32, I32],
|
||||
None,
|
||||
);
|
||||
pub const STORAGE_READ: StaticSignature = StaticSignature(&[I32, I32], None);
|
||||
|
||||
pub const STORAGE_WRITE: StaticSignature = StaticSignature(
|
||||
&[I32, I32],
|
||||
None,
|
||||
);
|
||||
pub const STORAGE_WRITE: StaticSignature = StaticSignature(&[I32, I32], None);
|
||||
|
||||
pub const RET: StaticSignature = StaticSignature(
|
||||
&[I32, I32],
|
||||
None,
|
||||
);
|
||||
pub const RET: StaticSignature = StaticSignature(&[I32, I32], None);
|
||||
|
||||
pub const GAS: StaticSignature = StaticSignature(
|
||||
&[I32],
|
||||
None,
|
||||
);
|
||||
pub const GAS: StaticSignature = StaticSignature(&[I32], None);
|
||||
|
||||
pub const FETCH_INPUT: StaticSignature = StaticSignature(
|
||||
&[I32],
|
||||
None,
|
||||
);
|
||||
pub const FETCH_INPUT: StaticSignature = StaticSignature(&[I32], None);
|
||||
|
||||
pub const INPUT_LENGTH: StaticSignature = StaticSignature(
|
||||
&[],
|
||||
Some(I32),
|
||||
);
|
||||
pub const INPUT_LENGTH: StaticSignature = StaticSignature(&[], Some(I32));
|
||||
|
||||
pub const CCALL: StaticSignature = StaticSignature(
|
||||
&[I64, I32, I32, I32, I32, I32, I32],
|
||||
Some(I32),
|
||||
);
|
||||
pub const CCALL: StaticSignature =
|
||||
StaticSignature(&[I64, I32, I32, I32, I32, I32, I32], Some(I32));
|
||||
|
||||
pub const DCALL: StaticSignature = StaticSignature(
|
||||
&[I64, I32, I32, I32, I32, I32],
|
||||
Some(I32),
|
||||
);
|
||||
pub const DCALL: StaticSignature = StaticSignature(&[I64, I32, I32, I32, I32, I32], Some(I32));
|
||||
|
||||
pub const SCALL: StaticSignature = StaticSignature(
|
||||
&[I64, I32, I32, I32, I32, I32],
|
||||
Some(I32),
|
||||
);
|
||||
pub const SCALL: StaticSignature = StaticSignature(&[I64, I32, I32, I32, I32, I32], Some(I32));
|
||||
|
||||
pub const PANIC: StaticSignature = StaticSignature(
|
||||
&[I32, I32],
|
||||
None,
|
||||
);
|
||||
pub const PANIC: StaticSignature = StaticSignature(&[I32, I32], None);
|
||||
|
||||
pub const DEBUG: StaticSignature = StaticSignature(
|
||||
&[I32, I32],
|
||||
None,
|
||||
);
|
||||
pub const DEBUG: StaticSignature = StaticSignature(&[I32, I32], None);
|
||||
|
||||
pub const VALUE: StaticSignature = StaticSignature(
|
||||
&[I32],
|
||||
None,
|
||||
);
|
||||
pub const VALUE: StaticSignature = StaticSignature(&[I32], None);
|
||||
|
||||
pub const CREATE: StaticSignature = StaticSignature(
|
||||
&[I32, I32, I32, I32],
|
||||
Some(I32),
|
||||
);
|
||||
pub const CREATE: StaticSignature = StaticSignature(&[I32, I32, I32, I32], Some(I32));
|
||||
|
||||
pub const CREATE2: StaticSignature = StaticSignature(
|
||||
&[I32, I32, I32, I32, I32],
|
||||
Some(I32),
|
||||
);
|
||||
pub const CREATE2: StaticSignature = StaticSignature(&[I32, I32, I32, I32, I32], Some(I32));
|
||||
|
||||
pub const SUICIDE: StaticSignature = StaticSignature(
|
||||
&[I32],
|
||||
None,
|
||||
);
|
||||
pub const SUICIDE: StaticSignature = StaticSignature(&[I32], None);
|
||||
|
||||
pub const BLOCKHASH: StaticSignature = StaticSignature(
|
||||
&[I64, I32],
|
||||
None,
|
||||
);
|
||||
pub const BLOCKHASH: StaticSignature = StaticSignature(&[I64, I32], None);
|
||||
|
||||
pub const BLOCKNUMBER: StaticSignature = StaticSignature(
|
||||
&[],
|
||||
Some(I64),
|
||||
);
|
||||
pub const BLOCKNUMBER: StaticSignature = StaticSignature(&[], Some(I64));
|
||||
|
||||
pub const COINBASE: StaticSignature = StaticSignature(
|
||||
&[I32],
|
||||
None,
|
||||
);
|
||||
pub const COINBASE: StaticSignature = StaticSignature(&[I32], None);
|
||||
|
||||
pub const DIFFICULTY: StaticSignature = StaticSignature(
|
||||
&[I32],
|
||||
None,
|
||||
);
|
||||
pub const DIFFICULTY: StaticSignature = StaticSignature(&[I32], None);
|
||||
|
||||
pub const GASLEFT: StaticSignature = StaticSignature(
|
||||
&[],
|
||||
Some(I64),
|
||||
);
|
||||
pub const GASLEFT: StaticSignature = StaticSignature(&[], Some(I64));
|
||||
|
||||
pub const GASLIMIT: StaticSignature = StaticSignature(
|
||||
&[I32],
|
||||
None,
|
||||
);
|
||||
pub const GASLIMIT: StaticSignature = StaticSignature(&[I32], None);
|
||||
|
||||
pub const TIMESTAMP: StaticSignature = StaticSignature(
|
||||
&[],
|
||||
Some(I64),
|
||||
);
|
||||
pub const TIMESTAMP: StaticSignature = StaticSignature(&[], Some(I64));
|
||||
|
||||
pub const ADDRESS: StaticSignature = StaticSignature(
|
||||
&[I32],
|
||||
None,
|
||||
);
|
||||
pub const ADDRESS: StaticSignature = StaticSignature(&[I32], None);
|
||||
|
||||
pub const SENDER: StaticSignature = StaticSignature(
|
||||
&[I32],
|
||||
None,
|
||||
);
|
||||
pub const SENDER: StaticSignature = StaticSignature(&[I32], None);
|
||||
|
||||
pub const ORIGIN: StaticSignature = StaticSignature(
|
||||
&[I32],
|
||||
None,
|
||||
);
|
||||
pub const ORIGIN: StaticSignature = StaticSignature(&[I32], None);
|
||||
|
||||
pub const ELOG: StaticSignature = StaticSignature(
|
||||
&[I32, I32, I32, I32],
|
||||
None,
|
||||
);
|
||||
pub const ELOG: StaticSignature = StaticSignature(&[I32, I32, I32, I32], None);
|
||||
|
||||
impl Into<wasmi::Signature> for StaticSignature {
|
||||
fn into(self) -> wasmi::Signature {
|
||||
wasmi::Signature::new(self.0, self.1)
|
||||
}
|
||||
}
|
||||
impl Into<wasmi::Signature> for StaticSignature {
|
||||
fn into(self) -> wasmi::Signature {
|
||||
wasmi::Signature::new(self.0, self.1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn host(signature: signatures::StaticSignature, idx: usize) -> FuncRef {
|
||||
FuncInstance::alloc_host(signature.into(), idx)
|
||||
FuncInstance::alloc_host(signature.into(), idx)
|
||||
}
|
||||
|
||||
/// Import resolver for wasmi
|
||||
@@ -209,110 +131,117 @@ fn host(signature: signatures::StaticSignature, idx: usize) -> FuncRef {
|
||||
/// entries.
|
||||
/// Also manages initial memory request from the runtime.
|
||||
pub struct ImportResolver {
|
||||
max_memory: u32,
|
||||
memory: RefCell<Option<MemoryRef>>,
|
||||
max_memory: u32,
|
||||
memory: RefCell<Option<MemoryRef>>,
|
||||
|
||||
have_create2: bool,
|
||||
have_gasleft: bool,
|
||||
have_create2: bool,
|
||||
have_gasleft: bool,
|
||||
}
|
||||
|
||||
impl ImportResolver {
|
||||
/// New import resolver with specifed maximum amount of inital memory (in wasm pages = 64kb)
|
||||
pub fn with_limit(max_memory: u32, schedule: &WasmCosts) -> ImportResolver {
|
||||
ImportResolver {
|
||||
max_memory: max_memory,
|
||||
memory: RefCell::new(None),
|
||||
/// New import resolver with specifed maximum amount of inital memory (in wasm pages = 64kb)
|
||||
pub fn with_limit(max_memory: u32, schedule: &WasmCosts) -> ImportResolver {
|
||||
ImportResolver {
|
||||
max_memory: max_memory,
|
||||
memory: RefCell::new(None),
|
||||
|
||||
have_create2: schedule.have_create2,
|
||||
have_gasleft: schedule.have_gasleft,
|
||||
}
|
||||
}
|
||||
have_create2: schedule.have_create2,
|
||||
have_gasleft: schedule.have_gasleft,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns memory that was instantiated during the contract module
|
||||
/// start. If contract does not use memory at all, the dummy memory of length (0, 0)
|
||||
/// will be created instead. So this method always returns memory instance
|
||||
/// unless errored.
|
||||
pub fn memory_ref(&self) -> MemoryRef {
|
||||
{
|
||||
let mut mem_ref = self.memory.borrow_mut();
|
||||
if mem_ref.is_none() {
|
||||
*mem_ref = Some(
|
||||
MemoryInstance::alloc(
|
||||
memory_units::Pages(0),
|
||||
Some(memory_units::Pages(0)),
|
||||
).expect("Memory allocation (0, 0) should not fail; qed")
|
||||
);
|
||||
}
|
||||
}
|
||||
/// Returns memory that was instantiated during the contract module
|
||||
/// start. If contract does not use memory at all, the dummy memory of length (0, 0)
|
||||
/// will be created instead. So this method always returns memory instance
|
||||
/// unless errored.
|
||||
pub fn memory_ref(&self) -> MemoryRef {
|
||||
{
|
||||
let mut mem_ref = self.memory.borrow_mut();
|
||||
if mem_ref.is_none() {
|
||||
*mem_ref = Some(
|
||||
MemoryInstance::alloc(memory_units::Pages(0), Some(memory_units::Pages(0)))
|
||||
.expect("Memory allocation (0, 0) should not fail; qed"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
self.memory.borrow().clone().expect("it is either existed or was created as (0, 0) above; qed")
|
||||
}
|
||||
self.memory
|
||||
.borrow()
|
||||
.clone()
|
||||
.expect("it is either existed or was created as (0, 0) above; qed")
|
||||
}
|
||||
|
||||
/// Returns memory size module initially requested
|
||||
pub fn memory_size(&self) -> Result<u32, Error> {
|
||||
Ok(self.memory_ref().current_size().0 as u32)
|
||||
}
|
||||
/// Returns memory size module initially requested
|
||||
pub fn memory_size(&self) -> Result<u32, Error> {
|
||||
Ok(self.memory_ref().current_size().0 as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl wasmi::ModuleImportResolver for ImportResolver {
|
||||
fn resolve_func(&self, field_name: &str, _signature: &Signature) -> Result<FuncRef, Error> {
|
||||
let func_ref = match field_name {
|
||||
"storage_read" => host(signatures::STORAGE_READ, ids::STORAGE_READ_FUNC),
|
||||
"storage_write" => host(signatures::STORAGE_WRITE, ids::STORAGE_WRITE_FUNC),
|
||||
"ret" => host(signatures::RET, ids::RET_FUNC),
|
||||
"gas" => host(signatures::GAS, ids::GAS_FUNC),
|
||||
"input_length" => host(signatures::INPUT_LENGTH, ids::INPUT_LENGTH_FUNC),
|
||||
"fetch_input" => host(signatures::FETCH_INPUT, ids::FETCH_INPUT_FUNC),
|
||||
"panic" => host(signatures::PANIC, ids::PANIC_FUNC),
|
||||
"debug" => host(signatures::DEBUG, ids::DEBUG_FUNC),
|
||||
"ccall" => host(signatures::CCALL, ids::CCALL_FUNC),
|
||||
"dcall" => host(signatures::DCALL, ids::DCALL_FUNC),
|
||||
"scall" => host(signatures::SCALL, ids::SCALL_FUNC),
|
||||
"value" => host(signatures::VALUE, ids::VALUE_FUNC),
|
||||
"create" => host(signatures::CREATE, ids::CREATE_FUNC),
|
||||
"suicide" => host(signatures::SUICIDE, ids::SUICIDE_FUNC),
|
||||
"blockhash" => host(signatures::BLOCKHASH, ids::BLOCKHASH_FUNC),
|
||||
"blocknumber" => host(signatures::BLOCKNUMBER, ids::BLOCKNUMBER_FUNC),
|
||||
"coinbase" => host(signatures::COINBASE, ids::COINBASE_FUNC),
|
||||
"difficulty" => host(signatures::DIFFICULTY, ids::DIFFICULTY_FUNC),
|
||||
"gaslimit" => host(signatures::GASLIMIT, ids::GASLIMIT_FUNC),
|
||||
"timestamp" => host(signatures::TIMESTAMP, ids::TIMESTAMP_FUNC),
|
||||
"address" => host(signatures::ADDRESS, ids::ADDRESS_FUNC),
|
||||
"sender" => host(signatures::SENDER, ids::SENDER_FUNC),
|
||||
"origin" => host(signatures::ORIGIN, ids::ORIGIN_FUNC),
|
||||
"elog" => host(signatures::ELOG, ids::ELOG_FUNC),
|
||||
"create2" if self.have_create2 => host(signatures::CREATE2, ids::CREATE2_FUNC),
|
||||
"gasleft" if self.have_gasleft => host(signatures::GASLEFT, ids::GASLEFT_FUNC),
|
||||
_ => {
|
||||
return Err(wasmi::Error::Instantiation(
|
||||
format!("Export {} not found", field_name),
|
||||
))
|
||||
}
|
||||
};
|
||||
fn resolve_func(&self, field_name: &str, _signature: &Signature) -> Result<FuncRef, Error> {
|
||||
let func_ref = match field_name {
|
||||
"storage_read" => host(signatures::STORAGE_READ, ids::STORAGE_READ_FUNC),
|
||||
"storage_write" => host(signatures::STORAGE_WRITE, ids::STORAGE_WRITE_FUNC),
|
||||
"ret" => host(signatures::RET, ids::RET_FUNC),
|
||||
"gas" => host(signatures::GAS, ids::GAS_FUNC),
|
||||
"input_length" => host(signatures::INPUT_LENGTH, ids::INPUT_LENGTH_FUNC),
|
||||
"fetch_input" => host(signatures::FETCH_INPUT, ids::FETCH_INPUT_FUNC),
|
||||
"panic" => host(signatures::PANIC, ids::PANIC_FUNC),
|
||||
"debug" => host(signatures::DEBUG, ids::DEBUG_FUNC),
|
||||
"ccall" => host(signatures::CCALL, ids::CCALL_FUNC),
|
||||
"dcall" => host(signatures::DCALL, ids::DCALL_FUNC),
|
||||
"scall" => host(signatures::SCALL, ids::SCALL_FUNC),
|
||||
"value" => host(signatures::VALUE, ids::VALUE_FUNC),
|
||||
"create" => host(signatures::CREATE, ids::CREATE_FUNC),
|
||||
"suicide" => host(signatures::SUICIDE, ids::SUICIDE_FUNC),
|
||||
"blockhash" => host(signatures::BLOCKHASH, ids::BLOCKHASH_FUNC),
|
||||
"blocknumber" => host(signatures::BLOCKNUMBER, ids::BLOCKNUMBER_FUNC),
|
||||
"coinbase" => host(signatures::COINBASE, ids::COINBASE_FUNC),
|
||||
"difficulty" => host(signatures::DIFFICULTY, ids::DIFFICULTY_FUNC),
|
||||
"gaslimit" => host(signatures::GASLIMIT, ids::GASLIMIT_FUNC),
|
||||
"timestamp" => host(signatures::TIMESTAMP, ids::TIMESTAMP_FUNC),
|
||||
"address" => host(signatures::ADDRESS, ids::ADDRESS_FUNC),
|
||||
"sender" => host(signatures::SENDER, ids::SENDER_FUNC),
|
||||
"origin" => host(signatures::ORIGIN, ids::ORIGIN_FUNC),
|
||||
"elog" => host(signatures::ELOG, ids::ELOG_FUNC),
|
||||
"create2" if self.have_create2 => host(signatures::CREATE2, ids::CREATE2_FUNC),
|
||||
"gasleft" if self.have_gasleft => host(signatures::GASLEFT, ids::GASLEFT_FUNC),
|
||||
_ => {
|
||||
return Err(wasmi::Error::Instantiation(format!(
|
||||
"Export {} not found",
|
||||
field_name
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
Ok(func_ref)
|
||||
}
|
||||
Ok(func_ref)
|
||||
}
|
||||
|
||||
fn resolve_memory(
|
||||
&self,
|
||||
field_name: &str,
|
||||
descriptor: &MemoryDescriptor,
|
||||
) -> Result<MemoryRef, Error> {
|
||||
if field_name == "memory" {
|
||||
let effective_max = descriptor.maximum().unwrap_or(self.max_memory + 1);
|
||||
if descriptor.initial() > self.max_memory || effective_max > self.max_memory
|
||||
{
|
||||
Err(Error::Instantiation("Module requested too much memory".to_owned()))
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
} else {
|
||||
Err(Error::Instantiation("Memory imported under unknown name".to_owned()))
|
||||
}
|
||||
}
|
||||
fn resolve_memory(
|
||||
&self,
|
||||
field_name: &str,
|
||||
descriptor: &MemoryDescriptor,
|
||||
) -> Result<MemoryRef, Error> {
|
||||
if field_name == "memory" {
|
||||
let effective_max = descriptor.maximum().unwrap_or(self.max_memory + 1);
|
||||
if descriptor.initial() > self.max_memory || effective_max > self.max_memory {
|
||||
Err(Error::Instantiation(
|
||||
"Module requested too much memory".to_owned(),
|
||||
))
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
} else {
|
||||
Err(Error::Instantiation(
|
||||
"Memory imported under unknown name".to_owned(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,12 @@
|
||||
|
||||
extern crate byteorder;
|
||||
extern crate ethereum_types;
|
||||
#[macro_use] extern crate log;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate libc;
|
||||
extern crate parity_wasm;
|
||||
extern crate vm;
|
||||
extern crate pwasm_utils as wasm_utils;
|
||||
extern crate vm;
|
||||
extern crate wasmi;
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -36,8 +37,7 @@ mod runtime;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
|
||||
use vm::{GasLeft, ReturnData, ActionParams};
|
||||
use vm::{ActionParams, GasLeft, ReturnData};
|
||||
use wasmi::{Error as InterpreterError, Trap};
|
||||
|
||||
use runtime::{Runtime, RuntimeContext};
|
||||
@@ -47,155 +47,164 @@ use ethereum_types::U256;
|
||||
/// Wrapped interpreter error
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Interpreter(InterpreterError),
|
||||
Trap(Trap),
|
||||
Interpreter(InterpreterError),
|
||||
Trap(Trap),
|
||||
}
|
||||
|
||||
impl From<InterpreterError> for Error {
|
||||
fn from(e: InterpreterError) -> Self {
|
||||
Error::Interpreter(e)
|
||||
}
|
||||
fn from(e: InterpreterError) -> Self {
|
||||
Error::Interpreter(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Trap> for Error {
|
||||
fn from(e: Trap) -> Self {
|
||||
Error::Trap(e)
|
||||
}
|
||||
fn from(e: Trap) -> Self {
|
||||
Error::Trap(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for vm::Error {
|
||||
fn from(e: Error) -> Self {
|
||||
match e {
|
||||
Error::Interpreter(e) => vm::Error::Wasm(format!("Wasm runtime error: {:?}", e)),
|
||||
Error::Trap(e) => vm::Error::Wasm(format!("Wasm contract trap: {:?}", e)),
|
||||
}
|
||||
}
|
||||
fn from(e: Error) -> Self {
|
||||
match e {
|
||||
Error::Interpreter(e) => vm::Error::Wasm(format!("Wasm runtime error: {:?}", e)),
|
||||
Error::Trap(e) => vm::Error::Wasm(format!("Wasm contract trap: {:?}", e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Wasm interpreter instance
|
||||
pub struct WasmInterpreter {
|
||||
params: ActionParams,
|
||||
params: ActionParams,
|
||||
}
|
||||
|
||||
impl WasmInterpreter {
|
||||
pub fn new(params: ActionParams) -> Self {
|
||||
WasmInterpreter { params }
|
||||
}
|
||||
pub fn new(params: ActionParams) -> Self {
|
||||
WasmInterpreter { params }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<runtime::Error> for vm::Error {
|
||||
fn from(e: runtime::Error) -> Self {
|
||||
vm::Error::Wasm(format!("Wasm runtime error: {:?}", e))
|
||||
}
|
||||
fn from(e: runtime::Error) -> Self {
|
||||
vm::Error::Wasm(format!("Wasm runtime error: {:?}", e))
|
||||
}
|
||||
}
|
||||
|
||||
enum ExecutionOutcome {
|
||||
Suicide,
|
||||
Return,
|
||||
NotSpecial,
|
||||
Suicide,
|
||||
Return,
|
||||
NotSpecial,
|
||||
}
|
||||
|
||||
impl WasmInterpreter {
|
||||
pub fn run(self: Box<WasmInterpreter>, ext: &mut vm::Ext) -> vm::Result<GasLeft> {
|
||||
let (module, data) = parser::payload(&self.params, ext.schedule().wasm())?;
|
||||
pub fn run(self: Box<WasmInterpreter>, ext: &mut vm::Ext) -> vm::Result<GasLeft> {
|
||||
let (module, data) = parser::payload(&self.params, ext.schedule().wasm())?;
|
||||
|
||||
let loaded_module = wasmi::Module::from_parity_wasm_module(module).map_err(Error::Interpreter)?;
|
||||
let loaded_module =
|
||||
wasmi::Module::from_parity_wasm_module(module).map_err(Error::Interpreter)?;
|
||||
|
||||
let instantiation_resolver = env::ImportResolver::with_limit(16, ext.schedule().wasm());
|
||||
let instantiation_resolver = env::ImportResolver::with_limit(16, ext.schedule().wasm());
|
||||
|
||||
let module_instance = wasmi::ModuleInstance::new(
|
||||
&loaded_module,
|
||||
&wasmi::ImportsBuilder::new().with_resolver("env", &instantiation_resolver)
|
||||
).map_err(Error::Interpreter)?;
|
||||
let module_instance = wasmi::ModuleInstance::new(
|
||||
&loaded_module,
|
||||
&wasmi::ImportsBuilder::new().with_resolver("env", &instantiation_resolver),
|
||||
)
|
||||
.map_err(Error::Interpreter)?;
|
||||
|
||||
let adjusted_gas = self.params.gas * U256::from(ext.schedule().wasm().opcodes_div) /
|
||||
U256::from(ext.schedule().wasm().opcodes_mul);
|
||||
let adjusted_gas = self.params.gas * U256::from(ext.schedule().wasm().opcodes_div)
|
||||
/ U256::from(ext.schedule().wasm().opcodes_mul);
|
||||
|
||||
if adjusted_gas > ::std::u64::MAX.into()
|
||||
{
|
||||
return Err(vm::Error::Wasm("Wasm interpreter cannot run contracts with gas (wasm adjusted) >= 2^64".to_owned()));
|
||||
}
|
||||
if adjusted_gas > ::std::u64::MAX.into() {
|
||||
return Err(vm::Error::Wasm(
|
||||
"Wasm interpreter cannot run contracts with gas (wasm adjusted) >= 2^64".to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
let initial_memory = instantiation_resolver.memory_size().map_err(Error::Interpreter)?;
|
||||
trace!(target: "wasm", "Contract requested {:?} pages of initial memory", initial_memory);
|
||||
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_resolver.memory_ref(),
|
||||
// cannot overflow, checked above
|
||||
adjusted_gas.low_u64(),
|
||||
data.to_vec(),
|
||||
RuntimeContext {
|
||||
address: self.params.address,
|
||||
sender: self.params.sender,
|
||||
origin: self.params.origin,
|
||||
code_address: self.params.code_address,
|
||||
value: self.params.value.value(),
|
||||
},
|
||||
);
|
||||
let (gas_left, result) = {
|
||||
let mut runtime = Runtime::with_params(
|
||||
ext,
|
||||
instantiation_resolver.memory_ref(),
|
||||
// cannot overflow, checked above
|
||||
adjusted_gas.low_u64(),
|
||||
data.to_vec(),
|
||||
RuntimeContext {
|
||||
address: self.params.address,
|
||||
sender: self.params.sender,
|
||||
origin: self.params.origin,
|
||||
code_address: self.params.code_address,
|
||||
value: self.params.value.value(),
|
||||
},
|
||||
);
|
||||
|
||||
// cannot overflow if static_region < 2^16,
|
||||
// initial_memory ∈ [0..2^32)
|
||||
// total_charge <- static_region * 2^32 * 2^16
|
||||
// total_charge ∈ [0..2^64) if static_region ∈ [0..2^16)
|
||||
// qed
|
||||
assert!(runtime.schedule().wasm().initial_mem < 1 << 16);
|
||||
runtime.charge(|s| initial_memory as u64 * s.wasm().initial_mem as u64)?;
|
||||
// cannot overflow if static_region < 2^16,
|
||||
// initial_memory ∈ [0..2^32)
|
||||
// total_charge <- static_region * 2^32 * 2^16
|
||||
// total_charge ∈ [0..2^64) if static_region ∈ [0..2^16)
|
||||
// qed
|
||||
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::Trap)?;
|
||||
let module_instance = module_instance
|
||||
.run_start(&mut runtime)
|
||||
.map_err(Error::Trap)?;
|
||||
|
||||
let invoke_result = module_instance.invoke_export("call", &[], &mut runtime);
|
||||
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");
|
||||
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; },
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
match **runtime_err {
|
||||
runtime::Error::Suicide => {
|
||||
execution_outcome = ExecutionOutcome::Suicide;
|
||||
}
|
||||
runtime::Error::Return => {
|
||||
execution_outcome = ExecutionOutcome::Return;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)));
|
||||
}
|
||||
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(),
|
||||
)
|
||||
};
|
||||
(
|
||||
runtime
|
||||
.gas_left()
|
||||
.expect("Cannot fail since it was not updated since last charge"),
|
||||
runtime.into_result(),
|
||||
)
|
||||
};
|
||||
|
||||
let gas_left =
|
||||
U256::from(gas_left) * U256::from(ext.schedule().wasm().opcodes_mul)
|
||||
/ U256::from(ext.schedule().wasm().opcodes_div);
|
||||
let gas_left = U256::from(gas_left) * U256::from(ext.schedule().wasm().opcodes_mul)
|
||||
/ U256::from(ext.schedule().wasm().opcodes_div);
|
||||
|
||||
if result.is_empty() {
|
||||
trace!(target: "wasm", "Contract execution result is empty.");
|
||||
Ok(GasLeft::Known(gas_left))
|
||||
} else {
|
||||
let len = result.len();
|
||||
Ok(GasLeft::NeedsReturn {
|
||||
gas_left: gas_left,
|
||||
data: ReturnData::new(
|
||||
result,
|
||||
0,
|
||||
len,
|
||||
),
|
||||
apply_state: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
if result.is_empty() {
|
||||
trace!(target: "wasm", "Contract execution result is empty.");
|
||||
Ok(GasLeft::Known(gas_left))
|
||||
} else {
|
||||
let len = result.len();
|
||||
Ok(GasLeft::NeedsReturn {
|
||||
gas_left: gas_left,
|
||||
data: ReturnData::new(result, 0, len),
|
||||
apply_state: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl vm::Exec for WasmInterpreter {
|
||||
fn exec(self: Box<WasmInterpreter>, ext: &mut vm::Ext) -> vm::ExecTrapResult<GasLeft> {
|
||||
Ok(self.run(ext))
|
||||
}
|
||||
fn exec(self: Box<WasmInterpreter>, ext: &mut vm::Ext) -> vm::ExecTrapResult<GasLeft> {
|
||||
Ok(self.run(ext))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,150 +19,150 @@ use std::io::{self, Read};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct PanicPayload {
|
||||
pub msg: Option<String>,
|
||||
pub file: Option<String>,
|
||||
pub line: Option<u32>,
|
||||
pub col: Option<u32>,
|
||||
pub msg: Option<String>,
|
||||
pub file: Option<String>,
|
||||
pub line: Option<u32>,
|
||||
pub col: Option<u32>,
|
||||
}
|
||||
|
||||
fn read_string(rdr: &mut io::Cursor<&[u8]>) -> io::Result<Option<String>> {
|
||||
let string_len = rdr.read_u32::<LittleEndian>()?;
|
||||
let string = if string_len == 0 {
|
||||
None
|
||||
} else {
|
||||
let mut content = vec![0; string_len as usize];
|
||||
rdr.read_exact(&mut content)?;
|
||||
Some(String::from_utf8_lossy(&content).into_owned())
|
||||
};
|
||||
Ok(string)
|
||||
let string_len = rdr.read_u32::<LittleEndian>()?;
|
||||
let string = if string_len == 0 {
|
||||
None
|
||||
} else {
|
||||
let mut content = vec![0; string_len as usize];
|
||||
rdr.read_exact(&mut content)?;
|
||||
Some(String::from_utf8_lossy(&content).into_owned())
|
||||
};
|
||||
Ok(string)
|
||||
}
|
||||
|
||||
pub fn decode(raw: &[u8]) -> PanicPayload {
|
||||
let mut rdr = io::Cursor::new(raw);
|
||||
let msg = read_string(&mut rdr).ok().and_then(|x| x);
|
||||
let file = read_string(&mut rdr).ok().and_then(|x| x);
|
||||
let line = rdr.read_u32::<LittleEndian>().ok();
|
||||
let col = rdr.read_u32::<LittleEndian>().ok();
|
||||
PanicPayload {
|
||||
msg: msg,
|
||||
file: file,
|
||||
line: line,
|
||||
col: col,
|
||||
}
|
||||
let mut rdr = io::Cursor::new(raw);
|
||||
let msg = read_string(&mut rdr).ok().and_then(|x| x);
|
||||
let file = read_string(&mut rdr).ok().and_then(|x| x);
|
||||
let line = rdr.read_u32::<LittleEndian>().ok();
|
||||
let col = rdr.read_u32::<LittleEndian>().ok();
|
||||
PanicPayload {
|
||||
msg: msg,
|
||||
file: file,
|
||||
line: line,
|
||||
col: col,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use byteorder::WriteBytesExt;
|
||||
use super::*;
|
||||
use byteorder::WriteBytesExt;
|
||||
|
||||
fn write_u32(payload: &mut Vec<u8>, val: u32) {
|
||||
payload.write_u32::<LittleEndian>(val).unwrap();
|
||||
}
|
||||
fn write_u32(payload: &mut Vec<u8>, val: u32) {
|
||||
payload.write_u32::<LittleEndian>(val).unwrap();
|
||||
}
|
||||
|
||||
fn write_bytes(payload: &mut Vec<u8>, bytes: &[u8]) {
|
||||
write_u32(payload, bytes.len() as u32);
|
||||
payload.extend(bytes);
|
||||
}
|
||||
fn write_bytes(payload: &mut Vec<u8>, bytes: &[u8]) {
|
||||
write_u32(payload, bytes.len() as u32);
|
||||
payload.extend(bytes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let mut raw = Vec::new();
|
||||
write_bytes(&mut raw, b"msg");
|
||||
write_bytes(&mut raw, b"file");
|
||||
write_u32(&mut raw, 1);
|
||||
write_u32(&mut raw, 2);
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let mut raw = Vec::new();
|
||||
write_bytes(&mut raw, b"msg");
|
||||
write_bytes(&mut raw, b"file");
|
||||
write_u32(&mut raw, 1);
|
||||
write_u32(&mut raw, 2);
|
||||
|
||||
let payload = decode(&raw);
|
||||
let payload = decode(&raw);
|
||||
|
||||
assert_eq!(
|
||||
payload,
|
||||
PanicPayload {
|
||||
msg: Some("msg".to_string()),
|
||||
file: Some("file".to_string()),
|
||||
line: Some(1),
|
||||
col: Some(2),
|
||||
}
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
payload,
|
||||
PanicPayload {
|
||||
msg: Some("msg".to_string()),
|
||||
file: Some("file".to_string()),
|
||||
line: Some(1),
|
||||
col: Some(2),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn only_msg() {
|
||||
let mut raw = Vec::new();
|
||||
write_bytes(&mut raw, b"msg");
|
||||
#[test]
|
||||
fn only_msg() {
|
||||
let mut raw = Vec::new();
|
||||
write_bytes(&mut raw, b"msg");
|
||||
|
||||
let payload = decode(&raw);
|
||||
let payload = decode(&raw);
|
||||
|
||||
assert_eq!(
|
||||
payload,
|
||||
PanicPayload {
|
||||
msg: Some("msg".to_string()),
|
||||
file: None,
|
||||
line: None,
|
||||
col: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
payload,
|
||||
PanicPayload {
|
||||
msg: Some("msg".to_string()),
|
||||
file: None,
|
||||
line: None,
|
||||
col: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_utf8() {
|
||||
let mut raw = Vec::new();
|
||||
write_bytes(&mut raw, b"\xF0\x90\x80msg");
|
||||
write_bytes(&mut raw, b"file");
|
||||
write_u32(&mut raw, 1);
|
||||
write_u32(&mut raw, 2);
|
||||
#[test]
|
||||
fn invalid_utf8() {
|
||||
let mut raw = Vec::new();
|
||||
write_bytes(&mut raw, b"\xF0\x90\x80msg");
|
||||
write_bytes(&mut raw, b"file");
|
||||
write_u32(&mut raw, 1);
|
||||
write_u32(&mut raw, 2);
|
||||
|
||||
let payload = decode(&raw);
|
||||
let payload = decode(&raw);
|
||||
|
||||
assert_eq!(
|
||||
payload,
|
||||
PanicPayload {
|
||||
msg: Some("<EFBFBD>msg".to_string()),
|
||||
file: Some("file".to_string()),
|
||||
line: Some(1),
|
||||
col: Some(2),
|
||||
}
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
payload,
|
||||
PanicPayload {
|
||||
msg: Some("<EFBFBD>msg".to_string()),
|
||||
file: Some("file".to_string()),
|
||||
line: Some(1),
|
||||
col: Some(2),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trailing_data() {
|
||||
let mut raw = Vec::new();
|
||||
write_bytes(&mut raw, b"msg");
|
||||
write_bytes(&mut raw, b"file");
|
||||
write_u32(&mut raw, 1);
|
||||
write_u32(&mut raw, 2);
|
||||
write_u32(&mut raw, 0xdeadbeef);
|
||||
#[test]
|
||||
fn trailing_data() {
|
||||
let mut raw = Vec::new();
|
||||
write_bytes(&mut raw, b"msg");
|
||||
write_bytes(&mut raw, b"file");
|
||||
write_u32(&mut raw, 1);
|
||||
write_u32(&mut raw, 2);
|
||||
write_u32(&mut raw, 0xdeadbeef);
|
||||
|
||||
let payload = decode(&raw);
|
||||
let payload = decode(&raw);
|
||||
|
||||
assert_eq!(
|
||||
payload,
|
||||
PanicPayload {
|
||||
msg: Some("msg".to_string()),
|
||||
file: Some("file".to_string()),
|
||||
line: Some(1),
|
||||
col: Some(2),
|
||||
}
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
payload,
|
||||
PanicPayload {
|
||||
msg: Some("msg".to_string()),
|
||||
file: Some("file".to_string()),
|
||||
line: Some(1),
|
||||
col: Some(2),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_str_is_none() {
|
||||
let mut raw = Vec::new();
|
||||
write_bytes(&mut raw, b"msg");
|
||||
write_bytes(&mut raw, b"");
|
||||
#[test]
|
||||
fn empty_str_is_none() {
|
||||
let mut raw = Vec::new();
|
||||
write_bytes(&mut raw, b"msg");
|
||||
write_bytes(&mut raw, b"");
|
||||
|
||||
let payload = decode(&raw);
|
||||
let payload = decode(&raw);
|
||||
|
||||
assert_eq!(
|
||||
payload,
|
||||
PanicPayload {
|
||||
msg: Some("msg".to_string()),
|
||||
file: None,
|
||||
line: None,
|
||||
col: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
payload,
|
||||
PanicPayload {
|
||||
msg: Some("msg".to_string()),
|
||||
file: None,
|
||||
line: None,
|
||||
col: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,83 +16,95 @@
|
||||
|
||||
//! ActionParams parser for wasm
|
||||
|
||||
use parity_wasm::{
|
||||
elements::{self, Deserialize},
|
||||
peek_size,
|
||||
};
|
||||
use vm;
|
||||
use wasm_utils::{self, rules};
|
||||
use parity_wasm::elements::{self, Deserialize};
|
||||
use parity_wasm::peek_size;
|
||||
|
||||
fn gas_rules(wasm_costs: &vm::WasmCosts) -> rules::Set {
|
||||
rules::Set::new(
|
||||
wasm_costs.regular,
|
||||
{
|
||||
let mut vals = ::std::collections::BTreeMap::new();
|
||||
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()
|
||||
rules::Set::new(wasm_costs.regular, {
|
||||
let mut vals = ::std::collections::BTreeMap::new();
|
||||
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
|
||||
/// loads the module instance from payload and injects gas counter according
|
||||
/// to schedule.
|
||||
pub fn payload<'a>(params: &'a vm::ActionParams, wasm_costs: &vm::WasmCosts)
|
||||
-> Result<(elements::Module, &'a [u8]), vm::Error>
|
||||
{
|
||||
let code = match params.code {
|
||||
Some(ref code) => &code[..],
|
||||
None => { return Err(vm::Error::Wasm("Invalid wasm call".to_owned())); }
|
||||
};
|
||||
pub fn payload<'a>(
|
||||
params: &'a vm::ActionParams,
|
||||
wasm_costs: &vm::WasmCosts,
|
||||
) -> Result<(elements::Module, &'a [u8]), vm::Error> {
|
||||
let code = match params.code {
|
||||
Some(ref code) => &code[..],
|
||||
None => {
|
||||
return Err(vm::Error::Wasm("Invalid wasm call".to_owned()));
|
||||
}
|
||||
};
|
||||
|
||||
let (mut cursor, data_position) = match params.params_type {
|
||||
vm::ParamsType::Embedded => {
|
||||
let module_size = peek_size(&*code);
|
||||
(
|
||||
::std::io::Cursor::new(&code[..module_size]),
|
||||
module_size
|
||||
)
|
||||
},
|
||||
vm::ParamsType::Separate => {
|
||||
(::std::io::Cursor::new(&code[..]), 0)
|
||||
},
|
||||
};
|
||||
let (mut cursor, data_position) = match params.params_type {
|
||||
vm::ParamsType::Embedded => {
|
||||
let module_size = peek_size(&*code);
|
||||
(::std::io::Cursor::new(&code[..module_size]), module_size)
|
||||
}
|
||||
vm::ParamsType::Separate => (::std::io::Cursor::new(&code[..]), 0),
|
||||
};
|
||||
|
||||
let deserialized_module = elements::Module::deserialize(
|
||||
&mut cursor
|
||||
).map_err(|err| {
|
||||
vm::Error::Wasm(format!("Error deserializing contract code ({:?})", err))
|
||||
})?;
|
||||
let deserialized_module = elements::Module::deserialize(&mut cursor)
|
||||
.map_err(|err| vm::Error::Wasm(format!("Error deserializing contract code ({:?})", err)))?;
|
||||
|
||||
if deserialized_module.memory_section().map_or(false, |ms| ms.entries().len() > 0) {
|
||||
// According to WebAssembly spec, internal memory is hidden from embedder and should not
|
||||
// be interacted with. So we disable this kind of modules at decoding level.
|
||||
return Err(vm::Error::Wasm(format!("Malformed wasm module: internal memory")));
|
||||
}
|
||||
if deserialized_module
|
||||
.memory_section()
|
||||
.map_or(false, |ms| ms.entries().len() > 0)
|
||||
{
|
||||
// According to WebAssembly spec, internal memory is hidden from embedder and should not
|
||||
// be interacted with. So we disable this kind of modules at decoding level.
|
||||
return Err(vm::Error::Wasm(format!(
|
||||
"Malformed wasm module: internal memory"
|
||||
)));
|
||||
}
|
||||
|
||||
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::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 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 => {
|
||||
if data_position < code.len() { &code[data_position..] } else { &[] }
|
||||
},
|
||||
vm::ParamsType::Separate => {
|
||||
match params.data {
|
||||
Some(ref s) => &s[..],
|
||||
None => &[]
|
||||
}
|
||||
}
|
||||
};
|
||||
let data = match params.params_type {
|
||||
vm::ParamsType::Embedded => {
|
||||
if data_position < code.len() {
|
||||
&code[data_position..]
|
||||
} else {
|
||||
&[]
|
||||
}
|
||||
}
|
||||
vm::ParamsType::Separate => match params.data {
|
||||
Some(ref s) => &s[..],
|
||||
None => &[],
|
||||
},
|
||||
};
|
||||
|
||||
Ok((contract_module, data))
|
||||
Ok((contract_module, data))
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user