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