parent
407c8c3fb9
commit
9e4c122cf3
@ -1 +1 @@
|
|||||||
Subproject commit 330f748b1eece451f460224b48d515489dd86f5c
|
Subproject commit 85e76c5ea2a54c6c54e35014643b5080a50460c5
|
@ -17,8 +17,9 @@
|
|||||||
//! Wasm env module bindings
|
//! Wasm env module bindings
|
||||||
|
|
||||||
use parity_wasm::elements::ValueType::*;
|
use parity_wasm::elements::ValueType::*;
|
||||||
use parity_wasm::interpreter::UserFunctionDescriptor;
|
use parity_wasm::interpreter::{self, UserFunctionDescriptor};
|
||||||
use parity_wasm::interpreter::UserFunctionDescriptor::*;
|
use parity_wasm::interpreter::UserFunctionDescriptor::*;
|
||||||
|
use super::runtime::Runtime;
|
||||||
|
|
||||||
pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
|
pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
|
||||||
Static(
|
Static(
|
||||||
@ -93,4 +94,17 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
|
|||||||
&[I32; 0],
|
&[I32; 0],
|
||||||
None
|
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 tests;
|
||||||
mod env;
|
mod env;
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
const DEFAULT_STACK_SPACE: u32 = 5 * 1024 * 1024;
|
const DEFAULT_STACK_SPACE: u32 = 5 * 1024 * 1024;
|
||||||
|
|
||||||
use parity_wasm::{interpreter, elements};
|
use parity_wasm::{interpreter, elements};
|
||||||
@ -89,6 +87,7 @@ impl vm::Vm for WasmInterpreter {
|
|||||||
DEFAULT_STACK_SPACE,
|
DEFAULT_STACK_SPACE,
|
||||||
params.gas.low_u64(),
|
params.gas.low_u64(),
|
||||||
RuntimeContext::new(params.address, params.sender),
|
RuntimeContext::new(params.address, params.sender),
|
||||||
|
&self.program,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut cursor = ::std::io::Cursor::new(&*code);
|
let mut cursor = ::std::io::Cursor::new(&*code);
|
||||||
@ -112,16 +111,8 @@ impl vm::Vm for WasmInterpreter {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
{
|
{
|
||||||
let execution_params = interpreter::ExecutionParams::with_external(
|
let execution_params = runtime.execution_params()
|
||||||
"env".into(),
|
.add_argument(interpreter::RuntimeValue::I32(d_ptr.as_raw() as i32));
|
||||||
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 module_instance = self.program.add_module("contract", contract_module, Some(&execution_params.externals))
|
let module_instance = self.program.add_module("contract", contract_module, Some(&execution_params.externals))
|
||||||
.map_err(|err| {
|
.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 {
|
impl From<runtime::Error> for vm::Error {
|
||||||
fn from(err: runtime::Error) -> vm::Error {
|
fn from(err: runtime::Error) -> vm::Error {
|
||||||
vm::Error::Wasm(format!("WASM runtime-error: {:?}", err))
|
vm::Error::Wasm(format!("WASM runtime-error: {:?}", err))
|
||||||
|
@ -72,24 +72,26 @@ impl RuntimeContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Runtime enviroment data for wasm contract execution
|
/// Runtime enviroment data for wasm contract execution
|
||||||
pub struct Runtime<'a> {
|
pub struct Runtime<'a, 'b> {
|
||||||
gas_counter: u64,
|
gas_counter: u64,
|
||||||
gas_limit: u64,
|
gas_limit: u64,
|
||||||
dynamic_top: u32,
|
dynamic_top: u32,
|
||||||
ext: &'a mut vm::Ext,
|
ext: &'a mut vm::Ext,
|
||||||
memory: Arc<interpreter::MemoryInstance>,
|
memory: Arc<interpreter::MemoryInstance>,
|
||||||
context: RuntimeContext,
|
context: RuntimeContext,
|
||||||
|
instance: &'b interpreter::ProgramInstance,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Runtime<'a> {
|
impl<'a, 'b> Runtime<'a, 'b> {
|
||||||
/// New runtime for wasm contract with specified params
|
/// New runtime for wasm contract with specified params
|
||||||
pub fn with_params<'b>(
|
pub fn with_params<'c, 'd>(
|
||||||
ext: &'b mut vm::Ext,
|
ext: &'c mut vm::Ext,
|
||||||
memory: Arc<interpreter::MemoryInstance>,
|
memory: Arc<interpreter::MemoryInstance>,
|
||||||
stack_space: u32,
|
stack_space: u32,
|
||||||
gas_limit: u64,
|
gas_limit: u64,
|
||||||
context: RuntimeContext,
|
context: RuntimeContext,
|
||||||
) -> Runtime<'b> {
|
program_instance: &'d interpreter::ProgramInstance,
|
||||||
|
) -> Runtime<'c, 'd> {
|
||||||
Runtime {
|
Runtime {
|
||||||
gas_counter: 0,
|
gas_counter: 0,
|
||||||
gas_limit: gas_limit,
|
gas_limit: gas_limit,
|
||||||
@ -97,6 +99,7 @@ impl<'a> Runtime<'a> {
|
|||||||
memory: memory,
|
memory: memory,
|
||||||
ext: ext,
|
ext: ext,
|
||||||
context: context,
|
context: context,
|
||||||
|
instance: program_instance,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,9 +452,58 @@ impl<'a> Runtime<'a> {
|
|||||||
|
|
||||||
Ok(Some(0i32.into()))
|
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)
|
fn execute(&mut self, name: &str, context: interpreter::CallerContext)
|
||||||
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||||
{
|
{
|
||||||
@ -494,6 +546,9 @@ impl<'a> interpreter::UserFunctionExecutor for Runtime<'a> {
|
|||||||
"_emscripten_memcpy_big" => {
|
"_emscripten_memcpy_big" => {
|
||||||
self.mem_copy(context)
|
self.mem_copy(context)
|
||||||
},
|
},
|
||||||
|
"_llvm_bswap_i64" => {
|
||||||
|
self.bitswap_i64(context)
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
trace!(target: "wasm", "Trapped due to unhandled function: '{}'", name);
|
trace!(target: "wasm", "Trapped due to unhandled function: '{}'", name);
|
||||||
self.user_trap(context)
|
self.user_trap(context)
|
||||||
|
@ -414,3 +414,37 @@ fn storage_read() {
|
|||||||
assert_eq!(gas_left, U256::from(99682));
|
assert_eq!(gas_left, U256::from(99682));
|
||||||
assert_eq!(Address::from(&result[12..32]), address);
|
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