core/state: fix typed nil panic in StopPrefetcher

commitAndFlush discarded errors from db.Reader() and db.Hasher() at
lines 1040-1041, storing the result directly into s.reader/s.hasher.
When Hasher() fails (e.g. newBinaryHasher returns nil, err), Go wraps
the nil *binaryHasher in the Hasher interface as a typed nil — an
interface value {type: *binaryHasher, value: nil} that passes == nil
checks. StopPrefetcher then type-asserts to Prefetcher (succeeds) and
calls TermPrefetch on the nil receiver, panicking at h.trie.term().

Fix: propagate errors from Reader() and Hasher() in commitAndFlush
instead of discarding them, and add defensive nil-receiver guards to
both binaryHasher.TermPrefetch and merkleHasher.TermPrefetch.
This commit is contained in:
CPerezz 2026-04-12 01:52:19 +02:00
parent b4caa05448
commit 5850970e57
No known key found for this signature in database
GPG key ID: 62045F34B97177DD
3 changed files with 18 additions and 2 deletions

View file

@ -387,5 +387,8 @@ func (h *binaryHasher) PrefetchStorage(addr common.Address, keys []common.Hash,
// TermPrefetch terminates all prefetcher goroutines. Safe to call multiple times.
func (h *binaryHasher) TermPrefetch() {
if h == nil {
return
}
h.trie.term()
}

View file

@ -457,6 +457,9 @@ func (h *merkleHasher) PrefetchStorage(addr common.Address, keys []common.Hash,
// TermPrefetch terminates all prefetcher goroutines. Safe to call multiple times.
func (h *merkleHasher) TermPrefetch() {
if h == nil {
return
}
h.acctTrie.term()
for _, tr := range h.storageTries {
tr.term()

View file

@ -1040,8 +1040,18 @@ func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool, noStorag
}
s.DatabaseCommits = time.Since(start)
s.reader, _ = s.db.Reader(s.originalRoot)
s.hasher, _ = s.db.Hasher(s.originalRoot)
reader, err := s.db.Reader(s.originalRoot)
if err != nil {
return nil, err
}
s.reader = reader
hasher, err := s.db.Hasher(s.originalRoot)
if err != nil {
return nil, err
}
s.hasher = hasher
return ret, nil
}