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. */
| 1899 | /** Undo the effects of this block (with given index) on the UTXO set represented by coins. |
| 1900 | * When FAILED is returned, view is left in an indeterminate state. */ |
| 1901 | DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view) |
| 1902 | { |
| 1903 | AssertLockHeld(::cs_main); |
| 1904 | bool fClean = true; |
| 1905 | |
| 1906 | CBlockUndo blockUndo; |
| 1907 | if (!UndoReadFromDisk(blockUndo, pindex)) { |
| 1908 | error("DisconnectBlock(): failure reading undo data"); |
| 1909 | return DISCONNECT_FAILED; |
| 1910 | } |
| 1911 | |
| 1912 | if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) { |
| 1913 | error("DisconnectBlock(): block and undo data inconsistent"); |
| 1914 | return DISCONNECT_FAILED; |
| 1915 | } |
| 1916 | |
| 1917 | // undo transactions in reverse order |
| 1918 | for (int i = block.vtx.size() - 1; i >= 0; i--) { |
| 1919 | const CTransaction &tx = *(block.vtx[i]); |
| 1920 | uint256 hash = tx.GetHash(); |
| 1921 | bool is_coinbase = tx.IsCoinBase(); |
| 1922 | |
| 1923 | // Check that all outputs are available and match the outputs in the block itself |
| 1924 | // exactly. |
| 1925 | for (size_t o = 0; o < tx.vout.size(); o++) { |
| 1926 | if (!tx.vout[o].scriptPubKey.IsUnspendable()) { |
| 1927 | COutPoint out(hash, o); |
| 1928 | Coin coin; |
| 1929 | bool is_spent = view.SpendCoin(out, &coin); |
| 1930 | if (!is_spent || !TxOutDBEntryIsSame(tx.vout[o], coin.out) || pindex->nHeight != coin.nHeight || is_coinbase != coin.fCoinBase) { |
| 1931 | fClean = false; // transaction output mismatch |
| 1932 | } |
| 1933 | } |
| 1934 | } |
| 1935 | |
| 1936 | // restore inputs |
| 1937 | const auto& fedpegscripts = GetValidFedpegScripts(pindex, Params().GetConsensus(), false /* nextblock_validation */); |
| 1938 | if (i > 0) { // not coinbases |
| 1939 | CTxUndo &txundo = blockUndo.vtxundo[i-1]; |
| 1940 | if (txundo.vprevout.size() != tx.vin.size()) { |
| 1941 | error("DisconnectBlock(): transaction and undo data inconsistent"); |
| 1942 | return DISCONNECT_FAILED; |
| 1943 | } |
| 1944 | for (unsigned int j = tx.vin.size(); j > 0;) { |
| 1945 | --j; |
| 1946 | const COutPoint& out = tx.vin[j].prevout; |
| 1947 | const CScriptWitness& pegin_wit = tx.witness.vtxinwit.size() > j ? tx.witness.vtxinwit[j].m_pegin_witness : CScriptWitness(); |
| 1948 | int res = ApplyTxInUndo(std::move(txundo.vprevout[j]), view, out, tx.vin[j], pegin_wit, fedpegscripts); |
| 1949 | if (res == DISCONNECT_FAILED) return DISCONNECT_FAILED; |
| 1950 | fClean = fClean && res != DISCONNECT_UNCLEAN; |
| 1951 | } |
| 1952 | // At this point, all of txundo.vprevout should have been moved out. |
| 1953 | } |
| 1954 | } |
| 1955 | |
| 1956 | // move best block pointer to prevout block |
| 1957 | view.SetBestBlock(pindex->pprev->GetBlockHash()); |
| 1958 |
no test coverage detected