fix: trienode calculate

Signed-off-by: jsvisa <delweng@gmail.com>
This commit is contained in:
jsvisa 2025-08-07 11:27:30 +08:00 committed by Gary Rong
parent 2ddf19a15a
commit 116f327c27

View file

@ -31,6 +31,14 @@ import (
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
) )
var (
accountSnapKeySize = int64(len(rawdb.SnapshotAccountPrefix) + common.HashLength)
storageSnapKeySize = int64(len(rawdb.SnapshotStoragePrefix) + common.HashLength + common.HashLength)
accountTrieKeyPrefixSize = int64(len(rawdb.TrieNodeAccountPrefix))
storageTrieKeyPrefixSize = int64(len(rawdb.TrieNodeStoragePrefix) + common.HashLength)
codeKeySize = int64(len(rawdb.CodePrefix) + common.HashLength)
)
// stateSizeMetrics represents the current state size statistics // stateSizeMetrics represents the current state size statistics
type stateSizeMetrics struct { type stateSizeMetrics struct {
Root common.Hash // Root hash of the state trie Root common.Hash // Root hash of the state trie
@ -180,7 +188,6 @@ func (g *StateSizeGenerator) initialize() chan struct{} {
// handleUpdate processes a single update with proper root continuity checking // handleUpdate processes a single update with proper root continuity checking
func (g *StateSizeGenerator) handleUpdate(update *stateUpdate, initialized bool) { func (g *StateSizeGenerator) handleUpdate(update *stateUpdate, initialized bool) {
// Calculate the diff
diff := g.calculateUpdateDiff(update) diff := g.calculateUpdateDiff(update)
var targetMetrics *stateSizeMetrics var targetMetrics *stateSizeMetrics
@ -192,12 +199,7 @@ func (g *StateSizeGenerator) handleUpdate(update *stateUpdate, initialized bool)
// Check root continuity - the update should build on our current state // Check root continuity - the update should build on our current state
if targetMetrics.Root != (common.Hash{}) && targetMetrics.Root != update.originRoot { if targetMetrics.Root != (common.Hash{}) && targetMetrics.Root != update.originRoot {
log.Warn("State update root discontinuity detected", log.Warn("State update root discontinuity detected", "current", targetMetrics.Root, "updateOrigin", update.originRoot, "updateNew", update.root)
"current", targetMetrics.Root,
"updateOrigin", update.originRoot,
"updateNew", update.root)
// For now, we accept the discontinuity but log it
// In production, you might want to reset metrics or handle differently
} }
// Update to the new state root // Update to the new state root
@ -230,15 +232,20 @@ func (g *StateSizeGenerator) calculateUpdateDiff(update *stateUpdate) stateSizeM
log.Warn("State update missing account", "address", addr) log.Warn("State update missing account", "address", addr)
continue continue
} }
if len(newValue) == 0 {
oldLen, newLen := len(oldValue), len(newValue)
if oldLen > 0 && newLen == 0 {
// Account deletion
diff.AccountCount -= 1 diff.AccountCount -= 1
diff.AccountBytes -= common.HashLength diff.AccountBytes -= accountSnapKeySize + int64(oldLen)
} } else if oldLen == 0 && newLen > 0 {
if len(oldValue) == 0 { // Account creation
diff.AccountCount += 1 diff.AccountCount += 1
diff.AccountBytes += common.HashLength diff.AccountBytes += accountSnapKeySize + int64(newLen)
} else {
// Account update
diff.AccountBytes += int64(newLen - oldLen)
} }
diff.AccountBytes += int64(len(newValue) - len(oldValue))
} }
// Calculate storage changes // Calculate storage changes
@ -263,38 +270,58 @@ func (g *StateSizeGenerator) calculateUpdateDiff(update *stateUpdate) stateSizeM
log.Warn("State update missing storage slot", "address", addr, "key", key) log.Warn("State update missing storage slot", "address", addr, "key", key)
continue continue
} }
if len(newValue) == 0 {
oldLen, newLen := len(oldValue), len(newValue)
if oldLen > 0 && newLen == 0 {
// Storage deletion
diff.StorageCount -= 1 diff.StorageCount -= 1
diff.StorageBytes -= common.HashLength diff.StorageBytes -= storageSnapKeySize + int64(oldLen)
} } else if oldLen == 0 && newLen > 0 {
if len(oldValue) == 0 { // Storage creation
diff.StorageCount += 1 diff.StorageCount += 1
diff.StorageBytes += common.HashLength diff.StorageBytes += storageSnapKeySize + int64(newLen)
} else {
// Storage update
diff.StorageBytes += int64(newLen - oldLen)
} }
diff.StorageBytes += int64(len(newValue) - len(oldValue))
} }
} }
// Calculate trie node changes // Calculate trie node changes
for _, subset := range update.nodes.Sets { for owner, subset := range update.nodes.Sets {
for path, n := range subset.Nodes { isAccountTrie := owner == (common.Hash{})
if len(n.Blob) == 0 { var keyPrefixSize int64
if isAccountTrie {
keyPrefixSize = accountTrieKeyPrefixSize
} else {
keyPrefixSize = storageTrieKeyPrefixSize
}
// Iterate over Origins since every modified node has an origin entry
for path, oldNode := range subset.Origins {
newNode, hasNew := subset.Nodes[path]
keySize := keyPrefixSize + int64(len(path))
if len(oldNode) > 0 && (!hasNew || len(newNode.Blob) == 0) {
// Node deletion
diff.TrieNodeCount -= 1 diff.TrieNodeCount -= 1
diff.TrieNodeBytes -= int64(len(path) + common.HashLength) diff.TrieNodeBytes -= keySize + int64(len(oldNode))
} } else if len(oldNode) == 0 && hasNew && len(newNode.Blob) > 0 {
prev, ok := subset.Origins[path] // Node creation
if ok {
diff.TrieNodeCount += 1 diff.TrieNodeCount += 1
diff.TrieNodeBytes += int64(len(path) + common.HashLength) diff.TrieNodeBytes += keySize + int64(len(newNode.Blob))
} else if len(oldNode) > 0 && hasNew && len(newNode.Blob) > 0 {
// Node update
diff.TrieNodeBytes += int64(len(newNode.Blob) - len(oldNode))
} }
diff.TrieNodeBytes += int64(len(n.Blob) - len(prev))
} }
} }
// Calculate code changes // Calculate code changes
for _, code := range update.codes { for _, code := range update.codes {
diff.ContractCount += 1 diff.ContractCount += 1
diff.ContractBytes += int64(len(code.blob) + common.HashLength) diff.ContractBytes += codeKeySize + int64(len(code.blob))
} }
return diff return diff
@ -356,52 +383,52 @@ func (g *StateSizeGenerator) initializeMetrics() error {
// Metrics will be directly updated by each goroutine // Metrics will be directly updated by each goroutine
var ( var (
accountCount, accountBytes int64 accountSnapCount, accountSnapBytes int64
storageCount, storageBytes int64 storageSnapCount, storageSnapBytes int64
trieAccountNodeCount, trieAccountNodeBytes int64 accountTrieCount, accountTrieBytes int64
trieStorageNodeCount, trieStorageNodeBytes int64 storageTrieCount, storageTrieBytes int64
contractCount, contractBytes int64 contractCount, contractBytes int64
) )
// Start all table iterations concurrently with direct metric updates // Start all table iterations concurrently with direct metric updates
group.Go(func() error { group.Go(func() error {
count, bytes, err := g.iterateTable(ctx, rawdb.SnapshotAccountPrefix, "account") count, bytes, err := g.iterateTable(ctx, rawdb.SnapshotAccountPrefix, "accountSnap")
if err != nil { if err != nil {
return err return err
} }
accountCount, accountBytes = count, bytes accountSnapCount, accountSnapBytes = count, bytes
return nil return nil
}) })
group.Go(func() error { group.Go(func() error {
count, bytes, err := g.iterateTable(ctx, rawdb.SnapshotStoragePrefix, "storage") count, bytes, err := g.iterateTable(ctx, rawdb.SnapshotStoragePrefix, "storageSnap")
if err != nil { if err != nil {
return err return err
} }
storageCount, storageBytes = count, bytes storageSnapCount, storageSnapBytes = count, bytes
return nil return nil
}) })
group.Go(func() error { group.Go(func() error {
count, bytes, err := g.iterateTable(ctx, rawdb.TrieNodeAccountPrefix, "trie account node") count, bytes, err := g.iterateTable(ctx, rawdb.TrieNodeAccountPrefix, "accountTrie")
if err != nil { if err != nil {
return err return err
} }
trieAccountNodeCount, trieAccountNodeBytes = count, bytes accountTrieCount, accountTrieBytes = count, bytes
return nil return nil
}) })
group.Go(func() error { group.Go(func() error {
count, bytes, err := g.iterateTable(ctx, rawdb.TrieNodeStoragePrefix, "trie storage node") count, bytes, err := g.iterateTable(ctx, rawdb.TrieNodeStoragePrefix, "storageTrie")
if err != nil { if err != nil {
return err return err
} }
trieStorageNodeCount, trieStorageNodeBytes = count, bytes storageTrieCount, storageTrieBytes = count, bytes
return nil return nil
}) })
group.Go(func() error { group.Go(func() error {
count, bytes, err := g.iterateTable(ctx, rawdb.CodePrefix, "contract code") count, bytes, err := g.iterateTable(ctx, rawdb.CodePrefix, "contract")
if err != nil { if err != nil {
return err return err
} }
@ -414,12 +441,12 @@ func (g *StateSizeGenerator) initializeMetrics() error {
return err return err
} }
g.metrics.AccountCount = accountCount g.metrics.AccountCount = accountSnapCount
g.metrics.AccountBytes = accountBytes g.metrics.AccountBytes = accountSnapBytes
g.metrics.StorageCount = storageCount g.metrics.StorageCount = storageSnapCount
g.metrics.StorageBytes = storageBytes g.metrics.StorageBytes = storageSnapBytes
g.metrics.TrieNodeCount = trieAccountNodeCount + trieStorageNodeCount g.metrics.TrieNodeCount = accountTrieCount + storageTrieCount
g.metrics.TrieNodeBytes = trieAccountNodeBytes + trieStorageNodeBytes g.metrics.TrieNodeBytes = accountTrieBytes + storageTrieBytes
g.metrics.ContractCount = contractCount g.metrics.ContractCount = contractCount
g.metrics.ContractBytes = contractBytes g.metrics.ContractBytes = contractBytes