github.com/core-coin/go-core/v2@v2.1.9/trie/iterator_test.go (about)

     1  // Copyright 2014 by the Authors
     2  // This file is part of the go-core library.
     3  //
     4  // The go-core 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-core 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-core 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/core-coin/go-core/v2/xcbdb/memorydb"
    26  
    27  	"github.com/core-coin/go-core/v2/common"
    28  )
    29  
    30  func TestIterator(t *testing.T) {
    31  	trie := newEmpty()
    32  	vals := []struct{ k, v string }{
    33  		{"do", "verb"},
    34  		{"core", "wookiedoo"},
    35  		{"horse", "stallion"},
    36  		{"shaman", "horse"},
    37  		{"doge", "coin"},
    38  		{"dog", "puppy"},
    39  		{"somethingveryoddindeedthis is", "myothernodedata"},
    40  	}
    41  	all := make(map[string]string)
    42  	for _, val := range vals {
    43  		all[val.k] = val.v
    44  		trie.Update([]byte(val.k), []byte(val.v))
    45  	}
    46  	trie.Commit(nil)
    47  
    48  	found := make(map[string]string)
    49  	it := NewIterator(trie.NodeIterator(nil))
    50  	for it.Next() {
    51  		found[string(it.Key)] = string(it.Value)
    52  	}
    53  
    54  	for k, v := range all {
    55  		if found[k] != v {
    56  			t.Errorf("iterator value mismatch for %s: got %q want %q", k, found[k], v)
    57  		}
    58  	}
    59  }
    60  
    61  type kv struct {
    62  	k, v []byte
    63  	t    bool
    64  }
    65  
    66  func TestIteratorLargeData(t *testing.T) {
    67  	trie := newEmpty()
    68  	vals := make(map[string]*kv)
    69  
    70  	for i := byte(0); i < 255; i++ {
    71  		value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false}
    72  		value2 := &kv{common.LeftPadBytes([]byte{10, i}, 32), []byte{i}, false}
    73  		trie.Update(value.k, value.v)
    74  		trie.Update(value2.k, value2.v)
    75  		vals[string(value.k)] = value
    76  		vals[string(value2.k)] = value2
    77  	}
    78  
    79  	it := NewIterator(trie.NodeIterator(nil))
    80  	for it.Next() {
    81  		vals[string(it.Key)].t = true
    82  	}
    83  
    84  	var untouched []*kv
    85  	for _, value := range vals {
    86  		if !value.t {
    87  			untouched = append(untouched, value)
    88  		}
    89  	}
    90  
    91  	if len(untouched) > 0 {
    92  		t.Errorf("Missed %d nodes", len(untouched))
    93  		for _, value := range untouched {
    94  			t.Error(value)
    95  		}
    96  	}
    97  }
    98  
    99  // Tests that the node iterator indeed walks over the entire database contents.
   100  func TestNodeIteratorCoverage(t *testing.T) {
   101  	// Create some arbitrary test trie to iterate
   102  	db, trie, _ := makeTestTrie()
   103  
   104  	// Gather all the node hashes found by the iterator
   105  	hashes := make(map[common.Hash]struct{})
   106  	for it := trie.NodeIterator(nil); it.Next(true); {
   107  		if it.Hash() != (common.Hash{}) {
   108  			hashes[it.Hash()] = struct{}{}
   109  		}
   110  	}
   111  	// Cross check the hashes and the database itself
   112  	for hash := range hashes {
   113  		if _, err := db.Node(hash); err != nil {
   114  			t.Errorf("failed to retrieve reported node %x: %v", hash, err)
   115  		}
   116  	}
   117  	for hash, obj := range db.dirties {
   118  		if obj != nil && hash != (common.Hash{}) {
   119  			if _, ok := hashes[hash]; !ok {
   120  				t.Errorf("state entry not reported %x", hash)
   121  			}
   122  		}
   123  	}
   124  	it := db.diskdb.NewIterator(nil, nil)
   125  	for it.Next() {
   126  		key := it.Key()
   127  		if _, ok := hashes[common.BytesToHash(key)]; !ok {
   128  			t.Errorf("state entry not reported %x", key)
   129  		}
   130  	}
   131  	it.Release()
   132  }
   133  
   134  type kvs struct{ k, v string }
   135  
   136  var testdata1 = []kvs{
   137  	{"barb", "ba"},
   138  	{"bard", "bc"},
   139  	{"bars", "bb"},
   140  	{"bar", "b"},
   141  	{"fab", "z"},
   142  	{"food", "ab"},
   143  	{"foos", "aa"},
   144  	{"foo", "a"},
   145  }
   146  
   147  var testdata2 = []kvs{
   148  	{"aardvark", "c"},
   149  	{"bar", "b"},
   150  	{"barb", "bd"},
   151  	{"bars", "be"},
   152  	{"fab", "z"},
   153  	{"foo", "a"},
   154  	{"foos", "aa"},
   155  	{"food", "ab"},
   156  	{"jars", "d"},
   157  }
   158  
   159  func TestIteratorSeek(t *testing.T) {
   160  	trie := newEmpty()
   161  	for _, val := range testdata1 {
   162  		trie.Update([]byte(val.k), []byte(val.v))
   163  	}
   164  
   165  	// Seek to the middle.
   166  	it := NewIterator(trie.NodeIterator([]byte("fab")))
   167  	if err := checkIteratorOrder(testdata1[4:], it); err != nil {
   168  		t.Fatal(err)
   169  	}
   170  
   171  	// Seek to a non-existent key.
   172  	it = NewIterator(trie.NodeIterator([]byte("barc")))
   173  	if err := checkIteratorOrder(testdata1[1:], it); err != nil {
   174  		t.Fatal(err)
   175  	}
   176  
   177  	// Seek beyond the end.
   178  	it = NewIterator(trie.NodeIterator([]byte("z")))
   179  	if err := checkIteratorOrder(nil, it); err != nil {
   180  		t.Fatal(err)
   181  	}
   182  }
   183  
   184  func checkIteratorOrder(want []kvs, it *Iterator) error {
   185  	for it.Next() {
   186  		if len(want) == 0 {
   187  			return fmt.Errorf("didn't expect any more values, got key %q", it.Key)
   188  		}
   189  		if !bytes.Equal(it.Key, []byte(want[0].k)) {
   190  			return fmt.Errorf("wrong key: got %q, want %q", it.Key, want[0].k)
   191  		}
   192  		want = want[1:]
   193  	}
   194  	if len(want) > 0 {
   195  		return fmt.Errorf("iterator ended early, want key %q", want[0])
   196  	}
   197  	return nil
   198  }
   199  
   200  func TestDifferenceIterator(t *testing.T) {
   201  	triea := newEmpty()
   202  	for _, val := range testdata1 {
   203  		triea.Update([]byte(val.k), []byte(val.v))
   204  	}
   205  	triea.Commit(nil)
   206  
   207  	trieb := newEmpty()
   208  	for _, val := range testdata2 {
   209  		trieb.Update([]byte(val.k), []byte(val.v))
   210  	}
   211  	trieb.Commit(nil)
   212  
   213  	found := make(map[string]string)
   214  	di, _ := NewDifferenceIterator(triea.NodeIterator(nil), trieb.NodeIterator(nil))
   215  	it := NewIterator(di)
   216  	for it.Next() {
   217  		found[string(it.Key)] = string(it.Value)
   218  	}
   219  
   220  	all := []struct{ k, v string }{
   221  		{"aardvark", "c"},
   222  		{"barb", "bd"},
   223  		{"bars", "be"},
   224  		{"jars", "d"},
   225  	}
   226  	for _, item := range all {
   227  		if found[item.k] != item.v {
   228  			t.Errorf("iterator value mismatch for %s: got %v want %v", item.k, found[item.k], item.v)
   229  		}
   230  	}
   231  	if len(found) != len(all) {
   232  		t.Errorf("iterator count mismatch: got %d values, want %d", len(found), len(all))
   233  	}
   234  }
   235  
   236  func TestUnionIterator(t *testing.T) {
   237  	triea := newEmpty()
   238  	for _, val := range testdata1 {
   239  		triea.Update([]byte(val.k), []byte(val.v))
   240  	}
   241  	triea.Commit(nil)
   242  
   243  	trieb := newEmpty()
   244  	for _, val := range testdata2 {
   245  		trieb.Update([]byte(val.k), []byte(val.v))
   246  	}
   247  	trieb.Commit(nil)
   248  
   249  	di, _ := NewUnionIterator([]NodeIterator{triea.NodeIterator(nil), trieb.NodeIterator(nil)})
   250  	it := NewIterator(di)
   251  
   252  	all := []struct{ k, v string }{
   253  		{"aardvark", "c"},
   254  		{"barb", "ba"},
   255  		{"barb", "bd"},
   256  		{"bard", "bc"},
   257  		{"bars", "bb"},
   258  		{"bars", "be"},
   259  		{"bar", "b"},
   260  		{"fab", "z"},
   261  		{"food", "ab"},
   262  		{"foos", "aa"},
   263  		{"foo", "a"},
   264  		{"jars", "d"},
   265  	}
   266  
   267  	for i, kv := range all {
   268  		if !it.Next() {
   269  			t.Errorf("Iterator ends prematurely at element %d", i)
   270  		}
   271  		if kv.k != string(it.Key) {
   272  			t.Errorf("iterator value mismatch for element %d: got key %s want %s", i, it.Key, kv.k)
   273  		}
   274  		if kv.v != string(it.Value) {
   275  			t.Errorf("iterator value mismatch for element %d: got value %s want %s", i, it.Value, kv.v)
   276  		}
   277  	}
   278  	if it.Next() {
   279  		t.Errorf("Iterator returned extra values.")
   280  	}
   281  }
   282  
   283  func TestIteratorNoDups(t *testing.T) {
   284  	var tr Trie
   285  	for _, val := range testdata1 {
   286  		tr.Update([]byte(val.k), []byte(val.v))
   287  	}
   288  	checkIteratorNoDups(t, tr.NodeIterator(nil), nil)
   289  }
   290  
   291  // This test checks that nodeIterator.Next can be retried after inserting missing trie nodes.
   292  func TestIteratorContinueAfterErrorDisk(t *testing.T)    { testIteratorContinueAfterError(t, false) }
   293  func TestIteratorContinueAfterErrorMemonly(t *testing.T) { testIteratorContinueAfterError(t, true) }
   294  
   295  func testIteratorContinueAfterError(t *testing.T, memonly bool) {
   296  	diskdb := memorydb.New()
   297  	triedb := NewDatabase(diskdb)
   298  
   299  	tr, _ := New(common.Hash{}, triedb)
   300  	for _, val := range testdata1 {
   301  		tr.Update([]byte(val.k), []byte(val.v))
   302  	}
   303  	tr.Commit(nil)
   304  	if !memonly {
   305  		triedb.Commit(tr.Hash(), true, nil)
   306  	}
   307  	wantNodeCount := checkIteratorNoDups(t, tr.NodeIterator(nil), nil)
   308  
   309  	var (
   310  		diskKeys [][]byte
   311  		memKeys  []common.Hash
   312  	)
   313  	if memonly {
   314  		memKeys = triedb.Nodes()
   315  	} else {
   316  		it := diskdb.NewIterator(nil, nil)
   317  		for it.Next() {
   318  			diskKeys = append(diskKeys, it.Key())
   319  		}
   320  		it.Release()
   321  	}
   322  	for i := 0; i < 20; i++ {
   323  		// Create trie that will load all nodes from DB.
   324  		tr, _ := New(tr.Hash(), triedb)
   325  
   326  		// Remove a random node from the database. It can't be the root node
   327  		// because that one is already loaded.
   328  		var (
   329  			rkey common.Hash
   330  			rval []byte
   331  			robj *cachedNode
   332  		)
   333  		for {
   334  			if memonly {
   335  				rkey = memKeys[rand.Intn(len(memKeys))]
   336  			} else {
   337  				copy(rkey[:], diskKeys[rand.Intn(len(diskKeys))])
   338  			}
   339  			if rkey != tr.Hash() {
   340  				break
   341  			}
   342  		}
   343  		if memonly {
   344  			robj = triedb.dirties[rkey]
   345  			delete(triedb.dirties, rkey)
   346  		} else {
   347  			rval, _ = diskdb.Get(rkey[:])
   348  			diskdb.Delete(rkey[:])
   349  		}
   350  		// Iterate until the error is hit.
   351  		seen := make(map[string]bool)
   352  		it := tr.NodeIterator(nil)
   353  		checkIteratorNoDups(t, it, seen)
   354  		missing, ok := it.Error().(*MissingNodeError)
   355  		if !ok || missing.NodeHash != rkey {
   356  			t.Fatal("didn't hit missing node, got", it.Error())
   357  		}
   358  
   359  		// Add the node back and continue iteration.
   360  		if memonly {
   361  			triedb.dirties[rkey] = robj
   362  		} else {
   363  			diskdb.Put(rkey[:], rval)
   364  		}
   365  		checkIteratorNoDups(t, it, seen)
   366  		if it.Error() != nil {
   367  			t.Fatal("unexpected error", it.Error())
   368  		}
   369  		if len(seen) != wantNodeCount {
   370  			t.Fatal("wrong node iteration count, got", len(seen), "want", wantNodeCount)
   371  		}
   372  	}
   373  }
   374  
   375  // Similar to the test above, this one checks that failure to create nodeIterator at a
   376  // certain key prefix behaves correctly when Next is called. The expectation is that Next
   377  // should retry seeking before returning true for the first time.
   378  func TestIteratorContinueAfterSeekErrorDisk(t *testing.T) {
   379  	testIteratorContinueAfterSeekError(t, false)
   380  }
   381  func TestIteratorContinueAfterSeekErrorMemonly(t *testing.T) {
   382  	testIteratorContinueAfterSeekError(t, true)
   383  }
   384  
   385  func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) {
   386  	// Commit test trie to db, then remove the node containing "bars".
   387  	diskdb := memorydb.New()
   388  	triedb := NewDatabase(diskdb)
   389  
   390  	ctr, _ := New(common.Hash{}, triedb)
   391  	for _, val := range testdata1 {
   392  		ctr.Update([]byte(val.k), []byte(val.v))
   393  	}
   394  	root, _ := ctr.Commit(nil)
   395  	if !memonly {
   396  		triedb.Commit(root, true, nil)
   397  	}
   398  	barNodeHash := common.HexToHash("0x9e3dfb5f6b3d86f07fbd1ca0eb55a023f002ad2a8b6bf56fafd7e9f63e07f16b")
   399  	var (
   400  		barNodeBlob []byte
   401  		barNodeObj  *cachedNode
   402  	)
   403  	if memonly {
   404  		barNodeObj = triedb.dirties[barNodeHash]
   405  		delete(triedb.dirties, barNodeHash)
   406  	} else {
   407  		barNodeBlob, _ = diskdb.Get(barNodeHash[:])
   408  		diskdb.Delete(barNodeHash[:])
   409  	}
   410  	// Create a new iterator that seeks to "bars". Seeking can't proceed because
   411  	// the node is missing.
   412  	tr, _ := New(root, triedb)
   413  	it := tr.NodeIterator([]byte("bars"))
   414  	missing, ok := it.Error().(*MissingNodeError)
   415  	if !ok {
   416  		t.Fatal("want MissingNodeError, got", it.Error())
   417  	} else if missing.NodeHash != barNodeHash {
   418  		t.Fatal("wrong node missing")
   419  	}
   420  	// Reinsert the missing node.
   421  	if memonly {
   422  		triedb.dirties[barNodeHash] = barNodeObj
   423  	} else {
   424  		diskdb.Put(barNodeHash[:], barNodeBlob)
   425  	}
   426  	// Check that iteration produces the right set of values.
   427  	if err := checkIteratorOrder(testdata1[2:], NewIterator(it)); err != nil {
   428  		t.Fatal(err)
   429  	}
   430  }
   431  
   432  func checkIteratorNoDups(t *testing.T, it NodeIterator, seen map[string]bool) int {
   433  	if seen == nil {
   434  		seen = make(map[string]bool)
   435  	}
   436  	for it.Next(true) {
   437  		if seen[string(it.Path())] {
   438  			t.Fatalf("iterator visited node path %x twice", it.Path())
   439  		}
   440  		seen[string(it.Path())] = true
   441  	}
   442  	return len(seen)
   443  }