/ src / blockencodings.h
blockencodings.h
  1  // Copyright (c) 2016-2022 The Bitcoin Core developers
  2  // Distributed under the MIT software license, see the accompanying
  3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  4  
  5  #ifndef BITCOIN_BLOCKENCODINGS_H
  6  #define BITCOIN_BLOCKENCODINGS_H
  7  
  8  #include <primitives/block.h>
  9  
 10  #include <functional>
 11  
 12  class CTxMemPool;
 13  class BlockValidationState;
 14  namespace Consensus {
 15  struct Params;
 16  };
 17  
 18  // Transaction compression schemes for compact block relay can be introduced by writing
 19  // an actual formatter here.
 20  using TransactionCompression = DefaultFormatter;
 21  
 22  class DifferenceFormatter
 23  {
 24      uint64_t m_shift = 0;
 25  
 26  public:
 27      template<typename Stream, typename I>
 28      void Ser(Stream& s, I v)
 29      {
 30          if (v < m_shift || v >= std::numeric_limits<uint64_t>::max()) throw std::ios_base::failure("differential value overflow");
 31          WriteCompactSize(s, v - m_shift);
 32          m_shift = uint64_t(v) + 1;
 33      }
 34      template<typename Stream, typename I>
 35      void Unser(Stream& s, I& v)
 36      {
 37          uint64_t n = ReadCompactSize(s);
 38          m_shift += n;
 39          if (m_shift < n || m_shift >= std::numeric_limits<uint64_t>::max() || m_shift < std::numeric_limits<I>::min() || m_shift > std::numeric_limits<I>::max()) throw std::ios_base::failure("differential value overflow");
 40          v = I(m_shift++);
 41      }
 42  };
 43  
 44  class BlockTransactionsRequest {
 45  public:
 46      // A BlockTransactionsRequest message
 47      uint256 blockhash;
 48      std::vector<uint16_t> indexes;
 49  
 50      SERIALIZE_METHODS(BlockTransactionsRequest, obj)
 51      {
 52          READWRITE(obj.blockhash, Using<VectorFormatter<DifferenceFormatter>>(obj.indexes));
 53      }
 54  };
 55  
 56  class BlockTransactions {
 57  public:
 58      // A BlockTransactions message
 59      uint256 blockhash;
 60      std::vector<CTransactionRef> txn;
 61  
 62      BlockTransactions() {}
 63      explicit BlockTransactions(const BlockTransactionsRequest& req) :
 64          blockhash(req.blockhash), txn(req.indexes.size()) {}
 65  
 66      SERIALIZE_METHODS(BlockTransactions, obj)
 67      {
 68          READWRITE(obj.blockhash, TX_WITH_WITNESS(Using<VectorFormatter<TransactionCompression>>(obj.txn)));
 69      }
 70  };
 71  
 72  // Dumb serialization/storage-helper for CBlockHeaderAndShortTxIDs and PartiallyDownloadedBlock
 73  struct PrefilledTransaction {
 74      // Used as an offset since last prefilled tx in CBlockHeaderAndShortTxIDs,
 75      // as a proper transaction-in-block-index in PartiallyDownloadedBlock
 76      uint16_t index;
 77      CTransactionRef tx;
 78  
 79      SERIALIZE_METHODS(PrefilledTransaction, obj) { READWRITE(COMPACTSIZE(obj.index), TX_WITH_WITNESS(Using<TransactionCompression>(obj.tx))); }
 80  };
 81  
 82  typedef enum ReadStatus_t
 83  {
 84      READ_STATUS_OK,
 85      READ_STATUS_INVALID, // Invalid object, peer is sending bogus crap
 86      READ_STATUS_FAILED, // Failed to process object
 87      READ_STATUS_CHECKBLOCK_FAILED, // Used only by FillBlock to indicate a
 88                                     // failure in CheckBlock.
 89  } ReadStatus;
 90  
 91  class CBlockHeaderAndShortTxIDs {
 92  private:
 93      mutable uint64_t shorttxidk0, shorttxidk1;
 94      uint64_t nonce;
 95  
 96      void FillShortTxIDSelector() const;
 97  
 98      friend class PartiallyDownloadedBlock;
 99  
100  protected:
101      std::vector<uint64_t> shorttxids;
102      std::vector<PrefilledTransaction> prefilledtxn;
103  
104  public:
105      static constexpr int SHORTTXIDS_LENGTH = 6;
106  
107      CBlockHeader header;
108  
109      // Dummy for deserialization
110      CBlockHeaderAndShortTxIDs() {}
111  
112      CBlockHeaderAndShortTxIDs(const CBlock& block);
113  
114      uint64_t GetShortID(const uint256& txhash) const;
115  
116      size_t BlockTxCount() const { return shorttxids.size() + prefilledtxn.size(); }
117  
118      SERIALIZE_METHODS(CBlockHeaderAndShortTxIDs, obj)
119      {
120          READWRITE(obj.header, obj.nonce, Using<VectorFormatter<CustomUintFormatter<SHORTTXIDS_LENGTH>>>(obj.shorttxids), obj.prefilledtxn);
121          if (ser_action.ForRead()) {
122              if (obj.BlockTxCount() > std::numeric_limits<uint16_t>::max()) {
123                  throw std::ios_base::failure("indexes overflowed 16 bits");
124              }
125              obj.FillShortTxIDSelector();
126          }
127      }
128  };
129  
130  class PartiallyDownloadedBlock {
131  protected:
132      std::vector<CTransactionRef> txn_available;
133      size_t prefilled_count = 0, mempool_count = 0, extra_count = 0;
134      const CTxMemPool* pool;
135  public:
136      CBlockHeader header;
137  
138      // Can be overridden for testing
139      using CheckBlockFn = std::function<bool(const CBlock&, BlockValidationState&, const Consensus::Params&, bool, bool)>;
140      CheckBlockFn m_check_block_mock{nullptr};
141  
142      explicit PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {}
143  
144      // extra_txn is a list of extra transactions to look at, in <witness hash, reference> form
145      ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<std::pair<uint256, CTransactionRef>>& extra_txn);
146      bool IsTxAvailable(size_t index) const;
147      ReadStatus FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing);
148  };
149  
150  #endif // BITCOIN_BLOCKENCODINGS_H