github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/chain/trie/iterator_test.go (about)

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