Bitcoin Core 32.99.0
P2P Digital Currency
Loading...
Searching...
No Matches
serialize_tests.cpp
Go to the documentation of this file.
1// Copyright (c) 2012-present The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <hash.h>
6#include <serialize.h>
7#include <streams.h>
8#include <test/util/common.h>
10#include <util/strencodings.h>
11
12#include <boost/test/unit_test.hpp>
13
14#include <algorithm>
15#include <cstdint>
16#include <limits>
17#include <string>
18
20
21// For testing move-semantics, declare a version of datastream that can be moved
22// but is not copyable.
32
34{
35protected:
36 int intval;
37 bool boolval;
38 std::string stringval;
39 char charstrval[16];
41public:
43 CSerializeMethodsTestSingle(int intvalin, bool boolvalin, std::string stringvalin, const uint8_t* charstrvalin, const CTransactionRef& txvalin) : intval(intvalin), boolval(boolvalin), stringval(std::move(stringvalin)), txval(txvalin)
44 {
45 memcpy(charstrval, charstrvalin, sizeof(charstrval));
46 }
47
49 {
50 READWRITE(obj.intval);
51 READWRITE(obj.boolval);
52 READWRITE(obj.stringval);
53 READWRITE(obj.charstrval);
55 }
56
58 {
59 return intval == rhs.intval &&
60 boolval == rhs.boolval &&
61 stringval == rhs.stringval &&
62 strcmp(charstrval, rhs.charstrval) == 0 &&
63 txval->Equals(*rhs.txval);
64 }
65};
66
77
79{
80 BOOST_CHECK_EQUAL(sizeof(unsigned char), GetSerializeSize((unsigned char)0));
89 // Bool is serialized as uint8_t
91
92 // Sanity-check GetSerializeSize and c++ type matching
93 BOOST_CHECK_EQUAL(GetSerializeSize((unsigned char)0), 1U);
103 BOOST_CHECK_EQUAL(GetSerializeSize(std::array<uint8_t, 1>{0}), 1U);
104 BOOST_CHECK_EQUAL(GetSerializeSize(std::array<uint8_t, 2>{0, 0}), 2U);
105}
106
108{
109 // encode
110
111 DataStream ss{};
112 DataStream::size_type size = 0;
113 for (int i = 0; i < 100000; i++) {
116 BOOST_CHECK(size == ss.size());
117 }
118
119 for (uint64_t i = 0; i < 100000000000ULL; i += 999999937) {
120 ss << VARINT(i);
121 size += ::GetSerializeSize(VARINT(i));
122 BOOST_CHECK(size == ss.size());
123 }
124
125 // decode
126 for (int i = 0; i < 100000; i++) {
127 int j = -1;
129 BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
130 }
131
132 for (uint64_t i = 0; i < 100000000000ULL; i += 999999937) {
133 uint64_t j = std::numeric_limits<uint64_t>::max();
134 ss >> VARINT(j);
135 BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
136 }
137}
138
140{
141 const auto read_varint = [](uint64_t serialized, auto value) {
142 DataStream ss{};
143 ss << VARINT(serialized);
144 ss >> VARINT(value);
145 return value;
146 };
147
148 for (const uint32_t small_value : {
149 uint32_t{0},
150 uint32_t{1},
151 std::numeric_limits<uint32_t>::max(),
152 }) {
154 }
155
156 for (const uint64_t large_value : {
157 uint64_t{std::numeric_limits<uint32_t>::max()} + 1,
158 std::numeric_limits<uint64_t>::max(),
159 }) {
161
162 BOOST_CHECK_EXCEPTION(read_varint(large_value, uint32_t{}), std::ios_base::failure, HasReason{"VarInt exceeds destination range"});
163 }
164
165 BOOST_CHECK_EXCEPTION(read_varint(uint64_t{1} << 39, uint32_t{}), std::ios_base::failure, HasReason{"VarInt increment exceeds destination range"});
166}
167
169{
170 DataStream ss{};
175 ss << VARINT(uint8_t{0x80}); BOOST_CHECK_EQUAL(HexStr(ss), "8000"); ss.clear();
179 ss << VARINT(uint16_t{0xffff}); BOOST_CHECK_EQUAL(HexStr(ss), "82fe7f"); ss.clear();
182 ss << VARINT(0x80123456U); BOOST_CHECK_EQUAL(HexStr(ss), "86ffc7e756"); ss.clear();
183 ss << VARINT(uint32_t{0x80123456U}); BOOST_CHECK_EQUAL(HexStr(ss), "86ffc7e756"); ss.clear();
184 ss << VARINT(0xffffffff); BOOST_CHECK_EQUAL(HexStr(ss), "8efefefe7f"); ss.clear();
185 ss << VARINT_MODE(0x7fffffffffffffffLL, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "fefefefefefefefe7f"); ss.clear();
186 ss << VARINT(0xffffffffffffffffULL); BOOST_CHECK_EQUAL(HexStr(ss), "80fefefefefefefefe7f"); ss.clear();
187}
188
190{
191 DataStream ss{};
192 std::vector<char>::size_type i, j;
193
194 for (i = 1; i <= MAX_SIZE; i *= 2)
195 {
196 WriteCompactSize(ss, i-1);
198 }
199 for (i = 1; i <= MAX_SIZE; i *= 2)
200 {
202 BOOST_CHECK_MESSAGE((i-1) == j, "decoded:" << j << " expected:" << (i-1));
204 BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
205 }
206}
207
208static bool isCanonicalException(const std::ios_base::failure& ex)
209{
210 std::ios_base::failure expectedException("non-canonical ReadCompactSize()");
211
212 // The string returned by what() can be different for different platforms.
213 // Instead of directly comparing the ex.what() with an expected string,
214 // create an instance of exception to see if ex.what() matches
215 // the expected explanatory string returned by the exception instance.
216 return strcmp(expectedException.what(), ex.what()) == 0;
217}
218
220{
221 std::vector<uint8_t> vec1{1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1};
222 std::vector<bool> vec2{1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1};
223
224 BOOST_CHECK(vec1 == std::vector<uint8_t>(vec2.begin(), vec2.end()));
225 BOOST_CHECK((HashWriter{} << vec1).GetHash() == (HashWriter{} << vec2).GetHash());
226}
227
229{
230 std::array<uint8_t, 32> array1{1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1};
232 ds << array1;
233 std::array<uint8_t, 32> array2;
234 ds >> array2;
236}
237
239{
240 // Write some non-canonical CompactSize encodings, and
241 // make sure an exception is thrown when read back.
242 DataStream ss{};
243 std::vector<char>::size_type n;
244
245 // zero encoded with three bytes:
246 ss << std::span{"\xfd\x00\x00"}.first(3);
248
249 // 0xfc encoded with three bytes:
250 ss << std::span{"\xfd\xfc\x00"}.first(3);
252
253 // 0xfd encoded with three bytes is OK:
254 ss << std::span{"\xfd\xfd\x00"}.first(3);
255 n = ReadCompactSize(ss);
256 BOOST_CHECK(n == 0xfd);
257
258 // zero encoded with five bytes:
259 ss << std::span{"\xfe\x00\x00\x00\x00"}.first(5);
261
262 // 0xffff encoded with five bytes:
263 ss << std::span{"\xfe\xff\xff\x00\x00"}.first(5);
265
266 // zero encoded with nine bytes:
267 ss << std::span{"\xff\x00\x00\x00\x00\x00\x00\x00\x00"}.first(9);
269
270 // 0x01ffffff encoded with nine bytes:
271 ss << std::span{"\xff\xff\xff\xff\x01\x00\x00\x00\x00"}.first(9);
273}
274
276{
277 // A CompactSize prefix followed by fewer bytes than it announces fails to read.
278 for (const char* hex : {"fd", "fd01", "fe010000", "ff01000000000000"}) {
279 DataStream ss{ParseHex(hex)};
280 BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, HasReason{"end of data"});
281 }
282}
283
285{
286 const std::string_view sv{"hello, world"};
288 ss << sv;
289 std::string s;
290 ss >> s;
292}
293
295{
296 const std::vector<int> v = {1,2,3,4,-5,-6,-7,-8,-9,-10,10000,20000,-30000};
297
298 auto check = [&]<size_t N>() {
300 ss << v;
301 try {
302 std::vector<int> r;
303 ss >> LIMITED_VECTOR(r, N);
304 BOOST_CHECK_LE(r.size(), N);
305 BOOST_CHECK(std::ranges::equal(r, v));
306 } catch (const std::ios_base::failure&) {
307 BOOST_CHECK_GT(v.size(), N);
308 }
309 };
310 check.operator()<0>();
311 check.operator()<10>();
312 check.operator()<12>();
313 check.operator()<13>();
314 check.operator()<14>();
315 check.operator()<100>();
316}
317
319{
320 int intval(100);
321 bool boolval(true);
322 std::string stringval("testing");
323 const uint8_t charstrval[16]{"testing charstr"};
326 CSerializeMethodsTestSingle methodtest1(intval, boolval, stringval, charstrval, tx_ref);
327 CSerializeMethodsTestMany methodtest2(intval, boolval, stringval, charstrval, tx_ref);
332 ss << methodtest1;
333 ss >> methodtest4;
334 ss << methodtest2;
335 ss >> methodtest3;
339
341 ss2 << intval << boolval << stringval << charstrval << TX_WITH_WITNESS(txval);
342 ss2 >> methodtest3;
344 {
346 const std::string in{"ab"};
347 ds << std::span{in} << std::byte{'c'};
348 std::array<std::byte, 2> out;
349 std::byte out_3;
350 ds >> std::span{out} >> out_3;
351 BOOST_CHECK_EQUAL(out.at(0), std::byte{'a'});
352 BOOST_CHECK_EQUAL(out.at(1), std::byte{'b'});
353 BOOST_CHECK_EQUAL(out_3, std::byte{'c'});
354 }
355}
356
358 const enum {
363};
366
368class Base
369{
370public:
372
373 Base() : m_base_data(17) {}
375
376 template <typename Stream>
377 void Serialize(Stream& s) const
378 {
379 if (s.template GetParams<BaseFormat>().m_base_format == BaseFormat::RAW) {
380 s << m_base_data;
381 } else {
383 }
384 }
385
386 template <typename Stream>
387 void Unserialize(Stream& s)
388 {
389 if (s.template GetParams<BaseFormat>().m_base_format == BaseFormat::RAW) {
390 s >> m_base_data;
391 } else {
392 std::string hex{"aa"};
393 s >> std::span{hex}.first(hex.size());
394 m_base_data = TryParseHex<uint8_t>(hex).value().at(0);
395 }
396 }
397};
398
411
412class Derived : public Base
413{
414public:
415 std::string m_derived_data;
416
418 {
419 auto& fmt = SER_PARAMS(DerivedAndBaseFormat);
420 READWRITE(fmt.m_base_format(AsBase<Base>(obj)));
421
422 if (ser_action.ForRead()) {
423 std::string str;
424 s >> str;
425 SER_READ(obj, obj.m_derived_data = str);
426 } else {
427 s << (fmt.m_derived_format == DerivedAndBaseFormat::DerivedFormat::LOWER ?
428 ToLower(obj.m_derived_data) :
429 ToUpper(obj.m_derived_data));
430 }
431 }
432};
433
438
443{
444public:
445 template <typename Stream>
446 void Serialize(Stream& s) const
447 {
448 const uint8_t param = s.template GetParams<OtherParam>().param;
449 s << param;
450 }
451
452 template <typename Stream>
453 void Unserialize(Stream& s) const
454 {
455 const uint8_t param = s.template GetParams<OtherParam>().param;
456 uint8_t value;
457 s >> value;
458 BOOST_CHECK_EQUAL(value, param);
459 }
460};
461
470{
471 const OtherParam other_param_used{.param = 0x10};
472 const OtherParam other_param_ignored{.param = 0x11};
474 const OtherParamChecker check;
477
478 Base base1{0x20};
479 pstream << base1 << check << other_param_override(check);
480 BOOST_CHECK_EQUAL(stream.str(), "\x20\x10\x12");
481
482 Base base2;
483 pstream >> base2 >> check >> other_param_override(check);
484 BOOST_CHECK_EQUAL(base2.m_base_data, 0x20);
485}
486
489{
490 UncopyableStream stream{MakeByteSpan(std::string_view{"abc"})};
491 ParamsStream pstream{std::move(stream), RAW, HEX, RAW};
492 BOOST_CHECK_EQUAL(pstream.GetStream().str(), "abc");
493 pstream.GetStream().clear();
494
495 Base base1{0x20};
496 pstream << base1;
497 BOOST_CHECK_EQUAL(pstream.GetStream().str(), "\x20");
498
499 Base base2;
500 pstream >> base2;
501 BOOST_CHECK_EQUAL(base2.m_base_data, 0x20);
502}
503
505{
506 Base b{0x0F};
507
509
510 stream << RAW(b);
511 BOOST_CHECK_EQUAL(stream.str(), "\x0F");
512
513 b.m_base_data = 0;
514 stream >> RAW(b);
515 BOOST_CHECK_EQUAL(b.m_base_data, 0x0F);
516
517 stream.clear();
518
519 stream << HEX(b);
520 BOOST_CHECK_EQUAL(stream.str(), "0f");
521
522 b.m_base_data = 0;
523 stream >> HEX(b);
524 BOOST_CHECK_EQUAL(b.m_base_data, 0x0F);
525}
526
528{
529 std::vector<Base> v{Base{0x0F}, Base{0xFF}};
530
532
533 stream << RAW(v);
534 BOOST_CHECK_EQUAL(stream.str(), "\x02\x0F\xFF");
535
536 v[0].m_base_data = 0;
537 v[1].m_base_data = 0;
538 stream >> RAW(v);
539 BOOST_CHECK_EQUAL(v[0].m_base_data, 0x0F);
540 BOOST_CHECK_EQUAL(v[1].m_base_data, 0xFF);
541
542 stream.clear();
543
544 stream << HEX(v);
545 BOOST_CHECK_EQUAL(stream.str(), "\x02"
546 "0fff");
547
548 v[0].m_base_data = 0;
549 v[1].m_base_data = 0;
550 stream >> HEX(v);
551 BOOST_CHECK_EQUAL(v[0].m_base_data, 0x0F);
552 BOOST_CHECK_EQUAL(v[1].m_base_data, 0xFF);
553}
554
557
559{
560 Derived d;
561 d.m_base_data = 0x0F;
562 d.m_derived_data = "xY";
563
565
566 stream << RAW_LOWER(d);
567
568 stream << HEX_UPPER(d);
569
570 BOOST_CHECK_EQUAL(stream.str(), "\x0F\x02xy"
571 "0f\x02XY");
572}
573
(Un)serialize a number as raw byte or 2 hexadecimal chars.
uint8_t m_base_data
void Unserialize(Stream &s)
void Serialize(Stream &s) const
Base(uint8_t data)
SERIALIZE_METHODS(CSerializeMethodsTestMany, obj)
CSerializeMethodsTestSingle(int intvalin, bool boolvalin, std::string stringvalin, const uint8_t *charstrvalin, const CTransactionRef &txvalin)
SERIALIZE_METHODS(CSerializeMethodsTestSingle, obj)
bool operator==(const CSerializeMethodsTestSingle &rhs) const
Double ended buffer combining vector and stream-like interfaces.
Definition streams.h:165
size_type size() const
Definition streams.h:198
vector_type::size_type size_type
Definition streams.h:173
void clear()
Definition streams.h:204
DataStream()=default
enum DerivedAndBaseFormat::DerivedFormat m_derived_format
std::string m_derived_data
SERIALIZE_METHODS(Derived, obj)
BOOST_CHECK_EXCEPTION predicates to check the specific validation error.
Definition common.h:38
A writer stream (for serialization) that computes a 256-bit hash.
Definition hash.h:109
Checker for value of OtherParam.
void Unserialize(Stream &s) const
void Serialize(Stream &s) const
Wrapper that overrides the GetParams() function of a stream.
Definition serialize.h:1169
UncopyableStream & operator=(const UncopyableStream &)=delete
UncopyableStream(const UncopyableStream &)=delete
UncopyableStream(UncopyableStream &&) noexcept=default
static const PrecomputedData data
Precomputed COutPoint and CCoins values.
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
BOOST_AUTO_TEST_SUITE_END()
std::string HexStr(const std::span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
Definition hex_base.cpp:30
BOOST_CHECK_GT(excessive_headers.size(), MAX_HEADERS_SIZE)
BOOST_CHECK_EXCEPTION(HTTPHeaders{}.Read(reader), std::runtime_error, HasReason{"Empty HTTP header name"})
#define BOOST_CHECK_EQUAL(v1, v2)
Definition object.cpp:17
#define BOOST_CHECK(expr)
Definition object.cpp:16
constexpr TransactionSerParams TX_WITH_WITNESS
static CTransactionRef MakeTransactionRef(Tx &&txIn)
std::shared_ptr< const CTransaction > CTransactionRef
#define VARINT(obj)
Definition serialize.h:494
#define VARINT_MODE(obj, mode)
Definition serialize.h:493
#define SER_PARAMS(type)
Formatter methods can retrieve parameters attached to a stream using the SER_PARAMS(type) macro as lo...
Definition serialize.h:209
@ NONNEGATIVE_SIGNED
constexpr uint64_t MAX_SIZE
The maximum size of a serialized object in bytes or number of elements (for eg vectors) when the size...
Definition serialize.h:35
#define LIMITED_VECTOR(obj, n)
Definition serialize.h:497
void WriteCompactSize(SizeComputer &os, uint64_t nSize)
Definition serialize.h:1151
#define SER_READ(obj, code)
Definition serialize.h:149
#define SER_PARAMS_OPFUNC
Helper macro for SerParams structs.
Definition serialize.h:1274
uint64_t ReadCompactSize(Stream &is, bool range_check=true)
Decode a CompactSize-encoded variable-length integer.
Definition serialize.h:333
uint64_t GetSerializeSize(const T &t)
Definition serialize.h:1157
#define READWRITE(...)
Definition serialize.h:148
constexpr DerivedAndBaseFormat HEX_UPPER
constexpr BaseFormat RAW
constexpr DerivedAndBaseFormat RAW_LOWER
constexpr BaseFormat HEX
static bool isCanonicalException(const std::ios_base::failure &ex)
BOOST_AUTO_TEST_CASE(sizes)
auto MakeByteSpan(const V &v) noexcept
Definition span.h:84
Utilities for converting data from/to strings.
std::vector< Byte > ParseHex(std::string_view hex_str)
Like TryParseHex, but returns an empty vector on invalid input.
enum BaseFormat::@15 m_base_format
Basic testing setup.
A mutable version of CTransaction.
DataStream ss
std::string ToUpper(std::string_view str)
Returns the uppercase equivalent of the given string.
std::string ToLower(std::string_view str)
Returns the lowercase equivalent of the given string.
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
Definition time.h:82