github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/trie/iterator_test.go (about)

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