fix prefetcher issue + reader bootstrap and get rid of triedb.IsVerkle() checks (#564)

- Fix an issue in which the prefetcher was creating a new MPT tree in verkle mode, based on the fact that triedb.IsVerkle() was false.
 - Also fix the tree bootstrapping in the reader
 - generally, no longer use db.triedb.IsVerkle() as it's only true if the db is used when starting in verkle mode.
This commit is contained in:
Guillaume Ballet 2026-02-07 20:39:44 +01:00 committed by GitHub
parent 8cc4463bbd
commit 14839c9113
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 21 additions and 9 deletions

View file

@ -318,17 +318,22 @@ func newTrieReader(root common.Hash, db *triedb.Database, ts *overlay.Transition
tr Trie
err error
)
if !db.IsVerkle() {
if !db.IsVerkle() && (ts == nil || !ts.InTransition()) {
tr, err = trie.NewStateTrie(trie.StateTrieID(root), db)
} else {
// When IsVerkle() is true, create a BinaryTrie wrapped in TransitionTrie
binTrie, binErr := bintrie.NewBinaryTrie(root, db)
var binTrie *bintrie.BinaryTrie
var binErr error
if ts.BaseRoot == (common.Hash{}) {
binTrie, binErr = bintrie.NewBinaryTrie(common.Hash{}, db)
} else {
binTrie, binErr = bintrie.NewBinaryTrie(root, db)
}
if binErr != nil {
return nil, binErr
}
// Based on the transition status, determine if the overlay
// tree needs to be created, or if a single, target tree is
// tree needs to be created, or if a single target tree is
// to be picked.
if ts.InTransition() {
mpt, err := trie.NewStateTrie(trie.StateTrieID(ts.BaseRoot), db)

View file

@ -147,6 +147,9 @@ func (s *stateObject) getTrie() (Trie, error) {
func (s *stateObject) getPrefetchedTrie() Trie {
// If there's nothing to meaningfully return, let the user figure it out by
// pulling the trie from disk.
if s.db.trie != nil && s.db.trie.IsVerkle() {
return nil
}
if (s.data.Root == types.EmptyRootHash && !s.db.db.TrieDB().IsVerkle()) || s.db.prefetcher == nil {
return nil
}

View file

@ -356,6 +356,10 @@ func (s *StateDB) InTransition() bool {
return completeValue != (common.Hash{})
}
func (s *StateDB) isVerkle() bool {
return s.db.TrieDB().IsVerkle() || (s.trie != nil && s.trie.IsVerkle())
}
// TxIndex returns the current transaction index set by SetTxContext.
func (s *StateDB) TxIndex() int {
return s.txIndex
@ -830,7 +834,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
start = time.Now()
workers errgroup.Group
)
if s.db.TrieDB().IsVerkle() {
if s.isVerkle() {
// Whilst MPT storage tries are independent, Verkle has one single trie
// for all the accounts and all the storage slots merged together. The
// former can thus be simply parallelized, but updating the latter will
@ -844,7 +848,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
}
obj := s.stateObjects[addr] // closure for the task runner below
workers.Go(func() error {
if s.db.TrieDB().IsVerkle() {
if s.isVerkle() {
obj.updateTrie()
} else {
obj.updateRoot()
@ -861,7 +865,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
// If witness building is enabled, gather all the read-only accesses.
// Skip witness collection in Verkle mode, they will be gathered
// together at the end.
if s.witness != nil && !s.db.TrieDB().IsVerkle() {
if s.witness != nil && !s.isVerkle() {
// Pull in anything that has been accessed before destruction
for _, obj := range s.stateObjectsDestruct {
// Skip any objects that haven't touched their storage
@ -918,7 +922,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
// only a single trie is used for state hashing. Replacing a non-nil verkle tree
// here could result in losing uncommitted changes from storage.
start = time.Now()
if s.prefetcher != nil {
if s.prefetcher != nil && !s.isVerkle() {
if trie := s.prefetcher.trie(common.Hash{}, s.originalRoot); trie == nil {
log.Error("Failed to retrieve account pre-fetcher trie")
} else {
@ -1137,7 +1141,7 @@ func (s *StateDB) handleDestruction(noStorageWiping bool) (map[common.Hash]*acco
deletes[addrHash] = op
// Short circuit if the origin storage was empty.
if prev.Root == types.EmptyRootHash || s.db.TrieDB().IsVerkle() {
if prev.Root == types.EmptyRootHash || s.isVerkle() {
continue
}
if noStorageWiping {