github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/trie/iterator_test.go (about)

     1  // Copyright 2014 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package trie
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"math/rand"
    23  	"testing"
    24  
    25  	"github.com/ethereum/go-ethereum/common"
    26  	"github.com/ethereum/go-ethereum/core/rawdb"
    27  	"github.com/ethereum/go-ethereum/core/types"
    28  	"github.com/ethereum/go-ethereum/crypto"
    29  	"github.com/ethereum/go-ethereum/trie/trienode"
    30  )
    31  
    32  func TestEmptyIterator(t *testing.T) {
    33  	trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme))
    34  	iter := trie.MustNodeIterator(nil)
    35  
    36  	seen := make(map[string]struct{})
    37  	for iter.Next(true) {
    38  		seen[string(iter.Path())] = struct{}{}
    39  	}
    40  	if len(seen) != 0 {
    41  		t.Fatal("Unexpected trie node iterated")
    42  	}
    43  }
    44  
    45  func TestIterator(t *testing.T) {
    46  	db := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)
    47  	trie := NewEmpty(db)
    48  	vals := []struct{ k, v string }{
    49  		{"do", "verb"},
    50  		{"ether", "wookiedoo"},
    51  		{"horse", "stallion"},
    52  		{"shaman", "horse"},
    53  		{"doge", "coin"},
    54  		{"dog", "puppy"},
    55  		{"somethingveryoddindeedthis is", "myothernodedata"},
    56  	}
    57  	all := make(map[string]string)
    58  	for _, val := range vals {
    59  		all[val.k] = val.v
    60  		trie.MustUpdate([]byte(val.k), []byte(val.v))
    61  	}
    62  	root, nodes, _ := trie.Commit(false)
    63  	db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
    64  
    65  	trie, _ = New(TrieID(root), db)
    66  	found := make(map[string]string)
    67  	it := NewIterator(trie.MustNodeIterator(nil))
    68  	for it.Next() {
    69  		found[string(it.Key)] = string(it.Value)
    70  	}
    71  
    72  	for k, v := range all {
    73  		if found[k] != v {
    74  			t.Errorf("iterator value mismatch for %s: got %q want %q", k, found[k], v)
    75  		}
    76  	}
    77  }
    78  
    79  type kv struct {
    80  	k, v []byte
    81  	t    bool
    82  }
    83  
    84  func (k *kv) cmp(other *kv) int {
    85  	return bytes.Compare(k.k, other.k)
    86  }
    87  
    88  func TestIteratorLargeData(t *testing.T) {
    89  	trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme))
    90  	vals := make(map[string]*kv)
    91  
    92  	for i := byte(0); i < 255; i++ {
    93  		value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false}
    94  		value2 := &kv{common.LeftPadBytes([]byte{10, i}, 32), []byte{i}, false}
    95  		trie.MustUpdate(value.k, value.v)
    96  		trie.MustUpdate(value2.k, value2.v)
    97  		vals[string(value.k)] = value
    98  		vals[string(value2.k)] = value2
    99  	}
   100  
   101  	it := NewIterator(trie.MustNodeIterator(nil))
   102  	for it.Next() {
   103  		vals[string(it.Key)].t = true
   104  	}
   105  
   106  	var untouched []*kv
   107  	for _, value := range vals {
   108  		if !value.t {
   109  			untouched = append(untouched, value)
   110  		}
   111  	}
   112  
   113  	if len(untouched) > 0 {
   114  		t.Errorf("Missed %d nodes", len(untouched))
   115  		for _, value := range untouched {
   116  			t.Error(value)
   117  		}
   118  	}
   119  }
   120  
   121  type iterationElement struct {
   122  	hash common.Hash
   123  	path []byte
   124  	blob []byte
   125  }
   126  
   127  // Tests that the node iterator indeed walks over the entire database contents.
   128  func TestNodeIteratorCoverage(t *testing.T) {
   129  	testNodeIteratorCoverage(t, rawdb.HashScheme)
   130  	testNodeIteratorCoverage(t, rawdb.PathScheme)
   131  }
   132  
   133  func testNodeIteratorCoverage(t *testing.T, scheme string) {
   134  	// Create some arbitrary test trie to iterate
   135  	db, nodeDb, trie, _ := makeTestTrie(scheme)
   136  
   137  	// Gather all the node hashes found by the iterator
   138  	var elements = make(map[common.Hash]iterationElement)
   139  	for it := trie.MustNodeIterator(nil); it.Next(true); {
   140  		if it.Hash() != (common.Hash{}) {
   141  			elements[it.Hash()] = iterationElement{
   142  				hash: it.Hash(),
   143  				path: common.CopyBytes(it.Path()),
   144  				blob: common.CopyBytes(it.NodeBlob()),
   145  			}
   146  		}
   147  	}
   148  	// Cross check the hashes and the database itself
   149  	reader, err := nodeDb.Reader(trie.Hash())
   150  	if err != nil {
   151  		t.Fatalf("state is not available %x", trie.Hash())
   152  	}
   153  	for _, element := range elements {
   154  		if blob, err := reader.Node(common.Hash{}, element.path, element.hash); err != nil {
   155  			t.Errorf("failed to retrieve reported node %x: %v", element.hash, err)
   156  		} else if !bytes.Equal(blob, element.blob) {
   157  			t.Errorf("node blob is different, want %v got %v", element.blob, blob)
   158  		}
   159  	}
   160  	var (
   161  		count int
   162  		it    = db.NewIterator(nil, nil)
   163  	)
   164  	for it.Next() {
   165  		res, _, _ := isTrieNode(nodeDb.Scheme(), it.Key(), it.Value())
   166  		if !res {
   167  			continue
   168  		}
   169  		count += 1
   170  		if elem, ok := elements[crypto.Keccak256Hash(it.Value())]; !ok {
   171  			t.Error("state entry not reported")
   172  		} else if !bytes.Equal(it.Value(), elem.blob) {
   173  			t.Errorf("node blob is different, want %v got %v", elem.blob, it.Value())
   174  		}
   175  	}
   176  	it.Release()
   177  	if count != len(elements) {
   178  		t.Errorf("state entry is mismatched %d %d", count, len(elements))
   179  	}
   180  }
   181  
   182  type kvs struct{ k, v string }
   183  
   184  var testdata1 = []kvs{
   185  	{"barb", "ba"},
   186  	{"bard", "bc"},
   187  	{"bars", "bb"},
   188  	{"bar", "b"},
   189  	{"fab", "z"},
   190  	{"food", "ab"},
   191  	{"foos", "aa"},
   192  	{"foo", "a"},
   193  }
   194  
   195  var testdata2 = []kvs{
   196  	{"aardvark", "c"},
   197  	{"bar", "b"},
   198  	{"barb", "bd"},
   199  	{"bars", "be"},
   200  	{"fab", "z"},
   201  	{"foo", "a"},
   202  	{"foos", "aa"},
   203  	{"food", "ab"},
   204  	{"jars", "d"},
   205  }
   206  
   207  func TestIteratorSeek(t *testing.T) {
   208  	trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme))
   209  	for _, val := range testdata1 {
   210  		trie.MustUpdate([]byte(val.k), []byte(val.v))
   211  	}
   212  
   213  	// Seek to the middle.
   214  	it := NewIterator(trie.MustNodeIterator([]byte("fab")))
   215  	if err := checkIteratorOrder(testdata1[4:], it); err != nil {
   216  		t.Fatal(err)
   217  	}
   218  
   219  	// Seek to a non-existent key.
   220  	it = NewIterator(trie.MustNodeIterator([]byte("barc")))
   221  	if err := checkIteratorOrder(testdata1[1:], it); err != nil {
   222  		t.Fatal(err)
   223  	}
   224  
   225  	// Seek beyond the end.
   226  	it = NewIterator(trie.MustNodeIterator([]byte("z")))
   227  	if err := checkIteratorOrder(nil, it); err != nil {
   228  		t.Fatal(err)
   229  	}
   230  }
   231  
   232  func checkIteratorOrder(want []kvs, it *Iterator) error {
   233  	for it.Next() {
   234  		if len(want) == 0 {
   235  			return fmt.Errorf("didn't expect any more values, got key %q", it.Key)
   236  		}
   237  		if !bytes.Equal(it.Key, []byte(want[0].k)) {
   238  			return fmt.Errorf("wrong key: got %q, want %q", it.Key, want[0].k)
   239  		}
   240  		want = want[1:]
   241  	}
   242  	if len(want) > 0 {
   243  		return fmt.Errorf("iterator ended early, want key %q", want[0])
   244  	}
   245  	return nil
   246  }
   247  
   248  func TestDifferenceIterator(t *testing.T) {
   249  	dba := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)
   250  	triea := NewEmpty(dba)
   251  	for _, val := range testdata1 {
   252  		triea.MustUpdate([]byte(val.k), []byte(val.v))
   253  	}
   254  	rootA, nodesA, _ := triea.Commit(false)
   255  	dba.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA))
   256  	triea, _ = New(TrieID(rootA), dba)
   257  
   258  	dbb := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)
   259  	trieb := NewEmpty(dbb)
   260  	for _, val := range testdata2 {
   261  		trieb.MustUpdate([]byte(val.k), []byte(val.v))
   262  	}
   263  	rootB, nodesB, _ := trieb.Commit(false)
   264  	dbb.Update(rootB, types.EmptyRootHash, trienode.NewWithNodeSet(nodesB))
   265  	trieb, _ = New(TrieID(rootB), dbb)
   266  
   267  	found := make(map[string]string)
   268  	di, _ := NewDifferenceIterator(triea.MustNodeIterator(nil), trieb.MustNodeIterator(nil))
   269  	it := NewIterator(di)
   270  	for it.Next() {
   271  		found[string(it.Key)] = string(it.Value)
   272  	}
   273  
   274  	all := []struct{ k, v string }{
   275  		{"aardvark", "c"},
   276  		{"barb", "bd"},
   277  		{"bars", "be"},
   278  		{"jars", "d"},
   279  	}
   280  	for _, item := range all {
   281  		if found[item.k] != item.v {
   282  			t.Errorf("iterator value mismatch for %s: got %v want %v", item.k, found[item.k], item.v)
   283  		}
   284  	}
   285  	if len(found) != len(all) {
   286  		t.Errorf("iterator count mismatch: got %d values, want %d", len(found), len(all))
   287  	}
   288  }
   289  
   290  func TestUnionIterator(t *testing.T) {
   291  	dba := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)
   292  	triea := NewEmpty(dba)
   293  	for _, val := range testdata1 {
   294  		triea.MustUpdate([]byte(val.k), []byte(val.v))
   295  	}
   296  	rootA, nodesA, _ := triea.Commit(false)
   297  	dba.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA))
   298  	triea, _ = New(TrieID(rootA), dba)
   299  
   300  	dbb := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)
   301  	trieb := NewEmpty(dbb)
   302  	for _, val := range testdata2 {
   303  		trieb.MustUpdate([]byte(val.k), []byte(val.v))
   304  	}
   305  	rootB, nodesB, _ := trieb.Commit(false)
   306  	dbb.Update(rootB, types.EmptyRootHash, trienode.NewWithNodeSet(nodesB))
   307  	trieb, _ = New(TrieID(rootB), dbb)
   308  
   309  	di, _ := NewUnionIterator([]NodeIterator{triea.MustNodeIterator(nil), trieb.MustNodeIterator(nil)})
   310  	it := NewIterator(di)
   311  
   312  	all := []struct{ k, v string }{
   313  		{"aardvark", "c"},
   314  		{"barb", "ba"},
   315  		{"barb", "bd"},
   316  		{"bard", "bc"},
   317  		{"bars", "bb"},
   318  		{"bars", "be"},
   319  		{"bar", "b"},
   320  		{"fab", "z"},
   321  		{"food", "ab"},
   322  		{"foos", "aa"},
   323  		{"foo", "a"},
   324  		{"jars", "d"},
   325  	}
   326  
   327  	for i, kv := range all {
   328  		if !it.Next() {
   329  			t.Errorf("Iterator ends prematurely at element %d", i)
   330  		}
   331  		if kv.k != string(it.Key) {
   332  			t.Errorf("iterator value mismatch for element %d: got key %s want %s", i, it.Key, kv.k)
   333  		}
   334  		if kv.v != string(it.Value) {
   335  			t.Errorf("iterator value mismatch for element %d: got value %s want %s", i, it.Value, kv.v)
   336  		}
   337  	}
   338  	if it.Next() {
   339  		t.Errorf("Iterator returned extra values.")
   340  	}
   341  }
   342  
   343  func TestIteratorNoDups(t *testing.T) {
   344  	db := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)
   345  	tr := NewEmpty(db)
   346  	for _, val := range testdata1 {
   347  		tr.MustUpdate([]byte(val.k), []byte(val.v))
   348  	}
   349  	checkIteratorNoDups(t, tr.MustNodeIterator(nil), nil)
   350  }
   351  
   352  // This test checks that nodeIterator.Next can be retried after inserting missing trie nodes.
   353  func TestIteratorContinueAfterError(t *testing.T) {
   354  	testIteratorContinueAfterError(t, false, rawdb.HashScheme)
   355  	testIteratorContinueAfterError(t, true, rawdb.HashScheme)
   356  	testIteratorContinueAfterError(t, false, rawdb.PathScheme)
   357  	testIteratorContinueAfterError(t, true, rawdb.PathScheme)
   358  }
   359  
   360  func testIteratorContinueAfterError(t *testing.T, memonly bool, scheme string) {
   361  	diskdb := rawdb.NewMemoryDatabase()
   362  	tdb := newTestDatabase(diskdb, scheme)
   363  
   364  	tr := NewEmpty(tdb)
   365  	for _, val := range testdata1 {
   366  		tr.MustUpdate([]byte(val.k), []byte(val.v))
   367  	}
   368  	root, nodes, _ := tr.Commit(false)
   369  	tdb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
   370  	if !memonly {
   371  		tdb.Commit(root)
   372  	}
   373  	tr, _ = New(TrieID(root), tdb)
   374  	wantNodeCount := checkIteratorNoDups(t, tr.MustNodeIterator(nil), nil)
   375  
   376  	var (
   377  		paths  [][]byte
   378  		hashes []common.Hash
   379  	)
   380  	if memonly {
   381  		for path, n := range nodes.Nodes {
   382  			paths = append(paths, []byte(path))
   383  			hashes = append(hashes, n.Hash)
   384  		}
   385  	} else {
   386  		it := diskdb.NewIterator(nil, nil)
   387  		for it.Next() {
   388  			ok, path, hash := isTrieNode(tdb.Scheme(), it.Key(), it.Value())
   389  			if !ok {
   390  				continue
   391  			}
   392  			paths = append(paths, path)
   393  			hashes = append(hashes, hash)
   394  		}
   395  		it.Release()
   396  	}
   397  	for i := 0; i < 20; i++ {
   398  		// Create trie that will load all nodes from DB.
   399  		tr, _ := New(TrieID(tr.Hash()), tdb)
   400  
   401  		// Remove a random node from the database. It can't be the root node
   402  		// because that one is already loaded.
   403  		var (
   404  			rval  []byte
   405  			rpath []byte
   406  			rhash common.Hash
   407  		)
   408  		for {
   409  			if memonly {
   410  				rpath = paths[rand.Intn(len(paths))]
   411  				n := nodes.Nodes[string(rpath)]
   412  				if n == nil {
   413  					continue
   414  				}
   415  				rhash = n.Hash
   416  			} else {
   417  				index := rand.Intn(len(paths))
   418  				rpath = paths[index]
   419  				rhash = hashes[index]
   420  			}
   421  			if rhash != tr.Hash() {
   422  				break
   423  			}
   424  		}
   425  		if memonly {
   426  			tr.reader.banned = map[string]struct{}{string(rpath): {}}
   427  		} else {
   428  			rval = rawdb.ReadTrieNode(diskdb, common.Hash{}, rpath, rhash, tdb.Scheme())
   429  			rawdb.DeleteTrieNode(diskdb, common.Hash{}, rpath, rhash, tdb.Scheme())
   430  		}
   431  		// Iterate until the error is hit.
   432  		seen := make(map[string]bool)
   433  		it := tr.MustNodeIterator(nil)
   434  		checkIteratorNoDups(t, it, seen)
   435  		missing, ok := it.Error().(*MissingNodeError)
   436  		if !ok || missing.NodeHash != rhash {
   437  			t.Fatal("didn't hit missing node, got", it.Error())
   438  		}
   439  
   440  		// Add the node back and continue iteration.
   441  		if memonly {
   442  			delete(tr.reader.banned, string(rpath))
   443  		} else {
   444  			rawdb.WriteTrieNode(diskdb, common.Hash{}, rpath, rhash, rval, tdb.Scheme())
   445  		}
   446  		checkIteratorNoDups(t, it, seen)
   447  		if it.Error() != nil {
   448  			t.Fatal("unexpected error", it.Error())
   449  		}
   450  		if len(seen) != wantNodeCount {
   451  			t.Fatal("wrong node iteration count, got", len(seen), "want", wantNodeCount)
   452  		}
   453  	}
   454  }
   455  
   456  // Similar to the test above, this one checks that failure to create nodeIterator at a
   457  // certain key prefix behaves correctly when Next is called. The expectation is that Next
   458  // should retry seeking before returning true for the first time.
   459  func TestIteratorContinueAfterSeekError(t *testing.T) {
   460  	testIteratorContinueAfterSeekError(t, false, rawdb.HashScheme)
   461  	testIteratorContinueAfterSeekError(t, true, rawdb.HashScheme)
   462  	testIteratorContinueAfterSeekError(t, false, rawdb.PathScheme)
   463  	testIteratorContinueAfterSeekError(t, true, rawdb.PathScheme)
   464  }
   465  
   466  func testIteratorContinueAfterSeekError(t *testing.T, memonly bool, scheme string) {
   467  	// Commit test trie to db, then remove the node containing "bars".
   468  	var (
   469  		barNodePath []byte
   470  		barNodeHash = common.HexToHash("05041990364eb72fcb1127652ce40d8bab765f2bfe53225b1170d276cc101c2e")
   471  	)
   472  	diskdb := rawdb.NewMemoryDatabase()
   473  	triedb := newTestDatabase(diskdb, scheme)
   474  	ctr := NewEmpty(triedb)
   475  	for _, val := range testdata1 {
   476  		ctr.MustUpdate([]byte(val.k), []byte(val.v))
   477  	}
   478  	root, nodes, _ := ctr.Commit(false)
   479  	for path, n := range nodes.Nodes {
   480  		if n.Hash == barNodeHash {
   481  			barNodePath = []byte(path)
   482  			break
   483  		}
   484  	}
   485  	triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
   486  	if !memonly {
   487  		triedb.Commit(root)
   488  	}
   489  	var (
   490  		barNodeBlob []byte
   491  	)
   492  	tr, _ := New(TrieID(root), triedb)
   493  	if memonly {
   494  		tr.reader.banned = map[string]struct{}{string(barNodePath): {}}
   495  	} else {
   496  		barNodeBlob = rawdb.ReadTrieNode(diskdb, common.Hash{}, barNodePath, barNodeHash, triedb.Scheme())
   497  		rawdb.DeleteTrieNode(diskdb, common.Hash{}, barNodePath, barNodeHash, triedb.Scheme())
   498  	}
   499  	// Create a new iterator that seeks to "bars". Seeking can't proceed because
   500  	// the node is missing.
   501  	it := tr.MustNodeIterator([]byte("bars"))
   502  	missing, ok := it.Error().(*MissingNodeError)
   503  	if !ok {
   504  		t.Fatal("want MissingNodeError, got", it.Error())
   505  	} else if missing.NodeHash != barNodeHash {
   506  		t.Fatal("wrong node missing")
   507  	}
   508  	// Reinsert the missing node.
   509  	if memonly {
   510  		delete(tr.reader.banned, string(barNodePath))
   511  	} else {
   512  		rawdb.WriteTrieNode(diskdb, common.Hash{}, barNodePath, barNodeHash, barNodeBlob, triedb.Scheme())
   513  	}
   514  	// Check that iteration produces the right set of values.
   515  	if err := checkIteratorOrder(testdata1[2:], NewIterator(it)); err != nil {
   516  		t.Fatal(err)
   517  	}
   518  }
   519  
   520  func checkIteratorNoDups(t *testing.T, it NodeIterator, seen map[string]bool) int {
   521  	if seen == nil {
   522  		seen = make(map[string]bool)
   523  	}
   524  	for it.Next(true) {
   525  		if seen[string(it.Path())] {
   526  			t.Fatalf("iterator visited node path %x twice", it.Path())
   527  		}
   528  		seen[string(it.Path())] = true
   529  	}
   530  	return len(seen)
   531  }
   532  
   533  func TestIteratorNodeBlob(t *testing.T) {
   534  	testIteratorNodeBlob(t, rawdb.HashScheme)
   535  	testIteratorNodeBlob(t, rawdb.PathScheme)
   536  }
   537  
   538  func testIteratorNodeBlob(t *testing.T, scheme string) {
   539  	var (
   540  		db     = rawdb.NewMemoryDatabase()
   541  		triedb = newTestDatabase(db, scheme)
   542  		trie   = NewEmpty(triedb)
   543  	)
   544  	vals := []struct{ k, v string }{
   545  		{"do", "verb"},
   546  		{"ether", "wookiedoo"},
   547  		{"horse", "stallion"},
   548  		{"shaman", "horse"},
   549  		{"doge", "coin"},
   550  		{"dog", "puppy"},
   551  		{"somethingveryoddindeedthis is", "myothernodedata"},
   552  	}
   553  	all := make(map[string]string)
   554  	for _, val := range vals {
   555  		all[val.k] = val.v
   556  		trie.MustUpdate([]byte(val.k), []byte(val.v))
   557  	}
   558  	root, nodes, _ := trie.Commit(false)
   559  	triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
   560  	triedb.Commit(root)
   561  
   562  	var found = make(map[common.Hash][]byte)
   563  	trie, _ = New(TrieID(root), triedb)
   564  	it := trie.MustNodeIterator(nil)
   565  	for it.Next(true) {
   566  		if it.Hash() == (common.Hash{}) {
   567  			continue
   568  		}
   569  		found[it.Hash()] = it.NodeBlob()
   570  	}
   571  
   572  	dbIter := db.NewIterator(nil, nil)
   573  	defer dbIter.Release()
   574  
   575  	var count int
   576  	for dbIter.Next() {
   577  		ok, _, _ := isTrieNode(triedb.Scheme(), dbIter.Key(), dbIter.Value())
   578  		if !ok {
   579  			continue
   580  		}
   581  		got, present := found[crypto.Keccak256Hash(dbIter.Value())]
   582  		if !present {
   583  			t.Fatal("Miss trie node")
   584  		}
   585  		if !bytes.Equal(got, dbIter.Value()) {
   586  			t.Fatalf("Unexpected trie node want %v got %v", dbIter.Value(), got)
   587  		}
   588  		count += 1
   589  	}
   590  	if count != len(found) {
   591  		t.Fatal("Find extra trie node via iterator")
   592  	}
   593  }
   594  
   595  // isTrieNode is a helper function which reports if the provided
   596  // database entry belongs to a trie node or not. Note in tests
   597  // only single layer trie is used, namely storage trie is not
   598  // considered at all.
   599  func isTrieNode(scheme string, key, val []byte) (bool, []byte, common.Hash) {
   600  	var (
   601  		path []byte
   602  		hash common.Hash
   603  	)
   604  	if scheme == rawdb.HashScheme {
   605  		ok := rawdb.IsLegacyTrieNode(key, val)
   606  		if !ok {
   607  			return false, nil, common.Hash{}
   608  		}
   609  		hash = common.BytesToHash(key)
   610  	} else {
   611  		ok, remain := rawdb.ResolveAccountTrieNodeKey(key)
   612  		if !ok {
   613  			return false, nil, common.Hash{}
   614  		}
   615  		path = common.CopyBytes(remain)
   616  		hash = crypto.Keccak256Hash(val)
   617  	}
   618  	return true, path, hash
   619  }
   620  
   621  func BenchmarkIterator(b *testing.B) {
   622  	diskDb, srcDb, tr, _ := makeTestTrie(rawdb.HashScheme)
   623  	root := tr.Hash()
   624  	b.ReportAllocs()
   625  	b.ResetTimer()
   626  	for i := 0; i < b.N; i++ {
   627  		if err := checkTrieConsistency(diskDb, srcDb.Scheme(), root, false); err != nil {
   628  			b.Fatal(err)
   629  		}
   630  	}
   631  }