-
Notifications
You must be signed in to change notification settings - Fork 21.4k
Closed
Labels
Description
System information
Geth version: v1.12.0
Expected behaviour
The documented behavior of a NodeIterator
constructed with a start path:
// NodeIterator returns an iterator that returns nodes of the trie. Iteration starts at
// the key after the given start key.
func (t *Trie) NodeIterator(start []byte) NodeIterator {
Actual behaviour
When the trie contains a value node whose key is a prefix of the passed start path, this value node's key (with terminator) compares >=
to the seeked path, so seek
stops at it, although the actual path is lexicographically less than the start path.
Steps to reproduce the behaviour
Run the following:
package main
import (
"fmt"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/trie"
)
func main() {
db := trie.NewDatabase(rawdb.NewMemoryDatabase())
tree := trie.NewEmpty(db)
tree.MustUpdate([]byte("foo"), []byte("bar"))
tree.MustUpdate([]byte("food"), []byte("baz"))
tree.MustUpdate([]byte("quux"), []byte("jar"))
it := tree.NodeIterator([]byte("food"))
for it.Next(true) {
if it.Leaf() {
key := string(it.LeafKey())
if key == "foo" {
panic(fmt.Sprintf("reached key %s", key))
}
}
}
}
Note that this also panics if food
is not added to the trie.
Proposed fix
I expect this issue rarely manifests because in practice, geth trie values are only inserted at 32-byte leaf nodes, so no leaf key will prefix a seeked start path. However it is not a consistent behavior, so it should be fixed or documented.
I propose a fix here: #27838
learnerLj