core/state: track the block-level accessList

This commit is contained in:
Gary Rong 2026-04-23 15:54:10 +08:00 committed by Jared Wasinger
parent 6fcebbfd00
commit f196057728
2 changed files with 45 additions and 1 deletions

View file

@ -274,6 +274,13 @@ func (s *stateObject) finalise() {
// map as the dirty slot might have been committed already (before the
// byzantium fork) and entry is necessary to modify the value back.
s.pendingStorage[key] = value
// Aggregate storage writes into the block-level access list.
// All slots in the dirtyStorage set must have post-transaction
// values that differ from their pre-transaction values.
if s.db.stateAccessList != nil {
s.db.stateAccessList.StorageWrite(uint16(s.db.txIndex+1), s.address, key, value)
}
}
if s.db.prefetcher != nil && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash {
if err := s.db.prefetcher.prefetch(s.addrHash(), s.data.Root, s.address, nil, slotsToPrefetch, false); err != nil {

View file

@ -18,6 +18,7 @@
package state
import (
"bytes"
"errors"
"fmt"
"maps"
@ -801,7 +802,7 @@ func (s *StateDB) LogsForBurnAccounts() []*types.Log {
// into the tries just yet. Only IntermediateRoot or Commit will do that.
func (s *StateDB) Finalise(deleteEmptyObjects bool) *bal.ConstructionBlockAccessList {
addressesToPrefetch := make([]common.Address, 0, len(s.journal.mutations))
for addr := range s.journal.mutations {
for addr, state := range s.journal.mutations {
obj, exist := s.stateObjects[addr]
if !exist {
// RIPEMD160 (0x03) gets an extra dirty marker for a historical
@ -822,7 +823,43 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) *bal.ConstructionBlockAccess
if _, ok := s.stateObjectsDestruct[obj.address]; !ok {
s.stateObjectsDestruct[obj.address] = obj
}
// Aggregate the account mutation into the block-level accessList
// if Amsterdam has been activated.
if s.stateAccessList != nil {
// Notably, if the account is deleted during the transaction,
// its pre-transaction nonce, code, and storage must be empty.
//
// EIP-6780 restricts self-destruct to contracts deployed within
// the same transaction, while EIP-7610 rejects deployments to
// destinations with non-empty storage, non-zero nonce and non-empty
// code.
//
// Therefore, when an account is deleted, its pre-transaction nonce
// code and storage is guaranteed to be empty, leaving nothing to
// clean up here.
balance := uint256.NewInt(0)
if state.balanceSet && balance.Cmp(state.balance) != 0 {
s.stateAccessList.BalanceChange(uint16(s.txIndex+1), addr, balance)
}
}
} else {
// Aggregate the account mutation into the block-level accessList
// if Amsterdam has been activated.
if s.stateAccessList != nil {
balance := obj.Balance()
if state.balanceSet && balance.Cmp(state.balance) != 0 {
s.stateAccessList.BalanceChange(uint16(s.txIndex+1), addr, balance)
}
nonce := obj.Nonce()
if state.nonceSet && nonce != state.nonce {
s.stateAccessList.NonceChange(addr, uint16(s.txIndex+1), nonce)
}
if state.codeSet {
if code := obj.Code(); !bytes.Equal(code, state.code) {
s.stateAccessList.CodeChange(addr, uint16(s.txIndex+1), code)
}
}
}
obj.finalise()
s.markUpdate(addr)
}