mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-22 20:56:42 +00:00
core/state: parallelize account trie updates in IntermediateRoot
This commit is contained in:
parent
b81f03e8ff
commit
537e87bc4c
1 changed files with 41 additions and 21 deletions
|
|
@ -814,6 +814,27 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
s.prefetcher = nil // Pre-byzantium, unset any used up prefetcher
|
s.prefetcher = nil // Pre-byzantium, unset any used up prefetcher
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
// Channel for accounts that have finished storage trie update.
|
||||||
|
type accountReady struct {
|
||||||
|
addr common.Address
|
||||||
|
obj *stateObject
|
||||||
|
}
|
||||||
|
accountUpdates := make(chan accountReady, len(s.mutations))
|
||||||
|
// Start a goroutine to update the account trie.
|
||||||
|
var accountUpdateDone sync.WaitGroup
|
||||||
|
accountUpdateDone.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer accountUpdateDone.Done()
|
||||||
|
for update := range accountUpdates {
|
||||||
|
start := time.Now()
|
||||||
|
s.updateStateObject(update.obj)
|
||||||
|
s.AccountUpdated += 1
|
||||||
|
if op, ok := s.mutations[update.addr]; ok {
|
||||||
|
op.applied = true
|
||||||
|
}
|
||||||
|
s.AccountUpdates += time.Since(start)
|
||||||
|
}
|
||||||
|
}()
|
||||||
// Process all storage updates concurrently. The state object update root
|
// Process all storage updates concurrently. The state object update root
|
||||||
// method will internally call a blocking trie fetch from the prefetcher,
|
// method will internally call a blocking trie fetch from the prefetcher,
|
||||||
// so there's no need to explicitly wait for the prefetchers to finish.
|
// so there's no need to explicitly wait for the prefetchers to finish.
|
||||||
|
|
@ -834,9 +855,13 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
obj := s.stateObjects[addr] // closure for the task runner below
|
obj := s.stateObjects[addr] // closure for the task runner below
|
||||||
|
addr := addr
|
||||||
|
op := op
|
||||||
workers.Go(func() error {
|
workers.Go(func() error {
|
||||||
if s.db.TrieDB().IsVerkle() {
|
if s.db.TrieDB().IsVerkle() {
|
||||||
obj.updateTrie()
|
obj.updateTrie()
|
||||||
|
op.applied = true
|
||||||
|
s.AccountUpdated += 1
|
||||||
} else {
|
} else {
|
||||||
obj.updateRoot()
|
obj.updateRoot()
|
||||||
|
|
||||||
|
|
@ -845,6 +870,8 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
if s.witness != nil && obj.trie != nil {
|
if s.witness != nil && obj.trie != nil {
|
||||||
s.witness.AddState(obj.trie.Witness())
|
s.witness.AddState(obj.trie.Witness())
|
||||||
}
|
}
|
||||||
|
// Send the account to be updated in the account trie
|
||||||
|
accountUpdates <- accountReady{addr: addr, obj: obj}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
@ -908,7 +935,6 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
// Don't check prefetcher if verkle trie has been used. In the context of verkle,
|
// Don't check prefetcher if verkle trie has been used. In the context of verkle,
|
||||||
// only a single trie is used for state hashing. Replacing a non-nil verkle tree
|
// only a single trie is used for state hashing. Replacing a non-nil verkle tree
|
||||||
// here could result in losing uncommitted changes from storage.
|
// here could result in losing uncommitted changes from storage.
|
||||||
start = time.Now()
|
|
||||||
if s.prefetcher != nil {
|
if s.prefetcher != nil {
|
||||||
if trie := s.prefetcher.trie(common.Hash{}, s.originalRoot); trie == nil {
|
if trie := s.prefetcher.trie(common.Hash{}, s.originalRoot); trie == nil {
|
||||||
log.Error("Failed to retrieve account pre-fetcher trie")
|
log.Error("Failed to retrieve account pre-fetcher trie")
|
||||||
|
|
@ -916,7 +942,11 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
s.trie = trie
|
s.trie = trie
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Perform updates before deletions. This prevents resolution of unnecessary trie nodes
|
// Close accountUpdates to terminate the account update goroutine's range loop.
|
||||||
|
close(accountUpdates)
|
||||||
|
// Wait for the account update goroutine to finish processing all accounts.
|
||||||
|
accountUpdateDone.Wait()
|
||||||
|
// Perform deletions after updates to prevent resolution of unnecessary trie nodes
|
||||||
// in circumstances similar to the following:
|
// in circumstances similar to the following:
|
||||||
//
|
//
|
||||||
// Consider nodes `A` and `B` who share the same full node parent `P` and have no other siblings.
|
// Consider nodes `A` and `B` who share the same full node parent `P` and have no other siblings.
|
||||||
|
|
@ -926,28 +956,18 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
// If the self-destruct is handled first, then `P` would be left with only one child, thus collapsed
|
// If the self-destruct is handled first, then `P` would be left with only one child, thus collapsed
|
||||||
// into a shortnode. This requires `B` to be resolved from disk.
|
// into a shortnode. This requires `B` to be resolved from disk.
|
||||||
// Whereas if the created node is handled first, then the collapse is avoided, and `B` is not resolved.
|
// Whereas if the created node is handled first, then the collapse is avoided, and `B` is not resolved.
|
||||||
var (
|
start = time.Now()
|
||||||
usedAddrs []common.Address
|
usedAddrs := make([]common.Address, 0, len(s.mutations))
|
||||||
deletedAddrs []common.Address
|
|
||||||
)
|
|
||||||
for addr, op := range s.mutations {
|
for addr, op := range s.mutations {
|
||||||
if op.applied {
|
if !op.applied {
|
||||||
continue
|
|
||||||
}
|
|
||||||
op.applied = true
|
op.applied = true
|
||||||
|
|
||||||
if op.isDelete() {
|
if op.isDelete() {
|
||||||
deletedAddrs = append(deletedAddrs, addr)
|
s.deleteStateObject(addr)
|
||||||
} else {
|
|
||||||
s.updateStateObject(s.stateObjects[addr])
|
|
||||||
s.AccountUpdated += 1
|
|
||||||
}
|
|
||||||
usedAddrs = append(usedAddrs, addr) // Copy needed for closure
|
|
||||||
}
|
|
||||||
for _, deletedAddr := range deletedAddrs {
|
|
||||||
s.deleteStateObject(deletedAddr)
|
|
||||||
s.AccountDeleted += 1
|
s.AccountDeleted += 1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
usedAddrs = append(usedAddrs, addr)
|
||||||
|
}
|
||||||
s.AccountUpdates += time.Since(start)
|
s.AccountUpdates += time.Since(start)
|
||||||
|
|
||||||
if s.prefetcher != nil {
|
if s.prefetcher != nil {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue