core: reset block headers together with header height info
We need to keep the headers information consistent with header batches and headers. This comit fixes the bug with failing blockchain initialization on recovering from state reset interrupted after the second stage (blocks/txs/AERs removal): ``` anna@kiwi:~/Documents/GitProjects/nspcc-dev/neo-go$ ./bin/neo-go db reset -t --height 83000 2022-11-20T16:28:29.437+0300 INFO MaxValidUntilBlockIncrement is not set or wrong, using default value {"MaxValidUntilBlockIncrement": 5760} 2022-11-20T16:28:29.440+0300 INFO restoring blockchain {"version": "0.2.6"} failed to create Blockchain instance: could not initialize blockchain: could not get header 1898cd356a4a2688ed1c6c7ba1fd6ba7d516959d8add3f8dd26232474d4539bd: key not found ```
This commit is contained in:
parent
283da8f599
commit
d67f0df516
2 changed files with 19 additions and 23 deletions
|
@ -672,7 +672,7 @@ func (bc *Blockchain) Reset(height uint32) error {
|
|||
}
|
||||
|
||||
func (bc *Blockchain) resetStateInternal(height uint32, stage stateChangeStage) error {
|
||||
// Cache isn't yet initialized, so retrieve header right from DAO.
|
||||
// Cache isn't yet initialized, so retrieve header height right from DAO.
|
||||
currHeight, err := bc.dao.GetCurrentBlockHeight()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to retrieve current block height: %w", err)
|
||||
|
@ -723,9 +723,10 @@ func (bc *Blockchain) resetStateInternal(height uint32, stage stateChangeStage)
|
|||
fallthrough
|
||||
case stateJumpStarted:
|
||||
bc.log.Info("trying to reset blocks, transactions and AERs")
|
||||
// Remove headers/blocks/transactions/aers from currHeight down to height (not including height itself).
|
||||
for i := height + 1; i <= hHeight; i++ {
|
||||
err := cache.PurgeBlock(bc.headerHashes[i])
|
||||
// Remove blocks/transactions/aers from currHeight down to height (not including height itself).
|
||||
// Keep headers for now, they'll be removed later.
|
||||
for i := height + 1; i <= currHeight; i++ {
|
||||
err := cache.DeleteBlock(bc.GetHeaderHash(int(i)))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error while removing block %d: %w", i, err)
|
||||
}
|
||||
|
@ -836,6 +837,9 @@ func (bc *Blockchain) resetStateInternal(height uint32, stage stateChangeStage)
|
|||
case newStorageItemsAdded:
|
||||
// Reset SYS-prefixed and IX-prefixed information.
|
||||
bc.log.Info("trying to reset headers information")
|
||||
for i := height + 1; i <= hHeight; i++ {
|
||||
cache.PurgeHeader(bc.GetHeaderHash(int(i)))
|
||||
}
|
||||
cache.DeleteHeaderHashes(height+1, headerBatchCount)
|
||||
cache.StoreAsCurrentBlock(b)
|
||||
cache.PutCurrentHeader(b.Hash(), height)
|
||||
|
|
|
@ -759,31 +759,15 @@ func (dao *Simple) StoreAsBlock(block *block.Block, aer1 *state.AppExecResult, a
|
|||
// DeleteBlock removes the block from dao. It's not atomic, so make sure you're
|
||||
// using private MemCached instance here.
|
||||
func (dao *Simple) DeleteBlock(h util.Uint256) error {
|
||||
return dao.deleteBlock(h, true)
|
||||
}
|
||||
|
||||
// PurgeBlock completely removes specified block (or just block header) from dao.
|
||||
// It differs from DeleteBlock in that it removes header anyway. It's not atomic,
|
||||
// so make sure you're using private MemCached instance here.
|
||||
func (dao *Simple) PurgeBlock(h util.Uint256) error {
|
||||
return dao.deleteBlock(h, false)
|
||||
}
|
||||
|
||||
func (dao *Simple) deleteBlock(h util.Uint256, keepHeader bool) error {
|
||||
key := dao.makeExecutableKey(h)
|
||||
|
||||
b, err := dao.getBlock(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if keepHeader {
|
||||
err = dao.storeHeader(key, &b.Header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
dao.Store.Delete(key)
|
||||
err = dao.storeHeader(key, &b.Header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, tx := range b.Transactions {
|
||||
|
@ -801,6 +785,14 @@ func (dao *Simple) deleteBlock(h util.Uint256, keepHeader bool) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// PurgeHeader completely removes specified header from dao. It differs from
|
||||
// DeleteBlock in that it removes header anyway and does nothing except removing
|
||||
// header. It does no checks for header existence.
|
||||
func (dao *Simple) PurgeHeader(h util.Uint256) {
|
||||
key := dao.makeExecutableKey(h)
|
||||
dao.Store.Delete(key)
|
||||
}
|
||||
|
||||
// StoreHeader saves the block header into the store.
|
||||
func (dao *Simple) StoreHeader(h *block.Header) error {
|
||||
return dao.storeHeader(dao.makeExecutableKey(h.Hash()), h)
|
||||
|
|
Loading…
Reference in a new issue