Line data Source code
1 : // Copyright (c) 2012-2020 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/setup_common.h>
9 : #include <util/strencodings.h>
10 :
11 : #include <stdint.h>
12 :
13 : #include <boost/test/unit_test.hpp>
14 :
15 89 : BOOST_FIXTURE_TEST_SUITE(serialize_tests, BasicTestingSetup)
16 :
17 6 : class CSerializeMethodsTestSingle
18 : {
19 : protected:
20 : int intval;
21 : bool boolval;
22 : std::string stringval;
23 : char charstrval[16];
24 : CTransactionRef txval;
25 : public:
26 3 : CSerializeMethodsTestSingle() = default;
27 3 : CSerializeMethodsTestSingle(int intvalin, bool boolvalin, std::string stringvalin, const char* charstrvalin, const CTransactionRef& txvalin) : intval(intvalin), boolval(boolvalin), stringval(std::move(stringvalin)), txval(txvalin)
28 1 : {
29 2 : memcpy(charstrval, charstrvalin, sizeof(charstrval));
30 3 : }
31 :
32 9 : SERIALIZE_METHODS(CSerializeMethodsTestSingle, obj)
33 : {
34 3 : READWRITE(obj.intval);
35 3 : READWRITE(obj.boolval);
36 3 : READWRITE(obj.stringval);
37 3 : READWRITE(obj.charstrval);
38 3 : READWRITE(obj.txval);
39 3 : }
40 :
41 5 : bool operator==(const CSerializeMethodsTestSingle& rhs)
42 : {
43 10 : return intval == rhs.intval && \
44 5 : boolval == rhs.boolval && \
45 5 : stringval == rhs.stringval && \
46 5 : strcmp(charstrval, rhs.charstrval) == 0 && \
47 5 : *txval == *rhs.txval;
48 : }
49 : };
50 :
51 6 : class CSerializeMethodsTestMany : public CSerializeMethodsTestSingle
52 : {
53 : public:
54 2 : using CSerializeMethodsTestSingle::CSerializeMethodsTestSingle;
55 :
56 6 : SERIALIZE_METHODS(CSerializeMethodsTestMany, obj)
57 : {
58 2 : READWRITE(obj.intval, obj.boolval, obj.stringval, obj.charstrval, obj.txval);
59 2 : }
60 : };
61 :
62 95 : BOOST_AUTO_TEST_CASE(sizes)
63 : {
64 1 : BOOST_CHECK_EQUAL(sizeof(char), GetSerializeSize(char(0), 0));
65 1 : BOOST_CHECK_EQUAL(sizeof(int8_t), GetSerializeSize(int8_t(0), 0));
66 1 : BOOST_CHECK_EQUAL(sizeof(uint8_t), GetSerializeSize(uint8_t(0), 0));
67 1 : BOOST_CHECK_EQUAL(sizeof(int16_t), GetSerializeSize(int16_t(0), 0));
68 1 : BOOST_CHECK_EQUAL(sizeof(uint16_t), GetSerializeSize(uint16_t(0), 0));
69 1 : BOOST_CHECK_EQUAL(sizeof(int32_t), GetSerializeSize(int32_t(0), 0));
70 1 : BOOST_CHECK_EQUAL(sizeof(uint32_t), GetSerializeSize(uint32_t(0), 0));
71 1 : BOOST_CHECK_EQUAL(sizeof(int64_t), GetSerializeSize(int64_t(0), 0));
72 1 : BOOST_CHECK_EQUAL(sizeof(uint64_t), GetSerializeSize(uint64_t(0), 0));
73 1 : BOOST_CHECK_EQUAL(sizeof(float), GetSerializeSize(float(0), 0));
74 1 : BOOST_CHECK_EQUAL(sizeof(double), GetSerializeSize(double(0), 0));
75 : // Bool is serialized as char
76 1 : BOOST_CHECK_EQUAL(sizeof(char), GetSerializeSize(bool(0), 0));
77 :
78 : // Sanity-check GetSerializeSize and c++ type matching
79 1 : BOOST_CHECK_EQUAL(GetSerializeSize(char(0), 0), 1U);
80 1 : BOOST_CHECK_EQUAL(GetSerializeSize(int8_t(0), 0), 1U);
81 1 : BOOST_CHECK_EQUAL(GetSerializeSize(uint8_t(0), 0), 1U);
82 1 : BOOST_CHECK_EQUAL(GetSerializeSize(int16_t(0), 0), 2U);
83 1 : BOOST_CHECK_EQUAL(GetSerializeSize(uint16_t(0), 0), 2U);
84 1 : BOOST_CHECK_EQUAL(GetSerializeSize(int32_t(0), 0), 4U);
85 1 : BOOST_CHECK_EQUAL(GetSerializeSize(uint32_t(0), 0), 4U);
86 1 : BOOST_CHECK_EQUAL(GetSerializeSize(int64_t(0), 0), 8U);
87 1 : BOOST_CHECK_EQUAL(GetSerializeSize(uint64_t(0), 0), 8U);
88 1 : BOOST_CHECK_EQUAL(GetSerializeSize(float(0), 0), 4U);
89 1 : BOOST_CHECK_EQUAL(GetSerializeSize(double(0), 0), 8U);
90 1 : BOOST_CHECK_EQUAL(GetSerializeSize(bool(0), 0), 1U);
91 1 : }
92 :
93 95 : BOOST_AUTO_TEST_CASE(floats_conversion)
94 : {
95 : // Choose values that map unambiguously to binary floating point to avoid
96 : // rounding issues at the compiler side.
97 1 : BOOST_CHECK_EQUAL(ser_uint32_to_float(0x00000000), 0.0F);
98 1 : BOOST_CHECK_EQUAL(ser_uint32_to_float(0x3f000000), 0.5F);
99 1 : BOOST_CHECK_EQUAL(ser_uint32_to_float(0x3f800000), 1.0F);
100 1 : BOOST_CHECK_EQUAL(ser_uint32_to_float(0x40000000), 2.0F);
101 1 : BOOST_CHECK_EQUAL(ser_uint32_to_float(0x40800000), 4.0F);
102 1 : BOOST_CHECK_EQUAL(ser_uint32_to_float(0x44444444), 785.066650390625F);
103 :
104 1 : BOOST_CHECK_EQUAL(ser_float_to_uint32(0.0F), 0x00000000U);
105 1 : BOOST_CHECK_EQUAL(ser_float_to_uint32(0.5F), 0x3f000000U);
106 1 : BOOST_CHECK_EQUAL(ser_float_to_uint32(1.0F), 0x3f800000U);
107 1 : BOOST_CHECK_EQUAL(ser_float_to_uint32(2.0F), 0x40000000U);
108 1 : BOOST_CHECK_EQUAL(ser_float_to_uint32(4.0F), 0x40800000U);
109 1 : BOOST_CHECK_EQUAL(ser_float_to_uint32(785.066650390625F), 0x44444444U);
110 1 : }
111 :
112 95 : BOOST_AUTO_TEST_CASE(doubles_conversion)
113 : {
114 : // Choose values that map unambiguously to binary floating point to avoid
115 : // rounding issues at the compiler side.
116 1 : BOOST_CHECK_EQUAL(ser_uint64_to_double(0x0000000000000000ULL), 0.0);
117 1 : BOOST_CHECK_EQUAL(ser_uint64_to_double(0x3fe0000000000000ULL), 0.5);
118 1 : BOOST_CHECK_EQUAL(ser_uint64_to_double(0x3ff0000000000000ULL), 1.0);
119 1 : BOOST_CHECK_EQUAL(ser_uint64_to_double(0x4000000000000000ULL), 2.0);
120 1 : BOOST_CHECK_EQUAL(ser_uint64_to_double(0x4010000000000000ULL), 4.0);
121 1 : BOOST_CHECK_EQUAL(ser_uint64_to_double(0x4088888880000000ULL), 785.066650390625);
122 :
123 1 : BOOST_CHECK_EQUAL(ser_double_to_uint64(0.0), 0x0000000000000000ULL);
124 1 : BOOST_CHECK_EQUAL(ser_double_to_uint64(0.5), 0x3fe0000000000000ULL);
125 1 : BOOST_CHECK_EQUAL(ser_double_to_uint64(1.0), 0x3ff0000000000000ULL);
126 1 : BOOST_CHECK_EQUAL(ser_double_to_uint64(2.0), 0x4000000000000000ULL);
127 1 : BOOST_CHECK_EQUAL(ser_double_to_uint64(4.0), 0x4010000000000000ULL);
128 1 : BOOST_CHECK_EQUAL(ser_double_to_uint64(785.066650390625), 0x4088888880000000ULL);
129 1 : }
130 : /*
131 : Python code to generate the below hashes:
132 :
133 : def reversed_hex(x):
134 : return binascii.hexlify(''.join(reversed(x)))
135 : def dsha256(x):
136 : return hashlib.sha256(hashlib.sha256(x).digest()).digest()
137 :
138 : reversed_hex(dsha256(''.join(struct.pack('<f', x) for x in range(0,1000)))) == '8e8b4cf3e4df8b332057e3e23af42ebc663b61e0495d5e7e32d85099d7f3fe0c'
139 : reversed_hex(dsha256(''.join(struct.pack('<d', x) for x in range(0,1000)))) == '43d0c82591953c4eafe114590d392676a01585d25b25d433557f0d7878b23f96'
140 : */
141 95 : BOOST_AUTO_TEST_CASE(floats)
142 : {
143 1 : CDataStream ss(SER_DISK, 0);
144 : // encode
145 1001 : for (int i = 0; i < 1000; i++) {
146 1000 : ss << float(i);
147 : }
148 1 : BOOST_CHECK(Hash(ss) == uint256S("8e8b4cf3e4df8b332057e3e23af42ebc663b61e0495d5e7e32d85099d7f3fe0c"));
149 :
150 : // decode
151 1001 : for (int i = 0; i < 1000; i++) {
152 1000 : float j;
153 1000 : ss >> j;
154 1000 : BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
155 1000 : }
156 1 : }
157 :
158 95 : BOOST_AUTO_TEST_CASE(doubles)
159 : {
160 1 : CDataStream ss(SER_DISK, 0);
161 : // encode
162 1001 : for (int i = 0; i < 1000; i++) {
163 1000 : ss << double(i);
164 : }
165 1 : BOOST_CHECK(Hash(ss) == uint256S("43d0c82591953c4eafe114590d392676a01585d25b25d433557f0d7878b23f96"));
166 :
167 : // decode
168 1001 : for (int i = 0; i < 1000; i++) {
169 1000 : double j;
170 1000 : ss >> j;
171 1000 : BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
172 1000 : }
173 1 : }
174 :
175 95 : BOOST_AUTO_TEST_CASE(varints)
176 : {
177 : // encode
178 :
179 1 : CDataStream ss(SER_DISK, 0);
180 : CDataStream::size_type size = 0;
181 100001 : for (int i = 0; i < 100000; i++) {
182 100000 : ss << VARINT_MODE(i, VarIntMode::NONNEGATIVE_SIGNED);
183 100000 : size += ::GetSerializeSize(VARINT_MODE(i, VarIntMode::NONNEGATIVE_SIGNED), 0);
184 100000 : BOOST_CHECK(size == ss.size());
185 : }
186 :
187 102 : for (uint64_t i = 0; i < 100000000000ULL; i += 999999937) {
188 101 : ss << VARINT(i);
189 101 : size += ::GetSerializeSize(VARINT(i), 0);
190 101 : BOOST_CHECK(size == ss.size());
191 : }
192 :
193 : // decode
194 100001 : for (int i = 0; i < 100000; i++) {
195 100000 : int j = -1;
196 100000 : ss >> VARINT_MODE(j, VarIntMode::NONNEGATIVE_SIGNED);
197 100000 : BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
198 100000 : }
199 :
200 102 : for (uint64_t i = 0; i < 100000000000ULL; i += 999999937) {
201 101 : uint64_t j = std::numeric_limits<uint64_t>::max();
202 101 : ss >> VARINT(j);
203 101 : BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
204 101 : }
205 1 : }
206 :
207 95 : BOOST_AUTO_TEST_CASE(varints_bitpatterns)
208 : {
209 1 : CDataStream ss(SER_DISK, 0);
210 1 : ss << VARINT_MODE(0, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "00"); ss.clear();
211 1 : ss << VARINT_MODE(0x7f, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "7f"); ss.clear();
212 1 : ss << VARINT_MODE((int8_t)0x7f, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "7f"); ss.clear();
213 1 : ss << VARINT_MODE(0x80, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "8000"); ss.clear();
214 1 : ss << VARINT((uint8_t)0x80); BOOST_CHECK_EQUAL(HexStr(ss), "8000"); ss.clear();
215 1 : ss << VARINT_MODE(0x1234, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "a334"); ss.clear();
216 1 : ss << VARINT_MODE((int16_t)0x1234, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "a334"); ss.clear();
217 1 : ss << VARINT_MODE(0xffff, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "82fe7f"); ss.clear();
218 1 : ss << VARINT((uint16_t)0xffff); BOOST_CHECK_EQUAL(HexStr(ss), "82fe7f"); ss.clear();
219 1 : ss << VARINT_MODE(0x123456, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "c7e756"); ss.clear();
220 1 : ss << VARINT_MODE((int32_t)0x123456, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "c7e756"); ss.clear();
221 1 : ss << VARINT(0x80123456U); BOOST_CHECK_EQUAL(HexStr(ss), "86ffc7e756"); ss.clear();
222 1 : ss << VARINT((uint32_t)0x80123456U); BOOST_CHECK_EQUAL(HexStr(ss), "86ffc7e756"); ss.clear();
223 1 : ss << VARINT(0xffffffff); BOOST_CHECK_EQUAL(HexStr(ss), "8efefefe7f"); ss.clear();
224 1 : ss << VARINT_MODE(0x7fffffffffffffffLL, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "fefefefefefefefe7f"); ss.clear();
225 1 : ss << VARINT(0xffffffffffffffffULL); BOOST_CHECK_EQUAL(HexStr(ss), "80fefefefefefefefe7f"); ss.clear();
226 1 : }
227 :
228 95 : BOOST_AUTO_TEST_CASE(compactsize)
229 : {
230 1 : CDataStream ss(SER_DISK, 0);
231 1 : std::vector<char>::size_type i, j;
232 :
233 27 : for (i = 1; i <= MAX_SIZE; i *= 2)
234 : {
235 26 : WriteCompactSize(ss, i-1);
236 26 : WriteCompactSize(ss, i);
237 : }
238 27 : for (i = 1; i <= MAX_SIZE; i *= 2)
239 : {
240 26 : j = ReadCompactSize(ss);
241 26 : BOOST_CHECK_MESSAGE((i-1) == j, "decoded:" << j << " expected:" << (i-1));
242 26 : j = ReadCompactSize(ss);
243 26 : BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
244 : }
245 1 : }
246 :
247 6 : static bool isCanonicalException(const std::ios_base::failure& ex)
248 : {
249 6 : std::ios_base::failure expectedException("non-canonical ReadCompactSize()");
250 :
251 : // The string returned by what() can be different for different platforms.
252 : // Instead of directly comparing the ex.what() with an expected string,
253 : // create an instance of exception to see if ex.what() matches
254 : // the expected explanatory string returned by the exception instance.
255 6 : return strcmp(expectedException.what(), ex.what()) == 0;
256 6 : }
257 :
258 95 : BOOST_AUTO_TEST_CASE(vector_bool)
259 : {
260 1 : 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};
261 1 : 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};
262 :
263 1 : BOOST_CHECK(vec1 == std::vector<uint8_t>(vec2.begin(), vec2.end()));
264 1 : BOOST_CHECK(SerializeHash(vec1) == SerializeHash(vec2));
265 1 : }
266 :
267 95 : BOOST_AUTO_TEST_CASE(noncanonical)
268 : {
269 : // Write some non-canonical CompactSize encodings, and
270 : // make sure an exception is thrown when read back.
271 1 : CDataStream ss(SER_DISK, 0);
272 : std::vector<char>::size_type n;
273 :
274 : // zero encoded with three bytes:
275 1 : ss.write("\xfd\x00\x00", 3);
276 2 : BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
277 :
278 : // 0xfc encoded with three bytes:
279 1 : ss.write("\xfd\xfc\x00", 3);
280 2 : BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
281 :
282 : // 0xfd encoded with three bytes is OK:
283 1 : ss.write("\xfd\xfd\x00", 3);
284 1 : n = ReadCompactSize(ss);
285 1 : BOOST_CHECK(n == 0xfd);
286 :
287 : // zero encoded with five bytes:
288 1 : ss.write("\xfe\x00\x00\x00\x00", 5);
289 2 : BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
290 :
291 : // 0xffff encoded with five bytes:
292 1 : ss.write("\xfe\xff\xff\x00\x00", 5);
293 2 : BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
294 :
295 : // zero encoded with nine bytes:
296 1 : ss.write("\xff\x00\x00\x00\x00\x00\x00\x00\x00", 9);
297 2 : BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
298 :
299 : // 0x01ffffff encoded with nine bytes:
300 1 : ss.write("\xff\xff\xff\xff\x01\x00\x00\x00\x00", 9);
301 2 : BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
302 7 : }
303 :
304 95 : BOOST_AUTO_TEST_CASE(insert_delete)
305 : {
306 : // Test inserting/deleting bytes.
307 1 : CDataStream ss(SER_DISK, 0);
308 1 : BOOST_CHECK_EQUAL(ss.size(), 0U);
309 :
310 1 : ss.write("\x00\x01\x02\xff", 4);
311 1 : BOOST_CHECK_EQUAL(ss.size(), 4U);
312 :
313 1 : char c = (char)11;
314 :
315 : // Inserting at beginning/end/middle:
316 1 : ss.insert(ss.begin(), c);
317 1 : BOOST_CHECK_EQUAL(ss.size(), 5U);
318 1 : BOOST_CHECK_EQUAL(ss[0], c);
319 1 : BOOST_CHECK_EQUAL(ss[1], 0);
320 :
321 1 : ss.insert(ss.end(), c);
322 1 : BOOST_CHECK_EQUAL(ss.size(), 6U);
323 1 : BOOST_CHECK_EQUAL(ss[4], (char)0xff);
324 1 : BOOST_CHECK_EQUAL(ss[5], c);
325 :
326 1 : ss.insert(ss.begin()+2, c);
327 1 : BOOST_CHECK_EQUAL(ss.size(), 7U);
328 1 : BOOST_CHECK_EQUAL(ss[2], c);
329 :
330 : // Delete at beginning/end/middle
331 1 : ss.erase(ss.begin());
332 1 : BOOST_CHECK_EQUAL(ss.size(), 6U);
333 1 : BOOST_CHECK_EQUAL(ss[0], 0);
334 :
335 1 : ss.erase(ss.begin()+ss.size()-1);
336 1 : BOOST_CHECK_EQUAL(ss.size(), 5U);
337 1 : BOOST_CHECK_EQUAL(ss[4], (char)0xff);
338 :
339 1 : ss.erase(ss.begin()+1);
340 1 : BOOST_CHECK_EQUAL(ss.size(), 4U);
341 1 : BOOST_CHECK_EQUAL(ss[0], 0);
342 1 : BOOST_CHECK_EQUAL(ss[1], 1);
343 1 : BOOST_CHECK_EQUAL(ss[2], 2);
344 1 : BOOST_CHECK_EQUAL(ss[3], (char)0xff);
345 :
346 : // Make sure GetAndClear does the right thing:
347 1 : CSerializeData d;
348 1 : ss.GetAndClear(d);
349 1 : BOOST_CHECK_EQUAL(ss.size(), 0U);
350 1 : }
351 :
352 95 : BOOST_AUTO_TEST_CASE(class_methods)
353 : {
354 1 : int intval(100);
355 1 : bool boolval(true);
356 1 : std::string stringval("testing");
357 1 : const char charstrval[16] = "testing charstr";
358 1 : CMutableTransaction txval;
359 1 : CTransactionRef tx_ref{MakeTransactionRef(txval)};
360 1 : CSerializeMethodsTestSingle methodtest1(intval, boolval, stringval, charstrval, tx_ref);
361 1 : CSerializeMethodsTestMany methodtest2(intval, boolval, stringval, charstrval, tx_ref);
362 1 : CSerializeMethodsTestSingle methodtest3;
363 1 : CSerializeMethodsTestMany methodtest4;
364 1 : CDataStream ss(SER_DISK, PROTOCOL_VERSION);
365 1 : BOOST_CHECK(methodtest1 == methodtest2);
366 1 : ss << methodtest1;
367 1 : ss >> methodtest4;
368 1 : ss << methodtest2;
369 1 : ss >> methodtest3;
370 1 : BOOST_CHECK(methodtest1 == methodtest2);
371 1 : BOOST_CHECK(methodtest2 == methodtest3);
372 1 : BOOST_CHECK(methodtest3 == methodtest4);
373 :
374 1 : CDataStream ss2(SER_DISK, PROTOCOL_VERSION, intval, boolval, stringval, charstrval, txval);
375 1 : ss2 >> methodtest3;
376 1 : BOOST_CHECK(methodtest3 == methodtest4);
377 1 : }
378 :
379 89 : BOOST_AUTO_TEST_SUITE_END()
|