77
88#include < primitives/block.h>
99
10+ // Transaction compression schemes for compact block relay can be introduced by writing
11+ // an actual formatter here.
12+ using TransactionCompression = DefaultFormatter;
1013
1114class CTxMemPool ;
1215
13- // Dumb helper to handle CTransaction compression at serialize-time
14- struct TransactionCompressor {
15- private:
16- CTransactionRef& tx;
17- public:
18- explicit TransactionCompressor (CTransactionRef& txIn) : tx(txIn) {}
16+ struct Uint48Formatter
17+ {
18+ template <typename Stream, typename I> void Ser (Stream& s, I v)
19+ {
20+ if (v < 0 || (v >> 48 ) != 0 ) throw std::ios_base::failure (" Uint48Formatter value out of range" );
21+
22+ uint32_t lsb = v & 0xffffffff ;
23+ uint16_t msb = (v >> 32 ) & 0xffff ;
24+ s << lsb << msb;
25+ }
1926
20- ADD_SERIALIZE_METHODS;
27+ template <typename Stream, typename I> void Unser (Stream& s, I& v)
28+ {
29+ static_assert (std::numeric_limits<I>::max () >= 0xffffffffffff && std::numeric_limits<I>::min () <= 0 , " Uint48Formatter needs a 48+ bit type" );
2130
22- template <typename Stream, typename Operation>
23- inline void SerializationOp (Stream& s, Operation ser_action) {
24- READWRITE (tx); // TODO: Compress tx encoding
31+ uint32_t lsb;
32+ uint16_t msb;
33+ s >> lsb >> msb;
34+ v = (uint64_t (msb) << 32 ) | uint64_t (lsb);
35+ }
36+ };
37+
38+ template <bool Unser>
39+ class DifferenceTransform
40+ {
41+ int32_t m_shift = 0 ;
42+
43+ public:
44+ uint16_t operator ()(uint16_t val)
45+ {
46+ int32_t out = m_shift + val;
47+ if (out < 0 || out > 0xffff ) throw std::ios_base::failure (" differential value overflow" );
48+ m_shift = Unser ? out + 1 : (-(int32_t )val) - 1 ;
49+ return uint16_t (out);
2550 }
2651};
2752
@@ -31,39 +56,9 @@ class BlockTransactionsRequest {
3156 uint256 blockhash;
3257 std::vector<uint16_t > indexes;
3358
34- ADD_SERIALIZE_METHODS;
35-
36- template <typename Stream, typename Operation>
37- inline void SerializationOp (Stream& s, Operation ser_action) {
38- READWRITE (blockhash);
39- uint64_t indexes_size = (uint64_t )indexes.size ();
40- READWRITE (COMPACTSIZE (indexes_size));
41- if (ser_action.ForRead ()) {
42- size_t i = 0 ;
43- while (indexes.size () < indexes_size) {
44- indexes.resize (std::min ((uint64_t )(1000 + indexes.size ()), indexes_size));
45- for (; i < indexes.size (); i++) {
46- uint64_t index = 0 ;
47- READWRITE (COMPACTSIZE (index));
48- if (index > std::numeric_limits<uint16_t >::max ())
49- throw std::ios_base::failure (" index overflowed 16 bits" );
50- indexes[i] = index;
51- }
52- }
53-
54- int32_t offset = 0 ;
55- for (size_t j = 0 ; j < indexes.size (); j++) {
56- if (int32_t (indexes[j]) + offset > std::numeric_limits<uint16_t >::max ())
57- throw std::ios_base::failure (" indexes overflowed 16 bits" );
58- indexes[j] = indexes[j] + offset;
59- offset = int32_t (indexes[j]) + 1 ;
60- }
61- } else {
62- for (size_t i = 0 ; i < indexes.size (); i++) {
63- uint64_t index = indexes[i] - (i == 0 ? 0 : (indexes[i - 1 ] + 1 ));
64- READWRITE (COMPACTSIZE (index));
65- }
66- }
59+ SERIALIZE_METHODS (BlockTransactionsRequest, obj)
60+ {
61+ READWRITE (obj.blockhash , Using<VectorFormatter<CompactSizeFormatter, DifferenceTransform<false >, DifferenceTransform<true >>>(obj.indexes ));
6762 }
6863};
6964
@@ -77,24 +72,9 @@ class BlockTransactions {
7772 explicit BlockTransactions (const BlockTransactionsRequest& req) :
7873 blockhash(req.blockhash), txn(req.indexes.size()) {}
7974
80- ADD_SERIALIZE_METHODS;
81-
82- template <typename Stream, typename Operation>
83- inline void SerializationOp (Stream& s, Operation ser_action) {
84- READWRITE (blockhash);
85- uint64_t txn_size = (uint64_t )txn.size ();
86- READWRITE (COMPACTSIZE (txn_size));
87- if (ser_action.ForRead ()) {
88- size_t i = 0 ;
89- while (txn.size () < txn_size) {
90- txn.resize (std::min ((uint64_t )(1000 + txn.size ()), txn_size));
91- for (; i < txn.size (); i++)
92- READWRITE (TransactionCompressor (txn[i]));
93- }
94- } else {
95- for (size_t i = 0 ; i < txn.size (); i++)
96- READWRITE (TransactionCompressor (txn[i]));
97- }
75+ SERIALIZE_METHODS (BlockTransactions, obj)
76+ {
77+ READWRITE (obj.blockhash , Using<VectorFormatter<TransactionCompression>>(obj.txn ));
9878 }
9979};
10080
@@ -105,17 +85,7 @@ struct PrefilledTransaction {
10585 uint16_t index;
10686 CTransactionRef tx;
10787
108- ADD_SERIALIZE_METHODS;
109-
110- template <typename Stream, typename Operation>
111- inline void SerializationOp (Stream& s, Operation ser_action) {
112- uint64_t idx = index;
113- READWRITE (COMPACTSIZE (idx));
114- if (idx > std::numeric_limits<uint16_t >::max ())
115- throw std::ios_base::failure (" index overflowed 16-bits" );
116- index = idx;
117- READWRITE (TransactionCompressor (tx));
118- }
88+ SERIALIZE_METHODS (PrefilledTransaction, obj) { READWRITE (COMPACTSIZE (obj.index ), Using<TransactionCompression>(obj.tx )); }
11989};
12090
12191typedef enum ReadStatus_t
@@ -153,43 +123,16 @@ class CBlockHeaderAndShortTxIDs {
153123
154124 size_t BlockTxCount () const { return shorttxids.size () + prefilledtxn.size (); }
155125
156- ADD_SERIALIZE_METHODS;
157-
158- template <typename Stream, typename Operation>
159- inline void SerializationOp (Stream& s, Operation ser_action) {
160- READWRITE (header);
161- READWRITE (nonce);
162-
163- uint64_t shorttxids_size = (uint64_t )shorttxids.size ();
164- READWRITE (COMPACTSIZE (shorttxids_size));
126+ SERIALIZE_METHODS (CBlockHeaderAndShortTxIDs, obj)
127+ {
128+ static_assert (SHORTTXIDS_LENGTH == 6 , " shorttxids serialization assumes 6-byte shorttxids" );
129+ READWRITE (obj.header , obj.nonce , Using<VectorFormatter<Uint48Formatter>>(obj.shorttxids ), obj.prefilledtxn );
165130 if (ser_action.ForRead ()) {
166- size_t i = 0 ;
167- while (shorttxids.size () < shorttxids_size) {
168- shorttxids.resize (std::min ((uint64_t )(1000 + shorttxids.size ()), shorttxids_size));
169- for (; i < shorttxids.size (); i++) {
170- uint32_t lsb = 0 ; uint16_t msb = 0 ;
171- READWRITE (lsb);
172- READWRITE (msb);
173- shorttxids[i] = (uint64_t (msb) << 32 ) | uint64_t (lsb);
174- static_assert (SHORTTXIDS_LENGTH == 6 , " shorttxids serialization assumes 6-byte shorttxids" );
175- }
176- }
177- } else {
178- for (size_t i = 0 ; i < shorttxids.size (); i++) {
179- uint32_t lsb = shorttxids[i] & 0xffffffff ;
180- uint16_t msb = (shorttxids[i] >> 32 ) & 0xffff ;
181- READWRITE (lsb);
182- READWRITE (msb);
131+ if (obj.BlockTxCount () > std::numeric_limits<uint16_t >::max ()) {
132+ throw std::ios_base::failure (" indexes overflowed 16 bits" );
183133 }
134+ obj.FillShortTxIDSelector ();
184135 }
185-
186- READWRITE (prefilledtxn);
187-
188- if (BlockTxCount () > std::numeric_limits<uint16_t >::max ())
189- throw std::ios_base::failure (" indexes overflowed 16 bits" );
190-
191- if (ser_action.ForRead ())
192- FillShortTxIDSelector ();
193136 }
194137};
195138
0 commit comments