github.com/reapchain/go-reapchain@v0.2.15-0.20210609012950-9735c110c705/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  	"testing"
    23  
    24  	"github.com/ethereum/go-ethereum/common"
    25  	"github.com/ethereum/go-ethereum/ethdb"
    26  )
    27  
    28  func TestIterator(t *testing.T) {
    29  	trie := newEmpty()
    30  	vals := []struct{ k, v string }{
    31  		{"do", "verb"},
    32  		{"ether", "wookiedoo"},
    33  		{"horse", "stallion"},
    34  		{"shaman", "horse"},
    35  		{"doge", "coin"},
    36  		{"dog", "puppy"},
    37  		{"somethingveryoddindeedthis is", "myothernodedata"},
    38  	}
    39  	all := make(map[string]string)
    40  	for _, val := range vals {
    41  		all[val.k] = val.v
    42  		trie.Update([]byte(val.k), []byte(val.v))
    43  	}
    44  	trie.Commit()
    45  
    46  	found := make(map[string]string)
    47  	it := NewIterator(trie.NodeIterator(nil))
    48  	for it.Next() {
    49  		found[string(it.Key)] = string(it.Value)
    50  	}
    51  
    52  	for k, v := range all {
    53  		if found[k] != v {
    54  			t.Errorf("iterator value mismatch for %s: got %q want %q", k, found[k], v)
    55  		}
    56  	}
    57  }
    58  
    59  type kv struct {
    60  	k, v []byte
    61  	t    bool
    62  }
    63  
    64  func TestIteratorLargeData(t *testing.T) {
    65  	trie := newEmpty()
    66  	vals := make(map[string]*kv)
    67  
    68  	for i := byte(0); i < 255; i++ {
    69  		value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false}
    70  		value2 := &kv{common.LeftPadBytes([]byte{10, i}, 32), []byte{i}, false}
    71  		trie.Update(value.k, value.v)
    72  		trie.Update(value2.k, value2.v)
    73  		vals[string(value.k)] = value
    74  		vals[string(value2.k)] = value2
    75  	}
    76  
    77  	it := NewIterator(trie.NodeIterator(nil))
    78  	for it.Next() {
    79  		vals[string(it.Key)].t = true
    80  	}
    81  
    82  	var untouched []*kv
    83  	for _, value := range vals {
    84  		if !value.t {
    85  			untouched = append(untouched, value)
    86  		}
    87  	}
    88  
    89  	if len(untouched) > 0 {
    90  		t.Errorf("Missed %d nodes", len(untouched))
    91  		for _, value := range untouched {
    92  			t.Error(value)
    93  		}
    94  	}
    95  }
    96  
    97  // Tests that the node iterator indeed walks over the entire database contents.
    98  func TestNodeIteratorCoverage(t *testing.T) {
    99  	// Create some arbitrary test trie to iterate
   100  	db, trie, _ := makeTestTrie()
   101  
   102  	// Gather all the node hashes found by the iterator
   103  	hashes := make(map[common.Hash]struct{})
   104  	for it := trie.NodeIterator(nil); it.Next(true); {
   105  		if it.Hash() != (common.Hash{}) {
   106  			hashes[it.Hash()] = struct{}{}
   107  		}
   108  	}
   109  	// Cross check the hashes and the database itself
   110  	for hash := range hashes {
   111  		if _, err := db.Get(hash.Bytes()); err != nil {
   112  			t.Errorf("failed to retrieve reported node %x: %v", hash, err)
   113  		}
   114  	}
   115  	for _, key := range db.(*ethdb.MemDatabase).Keys() {
   116  		if _, ok := hashes[common.BytesToHash(key)]; !ok {
   117  			t.Errorf("state entry not reported %x", key)
   118  		}
   119  	}
   120  }
   121  
   122  type kvs struct{ k, v string }
   123  
   124  var testdata1 = []kvs{
   125  	{"barb", "ba"},
   126  	{"bard", "bc"},
   127  	{"bars", "bb"},
   128  	{"bar", "b"},
   129  	{"fab", "z"},
   130  	{"food", "ab"},
   131  	{"foos", "aa"},
   132  	{"foo", "a"},
   133  }
   134  
   135  var testdata2 = []kvs{
   136  	{"aardvark", "c"},
   137  	{"bar", "b"},
   138  	{"barb", "bd"},
   139  	{"bars", "be"},
   140  	{"fab", "z"},
   141  	{"foo", "a"},
   142  	{"foos", "aa"},
   143  	{"food", "ab"},
   144  	{"jars", "d"},
   145  }
   146  
   147  func TestIteratorSeek(t *testing.T) {
   148  	trie := newEmpty()
   149  	for _, val := range testdata1 {
   150  		trie.Update([]byte(val.k), []byte(val.v))
   151  	}
   152  
   153  	// Seek to the middle.
   154  	it := NewIterator(trie.NodeIterator([]byte("fab")))
   155  	if err := checkIteratorOrder(testdata1[4:], it); err != nil {
   156  		t.Fatal(err)
   157  	}
   158  
   159  	// Seek to a non-existent key.
   160  	it = NewIterator(trie.NodeIterator([]byte("barc")))
   161  	if err := checkIteratorOrder(testdata1[1:], it); err != nil {
   162  		t.Fatal(err)
   163  	}
   164  
   165  	// Seek beyond the end.
   166  	it = NewIterator(trie.NodeIterator([]byte("z")))
   167  	if err := checkIteratorOrder(nil, it); err != nil {
   168  		t.Fatal(err)
   169  	}
   170  }
   171  
   172  func checkIteratorOrder(want []kvs, it *Iterator) error {
   173  	for it.Next() {
   174  		if len(want) == 0 {
   175  			return fmt.Errorf("didn't expect any more values, got key %q", it.Key)
   176  		}
   177  		if !bytes.Equal(it.Key, []byte(want[0].k)) {
   178  			return fmt.Errorf("wrong key: got %q, want %q", it.Key, want[0].k)
   179  		}
   180  		want = want[1:]
   181  	}
   182  	if len(want) > 0 {
   183  		return fmt.Errorf("iterator ended early, want key %q", want[0])
   184  	}
   185  	return nil
   186  }
   187  
   188  func TestDifferenceIterator(t *testing.T) {
   189  	triea := newEmpty()
   190  	for _, val := range testdata1 {
   191  		triea.Update([]byte(val.k), []byte(val.v))
   192  	}
   193  	triea.Commit()
   194  
   195  	trieb := newEmpty()
   196  	for _, val := range testdata2 {
   197  		trieb.Update([]byte(val.k), []byte(val.v))
   198  	}
   199  	trieb.Commit()
   200  
   201  	found := make(map[string]string)
   202  	di, _ := NewDifferenceIterator(triea.NodeIterator(nil), trieb.NodeIterator(nil))
   203  	it := NewIterator(di)
   204  	for it.Next() {
   205  		found[string(it.Key)] = string(it.Value)
   206  	}
   207  
   208  	all := []struct{ k, v string }{
   209  		{"aardvark", "c"},
   210  		{"barb", "bd"},
   211  		{"bars", "be"},
   212  		{"jars", "d"},
   213  	}
   214  	for _, item := range all {
   215  		if found[item.k] != item.v {
   216  			t.Errorf("iterator value mismatch for %s: got %v want %v", item.k, found[item.k], item.v)
   217  		}
   218  	}
   219  	if len(found) != len(all) {
   220  		t.Errorf("iterator count mismatch: got %d values, want %d", len(found), len(all))
   221  	}
   222  }
   223  
   224  func TestUnionIterator(t *testing.T) {
   225  	triea := newEmpty()
   226  	for _, val := range testdata1 {
   227  		triea.Update([]byte(val.k), []byte(val.v))
   228  	}
   229  	triea.Commit()
   230  
   231  	trieb := newEmpty()
   232  	for _, val := range testdata2 {
   233  		trieb.Update([]byte(val.k), []byte(val.v))
   234  	}
   235  	trieb.Commit()
   236  
   237  	di, _ := NewUnionIterator([]NodeIterator{triea.NodeIterator(nil), trieb.NodeIterator(nil)})
   238  	it := NewIterator(di)
   239  
   240  	all := []struct{ k, v string }{
   241  		{"aardvark", "c"},
   242  		{"barb", "bd"},
   243  		{"barb", "ba"},
   244  		{"bard", "bc"},
   245  		{"bars", "bb"},
   246  		{"bars", "be"},
   247  		{"bar", "b"},
   248  		{"fab", "z"},
   249  		{"food", "ab"},
   250  		{"foos", "aa"},
   251  		{"foo", "a"},
   252  		{"jars", "d"},
   253  	}
   254  
   255  	for i, kv := range all {
   256  		if !it.Next() {
   257  			t.Errorf("Iterator ends prematurely at element %d", i)
   258  		}
   259  		if kv.k != string(it.Key) {
   260  			t.Errorf("iterator value mismatch for element %d: got key %s want %s", i, it.Key, kv.k)
   261  		}
   262  		if kv.v != string(it.Value) {
   263  			t.Errorf("iterator value mismatch for element %d: got value %s want %s", i, it.Value, kv.v)
   264  		}
   265  	}
   266  	if it.Next() {
   267  		t.Errorf("Iterator returned extra values.")
   268  	}
   269  }