MCPcopy Create free account
hub / github.com/bitcoin/bitcoin / DisconnectBlock

Method DisconnectBlock

src/validation.cpp:2185–2254  ·  view source on GitHub ↗

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. */

Source from the content-addressed store, hash-verified

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. */
2185DisconnectResult 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);

Callers 2

VerifyDBMethod · 0.80

Calls 9

ApplyTxInUndoFunction · 0.85
ReadBlockUndoMethod · 0.80
IsUnspendableMethod · 0.80
SpendCoinMethod · 0.80
sizeMethod · 0.45
GetBlockHashMethod · 0.45
GetHashMethod · 0.45
IsCoinBaseMethod · 0.45
SetBestBlockMethod · 0.45

Tested by

no test coverage detected