…ytes
SelfDestructRefundBytes iterates s.stateObjects and previously called
IsNewContract / HasSelfDestructed on each entry to filter for accounts
that were both created and selfdestructed in the current transaction.
Both helpers go through StateDB.getStateObject, which unconditionally
records an EIP-7928 account read via s.stateReadList.AddAccount(addr).
The effect is that *every* live entry in the stateObjects cache gets
added to the per-tx read list whenever a tx triggers the EIP-8037
selfdestruct refund check (i.e. on every successful tx post-Amsterdam).
This pollutes the BAL with addresses the tx never actually touched.
In the miner, the cache may contain accounts loaded by earlier failed-tx
attempts (preCheck via getStateObject loaded them; RevertToSnapshot does
not evict the cache because reads aren't journaled). Validators
re-executing the sealed block don't have those cached entries, so they
don't reproduce the reads. Result: BAL hash mismatch on otherwise
deterministic execution.
Use direct field access on the already-iterated *stateObject so the
filter doesn't go through getStateObject. Functionally equivalent --
newContract and selfDestructed are the same fields the helpers consult
-- but with no read-list side effect.