diff --git a/src/evm/ext.rs b/src/evm/ext.rs index 748bc89da..83f093bcf 100644 --- a/src/evm/ext.rs +++ b/src/evm/ext.rs @@ -57,7 +57,7 @@ pub trait Ext { gas: &U256, sender_address: &Address, receive_address: &Address, - value: Option<&U256>, + value: Option, data: &[u8], code_address: &Address, output: &mut [u8]) -> MessageCallResult; diff --git a/src/evm/interpreter.rs b/src/evm/interpreter.rs index 276f2873b..7657b1bbe 100644 --- a/src/evm/interpreter.rs +++ b/src/evm/interpreter.rs @@ -566,66 +566,43 @@ impl Interpreter { } }; }, - instructions::DELEGATECALL => { - let call_gas = stack.pop_back(); - let code_address = stack.pop_back(); - let code_address = u256_to_address(&code_address); - - let in_off = stack.pop_back(); - let in_size = stack.pop_back(); - let out_off = stack.pop_back(); - let out_size = stack.pop_back(); - - let can_call = ext.depth() < ext.schedule().max_depth; - if !can_call { - stack.push(U256::zero()); - return Ok(InstructionResult::UnusedGas(call_gas)); - } - - let call_result = { - // we need to write and read from memory in the same time - // and we don't want to copy - let input = unsafe { ::std::mem::transmute(mem.read_slice(in_off, in_size)) }; - let output = mem.writeable_slice(out_off, out_size); - ext.call(&call_gas, ¶ms.sender, ¶ms.address, None, input, &code_address, output) - }; - - return match call_result { - MessageCallResult::Success(gas_left) => { - stack.push(U256::one()); - Ok(InstructionResult::UnusedGas(gas_left)) - }, - MessageCallResult::Failed => { - stack.push(U256::zero()); - Ok(InstructionResult::Ok) - } - }; - }, - instructions::CALL | instructions::CALLCODE => { + instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL => { assert!(ext.schedule().call_value_transfer_gas > ext.schedule().call_stipend, "overflow possible"); let call_gas = stack.pop_back(); let code_address = stack.pop_back(); let code_address = u256_to_address(&code_address); - let value = stack.pop_back(); + let value = match instruction == instructions::DELEGATECALL { + true => None, + false => Some(stack.pop_back()) + }; let in_off = stack.pop_back(); let in_size = stack.pop_back(); let out_off = stack.pop_back(); let out_size = stack.pop_back(); - let call_gas = call_gas + match value > U256::zero() { + // Add stipend (only CALL|CALLCODE when value > 0) + let call_gas = call_gas + value.map_or_else(U256::zero, |val| match val > U256::zero() { true => U256::from(ext.schedule().call_stipend), false => U256::zero() + }); + + // Get sender & receive addresses, check if we have balance + let (sender_address, receive_address, has_balance) = match instruction { + instructions::CALL => { + let has_balance = ext.balance(¶ms.address) >= value.unwrap(); + (¶ms.address, &code_address, has_balance) + }, + instructions::CALLCODE => { + let has_balance = ext.balance(¶ms.address) >= value.unwrap(); + (¶ms.address, ¶ms.address, has_balance) + }, + instructions::DELEGATECALL => (¶ms.sender, ¶ms.address, true), + _ => panic!(format!("Unexpected instruction {} in CALL branch.", instruction)) }; - let (sender_address, receive_address) = match instruction == instructions::CALL { - true => (¶ms.address, &code_address), - false => (¶ms.address, ¶ms.address) - }; - - let can_call = ext.balance(¶ms.address) >= value && ext.depth() < ext.schedule().max_depth; - + let can_call = has_balance && ext.depth() < ext.schedule().max_depth; if !can_call { stack.push(U256::zero()); return Ok(InstructionResult::UnusedGas(call_gas)); @@ -636,7 +613,7 @@ impl Interpreter { // and we don't want to copy let input = unsafe { ::std::mem::transmute(mem.read_slice(in_off, in_size)) }; let output = mem.writeable_slice(out_off, out_size); - ext.call(&call_gas, sender_address, receive_address, Some(&value), input, &code_address, output) + ext.call(&call_gas, sender_address, receive_address, value, input, &code_address, output) }; return match call_result { diff --git a/src/evm/tests.rs b/src/evm/tests.rs index cf4262914..ad81cf877 100644 --- a/src/evm/tests.rs +++ b/src/evm/tests.rs @@ -63,7 +63,7 @@ impl Ext for FakeExt { _gas: &U256, _sender_address: &Address, _receive_address: &Address, - _value: Option<&U256>, + _value: Option, _data: &[u8], _code_address: &Address, _output: &mut [u8]) -> MessageCallResult { diff --git a/src/externalities.rs b/src/externalities.rs index d8b5d6110..f9a79c3c0 100644 --- a/src/externalities.rs +++ b/src/externalities.rs @@ -138,7 +138,7 @@ impl<'a> Ext for Externalities<'a> { gas: &U256, sender_address: &Address, receive_address: &Address, - value: Option<&U256>, + value: Option, data: &[u8], code_address: &Address, output: &mut [u8]) -> MessageCallResult { @@ -156,7 +156,7 @@ impl<'a> Ext for Externalities<'a> { }; if let Some(value) = value { - params.value = ActionValue::Transfer(value.clone()); + params.value = ActionValue::Transfer(value); } let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth); diff --git a/src/tests/executive.rs b/src/tests/executive.rs index 0604c9992..a94fd1605 100644 --- a/src/tests/executive.rs +++ b/src/tests/executive.rs @@ -103,7 +103,7 @@ impl<'a> Ext for TestExt<'a> { gas: &U256, _sender_address: &Address, receive_address: &Address, - value: Option<&U256>, + value: Option, data: &[u8], _code_address: &Address, _output: &mut [u8]) -> MessageCallResult { @@ -111,7 +111,7 @@ impl<'a> Ext for TestExt<'a> { data: data.to_vec(), destination: Some(receive_address.clone()), gas_limit: *gas, - value: *value.unwrap() + value: value.unwrap() }); MessageCallResult::Success(*gas) }