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. */
| 1618 | /** Undo the effects of this block (with given index) on the UTXO set represented by coins. |
| 1619 | * When FAILED is returned, view is left in an indeterminate state. */ |
| 1620 | DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view) |
| 1621 | { |
| 1622 | bool fClean = true; |
| 1623 | |
| 1624 | CBlockUndo blockUndo; |
| 1625 | if (!UndoReadFromDisk(blockUndo, pindex)) { |
| 1626 | error("DisconnectBlock(): failure reading undo data"); |
| 1627 | return DISCONNECT_FAILED; |
| 1628 | } |
| 1629 | |
| 1630 | if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) { |
| 1631 | error("DisconnectBlock(): block and undo data inconsistent"); |
| 1632 | return DISCONNECT_FAILED; |
| 1633 | } |
| 1634 | |
| 1635 | // undo transactions in reverse order |
| 1636 | for (int i = block.vtx.size() - 1; i >= 0; i--) { |
| 1637 | const CTransaction &tx = *(block.vtx[i]); |
| 1638 | uint256 hash = tx.GetHash(); |
| 1639 | bool is_coinbase = tx.IsCoinBase(); |
| 1640 | |
| 1641 | // Check that all outputs are available and match the outputs in the block itself |
| 1642 | // exactly. |
| 1643 | for (size_t o = 0; o < tx.vout.size(); o++) { |
| 1644 | if (!tx.vout[o].scriptPubKey.IsUnspendable()) { |
| 1645 | COutPoint out(hash, o); |
| 1646 | Coin coin; |
| 1647 | bool is_spent = view.SpendCoin(out, &coin); |
| 1648 | if (!is_spent || tx.vout[o] != coin.out || pindex->nHeight != coin.nHeight || is_coinbase != coin.fCoinBase) { |
| 1649 | fClean = false; // transaction output mismatch |
| 1650 | } |
| 1651 | } |
| 1652 | } |
| 1653 | |
| 1654 | // restore inputs |
| 1655 | if (i > 0) { // not coinbases |
| 1656 | CTxUndo &txundo = blockUndo.vtxundo[i-1]; |
| 1657 | if (txundo.vprevout.size() != tx.vin.size()) { |
| 1658 | error("DisconnectBlock(): transaction and undo data inconsistent"); |
| 1659 | return DISCONNECT_FAILED; |
| 1660 | } |
| 1661 | for (unsigned int j = tx.vin.size(); j-- > 0;) { |
| 1662 | const COutPoint &out = tx.vin[j].prevout; |
| 1663 | int res = ApplyTxInUndo(std::move(txundo.vprevout[j]), view, out); |
| 1664 | if (res == DISCONNECT_FAILED) return DISCONNECT_FAILED; |
| 1665 | fClean = fClean && res != DISCONNECT_UNCLEAN; |
| 1666 | } |
| 1667 | // At this point, all of txundo.vprevout should have been moved out. |
| 1668 | } |
| 1669 | } |
| 1670 | |
| 1671 | // move best block pointer to prevout block |
| 1672 | view.SetBestBlock(pindex->pprev->GetBlockHash()); |
| 1673 | |
| 1674 | return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN; |
| 1675 | } |
| 1676 | |
| 1677 | void static FlushBlockFile(bool fFinalize = false) |
no test coverage detected