src/validation.cpp
/** 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. */
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.
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 .
DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view, bool clean)
{
    bool fClean = true;
    CBlockUndo blockUndo;
    if (!UndoReadFromDisk(blockUndo, pindex)) {
        error("DisconnectBlock(): failure reading undo data");
        return DISCONNECT_FAILED;
    }
    if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) {
        error("DisconnectBlock(): block and undo data inconsistent");
        return DISCONNECT_FAILED;
    }
    std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
    std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > addressUnspentIndex;
    for (int i = block.vtx.size() - 1; i >= 0; i--) {
        const CTransaction &tx = *(block.vtx[i]);
        uint256 hash = tx.GetHash();
        bool is_coinbase = tx.IsCoinBase();
        for (size_t o = 0; o < tx.vout.size(); o++) {
            if (!tx.vout[o].scriptPubKey.IsUnspendable()) {
                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) {
                    fClean = false; 
                }
            }
        }
        if (!clean && fAddressIndex) {
            for (unsigned int k = tx.vout.size(); k-- > 0;) {
                const CTxOut &out = tx.vout[k];
                CTxDestination dest;
                if (ExtractDestination(out.scriptPubKey, dest)) {
                    std::vector<unsigned char> bytesID(boost::apply_visitor(DataVisitor(), dest));
                    if(bytesID.empty()) {
                        continue;
                    }
                    std::vector<unsigned char> addressBytes(32);
                    std::copy(bytesID.begin(), bytesID.end(), addressBytes.begin());
                    addressIndex.push_back(std::make_pair(CAddressIndexKey(dest.which(), uint256(addressBytes), pindex->nHeight, i, hash, k, false), out.nValue));
                    addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(dest.which(), uint256(addressBytes), hash, k), CAddressUnspentValue()));
                }
            }
        }
        if (i > 0) { 
            CTxUndo &txundo = blockUndo.vtxundo[i-1];
            if (txundo.vprevout.size() != tx.vin.size()) {
                error("DisconnectBlock(): transaction and undo data inconsistent");
                return DISCONNECT_FAILED;
            }
            for (unsigned int j = tx.vin.size(); j-- > 0;) {
                const COutPoint &out = tx.vin[j].prevout;
                int res = ApplyTxInUndo(std::move(txundo.vprevout[j]), view, out);
                if (res == DISCONNECT_FAILED) return DISCONNECT_FAILED;
                fClean = fClean && res != DISCONNECT_UNCLEAN;
                const auto &undo = txundo.vprevout[j];
                const bool isTxCoinBase = tx.IsCoinBase();
                const CTxIn input = tx.vin[j];
                if (!clean && fAddressIndex) {
                    const CTxOut &prevout = view.GetOutputFor(input);
                    CTxDestination dest;
                    if (ExtractDestination(prevout.scriptPubKey, dest)) {
                        std::vector<unsigned char> bytesID(boost::apply_visitor(DataVisitor(), dest));
                        if(bytesID.empty()) {
                            continue;
                        }
                        std::vector<unsigned char> addressBytes(32);
                        std::copy(bytesID.begin(), bytesID.end(), addressBytes.begin());
                        addressIndex.push_back(std::make_pair(CAddressIndexKey(dest.which(), uint256(addressBytes), pindex->nHeight, i, hash, j, true), prevout.nValue * -1));
                        addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(dest.which(), uint256(addressBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight, isTxCoinBase)));
                    }
                }
            }
        }
    }
    view.SetBestBlock(pindex->pprev->GetBlockHash());
    if (!clean && fAddressIndex) {
        if (!pblocktree->EraseAddressIndex(addressIndex)) {
            error("Failed to delete address index");
            return DISCONNECT_FAILED;
        }
        if (!pblocktree->UpdateAddressUnspentIndex(addressUnspentIndex)) {
            error("Failed to write address unspent index");
            return DISCONNECT_FAILED;
        }
    }
    return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;
}
DisconnectResult CChainState :: DisconnectBlock ( const CBlock & block , const CBlockIndex * pindex , CCoinsViewCache & view , bool clean ) { bool fClean = true ; CBlockUndo blockUndo ; if ( ! UndoReadFromDisk ( blockUndo , pindex ) ) { error ( " " ) ; return DISCONNECT_FAILED ; } if ( blockUndo . vtxundo . size ( ) + 1 != block . vtx . size ( ) ) { error ( " " ) ; return DISCONNECT_FAILED ; } std :: vector < std :: pair < CAddressIndexKey , CAmount > > addressIndex ; std :: vector < std :: pair < CAddressUnspentKey , CAddressUnspentValue > > addressUnspentIndex ; for ( int i = block . vtx . size ( ) - 1 ; i >= 0 ; i -- ) { const CTransaction & tx = * ( block . vtx [ i ] ) ; uint256 hash = tx . GetHash ( ) ; bool is_coinbase = tx . IsCoinBase ( ) ; for ( size_t o = 0 ; o < tx . vout . size ( ) ; o ++ ) { if ( ! tx . vout [ o ] . scriptPubKey . IsUnspendable ( ) ) { 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 ) { fClean = false ; } } } if ( ! clean && fAddressIndex ) { for ( unsigned int k = tx . vout . size ( ) ; k -- > 0 ; ) { const CTxOut & out = tx . vout [ k ] ; CTxDestination dest ; if ( ExtractDestination ( out . scriptPubKey , dest ) ) { std :: vector < unsigned char > bytesID ( boost :: apply_visitor ( DataVisitor ( ) , dest ) ) ; if ( bytesID . empty ( ) ) { continue ; } std :: vector < unsigned char > addressBytes ( 32 ) ; std :: copy ( bytesID . begin ( ) , bytesID . end ( ) , addressBytes . begin ( ) ) ; addressIndex . push_back ( std :: make_pair ( CAddressIndexKey ( dest . which ( ) , uint256 ( addressBytes ) , pindex -> nHeight , i , hash , k , false ) , out . nValue ) ) ; addressUnspentIndex . push_back ( std :: make_pair ( CAddressUnspentKey ( dest . which ( ) , uint256 ( addressBytes ) , hash , k ) , CAddressUnspentValue ( ) ) ) ; } } } if ( i > 0 ) { CTxUndo & txundo = blockUndo . vtxundo [ i - 1 ] ; if ( txundo . vprevout . size ( ) != tx . vin . size ( ) ) { error ( " " ) ; return DISCONNECT_FAILED ; } for ( unsigned int j = tx . vin . size ( ) ; j -- > 0 ; ) { const COutPoint & out = tx . vin [ j ] . prevout ; int res = ApplyTxInUndo ( std :: move ( txundo . vprevout [ j ] ) , view , out ) ; if ( res == DISCONNECT_FAILED ) return DISCONNECT_FAILED ; fClean = fClean && res != DISCONNECT_UNCLEAN ; const auto & undo = txundo . vprevout [ j ] ; const bool isTxCoinBase = tx . IsCoinBase ( ) ; const CTxIn input = tx . vin [ j ] ; if ( ! clean && fAddressIndex ) { const CTxOut & prevout = view . GetOutputFor ( input ) ; CTxDestination dest ; if ( ExtractDestination ( prevout . scriptPubKey , dest ) ) { std :: vector < unsigned char > bytesID ( boost :: apply_visitor ( DataVisitor ( ) , dest ) ) ; if ( bytesID . empty ( ) ) { continue ; } std :: vector < unsigned char > addressBytes ( 32 ) ; std :: copy ( bytesID . begin ( ) , bytesID . end ( ) , addressBytes . begin ( ) ) ; addressIndex . push_back ( std :: make_pair ( CAddressIndexKey ( dest . which ( ) , uint256 ( addressBytes ) , pindex -> nHeight , i , hash , j , true ) , prevout . nValue * -1 ) ) ; addressUnspentIndex . push_back ( std :: make_pair ( CAddressUnspentKey ( dest . which ( ) , uint256 ( addressBytes ) , input . prevout . hash , input . prevout . n ) , CAddressUnspentValue ( prevout . nValue , prevout . scriptPubKey , undo . nHeight , isTxCoinBase ) ) ) ; } } } } } view . SetBestBlock ( pindex -> pprev -> GetBlockHash ( ) ) ; if ( ! clean && fAddressIndex ) { if ( ! pblocktree -> EraseAddressIndex ( addressIndex ) ) { error ( " " ) ; return DISCONNECT_FAILED ; } if ( ! pblocktree -> UpdateAddressUnspentIndex ( addressUnspentIndex ) ) { error ( " " ) ; return DISCONNECT_FAILED ; } } return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN ; }
Undo the effects of this block (with given index) on the UTXO set represented by coins.
Undo the effects of this block ( with given index ) on the UTXO set represented by coins .
// undo transactions in reverse order // Check that all outputs are available and match the outputs in the block itself // exactly. // transaction output mismatch // undo receiving activity // undo unspent index // restore inputs // not coinbases // undo spending activity // restore unspent index // At this point, all of txundo.vprevout should have been moved out. // move best block pointer to prevout block