core/vm: track 63/64 call gas off stack (#15563)

* core/vm: track 63/64 call gas off stack

Gas calculations in gasCall* relayed the available gas for calls by
replacing it on the stack. This lead to inconsistent traces, which we
papered over by copying the pre-execution stack in trace mode.

This change relays available gas using a temporary variable, off the
stack, and allows removing the weird copy.

* core/vm: remove stackCopy

* core/vm: pop call gas into pool

* core/vm: to -> addr
This commit is contained in:
Felix Lange
2017-11-28 20:05:49 +01:00
committed by Péter Szilágyi
parent 8f35e3086c
commit be12392fba
4 changed files with 55 additions and 99 deletions

View File

@ -603,24 +603,20 @@ func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
}
func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
gas := stack.pop().Uint64()
// pop gas and value of the stack.
addr, value := stack.pop(), stack.pop()
// Pop gas. The actual gas in in evm.callGasTemp.
evm.interpreter.intPool.put(stack.pop())
gas := evm.callGasTemp
// Pop other call parameters.
addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
toAddr := common.BigToAddress(addr)
value = math.U256(value)
// pop input size and offset
inOffset, inSize := stack.pop(), stack.pop()
// pop return size and offset
retOffset, retSize := stack.pop(), stack.pop()
address := common.BigToAddress(addr)
// Get the arguments from the memory
// Get the arguments from the memory.
args := memory.Get(inOffset.Int64(), inSize.Int64())
if value.Sign() != 0 {
gas += params.CallStipend
}
ret, returnGas, err := evm.Call(contract, address, args, gas, value)
ret, returnGas, err := evm.Call(contract, toAddr, args, gas, value)
if err != nil {
stack.push(new(big.Int))
} else {
@ -636,25 +632,20 @@ func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
}
func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
gas := stack.pop().Uint64()
// pop gas and value of the stack.
addr, value := stack.pop(), stack.pop()
// Pop gas. The actual gas is in evm.callGasTemp.
evm.interpreter.intPool.put(stack.pop())
gas := evm.callGasTemp
// Pop other call parameters.
addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
toAddr := common.BigToAddress(addr)
value = math.U256(value)
// pop input size and offset
inOffset, inSize := stack.pop(), stack.pop()
// pop return size and offset
retOffset, retSize := stack.pop(), stack.pop()
address := common.BigToAddress(addr)
// Get the arguments from the memory
// Get arguments from the memory.
args := memory.Get(inOffset.Int64(), inSize.Int64())
if value.Sign() != 0 {
gas += params.CallStipend
}
ret, returnGas, err := evm.CallCode(contract, address, args, gas, value)
ret, returnGas, err := evm.CallCode(contract, toAddr, args, gas, value)
if err != nil {
stack.push(new(big.Int))
} else {
@ -670,9 +661,13 @@ func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
}
func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
gas, to, inOffset, inSize, outOffset, outSize := stack.pop().Uint64(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
toAddr := common.BigToAddress(to)
// Pop gas. The actual gas is in evm.callGasTemp.
evm.interpreter.intPool.put(stack.pop())
gas := evm.callGasTemp
// Pop other call parameters.
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
toAddr := common.BigToAddress(addr)
// Get arguments from the memory.
args := memory.Get(inOffset.Int64(), inSize.Int64())
ret, returnGas, err := evm.DelegateCall(contract, toAddr, args, gas)
@ -682,30 +677,25 @@ func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, st
stack.push(big.NewInt(1))
}
if err == nil || err == errExecutionReverted {
memory.Set(outOffset.Uint64(), outSize.Uint64(), ret)
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
contract.Gas += returnGas
evm.interpreter.intPool.put(to, inOffset, inSize, outOffset, outSize)
evm.interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize)
return ret, nil
}
func opStaticCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
// pop gas
gas := stack.pop().Uint64()
// pop address
addr := stack.pop()
// pop input size and offset
inOffset, inSize := stack.pop(), stack.pop()
// pop return size and offset
retOffset, retSize := stack.pop(), stack.pop()
address := common.BigToAddress(addr)
// Get the arguments from the memory
// Pop gas. The actual gas is in evm.callGasTemp.
evm.interpreter.intPool.put(stack.pop())
gas := evm.callGasTemp
// Pop other call parameters.
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
toAddr := common.BigToAddress(addr)
// Get arguments from the memory.
args := memory.Get(inOffset.Int64(), inSize.Int64())
ret, returnGas, err := evm.StaticCall(contract, address, args, gas)
ret, returnGas, err := evm.StaticCall(contract, toAddr, args, gas)
if err != nil {
stack.push(new(big.Int))
} else {