github.com/MetalBlockchain/subnet-evm@v0.4.9/trie/iterator_test.go (about) 1 // (c) 2020-2021, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2014 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 package trie 28 29 import ( 30 "bytes" 31 "encoding/binary" 32 "fmt" 33 "math/rand" 34 "testing" 35 36 "github.com/MetalBlockchain/subnet-evm/core/rawdb" 37 "github.com/MetalBlockchain/subnet-evm/ethdb" 38 "github.com/MetalBlockchain/subnet-evm/ethdb/memorydb" 39 "github.com/ethereum/go-ethereum/common" 40 "github.com/ethereum/go-ethereum/crypto" 41 ) 42 43 func TestEmptyIterator(t *testing.T) { 44 trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) 45 iter := trie.NodeIterator(nil) 46 47 seen := make(map[string]struct{}) 48 for iter.Next(true) { 49 seen[string(iter.Path())] = struct{}{} 50 } 51 if len(seen) != 0 { 52 t.Fatal("Unexpected trie node iterated") 53 } 54 } 55 56 func TestIterator(t *testing.T) { 57 db := NewDatabase(rawdb.NewMemoryDatabase()) 58 trie := NewEmpty(db) 59 vals := []struct{ k, v string }{ 60 {"do", "verb"}, 61 {"ether", "wookiedoo"}, 62 {"horse", "stallion"}, 63 {"shaman", "horse"}, 64 {"doge", "coin"}, 65 {"dog", "puppy"}, 66 {"somethingveryoddindeedthis is", "myothernodedata"}, 67 } 68 all := make(map[string]string) 69 for _, val := range vals { 70 all[val.k] = val.v 71 trie.Update([]byte(val.k), []byte(val.v)) 72 } 73 root, nodes, err := trie.Commit(false) 74 if err != nil { 75 t.Fatalf("Failed to commit trie %v", err) 76 } 77 db.Update(NewWithNodeSet(nodes)) 78 79 trie, _ = New(common.Hash{}, root, db) 80 found := make(map[string]string) 81 it := NewIterator(trie.NodeIterator(nil)) 82 for it.Next() { 83 found[string(it.Key)] = string(it.Value) 84 } 85 86 for k, v := range all { 87 if found[k] != v { 88 t.Errorf("iterator value mismatch for %s: got %q want %q", k, found[k], v) 89 } 90 } 91 } 92 93 type kv struct { 94 k, v []byte 95 t bool 96 } 97 98 func TestIteratorLargeData(t *testing.T) { 99 trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) 100 vals := make(map[string]*kv) 101 102 for i := byte(0); i < 255; i++ { 103 value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} 104 value2 := &kv{common.LeftPadBytes([]byte{10, i}, 32), []byte{i}, false} 105 trie.Update(value.k, value.v) 106 trie.Update(value2.k, value2.v) 107 vals[string(value.k)] = value 108 vals[string(value2.k)] = value2 109 } 110 111 it := NewIterator(trie.NodeIterator(nil)) 112 for it.Next() { 113 vals[string(it.Key)].t = true 114 } 115 116 var untouched []*kv 117 for _, value := range vals { 118 if !value.t { 119 untouched = append(untouched, value) 120 } 121 } 122 123 if len(untouched) > 0 { 124 t.Errorf("Missed %d nodes", len(untouched)) 125 for _, value := range untouched { 126 t.Error(value) 127 } 128 } 129 } 130 131 // Tests that the node iterator indeed walks over the entire database contents. 132 func TestNodeIteratorCoverage(t *testing.T) { 133 // Create some arbitrary test trie to iterate 134 db, trie, _ := makeTestTrie() 135 136 // Gather all the node hashes found by the iterator 137 hashes := make(map[common.Hash]struct{}) 138 for it := trie.NodeIterator(nil); it.Next(true); { 139 if it.Hash() != (common.Hash{}) { 140 hashes[it.Hash()] = struct{}{} 141 } 142 } 143 // Cross check the hashes and the database itself 144 for hash := range hashes { 145 if _, err := db.RawNode(hash); err != nil { 146 t.Errorf("failed to retrieve reported node %x: %v", hash, err) 147 } 148 } 149 for hash, obj := range db.dirties { 150 if obj != nil && hash != (common.Hash{}) { 151 if _, ok := hashes[hash]; !ok { 152 t.Errorf("state entry not reported %x", hash) 153 } 154 } 155 } 156 it := db.diskdb.NewIterator(nil, nil) 157 for it.Next() { 158 key := it.Key() 159 if _, ok := hashes[common.BytesToHash(key)]; !ok { 160 t.Errorf("state entry not reported %x", key) 161 } 162 } 163 it.Release() 164 } 165 166 type kvs struct{ k, v string } 167 168 var testdata1 = []kvs{ 169 {"barb", "ba"}, 170 {"bard", "bc"}, 171 {"bars", "bb"}, 172 {"bar", "b"}, 173 {"fab", "z"}, 174 {"food", "ab"}, 175 {"foos", "aa"}, 176 {"foo", "a"}, 177 } 178 179 var testdata2 = []kvs{ 180 {"aardvark", "c"}, 181 {"bar", "b"}, 182 {"barb", "bd"}, 183 {"bars", "be"}, 184 {"fab", "z"}, 185 {"foo", "a"}, 186 {"foos", "aa"}, 187 {"food", "ab"}, 188 {"jars", "d"}, 189 } 190 191 func TestIteratorSeek(t *testing.T) { 192 trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) 193 for _, val := range testdata1 { 194 trie.Update([]byte(val.k), []byte(val.v)) 195 } 196 197 // Seek to the middle. 198 it := NewIterator(trie.NodeIterator([]byte("fab"))) 199 if err := checkIteratorOrder(testdata1[4:], it); err != nil { 200 t.Fatal(err) 201 } 202 203 // Seek to a non-existent key. 204 it = NewIterator(trie.NodeIterator([]byte("barc"))) 205 if err := checkIteratorOrder(testdata1[1:], it); err != nil { 206 t.Fatal(err) 207 } 208 209 // Seek beyond the end. 210 it = NewIterator(trie.NodeIterator([]byte("z"))) 211 if err := checkIteratorOrder(nil, it); err != nil { 212 t.Fatal(err) 213 } 214 } 215 216 func checkIteratorOrder(want []kvs, it *Iterator) error { 217 for it.Next() { 218 if len(want) == 0 { 219 return fmt.Errorf("didn't expect any more values, got key %q", it.Key) 220 } 221 if !bytes.Equal(it.Key, []byte(want[0].k)) { 222 return fmt.Errorf("wrong key: got %q, want %q", it.Key, want[0].k) 223 } 224 want = want[1:] 225 } 226 if len(want) > 0 { 227 return fmt.Errorf("iterator ended early, want key %q", want[0]) 228 } 229 return nil 230 } 231 232 func TestDifferenceIterator(t *testing.T) { 233 dba := NewDatabase(rawdb.NewMemoryDatabase()) 234 triea := NewEmpty(dba) 235 for _, val := range testdata1 { 236 triea.Update([]byte(val.k), []byte(val.v)) 237 } 238 rootA, nodesA, _ := triea.Commit(false) 239 dba.Update(NewWithNodeSet(nodesA)) 240 triea, _ = New(common.Hash{}, rootA, dba) 241 242 dbb := NewDatabase(rawdb.NewMemoryDatabase()) 243 trieb := NewEmpty(dbb) 244 for _, val := range testdata2 { 245 trieb.Update([]byte(val.k), []byte(val.v)) 246 } 247 rootB, nodesB, _ := trieb.Commit(false) 248 dbb.Update(NewWithNodeSet(nodesB)) 249 trieb, _ = New(common.Hash{}, rootB, dbb) 250 251 found := make(map[string]string) 252 di, _ := NewDifferenceIterator(triea.NodeIterator(nil), trieb.NodeIterator(nil)) 253 it := NewIterator(di) 254 for it.Next() { 255 found[string(it.Key)] = string(it.Value) 256 } 257 258 all := []struct{ k, v string }{ 259 {"aardvark", "c"}, 260 {"barb", "bd"}, 261 {"bars", "be"}, 262 {"jars", "d"}, 263 } 264 for _, item := range all { 265 if found[item.k] != item.v { 266 t.Errorf("iterator value mismatch for %s: got %v want %v", item.k, found[item.k], item.v) 267 } 268 } 269 if len(found) != len(all) { 270 t.Errorf("iterator count mismatch: got %d values, want %d", len(found), len(all)) 271 } 272 } 273 274 func TestUnionIterator(t *testing.T) { 275 dba := NewDatabase(rawdb.NewMemoryDatabase()) 276 triea := NewEmpty(dba) 277 for _, val := range testdata1 { 278 triea.Update([]byte(val.k), []byte(val.v)) 279 } 280 rootA, nodesA, _ := triea.Commit(false) 281 dba.Update(NewWithNodeSet(nodesA)) 282 triea, _ = New(common.Hash{}, rootA, dba) 283 284 dbb := NewDatabase(rawdb.NewMemoryDatabase()) 285 trieb := NewEmpty(dbb) 286 for _, val := range testdata2 { 287 trieb.Update([]byte(val.k), []byte(val.v)) 288 } 289 rootB, nodesB, _ := trieb.Commit(false) 290 dbb.Update(NewWithNodeSet(nodesB)) 291 trieb, _ = New(common.Hash{}, rootB, dbb) 292 293 di, _ := NewUnionIterator([]NodeIterator{triea.NodeIterator(nil), trieb.NodeIterator(nil)}) 294 it := NewIterator(di) 295 296 all := []struct{ k, v string }{ 297 {"aardvark", "c"}, 298 {"barb", "ba"}, 299 {"barb", "bd"}, 300 {"bard", "bc"}, 301 {"bars", "bb"}, 302 {"bars", "be"}, 303 {"bar", "b"}, 304 {"fab", "z"}, 305 {"food", "ab"}, 306 {"foos", "aa"}, 307 {"foo", "a"}, 308 {"jars", "d"}, 309 } 310 311 for i, kv := range all { 312 if !it.Next() { 313 t.Errorf("Iterator ends prematurely at element %d", i) 314 } 315 if kv.k != string(it.Key) { 316 t.Errorf("iterator value mismatch for element %d: got key %s want %s", i, it.Key, kv.k) 317 } 318 if kv.v != string(it.Value) { 319 t.Errorf("iterator value mismatch for element %d: got value %s want %s", i, it.Value, kv.v) 320 } 321 } 322 if it.Next() { 323 t.Errorf("Iterator returned extra values.") 324 } 325 } 326 327 func TestIteratorNoDups(t *testing.T) { 328 tr := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) 329 for _, val := range testdata1 { 330 tr.Update([]byte(val.k), []byte(val.v)) 331 } 332 checkIteratorNoDups(t, tr.NodeIterator(nil), nil) 333 } 334 335 // This test checks that nodeIterator.Next can be retried after inserting missing trie nodes. 336 func TestIteratorContinueAfterErrorDisk(t *testing.T) { testIteratorContinueAfterError(t, false) } 337 func TestIteratorContinueAfterErrorMemonly(t *testing.T) { testIteratorContinueAfterError(t, true) } 338 339 func testIteratorContinueAfterError(t *testing.T, memonly bool) { 340 diskdb := memorydb.New() 341 triedb := NewDatabase(diskdb) 342 343 tr := NewEmpty(triedb) 344 for _, val := range testdata1 { 345 tr.Update([]byte(val.k), []byte(val.v)) 346 } 347 _, nodes, _ := tr.Commit(false) 348 triedb.Update(NewWithNodeSet(nodes)) 349 if !memonly { 350 triedb.Commit(tr.Hash(), true, nil) 351 } 352 wantNodeCount := checkIteratorNoDups(t, tr.NodeIterator(nil), nil) 353 354 var ( 355 diskKeys [][]byte 356 memKeys []common.Hash 357 ) 358 if memonly { 359 memKeys = triedb.Nodes() 360 } else { 361 it := diskdb.NewIterator(nil, nil) 362 for it.Next() { 363 diskKeys = append(diskKeys, it.Key()) 364 } 365 it.Release() 366 } 367 for i := 0; i < 20; i++ { 368 // Create trie that will load all nodes from DB. 369 tr, _ := New(common.Hash{}, tr.Hash(), triedb) 370 371 // Remove a random node from the database. It can't be the root node 372 // because that one is already loaded. 373 var ( 374 rkey common.Hash 375 rval []byte 376 robj *cachedNode 377 ) 378 for { 379 if memonly { 380 rkey = memKeys[rand.Intn(len(memKeys))] 381 } else { 382 copy(rkey[:], diskKeys[rand.Intn(len(diskKeys))]) 383 } 384 if rkey != tr.Hash() { 385 break 386 } 387 } 388 if memonly { 389 robj = triedb.dirties[rkey] 390 delete(triedb.dirties, rkey) 391 } else { 392 rval, _ = diskdb.Get(rkey[:]) 393 diskdb.Delete(rkey[:]) 394 } 395 // Iterate until the error is hit. 396 seen := make(map[string]bool) 397 it := tr.NodeIterator(nil) 398 checkIteratorNoDups(t, it, seen) 399 missing, ok := it.Error().(*MissingNodeError) 400 if !ok || missing.NodeHash != rkey { 401 t.Fatal("didn't hit missing node, got", it.Error()) 402 } 403 404 // Add the node back and continue iteration. 405 if memonly { 406 triedb.dirties[rkey] = robj 407 } else { 408 diskdb.Put(rkey[:], rval) 409 } 410 checkIteratorNoDups(t, it, seen) 411 if it.Error() != nil { 412 t.Fatal("unexpected error", it.Error()) 413 } 414 if len(seen) != wantNodeCount { 415 t.Fatal("wrong node iteration count, got", len(seen), "want", wantNodeCount) 416 } 417 } 418 } 419 420 // Similar to the test above, this one checks that failure to create nodeIterator at a 421 // certain key prefix behaves correctly when Next is called. The expectation is that Next 422 // should retry seeking before returning true for the first time. 423 func TestIteratorContinueAfterSeekErrorDisk(t *testing.T) { 424 testIteratorContinueAfterSeekError(t, false) 425 } 426 func TestIteratorContinueAfterSeekErrorMemonly(t *testing.T) { 427 testIteratorContinueAfterSeekError(t, true) 428 } 429 430 func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) { 431 // Commit test trie to db, then remove the node containing "bars". 432 diskdb := memorydb.New() 433 triedb := NewDatabase(diskdb) 434 435 ctr := NewEmpty(triedb) 436 for _, val := range testdata1 { 437 ctr.Update([]byte(val.k), []byte(val.v)) 438 } 439 root, nodes, _ := ctr.Commit(false) 440 triedb.Update(NewWithNodeSet(nodes)) 441 if !memonly { 442 triedb.Commit(root, true, nil) 443 } 444 barNodeHash := common.HexToHash("05041990364eb72fcb1127652ce40d8bab765f2bfe53225b1170d276cc101c2e") 445 var ( 446 barNodeBlob []byte 447 barNodeObj *cachedNode 448 ) 449 if memonly { 450 barNodeObj = triedb.dirties[barNodeHash] 451 delete(triedb.dirties, barNodeHash) 452 } else { 453 barNodeBlob, _ = diskdb.Get(barNodeHash[:]) 454 diskdb.Delete(barNodeHash[:]) 455 } 456 // Create a new iterator that seeks to "bars". Seeking can't proceed because 457 // the node is missing. 458 tr, _ := New(common.Hash{}, root, triedb) 459 it := tr.NodeIterator([]byte("bars")) 460 missing, ok := it.Error().(*MissingNodeError) 461 if !ok { 462 t.Fatal("want MissingNodeError, got", it.Error()) 463 } else if missing.NodeHash != barNodeHash { 464 t.Fatal("wrong node missing") 465 } 466 // Reinsert the missing node. 467 if memonly { 468 triedb.dirties[barNodeHash] = barNodeObj 469 } else { 470 diskdb.Put(barNodeHash[:], barNodeBlob) 471 } 472 // Check that iteration produces the right set of values. 473 if err := checkIteratorOrder(testdata1[2:], NewIterator(it)); err != nil { 474 t.Fatal(err) 475 } 476 } 477 478 func checkIteratorNoDups(t *testing.T, it NodeIterator, seen map[string]bool) int { 479 if seen == nil { 480 seen = make(map[string]bool) 481 } 482 for it.Next(true) { 483 if seen[string(it.Path())] { 484 t.Fatalf("iterator visited node path %x twice", it.Path()) 485 } 486 seen[string(it.Path())] = true 487 } 488 return len(seen) 489 } 490 491 type loggingDb struct { 492 getCount uint64 493 backend ethdb.KeyValueStore 494 } 495 496 func (l *loggingDb) Has(key []byte) (bool, error) { 497 return l.backend.Has(key) 498 } 499 500 func (l *loggingDb) Get(key []byte) ([]byte, error) { 501 l.getCount++ 502 return l.backend.Get(key) 503 } 504 505 func (l *loggingDb) Put(key []byte, value []byte) error { 506 return l.backend.Put(key, value) 507 } 508 509 func (l *loggingDb) Delete(key []byte) error { 510 return l.backend.Delete(key) 511 } 512 513 func (l *loggingDb) NewBatch() ethdb.Batch { 514 return l.backend.NewBatch() 515 } 516 517 func (l *loggingDb) NewBatchWithSize(size int) ethdb.Batch { 518 return l.backend.NewBatchWithSize(size) 519 } 520 521 func (l *loggingDb) NewIterator(prefix []byte, start []byte) ethdb.Iterator { 522 fmt.Printf("NewIterator\n") 523 return l.backend.NewIterator(prefix, start) 524 } 525 526 func (l *loggingDb) Stat(property string) (string, error) { 527 return l.backend.Stat(property) 528 } 529 530 func (l *loggingDb) Compact(start []byte, limit []byte) error { 531 return l.backend.Compact(start, limit) 532 } 533 534 func (l *loggingDb) Close() error { 535 return l.backend.Close() 536 } 537 538 // makeLargeTestTrie create a sample test trie 539 func makeLargeTestTrie() (*Database, *StateTrie, *loggingDb) { 540 // Create an empty trie 541 logDb := &loggingDb{0, memorydb.New()} 542 triedb := NewDatabase(logDb) 543 trie, _ := NewStateTrie(common.Hash{}, common.Hash{}, triedb) 544 545 // Fill it with some arbitrary data 546 for i := 0; i < 10000; i++ { 547 key := make([]byte, 32) 548 val := make([]byte, 32) 549 binary.BigEndian.PutUint64(key, uint64(i)) 550 binary.BigEndian.PutUint64(val, uint64(i)) 551 key = crypto.Keccak256(key) 552 val = crypto.Keccak256(val) 553 trie.Update(key, val) 554 } 555 _, nodes, _ := trie.Commit(false) 556 triedb.Update(NewWithNodeSet(nodes)) 557 // Return the generated trie 558 return triedb, trie, logDb 559 } 560 561 // Tests that the node iterator indeed walks over the entire database contents. 562 func TestNodeIteratorLargeTrie(t *testing.T) { 563 // Create some arbitrary test trie to iterate 564 db, trie, logDb := makeLargeTestTrie() 565 db.Cap(0) // flush everything 566 // Do a seek operation 567 trie.NodeIterator(common.FromHex("0x77667766776677766778855885885885")) 568 // master: 24 get operations 569 // this pr: 5 get operations 570 if have, want := logDb.getCount, uint64(5); have != want { 571 t.Fatalf("Too many lookups during seek, have %d want %d", have, want) 572 } 573 } 574 575 func TestIteratorNodeBlob(t *testing.T) { 576 var ( 577 db = memorydb.New() 578 triedb = NewDatabase(db) 579 trie = NewEmpty(triedb) 580 ) 581 vals := []struct{ k, v string }{ 582 {"do", "verb"}, 583 {"ether", "wookiedoo"}, 584 {"horse", "stallion"}, 585 {"shaman", "horse"}, 586 {"doge", "coin"}, 587 {"dog", "puppy"}, 588 {"somethingveryoddindeedthis is", "myothernodedata"}, 589 } 590 all := make(map[string]string) 591 for _, val := range vals { 592 all[val.k] = val.v 593 trie.Update([]byte(val.k), []byte(val.v)) 594 } 595 _, nodes, _ := trie.Commit(false) 596 triedb.Update(NewWithNodeSet(nodes)) 597 triedb.Cap(0) 598 599 found := make(map[common.Hash][]byte) 600 it := trie.NodeIterator(nil) 601 for it.Next(true) { 602 if it.Hash() == (common.Hash{}) { 603 continue 604 } 605 found[it.Hash()] = it.NodeBlob() 606 } 607 608 dbIter := db.NewIterator(nil, nil) 609 defer dbIter.Release() 610 611 var count int 612 for dbIter.Next() { 613 got, present := found[common.BytesToHash(dbIter.Key())] 614 if !present { 615 t.Fatalf("Miss trie node %v", dbIter.Key()) 616 } 617 if !bytes.Equal(got, dbIter.Value()) { 618 t.Fatalf("Unexpected trie node want %v got %v", dbIter.Value(), got) 619 } 620 count += 1 621 } 622 if count != len(found) { 623 t.Fatal("Find extra trie node via iterator") 624 } 625 }