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 : 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 : 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, Using<VectorFormatter<TransactionCompression>>(obj.txn)); 69 0 : } 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 0 : SERIALIZE_METHODS(PrefilledTransaction, obj) { READWRITE(COMPACTSIZE(obj.index), 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 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 : 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