eth/tracers: improve tracing performance (#23016)

Improves the performance of debug.traceTransaction
This commit is contained in:
Martin Holst Swende
2021-07-01 09:15:04 +02:00
committed by GitHub
parent bbbeb7d8ba
commit f5f906dd0d
5 changed files with 105 additions and 34 deletions

View File

@ -29,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
)
// Storage represents a contract's storage.
@ -66,7 +67,7 @@ type StructLog struct {
GasCost uint64 `json:"gasCost"`
Memory []byte `json:"memory"`
MemorySize int `json:"memSize"`
Stack []*big.Int `json:"stack"`
Stack []uint256.Int `json:"stack"`
ReturnData []byte `json:"returnData"`
Storage map[common.Hash]common.Hash `json:"-"`
Depth int `json:"depth"`
@ -76,7 +77,6 @@ type StructLog struct {
// overrides for gencodec
type structLogMarshaling struct {
Stack []*math.HexOrDecimal256
Gas math.HexOrDecimal64
GasCost math.HexOrDecimal64
Memory hexutil.Bytes
@ -135,6 +135,14 @@ func NewStructLogger(cfg *LogConfig) *StructLogger {
return logger
}
// Reset clears the data held by the logger.
func (l *StructLogger) Reset() {
l.storage = make(map[common.Address]Storage)
l.output = make([]byte, 0)
l.logs = l.logs[:0]
l.err = nil
}
// CaptureStart implements the Tracer interface to initialize the tracing operation.
func (l *StructLogger) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
}
@ -157,16 +165,16 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
copy(mem, memory.Data())
}
// Copy a snapshot of the current stack state to a new buffer
var stck []*big.Int
var stck []uint256.Int
if !l.cfg.DisableStack {
stck = make([]*big.Int, len(stack.Data()))
stck = make([]uint256.Int, len(stack.Data()))
for i, item := range stack.Data() {
stck[i] = new(big.Int).Set(item.ToBig())
stck[i] = item
}
}
// Copy a snapshot of the current storage to a new container
var storage Storage
if !l.cfg.DisableStorage {
if !l.cfg.DisableStorage && (op == SLOAD || op == SSTORE) {
// initialise new changed values storage container for this contract
// if not present.
if l.storage[contract.Address()] == nil {
@ -179,16 +187,16 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
value = env.StateDB.GetState(contract.Address(), address)
)
l.storage[contract.Address()][address] = value
}
// capture SSTORE opcodes and record the written entry in the local storage.
if op == SSTORE && stack.len() >= 2 {
storage = l.storage[contract.Address()].Copy()
} else if op == SSTORE && stack.len() >= 2 {
// capture SSTORE opcodes and record the written entry in the local storage.
var (
value = common.Hash(stack.data[stack.len()-2].Bytes32())
address = common.Hash(stack.data[stack.len()-1].Bytes32())
)
l.storage[contract.Address()][address] = value
storage = l.storage[contract.Address()].Copy()
}
storage = l.storage[contract.Address()].Copy()
}
var rdata []byte
if !l.cfg.DisableReturnData {
@ -238,7 +246,7 @@ func WriteTrace(writer io.Writer, logs []StructLog) {
if len(log.Stack) > 0 {
fmt.Fprintln(writer, "Stack:")
for i := len(log.Stack) - 1; i >= 0; i-- {
fmt.Fprintf(writer, "%08d %x\n", len(log.Stack)-i-1, math.PaddedBigBytes(log.Stack[i], 32))
fmt.Fprintf(writer, "%08d %s\n", len(log.Stack)-i-1, log.Stack[i].Hex())
}
}
if len(log.Memory) > 0 {
@ -314,7 +322,7 @@ func (t *mdLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64
// format stack
var a []string
for _, elem := range stack.data {
a = append(a, fmt.Sprintf("%v", elem.String()))
a = append(a, elem.Hex())
}
b := fmt.Sprintf("[%v]", strings.Join(a, ","))
fmt.Fprintf(t.out, "%10v |", b)