Skip to content

Commit

Permalink
blockchain: in initChainState mark ancestors of best tip as valid if …
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
Roasbeef committed Aug 9, 2018
1 parent cf05f92 commit 4b13e79
Showing 1 changed file with 28 additions and 1 deletion.
29 changes: 28 additions & 1 deletion blockchain/chainio.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)))
Expand All @@ -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
Expand Down

0 comments on commit 4b13e79

Please sign in to comment.