parent
407c8c3fb9
commit
9e4c122cf3
@ -1 +1 @@
|
||||
Subproject commit 330f748b1eece451f460224b48d515489dd86f5c
|
||||
Subproject commit 85e76c5ea2a54c6c54e35014643b5080a50460c5
|
@ -17,8 +17,9 @@
|
||||
//! Wasm env module bindings
|
||||
|
||||
use parity_wasm::elements::ValueType::*;
|
||||
use parity_wasm::interpreter::UserFunctionDescriptor;
|
||||
use parity_wasm::interpreter::{self, UserFunctionDescriptor};
|
||||
use parity_wasm::interpreter::UserFunctionDescriptor::*;
|
||||
use super::runtime::Runtime;
|
||||
|
||||
pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
|
||||
Static(
|
||||
@ -93,4 +94,17 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
|
||||
&[I32; 0],
|
||||
None
|
||||
),
|
||||
|
||||
Static(
|
||||
"_llvm_bswap_i64",
|
||||
&[I32; 2],
|
||||
Some(I32)
|
||||
),
|
||||
];
|
||||
|
||||
pub fn native_bindings<'a>(runtime: &'a mut Runtime) -> interpreter::UserFunctions<'a> {
|
||||
interpreter::UserFunctions {
|
||||
executor: runtime,
|
||||
functions: ::std::borrow::Cow::from(SIGNATURES),
|
||||
}
|
||||
}
|
@ -32,8 +32,6 @@ mod result;
|
||||
mod tests;
|
||||
mod env;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
const DEFAULT_STACK_SPACE: u32 = 5 * 1024 * 1024;
|
||||
|
||||
use parity_wasm::{interpreter, elements};
|
||||
@ -89,6 +87,7 @@ impl vm::Vm for WasmInterpreter {
|
||||
DEFAULT_STACK_SPACE,
|
||||
params.gas.low_u64(),
|
||||
RuntimeContext::new(params.address, params.sender),
|
||||
&self.program,
|
||||
);
|
||||
|
||||
let mut cursor = ::std::io::Cursor::new(&*code);
|
||||
@ -112,16 +111,8 @@ impl vm::Vm for WasmInterpreter {
|
||||
)?;
|
||||
|
||||
{
|
||||
let execution_params = interpreter::ExecutionParams::with_external(
|
||||
"env".into(),
|
||||
Arc::new(
|
||||
interpreter::env_native_module(env_instance, native_bindings(&mut runtime))
|
||||
.map_err(|err| {
|
||||
// todo: prefer explicit panic here also?
|
||||
vm::Error::Wasm(format!("Error instantiating native bindings: {:?}", err))
|
||||
})?
|
||||
)
|
||||
).add_argument(interpreter::RuntimeValue::I32(d_ptr.as_raw() as i32));
|
||||
let execution_params = runtime.execution_params()
|
||||
.add_argument(interpreter::RuntimeValue::I32(d_ptr.as_raw() as i32));
|
||||
|
||||
let module_instance = self.program.add_module("contract", contract_module, Some(&execution_params.externals))
|
||||
.map_err(|err| {
|
||||
@ -158,13 +149,6 @@ impl vm::Vm for WasmInterpreter {
|
||||
}
|
||||
}
|
||||
|
||||
fn native_bindings<'a>(runtime: &'a mut Runtime) -> interpreter::UserFunctions<'a> {
|
||||
interpreter::UserFunctions {
|
||||
executor: runtime,
|
||||
functions: ::std::borrow::Cow::from(env::SIGNATURES),
|
||||
}
|
||||
}
|
||||
|
||||
impl From<runtime::Error> for vm::Error {
|
||||
fn from(err: runtime::Error) -> vm::Error {
|
||||
vm::Error::Wasm(format!("WASM runtime-error: {:?}", err))
|
||||
|
@ -72,24 +72,26 @@ impl RuntimeContext {
|
||||
}
|
||||
|
||||
/// Runtime enviroment data for wasm contract execution
|
||||
pub struct Runtime<'a> {
|
||||
pub struct Runtime<'a, 'b> {
|
||||
gas_counter: u64,
|
||||
gas_limit: u64,
|
||||
dynamic_top: u32,
|
||||
ext: &'a mut vm::Ext,
|
||||
memory: Arc<interpreter::MemoryInstance>,
|
||||
context: RuntimeContext,
|
||||
instance: &'b interpreter::ProgramInstance,
|
||||
}
|
||||
|
||||
impl<'a> Runtime<'a> {
|
||||
impl<'a, 'b> Runtime<'a, 'b> {
|
||||
/// New runtime for wasm contract with specified params
|
||||
pub fn with_params<'b>(
|
||||
ext: &'b mut vm::Ext,
|
||||
pub fn with_params<'c, 'd>(
|
||||
ext: &'c mut vm::Ext,
|
||||
memory: Arc<interpreter::MemoryInstance>,
|
||||
stack_space: u32,
|
||||
gas_limit: u64,
|
||||
context: RuntimeContext,
|
||||
) -> Runtime<'b> {
|
||||
program_instance: &'d interpreter::ProgramInstance,
|
||||
) -> Runtime<'c, 'd> {
|
||||
Runtime {
|
||||
gas_counter: 0,
|
||||
gas_limit: gas_limit,
|
||||
@ -97,6 +99,7 @@ impl<'a> Runtime<'a> {
|
||||
memory: memory,
|
||||
ext: ext,
|
||||
context: context,
|
||||
instance: program_instance,
|
||||
}
|
||||
}
|
||||
|
||||
@ -449,9 +452,58 @@ impl<'a> Runtime<'a> {
|
||||
|
||||
Ok(Some(0i32.into()))
|
||||
}
|
||||
|
||||
fn bswap_32(x: u32) -> u32 {
|
||||
x >> 24 | x >> 8 & 0xff00 | x << 8 & 0xff0000 | x << 24
|
||||
}
|
||||
|
||||
fn bitswap_i64(&mut self, context: interpreter::CallerContext)
|
||||
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||
{
|
||||
let x1 = context.value_stack.pop_as::<i32>()?;
|
||||
let x2 = context.value_stack.pop_as::<i32>()?;
|
||||
|
||||
let result = ((Runtime::bswap_32(x2 as u32) as u64) << 32
|
||||
| Runtime::bswap_32(x1 as u32) as u64) as i64;
|
||||
|
||||
self.return_i64(result)
|
||||
}
|
||||
|
||||
fn return_i64(&mut self, val: i64) -> Result<Option<interpreter::RuntimeValue>, interpreter::Error> {
|
||||
let uval = val as u64;
|
||||
let hi = (uval >> 32) as i32;
|
||||
let lo = (uval << 32 >> 32) as i32;
|
||||
|
||||
let target = self.instance.module("contract")
|
||||
.ok_or(interpreter::Error::Trap("Error locating main execution entry".to_owned()))?;
|
||||
target.execute_export(
|
||||
"setTempRet0",
|
||||
self.execution_params().add_argument(
|
||||
interpreter::RuntimeValue::I32(hi).into()
|
||||
),
|
||||
)?;
|
||||
Ok(Some(
|
||||
(lo).into()
|
||||
))
|
||||
}
|
||||
|
||||
pub fn execution_params(&mut self) -> interpreter::ExecutionParams {
|
||||
use super::env;
|
||||
|
||||
let env_instance = self.instance.module("env")
|
||||
.expect("Env module always exists; qed");
|
||||
|
||||
interpreter::ExecutionParams::with_external(
|
||||
"env".into(),
|
||||
Arc::new(
|
||||
interpreter::env_native_module(env_instance, env::native_bindings(self))
|
||||
.expect("Env module always exists; qed")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> interpreter::UserFunctionExecutor for Runtime<'a> {
|
||||
impl<'a, 'b> interpreter::UserFunctionExecutor for Runtime<'a, 'b> {
|
||||
fn execute(&mut self, name: &str, context: interpreter::CallerContext)
|
||||
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||
{
|
||||
@ -494,6 +546,9 @@ impl<'a> interpreter::UserFunctionExecutor for Runtime<'a> {
|
||||
"_emscripten_memcpy_big" => {
|
||||
self.mem_copy(context)
|
||||
},
|
||||
"_llvm_bswap_i64" => {
|
||||
self.bitswap_i64(context)
|
||||
},
|
||||
_ => {
|
||||
trace!(target: "wasm", "Trapped due to unhandled function: '{}'", name);
|
||||
self.user_trap(context)
|
||||
|
@ -414,3 +414,37 @@ fn storage_read() {
|
||||
assert_eq!(gas_left, U256::from(99682));
|
||||
assert_eq!(Address::from(&result[12..32]), address);
|
||||
}
|
||||
|
||||
|
||||
// Tests that contract's ability to read from a storage
|
||||
// Test prepopulates address into storage, than executes a contract which read that address from storage and write this address into result
|
||||
#[test]
|
||||
fn math_add() {
|
||||
::ethcore_logger::init_log();
|
||||
let code = load_sample!("math.wasm");
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
|
||||
let mut args = [0u8; 64];
|
||||
let arg_a = U256::from_dec_str("999999999999999999999999999999").unwrap();
|
||||
let arg_b = U256::from_dec_str("888888888888888888888888888888").unwrap();
|
||||
arg_a.to_big_endian(&mut args[0..32]);
|
||||
arg_b.to_big_endian(&mut args[32..64]);
|
||||
params.data = Some(args.to_vec());
|
||||
|
||||
let (gas_left, result) = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
let result = interpreter.exec(params, &mut FakeExt::new()).expect("Interpreter to execute without any errors");
|
||||
match result {
|
||||
GasLeft::Known(_) => { panic!("storage_read should return payload"); },
|
||||
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||
}
|
||||
};
|
||||
|
||||
let sum: U256 = (&result[..]).into();
|
||||
|
||||
assert_eq!(gas_left, U256::from(96284));
|
||||
assert_eq!(sum, U256::from_dec_str("1888888888888888888888888888887").unwrap());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user