From 511eb7fdeac36da9d6576c878a1c8d390b38f1bd Mon Sep 17 00:00:00 2001 From: Chris Geihsler Date: Wed, 13 Apr 2022 22:50:10 -0400 Subject: [PATCH 1/2] Ignore problematic blocks in DisconnectBlock When using checklevel=4, block verification fails because of duplicate coinbase transactions involving blocks 91812 and 91722. There was already a check in place for ConnectBlock to ignore the problematic blocks, but DisconnectBlock did not contain a similar check. This change ignores the blocks where these inconsistencies surface so that block verification will succeed at checklevel=4. --- src/validation.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/validation.cpp b/src/validation.cpp index f4b316f67a..6d87ab88b3 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1837,6 +1837,15 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI return DISCONNECT_FAILED; } + // Ignore blocks that contain transactions which are 'overwritten' by later transactions, + // unless those are already completely spent. + // See https://github.com/bitcoin/bitcoin/issues/22596 for additional information. + // Note: the blocks specified here are different than the ones used in ConnectBlock because DisconnectBlock + // unwinds the blocks in reverse. As a result, the inconsistency is not discovered until the earlier + // blocks with the duplicate coinbase transactions are disconnected. + bool fEnforceBIP30 = !((pindex->nHeight==91722 && pindex->GetBlockHash() == uint256S("0x00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e")) || + (pindex->nHeight==91812 && pindex->GetBlockHash() == uint256S("0x00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f"))); + // undo transactions in reverse order for (int i = block.vtx.size() - 1; i >= 0; i--) { const CTransaction &tx = *(block.vtx[i]); @@ -1850,7 +1859,7 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI COutPoint out(hash, o); Coin coin; bool is_spent = view.SpendCoin(out, &coin); - if (!is_spent || tx.vout[o] != coin.out || pindex->nHeight != coin.nHeight || is_coinbase != coin.fCoinBase) { + if (fEnforceBIP30 && (!is_spent || tx.vout[o] != coin.out || pindex->nHeight != coin.nHeight || is_coinbase != coin.fCoinBase)) { fClean = false; // transaction output mismatch } } From e899d4ca6f44785b6e5481e200a6a9a8d2448612 Mon Sep 17 00:00:00 2001 From: Chris Geihsler Date: Thu, 14 Apr 2022 11:48:19 -0400 Subject: [PATCH 2/2] init: limit bip30 exceptions to coinbase txs Co-authored-by: James O'Beirne --- src/validation.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index 6d87ab88b3..ffad7e8402 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1851,6 +1851,7 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI const CTransaction &tx = *(block.vtx[i]); uint256 hash = tx.GetHash(); bool is_coinbase = tx.IsCoinBase(); + bool is_bip30_exception = (is_coinbase && !fEnforceBIP30); // Check that all outputs are available and match the outputs in the block itself // exactly. @@ -1859,8 +1860,10 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI COutPoint out(hash, o); Coin coin; bool is_spent = view.SpendCoin(out, &coin); - if (fEnforceBIP30 && (!is_spent || tx.vout[o] != coin.out || pindex->nHeight != coin.nHeight || is_coinbase != coin.fCoinBase)) { - fClean = false; // transaction output mismatch + if (!is_spent || tx.vout[o] != coin.out || pindex->nHeight != coin.nHeight || is_coinbase != coin.fCoinBase) { + if (!is_bip30_exception) { + fClean = false; // transaction output mismatch + } } } }