mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-17 09:23:48 +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
|
// 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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue