forked from cerc-io/plugeth
Merge pull request #24391 from rjl493456442/trie-iterator
trie: implement NodeBlob API for trie iterator
This commit is contained in:
commit
fc8ad1b70d
@ -86,6 +86,10 @@ type NodeIterator interface {
|
|||||||
// For leaf nodes, the last element of the path is the 'terminator symbol' 0x10.
|
// For leaf nodes, the last element of the path is the 'terminator symbol' 0x10.
|
||||||
Path() []byte
|
Path() []byte
|
||||||
|
|
||||||
|
// NodeBlob returns the rlp-encoded value of the current iterated node.
|
||||||
|
// If the node is an embedded node in its parent, nil is returned then.
|
||||||
|
NodeBlob() []byte
|
||||||
|
|
||||||
// Leaf returns true iff the current node is a leaf node.
|
// Leaf returns true iff the current node is a leaf node.
|
||||||
Leaf() bool
|
Leaf() bool
|
||||||
|
|
||||||
@ -224,6 +228,18 @@ func (it *nodeIterator) Path() []byte {
|
|||||||
return it.path
|
return it.path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (it *nodeIterator) NodeBlob() []byte {
|
||||||
|
if it.Hash() == (common.Hash{}) {
|
||||||
|
return nil // skip the non-standalone node
|
||||||
|
}
|
||||||
|
blob, err := it.resolveBlob(it.Hash().Bytes(), it.Path())
|
||||||
|
if err != nil {
|
||||||
|
it.err = err
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return blob
|
||||||
|
}
|
||||||
|
|
||||||
func (it *nodeIterator) Error() error {
|
func (it *nodeIterator) Error() error {
|
||||||
if it.err == errIteratorEnd {
|
if it.err == errIteratorEnd {
|
||||||
return nil
|
return nil
|
||||||
@ -362,6 +378,15 @@ func (it *nodeIterator) resolveHash(hash hashNode, path []byte) (node, error) {
|
|||||||
return resolved, err
|
return resolved, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (it *nodeIterator) resolveBlob(hash hashNode, path []byte) ([]byte, error) {
|
||||||
|
if it.resolver != nil {
|
||||||
|
if blob, err := it.resolver.Get(hash); err == nil && len(blob) > 0 {
|
||||||
|
return blob, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return it.trie.resolveBlob(hash, path)
|
||||||
|
}
|
||||||
|
|
||||||
func (st *nodeIteratorState) resolve(it *nodeIterator, path []byte) error {
|
func (st *nodeIteratorState) resolve(it *nodeIterator, path []byte) error {
|
||||||
if hash, ok := st.node.(hashNode); ok {
|
if hash, ok := st.node.(hashNode); ok {
|
||||||
resolved, err := it.resolveHash(hash, path)
|
resolved, err := it.resolveHash(hash, path)
|
||||||
@ -549,6 +574,10 @@ func (it *differenceIterator) Path() []byte {
|
|||||||
return it.b.Path()
|
return it.b.Path()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (it *differenceIterator) NodeBlob() []byte {
|
||||||
|
return it.b.NodeBlob()
|
||||||
|
}
|
||||||
|
|
||||||
func (it *differenceIterator) AddResolver(resolver ethdb.KeyValueReader) {
|
func (it *differenceIterator) AddResolver(resolver ethdb.KeyValueReader) {
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
}
|
}
|
||||||
@ -660,6 +689,10 @@ func (it *unionIterator) Path() []byte {
|
|||||||
return (*it.items)[0].Path()
|
return (*it.items)[0].Path()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (it *unionIterator) NodeBlob() []byte {
|
||||||
|
return (*it.items)[0].NodeBlob()
|
||||||
|
}
|
||||||
|
|
||||||
func (it *unionIterator) AddResolver(resolver ethdb.KeyValueReader) {
|
func (it *unionIterator) AddResolver(resolver ethdb.KeyValueReader) {
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
}
|
}
|
||||||
|
@ -525,3 +525,54 @@ func TestNodeIteratorLargeTrie(t *testing.T) {
|
|||||||
t.Fatalf("Too many lookups during seek, have %d want %d", have, want)
|
t.Fatalf("Too many lookups during seek, have %d want %d", have, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIteratorNodeBlob(t *testing.T) {
|
||||||
|
var (
|
||||||
|
db = memorydb.New()
|
||||||
|
triedb = NewDatabase(db)
|
||||||
|
trie, _ = New(common.Hash{}, triedb)
|
||||||
|
)
|
||||||
|
vals := []struct{ k, v string }{
|
||||||
|
{"do", "verb"},
|
||||||
|
{"ether", "wookiedoo"},
|
||||||
|
{"horse", "stallion"},
|
||||||
|
{"shaman", "horse"},
|
||||||
|
{"doge", "coin"},
|
||||||
|
{"dog", "puppy"},
|
||||||
|
{"somethingveryoddindeedthis is", "myothernodedata"},
|
||||||
|
}
|
||||||
|
all := make(map[string]string)
|
||||||
|
for _, val := range vals {
|
||||||
|
all[val.k] = val.v
|
||||||
|
trie.Update([]byte(val.k), []byte(val.v))
|
||||||
|
}
|
||||||
|
trie.Commit(nil)
|
||||||
|
triedb.Cap(0)
|
||||||
|
|
||||||
|
found := make(map[common.Hash][]byte)
|
||||||
|
it := trie.NodeIterator(nil)
|
||||||
|
for it.Next(true) {
|
||||||
|
if it.Hash() == (common.Hash{}) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
found[it.Hash()] = it.NodeBlob()
|
||||||
|
}
|
||||||
|
|
||||||
|
dbIter := db.NewIterator(nil, nil)
|
||||||
|
defer dbIter.Release()
|
||||||
|
|
||||||
|
var count int
|
||||||
|
for dbIter.Next() {
|
||||||
|
got, present := found[common.BytesToHash(dbIter.Key())]
|
||||||
|
if !present {
|
||||||
|
t.Fatalf("Miss trie node %v", dbIter.Key())
|
||||||
|
}
|
||||||
|
if !bytes.Equal(got, dbIter.Value()) {
|
||||||
|
t.Fatalf("Unexpected trie node want %v got %v", dbIter.Value(), got)
|
||||||
|
}
|
||||||
|
count += 1
|
||||||
|
}
|
||||||
|
if count != len(found) {
|
||||||
|
t.Fatal("Find extra trie node via iterator")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -514,6 +514,15 @@ func (t *Trie) resolveHash(n hashNode, prefix []byte) (node, error) {
|
|||||||
return nil, &MissingNodeError{NodeHash: hash, Path: prefix}
|
return nil, &MissingNodeError{NodeHash: hash, Path: prefix}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Trie) resolveBlob(n hashNode, prefix []byte) ([]byte, error) {
|
||||||
|
hash := common.BytesToHash(n)
|
||||||
|
blob, _ := t.db.Node(hash)
|
||||||
|
if len(blob) != 0 {
|
||||||
|
return blob, nil
|
||||||
|
}
|
||||||
|
return nil, &MissingNodeError{NodeHash: hash, Path: prefix}
|
||||||
|
}
|
||||||
|
|
||||||
// Hash returns the root hash of the trie. It does not write to the
|
// Hash returns the root hash of the trie. It does not write to the
|
||||||
// database and can be used even if the trie doesn't have one.
|
// database and can be used even if the trie doesn't have one.
|
||||||
func (t *Trie) Hash() common.Hash {
|
func (t *Trie) Hash() common.Hash {
|
||||||
|
Loading…
Reference in New Issue
Block a user