computeStateDB retrieves the state database associated with a certain block. If no state is locally available for the given block, a number of blocks are attempted to be reexecuted to generate the desired state.
(block *types.Block, reexec uint64)
| 483 | // If no state is locally available for the given block, a number of blocks are |
| 484 | // attempted to be reexecuted to generate the desired state. |
| 485 | func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (*state.StateDB, error) { |
| 486 | // If we have the state fully available, use that |
| 487 | pubStateDB, err := api.cpc.blockchain.StateAt(block.StateRoot()) |
| 488 | if err == nil { |
| 489 | return pubStateDB, nil |
| 490 | } |
| 491 | // Otherwise try to reexec blocks until we find a state or reach our limit |
| 492 | origin := block.NumberU64() |
| 493 | database := state.NewDatabase(api.cpc.ChainDb()) |
| 494 | |
| 495 | for i := uint64(0); i < reexec; i++ { |
| 496 | block = api.cpc.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1) |
| 497 | if block == nil { |
| 498 | break |
| 499 | } |
| 500 | if pubStateDB, err = state.New(block.StateRoot(), database); err == nil { |
| 501 | break |
| 502 | } |
| 503 | } |
| 504 | if err != nil { |
| 505 | switch err.(type) { |
| 506 | case *trie.MissingNodeError: |
| 507 | return nil, errors.New("required historical state unavailable") |
| 508 | default: |
| 509 | return nil, err |
| 510 | } |
| 511 | } |
| 512 | // State was available at historical point, regenerate |
| 513 | var ( |
| 514 | start = time.Now() |
| 515 | logged time.Time |
| 516 | proot common.Hash |
| 517 | ) |
| 518 | for block.NumberU64() < origin { |
| 519 | // Print progress logs if long enough time elapsed |
| 520 | if time.Since(logged) > 8*time.Second { |
| 521 | log.Info("Regenerating historical state", "block", block.NumberU64()+1, "target", origin, "elapsed", time.Since(start)) |
| 522 | logged = time.Now() |
| 523 | } |
| 524 | // Retrieve the next block to regenerate and process it |
| 525 | if block = api.cpc.blockchain.GetBlockByNumber(block.NumberU64() + 1); block == nil { |
| 526 | return nil, fmt.Errorf("block #%d not found", block.NumberU64()+1) |
| 527 | } |
| 528 | |
| 529 | // TODO: check if below statement is correct. |
| 530 | privStateDB, _ := state.New(core.GetPrivateStateRoot(api.cpc.chainDb, block.StateRoot()), pubStateDB.Database()) |
| 531 | // TODO: pass real remote database. |
| 532 | _, _, _, _, err := api.cpc.blockchain.Processor().Process(block, pubStateDB, privStateDB, nil, vm.Config{}) |
| 533 | if err != nil { |
| 534 | return nil, err |
| 535 | } |
| 536 | // Finalize the state so any modifications are written to the trie |
| 537 | root, err := pubStateDB.Commit(true) |
| 538 | if err != nil { |
| 539 | return nil, err |
| 540 | } |
| 541 | if err := pubStateDB.Reset(root); err != nil { |
| 542 | return nil, err |