github.com/tacshi/go-ethereum@v0.0.0-20230616113857-84a434e20921/trie/util_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/tacshi/go-ethereum/common"
    24  	"github.com/tacshi/go-ethereum/core/rawdb"
    25  	"github.com/tacshi/go-ethereum/core/types"
    26  )
    27  
    28  // Tests if the trie diffs are tracked correctly.
    29  func TestTrieTracer(t *testing.T) {
    30  	db := NewDatabase(rawdb.NewMemoryDatabase())
    31  	trie := NewEmpty(db)
    32  	trie.tracer = newTracer()
    33  
    34  	// Insert a batch of entries, all the nodes should be marked as inserted
    35  	vals := []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  	for _, val := range vals {
    45  		trie.Update([]byte(val.k), []byte(val.v))
    46  	}
    47  	trie.Hash()
    48  
    49  	seen := make(map[string]struct{})
    50  	it := trie.NodeIterator(nil)
    51  	for it.Next(true) {
    52  		if it.Leaf() {
    53  			continue
    54  		}
    55  		seen[string(it.Path())] = struct{}{}
    56  	}
    57  	inserted := trie.tracer.insertList()
    58  	if len(inserted) != len(seen) {
    59  		t.Fatalf("Unexpected inserted node tracked want %d got %d", len(seen), len(inserted))
    60  	}
    61  	for _, k := range inserted {
    62  		_, ok := seen[string(k)]
    63  		if !ok {
    64  			t.Fatalf("Unexpected inserted node")
    65  		}
    66  	}
    67  	deleted := trie.tracer.deleteList()
    68  	if len(deleted) != 0 {
    69  		t.Fatalf("Unexpected deleted node tracked %d", len(deleted))
    70  	}
    71  
    72  	// Commit the changes and re-create with new root
    73  	root, nodes := trie.Commit(false)
    74  	if err := db.Update(NewWithNodeSet(nodes)); err != nil {
    75  		t.Fatal(err)
    76  	}
    77  	trie, _ = New(TrieID(root), db)
    78  	trie.tracer = newTracer()
    79  
    80  	// Delete all the elements, check deletion set
    81  	for _, val := range vals {
    82  		trie.Delete([]byte(val.k))
    83  	}
    84  	trie.Hash()
    85  
    86  	inserted = trie.tracer.insertList()
    87  	if len(inserted) != 0 {
    88  		t.Fatalf("Unexpected inserted node tracked %d", len(inserted))
    89  	}
    90  	deleted = trie.tracer.deleteList()
    91  	if len(deleted) != len(seen) {
    92  		t.Fatalf("Unexpected deleted node tracked want %d got %d", len(seen), len(deleted))
    93  	}
    94  	for _, k := range deleted {
    95  		_, ok := seen[string(k)]
    96  		if !ok {
    97  			t.Fatalf("Unexpected inserted node")
    98  		}
    99  	}
   100  }
   101  
   102  func TestTrieTracerNoop(t *testing.T) {
   103  	trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase()))
   104  	trie.tracer = newTracer()
   105  
   106  	// Insert a batch of entries, all the nodes should be marked as inserted
   107  	vals := []struct{ k, v string }{
   108  		{"do", "verb"},
   109  		{"ether", "wookiedoo"},
   110  		{"horse", "stallion"},
   111  		{"shaman", "horse"},
   112  		{"doge", "coin"},
   113  		{"dog", "puppy"},
   114  		{"somethingveryoddindeedthis is", "myothernodedata"},
   115  	}
   116  	for _, val := range vals {
   117  		trie.Update([]byte(val.k), []byte(val.v))
   118  	}
   119  	for _, val := range vals {
   120  		trie.Delete([]byte(val.k))
   121  	}
   122  	if len(trie.tracer.insertList()) != 0 {
   123  		t.Fatalf("Unexpected inserted node tracked %d", len(trie.tracer.insertList()))
   124  	}
   125  	if len(trie.tracer.deleteList()) != 0 {
   126  		t.Fatalf("Unexpected deleted node tracked %d", len(trie.tracer.deleteList()))
   127  	}
   128  }
   129  
   130  func TestTrieTracePrevValue(t *testing.T) {
   131  	db := NewDatabase(rawdb.NewMemoryDatabase())
   132  	trie := NewEmpty(db)
   133  	trie.tracer = newTracer()
   134  
   135  	paths, blobs := trie.tracer.prevList()
   136  	if len(paths) != 0 || len(blobs) != 0 {
   137  		t.Fatalf("Nothing should be tracked")
   138  	}
   139  	// Insert a batch of entries, all the nodes should be marked as inserted
   140  	vals := []struct{ k, v string }{
   141  		{"do", "verb"},
   142  		{"ether", "wookiedoo"},
   143  		{"horse", "stallion"},
   144  		{"shaman", "horse"},
   145  		{"doge", "coin"},
   146  		{"dog", "puppy"},
   147  		{"somethingveryoddindeedthis is", "myothernodedata"},
   148  	}
   149  	for _, val := range vals {
   150  		trie.Update([]byte(val.k), []byte(val.v))
   151  	}
   152  	paths, blobs = trie.tracer.prevList()
   153  	if len(paths) != 0 || len(blobs) != 0 {
   154  		t.Fatalf("Nothing should be tracked")
   155  	}
   156  
   157  	// Commit the changes and re-create with new root
   158  	root, nodes := trie.Commit(false)
   159  	if err := db.Update(NewWithNodeSet(nodes)); err != nil {
   160  		t.Fatal(err)
   161  	}
   162  	trie, _ = New(TrieID(root), db)
   163  	trie.tracer = newTracer()
   164  	trie.resolveAndTrack(root.Bytes(), nil)
   165  
   166  	// Load all nodes in trie
   167  	for _, val := range vals {
   168  		trie.TryGet([]byte(val.k))
   169  	}
   170  
   171  	// Ensure all nodes are tracked by tracer with correct prev-values
   172  	iter := trie.NodeIterator(nil)
   173  	seen := make(map[string][]byte)
   174  	for iter.Next(true) {
   175  		// Embedded nodes are ignored since they are not present in
   176  		// database.
   177  		if iter.Hash() == (common.Hash{}) {
   178  			continue
   179  		}
   180  		seen[string(iter.Path())] = common.CopyBytes(iter.NodeBlob())
   181  	}
   182  
   183  	paths, blobs = trie.tracer.prevList()
   184  	if len(paths) != len(seen) || len(blobs) != len(seen) {
   185  		t.Fatalf("Unexpected tracked values")
   186  	}
   187  	for i, path := range paths {
   188  		blob := blobs[i]
   189  		prev, ok := seen[string(path)]
   190  		if !ok {
   191  			t.Fatalf("Missing node %v", path)
   192  		}
   193  		if !bytes.Equal(blob, prev) {
   194  			t.Fatalf("Unexpected value path: %v, want: %v, got: %v", path, prev, blob)
   195  		}
   196  	}
   197  
   198  	// Re-open the trie and iterate the trie, ensure nothing will be tracked.
   199  	// Iterator will not link any loaded nodes to trie.
   200  	trie, _ = New(TrieID(root), db)
   201  	trie.tracer = newTracer()
   202  
   203  	iter = trie.NodeIterator(nil)
   204  	for iter.Next(true) {
   205  	}
   206  	paths, blobs = trie.tracer.prevList()
   207  	if len(paths) != 0 || len(blobs) != 0 {
   208  		t.Fatalf("Nothing should be tracked")
   209  	}
   210  
   211  	// Re-open the trie and generate proof for entries, ensure nothing will
   212  	// be tracked. Prover will not link any loaded nodes to trie.
   213  	trie, _ = New(TrieID(root), db)
   214  	trie.tracer = newTracer()
   215  	for _, val := range vals {
   216  		trie.Prove([]byte(val.k), 0, rawdb.NewMemoryDatabase())
   217  	}
   218  	paths, blobs = trie.tracer.prevList()
   219  	if len(paths) != 0 || len(blobs) != 0 {
   220  		t.Fatalf("Nothing should be tracked")
   221  	}
   222  
   223  	// Delete entries from trie, ensure all previous values are correct.
   224  	trie, _ = New(TrieID(root), db)
   225  	trie.tracer = newTracer()
   226  	trie.resolveAndTrack(root.Bytes(), nil)
   227  
   228  	for _, val := range vals {
   229  		trie.TryDelete([]byte(val.k))
   230  	}
   231  	paths, blobs = trie.tracer.prevList()
   232  	if len(paths) != len(seen) || len(blobs) != len(seen) {
   233  		t.Fatalf("Unexpected tracked values")
   234  	}
   235  	for i, path := range paths {
   236  		blob := blobs[i]
   237  		prev, ok := seen[string(path)]
   238  		if !ok {
   239  			t.Fatalf("Missing node %v", path)
   240  		}
   241  		if !bytes.Equal(blob, prev) {
   242  			t.Fatalf("Unexpected value path: %v, want: %v, got: %v", path, prev, blob)
   243  		}
   244  	}
   245  }
   246  
   247  func TestDeleteAll(t *testing.T) {
   248  	db := NewDatabase(rawdb.NewMemoryDatabase())
   249  	trie := NewEmpty(db)
   250  	trie.tracer = newTracer()
   251  
   252  	// Insert a batch of entries, all the nodes should be marked as inserted
   253  	vals := []struct{ k, v string }{
   254  		{"do", "verb"},
   255  		{"ether", "wookiedoo"},
   256  		{"horse", "stallion"},
   257  		{"shaman", "horse"},
   258  		{"doge", "coin"},
   259  		{"dog", "puppy"},
   260  		{"somethingveryoddindeedthis is", "myothernodedata"},
   261  	}
   262  	for _, val := range vals {
   263  		trie.Update([]byte(val.k), []byte(val.v))
   264  	}
   265  	root, set := trie.Commit(false)
   266  	if err := db.Update(NewWithNodeSet(set)); err != nil {
   267  		t.Fatal(err)
   268  	}
   269  	// Delete entries from trie, ensure all values are detected
   270  	trie, _ = New(TrieID(root), db)
   271  	trie.tracer = newTracer()
   272  	trie.resolveAndTrack(root.Bytes(), nil)
   273  
   274  	// Iterate all existent nodes
   275  	var (
   276  		it    = trie.NodeIterator(nil)
   277  		nodes = make(map[string][]byte)
   278  	)
   279  	for it.Next(true) {
   280  		if it.Hash() != (common.Hash{}) {
   281  			nodes[string(it.Path())] = common.CopyBytes(it.NodeBlob())
   282  		}
   283  	}
   284  
   285  	// Perform deletion to purge the entire trie
   286  	for _, val := range vals {
   287  		trie.Delete([]byte(val.k))
   288  	}
   289  	root, set = trie.Commit(false)
   290  	if root != types.EmptyRootHash {
   291  		t.Fatalf("Invalid trie root %v", root)
   292  	}
   293  	for path, blob := range set.deletes {
   294  		prev, ok := nodes[path]
   295  		if !ok {
   296  			t.Fatalf("Extra node deleted %v", []byte(path))
   297  		}
   298  		if !bytes.Equal(prev, blob) {
   299  			t.Fatalf("Unexpected previous value %v", []byte(path))
   300  		}
   301  	}
   302  	if len(set.deletes) != len(nodes) {
   303  		t.Fatalf("Unexpected deletion set")
   304  	}
   305  }