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