Wasm runtime update (#7356)

* call augmented, wasm-tests updated

* fix all call tests

* fix comments
This commit is contained in:
Nikolay Volf 2017-12-22 21:54:35 +03:00 committed by GitHub
parent d80dd81d77
commit 82340c058a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 97 additions and 40 deletions

@ -1 +1 @@
Subproject commit d6185ea16eaba7ff685c069c2064819f9549c4d7
Subproject commit d9d6133c1bc5dca4c74c9eb758a39546a0d46b45

View File

@ -69,17 +69,17 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
),
Static(
"_ccall",
&[I32; 6],
&[I64, I32, I32, I32, I32, I32, I32],
Some(I32),
),
Static(
"_dcall",
&[I32; 5],
&[I64, I32, I32, I32, I32, I32],
Some(I32),
),
Static(
"_scall",
&[I32; 5],
&[I64, I32, I32, I32, I32, I32],
Some(I32),
),
Static(

View File

@ -111,6 +111,7 @@ impl vm::Vm for WasmInterpreter {
address: params.address,
sender: params.sender,
origin: params.origin,
code_address: params.code_address,
value: params.value.value(),
},
&self.program,

View File

@ -104,6 +104,7 @@ pub struct RuntimeContext {
pub address: Address,
pub sender: Address,
pub origin: Address,
pub code_address: Address,
pub value: U256,
}
@ -305,6 +306,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
//
// method signature:
// fn (
// gas: i64,
// address: *const u8,
// val_ptr: *const u8,
// input_ptr: *const u8,
@ -323,6 +325,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
//
// signature (same as static call):
// fn (
// gas: i64,
// address: *const u8,
// input_ptr: *const u8,
// input_len: u32,
@ -330,7 +333,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
// result_len: u32,
// ) -> i32
self.do_call(false, CallType::CallCode, context)
self.do_call(false, CallType::DelegateCall, context)
}
fn do_call(
@ -363,6 +366,9 @@ impl<'a, 'b> Runtime<'a, 'b> {
let address = self.pop_address(&mut context)?;
trace!(target: "wasm", " address: {:?}", address);
let gas = context.value_stack.pop_as::<i64>()? as u64;
trace!(target: "wasm", " gas: {:?}", gas);
if let Some(ref val) = val {
let address_balance = self.ext.balance(&self.context.address)
.map_err(|_| UserTrap::BalanceQueryError)?;
@ -377,16 +383,16 @@ impl<'a, 'b> Runtime<'a, 'b> {
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(|_| UserTrap::InvalidGasState)?
.into();
// todo: optimize to use memory views once it's in
let payload = self.memory.get(input_ptr, input_len as usize)?;
self.charge(|_| gas.into())?;
let call_result = self.ext.call(
&gas,
&self.context.sender,
&self.context.address,
&gas.into(),
match call_type { CallType::DelegateCall => &self.context.sender, _ => &self.context.address },
match call_type { CallType::Call | CallType::StaticCall => &address, _ => &self.context.address },
val,
&payload,
&address,
@ -396,12 +402,16 @@ impl<'a, 'b> Runtime<'a, 'b> {
match call_result {
vm::MessageCallResult::Success(gas_left, _) => {
self.gas_counter = self.gas_limit - gas_left.low_u64();
// cannot overflow, before making call gas_counter was incremented with gas, and gas_left < gas
self.gas_counter = self.gas_counter - gas_left.low_u64();
self.memory.set(result_ptr, &result)?;
Ok(Some(0i32.into()))
},
vm::MessageCallResult::Reverted(gas_left, _) => {
self.gas_counter = self.gas_limit - gas_left.low_u64();
// cannot overflow, before making call gas_counter was incremented with gas, and gas_left < gas
self.gas_counter = self.gas_counter - gas_left.low_u64();
self.memory.set(result_ptr, &result)?;
Ok(Some((-1i32).into()))
},
@ -416,6 +426,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
{
// signature (same as code call):
// fn (
// gas: i64,
// address: *const u8,
// input_ptr: *const u8,
// input_len: u32,

View File

@ -60,7 +60,7 @@ fn empty() {
test_finalize(interpreter.exec(params, &mut ext)).unwrap()
};
assert_eq!(gas_left, U256::from(99_982));
assert_eq!(gas_left, U256::from(96_678));
}
// This test checks if the contract deserializes payload header properly.
@ -112,7 +112,7 @@ fn logger() {
U256::from(1_000_000_000),
"Logger sets 0x04 key to the trasferred value"
);
assert_eq!(gas_left, U256::from(19_147));
assert_eq!(gas_left, U256::from(15_860));
}
// This test checks if the contract can allocate memory and pass pointer to the result stream properly.
@ -147,7 +147,7 @@ fn identity() {
sender,
"Idenity test contract does not return the sender passed"
);
assert_eq!(gas_left, U256::from(99_844));
assert_eq!(gas_left, U256::from(96_540));
}
// Dispersion test sends byte array and expect the contract to 'disperse' the original elements with
@ -180,7 +180,7 @@ fn dispersion() {
result,
vec![0u8, 0, 125, 11, 197, 7, 255, 8, 19, 0]
);
assert_eq!(gas_left, U256::from(96_393));
assert_eq!(gas_left, U256::from(96_116));
}
#[test]
@ -208,7 +208,7 @@ fn suicide_not() {
result,
vec![0u8]
);
assert_eq!(gas_left, U256::from(96_725));
assert_eq!(gas_left, U256::from(96_461));
}
#[test]
@ -240,7 +240,7 @@ fn suicide() {
};
assert!(ext.suicides.contains(&refund));
assert_eq!(gas_left, U256::from(96_687));
assert_eq!(gas_left, U256::from(96_429));
}
#[test]
@ -270,7 +270,7 @@ fn create() {
assert!(ext.calls.contains(
&FakeCall {
call_type: FakeCallType::Create,
gas: U256::from(65_899),
gas: U256::from(62_545),
sender_address: None,
receive_address: None,
value: Some(1_000_000_000.into()),
@ -278,9 +278,52 @@ fn create() {
code_address: None,
}
));
assert_eq!(gas_left, U256::from(65_892));
assert_eq!(gas_left, U256::from(62_538));
}
#[test]
fn call_msg() {
::ethcore_logger::init_log();
let sender: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap();
let receiver: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
let contract_address: Address = "0d461d4174b4ae35775c4a342f1e5e1e4e6c4db5".parse().unwrap();
let mut params = ActionParams::default();
params.sender = sender.clone();
params.address = receiver.clone();
params.code_address = contract_address.clone();
params.gas = U256::from(100_000);
params.code = Some(Arc::new(load_sample!("call.wasm")));
params.data = Some(Vec::new());
let mut ext = FakeExt::new();
ext.balances.insert(receiver.clone(), U256::from(10000000000u64));
let gas_left = {
let mut interpreter = wasm_interpreter();
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
match result {
GasLeft::Known(gas_left) => gas_left,
GasLeft::NeedsReturn { .. } => { panic!("Call test should not return payload"); },
}
};
trace!(target: "wasm", "fake_calls: {:?}", &ext.calls);
assert!(ext.calls.contains(
&FakeCall {
call_type: FakeCallType::Call,
gas: U256::from(33_000),
sender_address: Some(receiver),
receive_address: Some(Address::from([99, 88, 77, 66, 55, 44, 33, 22, 11, 0, 11, 22, 33, 44, 55, 66, 77, 88, 99, 0])),
value: Some(1000000000.into()),
data: vec![129u8, 123, 113, 107, 101, 97],
code_address: Some(Address::from([99, 88, 77, 66, 55, 44, 33, 22, 11, 0, 11, 22, 33, 44, 55, 66, 77, 88, 99, 0])),
}
));
assert_eq!(gas_left, U256::from(95_699));
}
#[test]
fn call_code() {
@ -312,7 +355,7 @@ fn call_code() {
assert!(ext.calls.contains(
&FakeCall {
call_type: FakeCallType::Call,
gas: U256::from(98_713),
gas: U256::from(20_000),
sender_address: Some(sender),
receive_address: Some(receiver),
value: None,
@ -324,7 +367,7 @@ fn call_code() {
// siphash result
let res = LittleEndian::read_u32(&result[..]);
assert_eq!(res, 4198595614);
assert_eq!(gas_left, U256::from(93_855));
assert_eq!(gas_left, U256::from(90_550));
}
#[test]
@ -333,6 +376,7 @@ fn call_static() {
let sender: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
let receiver: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap();
let contract_address: Address = "0d461d4174b4ae35775c4a342f1e5e1e4e6c4db5".parse().unwrap();
let mut params = ActionParams::default();
params.sender = sender.clone();
@ -341,6 +385,7 @@ fn call_static() {
params.code = Some(Arc::new(load_sample!("call_static.wasm")));
params.data = Some(Vec::new());
params.value = ActionValue::transfer(1_000_000_000);
params.code_address = contract_address.clone();
let mut ext = FakeExt::new();
@ -357,9 +402,9 @@ fn call_static() {
assert!(ext.calls.contains(
&FakeCall {
call_type: FakeCallType::Call,
gas: U256::from(98_713),
sender_address: Some(sender),
receive_address: Some(receiver),
gas: U256::from(20_000),
sender_address: Some(receiver),
receive_address: Some("13077bfb00000000000000000000000000000000".parse().unwrap()),
value: None,
data: vec![1u8, 2, 3, 5, 7, 11],
code_address: Some("13077bfb00000000000000000000000000000000".parse().unwrap()),
@ -370,7 +415,7 @@ fn call_static() {
let res = LittleEndian::read_u32(&result[..]);
assert_eq!(res, 317632590);
assert_eq!(gas_left, U256::from(93_855));
assert_eq!(gas_left, U256::from(90_550));
}
// Realloc test
@ -393,7 +438,7 @@ fn realloc() {
}
};
assert_eq!(result, vec![0u8; 2]);
assert_eq!(gas_left, U256::from(96_723));
assert_eq!(gas_left, U256::from(96_445));
}
// Tests that contract's ability to read from a storage
@ -419,7 +464,7 @@ fn storage_read() {
};
assert_eq!(Address::from(&result[12..32]), address);
assert_eq!(gas_left, U256::from(99_767));
assert_eq!(gas_left, U256::from(96_463));
}
// Tests keccak calculation
@ -445,7 +490,7 @@ fn keccak() {
};
assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
assert_eq!(gas_left, U256::from(81_446));
assert_eq!(gas_left, U256::from(81_067));
}
// memcpy test.
@ -477,7 +522,7 @@ fn memcpy() {
};
assert_eq!(result, test_payload);
assert_eq!(gas_left, U256::from(72_216));
assert_eq!(gas_left, U256::from(71_940));
}
// memmove test.
@ -509,7 +554,7 @@ fn memmove() {
};
assert_eq!(result, test_payload);
assert_eq!(gas_left, U256::from(72_216));
assert_eq!(gas_left, U256::from(71_940));
}
// memset test
@ -534,7 +579,7 @@ fn memset() {
};
assert_eq!(result, vec![228u8; 8192]);
assert_eq!(gas_left, U256::from(72_196));
assert_eq!(gas_left, U256::from(71_921));
}
macro_rules! reqrep_test {
@ -591,7 +636,7 @@ fn math_add() {
U256::from_dec_str("1888888888888888888888888888887").unwrap(),
(&result[..]).into()
);
assert_eq!(gas_left, U256::from(95_524));
assert_eq!(gas_left, U256::from(95_384));
}
// multiplication
@ -613,7 +658,7 @@ fn math_mul() {
U256::from_dec_str("888888888888888888888888888887111111111111111111111111111112").unwrap(),
(&result[..]).into()
);
assert_eq!(gas_left, U256::from(94_674));
assert_eq!(gas_left, U256::from(94_374));
}
// subtraction
@ -635,7 +680,7 @@ fn math_sub() {
U256::from_dec_str("111111111111111111111111111111").unwrap(),
(&result[..]).into()
);
assert_eq!(gas_left, U256::from(95_516));
assert_eq!(gas_left, U256::from(95_372));
}
// subtraction with overflow
@ -677,7 +722,7 @@ fn math_div() {
U256::from_dec_str("1125000").unwrap(),
(&result[..]).into()
);
assert_eq!(gas_left, U256::from(88_514));
assert_eq!(gas_left, U256::from(88_356));
}
// This test checks the ability of wasm contract to invoke
@ -765,7 +810,7 @@ fn externs() {
"Gas limit requested and returned does not match"
);
assert_eq!(gas_left, U256::from(94_858));
assert_eq!(gas_left, U256::from(95_321));
}
#[test]
@ -791,7 +836,7 @@ fn embedded_keccak() {
};
assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
assert_eq!(gas_left, U256::from(81_446));
assert_eq!(gas_left, U256::from(81_067));
}
/// This test checks the correctness of log extern
@ -826,5 +871,5 @@ fn events() {
assert_eq!(&log_entry.data, b"gnihtemos");
assert_eq!(&result, b"gnihtemos");
assert_eq!(gas_left, U256::from(79_637));
assert_eq!(gas_left, U256::from(79_206));
}