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 }