Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

eth/tracers: avoid unsyncronized mutations on trie database #23632

Merged
merged 2 commits into from Sep 28, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion eth/state_accessor.go
Expand Up @@ -119,7 +119,8 @@ func (eth *Ethereum) stateAtBlock(block *types.Block, reexec uint64, base *state
// Finalize the state so any modifications are written to the trie
root, err := statedb.Commit(eth.blockchain.Config().IsEIP158(current.Number()))
if err != nil {
return nil, err
return nil, fmt.Errorf("stateAtBlock commit failed, number %d root %v: %w",
current.NumberU64(), current.Root().Hex(), err)
}
statedb, err = state.New(root, database, nil)
if err != nil {
Expand Down
28 changes: 20 additions & 8 deletions eth/tracers/api.go
Expand Up @@ -290,7 +290,11 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config
}()
}
// Start a goroutine to feed all the blocks into the tracers
begin := time.Now()
var (
begin = time.Now()
derefTodo []common.Hash // list of hashes to dereference from the db
derefsMu sync.Mutex // mutex for the derefs
)

go func() {
var (
Expand Down Expand Up @@ -324,6 +328,14 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config
return
default:
}
// clean out any derefs
derefsMu.Lock()
for _, h := range derefTodo {
statedb.Database().TrieDB().Dereference(h)
}
derefTodo = derefTodo[:0]
derefsMu.Unlock()

// Print progress logs if long enough time elapsed
if time.Since(logged) > 8*time.Second {
logged = time.Now()
Expand All @@ -337,10 +349,11 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config
}
// Prepare the statedb for tracing. Don't use the live database for
// tracing to avoid persisting state junks into the database.
statedb, err = api.backend.StateAtBlock(localctx, block, reexec, statedb, false)
if err != nil {
if _statedb, err := api.backend.StateAtBlock(localctx, block, reexec, statedb, false); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps rename the _statedb to s?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, is it necessary? if error is returned we will exit the for loop anyway. The statedb will not be used even it's set to nil.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, it isn't necessary. While investigating, I did use the statedb for outputting some more info, but that code is gone now, so I can revert that change

failed = err
break
} else {
statedb = _statedb
}
if statedb.Database().TrieDB() != nil {
// Hold the reference for tracer, will be released at the final stage
Expand Down Expand Up @@ -382,12 +395,11 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config
Hash: res.block.Hash(),
Traces: res.results,
}
// Schedule any parent tries held in memory by this task for dereferencing
done[uint64(result.Block)] = result

// Dereference any parent tries held in memory by this task
if res.statedb.Database().TrieDB() != nil {
res.statedb.Database().TrieDB().Dereference(res.rootref)
}
derefsMu.Lock()
derefTodo = append(derefTodo, res.rootref)
derefsMu.Unlock()
// Stream completed traces to the user, aborting on the first error
for result, ok := done[next]; ok; result, ok = done[next] {
if len(result.Traces) > 0 || next == end.NumberU64() {
Expand Down