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