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 <crypto/siphash.h>
9 : : #include <primitives/block.h>
10 : :
11 : : #include <functional>
12 : :
13 : : class CTxMemPool;
14 : : class BlockValidationState;
15 : : namespace Consensus {
16 : : struct Params;
17 : : };
18 : :
19 : : // Transaction compression schemes for compact block relay can be introduced by writing
20 : : // an actual formatter here.
21 : : using TransactionCompression = DefaultFormatter;
22 : :
23 : : class DifferenceFormatter
24 : : {
25 : : uint64_t m_shift = 0;
26 : :
27 : : public:
28 : : template<typename Stream, typename I>
29 : 5 : void Ser(Stream& s, I v)
30 : : {
31 [ - + - - ]: 5 : if (v < m_shift || v >= std::numeric_limits<uint64_t>::max()) throw std::ios_base::failure("differential value overflow");
32 : 5 : WriteCompactSize(s, v - m_shift);
33 : 5 : m_shift = uint64_t(v) + 1;
34 : 5 : }
35 : : template<typename Stream, typename I>
36 : 8 : void Unser(Stream& s, I& v)
37 : : {
38 : 8 : uint64_t n = ReadCompactSize(s);
39 : 8 : m_shift += n;
40 [ + - + - : 9 : 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");
+ + + - ]
41 : 7 : v = I(m_shift++);
42 : 7 : }
43 : : };
44 : :
45 : 3 : class BlockTransactionsRequest {
46 : : public:
47 : : // A BlockTransactionsRequest message
48 : : uint256 blockhash;
49 : : std::vector<uint16_t> indexes;
50 : :
51 : 10 : SERIALIZE_METHODS(BlockTransactionsRequest, obj)
52 : : {
53 : 5 : READWRITE(obj.blockhash, Using<VectorFormatter<DifferenceFormatter>>(obj.indexes));
54 : 4 : }
55 : : };
56 : :
57 : 0 : class BlockTransactions {
58 : : public:
59 : : // A BlockTransactions message
60 : : uint256 blockhash;
61 : : std::vector<CTransactionRef> txn;
62 : :
63 : : BlockTransactions() = default;
64 : 0 : explicit BlockTransactions(const BlockTransactionsRequest& req) :
65 [ # # ]: 0 : blockhash(req.blockhash), txn(req.indexes.size()) {}
66 : :
67 : 0 : SERIALIZE_METHODS(BlockTransactions, obj)
68 : : {
69 : 0 : READWRITE(obj.blockhash, TX_WITH_WITNESS(Using<VectorFormatter<TransactionCompression>>(obj.txn)));
70 : 0 : }
71 : : };
72 : :
73 : : // Dumb serialization/storage-helper for CBlockHeaderAndShortTxIDs and PartiallyDownloadedBlock
74 [ - - - + ]: 60 : struct PrefilledTransaction {
[ - + + -
- + + - -
+ + - - +
+ - ]
75 : : // Used as an offset since last prefilled tx in CBlockHeaderAndShortTxIDs,
76 : : // as a proper transaction-in-block-index in PartiallyDownloadedBlock
77 : : uint16_t index;
78 : : CTransactionRef tx;
79 : :
80 : 72 : SERIALIZE_METHODS(PrefilledTransaction, obj) { READWRITE(COMPACTSIZE(obj.index), TX_WITH_WITNESS(Using<TransactionCompression>(obj.tx))); }
81 : : };
82 : :
83 : : typedef enum ReadStatus_t
84 : : {
85 : : READ_STATUS_OK,
86 : : READ_STATUS_INVALID, // Invalid object, peer is sending bogus crap
87 : : READ_STATUS_FAILED, // Failed to process object
88 : : } ReadStatus;
89 : :
90 [ + - + - ]: 10 : class CBlockHeaderAndShortTxIDs {
91 : : mutable std::optional<PresaltedSipHasher> m_hasher;
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, 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 transactions to look at, in <witness hash, reference> form
148 : : ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<std::pair<Wtxid, 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
|