cleanup bal state transition

This commit is contained in:
Jared Wasinger 2025-11-12 17:51:01 +08:00
parent abd8612b1d
commit 74ca164123

View file

@ -15,6 +15,9 @@ import (
"time" "time"
) )
// BALStateTransition is responsible for performing the state root update
// and commit for EIP 7928 access-list-containing blocks. An instance of
// this object is only used for a single block.
type BALStateTransition struct { type BALStateTransition struct {
accessList *BALReader accessList *BALReader
db Database db Database
@ -22,13 +25,18 @@ type BALStateTransition struct {
stateTrie Trie stateTrie Trie
parentRoot common.Hash parentRoot common.Hash
rootHash common.Hash // the state root of the block
diffs map[common.Address]*bal.AccountMutations rootHash common.Hash
prestates sync.Map //map[common.Address]*types.StateAccount // the state modifications performed by the block
diffs map[common.Address]*bal.AccountMutations
poststates map[common.Address]*types.StateAccount // a map of common.Address -> *types.StateAccount containing the block
tries sync.Map //map[common.Address]Trie // prestate of all accounts that will be modified
prestates sync.Map
postStates map[common.Address]*types.StateAccount
// a map of common.Address -> Trie containing the account tries for all
// accounts with mutated storage
tries sync.Map //map[common.Address]Trie
deletions map[common.Address]struct{} deletions map[common.Address]struct{}
originStorages map[common.Address]map[common.Hash]common.Hash originStorages map[common.Address]map[common.Hash]common.Hash
@ -39,8 +47,6 @@ type BALStateTransition struct {
storageDeleted atomic.Int64 storageDeleted atomic.Int64
storageUpdated atomic.Int64 storageUpdated atomic.Int64
// TODO: maybe package these into their own 'CommitMetrics' struct instead of making them public fields
stateUpdate *stateUpdate stateUpdate *stateUpdate
metrics BALStateTransitionMetrics metrics BALStateTransitionMetrics
@ -85,7 +91,7 @@ func NewBALStateTransition(accessList *BALReader, db Database, parentRoot common
rootHash: common.Hash{}, rootHash: common.Hash{},
diffs: make(map[common.Address]*bal.AccountMutations), diffs: make(map[common.Address]*bal.AccountMutations),
prestates: sync.Map{}, prestates: sync.Map{},
poststates: make(map[common.Address]*types.StateAccount), postStates: make(map[common.Address]*types.StateAccount),
tries: sync.Map{}, tries: sync.Map{},
deletions: make(map[common.Address]struct{}), deletions: make(map[common.Address]struct{}),
originStorages: make(map[common.Address]map[common.Hash]common.Hash), originStorages: make(map[common.Address]map[common.Hash]common.Hash),
@ -128,6 +134,8 @@ func isAccountDeleted(prestate *types.StateAccount, mutations *bal.AccountMutati
return false return false
} }
// updateAccount applies the block state mutations to a given account returning
// the updated state account and new code (if the account code changed)
func (s *BALStateTransition) updateAccount(addr common.Address) (*types.StateAccount, []byte) { func (s *BALStateTransition) updateAccount(addr common.Address) (*types.StateAccount, []byte) {
a, _ := s.prestates.Load(addr) a, _ := s.prestates.Load(addr)
acct := a.(*types.StateAccount) acct := a.(*types.StateAccount)
@ -159,7 +167,7 @@ func (s *BALStateTransition) commitAccount(addr common.Address) (*accountUpdate,
) )
op := &accountUpdate{ op := &accountUpdate{
address: addr, address: addr,
data: types.SlimAccountRLP(*s.poststates[addr]), // TODO: cache the updated state acocunt somewhere data: types.SlimAccountRLP(*s.postStates[addr]), // TODO: cache the updated state acocunt somewhere
} }
if prestate, exist := s.prestates.Load(addr); exist { if prestate, exist := s.prestates.Load(addr); exist {
prestate := prestate.(*types.StateAccount) prestate := prestate.(*types.StateAccount)
@ -190,10 +198,11 @@ func (s *BALStateTransition) commitAccount(addr common.Address) (*accountUpdate,
} }
tr, _ := s.tries.Load(addr) tr, _ := s.tries.Load(addr)
root, nodes := tr.(Trie).Commit(false) root, nodes := tr.(Trie).Commit(false)
s.poststates[addr].Root = root s.postStates[addr].Root = root
return op, nodes, nil return op, nodes, nil
} }
// CommitWithUpdate flushes mutated trie nodes and state accounts to disk.
func (s *BALStateTransition) CommitWithUpdate(block uint64, deleteEmptyObjects bool, noStorageWiping bool) (common.Hash, *stateUpdate, error) { func (s *BALStateTransition) CommitWithUpdate(block uint64, deleteEmptyObjects bool, noStorageWiping bool) (common.Hash, *stateUpdate, error) {
// 1) create a stateUpdate object // 1) create a stateUpdate object
// Commit objects to the trie, measuring the elapsed time // Commit objects to the trie, measuring the elapsed time
@ -342,14 +351,28 @@ func (s *BALStateTransition) CommitWithUpdate(block uint64, deleteEmptyObjects b
return root, ret, nil return root, ret, nil
} }
// IntermediateRoot applies block state mutations and computes the updated state
// trie root.
func (s *BALStateTransition) IntermediateRoot(_ bool) common.Hash { func (s *BALStateTransition) IntermediateRoot(_ bool) common.Hash {
if s.rootHash != (common.Hash{}) { if s.rootHash != (common.Hash{}) {
return s.rootHash return s.rootHash
} }
// State root calculation proceeds as follows:
// 1 (a): load the prestate state accounts for addresses which were modified in the block
// 1 (b): load the origin storage values for all slots which were modified during the block (this is needed for computing the stateUpdate)
// 1 (c): update each mutated account, producing the post-block state object by applying the state mutations to the prestate (retrieved in 1a).
// 1 (d): prefetch the intermediate trie nodes of the mutated state set from the account trie.
//
// 2: compute the post-state root of the account trie
//
// Steps 1/2 are performed sequentially, with steps 1a-d performed in parallel
start := time.Now() start := time.Now()
lastIdx := len(s.accessList.block.Transactions()) + 1 lastIdx := len(s.accessList.block.Transactions()) + 1
//1 (b): load the origin storage values for all slots which were modified during the block
s.originStoragesWG.Add(1) s.originStoragesWG.Add(1)
go func() { go func() {
defer s.originStoragesWG.Done() defer s.originStoragesWG.Done()
@ -371,11 +394,6 @@ func (s *BALStateTransition) IntermediateRoot(_ bool) common.Hash {
var wg sync.WaitGroup var wg sync.WaitGroup
// 1. resolve the entire state object for the updated addrs, in parallel prefetch them in the account trie
// 1. in parallel:
// * load the prestate of mutated state objects from the snapshot, update their tries.
// * prefetch all mutated account in the account trie
for _, addr := range s.accessList.ModifiedAccounts() { for _, addr := range s.accessList.ModifiedAccounts() {
diff := s.accessList.readAccountDiff(addr, lastIdx) diff := s.accessList.readAccountDiff(addr, lastIdx)
s.diffs[addr] = diff s.diffs[addr] = diff
@ -385,6 +403,7 @@ func (s *BALStateTransition) IntermediateRoot(_ bool) common.Hash {
wg.Add(1) wg.Add(1)
address := addr address := addr
go func() { go func() {
// 1 (c): update each mutated account, producing the post-block state object by applying the state mutations to the prestate (retrieved in 1a).
acct := s.accessList.prestateReader.account(address) acct := s.accessList.prestateReader.account(address)
diff := s.diffs[address] diff := s.diffs[address]
if acct == nil { if acct == nil {
@ -428,21 +447,6 @@ func (s *BALStateTransition) IntermediateRoot(_ bool) common.Hash {
hashStart := time.Now() hashStart := time.Now()
tr.Hash() tr.Hash()
s.metrics.StateHash = time.Since(hashStart) s.metrics.StateHash = time.Since(hashStart)
/*
var objTrieData string
it, err := tr.NodeIterator([]byte{})
if err != nil {
panic(err)
}
for it.Next(true) {
if it.Leaf() {
objTrieData += fmt.Sprintf("%x: %x\n", it.Path(), it.LeafBlob())
} else {
objTrieData += fmt.Sprintf("%x: %x\n", it.Path(), it.Hash())
}
}
fmt.Printf("acct hash %x. hash=%x, updated storage: %v, deleted storage: %v trie:\n%s\n", crypto.Keccak256Hash(address[:]), tr.Hash(), updateKeys, deleteKeys, objTrieData)
*/
} }
wg.Done() wg.Done()
@ -450,7 +454,7 @@ func (s *BALStateTransition) IntermediateRoot(_ bool) common.Hash {
} }
wg.Add(1) wg.Add(1)
// prefetch all modified accounts in the main account trie. // 1 (d): prefetch the intermediate trie nodes of the mutated state set from the account trie.
go func() { go func() {
prefetchStart := time.Now() prefetchStart := time.Now()
if err := s.stateTrie.PrefetchAccount(s.accessList.ModifiedAccounts()); err != nil { if err := s.stateTrie.PrefetchAccount(s.accessList.ModifiedAccounts()); err != nil {
@ -463,8 +467,7 @@ func (s *BALStateTransition) IntermediateRoot(_ bool) common.Hash {
wg.Wait() wg.Wait()
s.metrics.AccountUpdate = time.Since(start) s.metrics.AccountUpdate = time.Since(start)
// stage 2: update the main account trie // 2: compute the post-state root of the account trie
stateUpdateStart := time.Now() stateUpdateStart := time.Now()
for mutatedAddr, _ := range s.diffs { for mutatedAddr, _ := range s.diffs {
p, _ := s.prestates.Load(mutatedAddr) p, _ := s.prestates.Load(mutatedAddr)
@ -489,7 +492,7 @@ func (s *BALStateTransition) IntermediateRoot(_ bool) common.Hash {
if err := s.stateTrie.UpdateAccount(mutatedAddr, acct, len(code)); err != nil { if err := s.stateTrie.UpdateAccount(mutatedAddr, acct, len(code)); err != nil {
panic("FUCK4") panic("FUCK4")
} }
s.poststates[mutatedAddr] = acct s.postStates[mutatedAddr] = acct
} }
} }
@ -498,21 +501,6 @@ func (s *BALStateTransition) IntermediateRoot(_ bool) common.Hash {
stateTrieHashStart := time.Now() stateTrieHashStart := time.Now()
s.rootHash = s.stateTrie.Hash() s.rootHash = s.stateTrie.Hash()
s.metrics.StateHash = time.Since(stateTrieHashStart) s.metrics.StateHash = time.Since(stateTrieHashStart)
/*
it, err := s.stateTrie.NodeIterator([]byte{})
if err != nil {
panic(err)
}
fmt.Println("state trie")
for it.Next(true) {
if it.Leaf() {
fmt.Printf("%x: %x\n", it.Path(), it.LeafBlob())
} else {
fmt.Printf("%x: %x\n", it.Path(), it.Hash())
}
}
*/
return s.rootHash return s.rootHash
} }