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 }