Skip to content

Commit 56640f4

Browse files
s1naziogaschr
authored andcommitted
eth/tracers: avoid panic in state test runner (#30332)
Make tracers more robust by handling `nil` receipt as input. Also pass in a receipt with gas used in the state test runner. Closes ethereum/go-ethereum#30117. --------- Co-authored-by: Sina Mahmoodi <[email protected]>
1 parent 953cfad commit 56640f4

24 files changed

+172
-118
lines changed

cmd/evm/internal/t8ntool/execution.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ type rejectedTx struct {
124124
// Apply applies a set of transactions to a pre-state
125125
func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
126126
txs types.Transactions, miningReward int64,
127-
getTracerFn func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error)) (*state.StateDB, *ExecutionResult, []byte, error) {
127+
getTracerFn func(txIndex int, txHash common.Hash, chainConfig *params.ChainConfig) (*tracers.Tracer, io.WriteCloser, error)) (*state.StateDB, *ExecutionResult, []byte, error) {
128128
// Capture errors for BLOCKHASH operation, if we haven't been supplied the
129129
// required blockhashes
130130
var hashError error
@@ -204,7 +204,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
204204
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
205205
continue
206206
}
207-
tracer, traceOutput, err := getTracerFn(txIndex, tx.Hash())
207+
tracer, traceOutput, err := getTracerFn(txIndex, tx.Hash(), chainConfig)
208208
if err != nil {
209209
return nil, nil, err
210210
}

cmd/evm/internal/t8ntool/transition.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,9 @@ type input struct {
8888

8989
func Transition(ctx *cli.Context) error {
9090

91-
var getTracer = func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error) { return nil, nil, nil }
91+
var getTracer = func(txIndex int, txHash common.Hash, chainConfig *params.ChainConfig) (*tracers.Tracer, io.WriteCloser, error) {
92+
return nil, nil, nil
93+
}
9294

9395
baseDir, err := createBasedir(ctx)
9496
if err != nil {
@@ -109,7 +111,7 @@ func Transition(ctx *cli.Context) error {
109111
prevFile.Close()
110112
}
111113
}()
112-
getTracer = func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error) {
114+
getTracer = func(txIndex int, txHash common.Hash, _ *params.ChainConfig) (*tracers.Tracer, io.WriteCloser, error) {
113115
if prevFile != nil {
114116
prevFile.Close()
115117
}

cmd/utils/flags.go

+3-10
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,7 @@ var (
601601
VMTraceJsonConfigFlag = &cli.StringFlag{
602602
Name: "vmtrace.jsonconfig",
603603
Usage: "Tracer configuration (JSON)",
604+
Value: "{}",
604605
Category: flags.VMCategory,
605606
}
606607
// API options.
@@ -2084,13 +2085,8 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
20842085
// VM tracing config.
20852086
if ctx.IsSet(VMTraceFlag.Name) {
20862087
if name := ctx.String(VMTraceFlag.Name); name != "" {
2087-
var config string
2088-
if ctx.IsSet(VMTraceJsonConfigFlag.Name) {
2089-
config = ctx.String(VMTraceJsonConfigFlag.Name)
2090-
}
2091-
20922088
cfg.VMTrace = name
2093-
cfg.VMTraceJsonConfig = config
2089+
cfg.VMTraceJsonConfig = ctx.String(VMTraceJsonConfigFlag.Name)
20942090
}
20952091
}
20962092
}
@@ -2423,10 +2419,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
24232419
vmcfg := vm.Config{EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name)}
24242420
if ctx.IsSet(VMTraceFlag.Name) {
24252421
if name := ctx.String(VMTraceFlag.Name); name != "" {
2426-
var config json.RawMessage
2427-
if ctx.IsSet(VMTraceJsonConfigFlag.Name) {
2428-
config = json.RawMessage(ctx.String(VMTraceJsonConfigFlag.Name))
2429-
}
2422+
config := json.RawMessage(ctx.String(VMTraceJsonConfigFlag.Name))
24302423
t, err := tracers.LiveDirectory.New(name, config)
24312424
if err != nil {
24322425
Fatalf("Failed to create tracer %q: %v", name, err)

core/tracing/hooks.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,8 @@ type VMContext struct {
5454
Time uint64
5555
Random *common.Hash
5656
// Effective tx gas price
57-
GasPrice *big.Int
58-
ChainConfig *params.ChainConfig
59-
StateDB StateDB
57+
GasPrice *big.Int
58+
StateDB StateDB
6059
}
6160

6261
// BlockEvent is emitted upon tracing an incoming block.

core/vm/evm.go

-1
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,6 @@ func (evm *EVM) GetVMContext() *tracing.VMContext {
563563
Time: evm.Context.Time,
564564
Random: evm.Context.Random,
565565
GasPrice: evm.TxContext.GasPrice,
566-
ChainConfig: evm.ChainConfig(),
567566
StateDB: evm.StateDB,
568567
}
569568
}

core/vm/runtime/runtime_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode
330330
cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
331331
cfg.GasLimit = gas
332332
if len(tracerCode) > 0 {
333-
tracer, err := tracers.DefaultDirectory.New(tracerCode, new(tracers.Context), nil)
333+
tracer, err := tracers.DefaultDirectory.New(tracerCode, new(tracers.Context), nil, cfg.ChainConfig)
334334
if err != nil {
335335
b.Fatal(err)
336336
}
@@ -822,7 +822,7 @@ func TestRuntimeJSTracer(t *testing.T) {
822822
statedb.SetCode(common.HexToAddress("0xee"), calleeCode)
823823
statedb.SetCode(common.HexToAddress("0xff"), suicideCode)
824824

825-
tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil)
825+
tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil, params.MergedTestChainConfig)
826826
if err != nil {
827827
t.Fatal(err)
828828
}
@@ -857,7 +857,7 @@ func TestJSTracerCreateTx(t *testing.T) {
857857
code := []byte{byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN)}
858858

859859
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
860-
tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil)
860+
tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil, params.MergedTestChainConfig)
861861
if err != nil {
862862
t.Fatal(err)
863863
}

eth/backend.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
252252
}
253253
)
254254
if config.VMTrace != "" {
255-
var traceConfig json.RawMessage
255+
traceConfig := json.RawMessage("{}")
256256
if config.VMTraceJsonConfig != "" {
257257
traceConfig = json.RawMessage(config.VMTraceJsonConfig)
258258
}

eth/tracers/api.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,7 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor
987987
Stop: logger.Stop,
988988
}
989989
} else {
990-
tracer, err = DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig)
990+
tracer, err = DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig, api.backend.ChainConfig())
991991
if err != nil {
992992
return nil, err
993993
}

eth/tracers/dir.go

+9-5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222

2323
"github.com/ethereum/go-ethereum/common"
2424
"github.com/ethereum/go-ethereum/core/tracing"
25+
"github.com/ethereum/go-ethereum/params"
2526
)
2627

2728
// Context contains some contextual infos for a transaction execution that is not
@@ -44,8 +45,8 @@ type Tracer struct {
4445
Stop func(err error)
4546
}
4647

47-
type ctorFn func(*Context, json.RawMessage) (*Tracer, error)
48-
type jsCtorFn func(string, *Context, json.RawMessage) (*Tracer, error)
48+
type ctorFn func(*Context, json.RawMessage, *params.ChainConfig) (*Tracer, error)
49+
type jsCtorFn func(string, *Context, json.RawMessage, *params.ChainConfig) (*Tracer, error)
4950

5051
type elem struct {
5152
ctor ctorFn
@@ -78,12 +79,15 @@ func (d *directory) RegisterJSEval(f jsCtorFn) {
7879
// New returns a new instance of a tracer, by iterating through the
7980
// registered lookups. Name is either name of an existing tracer
8081
// or an arbitrary JS code.
81-
func (d *directory) New(name string, ctx *Context, cfg json.RawMessage) (*Tracer, error) {
82+
func (d *directory) New(name string, ctx *Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*Tracer, error) {
83+
if len(cfg) == 0 {
84+
cfg = json.RawMessage("{}")
85+
}
8286
if elem, ok := d.elems[name]; ok {
83-
return elem.ctor(ctx, cfg)
87+
return elem.ctor(ctx, cfg, chainConfig)
8488
}
8589
// Assume JS code
86-
return d.jsEval(name, ctx, cfg)
90+
return d.jsEval(name, ctx, cfg, chainConfig)
8791
}
8892

8993
// IsJS will return true if the given tracer will evaluate

eth/tracers/internal/tracetest/calltrace_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
120120
)
121121
triedb.Close()
122122

123-
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
123+
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig, test.Genesis.Config)
124124
if err != nil {
125125
t.Fatalf("failed to create call tracer: %v", err)
126126
}
@@ -228,7 +228,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
228228
b.ReportAllocs()
229229
b.ResetTimer()
230230
for i := 0; i < b.N; i++ {
231-
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil)
231+
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil, test.Genesis.Config)
232232
if err != nil {
233233
b.Fatalf("failed to create call tracer: %v", err)
234234
}
@@ -265,7 +265,7 @@ func TestInternals(t *testing.T) {
265265
}
266266
)
267267
mkTracer := func(name string, cfg json.RawMessage) *tracers.Tracer {
268-
tr, err := tracers.DefaultDirectory.New(name, nil, cfg)
268+
tr, err := tracers.DefaultDirectory.New(name, nil, cfg, config)
269269
if err != nil {
270270
t.Fatalf("failed to create call tracer: %v", err)
271271
}

eth/tracers/internal/tracetest/flat_calltrace_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
8989
defer triedb.Close()
9090

9191
// Create the tracer, the EVM environment and run it
92-
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
92+
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig, test.Genesis.Config)
9393
if err != nil {
9494
return fmt.Errorf("failed to create call tracer: %v", err)
9595
}

eth/tracers/internal/tracetest/prestate_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
9898
)
9999
defer triedb.Close()
100100

101-
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
101+
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig, test.Genesis.Config)
102102
if err != nil {
103103
t.Fatalf("failed to create call tracer: %v", err)
104104
}

eth/tracers/js/goja.go

+10-7
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"github.com/ethereum/go-ethereum/core/types"
2929
"github.com/ethereum/go-ethereum/eth/tracers"
3030
"github.com/ethereum/go-ethereum/eth/tracers/internal"
31+
"github.com/ethereum/go-ethereum/params"
3132
"github.com/holiman/uint256"
3233

3334
"github.com/ethereum/go-ethereum/common"
@@ -46,10 +47,10 @@ func init() {
4647
if err != nil {
4748
panic(err)
4849
}
49-
type ctorFn = func(*tracers.Context, json.RawMessage) (*tracers.Tracer, error)
50+
type ctorFn = func(*tracers.Context, json.RawMessage, *params.ChainConfig) (*tracers.Tracer, error)
5051
lookup := func(code string) ctorFn {
51-
return func(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) {
52-
return newJsTracer(code, ctx, cfg)
52+
return func(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
53+
return newJsTracer(code, ctx, cfg, chainConfig)
5354
}
5455
}
5556
for name, code := range assetTracers {
@@ -102,6 +103,7 @@ func fromBuf(vm *goja.Runtime, bufType goja.Value, buf goja.Value, allowString b
102103
type jsTracer struct {
103104
vm *goja.Runtime
104105
env *tracing.VMContext
106+
chainConfig *params.ChainConfig
105107
toBig toBigFn // Converts a hex string into a JS bigint
106108
toBuf toBufFn // Converts a []byte into a JS buffer
107109
fromBuf fromBufFn // Converts an array, hex string or Uint8Array to a []byte
@@ -138,13 +140,14 @@ type jsTracer struct {
138140
// The methods `result` and `fault` are required to be present.
139141
// The methods `step`, `enter`, and `exit` are optional, but note that
140142
// `enter` and `exit` always go together.
141-
func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) {
143+
func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
142144
vm := goja.New()
143145
// By default field names are exported to JS as is, i.e. capitalized.
144146
vm.SetFieldNameMapper(goja.UncapFieldNameMapper())
145147
t := &jsTracer{
146-
vm: vm,
147-
ctx: make(map[string]goja.Value),
148+
vm: vm,
149+
ctx: make(map[string]goja.Value),
150+
chainConfig: chainConfig,
148151
}
149152
if ctx == nil {
150153
ctx = new(tracers.Context)
@@ -234,7 +237,7 @@ func (t *jsTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from
234237
db := &dbObj{db: env.StateDB, vm: t.vm, toBig: t.toBig, toBuf: t.toBuf, fromBuf: t.fromBuf}
235238
t.dbValue = db.setupObject()
236239
// Update list of precompiles based on current block
237-
rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time)
240+
rules := t.chainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time)
238241
t.activePrecompiles = vm.ActivePrecompiles(rules)
239242
t.ctx["block"] = t.vm.ToValue(t.env.BlockNumber.Uint64())
240243
t.ctx["gas"] = t.vm.ToValue(tx.Gas())

0 commit comments

Comments
 (0)