This commit is contained in:
Péter Szilágyi 2017-11-28 10:01:09 +00:00 committed by GitHub
commit e76ff1feef
2 changed files with 29 additions and 17 deletions

View file

@ -352,7 +352,7 @@ func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem
// We replace the stack item so that it's available when the opCall instruction is // We replace the stack item so that it's available when the opCall instruction is
// called. This information is otherwise lost due to the dependency on *current* // called. This information is otherwise lost due to the dependency on *current*
// available gas. // available gas.
stack.data[stack.len()-1] = new(big.Int).SetUint64(cg) stack.data[stack.len()-1].SetUint64(cg)
if gas, overflow = math.SafeAdd(gas, cg); overflow { if gas, overflow = math.SafeAdd(gas, cg); overflow {
return 0, errGasUintOverflow return 0, errGasUintOverflow
@ -384,7 +384,7 @@ func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack,
// We replace the stack item so that it's available when the opCall instruction is // We replace the stack item so that it's available when the opCall instruction is
// called. This information is otherwise lost due to the dependency on *current* // called. This information is otherwise lost due to the dependency on *current*
// available gas. // available gas.
stack.data[stack.len()-1] = new(big.Int).SetUint64(cg) stack.data[stack.len()-1].SetUint64(cg)
if gas, overflow = math.SafeAdd(gas, cg); overflow { if gas, overflow = math.SafeAdd(gas, cg); overflow {
return 0, errGasUintOverflow return 0, errGasUintOverflow
@ -445,7 +445,7 @@ func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *St
// (availableGas - gas) * 63 / 64 // (availableGas - gas) * 63 / 64
// We replace the stack item so that it's available when the opCall instruction is // We replace the stack item so that it's available when the opCall instruction is
// called. // called.
stack.data[stack.len()-1] = new(big.Int).SetUint64(cg) stack.data[stack.len()-1].SetUint64(cg)
if gas, overflow = math.SafeAdd(gas, cg); overflow { if gas, overflow = math.SafeAdd(gas, cg); overflow {
return 0, errGasUintOverflow return 0, errGasUintOverflow
@ -472,7 +472,7 @@ func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stac
// (availableGas - gas) * 63 / 64 // (availableGas - gas) * 63 / 64
// We replace the stack item so that it's available when the opCall instruction is // We replace the stack item so that it's available when the opCall instruction is
// called. // called.
stack.data[stack.len()-1] = new(big.Int).SetUint64(cg) stack.data[stack.len()-1].SetUint64(cg)
if gas, overflow = math.SafeAdd(gas, cg); overflow { if gas, overflow = math.SafeAdd(gas, cg); overflow {
return 0, errGasUintOverflow return 0, errGasUintOverflow

View file

@ -18,6 +18,7 @@ package vm
import ( import (
"fmt" "fmt"
"math/big"
"sync/atomic" "sync/atomic"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -137,17 +138,18 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret
// to be uint256. Practically much less so feasible. // to be uint256. Practically much less so feasible.
pc = uint64(0) // program counter pc = uint64(0) // program counter
cost uint64 cost uint64
// copies used by tracer // copies used by tracer
stackCopy = newstack() // stackCopy needed for Tracer since stack is mutated by 63/64 gas rule
pcCopy uint64 // needed for the deferred Tracer pcCopy uint64 // needed for the deferred Tracer
gasCopy uint64 // for Tracer to log gas remaining before execution gasCopy uint64 // for Tracer to log gas remaining before execution
stackTop *big.Int // top stack item in case CALL* gas calculation modifies it
logged bool // deferred Tracer should ignore already logged steps logged bool // deferred Tracer should ignore already logged steps
) )
contract.Input = input contract.Input = input
defer func() { defer func() {
if err != nil && !logged && in.cfg.Debug { if err != nil && !logged && in.cfg.Debug {
in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, mem, stackCopy, contract, in.evm.depth, err) in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err)
} }
}() }()
@ -159,16 +161,20 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret
// Get the memory location of pc // Get the memory location of pc
op = contract.GetOp(pc) op = contract.GetOp(pc)
// If the transaction is being traced, track some execution metadata
if in.cfg.Debug { if in.cfg.Debug {
logged = false logged = false
pcCopy = pc pcCopy = pc
gasCopy = contract.Gas gasCopy = contract.Gas
stackCopy = newstack() stackTop = nil
for _, val := range stack.data {
stackCopy.push(val)
}
}
if op == CALL || op == CALLCODE || op == DELEGATECALL || op == STATICCALL {
if len(stack.data) > 0 {
stackTop = new(big.Int).Set(stack.data[stack.len()-1])
}
}
}
// Get the operation from the jump table matching the opcode and validate the // Get the operation from the jump table matching the opcode and validate the
// stack and make sure there enough stack items available to perform the operation // stack and make sure there enough stack items available to perform the operation
operation := in.cfg.JumpTable[op] operation := in.cfg.JumpTable[op]
@ -209,12 +215,19 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret
if memorySize > 0 { if memorySize > 0 {
mem.Resize(memorySize) mem.Resize(memorySize)
} }
// If the transaction is being traced, feed the opcode to the tracer before exec
if in.cfg.Debug { if in.cfg.Debug {
in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, mem, stackCopy, contract, in.evm.depth, err) // The top stack item is modified for CALL*, temporarily replace if done so
if stackTop != nil {
stackTop, stack.data[stack.len()-1] = stack.data[stack.len()-1], stackTop
}
in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err)
if stackTop != nil {
stackTop, stack.data[stack.len()-1] = stack.data[stack.len()-1], stackTop
}
logged = true logged = true
} }
// execute the operation // execute the operation
res, err := operation.execute(&pc, in.evm, contract, mem, stack) res, err := operation.execute(&pc, in.evm, contract, mem, stack)
// verifyPool is a build flag. Pool verification makes sure the integrity // verifyPool is a build flag. Pool verification makes sure the integrity
@ -227,7 +240,6 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret
if operation.returns { if operation.returns {
in.returnData = res in.returnData = res
} }
switch { switch {
case err != nil: case err != nil:
return nil, err return nil, err