blockchain: in initChainState mark ancestors of best tip as valid if not marked
In this commit, we add an additional consistency check within the `initChainState` method. It has been observed that at times, a block wil lbe written to disk (as it's valid), but then the block index isn't updated to reflect this. This can cause btcd to fail to do things like serve cfheaders for valid blocks. To partially remedy this, when we're loading in the index, we assume that all ancestors of the current chain tip are valid, and mark them as such. At the very end, we'll flush the index to ensure the state is fully consistent. Typically this will be a noop, as only dirty elements are flushed.
This commit is contained in:
parent
cf05f92c3f
commit
4b13e79691
1 changed files with 28 additions and 1 deletions
|
@ -1128,7 +1128,7 @@ func (b *BlockChain) initChainState() error {
|
|||
}
|
||||
|
||||
// Attempt to load the chain state from the database.
|
||||
return b.db.View(func(dbTx database.Tx) error {
|
||||
err = b.db.View(func(dbTx database.Tx) error {
|
||||
// Fetch the stored chain state from the database metadata.
|
||||
// When it doesn't exist, it means the database hasn't been
|
||||
// initialized for use with chain yet, so break out now to allow
|
||||
|
@ -1221,6 +1221,25 @@ func (b *BlockChain) initChainState() error {
|
|||
return err
|
||||
}
|
||||
|
||||
// As a final consistency check, we'll run through all the
|
||||
// nodes which are ancestors of the current chain tip, and mark
|
||||
// them as valid if they aren't already marked as such. This
|
||||
// is a safe assumption as all the block before the current tip
|
||||
// are valid by definition.
|
||||
for iterNode := tip; iterNode != nil; iterNode = iterNode.parent {
|
||||
// If this isn't already marked as valid in the index, then
|
||||
// we'll mark it as valid now to ensure consistency once
|
||||
// we're up and running.
|
||||
if !iterNode.status.KnownValid() {
|
||||
log.Infof("Block %v (height=%v) ancestor of "+
|
||||
"chain tip not marked as valid, "+
|
||||
"upgrading to valid for consistency",
|
||||
iterNode.hash, iterNode.height)
|
||||
|
||||
b.index.SetStatusFlags(iterNode, statusValid)
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the state related to the best block.
|
||||
blockSize := uint64(len(blockBytes))
|
||||
blockWeight := uint64(GetBlockWeight(btcutil.NewBlock(&block)))
|
||||
|
@ -1230,6 +1249,14 @@ func (b *BlockChain) initChainState() error {
|
|||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// As we might have updated the index after it was loaded, we'll
|
||||
// attempt to flush the index to the DB. This will only result in a
|
||||
// write if the elements are dirty, so it'll usually be a noop.
|
||||
return b.index.flushToDB()
|
||||
}
|
||||
|
||||
// deserializeBlockRow parses a value in the block index bucket into a block
|
||||
|
|
Loading…
Reference in a new issue