1 // Copyright (c) 2016-2017 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.
5 #ifndef BITCOIN_BLOCK_ENCODINGS_H
6 #define BITCOIN_BLOCK_ENCODINGS_H
8 #include <primitives/block.h>
14 // Dumb helper to handle CTransaction compression at serialize-time
15 struct TransactionCompressor
{
19 explicit TransactionCompressor(CTransactionRef
& txIn
) : tx(txIn
) {}
21 ADD_SERIALIZE_METHODS
;
23 template <typename Stream
, typename Operation
>
24 inline void SerializationOp(Stream
& s
, Operation ser_action
) {
25 READWRITE(tx
); //TODO: Compress tx encoding
29 class BlockTransactionsRequest
{
31 // A BlockTransactionsRequest message
33 std::vector
<uint16_t> indexes
;
35 ADD_SERIALIZE_METHODS
;
37 template <typename Stream
, typename Operation
>
38 inline void SerializationOp(Stream
& s
, Operation ser_action
) {
40 uint64_t indexes_size
= (uint64_t)indexes
.size();
41 READWRITE(COMPACTSIZE(indexes_size
));
42 if (ser_action
.ForRead()) {
44 while (indexes
.size() < indexes_size
) {
45 indexes
.resize(std::min((uint64_t)(1000 + indexes
.size()), indexes_size
));
46 for (; i
< indexes
.size(); i
++) {
48 READWRITE(COMPACTSIZE(index
));
49 if (index
> std::numeric_limits
<uint16_t>::max())
50 throw std::ios_base::failure("index overflowed 16 bits");
56 for (size_t j
= 0; j
< indexes
.size(); j
++) {
57 if (uint64_t(indexes
[j
]) + uint64_t(offset
) > std::numeric_limits
<uint16_t>::max())
58 throw std::ios_base::failure("indexes overflowed 16 bits");
59 indexes
[j
] = indexes
[j
] + offset
;
60 offset
= indexes
[j
] + 1;
63 for (size_t i
= 0; i
< indexes
.size(); i
++) {
64 uint64_t index
= indexes
[i
] - (i
== 0 ? 0 : (indexes
[i
- 1] + 1));
65 READWRITE(COMPACTSIZE(index
));
71 class BlockTransactions
{
73 // A BlockTransactions message
75 std::vector
<CTransactionRef
> txn
;
77 BlockTransactions() {}
78 explicit BlockTransactions(const BlockTransactionsRequest
& req
) :
79 blockhash(req
.blockhash
), txn(req
.indexes
.size()) {}
81 ADD_SERIALIZE_METHODS
;
83 template <typename Stream
, typename Operation
>
84 inline void SerializationOp(Stream
& s
, Operation ser_action
) {
86 uint64_t txn_size
= (uint64_t)txn
.size();
87 READWRITE(COMPACTSIZE(txn_size
));
88 if (ser_action
.ForRead()) {
90 while (txn
.size() < txn_size
) {
91 txn
.resize(std::min((uint64_t)(1000 + txn
.size()), txn_size
));
92 for (; i
< txn
.size(); i
++)
93 READWRITE(REF(TransactionCompressor(txn
[i
])));
96 for (size_t i
= 0; i
< txn
.size(); i
++)
97 READWRITE(REF(TransactionCompressor(txn
[i
])));
102 // Dumb serialization/storage-helper for CBlockHeaderAndShortTxIDs and PartiallyDownloadedBlock
103 struct PrefilledTransaction
{
104 // Used as an offset since last prefilled tx in CBlockHeaderAndShortTxIDs,
105 // as a proper transaction-in-block-index in PartiallyDownloadedBlock
109 ADD_SERIALIZE_METHODS
;
111 template <typename Stream
, typename Operation
>
112 inline void SerializationOp(Stream
& s
, Operation ser_action
) {
113 uint64_t idx
= index
;
114 READWRITE(COMPACTSIZE(idx
));
115 if (idx
> std::numeric_limits
<uint16_t>::max())
116 throw std::ios_base::failure("index overflowed 16-bits");
118 READWRITE(REF(TransactionCompressor(tx
)));
122 typedef enum ReadStatus_t
125 READ_STATUS_INVALID
, // Invalid object, peer is sending bogus crap
126 READ_STATUS_FAILED
, // Failed to process object
127 READ_STATUS_CHECKBLOCK_FAILED
, // Used only by FillBlock to indicate a
128 // failure in CheckBlock.
131 class CBlockHeaderAndShortTxIDs
{
133 mutable uint64_t shorttxidk0
, shorttxidk1
;
136 void FillShortTxIDSelector() const;
138 friend class PartiallyDownloadedBlock
;
140 static const int SHORTTXIDS_LENGTH
= 6;
142 std::vector
<uint64_t> shorttxids
;
143 std::vector
<PrefilledTransaction
> prefilledtxn
;
148 // Dummy for deserialization
149 CBlockHeaderAndShortTxIDs() {}
151 CBlockHeaderAndShortTxIDs(const CBlock
& block
, bool fUseWTXID
);
153 uint64_t GetShortID(const uint256
& txhash
) const;
155 size_t BlockTxCount() const { return shorttxids
.size() + prefilledtxn
.size(); }
157 ADD_SERIALIZE_METHODS
;
159 template <typename Stream
, typename Operation
>
160 inline void SerializationOp(Stream
& s
, Operation ser_action
) {
164 uint64_t shorttxids_size
= (uint64_t)shorttxids
.size();
165 READWRITE(COMPACTSIZE(shorttxids_size
));
166 if (ser_action
.ForRead()) {
168 while (shorttxids
.size() < shorttxids_size
) {
169 shorttxids
.resize(std::min((uint64_t)(1000 + shorttxids
.size()), shorttxids_size
));
170 for (; i
< shorttxids
.size(); i
++) {
171 uint32_t lsb
= 0; uint16_t msb
= 0;
174 shorttxids
[i
] = (uint64_t(msb
) << 32) | uint64_t(lsb
);
175 static_assert(SHORTTXIDS_LENGTH
== 6, "shorttxids serialization assumes 6-byte shorttxids");
179 for (size_t i
= 0; i
< shorttxids
.size(); i
++) {
180 uint32_t lsb
= shorttxids
[i
] & 0xffffffff;
181 uint16_t msb
= (shorttxids
[i
] >> 32) & 0xffff;
187 READWRITE(prefilledtxn
);
189 if (ser_action
.ForRead())
190 FillShortTxIDSelector();
194 class PartiallyDownloadedBlock
{
196 std::vector
<CTransactionRef
> txn_available
;
197 size_t prefilled_count
= 0, mempool_count
= 0, extra_count
= 0;
201 explicit PartiallyDownloadedBlock(CTxMemPool
* poolIn
) : pool(poolIn
) {}
203 // extra_txn is a list of extra transactions to look at, in <witness hash, reference> form
204 ReadStatus
InitData(const CBlockHeaderAndShortTxIDs
& cmpctblock
, const std::vector
<std::pair
<uint256
, CTransactionRef
>>& extra_txn
);
205 bool IsTxAvailable(size_t index
) const;
206 ReadStatus
FillBlock(CBlock
& block
, const std::vector
<CTransactionRef
>& vtx_missing
);