github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/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.Reader(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 {"barb", "ba"}, 186 {"bard", "bc"}, 187 {"bars", "bb"}, 188 {"bar", "b"}, 189 {"fab", "z"}, 190 {"food", "ab"}, 191 {"foos", "aa"}, 192 {"foo", "a"}, 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[1:], 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 232 func checkIteratorOrder(want []kvs, it *Iterator) error { 233 for it.Next() { 234 if len(want) == 0 { 235 return fmt.Errorf("didn't expect any more values, got key %q", it.Key) 236 } 237 if !bytes.Equal(it.Key, []byte(want[0].k)) { 238 return fmt.Errorf("wrong key: got %q, want %q", it.Key, want[0].k) 239 } 240 want = want[1:] 241 } 242 if len(want) > 0 { 243 return fmt.Errorf("iterator ended early, want key %q", want[0]) 244 } 245 return nil 246 } 247 248 func TestDifferenceIterator(t *testing.T) { 249 dba := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) 250 triea := NewEmpty(dba) 251 for _, val := range testdata1 { 252 triea.MustUpdate([]byte(val.k), []byte(val.v)) 253 } 254 rootA, nodesA, _ := triea.Commit(false) 255 dba.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)) 256 triea, _ = New(TrieID(rootA), dba) 257 258 dbb := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) 259 trieb := NewEmpty(dbb) 260 for _, val := range testdata2 { 261 trieb.MustUpdate([]byte(val.k), []byte(val.v)) 262 } 263 rootB, nodesB, _ := trieb.Commit(false) 264 dbb.Update(rootB, types.EmptyRootHash, trienode.NewWithNodeSet(nodesB)) 265 trieb, _ = New(TrieID(rootB), dbb) 266 267 found := make(map[string]string) 268 di, _ := NewDifferenceIterator(triea.MustNodeIterator(nil), trieb.MustNodeIterator(nil)) 269 it := NewIterator(di) 270 for it.Next() { 271 found[string(it.Key)] = string(it.Value) 272 } 273 274 all := []struct{ k, v string }{ 275 {"aardvark", "c"}, 276 {"barb", "bd"}, 277 {"bars", "be"}, 278 {"jars", "d"}, 279 } 280 for _, item := range all { 281 if found[item.k] != item.v { 282 t.Errorf("iterator value mismatch for %s: got %v want %v", item.k, found[item.k], item.v) 283 } 284 } 285 if len(found) != len(all) { 286 t.Errorf("iterator count mismatch: got %d values, want %d", len(found), len(all)) 287 } 288 } 289 290 func TestUnionIterator(t *testing.T) { 291 dba := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) 292 triea := NewEmpty(dba) 293 for _, val := range testdata1 { 294 triea.MustUpdate([]byte(val.k), []byte(val.v)) 295 } 296 rootA, nodesA, _ := triea.Commit(false) 297 dba.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)) 298 triea, _ = New(TrieID(rootA), dba) 299 300 dbb := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) 301 trieb := NewEmpty(dbb) 302 for _, val := range testdata2 { 303 trieb.MustUpdate([]byte(val.k), []byte(val.v)) 304 } 305 rootB, nodesB, _ := trieb.Commit(false) 306 dbb.Update(rootB, types.EmptyRootHash, trienode.NewWithNodeSet(nodesB)) 307 trieb, _ = New(TrieID(rootB), dbb) 308 309 di, _ := NewUnionIterator([]NodeIterator{triea.MustNodeIterator(nil), trieb.MustNodeIterator(nil)}) 310 it := NewIterator(di) 311 312 all := []struct{ k, v string }{ 313 {"aardvark", "c"}, 314 {"barb", "ba"}, 315 {"barb", "bd"}, 316 {"bard", "bc"}, 317 {"bars", "bb"}, 318 {"bars", "be"}, 319 {"bar", "b"}, 320 {"fab", "z"}, 321 {"food", "ab"}, 322 {"foos", "aa"}, 323 {"foo", "a"}, 324 {"jars", "d"}, 325 } 326 327 for i, kv := range all { 328 if !it.Next() { 329 t.Errorf("Iterator ends prematurely at element %d", i) 330 } 331 if kv.k != string(it.Key) { 332 t.Errorf("iterator value mismatch for element %d: got key %s want %s", i, it.Key, kv.k) 333 } 334 if kv.v != string(it.Value) { 335 t.Errorf("iterator value mismatch for element %d: got value %s want %s", i, it.Value, kv.v) 336 } 337 } 338 if it.Next() { 339 t.Errorf("Iterator returned extra values.") 340 } 341 } 342 343 func TestIteratorNoDups(t *testing.T) { 344 db := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) 345 tr := NewEmpty(db) 346 for _, val := range testdata1 { 347 tr.MustUpdate([]byte(val.k), []byte(val.v)) 348 } 349 checkIteratorNoDups(t, tr.MustNodeIterator(nil), nil) 350 } 351 352 // This test checks that nodeIterator.Next can be retried after inserting missing trie nodes. 353 func TestIteratorContinueAfterError(t *testing.T) { 354 testIteratorContinueAfterError(t, false, rawdb.HashScheme) 355 testIteratorContinueAfterError(t, true, rawdb.HashScheme) 356 testIteratorContinueAfterError(t, false, rawdb.PathScheme) 357 testIteratorContinueAfterError(t, true, rawdb.PathScheme) 358 } 359 360 func testIteratorContinueAfterError(t *testing.T, memonly bool, scheme string) { 361 diskdb := rawdb.NewMemoryDatabase() 362 tdb := newTestDatabase(diskdb, scheme) 363 364 tr := NewEmpty(tdb) 365 for _, val := range testdata1 { 366 tr.MustUpdate([]byte(val.k), []byte(val.v)) 367 } 368 root, nodes, _ := tr.Commit(false) 369 tdb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) 370 if !memonly { 371 tdb.Commit(root) 372 } 373 tr, _ = New(TrieID(root), tdb) 374 wantNodeCount := checkIteratorNoDups(t, tr.MustNodeIterator(nil), nil) 375 376 var ( 377 paths [][]byte 378 hashes []common.Hash 379 ) 380 if memonly { 381 for path, n := range nodes.Nodes { 382 paths = append(paths, []byte(path)) 383 hashes = append(hashes, n.Hash) 384 } 385 } else { 386 it := diskdb.NewIterator(nil, nil) 387 for it.Next() { 388 ok, path, hash := isTrieNode(tdb.Scheme(), it.Key(), it.Value()) 389 if !ok { 390 continue 391 } 392 paths = append(paths, path) 393 hashes = append(hashes, hash) 394 } 395 it.Release() 396 } 397 for i := 0; i < 20; i++ { 398 // Create trie that will load all nodes from DB. 399 tr, _ := New(TrieID(tr.Hash()), tdb) 400 401 // Remove a random node from the database. It can't be the root node 402 // because that one is already loaded. 403 var ( 404 rval []byte 405 rpath []byte 406 rhash common.Hash 407 ) 408 for { 409 if memonly { 410 rpath = paths[rand.Intn(len(paths))] 411 n := nodes.Nodes[string(rpath)] 412 if n == nil { 413 continue 414 } 415 rhash = n.Hash 416 } else { 417 index := rand.Intn(len(paths)) 418 rpath = paths[index] 419 rhash = hashes[index] 420 } 421 if rhash != tr.Hash() { 422 break 423 } 424 } 425 if memonly { 426 tr.reader.banned = map[string]struct{}{string(rpath): {}} 427 } else { 428 rval = rawdb.ReadTrieNode(diskdb, common.Hash{}, rpath, rhash, tdb.Scheme()) 429 rawdb.DeleteTrieNode(diskdb, common.Hash{}, rpath, rhash, tdb.Scheme()) 430 } 431 // Iterate until the error is hit. 432 seen := make(map[string]bool) 433 it := tr.MustNodeIterator(nil) 434 checkIteratorNoDups(t, it, seen) 435 missing, ok := it.Error().(*MissingNodeError) 436 if !ok || missing.NodeHash != rhash { 437 t.Fatal("didn't hit missing node, got", it.Error()) 438 } 439 440 // Add the node back and continue iteration. 441 if memonly { 442 delete(tr.reader.banned, string(rpath)) 443 } else { 444 rawdb.WriteTrieNode(diskdb, common.Hash{}, rpath, rhash, rval, tdb.Scheme()) 445 } 446 checkIteratorNoDups(t, it, seen) 447 if it.Error() != nil { 448 t.Fatal("unexpected error", it.Error()) 449 } 450 if len(seen) != wantNodeCount { 451 t.Fatal("wrong node iteration count, got", len(seen), "want", wantNodeCount) 452 } 453 } 454 } 455 456 // Similar to the test above, this one checks that failure to create nodeIterator at a 457 // certain key prefix behaves correctly when Next is called. The expectation is that Next 458 // should retry seeking before returning true for the first time. 459 func TestIteratorContinueAfterSeekError(t *testing.T) { 460 testIteratorContinueAfterSeekError(t, false, rawdb.HashScheme) 461 testIteratorContinueAfterSeekError(t, true, rawdb.HashScheme) 462 testIteratorContinueAfterSeekError(t, false, rawdb.PathScheme) 463 testIteratorContinueAfterSeekError(t, true, rawdb.PathScheme) 464 } 465 466 func testIteratorContinueAfterSeekError(t *testing.T, memonly bool, scheme string) { 467 // Commit test trie to db, then remove the node containing "bars". 468 var ( 469 barNodePath []byte 470 barNodeHash = common.HexToHash("05041990364eb72fcb1127652ce40d8bab765f2bfe53225b1170d276cc101c2e") 471 ) 472 diskdb := rawdb.NewMemoryDatabase() 473 triedb := newTestDatabase(diskdb, scheme) 474 ctr := NewEmpty(triedb) 475 for _, val := range testdata1 { 476 ctr.MustUpdate([]byte(val.k), []byte(val.v)) 477 } 478 root, nodes, _ := ctr.Commit(false) 479 for path, n := range nodes.Nodes { 480 if n.Hash == barNodeHash { 481 barNodePath = []byte(path) 482 break 483 } 484 } 485 triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) 486 if !memonly { 487 triedb.Commit(root) 488 } 489 var ( 490 barNodeBlob []byte 491 ) 492 tr, _ := New(TrieID(root), triedb) 493 if memonly { 494 tr.reader.banned = map[string]struct{}{string(barNodePath): {}} 495 } else { 496 barNodeBlob = rawdb.ReadTrieNode(diskdb, common.Hash{}, barNodePath, barNodeHash, triedb.Scheme()) 497 rawdb.DeleteTrieNode(diskdb, common.Hash{}, barNodePath, barNodeHash, triedb.Scheme()) 498 } 499 // Create a new iterator that seeks to "bars". Seeking can't proceed because 500 // the node is missing. 501 it := tr.MustNodeIterator([]byte("bars")) 502 missing, ok := it.Error().(*MissingNodeError) 503 if !ok { 504 t.Fatal("want MissingNodeError, got", it.Error()) 505 } else if missing.NodeHash != barNodeHash { 506 t.Fatal("wrong node missing") 507 } 508 // Reinsert the missing node. 509 if memonly { 510 delete(tr.reader.banned, string(barNodePath)) 511 } else { 512 rawdb.WriteTrieNode(diskdb, common.Hash{}, barNodePath, barNodeHash, barNodeBlob, triedb.Scheme()) 513 } 514 // Check that iteration produces the right set of values. 515 if err := checkIteratorOrder(testdata1[2:], NewIterator(it)); err != nil { 516 t.Fatal(err) 517 } 518 } 519 520 func checkIteratorNoDups(t *testing.T, it NodeIterator, seen map[string]bool) int { 521 if seen == nil { 522 seen = make(map[string]bool) 523 } 524 for it.Next(true) { 525 if seen[string(it.Path())] { 526 t.Fatalf("iterator visited node path %x twice", it.Path()) 527 } 528 seen[string(it.Path())] = true 529 } 530 return len(seen) 531 } 532 533 func TestIteratorNodeBlob(t *testing.T) { 534 testIteratorNodeBlob(t, rawdb.HashScheme) 535 testIteratorNodeBlob(t, rawdb.PathScheme) 536 } 537 538 func testIteratorNodeBlob(t *testing.T, scheme string) { 539 var ( 540 db = rawdb.NewMemoryDatabase() 541 triedb = newTestDatabase(db, scheme) 542 trie = NewEmpty(triedb) 543 ) 544 vals := []struct{ k, v string }{ 545 {"do", "verb"}, 546 {"ether", "wookiedoo"}, 547 {"horse", "stallion"}, 548 {"shaman", "horse"}, 549 {"doge", "coin"}, 550 {"dog", "puppy"}, 551 {"somethingveryoddindeedthis is", "myothernodedata"}, 552 } 553 all := make(map[string]string) 554 for _, val := range vals { 555 all[val.k] = val.v 556 trie.MustUpdate([]byte(val.k), []byte(val.v)) 557 } 558 root, nodes, _ := trie.Commit(false) 559 triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) 560 triedb.Commit(root) 561 562 var found = make(map[common.Hash][]byte) 563 trie, _ = New(TrieID(root), triedb) 564 it := trie.MustNodeIterator(nil) 565 for it.Next(true) { 566 if it.Hash() == (common.Hash{}) { 567 continue 568 } 569 found[it.Hash()] = it.NodeBlob() 570 } 571 572 dbIter := db.NewIterator(nil, nil) 573 defer dbIter.Release() 574 575 var count int 576 for dbIter.Next() { 577 ok, _, _ := isTrieNode(triedb.Scheme(), dbIter.Key(), dbIter.Value()) 578 if !ok { 579 continue 580 } 581 got, present := found[crypto.Keccak256Hash(dbIter.Value())] 582 if !present { 583 t.Fatal("Miss trie node") 584 } 585 if !bytes.Equal(got, dbIter.Value()) { 586 t.Fatalf("Unexpected trie node want %v got %v", dbIter.Value(), got) 587 } 588 count += 1 589 } 590 if count != len(found) { 591 t.Fatal("Find extra trie node via iterator") 592 } 593 } 594 595 // isTrieNode is a helper function which reports if the provided 596 // database entry belongs to a trie node or not. Note in tests 597 // only single layer trie is used, namely storage trie is not 598 // considered at all. 599 func isTrieNode(scheme string, key, val []byte) (bool, []byte, common.Hash) { 600 var ( 601 path []byte 602 hash common.Hash 603 ) 604 if scheme == rawdb.HashScheme { 605 ok := rawdb.IsLegacyTrieNode(key, val) 606 if !ok { 607 return false, nil, common.Hash{} 608 } 609 hash = common.BytesToHash(key) 610 } else { 611 ok, remain := rawdb.ResolveAccountTrieNodeKey(key) 612 if !ok { 613 return false, nil, common.Hash{} 614 } 615 path = common.CopyBytes(remain) 616 hash = crypto.Keccak256Hash(val) 617 } 618 return true, path, hash 619 } 620 621 func BenchmarkIterator(b *testing.B) { 622 diskDb, srcDb, tr, _ := makeTestTrie(rawdb.HashScheme) 623 root := tr.Hash() 624 b.ReportAllocs() 625 b.ResetTimer() 626 for i := 0; i < b.N; i++ { 627 if err := checkTrieConsistency(diskDb, srcDb.Scheme(), root, false); err != nil { 628 b.Fatal(err) 629 } 630 } 631 }