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