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