wasm mvp continued
This commit is contained in:
parent
5fb32229f9
commit
5180919e52
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -878,6 +878,7 @@ dependencies = [
|
|||||||
"bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"common-types 0.1.0",
|
"common-types 0.1.0",
|
||||||
|
"ethcore-logger 1.8.0",
|
||||||
"ethcore-util 1.8.0",
|
"ethcore-util 1.8.0",
|
||||||
"ethjson 0.1.0",
|
"ethjson 0.1.0",
|
||||||
"evmjit 1.8.0",
|
"evmjit 1.8.0",
|
||||||
|
@ -14,8 +14,10 @@ lazy_static = "0.2"
|
|||||||
log = "0.3"
|
log = "0.3"
|
||||||
rlp = { path = "../../util/rlp" }
|
rlp = { path = "../../util/rlp" }
|
||||||
parity-wasm = "0.12"
|
parity-wasm = "0.12"
|
||||||
|
ethcore-logger = { path = "../../logger" }
|
||||||
wasm-utils = { git = "https://github.com/paritytech/wasm-utils" }
|
wasm-utils = { git = "https://github.com/paritytech/wasm-utils" }
|
||||||
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rustc-hex = "1.0"
|
rustc-hex = "1.0"
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ extern crate ethjson;
|
|||||||
extern crate rlp;
|
extern crate rlp;
|
||||||
extern crate parity_wasm;
|
extern crate parity_wasm;
|
||||||
extern crate wasm_utils;
|
extern crate wasm_utils;
|
||||||
|
extern crate ethcore_logger;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
@ -61,6 +61,21 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
|
|||||||
&[I32; 4],
|
&[I32; 4],
|
||||||
Some(I32),
|
Some(I32),
|
||||||
),
|
),
|
||||||
|
Static(
|
||||||
|
"_ccall",
|
||||||
|
&[I32; 6],
|
||||||
|
Some(I32),
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"_dcall",
|
||||||
|
&[I32; 5],
|
||||||
|
Some(I32),
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"_scall",
|
||||||
|
&[I32; 5],
|
||||||
|
Some(I32),
|
||||||
|
),
|
||||||
Static(
|
Static(
|
||||||
"abort",
|
"abort",
|
||||||
&[I32],
|
&[I32],
|
||||||
@ -71,49 +86,19 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
|
|||||||
&[],
|
&[],
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
Static(
|
|
||||||
"invoke_vii",
|
|
||||||
&[I32; 3],
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
Static(
|
|
||||||
"invoke_vi",
|
|
||||||
&[I32; 2],
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
Static(
|
|
||||||
"invoke_v",
|
|
||||||
&[I32],
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
Static(
|
|
||||||
"invoke_iii",
|
|
||||||
&[I32; 3],
|
|
||||||
Some(I32),
|
|
||||||
),
|
|
||||||
Static(
|
|
||||||
"___resumeException",
|
|
||||||
&[I32],
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
Static(
|
Static(
|
||||||
"_rust_begin_unwind",
|
"_rust_begin_unwind",
|
||||||
&[I32; 4],
|
&[I32; 4],
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
Static(
|
|
||||||
"___cxa_find_matching_catch_2",
|
|
||||||
&[],
|
|
||||||
Some(I32),
|
|
||||||
),
|
|
||||||
Static(
|
|
||||||
"___gxx_personality_v0",
|
|
||||||
&[I32; 6],
|
|
||||||
Some(I32),
|
|
||||||
),
|
|
||||||
Static(
|
Static(
|
||||||
"_emscripten_memcpy_big",
|
"_emscripten_memcpy_big",
|
||||||
&[I32; 3],
|
&[I32; 3],
|
||||||
Some(I32),
|
Some(I32),
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"___syscall6",
|
||||||
|
&[I32; 2],
|
||||||
|
Some(I32),
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
|
@ -34,7 +34,7 @@ use wasm_utils;
|
|||||||
|
|
||||||
use evm::{self, GasLeft, ReturnData};
|
use evm::{self, GasLeft, ReturnData};
|
||||||
use action_params::ActionParams;
|
use action_params::ActionParams;
|
||||||
use self::runtime::Runtime;
|
use self::runtime::{Runtime, RuntimeContext};
|
||||||
|
|
||||||
pub use self::runtime::Error as RuntimeError;
|
pub use self::runtime::Error as RuntimeError;
|
||||||
|
|
||||||
@ -82,6 +82,7 @@ impl evm::Evm for WasmInterpreter {
|
|||||||
env_memory,
|
env_memory,
|
||||||
DEFAULT_STACK_SPACE,
|
DEFAULT_STACK_SPACE,
|
||||||
params.gas.low_u64(),
|
params.gas.low_u64(),
|
||||||
|
RuntimeContext::new(params.address, params.sender),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut cursor = ::std::io::Cursor::new(&*code);
|
let mut cursor = ::std::io::Cursor::new(&*code);
|
||||||
|
@ -25,6 +25,7 @@ use ext;
|
|||||||
use parity_wasm::interpreter;
|
use parity_wasm::interpreter;
|
||||||
use util::{Address, H256, U256};
|
use util::{Address, H256, U256};
|
||||||
|
|
||||||
|
use call_type::CallType;
|
||||||
use super::ptr::{WasmPtr, Error as PtrError};
|
use super::ptr::{WasmPtr, Error as PtrError};
|
||||||
use super::call_args::CallArgs;
|
use super::call_args::CallArgs;
|
||||||
|
|
||||||
@ -57,6 +58,20 @@ impl From<PtrError> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct RuntimeContext {
|
||||||
|
address: Address,
|
||||||
|
sender: Address,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RuntimeContext {
|
||||||
|
pub fn new(address: Address, sender: Address) -> Self {
|
||||||
|
RuntimeContext {
|
||||||
|
address: address,
|
||||||
|
sender: sender,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Runtime enviroment data for wasm contract execution
|
/// Runtime enviroment data for wasm contract execution
|
||||||
pub struct Runtime<'a> {
|
pub struct Runtime<'a> {
|
||||||
gas_counter: u64,
|
gas_counter: u64,
|
||||||
@ -64,6 +79,7 @@ pub struct Runtime<'a> {
|
|||||||
dynamic_top: u32,
|
dynamic_top: u32,
|
||||||
ext: &'a mut ext::Ext,
|
ext: &'a mut ext::Ext,
|
||||||
memory: Arc<interpreter::MemoryInstance>,
|
memory: Arc<interpreter::MemoryInstance>,
|
||||||
|
context: RuntimeContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Runtime<'a> {
|
impl<'a> Runtime<'a> {
|
||||||
@ -73,6 +89,7 @@ impl<'a> Runtime<'a> {
|
|||||||
memory: Arc<interpreter::MemoryInstance>,
|
memory: Arc<interpreter::MemoryInstance>,
|
||||||
stack_space: u32,
|
stack_space: u32,
|
||||||
gas_limit: u64,
|
gas_limit: u64,
|
||||||
|
context: RuntimeContext,
|
||||||
) -> Runtime<'b> {
|
) -> Runtime<'b> {
|
||||||
Runtime {
|
Runtime {
|
||||||
gas_counter: 0,
|
gas_counter: 0,
|
||||||
@ -80,6 +97,7 @@ impl<'a> Runtime<'a> {
|
|||||||
dynamic_top: stack_space,
|
dynamic_top: stack_space,
|
||||||
memory: memory,
|
memory: memory,
|
||||||
ext: ext,
|
ext: ext,
|
||||||
|
context: context,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,13 +157,13 @@ impl<'a> Runtime<'a> {
|
|||||||
trace!(target: "wasm", "runtime: create contract");
|
trace!(target: "wasm", "runtime: create contract");
|
||||||
let mut context = context;
|
let mut context = context;
|
||||||
let result_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
let result_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
trace!(target: "wasm", " result_ptr: {:?}", result_ptr);
|
trace!(target: "wasm", "result_ptr: {:?}", result_ptr);
|
||||||
let code_len = context.value_stack.pop_as::<i32>()? as u32;
|
let code_len = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
trace!(target: "wasm", " code_len: {:?}", code_len);
|
trace!(target: "wasm", " code_len: {:?}", code_len);
|
||||||
let code_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
let code_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
trace!(target: "wasm", " code_ptr: {:?}", code_ptr);
|
trace!(target: "wasm", " code_ptr: {:?}", code_ptr);
|
||||||
let endowment = self.pop_u256(&mut context)?;
|
let endowment = self.pop_u256(&mut context)?;
|
||||||
trace!(target: "wasm", " val: {:?}", endowment);
|
trace!(target: "wasm", " val: {:?}", endowment);
|
||||||
|
|
||||||
let code = self.memory.get(code_ptr, code_len as usize)?;
|
let code = self.memory.get(code_ptr, code_len as usize)?;
|
||||||
|
|
||||||
@ -167,6 +185,127 @@ impl<'a> Runtime<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn call(&mut self, context: interpreter::CallerContext)
|
||||||
|
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// method signature:
|
||||||
|
// fn (
|
||||||
|
// address: *const u8,
|
||||||
|
// val_ptr: *const u8,
|
||||||
|
// input_ptr: *const u8,
|
||||||
|
// input_len: u32,
|
||||||
|
// result_ptr: *mut u8,
|
||||||
|
// result_len: u32,
|
||||||
|
// ) -> i32
|
||||||
|
|
||||||
|
self.do_call(true, CallType::Call, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn call_code(&mut self, context: interpreter::CallerContext)
|
||||||
|
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// signature (same as static call):
|
||||||
|
// fn (
|
||||||
|
// address: *const u8,
|
||||||
|
// input_ptr: *const u8,
|
||||||
|
// input_len: u32,
|
||||||
|
// result_ptr: *mut u8,
|
||||||
|
// result_len: u32,
|
||||||
|
// ) -> i32
|
||||||
|
|
||||||
|
self.do_call(false, CallType::CallCode, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_call(
|
||||||
|
&mut self,
|
||||||
|
use_val: bool,
|
||||||
|
call_type: CallType,
|
||||||
|
context: interpreter::CallerContext,
|
||||||
|
)
|
||||||
|
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||||
|
{
|
||||||
|
|
||||||
|
trace!(target: "wasm", "runtime: call code");
|
||||||
|
let mut context = context;
|
||||||
|
let result_alloc_len = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
|
trace!(target: "wasm", " result_len: {:?}", result_alloc_len);
|
||||||
|
|
||||||
|
let result_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
|
trace!(target: "wasm", " result_ptr: {:?}", result_ptr);
|
||||||
|
|
||||||
|
let input_len = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
|
trace!(target: "wasm", " input_len: {:?}", input_len);
|
||||||
|
|
||||||
|
let input_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
|
trace!(target: "wasm", " input_ptr: {:?}", input_ptr);
|
||||||
|
|
||||||
|
let val = if use_val { Some(self.pop_u256(&mut context)?) }
|
||||||
|
else { None };
|
||||||
|
trace!(target: "wasm", " val: {:?}", val);
|
||||||
|
|
||||||
|
let address = self.pop_address(&mut context)?;
|
||||||
|
trace!(target: "wasm", " address: {:?}", address);
|
||||||
|
|
||||||
|
if let Some(ref val) = val {
|
||||||
|
let address_balance = self.ext.balance(&self.context.address)
|
||||||
|
.map_err(|_| interpreter::Error::Trap("Gas state error".to_owned()))?;
|
||||||
|
|
||||||
|
if &address_balance < val {
|
||||||
|
trace!(target: "wasm", "runtime: call failed due to balance check");
|
||||||
|
return Ok(Some((-1i32).into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut result = Vec::with_capacity(result_alloc_len as usize);
|
||||||
|
result.resize(result_alloc_len as usize, 0);
|
||||||
|
let gas = self.gas_left()
|
||||||
|
.map_err(|_| interpreter::Error::Trap("Gas state error".to_owned()))?
|
||||||
|
.into();
|
||||||
|
// todo: optimize to use memory views once it's in
|
||||||
|
let payload = self.memory.get(input_ptr, input_len as usize)?;
|
||||||
|
|
||||||
|
let call_result = self.ext.call(
|
||||||
|
&gas,
|
||||||
|
&self.context.sender,
|
||||||
|
&self.context.address,
|
||||||
|
val,
|
||||||
|
&payload,
|
||||||
|
&address,
|
||||||
|
&mut result[..],
|
||||||
|
call_type,
|
||||||
|
);
|
||||||
|
|
||||||
|
match call_result {
|
||||||
|
ext::MessageCallResult::Success(gas_left, _) => {
|
||||||
|
self.gas_counter = self.gas_limit - gas_left.low_u64();
|
||||||
|
self.memory.set(result_ptr, &result)?;
|
||||||
|
Ok(Some(0i32.into()))
|
||||||
|
},
|
||||||
|
ext::MessageCallResult::Failed => {
|
||||||
|
Ok(Some((-1i32).into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn static_call(&mut self, context: interpreter::CallerContext)
|
||||||
|
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||||
|
{
|
||||||
|
// signature (same as code call):
|
||||||
|
// fn (
|
||||||
|
// address: *const u8,
|
||||||
|
// input_ptr: *const u8,
|
||||||
|
// input_len: u32,
|
||||||
|
// result_ptr: *mut u8,
|
||||||
|
// result_len: u32,
|
||||||
|
// ) -> i32
|
||||||
|
|
||||||
|
self.do_call(false, CallType::StaticCall, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Allocate memory using the wasm stack params
|
/// Allocate memory using the wasm stack params
|
||||||
pub fn malloc(&mut self, context: interpreter::CallerContext)
|
pub fn malloc(&mut self, context: interpreter::CallerContext)
|
||||||
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||||
@ -338,6 +477,15 @@ impl<'a> interpreter::UserFunctionExecutor for Runtime<'a> {
|
|||||||
"_create" => {
|
"_create" => {
|
||||||
self.create(context)
|
self.create(context)
|
||||||
},
|
},
|
||||||
|
"_ccall" => {
|
||||||
|
self.call(context)
|
||||||
|
},
|
||||||
|
"_dcall" => {
|
||||||
|
self.call_code(context)
|
||||||
|
},
|
||||||
|
"_scall" => {
|
||||||
|
self.static_call(context)
|
||||||
|
},
|
||||||
"_debug" => {
|
"_debug" => {
|
||||||
self.debug_log(context)
|
self.debug_log(context)
|
||||||
},
|
},
|
||||||
@ -348,7 +496,7 @@ impl<'a> interpreter::UserFunctionExecutor for Runtime<'a> {
|
|||||||
self.mem_copy(context)
|
self.mem_copy(context)
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
trace!("Unknown env func: '{}'", name);
|
trace!(target: "wasm", "Trapped due to unhandled function: '{}'", name);
|
||||||
self.user_trap(context)
|
self.user_trap(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ use super::WasmInterpreter;
|
|||||||
use evm::{self, Evm, GasLeft};
|
use evm::{self, Evm, GasLeft};
|
||||||
use action_params::{ActionParams, ActionValue};
|
use action_params::{ActionParams, ActionValue};
|
||||||
use util::{U256, H256, Address};
|
use util::{U256, H256, Address};
|
||||||
|
use byteorder::{LittleEndian, ByteOrder};
|
||||||
|
|
||||||
macro_rules! load_sample {
|
macro_rules! load_sample {
|
||||||
($name: expr) => {
|
($name: expr) => {
|
||||||
@ -85,7 +86,7 @@ fn logger() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
println!("ext.store: {:?}", ext.store);
|
println!("ext.store: {:?}", ext.store);
|
||||||
assert_eq!(gas_left, U256::from(99581));
|
assert_eq!(gas_left, U256::from(99590));
|
||||||
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"),
|
||||||
@ -136,7 +137,7 @@ fn identity() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(99_689));
|
assert_eq!(gas_left, U256::from(99_687));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Address::from_slice(&result),
|
Address::from_slice(&result),
|
||||||
@ -170,7 +171,7 @@ fn dispersion() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(99_402));
|
assert_eq!(gas_left, U256::from(99_423));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result,
|
result,
|
||||||
@ -199,7 +200,7 @@ fn suicide_not() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(99_703));
|
assert_eq!(gas_left, U256::from(99_656));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result,
|
result,
|
||||||
@ -233,12 +234,14 @@ fn suicide() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(99_747));
|
assert_eq!(gas_left, U256::from(99_740));
|
||||||
assert!(ext.suicides.contains(&refund));
|
assert!(ext.suicides.contains(&refund));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create() {
|
fn create() {
|
||||||
|
::ethcore_logger::init_log();
|
||||||
|
|
||||||
let mut params = ActionParams::default();
|
let mut params = ActionParams::default();
|
||||||
params.gas = U256::from(100_000);
|
params.gas = U256::from(100_000);
|
||||||
params.code = Some(Arc::new(load_sample!("creator.wasm")));
|
params.code = Some(Arc::new(load_sample!("creator.wasm")));
|
||||||
@ -262,7 +265,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_778),
|
gas: U256::from(99_767),
|
||||||
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()),
|
||||||
@ -270,5 +273,96 @@ fn create() {
|
|||||||
code_address: None,
|
code_address: None,
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
assert_eq!(gas_left, U256::from(99_768));
|
assert_eq!(gas_left, U256::from(99_759));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn call_code() {
|
||||||
|
::ethcore_logger::init_log();
|
||||||
|
|
||||||
|
let sender: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap();
|
||||||
|
let receiver: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
|
||||||
|
|
||||||
|
let mut params = ActionParams::default();
|
||||||
|
params.sender = sender.clone();
|
||||||
|
params.address = receiver.clone();
|
||||||
|
params.gas = U256::from(100_000);
|
||||||
|
params.code = Some(Arc::new(load_sample!("call_code.wasm")));
|
||||||
|
params.data = Some(Vec::new());
|
||||||
|
params.value = ActionValue::transfer(1_000_000_000);
|
||||||
|
|
||||||
|
let mut ext = FakeExt::new();
|
||||||
|
|
||||||
|
let (gas_left, result) = {
|
||||||
|
let mut interpreter = wasm_interpreter();
|
||||||
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
||||||
|
match result {
|
||||||
|
GasLeft::Known(_) => { panic!("Call test should return payload"); },
|
||||||
|
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
trace!(target: "wasm", "fake_calls: {:?}", &ext.calls);
|
||||||
|
assert!(ext.calls.contains(
|
||||||
|
&FakeCall {
|
||||||
|
call_type: FakeCallType::Call,
|
||||||
|
gas: U256::from(99_061),
|
||||||
|
sender_address: Some(sender),
|
||||||
|
receive_address: Some(receiver),
|
||||||
|
value: None,
|
||||||
|
data: vec![1u8, 2, 3, 5, 7, 11],
|
||||||
|
code_address: Some("0d13710000000000000000000000000000000000".parse().unwrap()),
|
||||||
|
}
|
||||||
|
));
|
||||||
|
assert_eq!(gas_left, U256::from(94196));
|
||||||
|
|
||||||
|
// siphash result
|
||||||
|
let res = LittleEndian::read_u32(&result[..]);
|
||||||
|
assert_eq!(res, 4198595614);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn call_static() {
|
||||||
|
::ethcore_logger::init_log();
|
||||||
|
|
||||||
|
let sender: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
|
||||||
|
let receiver: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap();
|
||||||
|
|
||||||
|
let mut params = ActionParams::default();
|
||||||
|
params.sender = sender.clone();
|
||||||
|
params.address = receiver.clone();
|
||||||
|
params.gas = U256::from(100_000);
|
||||||
|
params.code = Some(Arc::new(load_sample!("call_static.wasm")));
|
||||||
|
params.data = Some(Vec::new());
|
||||||
|
params.value = ActionValue::transfer(1_000_000_000);
|
||||||
|
|
||||||
|
let mut ext = FakeExt::new();
|
||||||
|
|
||||||
|
let (gas_left, result) = {
|
||||||
|
let mut interpreter = wasm_interpreter();
|
||||||
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
||||||
|
match result {
|
||||||
|
GasLeft::Known(_) => { panic!("Static call test should return payload"); },
|
||||||
|
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
trace!(target: "wasm", "fake_calls: {:?}", &ext.calls);
|
||||||
|
assert!(ext.calls.contains(
|
||||||
|
&FakeCall {
|
||||||
|
call_type: FakeCallType::Call,
|
||||||
|
gas: U256::from(99_061),
|
||||||
|
sender_address: Some(sender),
|
||||||
|
receive_address: Some(receiver),
|
||||||
|
value: None,
|
||||||
|
data: vec![1u8, 2, 3, 5, 7, 11],
|
||||||
|
code_address: Some("13077bfb00000000000000000000000000000000".parse().unwrap()),
|
||||||
|
}
|
||||||
|
));
|
||||||
|
assert_eq!(gas_left, U256::from(94196));
|
||||||
|
|
||||||
|
// siphash result
|
||||||
|
let res = LittleEndian::read_u32(&result[..]);
|
||||||
|
assert_eq!(res, 317632590);
|
||||||
}
|
}
|
@ -1 +1 @@
|
|||||||
Subproject commit 9ed6304313fa949ed92aa0570fb2bc759fb6dc58
|
Subproject commit 8361f18c7ea133d9b85edf7dea02f05b9feb1938
|
Loading…
Reference in New Issue
Block a user