arnaucube
arnaucube/asmtPublic Self-hosted repository
asmt/smt/trie_test.go
smt/trie_test.goRaw
  1/**
  2 *  @file
  3 *  @copyright defined in aergo/LICENSE.txt
  4 */
  5
  6package trie
  7
  8import (
  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/p4u/asmt/db"
 24)
 25
 26func TestTrieEmpty(t *testing.T) {
 27	smt := NewTrie(nil, Hasher, nil)
 28	if len(smt.Root) != 0 {
 29		t.Fatal("empty trie root hash not correct")
 30	}
 31}
 32
 33func TestTrieUpdateAndGet(t *testing.T) {
 34	smt := NewTrie(nil, Hasher, nil)
 35	smt.atomicUpdate = false
 36
 37	// Add data to empty trie
 38	keys := getFreshData(10, 32)
 39	values := getFreshData(10, 32)
 40	ch := make(chan mresult, 1)
 41	smt.update(smt.Root, keys, values, nil, 0, smt.TrieHeight, ch)
 42	res := <-ch
 43	root := res.update
 44
 45	// Check all keys have been stored
 46	for i, key := range keys {
 47		value, _ := smt.get(root, key, nil, 0, smt.TrieHeight)
 48		if !bytes.Equal(values[i], value) {
 49			t.Fatal("value not updated")
 50		}
 51	}
 52
 53	// Append to the trie
 54	newKeys := getFreshData(5, 32)
 55	newValues := getFreshData(5, 32)
 56	ch = make(chan mresult, 1)
 57	smt.update(root, newKeys, newValues, nil, 0, smt.TrieHeight, ch)
 58	res = <-ch
 59	newRoot := res.update
 60	if bytes.Equal(root, newRoot) {
 61		t.Fatal("trie not updated")
 62	}
 63	for i, newKey := range newKeys {
 64		newValue, _ := smt.get(newRoot, newKey, nil, 0, smt.TrieHeight)
 65		if !bytes.Equal(newValues[i], newValue) {
 66			t.Fatal("failed to get value")
 67		}
 68	}
 69}
 70
 71func TestTrieAtomicUpdate(t *testing.T) {
 72	smt := NewTrie(nil, Hasher, nil)
 73	smt.CacheHeightLimit = 0
 74	keys := getFreshData(1, 32)
 75	values := getFreshData(1, 32)
 76	root, _ := smt.AtomicUpdate(keys, values)
 77	updatedNb := len(smt.db.updatedNodes)
 78	cacheNb := len(smt.db.liveCache)
 79	newvalues := getFreshData(1, 32)
 80	if _, err := smt.AtomicUpdate(keys, newvalues); err != nil {
 81		t.Fatal(err)
 82	}
 83	if len(smt.db.updatedNodes) != 2*updatedNb {
 84		t.Fatal("Atomic update doesnt store all tries")
 85	}
 86	if len(smt.db.liveCache) != cacheNb {
 87		t.Fatal("Cache size should remain the same")
 88	}
 89
 90	// check keys of previous atomic update are accessible in
 91	// updated nodes with root.
 92	smt.atomicUpdate = false
 93	for i, key := range keys {
 94		value, _ := smt.get(root, key, nil, 0, smt.TrieHeight)
 95		if !bytes.Equal(values[i], value) {
 96			t.Fatal("failed to get value")
 97		}
 98	}
 99}
100
101func TestTriePublicUpdateAndGet(t *testing.T) {
102	smt := NewTrie(nil, Hasher, nil)
103	smt.CacheHeightLimit = 0
104	// Add data to empty trie
105	keys := getFreshData(20, 32)
106	values := getFreshData(20, 32)
107	root, _ := smt.Update(keys, values)
108	updatedNb := len(smt.db.updatedNodes)
109	cacheNb := len(smt.db.liveCache)
110
111	// Check all keys have been stored
112	for i, key := range keys {
113		value, _ := smt.Get(key)
114		if !bytes.Equal(values[i], value) {
115			t.Fatal("trie not updated")
116		}
117	}
118	if !bytes.Equal(root, smt.Root) {
119		t.Fatal("Root not stored")
120	}
121
122	newValues := getFreshData(20, 32)
123	if _, err := smt.Update(keys, newValues); err != nil {
124		t.Fatal(err)
125	}
126
127	if len(smt.db.updatedNodes) != updatedNb {
128		t.Fatal("multiple updates don't actualise updated nodes")
129	}
130	if len(smt.db.liveCache) != cacheNb {
131		t.Fatal("multiple updates don't actualise liveCache")
132	}
133	// Check all keys have been modified
134	for i, key := range keys {
135		value, _ := smt.Get(key)
136		if !bytes.Equal(newValues[i], value) {
137			t.Fatal("trie not updated")
138		}
139	}
140}
141
142func TestGetWithRoot(t *testing.T) {
143	dbPath := t.TempDir()
144	st := db.NewDB(db.LevelImpl, dbPath)
145	smt := NewTrie(nil, Hasher, st)
146	smt.CacheHeightLimit = 0
147
148	// Add data to empty trie
149	keys := getFreshData(20, 32)
150	values := getFreshData(20, 32)
151	root, _ := smt.Update(keys, values)
152
153	// Check all keys have been stored
154	for i, key := range keys {
155		value, _ := smt.Get(key)
156		if !bytes.Equal(values[i], value) {
157			t.Fatal("trie not updated")
158		}
159	}
160	if !bytes.Equal(root, smt.Root) {
161		t.Fatal("Root not stored")
162	}
163	if err := smt.Commit(); err != nil {
164		t.Fatal(err)
165	}
166	// Delete two values (0 and 1)
167	if _, err := smt.Update([][]byte{keys[0], keys[1]}, [][]byte{DefaultLeaf, DefaultLeaf}); err != nil {
168		t.Fatal(err)
169	}
170
171	// Change one value
172	oldValue3 := make([]byte, 32)
173	copy(oldValue3, values[3])
174	values[3] = getFreshData(1, 32)[0]
175	if _, err := smt.Update([][]byte{keys[3]}, [][]byte{values[3]}); err != nil {
176		t.Fatal(err)
177	}
178
179	// Check root has been actually updated
180	if bytes.Equal(smt.Root, root) {
181		t.Fatal("root not updated")
182	}
183
184	// Get the third value with the new root
185	v3, err := smt.GetWithRoot(keys[3], smt.Root)
186	if err != nil {
187		t.Fatal(err)
188	}
189	if !bytes.Equal(v3, values[3]) {
190		t.Fatalf("GetWithRoot did not keep the value: %x != %x", v3, values[3])
191	}
192
193	// Get the third value with the old root
194	v3, err = smt.GetWithRoot(keys[3], root)
195	if err != nil {
196		t.Fatal(err)
197	}
198	if !bytes.Equal(v3, oldValue3) {
199		t.Fatalf("GetWithRoot did not keep the value: %x != %x", v3, oldValue3)
200	}
201	st.Close()
202}
203
204func TestTrieWalk(t *testing.T) {
205	dbPath := t.TempDir()
206	st := db.NewDB(db.LevelImpl, dbPath)
207
208	smt := NewTrie(nil, Hasher, st)
209	smt.CacheHeightLimit = 0
210	// Add data to empty trie
211	keys := getFreshData(20, 32)
212	values := getFreshData(20, 32)
213	root, _ := smt.Update(keys, values)
214
215	// Check all keys have been stored
216	for i, key := range keys {
217		value, _ := smt.Get(key)
218		if !bytes.Equal(values[i], value) {
219			t.Fatal("trie not updated")
220		}
221	}
222	if !bytes.Equal(root, smt.Root) {
223		t.Fatal("Root not stored")
224	}
225
226	// Walk over the whole tree and compare the values
227	i := 0
228	if err := smt.Walk(nil, func(v *WalkResult) int32 {
229		if !bytes.Equal(v.Value, values[i]) {
230			t.Fatalf("walk value does not match %x != %x", v.Value, values[i])
231		}
232		if !bytes.Equal(v.Key, keys[i]) {
233			t.Fatalf("walk key does not match %x != %x", v.Key, keys[i])
234		}
235		i++
236		return 0
237	}); err != nil {
238		t.Fatal(err)
239	}
240
241	// Delete two values (0 and 3)
242	if _, err := smt.Update([][]byte{keys[0], keys[3]}, [][]byte{DefaultLeaf, DefaultLeaf}); err != nil {
243		t.Fatal(err)
244	}
245
246	// Delete two elements and walk again
247	i = 1
248	if err := smt.Walk(nil, func(v *WalkResult) int32 {
249		if i == 3 {
250			i++
251		}
252		if !bytes.Equal(v.Value, values[i]) {
253			t.Fatalf("walk value does not match %x == %x\n", v.Value, values[i])
254		}
255		if !bytes.Equal(v.Key, keys[i]) {
256			t.Fatalf("walk key does not match %x == %x\n", v.Key, keys[i])
257		}
258		i++
259		return 0
260	}); err != nil {
261		t.Fatal(err)
262	}
263
264	// Add one new value to preivous deleted key
265	values[3] = getFreshData(1, 32)[0]
266	if _, err := smt.Update([][]byte{keys[3]}, [][]byte{values[3]}); err != nil {
267		t.Fatal(err)
268	}
269
270	// Walk and check again
271	i = 1
272	if err := smt.Walk(nil, func(v *WalkResult) int32 {
273		if !bytes.Equal(v.Value, values[i]) {
274			t.Fatalf("walk value does not match %x != %x\n", v.Value, values[i])
275		}
276		if !bytes.Equal(v.Key, keys[i]) {
277			t.Fatalf("walk key does not match %x != %x\n", v.Key, keys[i])
278		}
279		i++
280		return 0
281	}); err != nil {
282		t.Fatal(err)
283	}
284
285	// Find a specific value and test stop
286	i = 0
287	if err := smt.Walk(nil, func(v *WalkResult) int32 {
288		if bytes.Equal(v.Value, values[5]) {
289			return 1
290		}
291		i++
292		return 0
293	}); err != nil {
294		t.Fatal(err)
295	}
296	if i != 4 {
297		t.Fatalf("Needed more iterations on walk than expected: %d != 4", i)
298	}
299
300	st.Close()
301}
302
303func TestTrieDelete(t *testing.T) {
304	smt := NewTrie(nil, Hasher, nil)
305	// Add data to empty trie
306	keys := getFreshData(20, 32)
307	values := getFreshData(20, 32)
308	ch := make(chan mresult, 1)
309	smt.update(smt.Root, keys, values, nil, 0, smt.TrieHeight, ch)
310	result := <-ch
311	root := result.update
312	value, _ := smt.get(root, keys[0], nil, 0, smt.TrieHeight)
313	if !bytes.Equal(values[0], value) {
314		t.Fatal("trie not updated")
315	}
316
317	// Delete from trie
318	// To delete a key, just set it's value to Default leaf hash.
319	ch = make(chan mresult, 1)
320	smt.update(root, keys[0:1], [][]byte{DefaultLeaf}, nil, 0, smt.TrieHeight, ch)
321	result = <-ch
322	updatedNb := len(smt.db.updatedNodes)
323	newRoot := result.update
324	newValue, _ := smt.get(newRoot, keys[0], nil, 0, smt.TrieHeight)
325	if len(newValue) != 0 {
326		t.Fatal("Failed to delete from trie")
327	}
328	// Remove deleted key from keys and check root with a clean trie.
329	smt2 := NewTrie(nil, Hasher, nil)
330	ch = make(chan mresult, 1)
331	smt2.update(smt.Root, keys[1:], values[1:], nil, 0, smt.TrieHeight, ch)
332	result = <-ch
333	cleanRoot := result.update
334	if !bytes.Equal(newRoot, cleanRoot) {
335		t.Fatal("roots mismatch")
336	}
337
338	if len(smt2.db.updatedNodes) != updatedNb {
339		t.Fatal("deleting doesn't actualise updated nodes")
340	}
341
342	//Empty the trie
343	var newValues [][]byte
344	for i := 0; i < 20; i++ {
345		newValues = append(newValues, DefaultLeaf)
346	}
347	ch = make(chan mresult, 1)
348	smt.update(root, keys, newValues, nil, 0, smt.TrieHeight, ch)
349	result = <-ch
350	root = result.update
351	//if !bytes.Equal(smt.DefaultHash(256), root) {
352	if len(root) != 0 {
353		t.Fatal("empty trie root hash not correct")
354	}
355
356	// Test deleting an already empty key
357	smt = NewTrie(nil, Hasher, nil)
358	keys = getFreshData(2, 32)
359	values = getFreshData(2, 32)
360	root, _ = smt.Update(keys, values)
361	key0 := make([]byte, 32)
362	key1 := make([]byte, 32)
363	if _, err := smt.Update([][]byte{key0, key1}, [][]byte{DefaultLeaf, DefaultLeaf}); err != nil {
364		t.Fatal(err)
365	}
366	if !bytes.Equal(root, smt.Root) {
367		t.Fatal("deleting a default key shouldnt' modify the tree")
368	}
369}
370
371// test updating and deleting at the same time
372func TestTrieUpdateAndDelete(t *testing.T) {
373	smt := NewTrie(nil, Hasher, nil)
374	smt.CacheHeightLimit = 0
375	key0 := make([]byte, 32)
376	values := getFreshData(1, 32)
377	root, _ := smt.Update([][]byte{key0}, values)
378	cacheNb := len(smt.db.liveCache)
379	updatedNb := len(smt.db.updatedNodes)
380	smt.atomicUpdate = false
381	_, _, k, v, isShortcut, _ := smt.loadChildren(root, smt.TrieHeight, 0, nil)
382	if !isShortcut || !bytes.Equal(k[:HashLength], key0) || !bytes.Equal(v[:HashLength], values[0]) {
383		t.Fatal("leaf shortcut didn't move up to root")
384	}
385
386	key1 := make([]byte, 32)
387	// set the last bit
388	bitSet(key1, 255)
389	keys := [][]byte{key0, key1}
390	values = [][]byte{DefaultLeaf, getFreshData(1, 32)[0]}
391	root, _ = smt.Update(keys, values)
392
393	if len(smt.db.liveCache) != cacheNb {
394		t.Fatal("number of cache nodes not correct after delete")
395	}
396	if len(smt.db.updatedNodes) != updatedNb {
397		t.Fatal("number of cache nodes not correct after delete")
398	}
399
400	smt.atomicUpdate = false
401	_, _, k, v, isShortcut, _ = smt.loadChildren(root, smt.TrieHeight, 0, nil)
402	if !isShortcut || !bytes.Equal(k[:HashLength], key1) || !bytes.Equal(v[:HashLength], values[1]) {
403		t.Fatal("leaf shortcut didn't move up to root")
404	}
405}
406
407func TestTrieMerkleProof(t *testing.T) {
408	smt := NewTrie(nil, Hasher, nil)
409	// Add data to empty trie
410	keys := getFreshData(10, 32)
411	values := getFreshData(10, 32)
412	if _, err := smt.Update(keys, values); err != nil {
413		t.Fatal(err)
414	}
415
416	for i, key := range keys {
417		ap, _, k, v, _ := smt.MerkleProof(key)
418		if !smt.VerifyInclusion(ap, key, values[i]) {
419			t.Fatalf("failed to verify inclusion proof")
420		}
421		if !bytes.Equal(key, k) && !bytes.Equal(values[i], v) {
422			t.Fatalf("merkle proof didnt return the correct key-value pair")
423		}
424	}
425	emptyKey := Hasher([]byte("non-member"))
426	ap, included, proofKey, proofValue, _ := smt.MerkleProof(emptyKey)
427	if included {
428		t.Fatalf("failed to verify non inclusion proof")
429	}
430	if !smt.VerifyNonInclusion(ap, emptyKey, proofValue, proofKey) {
431		t.Fatalf("failed to verify non inclusion proof")
432	}
433}
434
435func TestTrieMerkleProofCompressed(t *testing.T) {
436	smt := NewTrie(nil, Hasher, nil)
437	// Add data to empty trie
438	keys := getFreshData(10, 32)
439	values := getFreshData(10, 32)
440	if _, err := smt.Update(keys, values); err != nil {
441		t.Fatal(err)
442	}
443
444	for i, key := range keys {
445		bitmap, ap, length, _, k, v, _ := smt.MerkleProofCompressed(key)
446		if !smt.VerifyInclusionC(bitmap, key, values[i], ap, length) {
447			t.Fatalf("failed to verify inclusion proof")
448		}
449		if !bytes.Equal(key, k) && !bytes.Equal(values[i], v) {
450			t.Fatalf("merkle proof didnt return the correct key-value pair")
451		}
452	}
453	emptyKey := Hasher([]byte("non-member"))
454	bitmap, ap, length, included, proofKey, proofValue, _ := smt.MerkleProofCompressed(emptyKey)
455	if included {
456		t.Fatalf("failed to verify non inclusion proof")
457	}
458	if !smt.VerifyNonInclusionC(ap, length, bitmap, emptyKey, proofValue, proofKey) {
459		t.Fatalf("failed to verify non inclusion proof")
460	}
461}
462
463func TestTrieCommit(t *testing.T) {
464	dbPath := path.Join(".aergo", "db")
465	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
466		_ = os.MkdirAll(dbPath, 0711)
467	}
468	st := db.NewDB(db.LevelImpl, dbPath)
469
470	smt := NewTrie(nil, Hasher, st)
471	keys := getFreshData(10, 32)
472	values := getFreshData(10, 32)
473	if _, err := smt.Update(keys, values); err != nil {
474		t.Fatal(err)
475	}
476	if err := smt.Commit(); err != nil {
477		t.Fatal(err)
478	}
479	// liveCache is deleted so the key is fetched in badger db
480	smt.db.liveCache = make(map[Hash][][]byte)
481	for i, key := range keys {
482		value, _ := smt.Get(key)
483		if !bytes.Equal(value, values[i]) {
484			t.Fatal("failed to get value in committed db")
485		}
486	}
487	st.Close()
488	os.RemoveAll(".aergo")
489}
490
491func TestTrieStageUpdates(t *testing.T) {
492	dbPath := path.Join(".aergo", "db")
493	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
494		_ = os.MkdirAll(dbPath, 0711)
495	}
496	st := db.NewDB(db.LevelImpl, dbPath)
497
498	smt := NewTrie(nil, Hasher, st)
499	keys := getFreshData(10, 32)
500	values := getFreshData(10, 32)
501	if _, err := smt.Update(keys, values); err != nil {
502		t.Fatal(err)
503	}
504	txn := st.NewTx()
505	smt.StageUpdates(txn.(DbTx))
506	txn.Commit()
507	// liveCache is deleted so the key is fetched in badger db
508	smt.db.liveCache = make(map[Hash][][]byte)
509	for i, key := range keys {
510		value, _ := smt.Get(key)
511		if !bytes.Equal(value, values[i]) {
512			t.Fatal("failed to get value in committed db")
513		}
514	}
515	st.Close()
516	os.RemoveAll(".aergo")
517}
518
519func TestTrieRevert(t *testing.T) {
520	dbPath := path.Join(".aergo", "db")
521	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
522		_ = os.MkdirAll(dbPath, 0711)
523	}
524	st := db.NewDB(db.LevelImpl, dbPath)
525
526	smt := NewTrie(nil, Hasher, st)
527
528	// Edge case : Test that revert doesnt delete shortcut nodes
529	// when moved to a different position in tree
530	key0 := make([]byte, 32)
531	key1 := make([]byte, 32)
532	// setting the bit at 251 creates 2 shortcut batches at height 252
533	bitSet(key1, 251)
534	values := getFreshData(2, 32)
535	root, _ := smt.Update([][]byte{key0}, [][]byte{values[0]})
536	if err := smt.Commit(); err != nil {
537		t.Fatal(err)
538	}
539	root2, _ := smt.Update([][]byte{key1}, [][]byte{values[1]})
540	if err := smt.Commit(); err != nil {
541		t.Fatal(err)
542	}
543	if err := smt.Revert(root); err != nil {
544		t.Fatal(err)
545	}
546	if len(smt.db.Store.Get(root)) == 0 {
547		t.Fatal("shortcut node shouldnt be deleted by revert")
548	}
549	if len(smt.db.Store.Get(root2)) != 0 {
550		t.Fatal("reverted root should have been deleted")
551	}
552	key1 = make([]byte, 32)
553	// setting the bit at 255 stores the keys as the tip
554	bitSet(key1, 255)
555	if _, err := smt.Update([][]byte{key1}, [][]byte{values[1]}); err != nil {
556		t.Fatal(err)
557	}
558	if err := smt.Commit(); err != nil {
559		t.Fatal(err)
560	}
561	if err := smt.Revert(root); err != nil {
562		t.Fatal(err)
563	}
564	if len(smt.db.Store.Get(root)) == 0 {
565		t.Fatal("shortcut node shouldnt be deleted by revert")
566	}
567
568	// Test all nodes are reverted in the usual case
569	// Add data to empty trie
570	keys := getFreshData(10, 32)
571	values = getFreshData(10, 32)
572	root, _ = smt.Update(keys, values)
573	if err := smt.Commit(); err != nil {
574		t.Fatal(err)
575	}
576
577	// Update the values
578	newValues := getFreshData(10, 32)
579	if _, err := smt.Update(keys, newValues); err != nil {
580		t.Fatal(err)
581	}
582	updatedNodes1 := smt.db.updatedNodes
583	if err := smt.Commit(); err != nil {
584		t.Fatal(err)
585	}
586	newKeys := getFreshData(10, 32)
587	newValues = getFreshData(10, 32)
588	if _, err := smt.Update(newKeys, newValues); err != nil {
589		t.Fatal(err)
590	}
591	updatedNodes2 := smt.db.updatedNodes
592	if err := smt.Commit(); err != nil {
593		t.Fatal(err)
594	}
595
596	if err := smt.Revert(root); err != nil {
597		t.Fatal(err)
598	}
599
600	if !bytes.Equal(smt.Root, root) {
601		t.Fatal("revert failed")
602	}
603	if len(smt.pastTries) != 2 { // contains empty trie + reverted trie
604		t.Fatal("past tries not updated after revert")
605	}
606	// Check all keys have been reverted
607	for i, key := range keys {
608		value, _ := smt.Get(key)
609		if !bytes.Equal(values[i], value) {
610			t.Fatal("revert failed, values not updated")
611		}
612	}
613	if len(smt.db.liveCache) != 0 {
614		t.Fatal("live cache not reset after revert")
615	}
616	// Check all reverted nodes have been deleted
617	for node := range updatedNodes2 {
618		if len(smt.db.Store.Get(node[:])) != 0 {
619			t.Fatal("nodes not deleted from database", node)
620		}
621	}
622	for node := range updatedNodes1 {
623		if len(smt.db.Store.Get(node[:])) != 0 {
624			t.Fatal("nodes not deleted from database", node)
625		}
626	}
627	st.Close()
628	os.RemoveAll(".aergo")
629}
630
631func TestTrieRaisesError(t *testing.T) {
632	dbPath := path.Join(".aergo", "db")
633	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
634		_ = os.MkdirAll(dbPath, 0711)
635	}
636	st := db.NewDB(db.LevelImpl, dbPath)
637
638	smt := NewTrie(nil, Hasher, st)
639	// Add data to empty trie
640	keys := getFreshData(10, 32)
641	values := getFreshData(10, 32)
642	if _, err := smt.Update(keys, values); err != nil {
643		t.Fatal(err)
644	}
645	smt.db.liveCache = make(map[Hash][][]byte)
646	smt.db.updatedNodes = make(map[Hash][][]byte)
647
648	// Check errors are raised is a keys is not in cache nore db
649	for _, key := range keys {
650		_, err := smt.Get(key)
651		if err == nil {
652			t.Fatal("Error not created if database doesnt have a node")
653		}
654	}
655	_, _, _, _, _, _, err := smt.MerkleProofCompressed(keys[0])
656	if err == nil {
657		t.Fatal("Error not created if database doesnt have a node")
658	}
659	_, err = smt.Update(keys, values)
660	if err == nil {
661		t.Fatal("Error not created if database doesnt have a node")
662	}
663	st.Close()
664	os.RemoveAll(".aergo")
665
666	smt = NewTrie(nil, Hasher, nil)
667	err = smt.Commit()
668	if err == nil {
669		t.Fatal("Error not created if database not connected")
670	}
671	smt.db.liveCache = make(map[Hash][][]byte)
672	smt.atomicUpdate = false
673	_, _, _, _, _, err = smt.loadChildren(make([]byte, 32), smt.TrieHeight, 0, nil)
674	if err == nil {
675		t.Fatal("Error not created if database not connected")
676	}
677	err = smt.LoadCache(make([]byte, 32))
678	if err == nil {
679		t.Fatal("Error not created if database not connected")
680	}
681}
682
683func TestTrieLoadCache(t *testing.T) {
684	dbPath := path.Join(".aergo", "db")
685	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
686		_ = os.MkdirAll(dbPath, 0711)
687	}
688	st := db.NewDB(db.LevelImpl, dbPath)
689
690	smt := NewTrie(nil, Hasher, st)
691	// Test size of cache
692	smt.CacheHeightLimit = 0
693	key0 := make([]byte, 32)
694	key1 := make([]byte, 32)
695	bitSet(key1, 255)
696	values := getFreshData(2, 32)
697	if _, err := smt.Update([][]byte{key0, key1}, values); err != nil {
698		t.Fatal(err)
699	}
700	if len(smt.db.liveCache) != 66 {
701		// the nodes are at the tip, so 64 + 2 = 66
702		t.Fatal("cache size incorrect")
703	}
704
705	// Add data to empty trie
706	keys := getFreshData(10, 32)
707	values = getFreshData(10, 32)
708	if _, err := smt.Update(keys, values); err != nil {
709		t.Fatal(err)
710	}
711	if err := smt.Commit(); err != nil {
712		t.Fatal(err)
713	}
714
715	// Simulate node restart by deleting and loading cache
716	cacheSize := len(smt.db.liveCache)
717	smt.db.liveCache = make(map[Hash][][]byte)
718
719	err := smt.LoadCache(smt.Root)
720
721	if err != nil {
722		t.Fatal(err)
723	}
724	if cacheSize != len(smt.db.liveCache) {
725		t.Fatal("Cache loading from db incorrect")
726	}
727	st.Close()
728	os.RemoveAll(".aergo")
729}
730
731func TestHeight0LeafShortcut(t *testing.T) {
732	keySize := 32
733	smt := NewTrie(nil, Hasher, nil)
734	// Add 2 sibling keys that will be stored at height 0
735	key0 := make([]byte, keySize)
736	key1 := make([]byte, keySize)
737	bitSet(key1, keySize*8-1)
738	keys := [][]byte{key0, key1}
739	values := getFreshData(2, 32)
740	if _, err := smt.Update(keys, values); err != nil {
741		t.Fatal(err)
742	}
743	updatedNb := len(smt.db.updatedNodes)
744
745	// Check all keys have been stored
746	for i, key := range keys {
747		value, _ := smt.Get(key)
748		if !bytes.Equal(values[i], value) {
749			t.Fatal("trie not updated")
750		}
751	}
752	bitmap, ap, length, _, k, v, err := smt.MerkleProofCompressed(key1)
753	if err != nil {
754		t.Fatal(err)
755	}
756	if !bytes.Equal(key1, k) && !bytes.Equal(values[1], v) {
757		t.Fatalf("merkle proof didnt return the correct key-value pair")
758	}
759	if length != smt.TrieHeight {
760		t.Fatal("proof should have length equal to trie height for a leaf shortcut")
761	}
762	if !smt.VerifyInclusionC(bitmap, key1, values[1], ap, length) {
763		t.Fatal("failed to verify inclusion proof")
764	}
765
766	// Delete one key and check that the remaining one moved up to the root of the tree
767	newRoot, _ := smt.AtomicUpdate(keys[0:1], [][]byte{DefaultLeaf})
768
769	// Nb of updated nodes remains same because the new shortcut root was already stored at height 0.
770	if len(smt.db.updatedNodes) != updatedNb {
771		fmt.Println(len(smt.db.updatedNodes), updatedNb)
772		t.Fatal("number of cache nodes not correct after delete")
773	}
774	smt.atomicUpdate = false
775	_, _, k, v, isShortcut, err := smt.loadChildren(newRoot, smt.TrieHeight, 0, nil)
776	if err != nil {
777		t.Fatal(err)
778	}
779	if !isShortcut || !bytes.Equal(k[:HashLength], key1) || !bytes.Equal(v[:HashLength], values[1]) {
780		t.Fatal("leaf shortcut didn't move up to root")
781	}
782
783	_, _, length, _, k, v, _ = smt.MerkleProofCompressed(key1)
784	if length != 0 {
785		t.Fatal("proof should have length equal to trie height for a leaf shortcut")
786	}
787	if !bytes.Equal(key1, k) && !bytes.Equal(values[1], v) {
788		t.Fatalf("merkle proof didnt return the correct key-value pair")
789	}
790}
791
792func TestStash(t *testing.T) {
793	dbPath := path.Join(".aergo", "db")
794	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
795		_ = os.MkdirAll(dbPath, 0711)
796	}
797	st := db.NewDB(db.LevelImpl, dbPath)
798	smt := NewTrie(nil, Hasher, st)
799	// Add data to empty trie
800	keys := getFreshData(20, 32)
801	values := getFreshData(20, 32)
802	root, _ := smt.Update(keys, values)
803	cacheSize := len(smt.db.liveCache)
804	if err := smt.Commit(); err != nil {
805		t.Fatal(err)
806	}
807	if len(smt.pastTries) != 1 {
808		t.Fatal("Past tries not updated after commit")
809	}
810	values = getFreshData(20, 32)
811	if _, err := smt.Update(keys, values); err != nil {
812		t.Fatal(err)
813	}
814	if err := smt.Stash(true); err != nil {
815		t.Fatal(err)
816	}
817	if len(smt.pastTries) != 1 {
818		t.Fatal("Past tries not updated after commit")
819	}
820	if !bytes.Equal(smt.Root, root) {
821		t.Fatal("Trie not rolled back")
822	}
823	if len(smt.db.updatedNodes) != 0 {
824		t.Fatal("Trie not rolled back")
825	}
826	if len(smt.db.liveCache) != cacheSize {
827		t.Fatal("Trie not rolled back")
828	}
829	keys = getFreshData(20, 32)
830	values = getFreshData(20, 32)
831	if _, err := smt.AtomicUpdate(keys, values); err != nil {
832		t.Fatal(err)
833	}
834	values = getFreshData(20, 32)
835	if _, err := smt.AtomicUpdate(keys, values); err != nil {
836		t.Fatal(err)
837	}
838	if len(smt.pastTries) != 3 {
839		t.Fatal("Past tries not updated after commit")
840	}
841	if err := smt.Stash(true); err != nil {
842		t.Fatal(err)
843	}
844	if !bytes.Equal(smt.Root, root) {
845		t.Fatal("Trie not rolled back")
846	}
847	if len(smt.db.updatedNodes) != 0 {
848		t.Fatal("Trie not rolled back")
849	}
850	if len(smt.db.liveCache) != cacheSize {
851		t.Fatal("Trie not rolled back")
852	}
853	if len(smt.pastTries) != 1 {
854		t.Fatal("Past tries not updated after commit")
855	}
856	st.Close()
857	os.RemoveAll(".aergo")
858}
859
860func benchmark10MAccounts10Ktps(smt *Trie, b *testing.B) {
861	//b.ReportAllocs()
862	keys := getFreshData(100, 32)
863	values := getFreshData(100, 32)
864	if _, err := smt.Update(keys, values); err != nil {
865		b.Fatal(err)
866	}
867	fmt.Println("\nLoading b.N x 1000 accounts")
868	for i := 0; i < b.N; i++ {
869		newkeys := getFreshData(1000, 32)
870		newvalues := getFreshData(1000, 32)
871		start := time.Now()
872		if _, err := smt.Update(newkeys, newvalues); err != nil {
873			b.Fatal(err)
874		}
875		end := time.Now()
876		if err := smt.Commit(); err != nil {
877			b.Fatal(err)
878		}
879		end2 := time.Now()
880		for j, key := range newkeys {
881			val, _ := smt.Get(key)
882			if !bytes.Equal(val, newvalues[j]) {
883				b.Fatal("new key not included")
884			}
885		}
886		end3 := time.Now()
887		elapsed := end.Sub(start)
888		elapsed2 := end2.Sub(end)
889		elapsed3 := end3.Sub(end2)
890		var m runtime.MemStats
891		runtime.ReadMemStats(&m)
892		fmt.Println(i, " : update time : ", elapsed, "commit time : ", elapsed2,
893			"\n1000 Get time : ", elapsed3,
894			"\ndb read : ", smt.LoadDbCounter, "    cache read : ", smt.LoadCacheCounter,
895			"\ncache size : ", len(smt.db.liveCache),
896			"\nRAM : ", m.Sys/1024/1024, " MiB")
897	}
898}
899
900//go test -run=xxx -bench=. -benchmem -test.benchtime=20s
901func BenchmarkCacheHeightLimit233(b *testing.B) {
902	dbPath := path.Join(".aergo", "db")
903	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
904		_ = os.MkdirAll(dbPath, 0711)
905	}
906	st := db.NewDB(db.LevelImpl, dbPath)
907	smt := NewTrie(nil, Hasher, st)
908	smt.CacheHeightLimit = 233
909	benchmark10MAccounts10Ktps(smt, b)
910	st.Close()
911	os.RemoveAll(".aergo")
912}
913func BenchmarkCacheHeightLimit238(b *testing.B) {
914	dbPath := path.Join(".aergo", "db")
915	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
916		_ = os.MkdirAll(dbPath, 0711)
917	}
918	st := db.NewDB(db.LevelImpl, dbPath)
919	smt := NewTrie(nil, Hasher, st)
920	smt.CacheHeightLimit = 238
921	benchmark10MAccounts10Ktps(smt, b)
922	st.Close()
923	os.RemoveAll(".aergo")
924}
925func BenchmarkCacheHeightLimit245(b *testing.B) {
926	dbPath := path.Join(".aergo", "db")
927	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
928		_ = os.MkdirAll(dbPath, 0711)
929	}
930	st := db.NewDB(db.LevelImpl, dbPath)
931	smt := NewTrie(nil, Hasher, st)
932	smt.CacheHeightLimit = 245
933	benchmark10MAccounts10Ktps(smt, b)
934	st.Close()
935	os.RemoveAll(".aergo")
936}
937
938func getFreshData(size, length int) [][]byte {
939	var data [][]byte
940	for i := 0; i < size; i++ {
941		key := make([]byte, 32)
942		_, err := rand.Read(key)
943		if err != nil {
944			panic(err)
945		}
946		data = append(data, Hasher(key)[:length])
947	}
948	sort.Sort(DataArray(data))
949	return data
950}