mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-16 09:50:45 +00:00
trie/bintrie: fix NodeIterator Empty node handling
Fix three issues in the binary trie NodeIterator: 1. Empty nodes now properly backtrack to parent and continue iteration instead of terminating the entire walk early. 2. HashedNode resolver handles nil data (all-zeros hash) gracefully by treating it as Empty rather than panicking. 3. Parent update after node resolution guards against stack underflow when resolving the root node itself.
This commit is contained in:
parent
35b91092c5
commit
6cc4dc5f10
1 changed files with 24 additions and 8 deletions
|
|
@ -119,10 +119,17 @@ func (it *binaryNodeIterator) Next(descend bool) bool {
|
||||||
return it.Next(descend)
|
return it.Next(descend)
|
||||||
case HashedNode:
|
case HashedNode:
|
||||||
// resolve the node
|
// resolve the node
|
||||||
data, err := it.trie.nodeResolver(it.Path(), common.Hash(node))
|
resolverPath := it.Path()
|
||||||
|
data, err := it.trie.nodeResolver(resolverPath, common.Hash(node))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
if data == nil {
|
||||||
|
// Empty/nil node — treat as Empty, backtrack
|
||||||
|
it.current = Empty{}
|
||||||
|
it.stack[len(it.stack)-1].Node = it.current
|
||||||
|
return it.Next(descend)
|
||||||
|
}
|
||||||
it.current, err = DeserializeNodeWithHash(data, len(it.stack)-1, common.Hash(node))
|
it.current, err = DeserializeNodeWithHash(data, len(it.stack)-1, common.Hash(node))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
@ -130,16 +137,25 @@ func (it *binaryNodeIterator) Next(descend bool) bool {
|
||||||
|
|
||||||
// update the stack and parent with the resolved node
|
// update the stack and parent with the resolved node
|
||||||
it.stack[len(it.stack)-1].Node = it.current
|
it.stack[len(it.stack)-1].Node = it.current
|
||||||
parent := &it.stack[len(it.stack)-2]
|
if len(it.stack) >= 2 {
|
||||||
if parent.Index == 0 {
|
parent := &it.stack[len(it.stack)-2]
|
||||||
parent.Node.(*InternalNode).left = it.current
|
if parent.Index == 0 {
|
||||||
} else {
|
parent.Node.(*InternalNode).left = it.current
|
||||||
parent.Node.(*InternalNode).right = it.current
|
} else {
|
||||||
|
parent.Node.(*InternalNode).right = it.current
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return it.Next(descend)
|
return it.Next(descend)
|
||||||
case Empty:
|
case Empty:
|
||||||
// do nothing
|
// Empty node - go back to parent and continue
|
||||||
return false
|
if len(it.stack) <= 1 {
|
||||||
|
it.lastErr = errIteratorEnd
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
it.stack = it.stack[:len(it.stack)-1]
|
||||||
|
it.current = it.stack[len(it.stack)-1].Node
|
||||||
|
it.stack[len(it.stack)-1].Index++
|
||||||
|
return it.Next(descend)
|
||||||
default:
|
default:
|
||||||
panic("invalid node type")
|
panic("invalid node type")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue