github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/trie/trie_test.go (about)

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