From f2caa8fadcb21ab7656975f750f51c4222d64e41 Mon Sep 17 00:00:00 2001 From: Calvin Kim Date: Thu, 15 Feb 2024 18:13:52 +0900 Subject: [PATCH] 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. --- blockchain/utxocache.go | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/blockchain/utxocache.go b/blockchain/utxocache.go index 07dc698a91..3261f057e5 100644 --- a/blockchain/utxocache.go +++ b/blockchain/utxocache.go @@ -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 } }