github.com/reapchain/go-reapchain@v0.2.15-0.20210609012950-9735c110c705/trie/trie_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  	"io/ioutil"
    24  	"math/rand"
    25  	"os"
    26  	"reflect"
    27  	"testing"
    28  	"testing/quick"
    29  
    30  	"github.com/davecgh/go-spew/spew"
    31  	"github.com/ethereum/go-ethereum/common"
    32  	"github.com/ethereum/go-ethereum/ethdb"
    33  )
    34  
    35  func init() {
    36  	spew.Config.Indent = "    "
    37  	spew.Config.DisableMethods = true
    38  }
    39  
    40  // Used for testing
    41  func newEmpty() *Trie {
    42  	db, _ := ethdb.NewMemDatabase()
    43  	trie, _ := New(common.Hash{}, db)
    44  	return trie
    45  }
    46  
    47  func TestEmptyTrie(t *testing.T) {
    48  	var trie Trie
    49  	res := trie.Hash()
    50  	exp := emptyRoot
    51  	if res != common.Hash(exp) {
    52  		t.Errorf("expected %x got %x", exp, res)
    53  	}
    54  }
    55  
    56  func TestNull(t *testing.T) {
    57  	var trie Trie
    58  	key := make([]byte, 32)
    59  	value := []byte("test")
    60  	trie.Update(key, value)
    61  	if !bytes.Equal(trie.Get(key), value) {
    62  		t.Fatal("wrong value")
    63  	}
    64  }
    65  
    66  func TestMissingRoot(t *testing.T) {
    67  	db, _ := ethdb.NewMemDatabase()
    68  	trie, err := New(common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), db)
    69  	if trie != nil {
    70  		t.Error("New returned non-nil trie for invalid root")
    71  	}
    72  	if _, ok := err.(*MissingNodeError); !ok {
    73  		t.Errorf("New returned wrong error: %v", err)
    74  	}
    75  }
    76  
    77  func TestMissingNode(t *testing.T) {
    78  	db, _ := ethdb.NewMemDatabase()
    79  	trie, _ := New(common.Hash{}, db)
    80  	updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer")
    81  	updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf")
    82  	root, _ := trie.Commit()
    83  
    84  	trie, _ = New(root, db)
    85  	_, err := trie.TryGet([]byte("120000"))
    86  	if err != nil {
    87  		t.Errorf("Unexpected error: %v", err)
    88  	}
    89  
    90  	trie, _ = New(root, db)
    91  	_, err = trie.TryGet([]byte("120099"))
    92  	if err != nil {
    93  		t.Errorf("Unexpected error: %v", err)
    94  	}
    95  
    96  	trie, _ = New(root, db)
    97  	_, err = trie.TryGet([]byte("123456"))
    98  	if err != nil {
    99  		t.Errorf("Unexpected error: %v", err)
   100  	}
   101  
   102  	trie, _ = New(root, db)
   103  	err = trie.TryUpdate([]byte("120099"), []byte("zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv"))
   104  	if err != nil {
   105  		t.Errorf("Unexpected error: %v", err)
   106  	}
   107  
   108  	trie, _ = New(root, db)
   109  	err = trie.TryDelete([]byte("123456"))
   110  	if err != nil {
   111  		t.Errorf("Unexpected error: %v", err)
   112  	}
   113  
   114  	db.Delete(common.FromHex("e1d943cc8f061a0c0b98162830b970395ac9315654824bf21b73b891365262f9"))
   115  
   116  	trie, _ = New(root, db)
   117  	_, err = trie.TryGet([]byte("120000"))
   118  	if _, ok := err.(*MissingNodeError); !ok {
   119  		t.Errorf("Wrong error: %v", err)
   120  	}
   121  
   122  	trie, _ = New(root, db)
   123  	_, err = trie.TryGet([]byte("120099"))
   124  	if _, ok := err.(*MissingNodeError); !ok {
   125  		t.Errorf("Wrong error: %v", err)
   126  	}
   127  
   128  	trie, _ = New(root, db)
   129  	_, err = trie.TryGet([]byte("123456"))
   130  	if err != nil {
   131  		t.Errorf("Unexpected error: %v", err)
   132  	}
   133  
   134  	trie, _ = New(root, db)
   135  	err = trie.TryUpdate([]byte("120099"), []byte("zxcv"))
   136  	if _, ok := err.(*MissingNodeError); !ok {
   137  		t.Errorf("Wrong error: %v", err)
   138  	}
   139  
   140  	trie, _ = New(root, db)
   141  	err = trie.TryDelete([]byte("123456"))
   142  	if _, ok := err.(*MissingNodeError); !ok {
   143  		t.Errorf("Wrong error: %v", err)
   144  	}
   145  }
   146  
   147  func TestInsert(t *testing.T) {
   148  	trie := newEmpty()
   149  
   150  	updateString(trie, "doe", "reindeer")
   151  	updateString(trie, "dog", "puppy")
   152  	updateString(trie, "dogglesworth", "cat")
   153  
   154  	exp := common.HexToHash("8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3")
   155  	root := trie.Hash()
   156  	if root != exp {
   157  		t.Errorf("exp %x got %x", exp, root)
   158  	}
   159  
   160  	trie = newEmpty()
   161  	updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
   162  
   163  	exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab")
   164  	root, err := trie.Commit()
   165  	if err != nil {
   166  		t.Fatalf("commit error: %v", err)
   167  	}
   168  	if root != exp {
   169  		t.Errorf("exp %x got %x", exp, root)
   170  	}
   171  }
   172  
   173  func TestGet(t *testing.T) {
   174  	trie := newEmpty()
   175  	updateString(trie, "doe", "reindeer")
   176  	updateString(trie, "dog", "puppy")
   177  	updateString(trie, "dogglesworth", "cat")
   178  
   179  	for i := 0; i < 2; i++ {
   180  		res := getString(trie, "dog")
   181  		if !bytes.Equal(res, []byte("puppy")) {
   182  			t.Errorf("expected puppy got %x", res)
   183  		}
   184  
   185  		unknown := getString(trie, "unknown")
   186  		if unknown != nil {
   187  			t.Errorf("expected nil got %x", unknown)
   188  		}
   189  
   190  		if i == 1 {
   191  			return
   192  		}
   193  		trie.Commit()
   194  	}
   195  }
   196  
   197  func TestDelete(t *testing.T) {
   198  	trie := newEmpty()
   199  	vals := []struct{ k, v string }{
   200  		{"do", "verb"},
   201  		{"ether", "wookiedoo"},
   202  		{"horse", "stallion"},
   203  		{"shaman", "horse"},
   204  		{"doge", "coin"},
   205  		{"ether", ""},
   206  		{"dog", "puppy"},
   207  		{"shaman", ""},
   208  	}
   209  	for _, val := range vals {
   210  		if val.v != "" {
   211  			updateString(trie, val.k, val.v)
   212  		} else {
   213  			deleteString(trie, val.k)
   214  		}
   215  	}
   216  
   217  	hash := trie.Hash()
   218  	exp := common.HexToHash("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84")
   219  	if hash != exp {
   220  		t.Errorf("expected %x got %x", exp, hash)
   221  	}
   222  }
   223  
   224  func TestEmptyValues(t *testing.T) {
   225  	trie := newEmpty()
   226  
   227  	vals := []struct{ k, v string }{
   228  		{"do", "verb"},
   229  		{"ether", "wookiedoo"},
   230  		{"horse", "stallion"},
   231  		{"shaman", "horse"},
   232  		{"doge", "coin"},
   233  		{"ether", ""},
   234  		{"dog", "puppy"},
   235  		{"shaman", ""},
   236  	}
   237  	for _, val := range vals {
   238  		updateString(trie, val.k, val.v)
   239  	}
   240  
   241  	hash := trie.Hash()
   242  	exp := common.HexToHash("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84")
   243  	if hash != exp {
   244  		t.Errorf("expected %x got %x", exp, hash)
   245  	}
   246  }
   247  
   248  func TestReplication(t *testing.T) {
   249  	trie := newEmpty()
   250  	vals := []struct{ k, v string }{
   251  		{"do", "verb"},
   252  		{"ether", "wookiedoo"},
   253  		{"horse", "stallion"},
   254  		{"shaman", "horse"},
   255  		{"doge", "coin"},
   256  		{"dog", "puppy"},
   257  		{"somethingveryoddindeedthis is", "myothernodedata"},
   258  	}
   259  	for _, val := range vals {
   260  		updateString(trie, val.k, val.v)
   261  	}
   262  	exp, err := trie.Commit()
   263  	if err != nil {
   264  		t.Fatalf("commit error: %v", err)
   265  	}
   266  
   267  	// create a new trie on top of the database and check that lookups work.
   268  	trie2, err := New(exp, trie.db)
   269  	if err != nil {
   270  		t.Fatalf("can't recreate trie at %x: %v", exp, err)
   271  	}
   272  	for _, kv := range vals {
   273  		if string(getString(trie2, kv.k)) != kv.v {
   274  			t.Errorf("trie2 doesn't have %q => %q", kv.k, kv.v)
   275  		}
   276  	}
   277  	hash, err := trie2.Commit()
   278  	if err != nil {
   279  		t.Fatalf("commit error: %v", err)
   280  	}
   281  	if hash != exp {
   282  		t.Errorf("root failure. expected %x got %x", exp, hash)
   283  	}
   284  
   285  	// perform some insertions on the new trie.
   286  	vals2 := []struct{ k, v string }{
   287  		{"do", "verb"},
   288  		{"ether", "wookiedoo"},
   289  		{"horse", "stallion"},
   290  		// {"shaman", "horse"},
   291  		// {"doge", "coin"},
   292  		// {"ether", ""},
   293  		// {"dog", "puppy"},
   294  		// {"somethingveryoddindeedthis is", "myothernodedata"},
   295  		// {"shaman", ""},
   296  	}
   297  	for _, val := range vals2 {
   298  		updateString(trie2, val.k, val.v)
   299  	}
   300  	if hash := trie2.Hash(); hash != exp {
   301  		t.Errorf("root failure. expected %x got %x", exp, hash)
   302  	}
   303  }
   304  
   305  func TestLargeValue(t *testing.T) {
   306  	trie := newEmpty()
   307  	trie.Update([]byte("key1"), []byte{99, 99, 99, 99})
   308  	trie.Update([]byte("key2"), bytes.Repeat([]byte{1}, 32))
   309  	trie.Hash()
   310  }
   311  
   312  type countingDB struct {
   313  	Database
   314  	gets map[string]int
   315  }
   316  
   317  func (db *countingDB) Get(key []byte) ([]byte, error) {
   318  	db.gets[string(key)]++
   319  	return db.Database.Get(key)
   320  }
   321  
   322  // TestCacheUnload checks that decoded nodes are unloaded after a
   323  // certain number of commit operations.
   324  func TestCacheUnload(t *testing.T) {
   325  	// Create test trie with two branches.
   326  	trie := newEmpty()
   327  	key1 := "---------------------------------"
   328  	key2 := "---some other branch"
   329  	updateString(trie, key1, "this is the branch of key1.")
   330  	updateString(trie, key2, "this is the branch of key2.")
   331  	root, _ := trie.Commit()
   332  
   333  	// Commit the trie repeatedly and access key1.
   334  	// The branch containing it is loaded from DB exactly two times:
   335  	// in the 0th and 6th iteration.
   336  	db := &countingDB{Database: trie.db, gets: make(map[string]int)}
   337  	trie, _ = New(root, db)
   338  	trie.SetCacheLimit(5)
   339  	for i := 0; i < 12; i++ {
   340  		getString(trie, key1)
   341  		trie.Commit()
   342  	}
   343  
   344  	// Check that it got loaded two times.
   345  	for dbkey, count := range db.gets {
   346  		if count != 2 {
   347  			t.Errorf("db key %x loaded %d times, want %d times", []byte(dbkey), count, 2)
   348  		}
   349  	}
   350  }
   351  
   352  // randTest performs random trie operations.
   353  // Instances of this test are created by Generate.
   354  type randTest []randTestStep
   355  
   356  type randTestStep struct {
   357  	op    int
   358  	key   []byte // for opUpdate, opDelete, opGet
   359  	value []byte // for opUpdate
   360  }
   361  
   362  const (
   363  	opUpdate = iota
   364  	opDelete
   365  	opGet
   366  	opCommit
   367  	opHash
   368  	opReset
   369  	opItercheckhash
   370  	opCheckCacheInvariant
   371  	opMax // boundary value, not an actual op
   372  )
   373  
   374  func (randTest) Generate(r *rand.Rand, size int) reflect.Value {
   375  	var allKeys [][]byte
   376  	genKey := func() []byte {
   377  		if len(allKeys) < 2 || r.Intn(100) < 10 {
   378  			// new key
   379  			key := make([]byte, r.Intn(50))
   380  			r.Read(key)
   381  			allKeys = append(allKeys, key)
   382  			return key
   383  		}
   384  		// use existing key
   385  		return allKeys[r.Intn(len(allKeys))]
   386  	}
   387  
   388  	var steps randTest
   389  	for i := 0; i < size; i++ {
   390  		step := randTestStep{op: r.Intn(opMax)}
   391  		switch step.op {
   392  		case opUpdate:
   393  			step.key = genKey()
   394  			step.value = make([]byte, 8)
   395  			binary.BigEndian.PutUint64(step.value, uint64(i))
   396  		case opGet, opDelete:
   397  			step.key = genKey()
   398  		}
   399  		steps = append(steps, step)
   400  	}
   401  	return reflect.ValueOf(steps)
   402  }
   403  
   404  func runRandTest(rt randTest) bool {
   405  	db, _ := ethdb.NewMemDatabase()
   406  	tr, _ := New(common.Hash{}, db)
   407  	values := make(map[string]string) // tracks content of the trie
   408  
   409  	for _, step := range rt {
   410  		switch step.op {
   411  		case opUpdate:
   412  			tr.Update(step.key, step.value)
   413  			values[string(step.key)] = string(step.value)
   414  		case opDelete:
   415  			tr.Delete(step.key)
   416  			delete(values, string(step.key))
   417  		case opGet:
   418  			v := tr.Get(step.key)
   419  			want := values[string(step.key)]
   420  			if string(v) != want {
   421  				fmt.Printf("mismatch for key 0x%x, got 0x%x want 0x%x", step.key, v, want)
   422  				return false
   423  			}
   424  		case opCommit:
   425  			if _, err := tr.Commit(); err != nil {
   426  				panic(err)
   427  			}
   428  		case opHash:
   429  			tr.Hash()
   430  		case opReset:
   431  			hash, err := tr.Commit()
   432  			if err != nil {
   433  				panic(err)
   434  			}
   435  			newtr, err := New(hash, db)
   436  			if err != nil {
   437  				panic(err)
   438  			}
   439  			tr = newtr
   440  		case opItercheckhash:
   441  			checktr, _ := New(common.Hash{}, nil)
   442  			it := NewIterator(tr.NodeIterator(nil))
   443  			for it.Next() {
   444  				checktr.Update(it.Key, it.Value)
   445  			}
   446  			if tr.Hash() != checktr.Hash() {
   447  				fmt.Println("hashes not equal")
   448  				return false
   449  			}
   450  		case opCheckCacheInvariant:
   451  			return checkCacheInvariant(tr.root, nil, tr.cachegen, false, 0)
   452  		}
   453  	}
   454  	return true
   455  }
   456  
   457  func checkCacheInvariant(n, parent node, parentCachegen uint16, parentDirty bool, depth int) bool {
   458  	var children []node
   459  	var flag nodeFlag
   460  	switch n := n.(type) {
   461  	case *shortNode:
   462  		flag = n.flags
   463  		children = []node{n.Val}
   464  	case *fullNode:
   465  		flag = n.flags
   466  		children = n.Children[:]
   467  	default:
   468  		return true
   469  	}
   470  
   471  	showerror := func() {
   472  		fmt.Printf("at depth %d node %s", depth, spew.Sdump(n))
   473  		fmt.Printf("parent: %s", spew.Sdump(parent))
   474  	}
   475  	if flag.gen > parentCachegen {
   476  		fmt.Printf("cache invariant violation: %d > %d\n", flag.gen, parentCachegen)
   477  		showerror()
   478  		return false
   479  	}
   480  	if depth > 0 && !parentDirty && flag.dirty {
   481  		fmt.Printf("cache invariant violation: child is dirty but parent isn't\n")
   482  		showerror()
   483  		return false
   484  	}
   485  	for _, child := range children {
   486  		if !checkCacheInvariant(child, n, flag.gen, flag.dirty, depth+1) {
   487  			return false
   488  		}
   489  	}
   490  	return true
   491  }
   492  
   493  func TestRandom(t *testing.T) {
   494  	if err := quick.Check(runRandTest, nil); err != nil {
   495  		t.Fatal(err)
   496  	}
   497  }
   498  
   499  func BenchmarkGet(b *testing.B)      { benchGet(b, false) }
   500  func BenchmarkGetDB(b *testing.B)    { benchGet(b, true) }
   501  func BenchmarkUpdateBE(b *testing.B) { benchUpdate(b, binary.BigEndian) }
   502  func BenchmarkUpdateLE(b *testing.B) { benchUpdate(b, binary.LittleEndian) }
   503  func BenchmarkHashBE(b *testing.B)   { benchHash(b, binary.BigEndian) }
   504  func BenchmarkHashLE(b *testing.B)   { benchHash(b, binary.LittleEndian) }
   505  
   506  const benchElemCount = 20000
   507  
   508  func benchGet(b *testing.B, commit bool) {
   509  	trie := new(Trie)
   510  	if commit {
   511  		_, tmpdb := tempDB()
   512  		trie, _ = New(common.Hash{}, tmpdb)
   513  	}
   514  	k := make([]byte, 32)
   515  	for i := 0; i < benchElemCount; i++ {
   516  		binary.LittleEndian.PutUint64(k, uint64(i))
   517  		trie.Update(k, k)
   518  	}
   519  	binary.LittleEndian.PutUint64(k, benchElemCount/2)
   520  	if commit {
   521  		trie.Commit()
   522  	}
   523  
   524  	b.ResetTimer()
   525  	for i := 0; i < b.N; i++ {
   526  		trie.Get(k)
   527  	}
   528  	b.StopTimer()
   529  
   530  	if commit {
   531  		ldb := trie.db.(*ethdb.LDBDatabase)
   532  		ldb.Close()
   533  		os.RemoveAll(ldb.Path())
   534  	}
   535  }
   536  
   537  func benchUpdate(b *testing.B, e binary.ByteOrder) *Trie {
   538  	trie := newEmpty()
   539  	k := make([]byte, 32)
   540  	for i := 0; i < b.N; i++ {
   541  		e.PutUint64(k, uint64(i))
   542  		trie.Update(k, k)
   543  	}
   544  	return trie
   545  }
   546  
   547  func benchHash(b *testing.B, e binary.ByteOrder) {
   548  	trie := newEmpty()
   549  	k := make([]byte, 32)
   550  	for i := 0; i < benchElemCount; i++ {
   551  		e.PutUint64(k, uint64(i))
   552  		trie.Update(k, k)
   553  	}
   554  
   555  	b.ResetTimer()
   556  	for i := 0; i < b.N; i++ {
   557  		trie.Hash()
   558  	}
   559  }
   560  
   561  func tempDB() (string, Database) {
   562  	dir, err := ioutil.TempDir("", "trie-bench")
   563  	if err != nil {
   564  		panic(fmt.Sprintf("can't create temporary directory: %v", err))
   565  	}
   566  	db, err := ethdb.NewLDBDatabase(dir, 256, 0)
   567  	if err != nil {
   568  		panic(fmt.Sprintf("can't create temporary database: %v", err))
   569  	}
   570  	return dir, db
   571  }
   572  
   573  func getString(trie *Trie, k string) []byte {
   574  	return trie.Get([]byte(k))
   575  }
   576  
   577  func updateString(trie *Trie, k, v string) {
   578  	trie.Update([]byte(k), []byte(v))
   579  }
   580  
   581  func deleteString(trie *Trie, k string) {
   582  	trie.Delete([]byte(k))
   583  }