triedb/pathdb: use merged storage key

This commit is contained in:
Gary Rong 2025-05-28 10:01:24 +08:00
parent 285f7898d0
commit 81ed5630d3

View file

@ -25,6 +25,14 @@ import (
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
) )
// storageKey returns a key for uniquely identifying the storage slot.
func storageKey(accountHash common.Hash, slotHash common.Hash) [64]byte {
var key [64]byte
copy(key[:32], accountHash[:])
copy(key[32:], slotHash[:])
return key
}
// lookup is an internal structure used to efficiently determine the layer in // lookup is an internal structure used to efficiently determine the layer in
// which a state entry resides. // which a state entry resides.
type lookup struct { type lookup struct {
@ -38,7 +46,7 @@ type lookup struct {
// slot. The key is the account address hash and the storage key // slot. The key is the account address hash and the storage key
// hash, the value is a slice of **diff layer** IDs indicating // hash, the value is a slice of **diff layer** IDs indicating
// where the slot was modified, with the order from oldest to newest. // where the slot was modified, with the order from oldest to newest.
storages map[common.Hash]map[common.Hash][]common.Hash storages map[[64]byte][]common.Hash
// descendant is the callback indicating whether the layer with // descendant is the callback indicating whether the layer with
// given root is a descendant of the one specified by `ancestor`. // given root is a descendant of the one specified by `ancestor`.
@ -57,7 +65,7 @@ func newLookup(head layer, descendant func(state common.Hash, ancestor common.Ha
} }
l := &lookup{ l := &lookup{
accounts: make(map[common.Hash][]common.Hash), accounts: make(map[common.Hash][]common.Hash),
storages: make(map[common.Hash]map[common.Hash][]common.Hash), storages: make(map[[64]byte][]common.Hash),
descendant: descendant, descendant: descendant,
} }
// Apply the diff layers from bottom to top // Apply the diff layers from bottom to top
@ -133,17 +141,14 @@ func (l *lookup) accountTip(accountHash common.Hash, stateID common.Hash, base c
// data retrieval, (b) or the layer specified by the stateID is stale: reject // data retrieval, (b) or the layer specified by the stateID is stale: reject
// the data retrieval. // the data retrieval.
func (l *lookup) storageTip(accountHash common.Hash, slotHash common.Hash, stateID common.Hash, base common.Hash) common.Hash { func (l *lookup) storageTip(accountHash common.Hash, slotHash common.Hash, stateID common.Hash, base common.Hash) common.Hash {
subset, exists := l.storages[accountHash] list := l.storages[storageKey(accountHash, slotHash)]
if exists { for i := len(list) - 1; i >= 0; i-- {
list := subset[slotHash] // If the current state matches the stateID, or the requested state is a
for i := len(list) - 1; i >= 0; i-- { // descendant of it, return the current state as the most recent one
// If the current state matches the stateID, or the requested state is a // containing the modified data. Otherwise, the current state may be ahead
// descendant of it, return the current state as the most recent one // of the requested one or belong to a different branch.
// containing the modified data. Otherwise, the current state may be ahead if list[i] == stateID || l.descendant(stateID, list[i]) {
// of the requested one or belong to a different branch. return list[i]
if list[i] == stateID || l.descendant(stateID, list[i]) {
return list[i]
}
} }
} }
// No layer matching the stateID or its descendants was found. Use the // No layer matching the stateID or its descendants was found. Use the
@ -188,18 +193,14 @@ func (l *lookup) addLayer(diff *diffLayer) {
go func() { go func() {
defer wg.Done() defer wg.Done()
for accountHash, slots := range diff.states.storageData { for accountHash, slots := range diff.states.storageData {
subset := l.storages[accountHash]
if subset == nil {
subset = make(map[common.Hash][]common.Hash)
l.storages[accountHash] = subset
}
for slotHash := range slots { for slotHash := range slots {
list, exists := subset[slotHash] key := storageKey(accountHash, slotHash)
list, exists := l.storages[key]
if !exists { if !exists {
list = make([]common.Hash, 0, 16) // TODO(rjl493456442) use sync pool list = make([]common.Hash, 0, 16) // TODO(rjl493456442) use sync pool
} }
list = append(list, state) list = append(list, state)
subset[slotHash] = list l.storages[key] = list
} }
} }
}() }()
@ -238,10 +239,10 @@ func (l *lookup) removeLayer(diff *diffLayer) error {
}(time.Now()) }(time.Now())
var ( var (
wg errgroup.Group eg errgroup.Group
state = diff.rootHash() state = diff.rootHash()
) )
wg.Go(func() error { eg.Go(func() error {
for accountHash := range diff.states.accountData { for accountHash := range diff.states.accountData {
found, list := removeFromList(l.accounts[accountHash], state) found, list := removeFromList(l.accounts[accountHash], state)
if !found { if !found {
@ -256,28 +257,22 @@ func (l *lookup) removeLayer(diff *diffLayer) error {
return nil return nil
}) })
wg.Go(func() error { eg.Go(func() error {
for accountHash, slots := range diff.states.storageData { for accountHash, slots := range diff.states.storageData {
subset := l.storages[accountHash]
if subset == nil {
return fmt.Errorf("storage lookup is not found, %x", accountHash)
}
for slotHash := range slots { for slotHash := range slots {
found, list := removeFromList(subset[slotHash], state) key := storageKey(accountHash, slotHash)
found, list := removeFromList(l.storages[key], state)
if !found { if !found {
return fmt.Errorf("storage lookup is not found, %x %x, state: %x", accountHash, slotHash, state) return fmt.Errorf("storage lookup is not found, %x %x, state: %x", accountHash, slotHash, state)
} }
if len(list) != 0 { if len(list) != 0 {
subset[slotHash] = list l.storages[key] = list
} else { } else {
delete(subset, slotHash) delete(l.storages, key)
} }
} }
if len(subset) == 0 {
delete(l.storages, accountHash)
}
} }
return nil return nil
}) })
return wg.Wait() return eg.Wait()
} }