Skip to content

Commit 8321fe2

Browse files
holimanfjl
andauthored
tests: fix goroutine leak related to state snapshot generation (#28974)
--------- Co-authored-by: Felix Lange <[email protected]>
1 parent 55a46c3 commit 8321fe2

File tree

8 files changed

+144
-124
lines changed

8 files changed

+144
-124
lines changed

cmd/evm/staterunner.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import (
2525
"github.com/ethereum/go-ethereum/common"
2626
"github.com/ethereum/go-ethereum/core/rawdb"
2727
"github.com/ethereum/go-ethereum/core/state"
28-
"github.com/ethereum/go-ethereum/core/state/snapshot"
2928
"github.com/ethereum/go-ethereum/core/vm"
3029
"github.com/ethereum/go-ethereum/eth/tracers/logger"
3130
"github.com/ethereum/go-ethereum/tests"
@@ -90,26 +89,27 @@ func runStateTest(fname string, cfg vm.Config, jsonOut, dump bool) error {
9089
if err != nil {
9190
return err
9291
}
93-
var tests map[string]tests.StateTest
94-
if err := json.Unmarshal(src, &tests); err != nil {
92+
var testsByName map[string]tests.StateTest
93+
if err := json.Unmarshal(src, &testsByName); err != nil {
9594
return err
9695
}
96+
9797
// Iterate over all the tests, run them and aggregate the results
98-
results := make([]StatetestResult, 0, len(tests))
99-
for key, test := range tests {
98+
results := make([]StatetestResult, 0, len(testsByName))
99+
for key, test := range testsByName {
100100
for _, st := range test.Subtests() {
101101
// Run the test and aggregate the result
102102
result := &StatetestResult{Name: key, Fork: st.Fork, Pass: true}
103-
test.Run(st, cfg, false, rawdb.HashScheme, func(err error, snaps *snapshot.Tree, statedb *state.StateDB) {
103+
test.Run(st, cfg, false, rawdb.HashScheme, func(err error, tstate *tests.StateTestState) {
104104
var root common.Hash
105-
if statedb != nil {
106-
root = statedb.IntermediateRoot(false)
105+
if tstate.StateDB != nil {
106+
root = tstate.StateDB.IntermediateRoot(false)
107107
result.Root = &root
108108
if jsonOut {
109109
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
110110
}
111111
if dump { // Dump any state to aid debugging
112-
cpy, _ := state.New(root, statedb.Database(), nil)
112+
cpy, _ := state.New(root, tstate.StateDB.Database(), nil)
113113
dump := cpy.RawDump(nil)
114114
result.State = &dump
115115
}

core/state/snapshot/snapshot.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,14 @@ func (t *Tree) Disable() {
258258
for _, layer := range t.layers {
259259
switch layer := layer.(type) {
260260
case *diskLayer:
261+
262+
layer.lock.RLock()
263+
generating := layer.genMarker != nil
264+
layer.lock.RUnlock()
265+
if !generating {
266+
// Generator is already aborted or finished
267+
break
268+
}
261269
// If the base layer is generating, abort it
262270
if layer.genAbort != nil {
263271
abort := make(chan *generatorStats)

eth/tracers/internal/tracetest/calltrace_test.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,9 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
133133
GasLimit: uint64(test.Context.GasLimit),
134134
BaseFee: test.Genesis.BaseFee,
135135
}
136-
triedb, _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme)
136+
state = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme)
137137
)
138-
triedb.Close()
138+
state.Close()
139139

140140
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
141141
if err != nil {
@@ -145,7 +145,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
145145
if err != nil {
146146
t.Fatalf("failed to prepare transaction for tracing: %v", err)
147147
}
148-
evm := vm.NewEVM(context, core.NewEVMTxContext(msg), statedb, test.Genesis.Config, vm.Config{Tracer: tracer})
148+
evm := vm.NewEVM(context, core.NewEVMTxContext(msg), state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer})
149149
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
150150
if err != nil {
151151
t.Fatalf("failed to execute transaction: %v", err)
@@ -235,8 +235,8 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
235235
if err != nil {
236236
b.Fatalf("failed to prepare transaction for tracing: %v", err)
237237
}
238-
triedb, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme)
239-
defer triedb.Close()
238+
state := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme)
239+
defer state.Close()
240240

241241
b.ReportAllocs()
242242
b.ResetTimer()
@@ -245,16 +245,16 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
245245
if err != nil {
246246
b.Fatalf("failed to create call tracer: %v", err)
247247
}
248-
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer})
249-
snap := statedb.Snapshot()
248+
evm := vm.NewEVM(context, txContext, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer})
249+
snap := state.StateDB.Snapshot()
250250
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
251251
if _, err = st.TransitionDb(); err != nil {
252252
b.Fatalf("failed to execute transaction: %v", err)
253253
}
254254
if _, err = tracer.GetResult(); err != nil {
255255
b.Fatal(err)
256256
}
257-
statedb.RevertToSnapshot(snap)
257+
state.StateDB.RevertToSnapshot(snap)
258258
}
259259
}
260260

@@ -362,7 +362,7 @@ func TestInternals(t *testing.T) {
362362
},
363363
} {
364364
t.Run(tc.name, func(t *testing.T) {
365-
triedb, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(),
365+
state := tests.MakePreState(rawdb.NewMemoryDatabase(),
366366
core.GenesisAlloc{
367367
to: core.GenesisAccount{
368368
Code: tc.code,
@@ -371,9 +371,9 @@ func TestInternals(t *testing.T) {
371371
Balance: big.NewInt(500000000000000),
372372
},
373373
}, false, rawdb.HashScheme)
374-
defer triedb.Close()
374+
defer state.Close()
375375

376-
evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Tracer: tc.tracer})
376+
evm := vm.NewEVM(context, txContext, state.StateDB, params.MainnetChainConfig, vm.Config{Tracer: tc.tracer})
377377
msg := &core.Message{
378378
To: &to,
379379
From: origin,

eth/tracers/internal/tracetest/flat_calltrace_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
9595
Difficulty: (*big.Int)(test.Context.Difficulty),
9696
GasLimit: uint64(test.Context.GasLimit),
9797
}
98-
triedb, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme)
99-
defer triedb.Close()
98+
state := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme)
99+
defer state.Close()
100100

101101
// Create the tracer, the EVM environment and run it
102102
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
@@ -107,7 +107,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
107107
if err != nil {
108108
return fmt.Errorf("failed to prepare transaction for tracing: %v", err)
109109
}
110-
evm := vm.NewEVM(context, core.NewEVMTxContext(msg), statedb, test.Genesis.Config, vm.Config{Tracer: tracer})
110+
evm := vm.NewEVM(context, core.NewEVMTxContext(msg), state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer})
111111
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
112112

113113
if _, err = st.TransitionDb(); err != nil {

eth/tracers/internal/tracetest/prestate_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,9 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
103103
GasLimit: uint64(test.Context.GasLimit),
104104
BaseFee: test.Genesis.BaseFee,
105105
}
106-
triedb, _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme)
106+
state = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme)
107107
)
108-
defer triedb.Close()
108+
defer state.Close()
109109

110110
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
111111
if err != nil {
@@ -115,7 +115,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
115115
if err != nil {
116116
t.Fatalf("failed to prepare transaction for tracing: %v", err)
117117
}
118-
evm := vm.NewEVM(context, core.NewEVMTxContext(msg), statedb, test.Genesis.Config, vm.Config{Tracer: tracer})
118+
evm := vm.NewEVM(context, core.NewEVMTxContext(msg), state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer})
119119
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
120120
if _, err = st.TransitionDb(); err != nil {
121121
t.Fatalf("failed to execute transaction: %v", err)

eth/tracers/tracers_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ func BenchmarkTransactionTrace(b *testing.B) {
7979
Code: []byte{},
8080
Balance: big.NewInt(500000000000000),
8181
}
82-
triedb, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false, rawdb.HashScheme)
83-
defer triedb.Close()
82+
state := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false, rawdb.HashScheme)
83+
defer state.Close()
8484

8585
// Create the tracer, the EVM environment and run it
8686
tracer := logger.NewStructLogger(&logger.Config{
@@ -89,7 +89,7 @@ func BenchmarkTransactionTrace(b *testing.B) {
8989
//EnableMemory: false,
9090
//EnableReturnData: false,
9191
})
92-
evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer})
92+
evm := vm.NewEVM(context, txContext, state.StateDB, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer})
9393
msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
9494
if err != nil {
9595
b.Fatalf("failed to prepare transaction for tracing: %v", err)
@@ -98,13 +98,13 @@ func BenchmarkTransactionTrace(b *testing.B) {
9898
b.ReportAllocs()
9999

100100
for i := 0; i < b.N; i++ {
101-
snap := statedb.Snapshot()
101+
snap := state.StateDB.Snapshot()
102102
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
103103
_, err = st.TransitionDb()
104104
if err != nil {
105105
b.Fatal(err)
106106
}
107-
statedb.RevertToSnapshot(snap)
107+
state.StateDB.RevertToSnapshot(snap)
108108
if have, want := len(tracer.StructLogs()), 244752; have != want {
109109
b.Fatalf("trace wrong, want %d steps, have %d", want, have)
110110
}

tests/state_test.go

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ import (
3232

3333
"github.com/ethereum/go-ethereum/core"
3434
"github.com/ethereum/go-ethereum/core/rawdb"
35-
"github.com/ethereum/go-ethereum/core/state"
36-
"github.com/ethereum/go-ethereum/core/state/snapshot"
3735
"github.com/ethereum/go-ethereum/core/types"
3836
"github.com/ethereum/go-ethereum/core/vm"
3937
"github.com/ethereum/go-ethereum/eth/tracers/logger"
@@ -82,7 +80,7 @@ func TestState(t *testing.T) {
8280
t.Run(key+"/hash/trie", func(t *testing.T) {
8381
withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error {
8482
var result error
85-
test.Run(subtest, vmconfig, false, rawdb.HashScheme, func(err error, snaps *snapshot.Tree, state *state.StateDB) {
83+
test.Run(subtest, vmconfig, false, rawdb.HashScheme, func(err error, state *StateTestState) {
8684
result = st.checkFailure(t, err)
8785
})
8886
return result
@@ -91,9 +89,9 @@ func TestState(t *testing.T) {
9189
t.Run(key+"/hash/snap", func(t *testing.T) {
9290
withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error {
9391
var result error
94-
test.Run(subtest, vmconfig, true, rawdb.HashScheme, func(err error, snaps *snapshot.Tree, state *state.StateDB) {
95-
if snaps != nil && state != nil {
96-
if _, err := snaps.Journal(state.IntermediateRoot(false)); err != nil {
92+
test.Run(subtest, vmconfig, true, rawdb.HashScheme, func(err error, state *StateTestState) {
93+
if state.Snapshots != nil && state.StateDB != nil {
94+
if _, err := state.Snapshots.Journal(state.StateDB.IntermediateRoot(false)); err != nil {
9795
result = err
9896
return
9997
}
@@ -106,7 +104,7 @@ func TestState(t *testing.T) {
106104
t.Run(key+"/path/trie", func(t *testing.T) {
107105
withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error {
108106
var result error
109-
test.Run(subtest, vmconfig, false, rawdb.PathScheme, func(err error, snaps *snapshot.Tree, state *state.StateDB) {
107+
test.Run(subtest, vmconfig, false, rawdb.PathScheme, func(err error, state *StateTestState) {
110108
result = st.checkFailure(t, err)
111109
})
112110
return result
@@ -115,9 +113,9 @@ func TestState(t *testing.T) {
115113
t.Run(key+"/path/snap", func(t *testing.T) {
116114
withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error {
117115
var result error
118-
test.Run(subtest, vmconfig, true, rawdb.PathScheme, func(err error, snaps *snapshot.Tree, state *state.StateDB) {
119-
if snaps != nil && state != nil {
120-
if _, err := snaps.Journal(state.IntermediateRoot(false)); err != nil {
116+
test.Run(subtest, vmconfig, true, rawdb.PathScheme, func(err error, state *StateTestState) {
117+
if state.Snapshots != nil && state.StateDB != nil {
118+
if _, err := state.Snapshots.Journal(state.StateDB.IntermediateRoot(false)); err != nil {
121119
result = err
122120
return
123121
}
@@ -222,8 +220,8 @@ func runBenchmark(b *testing.B, t *StateTest) {
222220

223221
vmconfig.ExtraEips = eips
224222
block := t.genesis(config).ToBlock()
225-
triedb, _, statedb := MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre, false, rawdb.HashScheme)
226-
defer triedb.Close()
223+
state := MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre, false, rawdb.HashScheme)
224+
defer state.Close()
227225

228226
var baseFee *big.Int
229227
if rules.IsLondon {
@@ -261,7 +259,7 @@ func runBenchmark(b *testing.B, t *StateTest) {
261259
context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase)
262260
context.GetHash = vmTestBlockHash
263261
context.BaseFee = baseFee
264-
evm := vm.NewEVM(context, txContext, statedb, config, vmconfig)
262+
evm := vm.NewEVM(context, txContext, state.StateDB, config, vmconfig)
265263

266264
// Create "contract" for sender to cache code analysis.
267265
sender := vm.NewContract(vm.AccountRef(msg.From), vm.AccountRef(msg.From),
@@ -274,8 +272,8 @@ func runBenchmark(b *testing.B, t *StateTest) {
274272
)
275273
b.ResetTimer()
276274
for n := 0; n < b.N; n++ {
277-
snapshot := statedb.Snapshot()
278-
statedb.Prepare(rules, msg.From, context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList)
275+
snapshot := state.StateDB.Snapshot()
276+
state.StateDB.Prepare(rules, msg.From, context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList)
279277
b.StartTimer()
280278
start := time.Now()
281279

@@ -288,10 +286,10 @@ func runBenchmark(b *testing.B, t *StateTest) {
288286

289287
b.StopTimer()
290288
elapsed += uint64(time.Since(start))
291-
refund += statedb.GetRefund()
289+
refund += state.StateDB.GetRefund()
292290
gasUsed += msg.GasLimit - leftOverGas
293291

294-
statedb.RevertToSnapshot(snapshot)
292+
state.StateDB.RevertToSnapshot(snapshot)
295293
}
296294
if elapsed < 1 {
297295
elapsed = 1

0 commit comments

Comments
 (0)