mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-16 17:03:46 +00:00
core/vm: avoid unnecessary stack memory copies during gas calc
This commit is contained in:
parent
0f7fbb85d6
commit
8622119625
2 changed files with 29 additions and 17 deletions
|
|
@ -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
|
||||
// called. This information is otherwise lost due to the dependency on *current*
|
||||
// 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 {
|
||||
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
|
||||
// called. This information is otherwise lost due to the dependency on *current*
|
||||
// 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 {
|
||||
return 0, errGasUintOverflow
|
||||
|
|
@ -445,7 +445,7 @@ func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *St
|
|||
// (availableGas - gas) * 63 / 64
|
||||
// We replace the stack item so that it's available when the opCall instruction is
|
||||
// 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 {
|
||||
return 0, errGasUintOverflow
|
||||
|
|
@ -472,7 +472,7 @@ func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stac
|
|||
// (availableGas - gas) * 63 / 64
|
||||
// We replace the stack item so that it's available when the opCall instruction is
|
||||
// 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 {
|
||||
return 0, errGasUintOverflow
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package vm
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sync/atomic"
|
||||
|
||||
"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.
|
||||
pc = uint64(0) // program counter
|
||||
cost uint64
|
||||
|
||||
// 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
|
||||
gasCopy uint64 // for Tracer to log gas remaining before execution
|
||||
logged bool // deferred Tracer should ignore already logged steps
|
||||
pcCopy uint64 // needed for the deferred Tracer
|
||||
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
|
||||
)
|
||||
contract.Input = input
|
||||
|
||||
defer func() {
|
||||
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
|
||||
op = contract.GetOp(pc)
|
||||
|
||||
// If the transaction is being traced, track some execution metadata
|
||||
if in.cfg.Debug {
|
||||
logged = false
|
||||
|
||||
pcCopy = pc
|
||||
gasCopy = contract.Gas
|
||||
stackCopy = newstack()
|
||||
for _, val := range stack.data {
|
||||
stackCopy.push(val)
|
||||
stackTop = nil
|
||||
|
||||
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
|
||||
// stack and make sure there enough stack items available to perform the operation
|
||||
operation := in.cfg.JumpTable[op]
|
||||
|
|
@ -209,12 +215,19 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret
|
|||
if memorySize > 0 {
|
||||
mem.Resize(memorySize)
|
||||
}
|
||||
|
||||
// If the transaction is being traced, feed the opcode to the tracer before exec
|
||||
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
|
||||
}
|
||||
|
||||
// execute the operation
|
||||
res, err := operation.execute(&pc, in.evm, contract, mem, stack)
|
||||
// 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 {
|
||||
in.returnData = res
|
||||
}
|
||||
|
||||
switch {
|
||||
case err != nil:
|
||||
return nil, err
|
||||
|
|
|
|||
Loading…
Reference in a new issue