PR review fixes

- Removing unused code
- Adding test cases
This commit is contained in:
shahafn 2025-02-03 11:51:25 +02:00
parent d0755a687e
commit 9d5a50277c
4 changed files with 742 additions and 66 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
// Copyright 2021 The go-ethereum Authors
// Copyright 2025 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
@ -20,8 +20,6 @@ import (
"encoding/json"
"errors"
"math/big"
"runtime"
"runtime/debug"
"sync/atomic"
"github.com/ethereum/go-ethereum/accounts/abi"
@ -31,7 +29,6 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
)
@ -48,19 +45,17 @@ type contractSizeWithOpcode struct {
}
type callFrameWithOpcodes struct {
Type vm.OpCode `json:"-"`
From common.Address `json:"from"`
Gas uint64 `json:"gas"`
GasUsed uint64 `json:"gasUsed"`
To *common.Address `json:"to,omitempty" rlp:"optional"`
Input []byte `json:"input" rlp:"optional"`
Output []byte `json:"output,omitempty" rlp:"optional"`
Error string `json:"error,omitempty" rlp:"optional"`
RevertReason string `json:"revertReason,omitempty"`
Logs []callLog `json:"logs,omitempty" rlp:"optional"`
// Placed at end on purpose. The RLP will be decoded to 0 instead of
// nil if there are non-empty elements after in the struct.
Value *big.Int `json:"value,omitempty" rlp:"optional"`
Type vm.OpCode `json:"-"`
From common.Address `json:"from"`
Gas uint64 `json:"gas"`
GasUsed uint64 `json:"gasUsed"`
To *common.Address `json:"to,omitempty" rlp:"optional"`
Input []byte `json:"input" rlp:"optional"`
Output []byte `json:"output,omitempty" rlp:"optional"`
Error string `json:"error,omitempty" rlp:"optional"`
RevertReason string `json:"revertReason,omitempty"`
Logs []callLog `json:"logs,omitempty" rlp:"optional"`
Value *big.Int `json:"value,omitempty" rlp:"optional"`
revertedSnapshot bool
AccessedSlots accessedSlots `json:"accessedSlots"`
@ -108,12 +103,18 @@ func (f *callFrameWithOpcodes) processOutput(output []byte, err error, reverted
}
type callFrameWithOpcodesMarshaling struct {
TypeString string `json:"type"`
Gas hexutil.Uint64
GasUsed hexutil.Uint64
Value *hexutil.Big
Input hexutil.Bytes
Output hexutil.Bytes
TypeString string `json:"type"`
Gas hexutil.Uint64
GasUsed hexutil.Uint64
Value *hexutil.Big
Input hexutil.Bytes
Output hexutil.Bytes
AccessedSlots accessedSlots `json:"accessedSlots"`
ExtCodeAccessInfo []common.Address `json:"extCodeAccessInfo"`
UsedOpcodes map[vm.OpCode]uint64 `json:"usedOpcodes"`
ContractSize map[common.Address]*contractSizeWithOpcode `json:"contractSize"`
OutOfGas bool `json:"outOfGas"`
Calls []callFrameWithOpcodes `json:"calls,omitempty"`
}
type accessedSlots struct {
@ -140,25 +141,13 @@ type erc7562Tracer struct {
callstackWithOpcodes []callFrameWithOpcodes
lastOpWithStack *opcodeWithPartialStack
Keccak map[string]struct{} `json:"keccak"`
}
// catchPanic handles panic recovery and logs the panic and stack trace.
func catchPanic() {
if r := recover(); r != nil {
// Retrieve the function name
pc, _, _, _ := runtime.Caller(1)
funcName := runtime.FuncForPC(pc).Name()
// Log the panic and function name
log.Error("Panic in", funcName, r)
debug.PrintStack()
}
transactionType uint8
}
// newErc7562Tracer returns a native go tracer which tracks
// call frames of a tx, and implements vm.EVMLogger.
func newErc7562Tracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
t, err := newErc7562TracerObject(ctx, cfg)
func newErc7562Tracer(ctx *tracers.Context, cfg json.RawMessage, _ *params.ChainConfig) (*tracers.Tracer, error) {
t, err := newErc7562TracerObject(cfg)
if err != nil {
return nil, err
}
@ -195,7 +184,7 @@ func getFullConfiguration(partial erc7562TracerConfig) erc7562TracerConfig {
return config
}
func newErc7562TracerObject(ctx *tracers.Context, cfg json.RawMessage) (*erc7562Tracer, error) {
func newErc7562TracerObject(cfg json.RawMessage) (*erc7562Tracer, error) {
var config erc7562TracerConfig
if cfg != nil {
if err := json.Unmarshal(cfg, &config); err != nil {
@ -212,14 +201,13 @@ func newErc7562TracerObject(ctx *tracers.Context, cfg json.RawMessage) (*erc7562
}
func (t *erc7562Tracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
defer catchPanic()
t.env = env
t.gasLimit = tx.Gas()
t.transactionType = tx.Type()
}
// OnEnter is called when EVM enters a new scope (via call, create or selfdestruct).
func (t *erc7562Tracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
defer catchPanic()
t.depth = depth
// Skip if tracing was interrupted
if t.interrupt.Load() {
@ -250,7 +238,7 @@ func (t *erc7562Tracer) OnEnter(depth int, typ byte, from common.Address, to com
t.callstackWithOpcodes = append(t.callstackWithOpcodes, call)
}
func (t *erc7562Tracer) captureEnd(output []byte, gasUsed uint64, err error, reverted bool) {
func (t *erc7562Tracer) captureEnd(output []byte, err error, reverted bool) {
if len(t.callstackWithOpcodes) != 1 {
return
}
@ -260,9 +248,8 @@ func (t *erc7562Tracer) captureEnd(output []byte, gasUsed uint64, err error, rev
// OnExit is called when EVM exits a scope, even if the scope didn't
// execute any code.
func (t *erc7562Tracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
defer catchPanic()
if depth == 0 {
t.captureEnd(output, gasUsed, err, reverted)
t.captureEnd(output, err, reverted)
return
}
@ -287,7 +274,6 @@ func (t *erc7562Tracer) OnExit(depth int, output []byte, gasUsed uint64, err err
}
func (t *erc7562Tracer) OnTxEnd(receipt *types.Receipt, err error) {
defer catchPanic()
// Error happened during tx validation.
if err != nil {
return
@ -300,7 +286,6 @@ func (t *erc7562Tracer) OnTxEnd(receipt *types.Receipt, err error) {
}
func (t *erc7562Tracer) OnLog(log1 *types.Log) {
defer catchPanic()
// Only logs need to be captured via opcode processing
if !t.config.WithLog {
return
@ -321,7 +306,6 @@ func (t *erc7562Tracer) OnLog(log1 *types.Log) {
// GetResult returns the json-encoded nested list of call traces, and any
// error arising from the encoding or forceful termination (via `Stop`).
func (t *erc7562Tracer) GetResult() (json.RawMessage, error) {
defer catchPanic()
if len(t.callstackWithOpcodes) != 1 {
return nil, errors.New("incorrect number of top-level calls")
}
@ -356,7 +340,6 @@ func (t *erc7562Tracer) GetResult() (json.RawMessage, error) {
// Stop terminates execution of the tracer at the first opportune moment.
func (t *erc7562Tracer) Stop(err error) {
defer catchPanic()
t.reason = err
t.interrupt.Store(true)
}
@ -375,7 +358,6 @@ func (t *erc7562Tracer) clearFailedLogs(cf *callFrameWithOpcodes, parentFailed b
}
func (t *erc7562Tracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
defer catchPanic()
opcode := vm.OpCode(op)
var opcodeWithStack *opcodeWithPartialStack
stackSize := len(scope.StackData())
@ -413,14 +395,14 @@ func (t *erc7562Tracer) handleGasObserved(opcode vm.OpCode, currentCallFrame *ca
// [OP-012]
pendingGasObserved := t.lastOpWithStack.Opcode == vm.GAS && !isCall(opcode)
if pendingGasObserved {
incrementCount(currentCallFrame.UsedOpcodes, vm.GAS)
currentCallFrame.UsedOpcodes[vm.GAS]++
}
}
func (t *erc7562Tracer) storeUsedOpcode(opcode vm.OpCode, currentCallFrame *callFrameWithOpcodes) {
// ignore "unimportant" opcodes
if opcode != vm.GAS && !t.isIgnoredOpcode(opcode) {
incrementCount(currentCallFrame.UsedOpcodes, opcode)
currentCallFrame.UsedOpcodes[opcode]++
}
}
@ -439,11 +421,11 @@ func (t *erc7562Tracer) handleStorageAccess(opcode vm.OpCode, scope tracing.OpCo
currentCallFrame.AccessedSlots.Reads[slotHex] = append(currentCallFrame.AccessedSlots.Reads[slotHex], t.env.StateDB.GetState(addr, slot).Hex())
}
} else if opcode == vm.SSTORE {
incrementCount(currentCallFrame.AccessedSlots.Writes, slotHex)
currentCallFrame.AccessedSlots.Writes[slotHex]++
} else if opcode == vm.TLOAD {
incrementCount(currentCallFrame.AccessedSlots.TransientReads, slotHex)
currentCallFrame.AccessedSlots.TransientReads[slotHex]++
} else {
incrementCount(currentCallFrame.AccessedSlots.TransientWrites, slotHex)
currentCallFrame.AccessedSlots.TransientWrites[slotHex]++
}
}
}
@ -480,7 +462,7 @@ func (t *erc7562Tracer) handleAccessedContractSize(opcode vm.OpCode, scope traci
n = 1
}
addr := common.BytesToAddress(peepStack(scope.StackData(), n).Bytes())
if _, ok := currentCallFrame.ContractSize[addr]; !ok && !isAllowedPrecompile(addr) {
if _, ok := currentCallFrame.ContractSize[addr]; !ok {
currentCallFrame.ContractSize[addr] = &contractSizeWithOpcode{
ContractSize: len(t.env.StateDB.GetCode(addr)),
Opcode: opcode,
@ -537,14 +519,3 @@ func defaultIgnoredOpcodes() map[vm.OpCode]struct{} {
return ignored
}
// not using 'isPrecompiled' to only allow the ones defined by the ERC-7562 as stateless precompiles
// [OP-062]
func isAllowedPrecompile(addr common.Address) bool {
addrInt := addr.Big()
return addrInt.Cmp(big.NewInt(0)) == 1 && addrInt.Cmp(big.NewInt(10)) == -1
}
func incrementCount[K comparable](m map[K]uint64, k K) {
m[k] = m[k] + 1
}