PR review fixes
- Removing unused code - Adding test cases
This commit is contained in:
parent
d0755a687e
commit
9d5a50277c
135
eth/tracers/internal/tracetest/testdata/erc7562_tracer/erc7562Tracer.test_deployer.json
vendored
Normal file
135
eth/tracers/internal/tracetest/testdata/erc7562_tracer/erc7562Tracer.test_deployer.json
vendored
Normal file
File diff suppressed because one or more lines are too long
135
eth/tracers/internal/tracetest/testdata/erc7562_tracer/erc7562Tracer.test_paymaster.json
vendored
Normal file
135
eth/tracers/internal/tracetest/testdata/erc7562_tracer/erc7562Tracer.test_paymaster.json
vendored
Normal file
File diff suppressed because one or more lines are too long
435
eth/tracers/internal/tracetest/testdata/erc7562_tracer/erc7562Tracer.test_simple.json
vendored
Normal file
435
eth/tracers/internal/tracetest/testdata/erc7562_tracer/erc7562Tracer.test_simple.json
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue