github.com/ethereum/go-ethereum@v1.16.1/trie/iterator_test.go (about) 1 // Copyright 2014 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 "fmt" 22 "math/rand" 23 "testing" 24 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/core/rawdb" 27 "github.com/ethereum/go-ethereum/core/types" 28 "github.com/ethereum/go-ethereum/crypto" 29 "github.com/ethereum/go-ethereum/trie/trienode" 30 ) 31 32 func TestEmptyIterator(t *testing.T) { 33 trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) 34 iter := trie.MustNodeIterator(nil) 35 36 seen := make(map[string]struct{}) 37 for iter.Next(true) { 38 seen[string(iter.Path())] = struct{}{} 39 } 40 if len(seen) != 0 { 41 t.Fatal("Unexpected trie node iterated") 42 } 43 } 44 45 func TestIterator(t *testing.T) { 46 db := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) 47 trie := NewEmpty(db) 48 vals := []struct{ k, v string }{ 49 {"do", "verb"}, 50 {"ether", "wookiedoo"}, 51 {"horse", "stallion"}, 52 {"shaman", "horse"}, 53 {"doge", "coin"}, 54 {"dog", "puppy"}, 55 {"somethingveryoddindeedthis is", "myothernodedata"}, 56 } 57 all := make(map[string]string) 58 for _, val := range vals { 59 all[val.k] = val.v 60 trie.MustUpdate([]byte(val.k), []byte(val.v)) 61 } 62 root, nodes := trie.Commit(false) 63 db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) 64 65 trie, _ = New(TrieID(root), db) 66 found := make(map[string]string) 67 it := NewIterator(trie.MustNodeIterator(nil)) 68 for it.Next() { 69 found[string(it.Key)] = string(it.Value) 70 } 71 72 for k, v := range all { 73 if found[k] != v { 74 t.Errorf("iterator value mismatch for %s: got %q want %q", k, found[k], v) 75 } 76 } 77 } 78 79 type kv struct { 80 k, v []byte 81 t bool 82 } 83 84 func (k *kv) cmp(other *kv) int { 85 return bytes.Compare(k.k, other.k) 86 } 87 88 func TestIteratorLargeData(t *testing.T) { 89 trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) 90 vals := make(map[string]*kv) 91 92 for i := byte(0); i < 255; i++ { 93 value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} 94 value2 := &kv{common.LeftPadBytes([]byte{10, i}, 32), []byte{i}, false} 95 trie.MustUpdate(value.k, value.v) 96 trie.MustUpdate(value2.k, value2.v) 97 vals[string(value.k)] = value 98 vals[string(value2.k)] = value2 99 } 100 101 it := NewIterator(trie.MustNodeIterator(nil)) 102 for it.Next() { 103 vals[string(it.Key)].t = true 104 } 105 106 var untouched []*kv 107 for _, value := range vals { 108 if !value.t { 109 untouched = append(untouched, value) 110 } 111 } 112 113 if len(untouched) > 0 { 114 t.Errorf("Missed %d nodes", len(untouched)) 115 for _, value := range untouched { 116 t.Error(value) 117 } 118 } 119 } 120 121 type iterationElement struct { 122 hash common.Hash 123 path []byte 124 blob []byte 125 } 126 127 // Tests that the node iterator indeed walks over the entire database contents. 128 func TestNodeIteratorCoverage(t *testing.T) { 129 testNodeIteratorCoverage(t, rawdb.HashScheme) 130 testNodeIteratorCoverage(t, rawdb.PathScheme) 131 } 132 133 func testNodeIteratorCoverage(t *testing.T, scheme string) { 134 // Create some arbitrary test trie to iterate 135 db, nodeDb, trie, _ := makeTestTrie(scheme) 136 137 // Gather all the node hashes found by the iterator 138 var elements = make(map[common.Hash]iterationElement) 139 for it := trie.MustNodeIterator(nil); it.Next(true); { 140 if it.Hash() != (common.Hash{}) { 141 elements[it.Hash()] = iterationElement{ 142 hash: it.Hash(), 143 path: common.CopyBytes(it.Path()), 144 blob: common.CopyBytes(it.NodeBlob()), 145 } 146 } 147 } 148 // Cross check the hashes and the database itself 149 reader, err := nodeDb.NodeReader(trie.Hash()) 150 if err != nil { 151 t.Fatalf("state is not available %x", trie.Hash()) 152 } 153 for _, element := range elements { 154 if blob, err := reader.Node(common.Hash{}, element.path, element.hash); err != nil { 155 t.Errorf("failed to retrieve reported node %x: %v", element.hash, err) 156 } else if !bytes.Equal(blob, element.blob) { 157 t.Errorf("node blob is different, want %v got %v", element.blob, blob) 158 } 159 } 160 var ( 161 count int 162 it = db.NewIterator(nil, nil) 163 ) 164 for it.Next() { 165 res, _, _ := isTrieNode(nodeDb.Scheme(), it.Key(), it.Value()) 166 if !res { 167 continue 168 } 169 count += 1 170 if elem, ok := elements[crypto.Keccak256Hash(it.Value())]; !ok { 171 t.Error("state entry not reported") 172 } else if !bytes.Equal(it.Value(), elem.blob) { 173 t.Errorf("node blob is different, want %v got %v", elem.blob, it.Value()) 174 } 175 } 176 it.Release() 177 if count != len(elements) { 178 t.Errorf("state entry is mismatched %d %d", count, len(elements)) 179 } 180 } 181 182 type kvs struct{ k, v string } 183 184 var testdata1 = []kvs{ 185 {"bar", "b"}, 186 {"barb", "ba"}, 187 {"bard", "bc"}, 188 {"bars", "bb"}, 189 {"fab", "z"}, 190 {"foo", "a"}, 191 {"food", "ab"}, 192 {"foos", "aa"}, 193 } 194 195 var testdata2 = []kvs{ 196 {"aardvark", "c"}, 197 {"bar", "b"}, 198 {"barb", "bd"}, 199 {"bars", "be"}, 200 {"fab", "z"}, 201 {"foo", "a"}, 202 {"foos", "aa"}, 203 {"food", "ab"}, 204 {"jars", "d"}, 205 } 206 207 func TestIteratorSeek(t *testing.T) { 208 trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) 209 for _, val := range testdata1 { 210 trie.MustUpdate([]byte(val.k), []byte(val.v)) 211 } 212 213 // Seek to the middle. 214 it := NewIterator(trie.MustNodeIterator([]byte("fab"))) 215 if err := checkIteratorOrder(testdata1[4:], it); err != nil { 216 t.Fatal(err) 217 } 218 219 // Seek to a non-existent key. 220 it = NewIterator(trie.MustNodeIterator([]byte("barc"))) 221 if err := checkIteratorOrder(testdata1[2:], it); err != nil { 222 t.Fatal(err) 223 } 224 225 // Seek beyond the end. 226 it = NewIterator(trie.MustNodeIterator([]byte("z"))) 227 if err := checkIteratorOrder(nil, it); err != nil { 228 t.Fatal(err) 229 } 230 231 // Seek to a key for which a prefixing key exists. 232 it = NewIterator(trie.MustNodeIterator([]byte("food"))) 233 if err := checkIteratorOrder(testdata1[6:], it); err != nil { 234 t.Fatal(err) 235 } 236 } 237 238 func checkIteratorOrder(want []kvs, it *Iterator) error { 239 for it.Next() { 240 if len(want) == 0 { 241 return fmt.Errorf("didn't expect any more values, got key %q", it.Key) 242 } 243 if !bytes.Equal(it.Key, []byte(want[0].k)) { 244 return fmt.Errorf("wrong key: got %q, want %q", it.Key, want[0].k) 245 } 246 want = want[1:] 247 } 248 if len(want) > 0 { 249 return fmt.Errorf("iterator ended early, want key %q", want[0]) 250 } 251 return nil 252 } 253 254 func TestDifferenceIterator(t *testing.T) { 255 dba := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) 256 triea := NewEmpty(dba) 257 for _, val := range testdata1 { 258 triea.MustUpdate([]byte(val.k), []byte(val.v)) 259 } 260 rootA, nodesA := triea.Commit(false) 261 dba.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)) 262 triea, _ = New(TrieID(rootA), dba) 263 264 dbb := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) 265 trieb := NewEmpty(dbb) 266 for _, val := range testdata2 { 267 trieb.MustUpdate([]byte(val.k), []byte(val.v)) 268 } 269 rootB, nodesB := trieb.Commit(false) 270 dbb.Update(rootB, types.EmptyRootHash, trienode.NewWithNodeSet(nodesB)) 271 trieb, _ = New(TrieID(rootB), dbb) 272 273 found := make(map[string]string) 274 di, _ := NewDifferenceIterator(triea.MustNodeIterator(nil), trieb.MustNodeIterator(nil)) 275 it := NewIterator(di) 276 for it.Next() { 277 found[string(it.Key)] = string(it.Value) 278 } 279 280 all := []struct{ k, v string }{ 281 {"aardvark", "c"}, 282 {"barb", "bd"}, 283 {"bars", "be"}, 284 {"jars", "d"}, 285 } 286 for _, item := range all { 287 if found[item.k] != item.v { 288 t.Errorf("iterator value mismatch for %s: got %v want %v", item.k, found[item.k], item.v) 289 } 290 } 291 if len(found) != len(all) { 292 t.Errorf("iterator count mismatch: got %d values, want %d", len(found), len(all)) 293 } 294 } 295 296 func TestUnionIterator(t *testing.T) { 297 dba := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) 298 triea := NewEmpty(dba) 299 for _, val := range testdata1 { 300 triea.MustUpdate([]byte(val.k), []byte(val.v)) 301 } 302 rootA, nodesA := triea.Commit(false) 303 dba.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)) 304 triea, _ = New(TrieID(rootA), dba) 305 306 dbb := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) 307 trieb := NewEmpty(dbb) 308 for _, val := range testdata2 { 309 trieb.MustUpdate([]byte(val.k), []byte(val.v)) 310 } 311 rootB, nodesB := trieb.Commit(false) 312 dbb.Update(rootB, types.EmptyRootHash, trienode.NewWithNodeSet(nodesB)) 313 trieb, _ = New(TrieID(rootB), dbb) 314 315 di, _ := NewUnionIterator([]NodeIterator{triea.MustNodeIterator(nil), trieb.MustNodeIterator(nil)}) 316 it := NewIterator(di) 317 318 all := []struct{ k, v string }{ 319 {"aardvark", "c"}, 320 {"bar", "b"}, 321 {"barb", "ba"}, 322 {"barb", "bd"}, 323 {"bard", "bc"}, 324 {"bars", "bb"}, 325 {"bars", "be"}, 326 {"fab", "z"}, 327 {"foo", "a"}, 328 {"food", "ab"}, 329 {"foos", "aa"}, 330 {"jars", "d"}, 331 } 332 333 for i, kv := range all { 334 if !it.Next() { 335 t.Errorf("Iterator ends prematurely at element %d", i) 336 } 337 if kv.k != string(it.Key) { 338 t.Errorf("iterator value mismatch for element %d: got key %s want %s", i, it.Key, kv.k) 339 } 340 if kv.v != string(it.Value) { 341 t.Errorf("iterator value mismatch for element %d: got value %s want %s", i, it.Value, kv.v) 342 } 343 } 344 if it.Next() { 345 t.Errorf("Iterator returned extra values.") 346 } 347 } 348 349 func TestIteratorNoDups(t *testing.T) { 350 db := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) 351 tr := NewEmpty(db) 352 for _, val := range testdata1 { 353 tr.MustUpdate([]byte(val.k), []byte(val.v)) 354 } 355 checkIteratorNoDups(t, tr.MustNodeIterator(nil), nil) 356 } 357 358 // This test checks that nodeIterator.Next can be retried after inserting missing trie nodes. 359 func TestIteratorContinueAfterError(t *testing.T) { 360 testIteratorContinueAfterError(t, false, rawdb.HashScheme) 361 testIteratorContinueAfterError(t, true, rawdb.HashScheme) 362 testIteratorContinueAfterError(t, false, rawdb.PathScheme) 363 testIteratorContinueAfterError(t, true, rawdb.PathScheme) 364 } 365 366 func testIteratorContinueAfterError(t *testing.T, memonly bool, scheme string) { 367 diskdb := rawdb.NewMemoryDatabase() 368 tdb := newTestDatabase(diskdb, scheme) 369 370 tr := NewEmpty(tdb) 371 for _, val := range testdata1 { 372 tr.MustUpdate([]byte(val.k), []byte(val.v)) 373 } 374 root, nodes := tr.Commit(false) 375 tdb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) 376 if !memonly { 377 tdb.Commit(root) 378 } 379 tr, _ = New(TrieID(root), tdb) 380 wantNodeCount := checkIteratorNoDups(t, tr.MustNodeIterator(nil), nil) 381 382 var ( 383 paths [][]byte 384 hashes []common.Hash 385 ) 386 if memonly { 387 for path, n := range nodes.Nodes { 388 paths = append(paths, []byte(path)) 389 hashes = append(hashes, n.Hash) 390 } 391 } else { 392 it := diskdb.NewIterator(nil, nil) 393 for it.Next() { 394 ok, path, hash := isTrieNode(tdb.Scheme(), it.Key(), it.Value()) 395 if !ok { 396 continue 397 } 398 paths = append(paths, path) 399 hashes = append(hashes, hash) 400 } 401 it.Release() 402 } 403 for i := 0; i < 20; i++ { 404 // Create trie that will load all nodes from DB. 405 tr, _ := New(TrieID(tr.Hash()), tdb) 406 407 // Remove a random node from the database. It can't be the root node 408 // because that one is already loaded. 409 var ( 410 rval []byte 411 rpath []byte 412 rhash common.Hash 413 ) 414 for { 415 if memonly { 416 rpath = paths[rand.Intn(len(paths))] 417 n := nodes.Nodes[string(rpath)] 418 if n == nil { 419 continue 420 } 421 rhash = n.Hash 422 } else { 423 index := rand.Intn(len(paths)) 424 rpath = paths[index] 425 rhash = hashes[index] 426 } 427 if rhash != tr.Hash() { 428 break 429 } 430 } 431 if memonly { 432 tr.reader.banned = map[string]struct{}{string(rpath): {}} 433 } else { 434 rval = rawdb.ReadTrieNode(diskdb, common.Hash{}, rpath, rhash, tdb.Scheme()) 435 rawdb.DeleteTrieNode(diskdb, common.Hash{}, rpath, rhash, tdb.Scheme()) 436 } 437 // Iterate until the error is hit. 438 seen := make(map[string]bool) 439 it := tr.MustNodeIterator(nil) 440 checkIteratorNoDups(t, it, seen) 441 missing, ok := it.Error().(*MissingNodeError) 442 if !ok || missing.NodeHash != rhash { 443 t.Fatal("didn't hit missing node, got", it.Error()) 444 } 445 446 // Add the node back and continue iteration. 447 if memonly { 448 delete(tr.reader.banned, string(rpath)) 449 } else { 450 rawdb.WriteTrieNode(diskdb, common.Hash{}, rpath, rhash, rval, tdb.Scheme()) 451 } 452 checkIteratorNoDups(t, it, seen) 453 if it.Error() != nil { 454 t.Fatal("unexpected error", it.Error()) 455 } 456 if len(seen) != wantNodeCount { 457 t.Fatal("wrong node iteration count, got", len(seen), "want", wantNodeCount) 458 } 459 } 460 } 461 462 // Similar to the test above, this one checks that failure to create nodeIterator at a 463 // certain key prefix behaves correctly when Next is called. The expectation is that Next 464 // should retry seeking before returning true for the first time. 465 func TestIteratorContinueAfterSeekError(t *testing.T) { 466 testIteratorContinueAfterSeekError(t, false, rawdb.HashScheme) 467 testIteratorContinueAfterSeekError(t, true, rawdb.HashScheme) 468 testIteratorContinueAfterSeekError(t, false, rawdb.PathScheme) 469 testIteratorContinueAfterSeekError(t, true, rawdb.PathScheme) 470 } 471 472 func testIteratorContinueAfterSeekError(t *testing.T, memonly bool, scheme string) { 473 // Commit test trie to db, then remove the node containing "bars". 474 var ( 475 barNodePath []byte 476 barNodeHash = common.HexToHash("05041990364eb72fcb1127652ce40d8bab765f2bfe53225b1170d276cc101c2e") 477 ) 478 diskdb := rawdb.NewMemoryDatabase() 479 triedb := newTestDatabase(diskdb, scheme) 480 ctr := NewEmpty(triedb) 481 for _, val := range testdata1 { 482 ctr.MustUpdate([]byte(val.k), []byte(val.v)) 483 } 484 root, nodes := ctr.Commit(false) 485 for path, n := range nodes.Nodes { 486 if n.Hash == barNodeHash { 487 barNodePath = []byte(path) 488 break 489 } 490 } 491 triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) 492 if !memonly { 493 triedb.Commit(root) 494 } 495 var ( 496 barNodeBlob []byte 497 ) 498 tr, _ := New(TrieID(root), triedb) 499 if memonly { 500 tr.reader.banned = map[string]struct{}{string(barNodePath): {}} 501 } else { 502 barNodeBlob = rawdb.ReadTrieNode(diskdb, common.Hash{}, barNodePath, barNodeHash, triedb.Scheme()) 503 rawdb.DeleteTrieNode(diskdb, common.Hash{}, barNodePath, barNodeHash, triedb.Scheme()) 504 } 505 // Create a new iterator that seeks to "bars". Seeking can't proceed because 506 // the node is missing. 507 it := tr.MustNodeIterator([]byte("bars")) 508 missing, ok := it.Error().(*MissingNodeError) 509 if !ok { 510 t.Fatal("want MissingNodeError, got", it.Error()) 511 } else if missing.NodeHash != barNodeHash { 512 t.Fatal("wrong node missing") 513 } 514 // Reinsert the missing node. 515 if memonly { 516 delete(tr.reader.banned, string(barNodePath)) 517 } else { 518 rawdb.WriteTrieNode(diskdb, common.Hash{}, barNodePath, barNodeHash, barNodeBlob, triedb.Scheme()) 519 } 520 // Check that iteration produces the right set of values. 521 if err := checkIteratorOrder(testdata1[3:], NewIterator(it)); err != nil { 522 t.Fatal(err) 523 } 524 } 525 526 func checkIteratorNoDups(t *testing.T, it NodeIterator, seen map[string]bool) int { 527 if seen == nil { 528 seen = make(map[string]bool) 529 } 530 for it.Next(true) { 531 if seen[string(it.Path())] { 532 t.Fatalf("iterator visited node path %x twice", it.Path()) 533 } 534 seen[string(it.Path())] = true 535 } 536 return len(seen) 537 } 538 539 func TestIteratorNodeBlob(t *testing.T) { 540 testIteratorNodeBlob(t, rawdb.HashScheme) 541 testIteratorNodeBlob(t, rawdb.PathScheme) 542 } 543 544 func testIteratorNodeBlob(t *testing.T, scheme string) { 545 var ( 546 db = rawdb.NewMemoryDatabase() 547 triedb = newTestDatabase(db, scheme) 548 trie = NewEmpty(triedb) 549 ) 550 vals := []struct{ k, v string }{ 551 {"do", "verb"}, 552 {"ether", "wookiedoo"}, 553 {"horse", "stallion"}, 554 {"shaman", "horse"}, 555 {"doge", "coin"}, 556 {"dog", "puppy"}, 557 {"somethingveryoddindeedthis is", "myothernodedata"}, 558 } 559 all := make(map[string]string) 560 for _, val := range vals { 561 all[val.k] = val.v 562 trie.MustUpdate([]byte(val.k), []byte(val.v)) 563 } 564 root, nodes := trie.Commit(false) 565 triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) 566 triedb.Commit(root) 567 568 var found = make(map[common.Hash][]byte) 569 trie, _ = New(TrieID(root), triedb) 570 it := trie.MustNodeIterator(nil) 571 for it.Next(true) { 572 if it.Hash() == (common.Hash{}) { 573 continue 574 } 575 found[it.Hash()] = it.NodeBlob() 576 } 577 578 dbIter := db.NewIterator(nil, nil) 579 defer dbIter.Release() 580 581 var count int 582 for dbIter.Next() { 583 ok, _, _ := isTrieNode(triedb.Scheme(), dbIter.Key(), dbIter.Value()) 584 if !ok { 585 continue 586 } 587 got, present := found[crypto.Keccak256Hash(dbIter.Value())] 588 if !present { 589 t.Fatal("Miss trie node") 590 } 591 if !bytes.Equal(got, dbIter.Value()) { 592 t.Fatalf("Unexpected trie node want %v got %v", dbIter.Value(), got) 593 } 594 count += 1 595 } 596 if count != len(found) { 597 t.Fatal("Find extra trie node via iterator") 598 } 599 } 600 601 // isTrieNode is a helper function which reports if the provided 602 // database entry belongs to a trie node or not. Note in tests 603 // only single layer trie is used, namely storage trie is not 604 // considered at all. 605 func isTrieNode(scheme string, key, val []byte) (bool, []byte, common.Hash) { 606 var ( 607 path []byte 608 hash common.Hash 609 ) 610 if scheme == rawdb.HashScheme { 611 ok := rawdb.IsLegacyTrieNode(key, val) 612 if !ok { 613 return false, nil, common.Hash{} 614 } 615 hash = common.BytesToHash(key) 616 } else { 617 ok, remain := rawdb.ResolveAccountTrieNodeKey(key) 618 if !ok { 619 return false, nil, common.Hash{} 620 } 621 path = common.CopyBytes(remain) 622 hash = crypto.Keccak256Hash(val) 623 } 624 return true, path, hash 625 } 626 627 func BenchmarkIterator(b *testing.B) { 628 diskDb, srcDb, tr, _ := makeTestTrie(rawdb.HashScheme) 629 root := tr.Hash() 630 b.ReportAllocs() 631 b.ResetTimer() 632 for i := 0; i < b.N; i++ { 633 if err := checkTrieConsistency(diskDb, srcDb.Scheme(), root, false); err != nil { 634 b.Fatal(err) 635 } 636 } 637 }