text: // Copyright (c) 2016-2018 Duality Blockchain Solutions Developers
  // Copyright (c) 2014-2018 The Dash Core Developers
  // Copyright (c) 2009-2018 The Bitcoin Developers
  // Copyright (c) 2009-2018 Satoshi Nakamoto
  // Distributed under the MIT/X11 software license, see the accompanying
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
  #ifndef DYNAMIC_UNDO_H
  #define DYNAMIC_UNDO_H
  
  #include "compressor.h"
  #include "consensus/consensus.h"
  #include "serialize.h"
  #include "primitives/transaction.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<typename Stream>
      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<typename Stream>
      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 = MAX_BLOCK_SIZE / ::GetSerializeSize(CTxIn(), SER_NETWORK, PROTOCOL_VERSION);
  
  /** Undo information for a CTransaction */
  class CTxUndo
  {
  public:
      // undo information for all txins
      std::vector<Coin> vprevout;
  
      template <typename Stream>
      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 <typename Stream>
      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<CTxUndo> vtxundo; // for all but the coinbase
  
      ADD_SERIALIZE_METHODS;
  
      template <typename Stream, typename Operation>
      inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
          READWRITE(vtxundo);
      }
  };
  
  #endif // DYNAMIC_UNDO_H
  