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