github.com/theQRL/go-zond@v0.1.1/trie/tracer_test.go (about)

     1  // Copyright 2022 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  	"testing"
    22  
    23  	"github.com/theQRL/go-zond/common"
    24  	"github.com/theQRL/go-zond/core/rawdb"
    25  	"github.com/theQRL/go-zond/core/types"
    26  	"github.com/theQRL/go-zond/trie/trienode"
    27  )
    28  
    29  var (
    30  	tiny = []struct{ k, v string }{
    31  		{"k1", "v1"},
    32  		{"k2", "v2"},
    33  		{"k3", "v3"},
    34  	}
    35  	nonAligned = []struct{ k, v string }{
    36  		{"do", "verb"},
    37  		{"ether", "wookiedoo"},
    38  		{"horse", "stallion"},
    39  		{"shaman", "horse"},
    40  		{"doge", "coin"},
    41  		{"dog", "puppy"},
    42  		{"somethingveryoddindeedthis is", "myothernodedata"},
    43  	}
    44  	standard = []struct{ k, v string }{
    45  		{string(randBytes(32)), "verb"},
    46  		{string(randBytes(32)), "wookiedoo"},
    47  		{string(randBytes(32)), "stallion"},
    48  		{string(randBytes(32)), "horse"},
    49  		{string(randBytes(32)), "coin"},
    50  		{string(randBytes(32)), "puppy"},
    51  		{string(randBytes(32)), "myothernodedata"},
    52  	}
    53  )
    54  
    55  func TestTrieTracer(t *testing.T) {
    56  	testTrieTracer(t, tiny)
    57  	testTrieTracer(t, nonAligned)
    58  	testTrieTracer(t, standard)
    59  }
    60  
    61  // Tests if the trie diffs are tracked correctly. Tracer should capture
    62  // all non-leaf dirty nodes, no matter the node is embedded or not.
    63  func testTrieTracer(t *testing.T, vals []struct{ k, v string }) {
    64  	db := NewDatabase(rawdb.NewMemoryDatabase(), nil)
    65  	trie := NewEmpty(db)
    66  
    67  	// Determine all new nodes are tracked
    68  	for _, val := range vals {
    69  		trie.MustUpdate([]byte(val.k), []byte(val.v))
    70  	}
    71  	insertSet := copySet(trie.tracer.inserts) // copy before commit
    72  	deleteSet := copySet(trie.tracer.deletes) // copy before commit
    73  	root, nodes, _ := trie.Commit(false)
    74  	db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
    75  
    76  	seen := setKeys(iterNodes(db, root))
    77  	if !compareSet(insertSet, seen) {
    78  		t.Fatal("Unexpected insertion set")
    79  	}
    80  	if !compareSet(deleteSet, nil) {
    81  		t.Fatal("Unexpected deletion set")
    82  	}
    83  
    84  	// Determine all deletions are tracked
    85  	trie, _ = New(TrieID(root), db)
    86  	for _, val := range vals {
    87  		trie.MustDelete([]byte(val.k))
    88  	}
    89  	insertSet, deleteSet = copySet(trie.tracer.inserts), copySet(trie.tracer.deletes)
    90  	if !compareSet(insertSet, nil) {
    91  		t.Fatal("Unexpected insertion set")
    92  	}
    93  	if !compareSet(deleteSet, seen) {
    94  		t.Fatal("Unexpected deletion set")
    95  	}
    96  }
    97  
    98  // Test that after inserting a new batch of nodes and deleting them immediately,
    99  // the trie tracer should be cleared normally as no operation happened.
   100  func TestTrieTracerNoop(t *testing.T) {
   101  	testTrieTracerNoop(t, tiny)
   102  	testTrieTracerNoop(t, nonAligned)
   103  	testTrieTracerNoop(t, standard)
   104  }
   105  
   106  func testTrieTracerNoop(t *testing.T, vals []struct{ k, v string }) {
   107  	trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil))
   108  	for _, val := range vals {
   109  		trie.MustUpdate([]byte(val.k), []byte(val.v))
   110  	}
   111  	for _, val := range vals {
   112  		trie.MustDelete([]byte(val.k))
   113  	}
   114  	if len(trie.tracer.inserts) != 0 {
   115  		t.Fatal("Unexpected insertion set")
   116  	}
   117  	if len(trie.tracer.deletes) != 0 {
   118  		t.Fatal("Unexpected deletion set")
   119  	}
   120  }
   121  
   122  // Tests if the accessList is correctly tracked.
   123  func TestAccessList(t *testing.T) {
   124  	testAccessList(t, tiny)
   125  	testAccessList(t, nonAligned)
   126  	testAccessList(t, standard)
   127  }
   128  
   129  func testAccessList(t *testing.T, vals []struct{ k, v string }) {
   130  	var (
   131  		db   = NewDatabase(rawdb.NewMemoryDatabase(), nil)
   132  		trie = NewEmpty(db)
   133  		orig = trie.Copy()
   134  	)
   135  	// Create trie from scratch
   136  	for _, val := range vals {
   137  		trie.MustUpdate([]byte(val.k), []byte(val.v))
   138  	}
   139  	root, nodes, _ := trie.Commit(false)
   140  	db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
   141  
   142  	trie, _ = New(TrieID(root), db)
   143  	if err := verifyAccessList(orig, trie, nodes); err != nil {
   144  		t.Fatalf("Invalid accessList %v", err)
   145  	}
   146  
   147  	// Update trie
   148  	parent := root
   149  	trie, _ = New(TrieID(root), db)
   150  	orig = trie.Copy()
   151  	for _, val := range vals {
   152  		trie.MustUpdate([]byte(val.k), randBytes(32))
   153  	}
   154  	root, nodes, _ = trie.Commit(false)
   155  	db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil)
   156  
   157  	trie, _ = New(TrieID(root), db)
   158  	if err := verifyAccessList(orig, trie, nodes); err != nil {
   159  		t.Fatalf("Invalid accessList %v", err)
   160  	}
   161  
   162  	// Add more new nodes
   163  	parent = root
   164  	trie, _ = New(TrieID(root), db)
   165  	orig = trie.Copy()
   166  	var keys []string
   167  	for i := 0; i < 30; i++ {
   168  		key := randBytes(32)
   169  		keys = append(keys, string(key))
   170  		trie.MustUpdate(key, randBytes(32))
   171  	}
   172  	root, nodes, _ = trie.Commit(false)
   173  	db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil)
   174  
   175  	trie, _ = New(TrieID(root), db)
   176  	if err := verifyAccessList(orig, trie, nodes); err != nil {
   177  		t.Fatalf("Invalid accessList %v", err)
   178  	}
   179  
   180  	// Partial deletions
   181  	parent = root
   182  	trie, _ = New(TrieID(root), db)
   183  	orig = trie.Copy()
   184  	for _, key := range keys {
   185  		trie.MustUpdate([]byte(key), nil)
   186  	}
   187  	root, nodes, _ = trie.Commit(false)
   188  	db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil)
   189  
   190  	trie, _ = New(TrieID(root), db)
   191  	if err := verifyAccessList(orig, trie, nodes); err != nil {
   192  		t.Fatalf("Invalid accessList %v", err)
   193  	}
   194  
   195  	// Delete all
   196  	parent = root
   197  	trie, _ = New(TrieID(root), db)
   198  	orig = trie.Copy()
   199  	for _, val := range vals {
   200  		trie.MustUpdate([]byte(val.k), nil)
   201  	}
   202  	root, nodes, _ = trie.Commit(false)
   203  	db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil)
   204  
   205  	trie, _ = New(TrieID(root), db)
   206  	if err := verifyAccessList(orig, trie, nodes); err != nil {
   207  		t.Fatalf("Invalid accessList %v", err)
   208  	}
   209  }
   210  
   211  // Tests origin values won't be tracked in Iterator or Prover
   212  func TestAccessListLeak(t *testing.T) {
   213  	var (
   214  		db   = NewDatabase(rawdb.NewMemoryDatabase(), nil)
   215  		trie = NewEmpty(db)
   216  	)
   217  	// Create trie from scratch
   218  	for _, val := range standard {
   219  		trie.MustUpdate([]byte(val.k), []byte(val.v))
   220  	}
   221  	root, nodes, _ := trie.Commit(false)
   222  	db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
   223  
   224  	var cases = []struct {
   225  		op func(tr *Trie)
   226  	}{
   227  		{
   228  			func(tr *Trie) {
   229  				it := tr.MustNodeIterator(nil)
   230  				for it.Next(true) {
   231  				}
   232  			},
   233  		},
   234  		{
   235  			func(tr *Trie) {
   236  				it := NewIterator(tr.MustNodeIterator(nil))
   237  				for it.Next() {
   238  				}
   239  			},
   240  		},
   241  		{
   242  			func(tr *Trie) {
   243  				for _, val := range standard {
   244  					tr.Prove([]byte(val.k), rawdb.NewMemoryDatabase())
   245  				}
   246  			},
   247  		},
   248  	}
   249  	for _, c := range cases {
   250  		trie, _ = New(TrieID(root), db)
   251  		n1 := len(trie.tracer.accessList)
   252  		c.op(trie)
   253  		n2 := len(trie.tracer.accessList)
   254  
   255  		if n1 != n2 {
   256  			t.Fatalf("AccessList is leaked, prev %d after %d", n1, n2)
   257  		}
   258  	}
   259  }
   260  
   261  // Tests whether the original tree node is correctly deleted after being embedded
   262  // in its parent due to the smaller size of the original tree node.
   263  func TestTinyTree(t *testing.T) {
   264  	var (
   265  		db   = NewDatabase(rawdb.NewMemoryDatabase(), nil)
   266  		trie = NewEmpty(db)
   267  	)
   268  	for _, val := range tiny {
   269  		trie.MustUpdate([]byte(val.k), randBytes(32))
   270  	}
   271  	root, set, _ := trie.Commit(false)
   272  	db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(set), nil)
   273  
   274  	parent := root
   275  	trie, _ = New(TrieID(root), db)
   276  	orig := trie.Copy()
   277  	for _, val := range tiny {
   278  		trie.MustUpdate([]byte(val.k), []byte(val.v))
   279  	}
   280  	root, set, _ = trie.Commit(false)
   281  	db.Update(root, parent, 0, trienode.NewWithNodeSet(set), nil)
   282  
   283  	trie, _ = New(TrieID(root), db)
   284  	if err := verifyAccessList(orig, trie, set); err != nil {
   285  		t.Fatalf("Invalid accessList %v", err)
   286  	}
   287  }
   288  
   289  func compareSet(setA, setB map[string]struct{}) bool {
   290  	if len(setA) != len(setB) {
   291  		return false
   292  	}
   293  	for key := range setA {
   294  		if _, ok := setB[key]; !ok {
   295  			return false
   296  		}
   297  	}
   298  	return true
   299  }
   300  
   301  func forNodes(tr *Trie) map[string][]byte {
   302  	var (
   303  		it    = tr.MustNodeIterator(nil)
   304  		nodes = make(map[string][]byte)
   305  	)
   306  	for it.Next(true) {
   307  		if it.Leaf() {
   308  			continue
   309  		}
   310  		nodes[string(it.Path())] = common.CopyBytes(it.NodeBlob())
   311  	}
   312  	return nodes
   313  }
   314  
   315  func iterNodes(db *Database, root common.Hash) map[string][]byte {
   316  	tr, _ := New(TrieID(root), db)
   317  	return forNodes(tr)
   318  }
   319  
   320  func forHashedNodes(tr *Trie) map[string][]byte {
   321  	var (
   322  		it    = tr.MustNodeIterator(nil)
   323  		nodes = make(map[string][]byte)
   324  	)
   325  	for it.Next(true) {
   326  		if it.Hash() == (common.Hash{}) {
   327  			continue
   328  		}
   329  		nodes[string(it.Path())] = common.CopyBytes(it.NodeBlob())
   330  	}
   331  	return nodes
   332  }
   333  
   334  func diffTries(trieA, trieB *Trie) (map[string][]byte, map[string][]byte, map[string][]byte) {
   335  	var (
   336  		nodesA = forHashedNodes(trieA)
   337  		nodesB = forHashedNodes(trieB)
   338  		inA    = make(map[string][]byte) // hashed nodes in trie a but not b
   339  		inB    = make(map[string][]byte) // hashed nodes in trie b but not a
   340  		both   = make(map[string][]byte) // hashed nodes in both tries but different value
   341  	)
   342  	for path, blobA := range nodesA {
   343  		if blobB, ok := nodesB[path]; ok {
   344  			if bytes.Equal(blobA, blobB) {
   345  				continue
   346  			}
   347  			both[path] = blobA
   348  			continue
   349  		}
   350  		inA[path] = blobA
   351  	}
   352  	for path, blobB := range nodesB {
   353  		if _, ok := nodesA[path]; ok {
   354  			continue
   355  		}
   356  		inB[path] = blobB
   357  	}
   358  	return inA, inB, both
   359  }
   360  
   361  func setKeys(set map[string][]byte) map[string]struct{} {
   362  	keys := make(map[string]struct{})
   363  	for k := range set {
   364  		keys[k] = struct{}{}
   365  	}
   366  	return keys
   367  }
   368  
   369  func copySet(set map[string]struct{}) map[string]struct{} {
   370  	copied := make(map[string]struct{})
   371  	for k := range set {
   372  		copied[k] = struct{}{}
   373  	}
   374  	return copied
   375  }