github.com/tirogen/go-ethereum@v1.10.12-0.20221226051715-250cfede41b6/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/tirogen/go-ethereum/common" 25 "github.com/tirogen/go-ethereum/core/rawdb" 26 "github.com/tirogen/go-ethereum/core/types" 27 "github.com/tirogen/go-ethereum/crypto" 28 "github.com/tirogen/go-ethereum/ethdb" 29 "github.com/tirogen/go-ethereum/rlp" 30 "github.com/tirogen/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 empty := common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") 138 sync := NewStateSync(empty, rawdb.NewMemoryDatabase(), nil, db.Scheme()) 139 if paths, nodes, codes := sync.Missing(1); len(paths) != 0 || len(nodes) != 0 || len(codes) != 0 { 140 t.Errorf("content requested for empty state: %v, %v, %v", nodes, paths, codes) 141 } 142 } 143 144 // Tests that given a root hash, a state can sync iteratively on a single thread, 145 // requesting retrieval tasks and returning all of them in one go. 146 func TestIterativeStateSyncIndividual(t *testing.T) { 147 testIterativeStateSync(t, 1, false, false) 148 } 149 func TestIterativeStateSyncBatched(t *testing.T) { 150 testIterativeStateSync(t, 100, false, false) 151 } 152 func TestIterativeStateSyncIndividualFromDisk(t *testing.T) { 153 testIterativeStateSync(t, 1, true, false) 154 } 155 func TestIterativeStateSyncBatchedFromDisk(t *testing.T) { 156 testIterativeStateSync(t, 100, true, false) 157 } 158 func TestIterativeStateSyncIndividualByPath(t *testing.T) { 159 testIterativeStateSync(t, 1, false, true) 160 } 161 func TestIterativeStateSyncBatchedByPath(t *testing.T) { 162 testIterativeStateSync(t, 100, false, true) 163 } 164 165 // stateElement represents the element in the state trie(bytecode or trie node). 166 type stateElement struct { 167 path string 168 hash common.Hash 169 code common.Hash 170 syncPath trie.SyncPath 171 } 172 173 func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { 174 // Create a random state to copy 175 _, srcDb, srcRoot, srcAccounts := makeTestState() 176 if commit { 177 srcDb.TrieDB().Commit(srcRoot, false, nil) 178 } 179 srcTrie, _ := trie.New(trie.StateTrieID(srcRoot), srcDb.TrieDB()) 180 181 // Create a destination state and sync with the scheduler 182 dstDb := rawdb.NewMemoryDatabase() 183 sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) 184 185 var ( 186 nodeElements []stateElement 187 codeElements []stateElement 188 ) 189 paths, nodes, codes := sched.Missing(count) 190 for i := 0; i < len(paths); i++ { 191 nodeElements = append(nodeElements, stateElement{ 192 path: paths[i], 193 hash: nodes[i], 194 syncPath: trie.NewSyncPath([]byte(paths[i])), 195 }) 196 } 197 for i := 0; i < len(codes); i++ { 198 codeElements = append(codeElements, stateElement{ 199 code: codes[i], 200 }) 201 } 202 for len(nodeElements)+len(codeElements) > 0 { 203 var ( 204 nodeResults = make([]trie.NodeSyncResult, len(nodeElements)) 205 codeResults = make([]trie.CodeSyncResult, len(codeElements)) 206 ) 207 for i, element := range codeElements { 208 data, err := srcDb.ContractCode(common.Hash{}, element.code) 209 if err != nil { 210 t.Fatalf("failed to retrieve contract bytecode for hash %x", element.code) 211 } 212 codeResults[i] = trie.CodeSyncResult{Hash: element.code, Data: data} 213 } 214 for i, node := range nodeElements { 215 if bypath { 216 if len(node.syncPath) == 1 { 217 data, _, err := srcTrie.TryGetNode(node.syncPath[0]) 218 if err != nil { 219 t.Fatalf("failed to retrieve node data for path %x: %v", node.syncPath[0], err) 220 } 221 nodeResults[i] = trie.NodeSyncResult{Path: node.path, Data: data} 222 } else { 223 var acc types.StateAccount 224 if err := rlp.DecodeBytes(srcTrie.Get(node.syncPath[0]), &acc); err != nil { 225 t.Fatalf("failed to decode account on path %x: %v", node.syncPath[0], err) 226 } 227 id := trie.StorageTrieID(srcRoot, common.BytesToHash(node.syncPath[0]), acc.Root) 228 stTrie, err := trie.New(id, srcDb.TrieDB()) 229 if err != nil { 230 t.Fatalf("failed to retriev storage trie for path %x: %v", node.syncPath[1], err) 231 } 232 data, _, err := stTrie.TryGetNode(node.syncPath[1]) 233 if err != nil { 234 t.Fatalf("failed to retrieve node data for path %x: %v", node.syncPath[1], err) 235 } 236 nodeResults[i] = trie.NodeSyncResult{Path: node.path, Data: data} 237 } 238 } else { 239 data, err := srcDb.TrieDB().Node(node.hash) 240 if err != nil { 241 t.Fatalf("failed to retrieve node data for key %v", []byte(node.path)) 242 } 243 nodeResults[i] = trie.NodeSyncResult{Path: node.path, Data: data} 244 } 245 } 246 for _, result := range codeResults { 247 if err := sched.ProcessCode(result); err != nil { 248 t.Errorf("failed to process result %v", err) 249 } 250 } 251 for _, result := range nodeResults { 252 if err := sched.ProcessNode(result); err != nil { 253 t.Errorf("failed to process result %v", err) 254 } 255 } 256 batch := dstDb.NewBatch() 257 if err := sched.Commit(batch); err != nil { 258 t.Fatalf("failed to commit data: %v", err) 259 } 260 batch.Write() 261 262 paths, nodes, codes = sched.Missing(count) 263 nodeElements = nodeElements[:0] 264 for i := 0; i < len(paths); i++ { 265 nodeElements = append(nodeElements, stateElement{ 266 path: paths[i], 267 hash: nodes[i], 268 syncPath: trie.NewSyncPath([]byte(paths[i])), 269 }) 270 } 271 codeElements = codeElements[:0] 272 for i := 0; i < len(codes); i++ { 273 codeElements = append(codeElements, stateElement{ 274 code: codes[i], 275 }) 276 } 277 } 278 // Cross check that the two states are in sync 279 checkStateAccounts(t, dstDb, srcRoot, srcAccounts) 280 } 281 282 // Tests that the trie scheduler can correctly reconstruct the state even if only 283 // partial results are returned, and the others sent only later. 284 func TestIterativeDelayedStateSync(t *testing.T) { 285 // Create a random state to copy 286 _, srcDb, srcRoot, srcAccounts := makeTestState() 287 288 // Create a destination state and sync with the scheduler 289 dstDb := rawdb.NewMemoryDatabase() 290 sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) 291 292 var ( 293 nodeElements []stateElement 294 codeElements []stateElement 295 ) 296 paths, nodes, codes := sched.Missing(0) 297 for i := 0; i < len(paths); i++ { 298 nodeElements = append(nodeElements, stateElement{ 299 path: paths[i], 300 hash: nodes[i], 301 syncPath: trie.NewSyncPath([]byte(paths[i])), 302 }) 303 } 304 for i := 0; i < len(codes); i++ { 305 codeElements = append(codeElements, stateElement{ 306 code: codes[i], 307 }) 308 } 309 for len(nodeElements)+len(codeElements) > 0 { 310 // Sync only half of the scheduled nodes 311 var nodeProcessed int 312 var codeProcessed int 313 if len(codeElements) > 0 { 314 codeResults := make([]trie.CodeSyncResult, len(codeElements)/2+1) 315 for i, element := range codeElements[:len(codeResults)] { 316 data, err := srcDb.ContractCode(common.Hash{}, element.code) 317 if err != nil { 318 t.Fatalf("failed to retrieve contract bytecode for %x", element.code) 319 } 320 codeResults[i] = trie.CodeSyncResult{Hash: element.code, Data: data} 321 } 322 for _, result := range codeResults { 323 if err := sched.ProcessCode(result); err != nil { 324 t.Fatalf("failed to process result %v", err) 325 } 326 } 327 codeProcessed = len(codeResults) 328 } 329 if len(nodeElements) > 0 { 330 nodeResults := make([]trie.NodeSyncResult, len(nodeElements)/2+1) 331 for i, element := range nodeElements[:len(nodeResults)] { 332 data, err := srcDb.TrieDB().Node(element.hash) 333 if err != nil { 334 t.Fatalf("failed to retrieve contract bytecode for %x", element.code) 335 } 336 nodeResults[i] = trie.NodeSyncResult{Path: element.path, Data: data} 337 } 338 for _, result := range nodeResults { 339 if err := sched.ProcessNode(result); err != nil { 340 t.Fatalf("failed to process result %v", err) 341 } 342 } 343 nodeProcessed = len(nodeResults) 344 } 345 batch := dstDb.NewBatch() 346 if err := sched.Commit(batch); err != nil { 347 t.Fatalf("failed to commit data: %v", err) 348 } 349 batch.Write() 350 351 paths, nodes, codes = sched.Missing(0) 352 nodeElements = nodeElements[nodeProcessed:] 353 for i := 0; i < len(paths); i++ { 354 nodeElements = append(nodeElements, stateElement{ 355 path: paths[i], 356 hash: nodes[i], 357 syncPath: trie.NewSyncPath([]byte(paths[i])), 358 }) 359 } 360 codeElements = codeElements[codeProcessed:] 361 for i := 0; i < len(codes); i++ { 362 codeElements = append(codeElements, stateElement{ 363 code: codes[i], 364 }) 365 } 366 } 367 // Cross check that the two states are in sync 368 checkStateAccounts(t, dstDb, srcRoot, srcAccounts) 369 } 370 371 // Tests that given a root hash, a trie can sync iteratively on a single thread, 372 // requesting retrieval tasks and returning all of them in one go, however in a 373 // random order. 374 func TestIterativeRandomStateSyncIndividual(t *testing.T) { testIterativeRandomStateSync(t, 1) } 375 func TestIterativeRandomStateSyncBatched(t *testing.T) { testIterativeRandomStateSync(t, 100) } 376 377 func testIterativeRandomStateSync(t *testing.T, count int) { 378 // Create a random state to copy 379 _, srcDb, srcRoot, srcAccounts := makeTestState() 380 381 // Create a destination state and sync with the scheduler 382 dstDb := rawdb.NewMemoryDatabase() 383 sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) 384 385 nodeQueue := make(map[string]stateElement) 386 codeQueue := make(map[common.Hash]struct{}) 387 paths, nodes, codes := sched.Missing(count) 388 for i, path := range paths { 389 nodeQueue[path] = stateElement{ 390 path: path, 391 hash: nodes[i], 392 syncPath: trie.NewSyncPath([]byte(path)), 393 } 394 } 395 for _, hash := range codes { 396 codeQueue[hash] = struct{}{} 397 } 398 for len(nodeQueue)+len(codeQueue) > 0 { 399 // Fetch all the queued nodes in a random order 400 if len(codeQueue) > 0 { 401 results := make([]trie.CodeSyncResult, 0, len(codeQueue)) 402 for hash := range codeQueue { 403 data, err := srcDb.ContractCode(common.Hash{}, hash) 404 if err != nil { 405 t.Fatalf("failed to retrieve node data for %x", hash) 406 } 407 results = append(results, trie.CodeSyncResult{Hash: hash, Data: data}) 408 } 409 for _, result := range results { 410 if err := sched.ProcessCode(result); err != nil { 411 t.Fatalf("failed to process result %v", err) 412 } 413 } 414 } 415 if len(nodeQueue) > 0 { 416 results := make([]trie.NodeSyncResult, 0, len(nodeQueue)) 417 for path, element := range nodeQueue { 418 data, err := srcDb.TrieDB().Node(element.hash) 419 if err != nil { 420 t.Fatalf("failed to retrieve node data for %x %v %v", element.hash, []byte(element.path), element.path) 421 } 422 results = append(results, trie.NodeSyncResult{Path: path, Data: data}) 423 } 424 for _, result := range results { 425 if err := sched.ProcessNode(result); err != nil { 426 t.Fatalf("failed to process result %v", err) 427 } 428 } 429 } 430 // Feed the retrieved results back and queue new tasks 431 batch := dstDb.NewBatch() 432 if err := sched.Commit(batch); err != nil { 433 t.Fatalf("failed to commit data: %v", err) 434 } 435 batch.Write() 436 437 nodeQueue = make(map[string]stateElement) 438 codeQueue = make(map[common.Hash]struct{}) 439 paths, nodes, codes := sched.Missing(count) 440 for i, path := range paths { 441 nodeQueue[path] = stateElement{ 442 path: path, 443 hash: nodes[i], 444 syncPath: trie.NewSyncPath([]byte(path)), 445 } 446 } 447 for _, hash := range codes { 448 codeQueue[hash] = struct{}{} 449 } 450 } 451 // Cross check that the two states are in sync 452 checkStateAccounts(t, dstDb, srcRoot, srcAccounts) 453 } 454 455 // Tests that the trie scheduler can correctly reconstruct the state even if only 456 // partial results are returned (Even those randomly), others sent only later. 457 func TestIterativeRandomDelayedStateSync(t *testing.T) { 458 // Create a random state to copy 459 _, srcDb, srcRoot, srcAccounts := makeTestState() 460 461 // Create a destination state and sync with the scheduler 462 dstDb := rawdb.NewMemoryDatabase() 463 sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) 464 465 nodeQueue := make(map[string]stateElement) 466 codeQueue := make(map[common.Hash]struct{}) 467 paths, nodes, codes := sched.Missing(0) 468 for i, path := range paths { 469 nodeQueue[path] = stateElement{ 470 path: path, 471 hash: nodes[i], 472 syncPath: trie.NewSyncPath([]byte(path)), 473 } 474 } 475 for _, hash := range codes { 476 codeQueue[hash] = struct{}{} 477 } 478 for len(nodeQueue)+len(codeQueue) > 0 { 479 // Sync only half of the scheduled nodes, even those in random order 480 if len(codeQueue) > 0 { 481 results := make([]trie.CodeSyncResult, 0, len(codeQueue)/2+1) 482 for hash := range codeQueue { 483 delete(codeQueue, hash) 484 485 data, err := srcDb.ContractCode(common.Hash{}, hash) 486 if err != nil { 487 t.Fatalf("failed to retrieve node data for %x", hash) 488 } 489 results = append(results, trie.CodeSyncResult{Hash: hash, Data: data}) 490 491 if len(results) >= cap(results) { 492 break 493 } 494 } 495 for _, result := range results { 496 if err := sched.ProcessCode(result); err != nil { 497 t.Fatalf("failed to process result %v", err) 498 } 499 } 500 } 501 if len(nodeQueue) > 0 { 502 results := make([]trie.NodeSyncResult, 0, len(nodeQueue)/2+1) 503 for path, element := range nodeQueue { 504 delete(nodeQueue, path) 505 506 data, err := srcDb.TrieDB().Node(element.hash) 507 if err != nil { 508 t.Fatalf("failed to retrieve node data for %x", element.hash) 509 } 510 results = append(results, trie.NodeSyncResult{Path: path, Data: data}) 511 512 if len(results) >= cap(results) { 513 break 514 } 515 } 516 // Feed the retrieved results back and queue new tasks 517 for _, result := range results { 518 if err := sched.ProcessNode(result); err != nil { 519 t.Fatalf("failed to process result %v", err) 520 } 521 } 522 } 523 batch := dstDb.NewBatch() 524 if err := sched.Commit(batch); err != nil { 525 t.Fatalf("failed to commit data: %v", err) 526 } 527 batch.Write() 528 529 paths, nodes, codes := sched.Missing(0) 530 for i, path := range paths { 531 nodeQueue[path] = stateElement{ 532 path: path, 533 hash: nodes[i], 534 syncPath: trie.NewSyncPath([]byte(path)), 535 } 536 } 537 for _, hash := range codes { 538 codeQueue[hash] = struct{}{} 539 } 540 } 541 // Cross check that the two states are in sync 542 checkStateAccounts(t, dstDb, srcRoot, srcAccounts) 543 } 544 545 // Tests that at any point in time during a sync, only complete sub-tries are in 546 // the database. 547 func TestIncompleteStateSync(t *testing.T) { 548 // Create a random state to copy 549 db, srcDb, srcRoot, srcAccounts := makeTestState() 550 551 // isCodeLookup to save some hashing 552 var isCode = make(map[common.Hash]struct{}) 553 for _, acc := range srcAccounts { 554 if len(acc.code) > 0 { 555 isCode[crypto.Keccak256Hash(acc.code)] = struct{}{} 556 } 557 } 558 isCode[common.BytesToHash(emptyCodeHash)] = struct{}{} 559 checkTrieConsistency(db, srcRoot) 560 561 // Create a destination state and sync with the scheduler 562 dstDb := rawdb.NewMemoryDatabase() 563 sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) 564 565 var ( 566 addedCodes []common.Hash 567 addedPaths []string 568 addedHashes []common.Hash 569 ) 570 nodeQueue := make(map[string]stateElement) 571 codeQueue := make(map[common.Hash]struct{}) 572 paths, nodes, codes := sched.Missing(1) 573 for i, path := range paths { 574 nodeQueue[path] = stateElement{ 575 path: path, 576 hash: nodes[i], 577 syncPath: trie.NewSyncPath([]byte(path)), 578 } 579 } 580 for _, hash := range codes { 581 codeQueue[hash] = struct{}{} 582 } 583 for len(nodeQueue)+len(codeQueue) > 0 { 584 // Fetch a batch of state nodes 585 if len(codeQueue) > 0 { 586 results := make([]trie.CodeSyncResult, 0, len(codeQueue)) 587 for hash := range codeQueue { 588 data, err := srcDb.ContractCode(common.Hash{}, hash) 589 if err != nil { 590 t.Fatalf("failed to retrieve node data for %x", hash) 591 } 592 results = append(results, trie.CodeSyncResult{Hash: hash, Data: data}) 593 addedCodes = append(addedCodes, hash) 594 } 595 // Process each of the state nodes 596 for _, result := range results { 597 if err := sched.ProcessCode(result); err != nil { 598 t.Fatalf("failed to process result %v", err) 599 } 600 } 601 } 602 var nodehashes []common.Hash 603 if len(nodeQueue) > 0 { 604 results := make([]trie.NodeSyncResult, 0, len(nodeQueue)) 605 for path, element := range nodeQueue { 606 data, err := srcDb.TrieDB().Node(element.hash) 607 if err != nil { 608 t.Fatalf("failed to retrieve node data for %x", element.hash) 609 } 610 results = append(results, trie.NodeSyncResult{Path: path, Data: data}) 611 612 if element.hash != srcRoot { 613 addedPaths = append(addedPaths, element.path) 614 addedHashes = append(addedHashes, element.hash) 615 } 616 nodehashes = append(nodehashes, element.hash) 617 } 618 // Process each of the state nodes 619 for _, result := range results { 620 if err := sched.ProcessNode(result); err != nil { 621 t.Fatalf("failed to process result %v", err) 622 } 623 } 624 } 625 batch := dstDb.NewBatch() 626 if err := sched.Commit(batch); err != nil { 627 t.Fatalf("failed to commit data: %v", err) 628 } 629 batch.Write() 630 631 for _, root := range nodehashes { 632 // Can't use checkStateConsistency here because subtrie keys may have odd 633 // length and crash in LeafKey. 634 if err := checkTrieConsistency(dstDb, root); err != nil { 635 t.Fatalf("state inconsistent: %v", err) 636 } 637 } 638 // Fetch the next batch to retrieve 639 nodeQueue = make(map[string]stateElement) 640 codeQueue = make(map[common.Hash]struct{}) 641 paths, nodes, codes := sched.Missing(1) 642 for i, path := range paths { 643 nodeQueue[path] = stateElement{ 644 path: path, 645 hash: nodes[i], 646 syncPath: trie.NewSyncPath([]byte(path)), 647 } 648 } 649 for _, hash := range codes { 650 codeQueue[hash] = struct{}{} 651 } 652 } 653 // Sanity check that removing any node from the database is detected 654 for _, node := range addedCodes { 655 val := rawdb.ReadCode(dstDb, node) 656 rawdb.DeleteCode(dstDb, node) 657 if err := checkStateConsistency(dstDb, srcRoot); err == nil { 658 t.Errorf("trie inconsistency not caught, missing: %x", node) 659 } 660 rawdb.WriteCode(dstDb, node, val) 661 } 662 scheme := srcDb.TrieDB().Scheme() 663 for i, path := range addedPaths { 664 owner, inner := trie.ResolvePath([]byte(path)) 665 hash := addedHashes[i] 666 val := scheme.ReadTrieNode(dstDb, owner, inner, hash) 667 if val == nil { 668 t.Error("missing trie node") 669 } 670 scheme.DeleteTrieNode(dstDb, owner, inner, hash) 671 if err := checkStateConsistency(dstDb, srcRoot); err == nil { 672 t.Errorf("trie inconsistency not caught, missing: %v", path) 673 } 674 scheme.WriteTrieNode(dstDb, owner, inner, hash, val) 675 } 676 }