github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/trie/iterator_test.go (about)

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