github.com/tacshi/go-ethereum@v0.0.0-20230616113857-84a434e20921/core/state/sync_test.go (about) 1 // Copyright 2015 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 state 18 19 import ( 20 "bytes" 21 "math/big" 22 "testing" 23 24 "github.com/tacshi/go-ethereum/common" 25 "github.com/tacshi/go-ethereum/core/rawdb" 26 "github.com/tacshi/go-ethereum/core/types" 27 "github.com/tacshi/go-ethereum/crypto" 28 "github.com/tacshi/go-ethereum/ethdb" 29 "github.com/tacshi/go-ethereum/rlp" 30 "github.com/tacshi/go-ethereum/trie" 31 ) 32 33 // testAccount is the data associated with an account used by the state tests. 34 type testAccount struct { 35 address common.Address 36 balance *big.Int 37 nonce uint64 38 code []byte 39 } 40 41 // makeTestState create a sample test state to test node-wise reconstruction. 42 func makeTestState() (ethdb.Database, Database, common.Hash, []*testAccount) { 43 // Create an empty state 44 db := rawdb.NewMemoryDatabase() 45 sdb := NewDatabase(db) 46 state, _ := New(common.Hash{}, sdb, nil) 47 48 // Fill it with some arbitrary data 49 var accounts []*testAccount 50 for i := byte(0); i < 96; i++ { 51 obj := state.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 52 acc := &testAccount{address: common.BytesToAddress([]byte{i})} 53 54 obj.AddBalance(big.NewInt(int64(11 * i))) 55 acc.balance = big.NewInt(int64(11 * i)) 56 57 obj.SetNonce(uint64(42 * i)) 58 acc.nonce = uint64(42 * i) 59 60 if i%3 == 0 { 61 obj.SetCode(crypto.Keccak256Hash([]byte{i, i, i, i, i}), []byte{i, i, i, i, i}) 62 acc.code = []byte{i, i, i, i, i} 63 } 64 if i%5 == 0 { 65 for j := byte(0); j < 5; j++ { 66 hash := crypto.Keccak256Hash([]byte{i, i, i, i, i, j, j}) 67 obj.SetState(sdb, hash, hash) 68 } 69 } 70 state.updateStateObject(obj) 71 accounts = append(accounts, acc) 72 } 73 root, _ := state.Commit(false) 74 75 // Return the generated state 76 return db, sdb, root, accounts 77 } 78 79 // checkStateAccounts cross references a reconstructed state with an expected 80 // account array. 81 func checkStateAccounts(t *testing.T, db ethdb.Database, root common.Hash, accounts []*testAccount) { 82 // Check root availability and state contents 83 state, err := New(root, NewDatabase(db), nil) 84 if err != nil { 85 t.Fatalf("failed to create state trie at %x: %v", root, err) 86 } 87 if err := checkStateConsistency(db, root); err != nil { 88 t.Fatalf("inconsistent state trie at %x: %v", root, err) 89 } 90 for i, acc := range accounts { 91 if balance := state.GetBalance(acc.address); balance.Cmp(acc.balance) != 0 { 92 t.Errorf("account %d: balance mismatch: have %v, want %v", i, balance, acc.balance) 93 } 94 if nonce := state.GetNonce(acc.address); nonce != acc.nonce { 95 t.Errorf("account %d: nonce mismatch: have %v, want %v", i, nonce, acc.nonce) 96 } 97 if code := state.GetCode(acc.address); !bytes.Equal(code, acc.code) { 98 t.Errorf("account %d: code mismatch: have %x, want %x", i, code, acc.code) 99 } 100 } 101 } 102 103 // checkTrieConsistency checks that all nodes in a (sub-)trie are indeed present. 104 func checkTrieConsistency(db ethdb.Database, root common.Hash) error { 105 if v, _ := db.Get(root[:]); v == nil { 106 return nil // Consider a non existent state consistent. 107 } 108 trie, err := trie.New(trie.StateTrieID(root), trie.NewDatabase(db)) 109 if err != nil { 110 return err 111 } 112 it := trie.NodeIterator(nil) 113 for it.Next(true) { 114 } 115 return it.Error() 116 } 117 118 // checkStateConsistency checks that all data of a state root is present. 119 func checkStateConsistency(db ethdb.Database, root common.Hash) error { 120 // Create and iterate a state trie rooted in a sub-node 121 if _, err := db.Get(root.Bytes()); err != nil { 122 return nil // Consider a non existent state consistent. 123 } 124 state, err := New(root, NewDatabase(db), nil) 125 if err != nil { 126 return err 127 } 128 it := NewNodeIterator(state) 129 for it.Next() { 130 } 131 return it.Error 132 } 133 134 // Tests that an empty state is not scheduled for syncing. 135 func TestEmptyStateSync(t *testing.T) { 136 db := trie.NewDatabase(rawdb.NewMemoryDatabase()) 137 sync := NewStateSync(types.EmptyRootHash, rawdb.NewMemoryDatabase(), nil, db.Scheme()) 138 if paths, nodes, codes := sync.Missing(1); len(paths) != 0 || len(nodes) != 0 || len(codes) != 0 { 139 t.Errorf("content requested for empty state: %v, %v, %v", nodes, paths, codes) 140 } 141 } 142 143 // Tests that given a root hash, a state can sync iteratively on a single thread, 144 // requesting retrieval tasks and returning all of them in one go. 145 func TestIterativeStateSyncIndividual(t *testing.T) { 146 testIterativeStateSync(t, 1, false, false) 147 } 148 func TestIterativeStateSyncBatched(t *testing.T) { 149 testIterativeStateSync(t, 100, false, false) 150 } 151 func TestIterativeStateSyncIndividualFromDisk(t *testing.T) { 152 testIterativeStateSync(t, 1, true, false) 153 } 154 func TestIterativeStateSyncBatchedFromDisk(t *testing.T) { 155 testIterativeStateSync(t, 100, true, false) 156 } 157 func TestIterativeStateSyncIndividualByPath(t *testing.T) { 158 testIterativeStateSync(t, 1, false, true) 159 } 160 func TestIterativeStateSyncBatchedByPath(t *testing.T) { 161 testIterativeStateSync(t, 100, false, true) 162 } 163 164 // stateElement represents the element in the state trie(bytecode or trie node). 165 type stateElement struct { 166 path string 167 hash common.Hash 168 code common.Hash 169 syncPath trie.SyncPath 170 } 171 172 func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { 173 // Create a random state to copy 174 _, srcDb, srcRoot, srcAccounts := makeTestState() 175 if commit { 176 srcDb.TrieDB().Commit(srcRoot, false) 177 } 178 srcTrie, _ := trie.New(trie.StateTrieID(srcRoot), srcDb.TrieDB()) 179 180 // Create a destination state and sync with the scheduler 181 dstDb := rawdb.NewMemoryDatabase() 182 sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) 183 184 var ( 185 nodeElements []stateElement 186 codeElements []stateElement 187 ) 188 paths, nodes, codes := sched.Missing(count) 189 for i := 0; i < len(paths); i++ { 190 nodeElements = append(nodeElements, stateElement{ 191 path: paths[i], 192 hash: nodes[i], 193 syncPath: trie.NewSyncPath([]byte(paths[i])), 194 }) 195 } 196 for i := 0; i < len(codes); i++ { 197 codeElements = append(codeElements, stateElement{ 198 code: codes[i], 199 }) 200 } 201 for len(nodeElements)+len(codeElements) > 0 { 202 var ( 203 nodeResults = make([]trie.NodeSyncResult, len(nodeElements)) 204 codeResults = make([]trie.CodeSyncResult, len(codeElements)) 205 ) 206 for i, element := range codeElements { 207 data, err := srcDb.ContractCode(common.Hash{}, element.code) 208 if err != nil { 209 t.Fatalf("failed to retrieve contract bytecode for hash %x", element.code) 210 } 211 codeResults[i] = trie.CodeSyncResult{Hash: element.code, Data: data} 212 } 213 for i, node := range nodeElements { 214 if bypath { 215 if len(node.syncPath) == 1 { 216 data, _, err := srcTrie.TryGetNode(node.syncPath[0]) 217 if err != nil { 218 t.Fatalf("failed to retrieve node data for path %x: %v", node.syncPath[0], err) 219 } 220 nodeResults[i] = trie.NodeSyncResult{Path: node.path, Data: data} 221 } else { 222 var acc types.StateAccount 223 if err := rlp.DecodeBytes(srcTrie.Get(node.syncPath[0]), &acc); err != nil { 224 t.Fatalf("failed to decode account on path %x: %v", node.syncPath[0], err) 225 } 226 id := trie.StorageTrieID(srcRoot, common.BytesToHash(node.syncPath[0]), acc.Root) 227 stTrie, err := trie.New(id, srcDb.TrieDB()) 228 if err != nil { 229 t.Fatalf("failed to retriev storage trie for path %x: %v", node.syncPath[1], err) 230 } 231 data, _, err := stTrie.TryGetNode(node.syncPath[1]) 232 if err != nil { 233 t.Fatalf("failed to retrieve node data for path %x: %v", node.syncPath[1], err) 234 } 235 nodeResults[i] = trie.NodeSyncResult{Path: node.path, Data: data} 236 } 237 } else { 238 data, err := srcDb.TrieDB().Node(node.hash) 239 if err != nil { 240 t.Fatalf("failed to retrieve node data for key %v", []byte(node.path)) 241 } 242 nodeResults[i] = trie.NodeSyncResult{Path: node.path, Data: data} 243 } 244 } 245 for _, result := range codeResults { 246 if err := sched.ProcessCode(result); err != nil { 247 t.Errorf("failed to process result %v", err) 248 } 249 } 250 for _, result := range nodeResults { 251 if err := sched.ProcessNode(result); err != nil { 252 t.Errorf("failed to process result %v", err) 253 } 254 } 255 batch := dstDb.NewBatch() 256 if err := sched.Commit(batch); err != nil { 257 t.Fatalf("failed to commit data: %v", err) 258 } 259 batch.Write() 260 261 paths, nodes, codes = sched.Missing(count) 262 nodeElements = nodeElements[:0] 263 for i := 0; i < len(paths); i++ { 264 nodeElements = append(nodeElements, stateElement{ 265 path: paths[i], 266 hash: nodes[i], 267 syncPath: trie.NewSyncPath([]byte(paths[i])), 268 }) 269 } 270 codeElements = codeElements[:0] 271 for i := 0; i < len(codes); i++ { 272 codeElements = append(codeElements, stateElement{ 273 code: codes[i], 274 }) 275 } 276 } 277 // Cross check that the two states are in sync 278 checkStateAccounts(t, dstDb, srcRoot, srcAccounts) 279 } 280 281 // Tests that the trie scheduler can correctly reconstruct the state even if only 282 // partial results are returned, and the others sent only later. 283 func TestIterativeDelayedStateSync(t *testing.T) { 284 // Create a random state to copy 285 _, srcDb, srcRoot, srcAccounts := makeTestState() 286 287 // Create a destination state and sync with the scheduler 288 dstDb := rawdb.NewMemoryDatabase() 289 sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) 290 291 var ( 292 nodeElements []stateElement 293 codeElements []stateElement 294 ) 295 paths, nodes, codes := sched.Missing(0) 296 for i := 0; i < len(paths); i++ { 297 nodeElements = append(nodeElements, stateElement{ 298 path: paths[i], 299 hash: nodes[i], 300 syncPath: trie.NewSyncPath([]byte(paths[i])), 301 }) 302 } 303 for i := 0; i < len(codes); i++ { 304 codeElements = append(codeElements, stateElement{ 305 code: codes[i], 306 }) 307 } 308 for len(nodeElements)+len(codeElements) > 0 { 309 // Sync only half of the scheduled nodes 310 var nodeProcessed int 311 var codeProcessed int 312 if len(codeElements) > 0 { 313 codeResults := make([]trie.CodeSyncResult, len(codeElements)/2+1) 314 for i, element := range codeElements[:len(codeResults)] { 315 data, err := srcDb.ContractCode(common.Hash{}, element.code) 316 if err != nil { 317 t.Fatalf("failed to retrieve contract bytecode for %x", element.code) 318 } 319 codeResults[i] = trie.CodeSyncResult{Hash: element.code, Data: data} 320 } 321 for _, result := range codeResults { 322 if err := sched.ProcessCode(result); err != nil { 323 t.Fatalf("failed to process result %v", err) 324 } 325 } 326 codeProcessed = len(codeResults) 327 } 328 if len(nodeElements) > 0 { 329 nodeResults := make([]trie.NodeSyncResult, len(nodeElements)/2+1) 330 for i, element := range nodeElements[:len(nodeResults)] { 331 data, err := srcDb.TrieDB().Node(element.hash) 332 if err != nil { 333 t.Fatalf("failed to retrieve contract bytecode for %x", element.code) 334 } 335 nodeResults[i] = trie.NodeSyncResult{Path: element.path, Data: data} 336 } 337 for _, result := range nodeResults { 338 if err := sched.ProcessNode(result); err != nil { 339 t.Fatalf("failed to process result %v", err) 340 } 341 } 342 nodeProcessed = len(nodeResults) 343 } 344 batch := dstDb.NewBatch() 345 if err := sched.Commit(batch); err != nil { 346 t.Fatalf("failed to commit data: %v", err) 347 } 348 batch.Write() 349 350 paths, nodes, codes = sched.Missing(0) 351 nodeElements = nodeElements[nodeProcessed:] 352 for i := 0; i < len(paths); i++ { 353 nodeElements = append(nodeElements, stateElement{ 354 path: paths[i], 355 hash: nodes[i], 356 syncPath: trie.NewSyncPath([]byte(paths[i])), 357 }) 358 } 359 codeElements = codeElements[codeProcessed:] 360 for i := 0; i < len(codes); i++ { 361 codeElements = append(codeElements, stateElement{ 362 code: codes[i], 363 }) 364 } 365 } 366 // Cross check that the two states are in sync 367 checkStateAccounts(t, dstDb, srcRoot, srcAccounts) 368 } 369 370 // Tests that given a root hash, a trie can sync iteratively on a single thread, 371 // requesting retrieval tasks and returning all of them in one go, however in a 372 // random order. 373 func TestIterativeRandomStateSyncIndividual(t *testing.T) { testIterativeRandomStateSync(t, 1) } 374 func TestIterativeRandomStateSyncBatched(t *testing.T) { testIterativeRandomStateSync(t, 100) } 375 376 func testIterativeRandomStateSync(t *testing.T, count int) { 377 // Create a random state to copy 378 _, srcDb, srcRoot, srcAccounts := makeTestState() 379 380 // Create a destination state and sync with the scheduler 381 dstDb := rawdb.NewMemoryDatabase() 382 sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) 383 384 nodeQueue := make(map[string]stateElement) 385 codeQueue := make(map[common.Hash]struct{}) 386 paths, nodes, codes := sched.Missing(count) 387 for i, path := range paths { 388 nodeQueue[path] = stateElement{ 389 path: path, 390 hash: nodes[i], 391 syncPath: trie.NewSyncPath([]byte(path)), 392 } 393 } 394 for _, hash := range codes { 395 codeQueue[hash] = struct{}{} 396 } 397 for len(nodeQueue)+len(codeQueue) > 0 { 398 // Fetch all the queued nodes in a random order 399 if len(codeQueue) > 0 { 400 results := make([]trie.CodeSyncResult, 0, len(codeQueue)) 401 for hash := range codeQueue { 402 data, err := srcDb.ContractCode(common.Hash{}, hash) 403 if err != nil { 404 t.Fatalf("failed to retrieve node data for %x", hash) 405 } 406 results = append(results, trie.CodeSyncResult{Hash: hash, Data: data}) 407 } 408 for _, result := range results { 409 if err := sched.ProcessCode(result); err != nil { 410 t.Fatalf("failed to process result %v", err) 411 } 412 } 413 } 414 if len(nodeQueue) > 0 { 415 results := make([]trie.NodeSyncResult, 0, len(nodeQueue)) 416 for path, element := range nodeQueue { 417 data, err := srcDb.TrieDB().Node(element.hash) 418 if err != nil { 419 t.Fatalf("failed to retrieve node data for %x %v %v", element.hash, []byte(element.path), element.path) 420 } 421 results = append(results, trie.NodeSyncResult{Path: path, Data: data}) 422 } 423 for _, result := range results { 424 if err := sched.ProcessNode(result); err != nil { 425 t.Fatalf("failed to process result %v", err) 426 } 427 } 428 } 429 // Feed the retrieved results back and queue new tasks 430 batch := dstDb.NewBatch() 431 if err := sched.Commit(batch); err != nil { 432 t.Fatalf("failed to commit data: %v", err) 433 } 434 batch.Write() 435 436 nodeQueue = make(map[string]stateElement) 437 codeQueue = make(map[common.Hash]struct{}) 438 paths, nodes, codes := sched.Missing(count) 439 for i, path := range paths { 440 nodeQueue[path] = stateElement{ 441 path: path, 442 hash: nodes[i], 443 syncPath: trie.NewSyncPath([]byte(path)), 444 } 445 } 446 for _, hash := range codes { 447 codeQueue[hash] = struct{}{} 448 } 449 } 450 // Cross check that the two states are in sync 451 checkStateAccounts(t, dstDb, srcRoot, srcAccounts) 452 } 453 454 // Tests that the trie scheduler can correctly reconstruct the state even if only 455 // partial results are returned (Even those randomly), others sent only later. 456 func TestIterativeRandomDelayedStateSync(t *testing.T) { 457 // Create a random state to copy 458 _, srcDb, srcRoot, srcAccounts := makeTestState() 459 460 // Create a destination state and sync with the scheduler 461 dstDb := rawdb.NewMemoryDatabase() 462 sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) 463 464 nodeQueue := make(map[string]stateElement) 465 codeQueue := make(map[common.Hash]struct{}) 466 paths, nodes, codes := sched.Missing(0) 467 for i, path := range paths { 468 nodeQueue[path] = stateElement{ 469 path: path, 470 hash: nodes[i], 471 syncPath: trie.NewSyncPath([]byte(path)), 472 } 473 } 474 for _, hash := range codes { 475 codeQueue[hash] = struct{}{} 476 } 477 for len(nodeQueue)+len(codeQueue) > 0 { 478 // Sync only half of the scheduled nodes, even those in random order 479 if len(codeQueue) > 0 { 480 results := make([]trie.CodeSyncResult, 0, len(codeQueue)/2+1) 481 for hash := range codeQueue { 482 delete(codeQueue, hash) 483 484 data, err := srcDb.ContractCode(common.Hash{}, hash) 485 if err != nil { 486 t.Fatalf("failed to retrieve node data for %x", hash) 487 } 488 results = append(results, trie.CodeSyncResult{Hash: hash, Data: data}) 489 490 if len(results) >= cap(results) { 491 break 492 } 493 } 494 for _, result := range results { 495 if err := sched.ProcessCode(result); err != nil { 496 t.Fatalf("failed to process result %v", err) 497 } 498 } 499 } 500 if len(nodeQueue) > 0 { 501 results := make([]trie.NodeSyncResult, 0, len(nodeQueue)/2+1) 502 for path, element := range nodeQueue { 503 delete(nodeQueue, path) 504 505 data, err := srcDb.TrieDB().Node(element.hash) 506 if err != nil { 507 t.Fatalf("failed to retrieve node data for %x", element.hash) 508 } 509 results = append(results, trie.NodeSyncResult{Path: path, Data: data}) 510 511 if len(results) >= cap(results) { 512 break 513 } 514 } 515 // Feed the retrieved results back and queue new tasks 516 for _, result := range results { 517 if err := sched.ProcessNode(result); err != nil { 518 t.Fatalf("failed to process result %v", err) 519 } 520 } 521 } 522 batch := dstDb.NewBatch() 523 if err := sched.Commit(batch); err != nil { 524 t.Fatalf("failed to commit data: %v", err) 525 } 526 batch.Write() 527 528 paths, nodes, codes := sched.Missing(0) 529 for i, path := range paths { 530 nodeQueue[path] = stateElement{ 531 path: path, 532 hash: nodes[i], 533 syncPath: trie.NewSyncPath([]byte(path)), 534 } 535 } 536 for _, hash := range codes { 537 codeQueue[hash] = struct{}{} 538 } 539 } 540 // Cross check that the two states are in sync 541 checkStateAccounts(t, dstDb, srcRoot, srcAccounts) 542 } 543 544 // Tests that at any point in time during a sync, only complete sub-tries are in 545 // the database. 546 func TestIncompleteStateSync(t *testing.T) { 547 // Create a random state to copy 548 db, srcDb, srcRoot, srcAccounts := makeTestState() 549 550 // isCodeLookup to save some hashing 551 var isCode = make(map[common.Hash]struct{}) 552 for _, acc := range srcAccounts { 553 if len(acc.code) > 0 { 554 isCode[crypto.Keccak256Hash(acc.code)] = struct{}{} 555 } 556 } 557 isCode[types.EmptyCodeHash] = struct{}{} 558 checkTrieConsistency(db, srcRoot) 559 560 // Create a destination state and sync with the scheduler 561 dstDb := rawdb.NewMemoryDatabase() 562 sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) 563 564 var ( 565 addedCodes []common.Hash 566 addedPaths []string 567 addedHashes []common.Hash 568 ) 569 nodeQueue := make(map[string]stateElement) 570 codeQueue := make(map[common.Hash]struct{}) 571 paths, nodes, codes := sched.Missing(1) 572 for i, path := range paths { 573 nodeQueue[path] = stateElement{ 574 path: path, 575 hash: nodes[i], 576 syncPath: trie.NewSyncPath([]byte(path)), 577 } 578 } 579 for _, hash := range codes { 580 codeQueue[hash] = struct{}{} 581 } 582 for len(nodeQueue)+len(codeQueue) > 0 { 583 // Fetch a batch of state nodes 584 if len(codeQueue) > 0 { 585 results := make([]trie.CodeSyncResult, 0, len(codeQueue)) 586 for hash := range codeQueue { 587 data, err := srcDb.ContractCode(common.Hash{}, hash) 588 if err != nil { 589 t.Fatalf("failed to retrieve node data for %x", hash) 590 } 591 results = append(results, trie.CodeSyncResult{Hash: hash, Data: data}) 592 addedCodes = append(addedCodes, hash) 593 } 594 // Process each of the state nodes 595 for _, result := range results { 596 if err := sched.ProcessCode(result); err != nil { 597 t.Fatalf("failed to process result %v", err) 598 } 599 } 600 } 601 var nodehashes []common.Hash 602 if len(nodeQueue) > 0 { 603 results := make([]trie.NodeSyncResult, 0, len(nodeQueue)) 604 for path, element := range nodeQueue { 605 data, err := srcDb.TrieDB().Node(element.hash) 606 if err != nil { 607 t.Fatalf("failed to retrieve node data for %x", element.hash) 608 } 609 results = append(results, trie.NodeSyncResult{Path: path, Data: data}) 610 611 if element.hash != srcRoot { 612 addedPaths = append(addedPaths, element.path) 613 addedHashes = append(addedHashes, element.hash) 614 } 615 nodehashes = append(nodehashes, element.hash) 616 } 617 // Process each of the state nodes 618 for _, result := range results { 619 if err := sched.ProcessNode(result); err != nil { 620 t.Fatalf("failed to process result %v", err) 621 } 622 } 623 } 624 batch := dstDb.NewBatch() 625 if err := sched.Commit(batch); err != nil { 626 t.Fatalf("failed to commit data: %v", err) 627 } 628 batch.Write() 629 630 for _, root := range nodehashes { 631 // Can't use checkStateConsistency here because subtrie keys may have odd 632 // length and crash in LeafKey. 633 if err := checkTrieConsistency(dstDb, root); err != nil { 634 t.Fatalf("state inconsistent: %v", err) 635 } 636 } 637 // Fetch the next batch to retrieve 638 nodeQueue = make(map[string]stateElement) 639 codeQueue = make(map[common.Hash]struct{}) 640 paths, nodes, codes := sched.Missing(1) 641 for i, path := range paths { 642 nodeQueue[path] = stateElement{ 643 path: path, 644 hash: nodes[i], 645 syncPath: trie.NewSyncPath([]byte(path)), 646 } 647 } 648 for _, hash := range codes { 649 codeQueue[hash] = struct{}{} 650 } 651 } 652 // Sanity check that removing any node from the database is detected 653 for _, node := range addedCodes { 654 val := rawdb.ReadCode(dstDb, node) 655 rawdb.DeleteCode(dstDb, node) 656 if err := checkStateConsistency(dstDb, srcRoot); err == nil { 657 t.Errorf("trie inconsistency not caught, missing: %x", node) 658 } 659 rawdb.WriteCode(dstDb, node, val) 660 } 661 scheme := srcDb.TrieDB().Scheme() 662 for i, path := range addedPaths { 663 owner, inner := trie.ResolvePath([]byte(path)) 664 hash := addedHashes[i] 665 val := rawdb.ReadTrieNode(dstDb, owner, inner, hash, scheme) 666 if val == nil { 667 t.Error("missing trie node") 668 } 669 rawdb.DeleteTrieNode(dstDb, owner, inner, hash, scheme) 670 if err := checkStateConsistency(dstDb, srcRoot); err == nil { 671 t.Errorf("trie inconsistency not caught, missing: %v", path) 672 } 673 rawdb.WriteTrieNode(dstDb, owner, inner, hash, val, scheme) 674 } 675 }