diff --git a/core/blockchain.go b/core/blockchain.go index c6c84535034..f79a108012d 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2324,3 +2324,16 @@ func (bc *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (i _, err := bc.hc.InsertHeaderChain(chain, start, bc.forker) return 0, err } + +// FlushState persists the post-state of a block to disk. +func (bc *BlockChain) FlushState(number uint64) error { + if !bc.chainmu.TryLock() { + return errChainStopped + } + defer bc.chainmu.Unlock() + + triedb := bc.stateCache.TrieDB() + block := bc.GetBlockByNumber(number) + log.Info("Writing cached state to disk", "block", block.Number(), "hash", block.Hash(), "root", block.Root()) + return triedb.Commit(block.Root(), true, nil) +} diff --git a/eth/api.go b/eth/api.go index f81dfa922b7..ad4c68a90fe 100644 --- a/eth/api.go +++ b/eth/api.go @@ -607,3 +607,12 @@ func (api *PrivateDebugAPI) GetAccessibleState(from, to rpc.BlockNumber) (uint64 } return 0, fmt.Errorf("No state found") } + +// FlushState persists the state of a given block to disk. +func (api *PrivateDebugAPI) FlushState(number rpc.BlockNumber) error { + // Genesis, latest and pending not supported + if number.Int64() <= 0 { + return fmt.Errorf("Invalid block number") + } + return api.eth.BlockChain().FlushState(uint64(number.Int64())) +} diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 87bf464157b..a653b118a37 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -471,6 +471,12 @@ web3._extend({ params: 2, inputFormatter:[web3._extend.formatters.inputBlockNumberFormatter, web3._extend.formatters.inputBlockNumberFormatter], }), + new web3._extend.Method({ + name: 'flushState', + call: 'debug_flushState', + params: 1, + inputFormatter:[web3._extend.formatters.inputBlockNumberFormatter], + }), ], properties: [] });