Branch data Line data Source code
1 : : // Copyright (c) 2009-2010 Satoshi Nakamoto
2 : : // Copyright (c) 2009-2022 The Bitcoin Core developers
3 : : // Distributed under the MIT software license, see the accompanying
4 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 : :
6 : : #ifndef BITCOIN_SERIALIZE_H
7 : : #define BITCOIN_SERIALIZE_H
8 : :
9 : : #include <attributes.h>
10 : : #include <compat/endian.h>
11 : :
12 : : #include <algorithm>
13 : : #include <cstdint>
14 : : #include <cstring>
15 : : #include <ios>
16 : : #include <limits>
17 : : #include <map>
18 : : #include <memory>
19 : : #include <set>
20 : : #include <string>
21 : : #include <string.h>
22 : : #include <utility>
23 : : #include <vector>
24 : :
25 : : #include <prevector.h>
26 : : #include <span.h>
27 : :
28 : : /**
29 : : * The maximum size of a serialized object in bytes or number of elements
30 : : * (for eg vectors) when the size is encoded as CompactSize.
31 : : */
32 : : static constexpr uint64_t MAX_SIZE = 0x02000000;
33 : :
34 : : /** Maximum amount of memory (in bytes) to allocate at once when deserializing vectors. */
35 : : static const unsigned int MAX_VECTOR_ALLOCATE = 5000000;
36 : :
37 : : /**
38 : : * Dummy data type to identify deserializing constructors.
39 : : *
40 : : * By convention, a constructor of a type T with signature
41 : : *
42 : : * template <typename Stream> T::T(deserialize_type, Stream& s)
43 : : *
44 : : * is a deserializing constructor, which builds the type by
45 : : * deserializing it from s. If T contains const fields, this
46 : : * is likely the only way to do so.
47 : : */
48 : : struct deserialize_type {};
49 : : constexpr deserialize_type deserialize {};
50 : :
51 : : /*
52 : : * Lowest-level serialization and conversion.
53 : : */
54 : 14033 : template<typename Stream> inline void ser_writedata8(Stream &s, uint8_t obj)
55 : : {
56 : 14033 : s.write(AsBytes(Span{&obj, 1}));
57 : 14033 : }
58 : 0 : template<typename Stream> inline void ser_writedata16(Stream &s, uint16_t obj)
59 : : {
60 : 0 : obj = htole16(obj);
61 : 0 : s.write(AsBytes(Span{&obj, 1}));
62 : 0 : }
63 : 0 : template<typename Stream> inline void ser_writedata16be(Stream &s, uint16_t obj)
64 : : {
65 : 0 : obj = htobe16(obj);
66 : 0 : s.write(AsBytes(Span{&obj, 1}));
67 : 0 : }
68 : 17582 : template<typename Stream> inline void ser_writedata32(Stream &s, uint32_t obj)
69 : : {
70 : 17582 : obj = htole32(obj);
71 : 17582 : s.write(AsBytes(Span{&obj, 1}));
72 : 17582 : }
73 : 0 : template<typename Stream> inline void ser_writedata32be(Stream &s, uint32_t obj)
74 : : {
75 : 0 : obj = htobe32(obj);
76 : 0 : s.write(AsBytes(Span{&obj, 1}));
77 : 0 : }
78 : 34978 : template<typename Stream> inline void ser_writedata64(Stream &s, uint64_t obj)
79 : : {
80 : 34978 : obj = htole64(obj);
81 : 34978 : s.write(AsBytes(Span{&obj, 1}));
82 : 34978 : }
83 : 5 : template<typename Stream> inline uint8_t ser_readdata8(Stream &s)
84 : : {
85 : : uint8_t obj;
86 : 5 : s.read(AsWritableBytes(Span{&obj, 1}));
87 : 5 : return obj;
88 : : }
89 : 0 : template<typename Stream> inline uint16_t ser_readdata16(Stream &s)
90 : : {
91 : : uint16_t obj;
92 : 0 : s.read(AsWritableBytes(Span{&obj, 1}));
93 : 0 : return le16toh(obj);
94 : : }
95 : 0 : template<typename Stream> inline uint16_t ser_readdata16be(Stream &s)
96 : : {
97 : : uint16_t obj;
98 : 0 : s.read(AsWritableBytes(Span{&obj, 1}));
99 : 0 : return be16toh(obj);
100 : : }
101 : 143 : template<typename Stream> inline uint32_t ser_readdata32(Stream &s)
102 : : {
103 : : uint32_t obj;
104 : 143 : s.read(AsWritableBytes(Span{&obj, 1}));
105 : 143 : return le32toh(obj);
106 : : }
107 : 0 : template<typename Stream> inline uint32_t ser_readdata32be(Stream &s)
108 : : {
109 : : uint32_t obj;
110 : 0 : s.read(AsWritableBytes(Span{&obj, 1}));
111 : 0 : return be32toh(obj);
112 : : }
113 : 1 : template<typename Stream> inline uint64_t ser_readdata64(Stream &s)
114 : : {
115 : : uint64_t obj;
116 : 1 : s.read(AsWritableBytes(Span{&obj, 1}));
117 : 1 : return le64toh(obj);
118 : : }
119 : :
120 : :
121 : : /////////////////////////////////////////////////////////////////
122 : : //
123 : : // Templates for serializing to anything that looks like a stream,
124 : : // i.e. anything that supports .read(Span<std::byte>) and .write(Span<const std::byte>)
125 : : //
126 : :
127 : : class CSizeComputer;
128 : :
129 : : enum
130 : : {
131 : : // primary actions
132 : : SER_NETWORK = (1 << 0),
133 : : SER_DISK = (1 << 1),
134 : : };
135 : :
136 : : /**
137 : : * Convert any argument to a reference to X, maintaining constness.
138 : : *
139 : : * This can be used in serialization code to invoke a base class's
140 : : * serialization routines.
141 : : *
142 : : * Example use:
143 : : * class Base { ... };
144 : : * class Child : public Base {
145 : : * int m_data;
146 : : * public:
147 : : * SERIALIZE_METHODS(Child, obj) {
148 : : * READWRITE(AsBase<Base>(obj), obj.m_data);
149 : : * }
150 : : * };
151 : : *
152 : : * static_cast cannot easily be used here, as the type of Obj will be const Child&
153 : : * during serialization and Child& during deserialization. AsBase will convert to
154 : : * const Base& and Base& appropriately.
155 : : */
156 : : template <class Out, class In>
157 : 3 : Out& AsBase(In& x)
158 : : {
159 : : static_assert(std::is_base_of_v<Out, In>);
160 : 3 : return x;
161 : : }
162 : : template <class Out, class In>
163 : 14014 : const Out& AsBase(const In& x)
164 : : {
165 : : static_assert(std::is_base_of_v<Out, In>);
166 : 14014 : return x;
167 : : }
168 : :
169 : : #define READWRITE(...) (ser_action.SerReadWriteMany(s, __VA_ARGS__))
170 : : #define SER_READ(obj, code) ser_action.SerRead(s, obj, [&](Stream& s, typename std::remove_const<Type>::type& obj) { code; })
171 : : #define SER_WRITE(obj, code) ser_action.SerWrite(s, obj, [&](Stream& s, const Type& obj) { code; })
172 : :
173 : : /**
174 : : * Implement the Ser and Unser methods needed for implementing a formatter (see Using below).
175 : : *
176 : : * Both Ser and Unser are delegated to a single static method SerializationOps, which is polymorphic
177 : : * in the serialized/deserialized type (allowing it to be const when serializing, and non-const when
178 : : * deserializing).
179 : : *
180 : : * Example use:
181 : : * struct FooFormatter {
182 : : * FORMATTER_METHODS(Class, obj) { READWRITE(obj.val1, VARINT(obj.val2)); }
183 : : * }
184 : : * would define a class FooFormatter that defines a serialization of Class objects consisting
185 : : * of serializing its val1 member using the default serialization, and its val2 member using
186 : : * VARINT serialization. That FooFormatter can then be used in statements like
187 : : * READWRITE(Using<FooFormatter>(obj.bla)).
188 : : */
189 : : #define FORMATTER_METHODS(cls, obj) \
190 : : template<typename Stream> \
191 : : static void Ser(Stream& s, const cls& obj) { SerializationOps(obj, s, ActionSerialize{}); } \
192 : : template<typename Stream> \
193 : : static void Unser(Stream& s, cls& obj) { SerializationOps(obj, s, ActionUnserialize{}); } \
194 : : template<typename Stream, typename Type, typename Operation> \
195 : : static void SerializationOps(Type& obj, Stream& s, Operation ser_action)
196 : :
197 : : /**
198 : : * Variant of FORMATTER_METHODS that supports a declared parameter type.
199 : : *
200 : : * If a formatter has a declared parameter type, it must be invoked directly or
201 : : * indirectly with a parameter of that type. This permits making serialization
202 : : * depend on run-time context in a type-safe way.
203 : : *
204 : : * Example use:
205 : : * struct BarParameter { bool fancy; ... };
206 : : * struct Bar { ... };
207 : : * struct FooFormatter {
208 : : * FORMATTER_METHODS(Bar, obj, BarParameter, param) {
209 : : * if (param.fancy) {
210 : : * READWRITE(VARINT(obj.value));
211 : : * } else {
212 : : * READWRITE(obj.value);
213 : : * }
214 : : * }
215 : : * };
216 : : * which would then be invoked as
217 : : * READWRITE(WithParams(BarParameter{...}, Using<FooFormatter>(obj.foo)))
218 : : *
219 : : * WithParams(parameter, obj) can be invoked anywhere in the call stack; it is
220 : : * passed down recursively into all serialization code, until another
221 : : * WithParams overrides it.
222 : : *
223 : : * Parameters will be implicitly converted where appropriate. This means that
224 : : * "parent" serialization code can use a parameter that derives from, or is
225 : : * convertible to, a "child" formatter's parameter type.
226 : : *
227 : : * Compilation will fail in any context where serialization is invoked but
228 : : * no parameter of a type convertible to BarParameter is provided.
229 : : */
230 : : #define FORMATTER_METHODS_PARAMS(cls, obj, paramcls, paramobj) \
231 : : template <typename Stream> \
232 : : static void Ser(Stream& s, const cls& obj) { SerializationOps(obj, s, ActionSerialize{}, s.GetParams()); } \
233 : : template <typename Stream> \
234 : : static void Unser(Stream& s, cls& obj) { SerializationOps(obj, s, ActionUnserialize{}, s.GetParams()); } \
235 : : template <typename Stream, typename Type, typename Operation> \
236 : : static void SerializationOps(Type& obj, Stream& s, Operation ser_action, const paramcls& paramobj)
237 : :
238 : : #define BASE_SERIALIZE_METHODS(cls) \
239 : : template <typename Stream> \
240 : : void Serialize(Stream& s) const \
241 : : { \
242 : : static_assert(std::is_same<const cls&, decltype(*this)>::value, "Serialize type mismatch"); \
243 : : Ser(s, *this); \
244 : : } \
245 : : template <typename Stream> \
246 : : void Unserialize(Stream& s) \
247 : : { \
248 : : static_assert(std::is_same<cls&, decltype(*this)>::value, "Unserialize type mismatch"); \
249 : : Unser(s, *this); \
250 : : }
251 : :
252 : : /**
253 : : * Implement the Serialize and Unserialize methods by delegating to a single templated
254 : : * static method that takes the to-be-(de)serialized object as a parameter. This approach
255 : : * has the advantage that the constness of the object becomes a template parameter, and
256 : : * thus allows a single implementation that sees the object as const for serializing
257 : : * and non-const for deserializing, without casts.
258 : : */
259 : : #define SERIALIZE_METHODS(cls, obj) \
260 : : BASE_SERIALIZE_METHODS(cls) \
261 : : FORMATTER_METHODS(cls, obj)
262 : :
263 : : /**
264 : : * Variant of SERIALIZE_METHODS that supports a declared parameter type.
265 : : *
266 : : * See FORMATTER_METHODS_PARAMS for more information on parameters.
267 : : */
268 : : #define SERIALIZE_METHODS_PARAMS(cls, obj, paramcls, paramobj) \
269 : : BASE_SERIALIZE_METHODS(cls) \
270 : : FORMATTER_METHODS_PARAMS(cls, obj, paramcls, paramobj)
271 : :
272 : : // clang-format off
273 : : #ifndef CHAR_EQUALS_INT8
274 : : template <typename Stream> void Serialize(Stream&, char) = delete; // char serialization forbidden. Use uint8_t or int8_t
275 : : #endif
276 : 0 : template <typename Stream> void Serialize(Stream& s, std::byte a) { ser_writedata8(s, uint8_t(a)); }
277 : 0 : template<typename Stream> inline void Serialize(Stream& s, int8_t a ) { ser_writedata8(s, a); }
278 : 11 : template<typename Stream> inline void Serialize(Stream& s, uint8_t a ) { ser_writedata8(s, a); }
279 : 0 : template<typename Stream> inline void Serialize(Stream& s, int16_t a ) { ser_writedata16(s, a); }
280 : 0 : template<typename Stream> inline void Serialize(Stream& s, uint16_t a) { ser_writedata16(s, a); }
281 : 14014 : template<typename Stream> inline void Serialize(Stream& s, int32_t a ) { ser_writedata32(s, a); }
282 : 3568 : template<typename Stream> inline void Serialize(Stream& s, uint32_t a) { ser_writedata32(s, a); }
283 : 7006 : template<typename Stream> inline void Serialize(Stream& s, int64_t a ) { ser_writedata64(s, a); }
284 : 27972 : template<typename Stream> inline void Serialize(Stream& s, uint64_t a) { ser_writedata64(s, a); }
285 : 3489 : template<typename Stream, int N> inline void Serialize(Stream& s, const char (&a)[N]) { s.write(MakeByteSpan(a)); }
286 : 17475 : template<typename Stream, int N> inline void Serialize(Stream& s, const unsigned char (&a)[N]) { s.write(MakeByteSpan(a)); }
287 : 3490 : template <typename Stream, typename B, std::size_t N> void Serialize(Stream& s, const std::array<B, N>& a) { (void)/* force byte-type */UCharCast(a.data()); s.write(MakeByteSpan(a)); }
288 : 63 : template <typename Stream, typename B> void Serialize(Stream& s, Span<B> span) { (void)/* force byte-type */UCharCast(span.data()); s.write(AsBytes(span)); }
289 : :
290 : : #ifndef CHAR_EQUALS_INT8
291 : : template <typename Stream> void Unserialize(Stream&, char) = delete; // char serialization forbidden. Use uint8_t or int8_t
292 : : #endif
293 : 0 : template <typename Stream> void Unserialize(Stream& s, std::byte& a) { a = std::byte{ser_readdata8(s)}; }
294 : 0 : template<typename Stream> inline void Unserialize(Stream& s, int8_t& a ) { a = ser_readdata8(s); }
295 : 0 : template<typename Stream> inline void Unserialize(Stream& s, uint8_t& a ) { a = ser_readdata8(s); }
296 : 0 : template<typename Stream> inline void Unserialize(Stream& s, int16_t& a ) { a = ser_readdata16(s); }
297 : 0 : template<typename Stream> inline void Unserialize(Stream& s, uint16_t& a) { a = ser_readdata16(s); }
298 : 2 : template<typename Stream> inline void Unserialize(Stream& s, int32_t& a ) { a = ser_readdata32(s); }
299 : 141 : template<typename Stream> inline void Unserialize(Stream& s, uint32_t& a) { a = ser_readdata32(s); }
300 : 1 : template<typename Stream> inline void Unserialize(Stream& s, int64_t& a ) { a = ser_readdata64(s); }
301 : 0 : template<typename Stream> inline void Unserialize(Stream& s, uint64_t& a) { a = ser_readdata64(s); }
302 : 135 : template<typename Stream, int N> inline void Unserialize(Stream& s, char (&a)[N]) { s.read(MakeWritableByteSpan(a)); }
303 : 135 : template<typename Stream, int N> inline void Unserialize(Stream& s, unsigned char (&a)[N]) { s.read(MakeWritableByteSpan(a)); }
304 : 135 : template <typename Stream, typename B, std::size_t N> void Unserialize(Stream& s, std::array<B, N>& a) { (void)/* force byte-type */UCharCast(a.data()); s.read(MakeWritableByteSpan(a)); }
305 : 0 : template <typename Stream, typename B> void Unserialize(Stream& s, Span<B> span) { (void)/* force byte-type */UCharCast(span.data()); s.read(AsWritableBytes(span)); }
306 : :
307 : 6993 : template <typename Stream> inline void Serialize(Stream& s, bool a) { uint8_t f = a; ser_writedata8(s, f); }
308 : 0 : template <typename Stream> inline void Unserialize(Stream& s, bool& a) { uint8_t f = ser_readdata8(s); a = f; }
309 : : // clang-format on
310 : :
311 : :
312 : : /**
313 : : * Compact Size
314 : : * size < 253 -- 1 byte
315 : : * size <= USHRT_MAX -- 3 bytes (253 + 2 bytes)
316 : : * size <= UINT_MAX -- 5 bytes (254 + 4 bytes)
317 : : * size > UINT_MAX -- 9 bytes (255 + 8 bytes)
318 : : */
319 : 21 : inline unsigned int GetSizeOfCompactSize(uint64_t nSize)
320 : : {
321 [ + - ]: 21 : if (nSize < 253) return sizeof(unsigned char);
322 [ # # ]: 0 : else if (nSize <= std::numeric_limits<uint16_t>::max()) return sizeof(unsigned char) + sizeof(uint16_t);
323 [ # # ]: 0 : else if (nSize <= std::numeric_limits<unsigned int>::max()) return sizeof(unsigned char) + sizeof(unsigned int);
324 : 0 : else return sizeof(unsigned char) + sizeof(uint64_t);
325 : 21 : }
326 : :
327 : : inline void WriteCompactSize(CSizeComputer& os, uint64_t nSize);
328 : :
329 : : template<typename Stream>
330 : 7029 : void WriteCompactSize(Stream& os, uint64_t nSize)
331 : : {
332 [ + - # # : 7029 : if (nSize < 253)
# # + - #
# # # #
# ]
333 : : {
334 : 7029 : ser_writedata8(os, nSize);
335 : 7029 : }
336 [ # # # # : 0 : else if (nSize <= std::numeric_limits<uint16_t>::max())
# # # # #
# # # #
# ]
337 : : {
338 : 0 : ser_writedata8(os, 253);
339 : 0 : ser_writedata16(os, nSize);
340 : 0 : }
341 [ # # # # : 0 : else if (nSize <= std::numeric_limits<unsigned int>::max())
# # # # #
# # # #
# ]
342 : : {
343 : 0 : ser_writedata8(os, 254);
344 : 0 : ser_writedata32(os, nSize);
345 : 0 : }
346 : : else
347 : : {
348 : 0 : ser_writedata8(os, 255);
349 : 0 : ser_writedata64(os, nSize);
350 : : }
351 : 7029 : return;
352 : : }
353 : :
354 : : /**
355 : : * Decode a CompactSize-encoded variable-length integer.
356 : : *
357 : : * As these are primarily used to encode the size of vector-like serializations, by default a range
358 : : * check is performed. When used as a generic number encoding, range_check should be set to false.
359 : : */
360 : : template<typename Stream>
361 : 5 : uint64_t ReadCompactSize(Stream& is, bool range_check = true)
362 : : {
363 : 5 : uint8_t chSize = ser_readdata8(is);
364 : 5 : uint64_t nSizeRet = 0;
365 [ + - # # : 5 : if (chSize < 253)
# # # # #
# # # # #
# # ]
366 : : {
367 : 5 : nSizeRet = chSize;
368 : 5 : }
369 [ # # # # : 0 : else if (chSize == 253)
# # # # #
# # # # #
# # ]
370 : : {
371 : 0 : nSizeRet = ser_readdata16(is);
372 [ # # # # : 0 : if (nSizeRet < 253)
# # # # #
# # # # #
# # ]
373 [ # # # # : 0 : throw std::ios_base::failure("non-canonical ReadCompactSize()");
# # # # #
# # # # #
# # ]
374 : 0 : }
375 [ # # # # : 0 : else if (chSize == 254)
# # # # #
# # # # #
# # ]
376 : : {
377 : 0 : nSizeRet = ser_readdata32(is);
378 [ # # # # : 0 : if (nSizeRet < 0x10000u)
# # # # #
# # # # #
# # ]
379 [ # # # # : 0 : throw std::ios_base::failure("non-canonical ReadCompactSize()");
# # # # #
# # # # #
# # ]
380 : 0 : }
381 : : else
382 : : {
383 : 0 : nSizeRet = ser_readdata64(is);
384 [ # # # # : 0 : if (nSizeRet < 0x100000000ULL)
# # # # #
# # # # #
# # ]
385 [ # # # # : 0 : throw std::ios_base::failure("non-canonical ReadCompactSize()");
# # # # #
# # # # #
# # ]
386 : : }
387 [ + - + - : 5 : if (range_check && nSizeRet > MAX_SIZE) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
388 [ # # # # : 0 : throw std::ios_base::failure("ReadCompactSize(): size too large");
# # # # #
# # # # #
# # ]
389 : : }
390 : 5 : return nSizeRet;
391 : 0 : }
392 : :
393 : : /**
394 : : * Variable-length integers: bytes are a MSB base-128 encoding of the number.
395 : : * The high bit in each byte signifies whether another digit follows. To make
396 : : * sure the encoding is one-to-one, one is subtracted from all but the last digit.
397 : : * Thus, the byte sequence a[] with length len, where all but the last byte
398 : : * has bit 128 set, encodes the number:
399 : : *
400 : : * (a[len-1] & 0x7F) + sum(i=1..len-1, 128^i*((a[len-i-1] & 0x7F)+1))
401 : : *
402 : : * Properties:
403 : : * * Very small (0-127: 1 byte, 128-16511: 2 bytes, 16512-2113663: 3 bytes)
404 : : * * Every integer has exactly one encoding
405 : : * * Encoding does not depend on size of original integer type
406 : : * * No redundancy: every (infinite) byte sequence corresponds to a list
407 : : * of encoded integers.
408 : : *
409 : : * 0: [0x00] 256: [0x81 0x00]
410 : : * 1: [0x01] 16383: [0xFE 0x7F]
411 : : * 127: [0x7F] 16384: [0xFF 0x00]
412 : : * 128: [0x80 0x00] 16511: [0xFF 0x7F]
413 : : * 255: [0x80 0x7F] 65535: [0x82 0xFE 0x7F]
414 : : * 2^32: [0x8E 0xFE 0xFE 0xFF 0x00]
415 : : */
416 : :
417 : : /**
418 : : * Mode for encoding VarInts.
419 : : *
420 : : * Currently there is no support for signed encodings. The default mode will not
421 : : * compile with signed values, and the legacy "nonnegative signed" mode will
422 : : * accept signed values, but improperly encode and decode them if they are
423 : : * negative. In the future, the DEFAULT mode could be extended to support
424 : : * negative numbers in a backwards compatible way, and additional modes could be
425 : : * added to support different varint formats (e.g. zigzag encoding).
426 : : */
427 : : enum class VarIntMode { DEFAULT, NONNEGATIVE_SIGNED };
428 : :
429 : : template <VarIntMode Mode, typename I>
430 : : struct CheckVarIntMode {
431 : 0 : constexpr CheckVarIntMode()
432 : : {
433 : : static_assert(Mode != VarIntMode::DEFAULT || std::is_unsigned<I>::value, "Unsigned type required with mode DEFAULT.");
434 : : static_assert(Mode != VarIntMode::NONNEGATIVE_SIGNED || std::is_signed<I>::value, "Signed type required with mode NONNEGATIVE_SIGNED.");
435 : 0 : }
436 : : };
437 : :
438 : : template<VarIntMode Mode, typename I>
439 : : inline unsigned int GetSizeOfVarInt(I n)
440 : : {
441 : : CheckVarIntMode<Mode, I>();
442 : : int nRet = 0;
443 : : while(true) {
444 : : nRet++;
445 : : if (n <= 0x7F)
446 : : break;
447 : : n = (n >> 7) - 1;
448 : : }
449 : : return nRet;
450 : : }
451 : :
452 : : template<typename I>
453 : : inline void WriteVarInt(CSizeComputer& os, I n);
454 : :
455 : : template<typename Stream, VarIntMode Mode, typename I>
456 : 0 : void WriteVarInt(Stream& os, I n)
457 : : {
458 : 0 : CheckVarIntMode<Mode, I>();
459 : : unsigned char tmp[(sizeof(n)*8+6)/7];
460 : 0 : int len=0;
461 : 0 : while(true) {
462 : 0 : tmp[len] = (n & 0x7F) | (len ? 0x80 : 0x00);
463 [ # # # # : 0 : if (n <= 0x7F)
# # # # #
# # # # #
# # # # ]
464 : 0 : break;
465 : 0 : n = (n >> 7) - 1;
466 : 0 : len++;
467 : : }
468 : 0 : do {
469 : 0 : ser_writedata8(os, tmp[len]);
470 [ # # # # : 0 : } while(len--);
# # # # #
# # # # #
# # # # ]
471 : 0 : }
472 : :
473 : : template<typename Stream, VarIntMode Mode, typename I>
474 : 0 : I ReadVarInt(Stream& is)
475 : : {
476 : 0 : CheckVarIntMode<Mode, I>();
477 : 0 : I n = 0;
478 : 0 : while(true) {
479 : 0 : unsigned char chData = ser_readdata8(is);
480 [ # # # # : 0 : if (n > (std::numeric_limits<I>::max() >> 7)) {
# # # # #
# ]
481 [ # # # # : 0 : throw std::ios_base::failure("ReadVarInt(): size too large");
# # # # #
# ]
482 : : }
483 : 0 : n = (n << 7) | (chData & 0x7F);
484 [ # # # # : 0 : if (chData & 0x80) {
# # # # #
# ]
485 [ # # # # : 0 : if (n == std::numeric_limits<I>::max()) {
# # # # #
# ]
486 [ # # # # : 0 : throw std::ios_base::failure("ReadVarInt(): size too large");
# # # # #
# ]
487 : : }
488 : 0 : n++;
489 : 0 : } else {
490 : 0 : return n;
491 : : }
492 : : }
493 : 0 : }
494 : :
495 : : /** Simple wrapper class to serialize objects using a formatter; used by Using(). */
496 : : template<typename Formatter, typename T>
497 : : class Wrapper
498 : : {
499 : : static_assert(std::is_lvalue_reference<T>::value, "Wrapper needs an lvalue reference type T");
500 : : protected:
501 : : T m_object;
502 : : public:
503 : 14015 : explicit Wrapper(T obj) : m_object(obj) {}
504 : 14012 : template<typename Stream> void Serialize(Stream &s) const { Formatter().Ser(s, m_object); }
505 : 3 : template<typename Stream> void Unserialize(Stream &s) { Formatter().Unser(s, m_object); }
506 : : };
507 : :
508 : : /** Cause serialization/deserialization of an object to be done using a specified formatter class.
509 : : *
510 : : * To use this, you need a class Formatter that has public functions Ser(stream, const object&) for
511 : : * serialization, and Unser(stream, object&) for deserialization. Serialization routines (inside
512 : : * READWRITE, or directly with << and >> operators), can then use Using<Formatter>(object).
513 : : *
514 : : * This works by constructing a Wrapper<Formatter, T>-wrapped version of object, where T is
515 : : * const during serialization, and non-const during deserialization, which maintains const
516 : : * correctness.
517 : : */
518 : : template<typename Formatter, typename T>
519 : 14015 : static inline Wrapper<Formatter, T&> Using(T&& t) { return Wrapper<Formatter, T&>(t); }
520 : :
521 : : #define VARINT_MODE(obj, mode) Using<VarIntFormatter<mode>>(obj)
522 : : #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj)
523 : : #define COMPACTSIZE(obj) Using<CompactSizeFormatter<true>>(obj)
524 : : #define LIMITED_STRING(obj,n) Using<LimitedStringFormatter<n>>(obj)
525 : :
526 : : /** Serialization wrapper class for integers in VarInt format. */
527 : : template<VarIntMode Mode>
528 : : struct VarIntFormatter
529 : : {
530 : 0 : template<typename Stream, typename I> void Ser(Stream &s, I v)
531 : : {
532 : 0 : WriteVarInt<Stream,Mode,typename std::remove_cv<I>::type>(s, v);
533 : 0 : }
534 : :
535 : 0 : template<typename Stream, typename I> void Unser(Stream& s, I& v)
536 : : {
537 : 0 : v = ReadVarInt<Stream,Mode,typename std::remove_cv<I>::type>(s);
538 : 0 : }
539 : : };
540 : :
541 : : /** Serialization wrapper class for custom integers and enums.
542 : : *
543 : : * It permits specifying the serialized size (1 to 8 bytes) and endianness.
544 : : *
545 : : * Use the big endian mode for values that are stored in memory in native
546 : : * byte order, but serialized in big endian notation. This is only intended
547 : : * to implement serializers that are compatible with existing formats, and
548 : : * its use is not recommended for new data structures.
549 : : */
550 : : template<int Bytes, bool BigEndian = false>
551 : : struct CustomUintFormatter
552 : : {
553 : : static_assert(Bytes > 0 && Bytes <= 8, "CustomUintFormatter Bytes out of range");
554 : : static constexpr uint64_t MAX = 0xffffffffffffffff >> (8 * (8 - Bytes));
555 : :
556 : 13986 : template <typename Stream, typename I> void Ser(Stream& s, I v)
557 : : {
558 [ # # # # : 13986 : if (v < 0 || v > MAX) throw std::ios_base::failure("CustomUintFormatter value out of range");
+ - # # #
# # # # #
# # ]
559 : : if (BigEndian) {
560 : 13986 : uint64_t raw = htobe64(v);
561 : 13986 : s.write(AsBytes(Span{&raw, 1}).last(Bytes));
562 : : } else {
563 : 0 : uint64_t raw = htole64(v);
564 : 0 : s.write(AsBytes(Span{&raw, 1}).first(Bytes));
565 : : }
566 : 13986 : }
567 : :
568 : 0 : template <typename Stream, typename I> void Unser(Stream& s, I& v)
569 : : {
570 : : using U = typename std::conditional<std::is_enum<I>::value, std::underlying_type<I>, std::common_type<I>>::type::type;
571 : : static_assert(std::numeric_limits<U>::max() >= MAX && std::numeric_limits<U>::min() <= 0, "Assigned type too small");
572 : 0 : uint64_t raw = 0;
573 : : if (BigEndian) {
574 : 0 : s.read(AsWritableBytes(Span{&raw, 1}).last(Bytes));
575 : 0 : v = static_cast<I>(be64toh(raw));
576 : : } else {
577 : 0 : s.read(AsWritableBytes(Span{&raw, 1}).first(Bytes));
578 : 0 : v = static_cast<I>(le64toh(raw));
579 : : }
580 : 0 : }
581 : : };
582 : :
583 : : template<int Bytes> using BigEndianFormatter = CustomUintFormatter<Bytes, true>;
584 : :
585 : : /** Formatter for integers in CompactSize format. */
586 : : template<bool RangeCheck>
587 : : struct CompactSizeFormatter
588 : : {
589 : : template<typename Stream, typename I>
590 : 0 : void Unser(Stream& s, I& v)
591 : : {
592 : 0 : uint64_t n = ReadCompactSize<Stream>(s, RangeCheck);
593 [ # # # # : 0 : if (n < std::numeric_limits<I>::min() || n > std::numeric_limits<I>::max()) {
# # # # #
# # # # #
# # # # #
# # # #
# ]
594 [ # # # # : 0 : throw std::ios_base::failure("CompactSize exceeds limit of type");
# # # # #
# # # # #
# # # # #
# # # #
# ]
595 : : }
596 : 0 : v = n;
597 : 0 : }
598 : :
599 : : template<typename Stream, typename I>
600 : 0 : void Ser(Stream& s, I v)
601 : : {
602 : : static_assert(std::is_unsigned<I>::value, "CompactSize only supported for unsigned integers");
603 : : static_assert(std::numeric_limits<I>::max() <= std::numeric_limits<uint64_t>::max(), "CompactSize only supports 64-bit integers and below");
604 : :
605 : 0 : WriteCompactSize<Stream>(s, v);
606 : 0 : }
607 : : };
608 : :
609 : : template <typename U, bool LOSSY = false>
610 : : struct ChronoFormatter {
611 : : template <typename Stream, typename Tp>
612 : 0 : void Unser(Stream& s, Tp& tp)
613 : : {
614 : : U u;
615 : 0 : s >> u;
616 : : // Lossy deserialization does not make sense, so force Wnarrowing
617 : 0 : tp = Tp{typename Tp::duration{typename Tp::duration::rep{u}}};
618 : 0 : }
619 : : template <typename Stream, typename Tp>
620 : 0 : void Ser(Stream& s, Tp tp)
621 : : {
622 : : if constexpr (LOSSY) {
623 : 0 : s << U(tp.time_since_epoch().count());
624 : : } else {
625 : 0 : s << U{tp.time_since_epoch().count()};
626 : : }
627 : 0 : }
628 : : };
629 : : template <typename U>
630 : : using LossyChronoFormatter = ChronoFormatter<U, true>;
631 : :
632 : : class CompactSizeWriter
633 : : {
634 : : protected:
635 : : uint64_t n;
636 : : public:
637 : 0 : explicit CompactSizeWriter(uint64_t n_in) : n(n_in) { }
638 : :
639 : : template<typename Stream>
640 : 0 : void Serialize(Stream &s) const {
641 : 0 : WriteCompactSize<Stream>(s, n);
642 : 0 : }
643 : : };
644 : :
645 : : template<size_t Limit>
646 : : struct LimitedStringFormatter
647 : : {
648 : : template<typename Stream>
649 : 0 : void Unser(Stream& s, std::string& v)
650 : : {
651 : 0 : size_t size = ReadCompactSize(s);
652 [ # # ]: 0 : if (size > Limit) {
653 [ # # ]: 0 : throw std::ios_base::failure("String length limit exceeded");
654 : : }
655 : 0 : v.resize(size);
656 [ # # ]: 0 : if (size != 0) s.read(MakeWritableByteSpan(v));
657 : 0 : }
658 : :
659 : : template<typename Stream>
660 : 0 : void Ser(Stream& s, const std::string& v)
661 : : {
662 : 0 : s << v;
663 : 0 : }
664 : : };
665 : :
666 : : /** Formatter to serialize/deserialize vector elements using another formatter
667 : : *
668 : : * Example:
669 : : * struct X {
670 : : * std::vector<uint64_t> v;
671 : : * SERIALIZE_METHODS(X, obj) { READWRITE(Using<VectorFormatter<VarInt>>(obj.v)); }
672 : : * };
673 : : * will define a struct that contains a vector of uint64_t, which is serialized
674 : : * as a vector of VarInt-encoded integers.
675 : : *
676 : : * V is not required to be an std::vector type. It works for any class that
677 : : * exposes a value_type, size, reserve, emplace_back, back, and const iterators.
678 : : */
679 : : template<class Formatter>
680 : : struct VectorFormatter
681 : : {
682 : : template<typename Stream, typename V>
683 : 26 : void Ser(Stream& s, const V& v)
684 : : {
685 : 0 : Formatter formatter;
686 : 26 : WriteCompactSize(s, v.size());
687 [ + + + + : 52 : for (const typename V::value_type& elem : v) {
+ + # # #
# # # # #
# # # # #
# + + # #
# # # # #
# # # #
# ]
688 : 26 : formatter.Ser(s, elem);
689 : : }
690 : 26 : }
691 : :
692 : : template<typename Stream, typename V>
693 : 3 : void Unser(Stream& s, V& v)
694 : : {
695 : 0 : Formatter formatter;
696 : 3 : v.clear();
697 : 3 : size_t size = ReadCompactSize(s);
698 : 3 : size_t allocated = 0;
699 [ + + + + : 6 : while (allocated < size) {
+ + # # #
# # # # #
# # # # #
# # # # #
# # # # ]
700 : : // For DoS prevention, do not blindly allocate as much as the stream claims to contain.
701 : : // Instead, allocate in 5MiB batches, so that an attacker actually needs to provide
702 : : // X MiB of data to make us allocate X+5 Mib.
703 : : static_assert(sizeof(typename V::value_type) <= MAX_VECTOR_ALLOCATE, "Vector element size too large");
704 : 3 : allocated = std::min(size, allocated + MAX_VECTOR_ALLOCATE / sizeof(typename V::value_type));
705 : 3 : v.reserve(allocated);
706 [ + + + + : 6 : while (v.size() < allocated) {
+ + # # #
# # # # #
# # # # #
# # # # #
# # # # ]
707 : 3 : v.emplace_back();
708 : 3 : formatter.Unser(s, v.back());
709 : : }
710 : : }
711 : 3 : };
712 : : };
713 : :
714 : : /**
715 : : * Forward declarations
716 : : */
717 : :
718 : : /**
719 : : * string
720 : : */
721 : : template<typename Stream, typename C> void Serialize(Stream& os, const std::basic_string<C>& str);
722 : : template<typename Stream, typename C> void Unserialize(Stream& is, std::basic_string<C>& str);
723 : :
724 : : /**
725 : : * prevector
726 : : * prevectors of unsigned char are a special case and are intended to be serialized as a single opaque blob.
727 : : */
728 : : template<typename Stream, unsigned int N, typename T> inline void Serialize(Stream& os, const prevector<N, T>& v);
729 : : template<typename Stream, unsigned int N, typename T> inline void Unserialize(Stream& is, prevector<N, T>& v);
730 : :
731 : : /**
732 : : * vector
733 : : * vectors of unsigned char are a special case and are intended to be serialized as a single opaque blob.
734 : : */
735 : : template<typename Stream, typename T, typename A> inline void Serialize(Stream& os, const std::vector<T, A>& v);
736 : : template<typename Stream, typename T, typename A> inline void Unserialize(Stream& is, std::vector<T, A>& v);
737 : :
738 : : /**
739 : : * pair
740 : : */
741 : : template<typename Stream, typename K, typename T> void Serialize(Stream& os, const std::pair<K, T>& item);
742 : : template<typename Stream, typename K, typename T> void Unserialize(Stream& is, std::pair<K, T>& item);
743 : :
744 : : /**
745 : : * map
746 : : */
747 : : template<typename Stream, typename K, typename T, typename Pred, typename A> void Serialize(Stream& os, const std::map<K, T, Pred, A>& m);
748 : : template<typename Stream, typename K, typename T, typename Pred, typename A> void Unserialize(Stream& is, std::map<K, T, Pred, A>& m);
749 : :
750 : : /**
751 : : * set
752 : : */
753 : : template<typename Stream, typename K, typename Pred, typename A> void Serialize(Stream& os, const std::set<K, Pred, A>& m);
754 : : template<typename Stream, typename K, typename Pred, typename A> void Unserialize(Stream& is, std::set<K, Pred, A>& m);
755 : :
756 : : /**
757 : : * shared_ptr
758 : : */
759 : : template<typename Stream, typename T> void Serialize(Stream& os, const std::shared_ptr<const T>& p);
760 : : template<typename Stream, typename T> void Unserialize(Stream& os, std::shared_ptr<const T>& p);
761 : :
762 : : /**
763 : : * unique_ptr
764 : : */
765 : : template<typename Stream, typename T> void Serialize(Stream& os, const std::unique_ptr<const T>& p);
766 : : template<typename Stream, typename T> void Unserialize(Stream& os, std::unique_ptr<const T>& p);
767 : :
768 : :
769 : :
770 : : /**
771 : : * If none of the specialized versions above matched, default to calling member function.
772 : : */
773 : : template<typename Stream, typename T>
774 : 59611 : inline void Serialize(Stream& os, const T& a)
775 : : {
776 : 59611 : a.Serialize(os);
777 : 59611 : }
778 : :
779 : : template<typename Stream, typename T>
780 : 148 : inline void Unserialize(Stream& is, T&& a)
781 : : {
782 : 148 : a.Unserialize(is);
783 : 148 : }
784 : :
785 : : /** Default formatter. Serializes objects as themselves.
786 : : *
787 : : * The vector/prevector serialization code passes this to VectorFormatter
788 : : * to enable reusing that logic. It shouldn't be needed elsewhere.
789 : : */
790 : : struct DefaultFormatter
791 : : {
792 : : template<typename Stream, typename T>
793 : 26 : static void Ser(Stream& s, const T& t) { Serialize(s, t); }
794 : :
795 : : template<typename Stream, typename T>
796 : 3 : static void Unser(Stream& s, T& t) { Unserialize(s, t); }
797 : : };
798 : :
799 : :
800 : :
801 : :
802 : :
803 : : /**
804 : : * string
805 : : */
806 : : template<typename Stream, typename C>
807 : 6998 : void Serialize(Stream& os, const std::basic_string<C>& str)
808 : : {
809 : 6998 : WriteCompactSize(os, str.size());
810 [ + + # # ]: 6998 : if (!str.empty())
811 : 5 : os.write(MakeByteSpan(str));
812 : 6998 : }
813 : :
814 : : template<typename Stream, typename C>
815 : 0 : void Unserialize(Stream& is, std::basic_string<C>& str)
816 : : {
817 : 0 : unsigned int nSize = ReadCompactSize(is);
818 : 0 : str.resize(nSize);
819 [ # # # # ]: 0 : if (nSize != 0)
820 : 0 : is.read(MakeWritableByteSpan(str));
821 : 0 : }
822 : :
823 : :
824 : :
825 : : /**
826 : : * prevector
827 : : */
828 : : template <typename Stream, unsigned int N, typename T>
829 : 24 : void Serialize(Stream& os, const prevector<N, T>& v)
830 : : {
831 : : if constexpr (std::is_same_v<T, unsigned char>) {
832 : 24 : WriteCompactSize(os, v.size());
833 [ + + # # : 24 : if (!v.empty())
# # # # #
# ]
834 : 22 : os.write(MakeByteSpan(v));
835 : : } else {
836 : 0 : Serialize(os, Using<VectorFormatter<DefaultFormatter>>(v));
837 : : }
838 : 24 : }
839 : :
840 : :
841 : : template <typename Stream, unsigned int N, typename T>
842 : 2 : void Unserialize(Stream& is, prevector<N, T>& v)
843 : : {
844 : : if constexpr (std::is_same_v<T, unsigned char>) {
845 : : // Limit size per read so bogus size value won't cause out of memory
846 : 2 : v.clear();
847 : 2 : unsigned int nSize = ReadCompactSize(is);
848 : 2 : unsigned int i = 0;
849 [ + + # # ]: 4 : while (i < nSize) {
850 : 2 : unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T)));
851 : 2 : v.resize_uninitialized(i + blk);
852 : 2 : is.read(AsWritableBytes(Span{&v[i], blk}));
853 : 2 : i += blk;
854 : : }
855 : : } else {
856 : 0 : Unserialize(is, Using<VectorFormatter<DefaultFormatter>>(v));
857 : : }
858 : 2 : }
859 : :
860 : :
861 : : /**
862 : : * vector
863 : : */
864 : : template <typename Stream, typename T, typename A>
865 : 28 : void Serialize(Stream& os, const std::vector<T, A>& v)
866 : : {
867 : : if constexpr (std::is_same_v<T, unsigned char>) {
868 : 2 : WriteCompactSize(os, v.size());
869 [ - + # # : 2 : if (!v.empty())
# # # # ]
870 : 2 : os.write(MakeByteSpan(v));
871 : : } else if constexpr (std::is_same_v<T, bool>) {
872 : : // A special case for std::vector<bool>, as dereferencing
873 : : // std::vector<bool>::const_iterator does not result in a const bool&
874 : : // due to std::vector's special casing for bool arguments.
875 : 0 : WriteCompactSize(os, v.size());
876 [ # # ]: 0 : for (bool elem : v) {
877 : 0 : ::Serialize(os, elem);
878 : : }
879 : : } else {
880 : 26 : Serialize(os, Using<VectorFormatter<DefaultFormatter>>(v));
881 : : }
882 : 28 : }
883 : :
884 : :
885 : : template <typename Stream, typename T, typename A>
886 : 3 : void Unserialize(Stream& is, std::vector<T, A>& v)
887 : : {
888 : : if constexpr (std::is_same_v<T, unsigned char>) {
889 : : // Limit size per read so bogus size value won't cause out of memory
890 : 0 : v.clear();
891 : 0 : unsigned int nSize = ReadCompactSize(is);
892 : 0 : unsigned int i = 0;
893 [ # # # # : 0 : while (i < nSize) {
# # # # ]
894 : 0 : unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T)));
895 : 0 : v.resize(i + blk);
896 : 0 : is.read(AsWritableBytes(Span{&v[i], blk}));
897 : 0 : i += blk;
898 : : }
899 : : } else {
900 : 3 : Unserialize(is, Using<VectorFormatter<DefaultFormatter>>(v));
901 : : }
902 : 3 : }
903 : :
904 : :
905 : : /**
906 : : * pair
907 : : */
908 : : template<typename Stream, typename K, typename T>
909 : 5 : void Serialize(Stream& os, const std::pair<K, T>& item)
910 : : {
911 : 5 : Serialize(os, item.first);
912 : 5 : Serialize(os, item.second);
913 : 5 : }
914 : :
915 : : template<typename Stream, typename K, typename T>
916 : 0 : void Unserialize(Stream& is, std::pair<K, T>& item)
917 : : {
918 : 0 : Unserialize(is, item.first);
919 : 0 : Unserialize(is, item.second);
920 : 0 : }
921 : :
922 : :
923 : :
924 : : /**
925 : : * map
926 : : */
927 : : template<typename Stream, typename K, typename T, typename Pred, typename A>
928 : 0 : void Serialize(Stream& os, const std::map<K, T, Pred, A>& m)
929 : : {
930 : 0 : WriteCompactSize(os, m.size());
931 [ # # ]: 0 : for (const auto& entry : m)
932 : 0 : Serialize(os, entry);
933 : 0 : }
934 : :
935 : : template<typename Stream, typename K, typename T, typename Pred, typename A>
936 : 0 : void Unserialize(Stream& is, std::map<K, T, Pred, A>& m)
937 : : {
938 : 0 : m.clear();
939 : 0 : unsigned int nSize = ReadCompactSize(is);
940 : 0 : typename std::map<K, T, Pred, A>::iterator mi = m.begin();
941 [ # # ]: 0 : for (unsigned int i = 0; i < nSize; i++)
942 : : {
943 : 0 : std::pair<K, T> item;
944 [ # # ]: 0 : Unserialize(is, item);
945 [ # # ]: 0 : mi = m.insert(mi, item);
946 : 0 : }
947 : 0 : }
948 : :
949 : :
950 : :
951 : : /**
952 : : * set
953 : : */
954 : : template<typename Stream, typename K, typename Pred, typename A>
955 : 0 : void Serialize(Stream& os, const std::set<K, Pred, A>& m)
956 : : {
957 : 0 : WriteCompactSize(os, m.size());
958 [ # # ]: 0 : for (typename std::set<K, Pred, A>::const_iterator it = m.begin(); it != m.end(); ++it)
959 : 0 : Serialize(os, (*it));
960 : 0 : }
961 : :
962 : : template<typename Stream, typename K, typename Pred, typename A>
963 : 0 : void Unserialize(Stream& is, std::set<K, Pred, A>& m)
964 : : {
965 : 0 : m.clear();
966 : 0 : unsigned int nSize = ReadCompactSize(is);
967 : 0 : typename std::set<K, Pred, A>::iterator it = m.begin();
968 [ # # ]: 0 : for (unsigned int i = 0; i < nSize; i++)
969 : : {
970 : 0 : K key;
971 : 0 : Unserialize(is, key);
972 : 0 : it = m.insert(it, key);
973 : 0 : }
974 : 0 : }
975 : :
976 : :
977 : :
978 : : /**
979 : : * unique_ptr
980 : : */
981 : : template<typename Stream, typename T> void
982 : : Serialize(Stream& os, const std::unique_ptr<const T>& p)
983 : : {
984 : : Serialize(os, *p);
985 : : }
986 : :
987 : : template<typename Stream, typename T>
988 : : void Unserialize(Stream& is, std::unique_ptr<const T>& p)
989 : : {
990 : : p.reset(new T(deserialize, is));
991 : : }
992 : :
993 : :
994 : :
995 : : /**
996 : : * shared_ptr
997 : : */
998 : : template<typename Stream, typename T> void
999 : 4 : Serialize(Stream& os, const std::shared_ptr<const T>& p)
1000 : : {
1001 : 4 : Serialize(os, *p);
1002 : 4 : }
1003 : :
1004 : : template<typename Stream, typename T>
1005 : 1 : void Unserialize(Stream& is, std::shared_ptr<const T>& p)
1006 : : {
1007 : 1 : p = std::make_shared<const T>(deserialize, is);
1008 : 1 : }
1009 : :
1010 : : /**
1011 : : * Support for (un)serializing many things at once
1012 : : */
1013 : :
1014 : : template <typename Stream, typename... Args>
1015 : 28035 : void SerializeMany(Stream& s, const Args&... args)
1016 : : {
1017 : 28035 : (::Serialize(s, args), ...);
1018 : 28035 : }
1019 : :
1020 : : template <typename Stream, typename... Args>
1021 : 142 : inline void UnserializeMany(Stream& s, Args&&... args)
1022 : : {
1023 : 142 : (::Unserialize(s, args), ...);
1024 : 142 : }
1025 : :
1026 : : /**
1027 : : * Support for all macros providing or using the ser_action parameter of the SerializationOps method.
1028 : : */
1029 : : struct ActionSerialize {
1030 : : static constexpr bool ForRead() { return false; }
1031 : :
1032 : : template<typename Stream, typename... Args>
1033 : 17553 : static void SerReadWriteMany(Stream& s, const Args&... args)
1034 : : {
1035 : 17553 : ::SerializeMany(s, args...);
1036 : 17553 : }
1037 : :
1038 : : template<typename Stream, typename Type, typename Fn>
1039 : 0 : static void SerRead(Stream& s, Type&&, Fn&&)
1040 : : {
1041 : 0 : }
1042 : :
1043 : : template<typename Stream, typename Type, typename Fn>
1044 : 0 : static void SerWrite(Stream& s, Type&& obj, Fn&& fn)
1045 : : {
1046 : 0 : fn(s, std::forward<Type>(obj));
1047 : 0 : }
1048 : : };
1049 : : struct ActionUnserialize {
1050 : : static constexpr bool ForRead() { return true; }
1051 : :
1052 : : template<typename Stream, typename... Args>
1053 : 142 : static void SerReadWriteMany(Stream& s, Args&&... args)
1054 : : {
1055 : 142 : ::UnserializeMany(s, args...);
1056 : 142 : }
1057 : :
1058 : : template<typename Stream, typename Type, typename Fn>
1059 : 0 : static void SerRead(Stream& s, Type&& obj, Fn&& fn)
1060 : : {
1061 : 0 : fn(s, std::forward<Type>(obj));
1062 : 0 : }
1063 : :
1064 : : template<typename Stream, typename Type, typename Fn>
1065 : 0 : static void SerWrite(Stream& s, Type&&, Fn&&)
1066 : : {
1067 : 0 : }
1068 : : };
1069 : :
1070 : : /* ::GetSerializeSize implementations
1071 : : *
1072 : : * Computing the serialized size of objects is done through a special stream
1073 : : * object of type CSizeComputer, which only records the number of bytes written
1074 : : * to it.
1075 : : *
1076 : : * If your Serialize or SerializationOp method has non-trivial overhead for
1077 : : * serialization, it may be worthwhile to implement a specialized version for
1078 : : * CSizeComputer, which uses the s.seek() method to record bytes that would
1079 : : * be written instead.
1080 : : */
1081 : : class CSizeComputer
1082 : : {
1083 : : protected:
1084 : 6 : size_t nSize{0};
1085 : :
1086 : : const int nVersion;
1087 : : public:
1088 : 12 : explicit CSizeComputer(int nVersionIn) : nVersion(nVersionIn) {}
1089 : :
1090 : 52 : void write(Span<const std::byte> src)
1091 : : {
1092 : 52 : this->nSize += src.size();
1093 : 52 : }
1094 : :
1095 : : /** Pretend _nSize bytes are written, without specifying them. */
1096 : 21 : void seek(size_t _nSize)
1097 : : {
1098 : 21 : this->nSize += _nSize;
1099 : 21 : }
1100 : :
1101 : : template<typename T>
1102 : 32 : CSizeComputer& operator<<(const T& obj)
1103 : : {
1104 : 32 : ::Serialize(*this, obj);
1105 : 32 : return (*this);
1106 : : }
1107 : :
1108 : 6 : size_t size() const {
1109 : 6 : return nSize;
1110 : : }
1111 : :
1112 : 4 : int GetVersion() const { return nVersion; }
1113 : : };
1114 : :
1115 : : template<typename I>
1116 : : inline void WriteVarInt(CSizeComputer &s, I n)
1117 : : {
1118 : : s.seek(GetSizeOfVarInt<I>(n));
1119 : : }
1120 : :
1121 : 21 : inline void WriteCompactSize(CSizeComputer &s, uint64_t nSize)
1122 : : {
1123 : 21 : s.seek(GetSizeOfCompactSize(nSize));
1124 : 21 : }
1125 : :
1126 : : template <typename T>
1127 : 6 : size_t GetSerializeSize(const T& t, int nVersion = 0)
1128 : : {
1129 : 6 : return (CSizeComputer(nVersion) << t).size();
1130 : : }
1131 : :
1132 : : template <typename... T>
1133 : 0 : size_t GetSerializeSizeMany(int nVersion, const T&... t)
1134 : : {
1135 : 0 : CSizeComputer sc(nVersion);
1136 : 0 : SerializeMany(sc, t...);
1137 : 0 : return sc.size();
1138 : : }
1139 : :
1140 : : /** Wrapper that overrides the GetParams() function of a stream (and hides GetVersion/GetType). */
1141 : : template <typename Params, typename SubStream>
1142 : : class ParamsStream
1143 : : {
1144 : : const Params& m_params;
1145 : : SubStream& m_substream; // private to avoid leaking version/type into serialization code that shouldn't see it
1146 : :
1147 : : public:
1148 : 13986 : ParamsStream(const Params& params LIFETIMEBOUND, SubStream& substream LIFETIMEBOUND) : m_params{params}, m_substream{substream} {}
1149 : 13986 : template <typename U> ParamsStream& operator<<(const U& obj) { ::Serialize(*this, obj); return *this; }
1150 : 0 : template <typename U> ParamsStream& operator>>(U&& obj) { ::Unserialize(*this, obj); return *this; }
1151 : 27972 : void write(Span<const std::byte> src) { m_substream.write(src); }
1152 : 0 : void read(Span<std::byte> dst) { m_substream.read(dst); }
1153 : 0 : void ignore(size_t num) { m_substream.ignore(num); }
1154 : 0 : bool eof() const { return m_substream.eof(); }
1155 : : size_t size() const { return m_substream.size(); }
1156 : 13986 : const Params& GetParams() const { return m_params; }
1157 : : int GetVersion() = delete; // Deprecated with Params usage
1158 : : int GetType() = delete; // Deprecated with Params usage
1159 : : };
1160 : :
1161 : : /** Wrapper that serializes objects with the specified parameters. */
1162 : : template <typename Params, typename T>
1163 : : class ParamsWrapper
1164 : : {
1165 : : const Params& m_params;
1166 : : T& m_object;
1167 : :
1168 : : public:
1169 : 13986 : explicit ParamsWrapper(const Params& params, T& obj) : m_params{params}, m_object{obj} {}
1170 : :
1171 : : template <typename Stream>
1172 : 13986 : void Serialize(Stream& s) const
1173 : : {
1174 : 13986 : ParamsStream ss{m_params, s};
1175 : 13986 : ::Serialize(ss, m_object);
1176 : 13986 : }
1177 : : template <typename Stream>
1178 : 0 : void Unserialize(Stream& s)
1179 : : {
1180 : 0 : ParamsStream ss{m_params, s};
1181 : 0 : ::Unserialize(ss, m_object);
1182 : 0 : }
1183 : : };
1184 : :
1185 : : /**
1186 : : * Return a wrapper around t that (de)serializes it with specified parameter params.
1187 : : *
1188 : : * See FORMATTER_METHODS_PARAMS for more information on serialization parameters.
1189 : : */
1190 : : template <typename Params, typename T>
1191 : 13986 : static auto WithParams(const Params& params, T&& t)
1192 : : {
1193 : 13986 : return ParamsWrapper<Params, T>{params, t};
1194 : : }
1195 : :
1196 : : /**
1197 : : * Helper macro for SerParams structs
1198 : : *
1199 : : * Allows you define SerParams instances and then apply them directly
1200 : : * to an object via function call syntax, eg:
1201 : : *
1202 : : * constexpr SerParams FOO{....};
1203 : : * ss << FOO(obj);
1204 : : */
1205 : : #define SER_PARAMS_OPFUNC \
1206 : : template <typename T> \
1207 : : auto operator()(T&& t) const { return WithParams(*this, t); }
1208 : :
1209 : : #endif // BITCOIN_SERIALIZE_H
|