mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-20 23:09:27 +00:00
refine
Signed-off-by: jsvisa <delweng@gmail.com>
This commit is contained in:
parent
bd840a1c18
commit
20a3a7ded2
1 changed files with 75 additions and 114 deletions
|
|
@ -334,45 +334,32 @@ func traverseState(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// StorageCallbacks defines the callbacks for different storage traversal modes
|
type OnStorageNodeHook func(node common.Hash, path []byte) error
|
||||||
type StorageCallbacks struct {
|
|
||||||
// Called for each storage node (only for raw mode)
|
|
||||||
OnStorageNode func(node common.Hash, path []byte) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// createSimpleStorageCallbacks creates callbacks for simple storage traversal
|
// createRawStorageHook creates hooks for raw storage traversal with verification
|
||||||
func createSimpleStorageCallbacks() *StorageCallbacks {
|
func createRawStorageHook(reader database.NodeReader, accountHash common.Hash) OnStorageNodeHook {
|
||||||
return &StorageCallbacks{
|
return func(node common.Hash, path []byte) error {
|
||||||
OnStorageNode: nil, // Simple mode doesn't process nodes
|
if node != (common.Hash{}) {
|
||||||
}
|
blob, _ := reader.Node(accountHash, path, node)
|
||||||
}
|
if len(blob) == 0 {
|
||||||
|
log.Error("Missing trie node(storage)", "hash", node)
|
||||||
// createRawStorageCallbacks creates callbacks for raw storage traversal with verification
|
return errors.New("missing storage")
|
||||||
func createRawStorageCallbacks(reader database.NodeReader, accountHash common.Hash) *StorageCallbacks {
|
|
||||||
return &StorageCallbacks{
|
|
||||||
OnStorageNode: func(node common.Hash, path []byte) error {
|
|
||||||
if node != (common.Hash{}) {
|
|
||||||
blob, _ := reader.Node(accountHash, path, node)
|
|
||||||
if len(blob) == 0 {
|
|
||||||
log.Error("Missing trie node(storage)", "hash", node)
|
|
||||||
return errors.New("missing storage")
|
|
||||||
}
|
|
||||||
if !bytes.Equal(crypto.Keccak256(blob), node.Bytes()) {
|
|
||||||
log.Error("Invalid trie node(storage)", "hash", node.Hex(), "value", blob)
|
|
||||||
return errors.New("invalid storage node")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
if !bytes.Equal(crypto.Keccak256(blob), node.Bytes()) {
|
||||||
},
|
log.Error("Invalid trie node(storage)", "hash", node.Hex(), "value", blob)
|
||||||
|
return errors.New("invalid storage node")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// traverseStorageParallelWithCallbacks parallelizes storage trie traversal using callbacks
|
// traverseStorage parallelizes storage trie traversal
|
||||||
func traverseStorageParallelWithCallbacks(ctx context.Context, storageTrie *trie.StateTrie, startKey, limitKey []byte, callbacks *StorageCallbacks, raw bool) (slots, nodes uint64, err error) {
|
func traverseStorage(ctx context.Context, storageTrie *trie.StateTrie, startKey, limitKey []byte, raw bool, hook OnStorageNodeHook) (uint64, uint64, error) {
|
||||||
var (
|
var (
|
||||||
eg, cctx = errgroup.WithContext(ctx)
|
eg, cctx = errgroup.WithContext(ctx)
|
||||||
slotsAtomic atomic.Uint64
|
slots atomic.Uint64
|
||||||
nodesAtomic atomic.Uint64
|
nodes atomic.Uint64
|
||||||
)
|
)
|
||||||
|
|
||||||
for i := 0; i < 16; i++ {
|
for i := 0; i < 16; i++ {
|
||||||
|
|
@ -410,12 +397,12 @@ func traverseStorageParallelWithCallbacks(ctx context.Context, storageTrie *trie
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
localSlots, localNodes, err := traverseStorageBranchWithCallbacks(cctx, storageTrie, branchStart, branchLimit, callbacks, raw)
|
localSlots, localNodes, err := traverseStorageBranchWithHooks(cctx, storageTrie, branchStart, branchLimit, raw, hook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
slotsAtomic.Add(localSlots)
|
slots.Add(localSlots)
|
||||||
nodesAtomic.Add(localNodes)
|
nodes.Add(localNodes)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -424,11 +411,11 @@ func traverseStorageParallelWithCallbacks(ctx context.Context, storageTrie *trie
|
||||||
return 0, 0, err
|
return 0, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return slotsAtomic.Load(), nodesAtomic.Load(), nil
|
return slots.Load(), nodes.Load(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// traverseStorageBranchWithCallbacks traverses a specific range of the storage trie using callbacks
|
// traverseStorageBranchWithHooks traverses a specific range of the storage trie using hooks
|
||||||
func traverseStorageBranchWithCallbacks(ctx context.Context, storageTrie *trie.StateTrie, startKey, limitKey []byte, callbacks *StorageCallbacks, raw bool) (slots, nodes uint64, err error) {
|
func traverseStorageBranchWithHooks(ctx context.Context, storageTrie *trie.StateTrie, startKey, limitKey []byte, raw bool, hook OnStorageNodeHook) (slots, nodes uint64, err error) {
|
||||||
nodeIter, err := storageTrie.NodeIterator(startKey)
|
nodeIter, err := storageTrie.NodeIterator(startKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, err
|
return 0, 0, err
|
||||||
|
|
@ -444,8 +431,8 @@ func traverseStorageBranchWithCallbacks(ctx context.Context, storageTrie *trie.S
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes++
|
nodes++
|
||||||
if callbacks != nil && callbacks.OnStorageNode != nil {
|
if hook != nil {
|
||||||
if err := callbacks.OnStorageNode(nodeIter.Hash(), nodeIter.Path()); err != nil {
|
if err := hook(nodeIter.Hash(), nodeIter.Path()); err != nil {
|
||||||
return 0, 0, err
|
return 0, 0, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -470,7 +457,6 @@ func traverseStorageBranchWithCallbacks(ctx context.Context, storageTrie *trie.S
|
||||||
if limitKey != nil && bytes.Compare(storageIter.Key, limitKey) >= 0 {
|
if limitKey != nil && bytes.Compare(storageIter.Key, limitKey) >= 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
slots++
|
slots++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -572,19 +558,17 @@ func (ts *traverseSetup) traverseAccount(ctx context.Context, counters *traverse
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var callbacks *StorageCallbacks
|
var hook OnStorageNodeHook
|
||||||
if raw {
|
if raw {
|
||||||
reader, err := ts.triedb.NodeReader(ts.config.root)
|
reader, err := ts.triedb.NodeReader(ts.config.root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("State is non-existent", "root", ts.config.root)
|
log.Error("State is non-existent", "root", ts.config.root)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
callbacks = createRawStorageCallbacks(reader, ts.config.account)
|
hook = createRawStorageHook(reader, ts.config.account)
|
||||||
} else {
|
|
||||||
callbacks = createSimpleStorageCallbacks()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
slots, nodes, err := traverseStorageParallelWithCallbacks(ctx, storageTrie, ts.config.startKey, ts.config.limitKey, callbacks, raw)
|
slots, nodes, err := traverseStorage(ctx, storageTrie, ts.config.startKey, ts.config.limitKey, raw, hook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to traverse storage trie", "root", acc.Root, "err", err)
|
log.Error("Failed to traverse storage trie", "root", acc.Root, "err", err)
|
||||||
return err
|
return err
|
||||||
|
|
@ -649,15 +633,14 @@ func (ts *traverseSetup) traverseState(ctx context.Context, counters *traverseCo
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create appropriate callbacks based on traversal mode
|
var hooks *TraverseHooks
|
||||||
var callbacks *TraverseCallbacks
|
|
||||||
if raw {
|
if raw {
|
||||||
callbacks = ts.createRawCallbacks(counters, reader)
|
hooks = ts.createRawHooks(reader)
|
||||||
} else {
|
} else {
|
||||||
callbacks = ts.createSimpleCallbacks(counters)
|
hooks = ts.createSimpleHooks()
|
||||||
}
|
}
|
||||||
|
|
||||||
return ts.traverseStateBranchWithCallbacks(ctx, startKey, limitKey, callbacks, raw)
|
return ts.traverseStateBranchWithHooks(ctx, startKey, limitKey, raw, counters, hooks)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -715,50 +698,36 @@ func parseTraverseArgs(ctx *cli.Context) (*traverseConfig, error) {
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TraverseCallbacks defines the callbacks for different traversal modes
|
// TraverseHooks defines the hooks for different traversal modes
|
||||||
type TraverseCallbacks struct {
|
type TraverseHooks struct {
|
||||||
// Called for each trie account node (only for raw mode)
|
// Called for each trie account node (only for raw mode)
|
||||||
OnNode func(node common.Hash, path []byte) error
|
OnAccountNode func(node common.Hash, path []byte) error
|
||||||
// Called for each account
|
// Called for each storage trie
|
||||||
OnAccount func(acc types.StateAccount, accountHash common.Hash) error
|
OnStorageTrie func(ctx context.Context, storageTrie *trie.StateTrie, accountHash common.Hash) (slots, nodes uint64, err error)
|
||||||
// Called for each storage slot
|
|
||||||
OnStorage func(ctx context.Context, storageTrie *trie.StateTrie, accountHash common.Hash) (slots, nodes uint64, err error)
|
|
||||||
// Called for each code
|
// Called for each code
|
||||||
OnCode func(codeHash []byte, accountHash common.Hash) error
|
OnCode func(codeHash []byte, accountHash common.Hash) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// createSimpleCallbacks creates callbacks for simple traversal mode
|
// createSimpleHooks creates hooks for simple traversal mode
|
||||||
func (ts *traverseSetup) createSimpleCallbacks(counters *traverseCounters) *TraverseCallbacks {
|
func (ts *traverseSetup) createSimpleHooks() *TraverseHooks {
|
||||||
return &TraverseCallbacks{
|
return &TraverseHooks{
|
||||||
OnAccount: func(acc types.StateAccount, accountHash common.Hash) error {
|
OnStorageTrie: func(ctx context.Context, storageTrie *trie.StateTrie, accountHash common.Hash) (slots, nodes uint64, err error) {
|
||||||
counters.accounts.Add(1)
|
return traverseStorage(ctx, storageTrie, nil, nil, false, nil)
|
||||||
return nil
|
|
||||||
},
|
|
||||||
OnStorage: func(ctx context.Context, storageTrie *trie.StateTrie, accountHash common.Hash) (slots, nodes uint64, err error) {
|
|
||||||
callbacks := createSimpleStorageCallbacks()
|
|
||||||
s, n, err := traverseStorageParallelWithCallbacks(ctx, storageTrie, nil, nil, callbacks, false)
|
|
||||||
if err != nil {
|
|
||||||
return 0, 0, err
|
|
||||||
}
|
|
||||||
counters.slots.Add(s)
|
|
||||||
return s, n, nil
|
|
||||||
},
|
},
|
||||||
OnCode: func(codeHash []byte, accountHash common.Hash) error {
|
OnCode: func(codeHash []byte, accountHash common.Hash) error {
|
||||||
if !rawdb.HasCode(ts.chaindb, common.BytesToHash(codeHash)) {
|
if !rawdb.HasCode(ts.chaindb, common.BytesToHash(codeHash)) {
|
||||||
log.Error("Code is missing", "hash", common.BytesToHash(codeHash))
|
log.Error("Code is missing", "hash", common.BytesToHash(codeHash))
|
||||||
return errors.New("missing code")
|
return errors.New("missing code")
|
||||||
}
|
}
|
||||||
counters.codes.Add(1)
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// createRawCallbacks creates callbacks for raw traversal mode with detailed verification
|
// createRawHooks creates hooks for raw traversal mode with detailed verification
|
||||||
func (ts *traverseSetup) createRawCallbacks(counters *traverseCounters, reader database.NodeReader) *TraverseCallbacks {
|
func (ts *traverseSetup) createRawHooks(reader database.NodeReader) *TraverseHooks {
|
||||||
return &TraverseCallbacks{
|
return &TraverseHooks{
|
||||||
OnNode: func(node common.Hash, path []byte) error {
|
OnAccountNode: func(node common.Hash, path []byte) error {
|
||||||
counters.nodes.Add(1)
|
|
||||||
if node != (common.Hash{}) {
|
if node != (common.Hash{}) {
|
||||||
blob, _ := reader.Node(common.Hash{}, path, node)
|
blob, _ := reader.Node(common.Hash{}, path, node)
|
||||||
if len(blob) == 0 {
|
if len(blob) == 0 {
|
||||||
|
|
@ -772,33 +741,22 @@ func (ts *traverseSetup) createRawCallbacks(counters *traverseCounters, reader d
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
OnAccount: func(acc types.StateAccount, accountHash common.Hash) error {
|
OnStorageTrie: func(ctx context.Context, storageTrie *trie.StateTrie, accountHash common.Hash) (slots, nodes uint64, err error) {
|
||||||
counters.accounts.Add(1)
|
hook := createRawStorageHook(reader, accountHash)
|
||||||
return nil
|
return traverseStorage(ctx, storageTrie, nil, nil, true, hook)
|
||||||
},
|
|
||||||
OnStorage: func(ctx context.Context, storageTrie *trie.StateTrie, accountHash common.Hash) (slots, nodes uint64, err error) {
|
|
||||||
callbacks := createRawStorageCallbacks(reader, accountHash)
|
|
||||||
s, n, err := traverseStorageParallelWithCallbacks(ctx, storageTrie, nil, nil, callbacks, true)
|
|
||||||
if err != nil {
|
|
||||||
return 0, 0, err
|
|
||||||
}
|
|
||||||
counters.slots.Add(s)
|
|
||||||
counters.nodes.Add(n)
|
|
||||||
return s, n, nil
|
|
||||||
},
|
},
|
||||||
OnCode: func(codeHash []byte, accountHash common.Hash) error {
|
OnCode: func(codeHash []byte, accountHash common.Hash) error {
|
||||||
if !rawdb.HasCode(ts.chaindb, common.BytesToHash(codeHash)) {
|
if !rawdb.HasCode(ts.chaindb, common.BytesToHash(codeHash)) {
|
||||||
log.Error("Code is missing", "account", accountHash)
|
log.Error("Code is missing", "account", accountHash)
|
||||||
return errors.New("missing code")
|
return errors.New("missing code")
|
||||||
}
|
}
|
||||||
counters.codes.Add(1)
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// traverseStateBranchWithCallbacks provides common branch traversal logic using callbacks
|
// traverseStateBranchWithHooks provides common branch traversal logic using hooks
|
||||||
func (ts *traverseSetup) traverseStateBranchWithCallbacks(ctx context.Context, startKey, limitKey []byte, callbacks *TraverseCallbacks, raw bool) error {
|
func (ts *traverseSetup) traverseStateBranchWithHooks(ctx context.Context, startKey, limitKey []byte, raw bool, counters *traverseCounters, hooks *TraverseHooks) error {
|
||||||
accIter, err := ts.trie.NodeIterator(startKey)
|
accIter, err := ts.trie.NodeIterator(startKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -813,8 +771,9 @@ func (ts *traverseSetup) traverseStateBranchWithCallbacks(ctx context.Context, s
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
if callbacks.OnNode != nil {
|
counters.nodes.Add(1)
|
||||||
if err := callbacks.OnNode(accIter.Hash(), accIter.Path()); err != nil {
|
if hooks != nil && hooks.OnAccountNode != nil {
|
||||||
|
if err := hooks.OnAccountNode(accIter.Hash(), accIter.Path()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -824,6 +783,7 @@ func (ts *traverseSetup) traverseStateBranchWithCallbacks(ctx context.Context, s
|
||||||
if limitKey != nil && bytes.Compare(accIter.LeafKey(), limitKey) >= 0 {
|
if limitKey != nil && bytes.Compare(accIter.LeafKey(), limitKey) >= 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
counters.accounts.Add(1)
|
||||||
|
|
||||||
var acc types.StateAccount
|
var acc types.StateAccount
|
||||||
if err := rlp.DecodeBytes(accIter.LeafBlob(), &acc); err != nil {
|
if err := rlp.DecodeBytes(accIter.LeafBlob(), &acc); err != nil {
|
||||||
|
|
@ -833,11 +793,6 @@ func (ts *traverseSetup) traverseStateBranchWithCallbacks(ctx context.Context, s
|
||||||
|
|
||||||
accountHash := common.BytesToHash(accIter.LeafKey())
|
accountHash := common.BytesToHash(accIter.LeafKey())
|
||||||
|
|
||||||
if err := callbacks.OnAccount(acc, accountHash); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process storage if present
|
|
||||||
if acc.Root != types.EmptyRootHash {
|
if acc.Root != types.EmptyRootHash {
|
||||||
id := trie.StorageTrieID(ts.config.root, accountHash, acc.Root)
|
id := trie.StorageTrieID(ts.config.root, accountHash, acc.Root)
|
||||||
storageTrie, err := trie.NewStateTrie(id, ts.triedb)
|
storageTrie, err := trie.NewStateTrie(id, ts.triedb)
|
||||||
|
|
@ -846,15 +801,21 @@ func (ts *traverseSetup) traverseStateBranchWithCallbacks(ctx context.Context, s
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, _, err := callbacks.OnStorage(ctx, storageTrie, accountHash); err != nil {
|
if hooks != nil && hooks.OnStorageTrie != nil {
|
||||||
return err
|
slots, nodes, err := hooks.OnStorageTrie(ctx, storageTrie, accountHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
counters.slots.Add(slots)
|
||||||
|
counters.nodes.Add(nodes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !bytes.Equal(acc.CodeHash, types.EmptyCodeHash.Bytes()) {
|
if !bytes.Equal(acc.CodeHash, types.EmptyCodeHash.Bytes()) {
|
||||||
if err := callbacks.OnCode(acc.CodeHash, accountHash); err != nil {
|
if err := hooks.OnCode(acc.CodeHash, accountHash); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
counters.codes.Add(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -873,11 +834,12 @@ func (ts *traverseSetup) traverseStateBranchWithCallbacks(ctx context.Context, s
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we've reached the limit for this branch
|
|
||||||
if limitKey != nil && bytes.Compare(accIter.Key, limitKey) >= 0 {
|
if limitKey != nil && bytes.Compare(accIter.Key, limitKey) >= 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
counters.accounts.Add(1)
|
||||||
|
|
||||||
var acc types.StateAccount
|
var acc types.StateAccount
|
||||||
if err := rlp.DecodeBytes(accIter.Value, &acc); err != nil {
|
if err := rlp.DecodeBytes(accIter.Value, &acc); err != nil {
|
||||||
log.Error("Invalid account encountered during traversal", "err", err)
|
log.Error("Invalid account encountered during traversal", "err", err)
|
||||||
|
|
@ -886,11 +848,6 @@ func (ts *traverseSetup) traverseStateBranchWithCallbacks(ctx context.Context, s
|
||||||
|
|
||||||
accountHash := common.BytesToHash(accIter.Key)
|
accountHash := common.BytesToHash(accIter.Key)
|
||||||
|
|
||||||
// Process account
|
|
||||||
if err := callbacks.OnAccount(acc, accountHash); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process storage if present
|
// Process storage if present
|
||||||
if acc.Root != types.EmptyRootHash {
|
if acc.Root != types.EmptyRootHash {
|
||||||
id := trie.StorageTrieID(ts.config.root, accountHash, acc.Root)
|
id := trie.StorageTrieID(ts.config.root, accountHash, acc.Root)
|
||||||
|
|
@ -900,16 +857,20 @@ func (ts *traverseSetup) traverseStateBranchWithCallbacks(ctx context.Context, s
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, _, err := callbacks.OnStorage(ctx, storageTrie, accountHash); err != nil {
|
slots, nodes, err := hooks.OnStorageTrie(ctx, storageTrie, accountHash)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
counters.slots.Add(slots)
|
||||||
|
counters.nodes.Add(nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process code if present
|
// Process code if present
|
||||||
if !bytes.Equal(acc.CodeHash, types.EmptyCodeHash.Bytes()) {
|
if !bytes.Equal(acc.CodeHash, types.EmptyCodeHash.Bytes()) {
|
||||||
if err := callbacks.OnCode(acc.CodeHash, accountHash); err != nil {
|
if err := hooks.OnCode(acc.CodeHash, accountHash); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
counters.codes.Add(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue