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