github.com/aergoio/aergo@v1.3.1/pkg/trie/trie_test.go (about)

     1  /**
     2   *  @file
     3   *  @copyright defined in aergo/LICENSE.txt
     4   */
     5  
     6  package trie
     7  
     8  import (
     9  	"bytes"
    10  	"runtime"
    11  
    12  	//"io/ioutil"
    13  	"os"
    14  	"path"
    15  	"time"
    16  
    17  	//"encoding/hex"
    18  	"fmt"
    19  	"math/rand"
    20  	"sort"
    21  	"testing"
    22  
    23  	"github.com/aergoio/aergo-lib/db"
    24  	"github.com/aergoio/aergo/internal/common"
    25  	//"github.com/dgraph-io/badger"
    26  	//"github.com/dgraph-io/badger/options"
    27  )
    28  
    29  func TestTrieEmpty(t *testing.T) {
    30  	smt := NewTrie(nil, common.Hasher, nil)
    31  	if len(smt.Root) != 0 {
    32  		t.Fatal("empty trie root hash not correct")
    33  	}
    34  }
    35  
    36  func TestTrieUpdateAndGet(t *testing.T) {
    37  	smt := NewTrie(nil, common.Hasher, nil)
    38  	smt.atomicUpdate = false
    39  
    40  	// Add data to empty trie
    41  	keys := getFreshData(10, 32)
    42  	values := getFreshData(10, 32)
    43  	ch := make(chan mresult, 1)
    44  	smt.update(smt.Root, keys, values, nil, 0, smt.TrieHeight, ch)
    45  	res := <-ch
    46  	root := res.update
    47  
    48  	// Check all keys have been stored
    49  	for i, key := range keys {
    50  		value, _ := smt.get(root, key, nil, 0, smt.TrieHeight)
    51  		if !bytes.Equal(values[i], value) {
    52  			t.Fatal("value not updated")
    53  		}
    54  	}
    55  
    56  	// Append to the trie
    57  	newKeys := getFreshData(5, 32)
    58  	newValues := getFreshData(5, 32)
    59  	ch = make(chan mresult, 1)
    60  	smt.update(root, newKeys, newValues, nil, 0, smt.TrieHeight, ch)
    61  	res = <-ch
    62  	newRoot := res.update
    63  	if bytes.Equal(root, newRoot) {
    64  		t.Fatal("trie not updated")
    65  	}
    66  	for i, newKey := range newKeys {
    67  		newValue, _ := smt.get(newRoot, newKey, nil, 0, smt.TrieHeight)
    68  		if !bytes.Equal(newValues[i], newValue) {
    69  			t.Fatal("failed to get value")
    70  		}
    71  	}
    72  }
    73  
    74  func TestTrieAtomicUpdate(t *testing.T) {
    75  	smt := NewTrie(nil, common.Hasher, nil)
    76  	smt.CacheHeightLimit = 0
    77  	keys := getFreshData(1, 32)
    78  	values := getFreshData(1, 32)
    79  	root, _ := smt.AtomicUpdate(keys, values)
    80  	updatedNb := len(smt.db.updatedNodes)
    81  	cacheNb := len(smt.db.liveCache)
    82  	newvalues := getFreshData(1, 32)
    83  	smt.AtomicUpdate(keys, newvalues)
    84  	if len(smt.db.updatedNodes) != 2*updatedNb {
    85  		t.Fatal("Atomic update doesnt store all tries")
    86  	}
    87  	if len(smt.db.liveCache) != cacheNb {
    88  		t.Fatal("Cache size should remain the same")
    89  	}
    90  
    91  	// check keys of previous atomic update are accessible in
    92  	// updated nodes with root.
    93  	smt.atomicUpdate = false
    94  	for i, key := range keys {
    95  		value, _ := smt.get(root, key, nil, 0, smt.TrieHeight)
    96  		if !bytes.Equal(values[i], value) {
    97  			t.Fatal("failed to get value")
    98  		}
    99  	}
   100  }
   101  
   102  func TestTriePublicUpdateAndGet(t *testing.T) {
   103  	smt := NewTrie(nil, common.Hasher, nil)
   104  	smt.CacheHeightLimit = 0
   105  	// Add data to empty trie
   106  	keys := getFreshData(20, 32)
   107  	values := getFreshData(20, 32)
   108  	root, _ := smt.Update(keys, values)
   109  	updatedNb := len(smt.db.updatedNodes)
   110  	cacheNb := len(smt.db.liveCache)
   111  
   112  	// Check all keys have been stored
   113  	for i, key := range keys {
   114  		value, _ := smt.Get(key)
   115  		if !bytes.Equal(values[i], value) {
   116  			t.Fatal("trie not updated")
   117  		}
   118  	}
   119  	if !bytes.Equal(root, smt.Root) {
   120  		t.Fatal("Root not stored")
   121  	}
   122  
   123  	newValues := getFreshData(20, 32)
   124  	smt.Update(keys, newValues)
   125  
   126  	if len(smt.db.updatedNodes) != updatedNb {
   127  		t.Fatal("multiple updates don't actualise updated nodes")
   128  	}
   129  	if len(smt.db.liveCache) != cacheNb {
   130  		t.Fatal("multiple updates don't actualise liveCache")
   131  	}
   132  	// Check all keys have been modified
   133  	for i, key := range keys {
   134  		value, _ := smt.Get(key)
   135  		if !bytes.Equal(newValues[i], value) {
   136  			t.Fatal("trie not updated")
   137  		}
   138  	}
   139  }
   140  
   141  func TestTrieDelete(t *testing.T) {
   142  	smt := NewTrie(nil, common.Hasher, nil)
   143  	// Add data to empty trie
   144  	keys := getFreshData(20, 32)
   145  	values := getFreshData(20, 32)
   146  	ch := make(chan mresult, 1)
   147  	smt.update(smt.Root, keys, values, nil, 0, smt.TrieHeight, ch)
   148  	result := <-ch
   149  	root := result.update
   150  	value, _ := smt.get(root, keys[0], nil, 0, smt.TrieHeight)
   151  	if !bytes.Equal(values[0], value) {
   152  		t.Fatal("trie not updated")
   153  	}
   154  
   155  	// Delete from trie
   156  	// To delete a key, just set it's value to Default leaf hash.
   157  	ch = make(chan mresult, 1)
   158  	smt.update(root, keys[0:1], [][]byte{DefaultLeaf}, nil, 0, smt.TrieHeight, ch)
   159  	result = <-ch
   160  	updatedNb := len(smt.db.updatedNodes)
   161  	newRoot := result.update
   162  	newValue, _ := smt.get(newRoot, keys[0], nil, 0, smt.TrieHeight)
   163  	if len(newValue) != 0 {
   164  		t.Fatal("Failed to delete from trie")
   165  	}
   166  	// Remove deleted key from keys and check root with a clean trie.
   167  	smt2 := NewTrie(nil, common.Hasher, nil)
   168  	ch = make(chan mresult, 1)
   169  	smt2.update(smt.Root, keys[1:], values[1:], nil, 0, smt.TrieHeight, ch)
   170  	result = <-ch
   171  	cleanRoot := result.update
   172  	if !bytes.Equal(newRoot, cleanRoot) {
   173  		t.Fatal("roots mismatch")
   174  	}
   175  
   176  	if len(smt2.db.updatedNodes) != updatedNb {
   177  		t.Fatal("deleting doesn't actualise updated nodes")
   178  	}
   179  
   180  	//Empty the trie
   181  	var newValues [][]byte
   182  	for i := 0; i < 20; i++ {
   183  		newValues = append(newValues, DefaultLeaf)
   184  	}
   185  	ch = make(chan mresult, 1)
   186  	smt.update(root, keys, newValues, nil, 0, smt.TrieHeight, ch)
   187  	result = <-ch
   188  	root = result.update
   189  	//if !bytes.Equal(smt.DefaultHash(256), root) {
   190  	if len(root) != 0 {
   191  		t.Fatal("empty trie root hash not correct")
   192  	}
   193  
   194  	// Test deleting an already empty key
   195  	smt = NewTrie(nil, common.Hasher, nil)
   196  	keys = getFreshData(2, 32)
   197  	values = getFreshData(2, 32)
   198  	root, _ = smt.Update(keys, values)
   199  	key0 := make([]byte, 32, 32)
   200  	key1 := make([]byte, 32, 32)
   201  	smt.Update([][]byte{key0, key1}, [][]byte{DefaultLeaf, DefaultLeaf})
   202  	if !bytes.Equal(root, smt.Root) {
   203  		t.Fatal("deleting a default key shouldnt' modify the tree")
   204  	}
   205  }
   206  
   207  // test updating and deleting at the same time
   208  func TestTrieUpdateAndDelete(t *testing.T) {
   209  	smt := NewTrie(nil, common.Hasher, nil)
   210  	smt.CacheHeightLimit = 0
   211  	key0 := make([]byte, 32, 32)
   212  	values := getFreshData(1, 32)
   213  	root, _ := smt.Update([][]byte{key0}, values)
   214  	cacheNb := len(smt.db.liveCache)
   215  	updatedNb := len(smt.db.updatedNodes)
   216  	smt.atomicUpdate = false
   217  	_, _, k, v, isShortcut, _ := smt.loadChildren(root, smt.TrieHeight, 0, nil)
   218  	if !isShortcut || !bytes.Equal(k[:HashLength], key0) || !bytes.Equal(v[:HashLength], values[0]) {
   219  		t.Fatal("leaf shortcut didn't move up to root")
   220  	}
   221  
   222  	key1 := make([]byte, 32, 32)
   223  	// set the last bit
   224  	bitSet(key1, 255)
   225  	keys := [][]byte{key0, key1}
   226  	values = [][]byte{DefaultLeaf, getFreshData(1, 32)[0]}
   227  	root, _ = smt.Update(keys, values)
   228  
   229  	if len(smt.db.liveCache) != cacheNb {
   230  		t.Fatal("number of cache nodes not correct after delete")
   231  	}
   232  	if len(smt.db.updatedNodes) != updatedNb {
   233  		t.Fatal("number of cache nodes not correct after delete")
   234  	}
   235  
   236  	smt.atomicUpdate = false
   237  	_, _, k, v, isShortcut, _ = smt.loadChildren(root, smt.TrieHeight, 0, nil)
   238  	if !isShortcut || !bytes.Equal(k[:HashLength], key1) || !bytes.Equal(v[:HashLength], values[1]) {
   239  		t.Fatal("leaf shortcut didn't move up to root")
   240  	}
   241  }
   242  
   243  func TestTrieMerkleProof(t *testing.T) {
   244  	smt := NewTrie(nil, common.Hasher, nil)
   245  	// Add data to empty trie
   246  	keys := getFreshData(10, 32)
   247  	values := getFreshData(10, 32)
   248  	smt.Update(keys, values)
   249  
   250  	for i, key := range keys {
   251  		ap, _, k, v, _ := smt.MerkleProof(key)
   252  		if !smt.VerifyInclusion(ap, key, values[i]) {
   253  			t.Fatalf("failed to verify inclusion proof")
   254  		}
   255  		if !bytes.Equal(key, k) && !bytes.Equal(values[i], v) {
   256  			t.Fatalf("merkle proof didnt return the correct key-value pair")
   257  		}
   258  	}
   259  	emptyKey := common.Hasher([]byte("non-member"))
   260  	ap, included, proofKey, proofValue, _ := smt.MerkleProof(emptyKey)
   261  	if included {
   262  		t.Fatalf("failed to verify non inclusion proof")
   263  	}
   264  	if !smt.VerifyNonInclusion(ap, emptyKey, proofValue, proofKey) {
   265  		t.Fatalf("failed to verify non inclusion proof")
   266  	}
   267  }
   268  
   269  func TestTrieMerkleProofCompressed(t *testing.T) {
   270  	smt := NewTrie(nil, common.Hasher, nil)
   271  	// Add data to empty trie
   272  	keys := getFreshData(10, 32)
   273  	values := getFreshData(10, 32)
   274  	smt.Update(keys, values)
   275  
   276  	for i, key := range keys {
   277  		bitmap, ap, length, _, k, v, _ := smt.MerkleProofCompressed(key)
   278  		if !smt.VerifyInclusionC(bitmap, key, values[i], ap, length) {
   279  			t.Fatalf("failed to verify inclusion proof")
   280  		}
   281  		if !bytes.Equal(key, k) && !bytes.Equal(values[i], v) {
   282  			t.Fatalf("merkle proof didnt return the correct key-value pair")
   283  		}
   284  	}
   285  	emptyKey := common.Hasher([]byte("non-member"))
   286  	bitmap, ap, length, included, proofKey, proofValue, _ := smt.MerkleProofCompressed(emptyKey)
   287  	if included {
   288  		t.Fatalf("failed to verify non inclusion proof")
   289  	}
   290  	if !smt.VerifyNonInclusionC(ap, length, bitmap, emptyKey, proofValue, proofKey) {
   291  		t.Fatalf("failed to verify non inclusion proof")
   292  	}
   293  }
   294  
   295  func TestTrieCommit(t *testing.T) {
   296  	dbPath := path.Join(".aergo", "db")
   297  	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
   298  		_ = os.MkdirAll(dbPath, 0711)
   299  	}
   300  	st := db.NewDB(db.BadgerImpl, dbPath)
   301  
   302  	smt := NewTrie(nil, common.Hasher, st)
   303  	keys := getFreshData(10, 32)
   304  	values := getFreshData(10, 32)
   305  	smt.Update(keys, values)
   306  	smt.Commit()
   307  	// liveCache is deleted so the key is fetched in badger db
   308  	smt.db.liveCache = make(map[Hash][][]byte)
   309  	for i, key := range keys {
   310  		value, _ := smt.Get(key)
   311  		if !bytes.Equal(value, values[i]) {
   312  			t.Fatal("failed to get value in committed db")
   313  		}
   314  	}
   315  	st.Close()
   316  	os.RemoveAll(".aergo")
   317  }
   318  
   319  func TestTrieStageUpdates(t *testing.T) {
   320  	dbPath := path.Join(".aergo", "db")
   321  	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
   322  		_ = os.MkdirAll(dbPath, 0711)
   323  	}
   324  	st := db.NewDB(db.BadgerImpl, dbPath)
   325  
   326  	smt := NewTrie(nil, common.Hasher, st)
   327  	keys := getFreshData(10, 32)
   328  	values := getFreshData(10, 32)
   329  	smt.Update(keys, values)
   330  	txn := st.NewTx()
   331  	smt.StageUpdates(txn.(DbTx))
   332  	txn.Commit()
   333  	// liveCache is deleted so the key is fetched in badger db
   334  	smt.db.liveCache = make(map[Hash][][]byte)
   335  	for i, key := range keys {
   336  		value, _ := smt.Get(key)
   337  		if !bytes.Equal(value, values[i]) {
   338  			t.Fatal("failed to get value in committed db")
   339  		}
   340  	}
   341  	st.Close()
   342  	os.RemoveAll(".aergo")
   343  }
   344  
   345  func TestTrieRevert(t *testing.T) {
   346  	dbPath := path.Join(".aergo", "db")
   347  	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
   348  		_ = os.MkdirAll(dbPath, 0711)
   349  	}
   350  	st := db.NewDB(db.BadgerImpl, dbPath)
   351  
   352  	smt := NewTrie(nil, common.Hasher, st)
   353  
   354  	// Edge case : Test that revert doesnt delete shortcut nodes
   355  	// when moved to a different position in tree
   356  	key0 := make([]byte, 32, 32)
   357  	key1 := make([]byte, 32, 32)
   358  	// setting the bit at 251 creates 2 shortcut batches at height 252
   359  	bitSet(key1, 251)
   360  	values := getFreshData(2, 32)
   361  	keys := [][]byte{key0, key1}
   362  	root, _ := smt.Update([][]byte{key0}, [][]byte{values[0]})
   363  	smt.Commit()
   364  	root2, _ := smt.Update([][]byte{key1}, [][]byte{values[1]})
   365  	smt.Commit()
   366  	smt.Revert(root)
   367  	if len(smt.db.Store.Get(root)) == 0 {
   368  		t.Fatal("shortcut node shouldnt be deleted by revert")
   369  	}
   370  	if len(smt.db.Store.Get(root2)) != 0 {
   371  		t.Fatal("reverted root should have been deleted")
   372  	}
   373  	key1 = make([]byte, 32, 32)
   374  	// setting the bit at 255 stores the keys as the tip
   375  	bitSet(key1, 255)
   376  	smt.Update([][]byte{key1}, [][]byte{values[1]})
   377  	smt.Commit()
   378  	smt.Revert(root)
   379  	if len(smt.db.Store.Get(root)) == 0 {
   380  		t.Fatal("shortcut node shouldnt be deleted by revert")
   381  	}
   382  
   383  	// Test all nodes are reverted in the usual case
   384  	// Add data to empty trie
   385  	keys = getFreshData(10, 32)
   386  	values = getFreshData(10, 32)
   387  	root, _ = smt.Update(keys, values)
   388  	smt.Commit()
   389  
   390  	// Update the values
   391  	newValues := getFreshData(10, 32)
   392  	smt.Update(keys, newValues)
   393  	updatedNodes1 := smt.db.updatedNodes
   394  	smt.Commit()
   395  	newKeys := getFreshData(10, 32)
   396  	newValues = getFreshData(10, 32)
   397  	smt.Update(newKeys, newValues)
   398  	updatedNodes2 := smt.db.updatedNodes
   399  	smt.Commit()
   400  
   401  	smt.Revert(root)
   402  
   403  	if !bytes.Equal(smt.Root, root) {
   404  		t.Fatal("revert failed")
   405  	}
   406  	if len(smt.pastTries) != 2 { // contains empty trie + reverted trie
   407  		t.Fatal("past tries not updated after revert")
   408  	}
   409  	// Check all keys have been reverted
   410  	for i, key := range keys {
   411  		value, _ := smt.Get(key)
   412  		if !bytes.Equal(values[i], value) {
   413  			t.Fatal("revert failed, values not updated")
   414  		}
   415  	}
   416  	if len(smt.db.liveCache) != 0 {
   417  		t.Fatal("live cache not reset after revert")
   418  	}
   419  	// Check all reverted nodes have been deleted
   420  	for node, _ := range updatedNodes2 {
   421  		if len(smt.db.Store.Get(node[:])) != 0 {
   422  			t.Fatal("nodes not deleted from database", node)
   423  		}
   424  	}
   425  	for node, _ := range updatedNodes1 {
   426  		if len(smt.db.Store.Get(node[:])) != 0 {
   427  			t.Fatal("nodes not deleted from database", node)
   428  		}
   429  	}
   430  	st.Close()
   431  	os.RemoveAll(".aergo")
   432  }
   433  
   434  func TestTrieRaisesError(t *testing.T) {
   435  	dbPath := path.Join(".aergo", "db")
   436  	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
   437  		_ = os.MkdirAll(dbPath, 0711)
   438  	}
   439  	st := db.NewDB(db.BadgerImpl, dbPath)
   440  
   441  	smt := NewTrie(nil, common.Hasher, st)
   442  	// Add data to empty trie
   443  	keys := getFreshData(10, 32)
   444  	values := getFreshData(10, 32)
   445  	smt.Update(keys, values)
   446  	smt.db.liveCache = make(map[Hash][][]byte)
   447  	smt.db.updatedNodes = make(map[Hash][][]byte)
   448  
   449  	// Check errors are raised is a keys is not in cache nore db
   450  	for _, key := range keys {
   451  		_, err := smt.Get(key)
   452  		if err == nil {
   453  			t.Fatal("Error not created if database doesnt have a node")
   454  		}
   455  	}
   456  	_, _, _, _, _, _, err := smt.MerkleProofCompressed(keys[0])
   457  	if err == nil {
   458  		t.Fatal("Error not created if database doesnt have a node")
   459  	}
   460  	_, err = smt.Update(keys, values)
   461  	if err == nil {
   462  		t.Fatal("Error not created if database doesnt have a node")
   463  	}
   464  	st.Close()
   465  	os.RemoveAll(".aergo")
   466  
   467  	smt = NewTrie(nil, common.Hasher, nil)
   468  	err = smt.Commit()
   469  	if err == nil {
   470  		t.Fatal("Error not created if database not connected")
   471  	}
   472  	smt.db.liveCache = make(map[Hash][][]byte)
   473  	smt.atomicUpdate = false
   474  	_, _, _, _, _, err = smt.loadChildren(make([]byte, 32, 32), smt.TrieHeight, 0, nil)
   475  	if err == nil {
   476  		t.Fatal("Error not created if database not connected")
   477  	}
   478  	err = smt.LoadCache(make([]byte, 32))
   479  	if err == nil {
   480  		t.Fatal("Error not created if database not connected")
   481  	}
   482  }
   483  
   484  func TestTrieLoadCache(t *testing.T) {
   485  	dbPath := path.Join(".aergo", "db")
   486  	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
   487  		_ = os.MkdirAll(dbPath, 0711)
   488  	}
   489  	st := db.NewDB(db.BadgerImpl, dbPath)
   490  
   491  	smt := NewTrie(nil, common.Hasher, st)
   492  	// Test size of cache
   493  	smt.CacheHeightLimit = 0
   494  	key0 := make([]byte, 32, 32)
   495  	key1 := make([]byte, 32, 32)
   496  	bitSet(key1, 255)
   497  	values := getFreshData(2, 32)
   498  	smt.Update([][]byte{key0, key1}, values)
   499  	if len(smt.db.liveCache) != 66 {
   500  		// the nodes are at the tip, so 64 + 2 = 66
   501  		t.Fatal("cache size incorrect")
   502  	}
   503  
   504  	// Add data to empty trie
   505  	keys := getFreshData(10, 32)
   506  	values = getFreshData(10, 32)
   507  	smt.Update(keys, values)
   508  	smt.Commit()
   509  
   510  	// Simulate node restart by deleting and loading cache
   511  	cacheSize := len(smt.db.liveCache)
   512  	smt.db.liveCache = make(map[Hash][][]byte)
   513  
   514  	err := smt.LoadCache(smt.Root)
   515  
   516  	if err != nil {
   517  		t.Fatal(err)
   518  	}
   519  	if cacheSize != len(smt.db.liveCache) {
   520  		t.Fatal("Cache loading from db incorrect")
   521  	}
   522  	st.Close()
   523  	os.RemoveAll(".aergo")
   524  }
   525  
   526  func TestHeight0LeafShortcut(t *testing.T) {
   527  	keySize := 32
   528  	smt := NewTrie(nil, common.Hasher, nil)
   529  	// Add 2 sibling keys that will be stored at height 0
   530  	key0 := make([]byte, keySize, keySize)
   531  	key1 := make([]byte, keySize, keySize)
   532  	bitSet(key1, keySize*8-1)
   533  	keys := [][]byte{key0, key1}
   534  	values := getFreshData(2, 32)
   535  	smt.Update(keys, values)
   536  	updatedNb := len(smt.db.updatedNodes)
   537  
   538  	// Check all keys have been stored
   539  	for i, key := range keys {
   540  		value, _ := smt.Get(key)
   541  		if !bytes.Equal(values[i], value) {
   542  			t.Fatal("trie not updated")
   543  		}
   544  	}
   545  	bitmap, ap, length, _, k, v, err := smt.MerkleProofCompressed(key1)
   546  	if err != nil {
   547  		t.Fatal(err)
   548  	}
   549  	if !bytes.Equal(key1, k) && !bytes.Equal(values[1], v) {
   550  		t.Fatalf("merkle proof didnt return the correct key-value pair")
   551  	}
   552  	if length != smt.TrieHeight {
   553  		t.Fatal("proof should have length equal to trie height for a leaf shortcut")
   554  	}
   555  	if !smt.VerifyInclusionC(bitmap, key1, values[1], ap, length) {
   556  		t.Fatal("failed to verify inclusion proof")
   557  	}
   558  
   559  	// Delete one key and check that the remaining one moved up to the root of the tree
   560  	newRoot, _ := smt.AtomicUpdate(keys[0:1], [][]byte{DefaultLeaf})
   561  
   562  	// Nb of updated nodes remains same because the new shortcut root was already stored at height 0.
   563  	if len(smt.db.updatedNodes) != updatedNb {
   564  		fmt.Println(len(smt.db.updatedNodes), updatedNb)
   565  		t.Fatal("number of cache nodes not correct after delete")
   566  	}
   567  	smt.atomicUpdate = false
   568  	_, _, k, v, isShortcut, err := smt.loadChildren(newRoot, smt.TrieHeight, 0, nil)
   569  	if err != nil {
   570  		t.Fatal(err)
   571  	}
   572  	if !isShortcut || !bytes.Equal(k[:HashLength], key1) || !bytes.Equal(v[:HashLength], values[1]) {
   573  		t.Fatal("leaf shortcut didn't move up to root")
   574  	}
   575  
   576  	_, _, length, _, k, v, _ = smt.MerkleProofCompressed(key1)
   577  	if length != 0 {
   578  		t.Fatal("proof should have length equal to trie height for a leaf shortcut")
   579  	}
   580  	if !bytes.Equal(key1, k) && !bytes.Equal(values[1], v) {
   581  		t.Fatalf("merkle proof didnt return the correct key-value pair")
   582  	}
   583  }
   584  
   585  func TestStash(t *testing.T) {
   586  	dbPath := path.Join(".aergo", "db")
   587  	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
   588  		_ = os.MkdirAll(dbPath, 0711)
   589  	}
   590  	st := db.NewDB(db.BadgerImpl, dbPath)
   591  	smt := NewTrie(nil, common.Hasher, st)
   592  	// Add data to empty trie
   593  	keys := getFreshData(20, 32)
   594  	values := getFreshData(20, 32)
   595  	root, _ := smt.Update(keys, values)
   596  	cacheSize := len(smt.db.liveCache)
   597  	smt.Commit()
   598  	if len(smt.pastTries) != 1 {
   599  		t.Fatal("Past tries not updated after commit")
   600  	}
   601  	values = getFreshData(20, 32)
   602  	smt.Update(keys, values)
   603  	smt.Stash(true)
   604  	if len(smt.pastTries) != 1 {
   605  		t.Fatal("Past tries not updated after commit")
   606  	}
   607  	if !bytes.Equal(smt.Root, root) {
   608  		t.Fatal("Trie not rolled back")
   609  	}
   610  	if len(smt.db.updatedNodes) != 0 {
   611  		t.Fatal("Trie not rolled back")
   612  	}
   613  	if len(smt.db.liveCache) != cacheSize {
   614  		t.Fatal("Trie not rolled back")
   615  	}
   616  	keys = getFreshData(20, 32)
   617  	values = getFreshData(20, 32)
   618  	smt.AtomicUpdate(keys, values)
   619  	values = getFreshData(20, 32)
   620  	smt.AtomicUpdate(keys, values)
   621  	if len(smt.pastTries) != 3 {
   622  		t.Fatal("Past tries not updated after commit")
   623  	}
   624  	smt.Stash(true)
   625  	if !bytes.Equal(smt.Root, root) {
   626  		t.Fatal("Trie not rolled back")
   627  	}
   628  	if len(smt.db.updatedNodes) != 0 {
   629  		t.Fatal("Trie not rolled back")
   630  	}
   631  	if len(smt.db.liveCache) != cacheSize {
   632  		t.Fatal("Trie not rolled back")
   633  	}
   634  	if len(smt.pastTries) != 1 {
   635  		t.Fatal("Past tries not updated after commit")
   636  	}
   637  	st.Close()
   638  	os.RemoveAll(".aergo")
   639  }
   640  
   641  func benchmark10MAccounts10Ktps(smt *Trie, b *testing.B) {
   642  	//b.ReportAllocs()
   643  	keys := getFreshData(100, 32)
   644  	values := getFreshData(100, 32)
   645  	smt.Update(keys, values)
   646  	fmt.Println("\nLoading b.N x 1000 accounts")
   647  	for i := 0; i < b.N; i++ {
   648  		newkeys := getFreshData(1000, 32)
   649  		newvalues := getFreshData(1000, 32)
   650  		start := time.Now()
   651  		smt.Update(newkeys, newvalues)
   652  		end := time.Now()
   653  		smt.Commit()
   654  		end2 := time.Now()
   655  		for j, key := range newkeys {
   656  			val, _ := smt.Get(key)
   657  			if !bytes.Equal(val, newvalues[j]) {
   658  				b.Fatal("new key not included")
   659  			}
   660  		}
   661  		end3 := time.Now()
   662  		elapsed := end.Sub(start)
   663  		elapsed2 := end2.Sub(end)
   664  		elapsed3 := end3.Sub(end2)
   665  		var m runtime.MemStats
   666  		runtime.ReadMemStats(&m)
   667  		fmt.Println(i, " : update time : ", elapsed, "commit time : ", elapsed2,
   668  			"\n1000 Get time : ", elapsed3,
   669  			"\ndb read : ", smt.LoadDbCounter, "    cache read : ", smt.LoadCacheCounter,
   670  			"\ncache size : ", len(smt.db.liveCache),
   671  			"\nRAM : ", m.Sys/1024/1024, " MiB")
   672  	}
   673  }
   674  
   675  //go test -run=xxx -bench=. -benchmem -test.benchtime=20s
   676  func BenchmarkCacheHeightLimit233(b *testing.B) {
   677  	dbPath := path.Join(".aergo", "db")
   678  	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
   679  		_ = os.MkdirAll(dbPath, 0711)
   680  	}
   681  	st := db.NewDB(db.BadgerImpl, dbPath)
   682  	smt := NewTrie(nil, common.Hasher, st)
   683  	smt.CacheHeightLimit = 233
   684  	benchmark10MAccounts10Ktps(smt, b)
   685  	st.Close()
   686  	os.RemoveAll(".aergo")
   687  }
   688  func BenchmarkCacheHeightLimit238(b *testing.B) {
   689  	dbPath := path.Join(".aergo", "db")
   690  	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
   691  		_ = os.MkdirAll(dbPath, 0711)
   692  	}
   693  	st := db.NewDB(db.BadgerImpl, dbPath)
   694  	smt := NewTrie(nil, common.Hasher, st)
   695  	smt.CacheHeightLimit = 238
   696  	benchmark10MAccounts10Ktps(smt, b)
   697  	st.Close()
   698  	os.RemoveAll(".aergo")
   699  }
   700  func BenchmarkCacheHeightLimit245(b *testing.B) {
   701  	dbPath := path.Join(".aergo", "db")
   702  	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
   703  		_ = os.MkdirAll(dbPath, 0711)
   704  	}
   705  	st := db.NewDB(db.BadgerImpl, dbPath)
   706  	smt := NewTrie(nil, common.Hasher, st)
   707  	smt.CacheHeightLimit = 245
   708  	benchmark10MAccounts10Ktps(smt, b)
   709  	st.Close()
   710  	os.RemoveAll(".aergo")
   711  }
   712  
   713  func getFreshData(size, length int) [][]byte {
   714  	var data [][]byte
   715  	for i := 0; i < size; i++ {
   716  		key := make([]byte, 32)
   717  		_, err := rand.Read(key)
   718  		if err != nil {
   719  			panic(err)
   720  		}
   721  		data = append(data, common.Hasher(key)[:length])
   722  	}
   723  	sort.Sort(DataArray(data))
   724  	return data
   725  }