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