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 : : class DifferenceFormatter
23 : : {
24 : : uint64_t m_shift = 0;
25 : :
26 : : public:
27 : : template<typename Stream, typename I>
28 : 5 : void Ser(Stream& s, I v)
29 : : {
30 [ - + - - ]: 5 : if (v < m_shift || v >= std::numeric_limits<uint64_t>::max()) throw std::ios_base::failure("differential value overflow");
31 : 5 : WriteCompactSize(s, v - m_shift);
32 : 5 : m_shift = uint64_t(v) + 1;
33 : 5 : }
34 : : template<typename Stream, typename I>
35 : 8 : void Unser(Stream& s, I& v)
36 : : {
37 : 8 : uint64_t n = ReadCompactSize(s);
38 : 8 : m_shift += n;
39 [ + - + - : 8 : 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 : 7 : v = I(m_shift++);
41 : 7 : }
42 : : };
43 : :
44 : 3 : class BlockTransactionsRequest {
45 : : public:
46 : : // A BlockTransactionsRequest message
47 : : uint256 blockhash;
48 : : std::vector<uint16_t> indexes;
49 : :
50 : 10 : SERIALIZE_METHODS(BlockTransactionsRequest, obj)
51 : : {
52 : 5 : READWRITE(obj.blockhash, Using<VectorFormatter<DifferenceFormatter>>(obj.indexes));
53 : 4 : }
54 : : };
55 : :
56 : 0 : class BlockTransactions {
57 : : public:
58 : : // A BlockTransactions message
59 : : uint256 blockhash;
60 : : std::vector<CTransactionRef> txn;
61 : :
62 : : BlockTransactions() = default;
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 [ - - - + ]: 60 : 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 : 58 : 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 [ + - + - ]: 10 : 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 : : /**
110 : : * Dummy for deserialization
111 : : */
112 : 7 : CBlockHeaderAndShortTxIDs() = default;
113 : :
114 : : /**
115 : : * @param[in] nonce This should be randomly generated, and is used for the siphash secret key
116 : : */
117 : : CBlockHeaderAndShortTxIDs(const CBlock& block, const uint64_t nonce);
118 : :
119 : : uint64_t GetShortID(const Wtxid& wtxid) const;
120 : :
121 [ # # ]: 13 : size_t BlockTxCount() const { return shorttxids.size() + prefilledtxn.size(); }
122 : :
123 : 28 : SERIALIZE_METHODS(CBlockHeaderAndShortTxIDs, obj)
124 : : {
125 [ - + ]: 17 : READWRITE(obj.header, obj.nonce, Using<VectorFormatter<CustomUintFormatter<SHORTTXIDS_LENGTH>>>(obj.shorttxids), obj.prefilledtxn);
126 : : if (ser_action.ForRead()) {
127 [ - + ]: 7 : if (obj.BlockTxCount() > std::numeric_limits<uint16_t>::max()) {
128 [ # # ]: 0 : throw std::ios_base::failure("indexes overflowed 16 bits");
129 : : }
130 : 7 : obj.FillShortTxIDSelector();
131 : : }
132 : 17 : }
133 : : };
134 : :
135 [ + - + - : 10 : class PartiallyDownloadedBlock {
+ - + - ]
136 : : protected:
137 : : std::vector<CTransactionRef> txn_available;
138 : : size_t prefilled_count = 0, mempool_count = 0, extra_count = 0;
139 : : const CTxMemPool* pool;
140 : : public:
141 : : CBlockHeader header;
142 : :
143 : : // Can be overridden for testing
144 : : using CheckBlockFn = std::function<bool(const CBlock&, BlockValidationState&, const Consensus::Params&, bool, bool)>;
145 : : CheckBlockFn m_check_block_mock{nullptr};
146 : :
147 : 6 : explicit PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {}
148 : :
149 : : // extra_txn is a list of extra orphan/conflicted/etc transactions to look at
150 : : ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<CTransactionRef>& extra_txn);
151 : : bool IsTxAvailable(size_t index) const;
152 : : ReadStatus FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing);
153 : : };
154 : :
155 : : #endif // BITCOIN_BLOCKENCODINGS_H
|