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 : 72 : 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 : : } ReadStatus;
88 : :
89 [ + - + - ]: 10 : class CBlockHeaderAndShortTxIDs {
90 : : private:
91 : : mutable uint64_t shorttxidk0, shorttxidk1;
92 : : uint64_t nonce;
93 : :
94 : : void FillShortTxIDSelector() const;
95 : :
96 : : friend class PartiallyDownloadedBlock;
97 : :
98 : : protected:
99 : : std::vector<uint64_t> shorttxids;
100 : : std::vector<PrefilledTransaction> prefilledtxn;
101 : :
102 : : public:
103 : : static constexpr int SHORTTXIDS_LENGTH = 6;
104 : :
105 : : CBlockHeader header;
106 : :
107 : : /**
108 : : * Dummy for deserialization
109 : : */
110 : 7 : CBlockHeaderAndShortTxIDs() = default;
111 : :
112 : : /**
113 : : * @param[in] nonce This should be randomly generated, and is used for the siphash secret key
114 : : */
115 : : CBlockHeaderAndShortTxIDs(const CBlock& block, const uint64_t nonce);
116 : :
117 : : uint64_t GetShortID(const Wtxid& wtxid) const;
118 : :
119 [ # # ]: 13 : size_t BlockTxCount() const { return shorttxids.size() + prefilledtxn.size(); }
120 : :
121 : 34 : SERIALIZE_METHODS(CBlockHeaderAndShortTxIDs, obj)
122 : : {
123 [ - + ]: 23 : READWRITE(obj.header, obj.nonce, Using<VectorFormatter<CustomUintFormatter<SHORTTXIDS_LENGTH>>>(obj.shorttxids), obj.prefilledtxn);
124 : : if (ser_action.ForRead()) {
125 [ - + ]: 7 : if (obj.BlockTxCount() > std::numeric_limits<uint16_t>::max()) {
126 [ # # ]: 0 : throw std::ios_base::failure("indexes overflowed 16 bits");
127 : : }
128 : 7 : obj.FillShortTxIDSelector();
129 : : }
130 : 23 : }
131 : : };
132 : :
133 [ + - + - : 10 : class PartiallyDownloadedBlock {
+ - + - ]
134 : : protected:
135 : : std::vector<CTransactionRef> txn_available;
136 : : size_t prefilled_count = 0, mempool_count = 0, extra_count = 0;
137 : : const CTxMemPool* pool;
138 : : public:
139 : : CBlockHeader header;
140 : :
141 : : // Can be overridden for testing
142 : : using IsBlockMutatedFn = std::function<bool(const CBlock&, bool)>;
143 : : IsBlockMutatedFn m_check_block_mutated_mock{nullptr};
144 : :
145 : 6 : explicit PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {}
146 : :
147 : : // extra_txn is a list of extra orphan/conflicted/etc transactions to look at
148 : : ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<CTransactionRef>& extra_txn);
149 : : bool IsTxAvailable(size_t index) const;
150 : : // segwit_active enforces witness mutation checks just before reporting a healthy status
151 : : ReadStatus FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing, bool segwit_active);
152 : : };
153 : :
154 : : #endif // BITCOIN_BLOCKENCODINGS_H
|