Branch data Line data Source code
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 : 0 : class DifferenceFormatter 23 : : { 24 : 0 : uint64_t m_shift = 0; 25 : : 26 : : public: 27 : : template<typename Stream, typename I> 28 : 0 : void Ser(Stream& s, I v) 29 : : { 30 [ # # ][ # # ]: 0 : if (v < m_shift || v >= std::numeric_limits<uint64_t>::max()) throw std::ios_base::failure("differential value overflow"); 31 : 0 : WriteCompactSize(s, v - m_shift); 32 : 0 : m_shift = uint64_t(v) + 1; 33 : 0 : } 34 : : template<typename Stream, typename I> 35 : 0 : void Unser(Stream& s, I& v) 36 : : { 37 : 0 : uint64_t n = ReadCompactSize(s); 38 : 0 : m_shift += n; 39 [ # # ][ # # ]: 0 : 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 : 0 : v = I(m_shift++); 41 : 0 : } 42 : : }; 43 : : 44 : 0 : class BlockTransactionsRequest { 45 : : public: 46 : : // A BlockTransactionsRequest message 47 : : uint256 blockhash; 48 : : std::vector<uint16_t> indexes; 49 : : 50 : 0 : SERIALIZE_METHODS(BlockTransactionsRequest, obj) 51 : : { 52 : 0 : READWRITE(obj.blockhash, Using<VectorFormatter<DifferenceFormatter>>(obj.indexes)); 53 : 0 : } 54 : : }; 55 : : 56 : 0 : class BlockTransactions { 57 : : public: 58 : : // A BlockTransactions message 59 : : uint256 blockhash; 60 : : std::vector<CTransactionRef> txn; 61 : : 62 : 0 : BlockTransactions() {} 63 : 0 : explicit BlockTransactions(const BlockTransactionsRequest& req) : 64 [ # # ]: 0 : blockhash(req.blockhash), txn(req.indexes.size()) {} 65 : : 66 : 0 : SERIALIZE_METHODS(BlockTransactions, obj) 67 : : { 68 : 0 : READWRITE(obj.blockhash, TX_WITH_WITNESS(Using<VectorFormatter<TransactionCompression>>(obj.txn))); 69 : 0 : } 70 : : }; 71 : : 72 : : // Dumb serialization/storage-helper for CBlockHeaderAndShortTxIDs and PartiallyDownloadedBlock 73 : 0 : 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 : 0 : 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 : 0 : 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 [ # # ]: 0 : CBlockHeaderAndShortTxIDs() {} 111 : : 112 : : CBlockHeaderAndShortTxIDs(const CBlock& block); 113 : : 114 : : uint64_t GetShortID(const uint256& txhash) const; 115 : : 116 : 0 : size_t BlockTxCount() const { return shorttxids.size() + prefilledtxn.size(); } 117 : : 118 : 0 : SERIALIZE_METHODS(CBlockHeaderAndShortTxIDs, obj) 119 : : { 120 : 0 : READWRITE(obj.header, obj.nonce, Using<VectorFormatter<CustomUintFormatter<SHORTTXIDS_LENGTH>>>(obj.shorttxids), obj.prefilledtxn); 121 : : if (ser_action.ForRead()) { 122 [ # # ]: 0 : if (obj.BlockTxCount() > std::numeric_limits<uint16_t>::max()) { 123 [ # # ]: 0 : throw std::ios_base::failure("indexes overflowed 16 bits"); 124 : : } 125 : 0 : obj.FillShortTxIDSelector(); 126 : : } 127 : 0 : } 128 : : }; 129 : : 130 : 0 : class PartiallyDownloadedBlock { 131 : : protected: 132 : : std::vector<CTransactionRef> txn_available; 133 : 0 : 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 : 0 : CheckBlockFn m_check_block_mock{nullptr}; 141 : : 142 [ # # ][ # # ]: 0 : 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