Tests that at any point in time during a sync, only complete sub-tries are in the database.
(t *testing.T)
| 289 | // Tests that at any point in time during a sync, only complete sub-tries are in |
| 290 | // the database. |
| 291 | func TestIncompleteStateSync(t *testing.T) { |
| 292 | // Create a random state to copy |
| 293 | srcDb, srcRoot, srcAccounts := makeTestState() |
| 294 | |
| 295 | checkTrieConsistency(srcDb.TrieDB().DiskDB().(database.Database), srcRoot) |
| 296 | |
| 297 | // Create a destination state and sync with the scheduler |
| 298 | dstDb := database.NewMemDatabase() |
| 299 | sched := NewStateSync(srcRoot, dstDb) |
| 300 | |
| 301 | added := []common.Hash{} |
| 302 | queue := append([]common.Hash{}, sched.Missing(1)...) |
| 303 | for len(queue) > 0 { |
| 304 | // Fetch a batch of state nodes |
| 305 | results := make([]trie.SyncResult, len(queue)) |
| 306 | for i, hash := range queue { |
| 307 | data, err := srcDb.TrieDB().Node(hash) |
| 308 | if err != nil { |
| 309 | t.Fatalf("failed to retrieve node data for %x", hash) |
| 310 | } |
| 311 | results[i] = trie.SyncResult{Hash: hash, Data: data} |
| 312 | } |
| 313 | // Process each of the state nodes |
| 314 | if _, index, err := sched.Process(results); err != nil { |
| 315 | t.Fatalf("failed to process result #%d: %v", index, err) |
| 316 | } |
| 317 | if index, err := sched.Commit(dstDb); err != nil { |
| 318 | t.Fatalf("failed to commit data #%d: %v", index, err) |
| 319 | } |
| 320 | for _, result := range results { |
| 321 | added = append(added, result.Hash) |
| 322 | } |
| 323 | // Check that all known sub-tries added so far are complete or missing entirely. |
| 324 | checkSubtries: |
| 325 | for _, hash := range added { |
| 326 | for _, acc := range srcAccounts { |
| 327 | if hash == crypto.Keccak256Hash(acc.code) { |
| 328 | continue checkSubtries // skip trie check of code nodes. |
| 329 | } |
| 330 | } |
| 331 | // Can't use checkStateConsistency here because subtrie keys may have odd |
| 332 | // length and crash in LeafKey. |
| 333 | if err := checkTrieConsistency(dstDb, hash); err != nil { |
| 334 | t.Fatalf("state inconsistent: %v", err) |
| 335 | } |
| 336 | } |
| 337 | // Fetch the next batch to retrieve |
| 338 | queue = append(queue[:0], sched.Missing(1)...) |
| 339 | } |
| 340 | // Sanity check that removing any node from the database is detected |
| 341 | for _, node := range added[1:] { |
| 342 | key := node.Bytes() |
| 343 | value, _ := dstDb.Get(key) |
| 344 | |
| 345 | dstDb.Delete(key) |
| 346 | if err := checkStateConsistency(dstDb, added[0]); err == nil { |
| 347 | t.Fatalf("trie inconsistency not caught, missing: %x", key) |
| 348 | } |
nothing calls this directly
no test coverage detected