Undo the effects of this block (with given index) on the UTXO set represented by coins. * When FAILED is returned, view is left in an indeterminate state. */
| 2183 | /** Undo the effects of this block (with given index) on the UTXO set represented by coins. |
| 2184 | * When FAILED is returned, view is left in an indeterminate state. */ |
| 2185 | DisconnectResult Chainstate::DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view) |
| 2186 | { |
| 2187 | AssertLockHeld(::cs_main); |
| 2188 | bool fClean = true; |
| 2189 | |
| 2190 | CBlockUndo blockUndo; |
| 2191 | if (!m_blockman.ReadBlockUndo(blockUndo, *pindex)) { |
| 2192 | LogError("DisconnectBlock(): failure reading undo data\n"); |
| 2193 | return DISCONNECT_FAILED; |
| 2194 | } |
| 2195 | |
| 2196 | if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) { |
| 2197 | LogError("DisconnectBlock(): block and undo data inconsistent\n"); |
| 2198 | return DISCONNECT_FAILED; |
| 2199 | } |
| 2200 | |
| 2201 | // Ignore blocks that contain transactions which are 'overwritten' by later transactions, |
| 2202 | // unless those are already completely spent. |
| 2203 | // See https://github.com/bitcoin/bitcoin/issues/22596 for additional information. |
| 2204 | // Note: the blocks specified here are different than the ones used in ConnectBlock because DisconnectBlock |
| 2205 | // unwinds the blocks in reverse. As a result, the inconsistency is not discovered until the earlier |
| 2206 | // blocks with the duplicate coinbase transactions are disconnected. |
| 2207 | bool fEnforceBIP30 = !((pindex->nHeight==91722 && pindex->GetBlockHash() == uint256{"00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e"}) || |
| 2208 | (pindex->nHeight==91812 && pindex->GetBlockHash() == uint256{"00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f"})); |
| 2209 | |
| 2210 | // undo transactions in reverse order |
| 2211 | for (int i = block.vtx.size() - 1; i >= 0; i--) { |
| 2212 | const CTransaction &tx = *(block.vtx[i]); |
| 2213 | Txid hash = tx.GetHash(); |
| 2214 | bool is_coinbase = tx.IsCoinBase(); |
| 2215 | bool is_bip30_exception = (is_coinbase && !fEnforceBIP30); |
| 2216 | |
| 2217 | // Check that all outputs are available and match the outputs in the block itself |
| 2218 | // exactly. |
| 2219 | for (size_t o = 0; o < tx.vout.size(); o++) { |
| 2220 | if (!tx.vout[o].scriptPubKey.IsUnspendable()) { |
| 2221 | COutPoint out(hash, o); |
| 2222 | Coin coin; |
| 2223 | bool is_spent = view.SpendCoin(out, &coin); |
| 2224 | if (!is_spent || tx.vout[o] != coin.out || pindex->nHeight != coin.nHeight || is_coinbase != coin.IsCoinBase()) { |
| 2225 | if (!is_bip30_exception) { |
| 2226 | fClean = false; // transaction output mismatch |
| 2227 | } |
| 2228 | } |
| 2229 | } |
| 2230 | } |
| 2231 | |
| 2232 | // restore inputs |
| 2233 | if (i > 0) { // not coinbases |
| 2234 | CTxUndo &txundo = blockUndo.vtxundo[i-1]; |
| 2235 | if (txundo.vprevout.size() != tx.vin.size()) { |
| 2236 | LogError("DisconnectBlock(): transaction and undo data inconsistent\n"); |
| 2237 | return DISCONNECT_FAILED; |
| 2238 | } |
| 2239 | for (unsigned int j = tx.vin.size(); j > 0;) { |
| 2240 | --j; |
| 2241 | const COutPoint& out = tx.vin[j].prevout; |
| 2242 | int res = ApplyTxInUndo(std::move(txundo.vprevout[j]), view, out); |
no test coverage detected