forked from cerc-io/plugeth
trie: add start key to NodeIterator constructors
The 'step' method is split into two parts, 'peek' and 'push'. peek returns the next state but doesn't make it current. The end of iteration was previously tracked by setting 'trie' to nil. End of iteration is now tracked using the 'iteratorEnd' error, which is slightly cleaner and requires less code.
This commit is contained in:
parent
a13e920af0
commit
4047ccad2f
@ -45,7 +45,7 @@ func (self *StateDB) RawDump() Dump {
|
|||||||
Accounts: make(map[string]DumpAccount),
|
Accounts: make(map[string]DumpAccount),
|
||||||
}
|
}
|
||||||
|
|
||||||
it := trie.NewIterator(self.trie.NodeIterator())
|
it := trie.NewIterator(self.trie.NodeIterator(nil))
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
addr := self.trie.GetKey(it.Key)
|
addr := self.trie.GetKey(it.Key)
|
||||||
var data Account
|
var data Account
|
||||||
@ -62,7 +62,7 @@ func (self *StateDB) RawDump() Dump {
|
|||||||
Code: common.Bytes2Hex(obj.Code(self.db)),
|
Code: common.Bytes2Hex(obj.Code(self.db)),
|
||||||
Storage: make(map[string]string),
|
Storage: make(map[string]string),
|
||||||
}
|
}
|
||||||
storageIt := trie.NewIterator(obj.getTrie(self.db).NodeIterator())
|
storageIt := trie.NewIterator(obj.getTrie(self.db).NodeIterator(nil))
|
||||||
for storageIt.Next() {
|
for storageIt.Next() {
|
||||||
account.Storage[common.Bytes2Hex(self.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(storageIt.Value)
|
account.Storage[common.Bytes2Hex(self.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(storageIt.Value)
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ func (it *NodeIterator) step() error {
|
|||||||
}
|
}
|
||||||
// Initialize the iterator if we've just started
|
// Initialize the iterator if we've just started
|
||||||
if it.stateIt == nil {
|
if it.stateIt == nil {
|
||||||
it.stateIt = it.state.trie.NodeIterator()
|
it.stateIt = it.state.trie.NodeIterator(nil)
|
||||||
}
|
}
|
||||||
// If we had data nodes previously, we surely have at least state nodes
|
// If we had data nodes previously, we surely have at least state nodes
|
||||||
if it.dataIt != nil {
|
if it.dataIt != nil {
|
||||||
@ -118,7 +118,7 @@ func (it *NodeIterator) step() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
it.dataIt = dataTrie.NodeIterator()
|
it.dataIt = dataTrie.NodeIterator(nil)
|
||||||
if !it.dataIt.Next(true) {
|
if !it.dataIt.Next(true) {
|
||||||
it.dataIt = nil
|
it.dataIt = nil
|
||||||
}
|
}
|
||||||
|
@ -481,7 +481,7 @@ func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common
|
|||||||
cb(h, value)
|
cb(h, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
it := trie.NewIterator(so.getTrie(db.db).NodeIterator())
|
it := trie.NewIterator(so.getTrie(db.db).NodeIterator(nil))
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
// ignore cached values
|
// ignore cached values
|
||||||
key := common.BytesToHash(db.trie.GetKey(it.Key))
|
key := common.BytesToHash(db.trie.GetKey(it.Key))
|
||||||
|
131
trie/iterator.go
131
trie/iterator.go
@ -19,10 +19,13 @@ package trie
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"container/heap"
|
"container/heap"
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var iteratorEnd = errors.New("end of iteration")
|
||||||
|
|
||||||
// Iterator is a key-value trie iterator that traverses a Trie.
|
// Iterator is a key-value trie iterator that traverses a Trie.
|
||||||
type Iterator struct {
|
type Iterator struct {
|
||||||
nodeIt NodeIterator
|
nodeIt NodeIterator
|
||||||
@ -79,25 +82,24 @@ type nodeIteratorState struct {
|
|||||||
hash common.Hash // Hash of the node being iterated (nil if not standalone)
|
hash common.Hash // Hash of the node being iterated (nil if not standalone)
|
||||||
node node // Trie node being iterated
|
node node // Trie node being iterated
|
||||||
parent common.Hash // Hash of the first full ancestor node (nil if current is the root)
|
parent common.Hash // Hash of the first full ancestor node (nil if current is the root)
|
||||||
child int // Child to be processed next
|
index int // Child to be processed next
|
||||||
pathlen int // Length of the path to this node
|
pathlen int // Length of the path to this node
|
||||||
}
|
}
|
||||||
|
|
||||||
type nodeIterator struct {
|
type nodeIterator struct {
|
||||||
trie *Trie // Trie being iterated
|
trie *Trie // Trie being iterated
|
||||||
stack []*nodeIteratorState // Hierarchy of trie nodes persisting the iteration state
|
stack []*nodeIteratorState // Hierarchy of trie nodes persisting the iteration state
|
||||||
|
err error // Failure set in case of an internal error in the iterator
|
||||||
err error // Failure set in case of an internal error in the iterator
|
path []byte // Path to the current node
|
||||||
|
|
||||||
path []byte // Path to the current node
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// newNodeIterator creates an post-order trie iterator.
|
func newNodeIterator(trie *Trie, start []byte) NodeIterator {
|
||||||
func newNodeIterator(trie *Trie) NodeIterator {
|
|
||||||
if trie.Hash() == emptyState {
|
if trie.Hash() == emptyState {
|
||||||
return new(nodeIterator)
|
return new(nodeIterator)
|
||||||
}
|
}
|
||||||
return &nodeIterator{trie: trie}
|
it := &nodeIterator{trie: trie}
|
||||||
|
it.seek(start)
|
||||||
|
return it
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash returns the hash of the current node
|
// Hash returns the hash of the current node
|
||||||
@ -147,6 +149,9 @@ func (it *nodeIterator) Path() []byte {
|
|||||||
|
|
||||||
// Error returns the error set in case of an internal error in the iterator
|
// Error returns the error set in case of an internal error in the iterator
|
||||||
func (it *nodeIterator) Error() error {
|
func (it *nodeIterator) Error() error {
|
||||||
|
if it.err == iteratorEnd {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return it.err
|
return it.err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,47 +160,54 @@ func (it *nodeIterator) Error() error {
|
|||||||
// sets the Error field to the encountered failure. If `descend` is false,
|
// sets the Error field to the encountered failure. If `descend` is false,
|
||||||
// skips iterating over any subnodes of the current node.
|
// skips iterating over any subnodes of the current node.
|
||||||
func (it *nodeIterator) Next(descend bool) bool {
|
func (it *nodeIterator) Next(descend bool) bool {
|
||||||
// If the iterator failed previously, don't do anything
|
|
||||||
if it.err != nil {
|
if it.err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// Otherwise step forward with the iterator and report any errors
|
// Otherwise step forward with the iterator and report any errors
|
||||||
if err := it.step(descend); err != nil {
|
state, parentIndex, path, err := it.peek(descend)
|
||||||
|
if err != nil {
|
||||||
it.err = err
|
it.err = err
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return it.trie != nil
|
it.push(state, parentIndex, path)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// step moves the iterator to the next node of the trie.
|
func (it *nodeIterator) seek(prefix []byte) {
|
||||||
func (it *nodeIterator) step(descend bool) error {
|
// The path we're looking for is the hex encoded key without terminator.
|
||||||
if it.trie == nil {
|
key := keybytesToHex(prefix)
|
||||||
// Abort if we reached the end of the iteration
|
key = key[:len(key)-1]
|
||||||
return nil
|
// Move forward until we're just before the closest match to key.
|
||||||
|
for {
|
||||||
|
state, parentIndex, path, err := it.peek(bytes.HasPrefix(key, it.path))
|
||||||
|
if err != nil || bytes.Compare(path, key) >= 0 {
|
||||||
|
it.err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
it.push(state, parentIndex, path)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// peek creates the next state of the iterator.
|
||||||
|
func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, error) {
|
||||||
if len(it.stack) == 0 {
|
if len(it.stack) == 0 {
|
||||||
// Initialize the iterator if we've just started.
|
// Initialize the iterator if we've just started.
|
||||||
root := it.trie.Hash()
|
root := it.trie.Hash()
|
||||||
state := &nodeIteratorState{node: it.trie.root, child: -1}
|
state := &nodeIteratorState{node: it.trie.root, index: -1}
|
||||||
if root != emptyRoot {
|
if root != emptyRoot {
|
||||||
state.hash = root
|
state.hash = root
|
||||||
}
|
}
|
||||||
it.stack = append(it.stack, state)
|
return state, nil, nil, nil
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !descend {
|
if !descend {
|
||||||
// If we're skipping children, pop the current node first
|
// If we're skipping children, pop the current node first
|
||||||
it.path = it.path[:it.stack[len(it.stack)-1].pathlen]
|
it.pop()
|
||||||
it.stack = it.stack[:len(it.stack)-1]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Continue iteration to the next child
|
// Continue iteration to the next child
|
||||||
outer:
|
|
||||||
for {
|
for {
|
||||||
if len(it.stack) == 0 {
|
if len(it.stack) == 0 {
|
||||||
it.trie = nil
|
return nil, nil, nil, iteratorEnd
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
parent := it.stack[len(it.stack)-1]
|
parent := it.stack[len(it.stack)-1]
|
||||||
ancestor := parent.hash
|
ancestor := parent.hash
|
||||||
@ -203,63 +215,76 @@ outer:
|
|||||||
ancestor = parent.parent
|
ancestor = parent.parent
|
||||||
}
|
}
|
||||||
if node, ok := parent.node.(*fullNode); ok {
|
if node, ok := parent.node.(*fullNode); ok {
|
||||||
// Full node, iterate over children
|
// Full node, move to the first non-nil child.
|
||||||
for parent.child++; parent.child < len(node.Children); parent.child++ {
|
for i := parent.index + 1; i < len(node.Children); i++ {
|
||||||
child := node.Children[parent.child]
|
child := node.Children[i]
|
||||||
if child != nil {
|
if child != nil {
|
||||||
hash, _ := child.cache()
|
hash, _ := child.cache()
|
||||||
it.stack = append(it.stack, &nodeIteratorState{
|
state := &nodeIteratorState{
|
||||||
hash: common.BytesToHash(hash),
|
hash: common.BytesToHash(hash),
|
||||||
node: child,
|
node: child,
|
||||||
parent: ancestor,
|
parent: ancestor,
|
||||||
child: -1,
|
index: -1,
|
||||||
pathlen: len(it.path),
|
pathlen: len(it.path),
|
||||||
})
|
}
|
||||||
it.path = append(it.path, byte(parent.child))
|
path := append(it.path, byte(i))
|
||||||
break outer
|
parent.index = i - 1
|
||||||
|
return state, &parent.index, path, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if node, ok := parent.node.(*shortNode); ok {
|
} else if node, ok := parent.node.(*shortNode); ok {
|
||||||
// Short node, return the pointer singleton child
|
// Short node, return the pointer singleton child
|
||||||
if parent.child < 0 {
|
if parent.index < 0 {
|
||||||
parent.child++
|
|
||||||
hash, _ := node.Val.cache()
|
hash, _ := node.Val.cache()
|
||||||
it.stack = append(it.stack, &nodeIteratorState{
|
state := &nodeIteratorState{
|
||||||
hash: common.BytesToHash(hash),
|
hash: common.BytesToHash(hash),
|
||||||
node: node.Val,
|
node: node.Val,
|
||||||
parent: ancestor,
|
parent: ancestor,
|
||||||
child: -1,
|
index: -1,
|
||||||
pathlen: len(it.path),
|
pathlen: len(it.path),
|
||||||
})
|
|
||||||
if hasTerm(node.Key) {
|
|
||||||
it.path = append(it.path, node.Key[:len(node.Key)-1]...)
|
|
||||||
} else {
|
|
||||||
it.path = append(it.path, node.Key...)
|
|
||||||
}
|
}
|
||||||
break
|
var path []byte
|
||||||
|
if hasTerm(node.Key) {
|
||||||
|
path = append(it.path, node.Key[:len(node.Key)-1]...)
|
||||||
|
} else {
|
||||||
|
path = append(it.path, node.Key...)
|
||||||
|
}
|
||||||
|
return state, &parent.index, path, nil
|
||||||
}
|
}
|
||||||
} else if hash, ok := parent.node.(hashNode); ok {
|
} else if hash, ok := parent.node.(hashNode); ok {
|
||||||
// Hash node, resolve the hash child from the database
|
// Hash node, resolve the hash child from the database
|
||||||
if parent.child < 0 {
|
if parent.index < 0 {
|
||||||
parent.child++
|
|
||||||
node, err := it.trie.resolveHash(hash, nil, nil)
|
node, err := it.trie.resolveHash(hash, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return it.stack[len(it.stack)-1], &parent.index, it.path, err
|
||||||
}
|
}
|
||||||
it.stack = append(it.stack, &nodeIteratorState{
|
state := &nodeIteratorState{
|
||||||
hash: common.BytesToHash(hash),
|
hash: common.BytesToHash(hash),
|
||||||
node: node,
|
node: node,
|
||||||
parent: ancestor,
|
parent: ancestor,
|
||||||
child: -1,
|
index: -1,
|
||||||
pathlen: len(it.path),
|
pathlen: len(it.path),
|
||||||
})
|
}
|
||||||
break
|
return state, &parent.index, it.path, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
it.path = it.path[:parent.pathlen]
|
// No more child nodes, move back up.
|
||||||
it.stack = it.stack[:len(it.stack)-1]
|
it.pop()
|
||||||
}
|
}
|
||||||
return nil
|
}
|
||||||
|
|
||||||
|
func (it *nodeIterator) push(state *nodeIteratorState, parentIndex *int, path []byte) {
|
||||||
|
it.path = path
|
||||||
|
it.stack = append(it.stack, state)
|
||||||
|
if parentIndex != nil {
|
||||||
|
*parentIndex += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *nodeIterator) pop() {
|
||||||
|
parent := it.stack[len(it.stack)-1]
|
||||||
|
it.path = it.path[:parent.pathlen]
|
||||||
|
it.stack = it.stack[:len(it.stack)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareNodes(a, b NodeIterator) int {
|
func compareNodes(a, b NodeIterator) int {
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
package trie
|
package trie
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
@ -42,7 +44,7 @@ func TestIterator(t *testing.T) {
|
|||||||
trie.Commit()
|
trie.Commit()
|
||||||
|
|
||||||
found := make(map[string]string)
|
found := make(map[string]string)
|
||||||
it := NewIterator(trie.NodeIterator())
|
it := NewIterator(trie.NodeIterator(nil))
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
found[string(it.Key)] = string(it.Value)
|
found[string(it.Key)] = string(it.Value)
|
||||||
}
|
}
|
||||||
@ -72,7 +74,7 @@ func TestIteratorLargeData(t *testing.T) {
|
|||||||
vals[string(value2.k)] = value2
|
vals[string(value2.k)] = value2
|
||||||
}
|
}
|
||||||
|
|
||||||
it := NewIterator(trie.NodeIterator())
|
it := NewIterator(trie.NodeIterator(nil))
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
vals[string(it.Key)].t = true
|
vals[string(it.Key)].t = true
|
||||||
}
|
}
|
||||||
@ -99,7 +101,7 @@ func TestNodeIteratorCoverage(t *testing.T) {
|
|||||||
|
|
||||||
// Gather all the node hashes found by the iterator
|
// Gather all the node hashes found by the iterator
|
||||||
hashes := make(map[common.Hash]struct{})
|
hashes := make(map[common.Hash]struct{})
|
||||||
for it := trie.NodeIterator(); it.Next(true); {
|
for it := trie.NodeIterator(nil); it.Next(true); {
|
||||||
if it.Hash() != (common.Hash{}) {
|
if it.Hash() != (common.Hash{}) {
|
||||||
hashes[it.Hash()] = struct{}{}
|
hashes[it.Hash()] = struct{}{}
|
||||||
}
|
}
|
||||||
@ -117,18 +119,20 @@ func TestNodeIteratorCoverage(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var testdata1 = []struct{ k, v string }{
|
type kvs struct{ k, v string }
|
||||||
{"bar", "b"},
|
|
||||||
|
var testdata1 = []kvs{
|
||||||
{"barb", "ba"},
|
{"barb", "ba"},
|
||||||
{"bars", "bb"},
|
|
||||||
{"bard", "bc"},
|
{"bard", "bc"},
|
||||||
|
{"bars", "bb"},
|
||||||
|
{"bar", "b"},
|
||||||
{"fab", "z"},
|
{"fab", "z"},
|
||||||
{"foo", "a"},
|
|
||||||
{"food", "ab"},
|
{"food", "ab"},
|
||||||
{"foos", "aa"},
|
{"foos", "aa"},
|
||||||
|
{"foo", "a"},
|
||||||
}
|
}
|
||||||
|
|
||||||
var testdata2 = []struct{ k, v string }{
|
var testdata2 = []kvs{
|
||||||
{"aardvark", "c"},
|
{"aardvark", "c"},
|
||||||
{"bar", "b"},
|
{"bar", "b"},
|
||||||
{"barb", "bd"},
|
{"barb", "bd"},
|
||||||
@ -140,6 +144,47 @@ var testdata2 = []struct{ k, v string }{
|
|||||||
{"jars", "d"},
|
{"jars", "d"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIteratorSeek(t *testing.T) {
|
||||||
|
trie := newEmpty()
|
||||||
|
for _, val := range testdata1 {
|
||||||
|
trie.Update([]byte(val.k), []byte(val.v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seek to the middle.
|
||||||
|
it := NewIterator(trie.NodeIterator([]byte("fab")))
|
||||||
|
if err := checkIteratorOrder(testdata1[4:], it); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seek to a non-existent key.
|
||||||
|
it = NewIterator(trie.NodeIterator([]byte("barc")))
|
||||||
|
if err := checkIteratorOrder(testdata1[1:], it); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seek beyond the end.
|
||||||
|
it = NewIterator(trie.NodeIterator([]byte("z")))
|
||||||
|
if err := checkIteratorOrder(nil, it); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkIteratorOrder(want []kvs, it *Iterator) error {
|
||||||
|
for it.Next() {
|
||||||
|
if len(want) == 0 {
|
||||||
|
return fmt.Errorf("didn't expect any more values, got key %q", it.Key)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(it.Key, []byte(want[0].k)) {
|
||||||
|
return fmt.Errorf("wrong key: got %q, want %q", it.Key, want[0].k)
|
||||||
|
}
|
||||||
|
want = want[1:]
|
||||||
|
}
|
||||||
|
if len(want) > 0 {
|
||||||
|
return fmt.Errorf("iterator ended early, want key %q", want[0])
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func TestDifferenceIterator(t *testing.T) {
|
func TestDifferenceIterator(t *testing.T) {
|
||||||
triea := newEmpty()
|
triea := newEmpty()
|
||||||
for _, val := range testdata1 {
|
for _, val := range testdata1 {
|
||||||
@ -154,7 +199,7 @@ func TestDifferenceIterator(t *testing.T) {
|
|||||||
trieb.Commit()
|
trieb.Commit()
|
||||||
|
|
||||||
found := make(map[string]string)
|
found := make(map[string]string)
|
||||||
di, _ := NewDifferenceIterator(triea.NodeIterator(), trieb.NodeIterator())
|
di, _ := NewDifferenceIterator(triea.NodeIterator(nil), trieb.NodeIterator(nil))
|
||||||
it := NewIterator(di)
|
it := NewIterator(di)
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
found[string(it.Key)] = string(it.Value)
|
found[string(it.Key)] = string(it.Value)
|
||||||
@ -189,7 +234,7 @@ func TestUnionIterator(t *testing.T) {
|
|||||||
}
|
}
|
||||||
trieb.Commit()
|
trieb.Commit()
|
||||||
|
|
||||||
di, _ := NewUnionIterator([]NodeIterator{triea.NodeIterator(), trieb.NodeIterator()})
|
di, _ := NewUnionIterator([]NodeIterator{triea.NodeIterator(nil), trieb.NodeIterator(nil)})
|
||||||
it := NewIterator(di)
|
it := NewIterator(di)
|
||||||
|
|
||||||
all := []struct{ k, v string }{
|
all := []struct{ k, v string }{
|
||||||
|
@ -156,8 +156,10 @@ func (t *SecureTrie) Root() []byte {
|
|||||||
return t.trie.Root()
|
return t.trie.Root()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *SecureTrie) NodeIterator() NodeIterator {
|
// NodeIterator returns an iterator that returns nodes of the underlying trie. Iteration
|
||||||
return t.trie.NodeIterator()
|
// starts at the key after the given start key.
|
||||||
|
func (t *SecureTrie) NodeIterator(start []byte) NodeIterator {
|
||||||
|
return t.trie.NodeIterator(start)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommitTo writes all nodes and the secure hash pre-images to the given database.
|
// CommitTo writes all nodes and the secure hash pre-images to the given database.
|
||||||
|
@ -80,7 +80,7 @@ func checkTrieConsistency(db Database, root common.Hash) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil // // Consider a non existent state consistent
|
return nil // // Consider a non existent state consistent
|
||||||
}
|
}
|
||||||
it := trie.NodeIterator()
|
it := trie.NodeIterator(nil)
|
||||||
for it.Next(true) {
|
for it.Next(true) {
|
||||||
}
|
}
|
||||||
return it.Error()
|
return it.Error()
|
||||||
|
@ -125,9 +125,10 @@ func New(root common.Hash, db Database) (*Trie, error) {
|
|||||||
return trie, nil
|
return trie, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterator returns an iterator over all mappings in the trie.
|
// NodeIterator returns an iterator that returns nodes of the trie. Iteration starts at
|
||||||
func (t *Trie) NodeIterator() NodeIterator {
|
// the key after the given start key.
|
||||||
return newNodeIterator(t)
|
func (t *Trie) NodeIterator(start []byte) NodeIterator {
|
||||||
|
return newNodeIterator(t, start)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the value for key stored in the trie.
|
// Get returns the value for key stored in the trie.
|
||||||
|
@ -439,7 +439,7 @@ func runRandTest(rt randTest) bool {
|
|||||||
tr = newtr
|
tr = newtr
|
||||||
case opItercheckhash:
|
case opItercheckhash:
|
||||||
checktr, _ := New(common.Hash{}, nil)
|
checktr, _ := New(common.Hash{}, nil)
|
||||||
it := NewIterator(tr.NodeIterator())
|
it := NewIterator(tr.NodeIterator(nil))
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
checktr.Update(it.Key, it.Value)
|
checktr.Update(it.Key, it.Value)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user