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