diff --git a/ethcore/res/wasm-tests b/ethcore/res/wasm-tests index d6185ea16..d9d6133c1 160000 --- a/ethcore/res/wasm-tests +++ b/ethcore/res/wasm-tests @@ -1 +1 @@ -Subproject commit d6185ea16eaba7ff685c069c2064819f9549c4d7 +Subproject commit d9d6133c1bc5dca4c74c9eb758a39546a0d46b45 diff --git a/ethcore/wasm/src/env.rs b/ethcore/wasm/src/env.rs index ed4bda68b..cae673858 100644 --- a/ethcore/wasm/src/env.rs +++ b/ethcore/wasm/src/env.rs @@ -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( diff --git a/ethcore/wasm/src/lib.rs b/ethcore/wasm/src/lib.rs index 30ce03665..5b4e59fcb 100644 --- a/ethcore/wasm/src/lib.rs +++ b/ethcore/wasm/src/lib.rs @@ -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, diff --git a/ethcore/wasm/src/runtime.rs b/ethcore/wasm/src/runtime.rs index bad325fbf..700233951 100644 --- a/ethcore/wasm/src/runtime.rs +++ b/ethcore/wasm/src/runtime.rs @@ -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::()? 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, diff --git a/ethcore/wasm/src/tests.rs b/ethcore/wasm/src/tests.rs index a387f9292..115199aeb 100644 --- a/ethcore/wasm/src/tests.rs +++ b/ethcore/wasm/src/tests.rs @@ -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)); }