github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/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/ethereum/go-ethereum/common" 24 "github.com/ethereum/go-ethereum/core/rawdb" 25 "github.com/ethereum/go-ethereum/core/types" 26 "github.com/ethereum/go-ethereum/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 := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) 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, trienode.NewWithNodeSet(nodes)) 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 db := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) 108 trie := NewEmpty(db) 109 for _, val := range vals { 110 trie.MustUpdate([]byte(val.k), []byte(val.v)) 111 } 112 for _, val := range vals { 113 trie.MustDelete([]byte(val.k)) 114 } 115 if len(trie.tracer.inserts) != 0 { 116 t.Fatal("Unexpected insertion set") 117 } 118 if len(trie.tracer.deletes) != 0 { 119 t.Fatal("Unexpected deletion set") 120 } 121 } 122 123 // Tests if the accessList is correctly tracked. 124 func TestAccessList(t *testing.T) { 125 testAccessList(t, tiny) 126 testAccessList(t, nonAligned) 127 testAccessList(t, standard) 128 } 129 130 func testAccessList(t *testing.T, vals []struct{ k, v string }) { 131 var ( 132 db = newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) 133 trie = NewEmpty(db) 134 orig = trie.Copy() 135 ) 136 // Create trie from scratch 137 for _, val := range vals { 138 trie.MustUpdate([]byte(val.k), []byte(val.v)) 139 } 140 root, nodes, _ := trie.Commit(false) 141 db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) 142 143 trie, _ = New(TrieID(root), db) 144 if err := verifyAccessList(orig, trie, nodes); err != nil { 145 t.Fatalf("Invalid accessList %v", err) 146 } 147 148 // Update trie 149 parent := root 150 trie, _ = New(TrieID(root), db) 151 orig = trie.Copy() 152 for _, val := range vals { 153 trie.MustUpdate([]byte(val.k), randBytes(32)) 154 } 155 root, nodes, _ = trie.Commit(false) 156 db.Update(root, parent, trienode.NewWithNodeSet(nodes)) 157 158 trie, _ = New(TrieID(root), db) 159 if err := verifyAccessList(orig, trie, nodes); err != nil { 160 t.Fatalf("Invalid accessList %v", err) 161 } 162 163 // Add more new nodes 164 parent = root 165 trie, _ = New(TrieID(root), db) 166 orig = trie.Copy() 167 var keys []string 168 for i := 0; i < 30; i++ { 169 key := randBytes(32) 170 keys = append(keys, string(key)) 171 trie.MustUpdate(key, randBytes(32)) 172 } 173 root, nodes, _ = trie.Commit(false) 174 db.Update(root, parent, trienode.NewWithNodeSet(nodes)) 175 176 trie, _ = New(TrieID(root), db) 177 if err := verifyAccessList(orig, trie, nodes); err != nil { 178 t.Fatalf("Invalid accessList %v", err) 179 } 180 181 // Partial deletions 182 parent = root 183 trie, _ = New(TrieID(root), db) 184 orig = trie.Copy() 185 for _, key := range keys { 186 trie.MustUpdate([]byte(key), nil) 187 } 188 root, nodes, _ = trie.Commit(false) 189 db.Update(root, parent, trienode.NewWithNodeSet(nodes)) 190 191 trie, _ = New(TrieID(root), db) 192 if err := verifyAccessList(orig, trie, nodes); err != nil { 193 t.Fatalf("Invalid accessList %v", err) 194 } 195 196 // Delete all 197 parent = root 198 trie, _ = New(TrieID(root), db) 199 orig = trie.Copy() 200 for _, val := range vals { 201 trie.MustUpdate([]byte(val.k), nil) 202 } 203 root, nodes, _ = trie.Commit(false) 204 db.Update(root, parent, trienode.NewWithNodeSet(nodes)) 205 206 trie, _ = New(TrieID(root), db) 207 if err := verifyAccessList(orig, trie, nodes); err != nil { 208 t.Fatalf("Invalid accessList %v", err) 209 } 210 } 211 212 // Tests origin values won't be tracked in Iterator or Prover 213 func TestAccessListLeak(t *testing.T) { 214 var ( 215 db = newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) 216 trie = NewEmpty(db) 217 ) 218 // Create trie from scratch 219 for _, val := range standard { 220 trie.MustUpdate([]byte(val.k), []byte(val.v)) 221 } 222 root, nodes, _ := trie.Commit(false) 223 db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) 224 225 var cases = []struct { 226 op func(tr *Trie) 227 }{ 228 { 229 func(tr *Trie) { 230 it := tr.MustNodeIterator(nil) 231 for it.Next(true) { 232 } 233 }, 234 }, 235 { 236 func(tr *Trie) { 237 it := NewIterator(tr.MustNodeIterator(nil)) 238 for it.Next() { 239 } 240 }, 241 }, 242 { 243 func(tr *Trie) { 244 for _, val := range standard { 245 tr.Prove([]byte(val.k), rawdb.NewMemoryDatabase()) 246 } 247 }, 248 }, 249 } 250 for _, c := range cases { 251 trie, _ = New(TrieID(root), db) 252 n1 := len(trie.tracer.accessList) 253 c.op(trie) 254 n2 := len(trie.tracer.accessList) 255 256 if n1 != n2 { 257 t.Fatalf("AccessList is leaked, prev %d after %d", n1, n2) 258 } 259 } 260 } 261 262 // Tests whether the original tree node is correctly deleted after being embedded 263 // in its parent due to the smaller size of the original tree node. 264 func TestTinyTree(t *testing.T) { 265 var ( 266 db = newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) 267 trie = NewEmpty(db) 268 ) 269 for _, val := range tiny { 270 trie.MustUpdate([]byte(val.k), randBytes(32)) 271 } 272 root, set, _ := trie.Commit(false) 273 db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(set)) 274 275 parent := root 276 trie, _ = New(TrieID(root), db) 277 orig := trie.Copy() 278 for _, val := range tiny { 279 trie.MustUpdate([]byte(val.k), []byte(val.v)) 280 } 281 root, set, _ = trie.Commit(false) 282 db.Update(root, parent, trienode.NewWithNodeSet(set)) 283 284 trie, _ = New(TrieID(root), db) 285 if err := verifyAccessList(orig, trie, set); err != nil { 286 t.Fatalf("Invalid accessList %v", err) 287 } 288 } 289 290 func compareSet(setA, setB map[string]struct{}) bool { 291 if len(setA) != len(setB) { 292 return false 293 } 294 for key := range setA { 295 if _, ok := setB[key]; !ok { 296 return false 297 } 298 } 299 return true 300 } 301 302 func forNodes(tr *Trie) map[string][]byte { 303 var ( 304 it = tr.MustNodeIterator(nil) 305 nodes = make(map[string][]byte) 306 ) 307 for it.Next(true) { 308 if it.Leaf() { 309 continue 310 } 311 nodes[string(it.Path())] = common.CopyBytes(it.NodeBlob()) 312 } 313 return nodes 314 } 315 316 func iterNodes(db *testDb, root common.Hash) map[string][]byte { 317 tr, _ := New(TrieID(root), db) 318 return forNodes(tr) 319 } 320 321 func forHashedNodes(tr *Trie) map[string][]byte { 322 var ( 323 it = tr.MustNodeIterator(nil) 324 nodes = make(map[string][]byte) 325 ) 326 for it.Next(true) { 327 if it.Hash() == (common.Hash{}) { 328 continue 329 } 330 nodes[string(it.Path())] = common.CopyBytes(it.NodeBlob()) 331 } 332 return nodes 333 } 334 335 func diffTries(trieA, trieB *Trie) (map[string][]byte, map[string][]byte, map[string][]byte) { 336 var ( 337 nodesA = forHashedNodes(trieA) 338 nodesB = forHashedNodes(trieB) 339 inA = make(map[string][]byte) // hashed nodes in trie a but not b 340 inB = make(map[string][]byte) // hashed nodes in trie b but not a 341 both = make(map[string][]byte) // hashed nodes in both tries but different value 342 ) 343 for path, blobA := range nodesA { 344 if blobB, ok := nodesB[path]; ok { 345 if bytes.Equal(blobA, blobB) { 346 continue 347 } 348 both[path] = blobA 349 continue 350 } 351 inA[path] = blobA 352 } 353 for path, blobB := range nodesB { 354 if _, ok := nodesA[path]; ok { 355 continue 356 } 357 inB[path] = blobB 358 } 359 return inA, inB, both 360 } 361 362 func setKeys(set map[string][]byte) map[string]struct{} { 363 keys := make(map[string]struct{}) 364 for k := range set { 365 keys[k] = struct{}{} 366 } 367 return keys 368 } 369 370 func copySet(set map[string]struct{}) map[string]struct{} { 371 copied := make(map[string]struct{}) 372 for k := range set { 373 copied[k] = struct{}{} 374 } 375 return copied 376 }