// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_UNDO_H #define BITCOIN_UNDO_H #include "compressor.h" #include "consensus/consensus.h" #include "primitives/transaction.h" #include "serialize.h" /** Undo information for a CTxIn * * Contains the prevout's CTxOut being spent, and its metadata as well * (coinbase or not, height). The serialization contains a dummy value of * zero. This is be compatible with older versions which expect to see * the transaction version there. */ class TxInUndoSerializer { const Coin* txout; public: template void Serialize(Stream &s, int nType, int nVersion) const { ::Serialize(s, VARINT(txout->nHeight * 2 + (txout->fCoinBase ? 1 : 0)), nType, nVersion); if (txout->nHeight > 0) { // Required to maintain compatibility with older undo format. ::Serialize(s, (unsigned char)0, nType, nVersion); } ::Serialize(s, CTxOutCompressor(REF(txout->out)), nType, nVersion); } TxInUndoSerializer(const Coin* coin) : txout(coin) {} }; class TxInUndoDeserializer { Coin* txout; public: template void Unserialize(Stream &s, int nType, int nVersion) { unsigned int nCode = 0; ::Unserialize(s, VARINT(nCode), nType, nVersion); txout->nHeight = nCode / 2; txout->fCoinBase = nCode & 1; if (txout->nHeight > 0) { // Old versions stored the version number for the last spend of // a transaction's outputs. Non-final spends were indicated with // height = 0. int nVersionDummy; ::Unserialize(s, VARINT(nVersionDummy), nType, nVersion); } ::Unserialize(s, REF(CTxOutCompressor(REF(txout->out))), nType, nVersion); } TxInUndoDeserializer(Coin* coin) : txout(coin) {} }; static const size_t MAX_INPUTS_PER_BLOCK = MaxBlockSize(true) / ::GetSerializeSize(CTxIn(), SER_NETWORK, PROTOCOL_VERSION); /** Undo information for a CTransaction */ class CTxUndo { public: // undo information for all txins std::vector vprevout; template void Serialize(Stream& s, int nType, int nVersion) const { // TODO: avoid reimplementing vector serializer uint64_t count = vprevout.size(); ::Serialize(s, COMPACTSIZE(REF(count)), nType, nVersion); for (const auto& prevout : vprevout) { ::Serialize(s, REF(TxInUndoSerializer(&prevout)), nType, nVersion); } } template void Unserialize(Stream& s, int nType, int nVersion) { // TODO: avoid reimplementing vector deserializer uint64_t count = 0; ::Unserialize(s, COMPACTSIZE(count), nType, nVersion); if (count > MAX_INPUTS_PER_BLOCK) { throw std::ios_base::failure("Too many input undo records"); } vprevout.resize(count); for (auto& prevout : vprevout) { ::Unserialize(s, REF(TxInUndoDeserializer(&prevout)), nType, nVersion); } } }; /** Undo information for a CBlock */ class CBlockUndo { public: std::vector vtxundo; // for all but the coinbase ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(vtxundo); } }; #endif // BITCOIN_UNDO_H