blockchain: don't rely on BlockHeightByHash for prune height

calculations

Since BlockHeightByHash only returns the heights for blocks that are in
the main chain, when a block that is stale gets pruned, this will cause
an error in the block height lookup and cause an error in block
processing.

Look up the node directly from the index and if the node isn't found,
just skip that node. For utxoCache.lastFlushHash, if that isn't found,
just force a flush.
This commit is contained in:
Calvin Kim 2024-02-15 18:13:52 +09:00
parent a0c9e3b384
commit f2caa8fadc

View file

@ -617,6 +617,7 @@ func (b *BlockChain) InitConsistentState(tip *blockNode, interrupt <-chan struct
// Set the last flush hash as it's the default value of 0s.
s.lastFlushHash = tip.hash
s.lastFlushTime = time.Now()
return err
}
@ -725,22 +726,35 @@ func (b *BlockChain) InitConsistentState(tip *blockNode, interrupt <-chan struct
// Example: if the last flush hash was at height 100 and one of the deleted blocks was at
// height 98, this function will return true.
func (b *BlockChain) flushNeededAfterPrune(deletedBlockHashes []chainhash.Hash) (bool, error) {
lastFlushHeight, err := b.BlockHeightByHash(&b.utxoCache.lastFlushHash)
if err != nil {
return false, err
node := b.index.LookupNode(&b.utxoCache.lastFlushHash)
if node == nil {
// If we couldn't find the node where we last flushed at, have the utxo cache
// flush to be safe and that will set the last flush hash again.
//
// This realistically should never happen as nodes are never deleted from
// the block index. This happening likely means that there's a hardware
// error which is something we can't recover from. The best that we can
// do here is to just force a flush and hope that the newly set
// lastFlushHash doesn't error.
return true, nil
}
lastFlushHeight := node.Height()
// Loop through all the block hashes and find out what the highest block height
// among the deleted hashes is.
highestDeletedHeight := int32(-1)
for _, deletedBlockHash := range deletedBlockHashes {
height, err := b.BlockHeightByHash(&deletedBlockHash)
if err != nil {
return false, err
node := b.index.LookupNode(&deletedBlockHash)
if node == nil {
// If we couldn't find this node, just skip it and try the next
// deleted hash. This might be a corruption in the database
// but there's nothing we can do here to address it except for
// moving onto the next block.
continue
}
if height > highestDeletedHeight {
highestDeletedHeight = height
if node.height > highestDeletedHeight {
highestDeletedHeight = node.height
}
}