PIVX Core  5.6.99
P2P Digital Currency
serialize_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2012-2013 The Bitcoin Core developers
2 // Copyright (c) 2019-2021 The PIVX Core developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or https://www.opensource.org/licenses/mit-license.php.
5 
6 #include "optional.h"
7 #include "serialize.h"
8 #include "streams.h"
9 #include "hash.h"
10 #include "test/test_pivx.h"
11 
12 #include <stdint.h>
13 
14 #include <boost/test/unit_test.hpp>
15 
16 template<typename T>
17 void check_ser_rep(T thing, std::vector<unsigned char> expected)
18 {
19  CDataStream ss(SER_DISK, 0);
20  ss << thing;
21 
22  BOOST_CHECK(GetSerializeSize(thing, 0) == ss.size());
23 
24  std::vector<unsigned char> serialized_representation(ss.begin(), ss.end());
25 
26  BOOST_CHECK(serialized_representation == expected);
27 
28  T thing_deserialized;
29  ss >> thing_deserialized;
30 
31  BOOST_CHECK(thing_deserialized == thing);
32 }
33 
35 
37 {
38 protected:
39  int intval;
40  bool boolval;
41  std::string stringval;
42  char charstrval[16];
44 public:
46  CSerializeMethodsTestSingle(int intvalin, bool boolvalin, std::string stringvalin, const char* charstrvalin, CTransaction txvalin) : intval(intvalin), boolval(boolvalin), stringval(std::move(stringvalin)), txval(MakeTransactionRef(txvalin))
47  {
48  memcpy(charstrval, charstrvalin, sizeof(charstrval));
49  }
50 
52  {
53  READWRITE(obj.intval);
54  READWRITE(obj.boolval);
55  READWRITE(obj.stringval);
56  READWRITE(obj.charstrval);
57  READWRITE(obj.txval);
58  }
59 
61  {
62  return intval == rhs.intval && \
63  boolval == rhs.boolval && \
64  stringval == rhs.stringval && \
65  strcmp(charstrval, rhs.charstrval) == 0 && \
66  *txval == *rhs.txval;
67  }
68 };
69 
71 {
72 public:
74 
76  {
77  READWRITE(obj.intval, obj.boolval, obj.stringval, obj.charstrval, obj.txval);
78  }
79 };
80 
82 {
83  BOOST_CHECK_EQUAL(sizeof(char), GetSerializeSize(char(0), 0));
84  BOOST_CHECK_EQUAL(sizeof(int8_t), GetSerializeSize(int8_t(0), 0));
85  BOOST_CHECK_EQUAL(sizeof(uint8_t), GetSerializeSize(uint8_t(0), 0));
86  BOOST_CHECK_EQUAL(sizeof(int16_t), GetSerializeSize(int16_t(0), 0));
87  BOOST_CHECK_EQUAL(sizeof(uint16_t), GetSerializeSize(uint16_t(0), 0));
88  BOOST_CHECK_EQUAL(sizeof(int32_t), GetSerializeSize(int32_t(0), 0));
89  BOOST_CHECK_EQUAL(sizeof(uint32_t), GetSerializeSize(uint32_t(0), 0));
90  BOOST_CHECK_EQUAL(sizeof(int64_t), GetSerializeSize(int64_t(0), 0));
91  BOOST_CHECK_EQUAL(sizeof(uint64_t), GetSerializeSize(uint64_t(0), 0));
92  BOOST_CHECK_EQUAL(sizeof(float), GetSerializeSize(float(0), 0));
93  BOOST_CHECK_EQUAL(sizeof(double), GetSerializeSize(double(0), 0));
94 
95  // Bool is serialized as char
96  BOOST_CHECK_EQUAL(sizeof(char), GetSerializeSize(bool(0), 0));
97 
98  // Sanity-check GetSerializeSize and c++ type matching
99  BOOST_CHECK_EQUAL(GetSerializeSize(char(0), 0), 1);
100  BOOST_CHECK_EQUAL(GetSerializeSize(int8_t(0), 0), 1);
101  BOOST_CHECK_EQUAL(GetSerializeSize(uint8_t(0), 0), 1);
102  BOOST_CHECK_EQUAL(GetSerializeSize(int16_t(0), 0), 2);
103  BOOST_CHECK_EQUAL(GetSerializeSize(uint16_t(0), 0), 2);
104  BOOST_CHECK_EQUAL(GetSerializeSize(int32_t(0), 0), 4);
105  BOOST_CHECK_EQUAL(GetSerializeSize(uint32_t(0), 0), 4);
106  BOOST_CHECK_EQUAL(GetSerializeSize(int64_t(0), 0), 8);
107  BOOST_CHECK_EQUAL(GetSerializeSize(uint64_t(0), 0), 8);
108  BOOST_CHECK_EQUAL(GetSerializeSize(float(0), 0), 4);
109  BOOST_CHECK_EQUAL(GetSerializeSize(double(0), 0), 8);
110  BOOST_CHECK_EQUAL(GetSerializeSize(bool(0), 0), 1);
111 }
112 
113 BOOST_AUTO_TEST_CASE(floats_conversion)
114 {
115  // Choose values that map unambigiously to binary floating point to avoid
116  // rounding issues at the compiler side.
117  BOOST_CHECK_EQUAL(ser_uint32_to_float(0x00000000), 0.0F);
118  BOOST_CHECK_EQUAL(ser_uint32_to_float(0x3f000000), 0.5F);
119  BOOST_CHECK_EQUAL(ser_uint32_to_float(0x3f800000), 1.0F);
120  BOOST_CHECK_EQUAL(ser_uint32_to_float(0x40000000), 2.0F);
121  BOOST_CHECK_EQUAL(ser_uint32_to_float(0x40800000), 4.0F);
122  BOOST_CHECK_EQUAL(ser_uint32_to_float(0x44444444), 785.066650390625F);
123 
124  BOOST_CHECK_EQUAL(ser_float_to_uint32(0.0F), 0x00000000);
125  BOOST_CHECK_EQUAL(ser_float_to_uint32(0.5F), 0x3f000000);
126  BOOST_CHECK_EQUAL(ser_float_to_uint32(1.0F), 0x3f800000);
127  BOOST_CHECK_EQUAL(ser_float_to_uint32(2.0F), 0x40000000);
128  BOOST_CHECK_EQUAL(ser_float_to_uint32(4.0F), 0x40800000);
129  BOOST_CHECK_EQUAL(ser_float_to_uint32(785.066650390625F), 0x44444444);
130 }
131 
132 BOOST_AUTO_TEST_CASE(doubles_conversion)
133 {
134  // Choose values that map unambigiously to binary floating point to avoid
135  // rounding issues at the compiler side.
136  BOOST_CHECK_EQUAL(ser_uint64_to_double(0x0000000000000000ULL), 0.0);
137  BOOST_CHECK_EQUAL(ser_uint64_to_double(0x3fe0000000000000ULL), 0.5);
138  BOOST_CHECK_EQUAL(ser_uint64_to_double(0x3ff0000000000000ULL), 1.0);
139  BOOST_CHECK_EQUAL(ser_uint64_to_double(0x4000000000000000ULL), 2.0);
140  BOOST_CHECK_EQUAL(ser_uint64_to_double(0x4010000000000000ULL), 4.0);
141  BOOST_CHECK_EQUAL(ser_uint64_to_double(0x4088888880000000ULL), 785.066650390625);
142 
143  BOOST_CHECK_EQUAL(ser_double_to_uint64(0.0), 0x0000000000000000ULL);
144  BOOST_CHECK_EQUAL(ser_double_to_uint64(0.5), 0x3fe0000000000000ULL);
145  BOOST_CHECK_EQUAL(ser_double_to_uint64(1.0), 0x3ff0000000000000ULL);
146  BOOST_CHECK_EQUAL(ser_double_to_uint64(2.0), 0x4000000000000000ULL);
147  BOOST_CHECK_EQUAL(ser_double_to_uint64(4.0), 0x4010000000000000ULL);
148  BOOST_CHECK_EQUAL(ser_double_to_uint64(785.066650390625), 0x4088888880000000ULL);
149 }
150 /*
151 Python code to generate the below hashes:
152  def reversed_hex(x):
153  return binascii.hexlify(''.join(reversed(x)))
154  def dsha256(x):
155  return hashlib.sha256(hashlib.sha256(x).digest()).digest()
156  reversed_hex(dsha256(''.join(struct.pack('<f', x) for x in range(0,1000)))) == '8e8b4cf3e4df8b332057e3e23af42ebc663b61e0495d5e7e32d85099d7f3fe0c'
157  reversed_hex(dsha256(''.join(struct.pack('<d', x) for x in range(0,1000)))) == '43d0c82591953c4eafe114590d392676a01585d25b25d433557f0d7878b23f96'
158 */
160 {
161  CDataStream ss(SER_DISK, 0);
162  // encode
163  for (int i = 0; i < 1000; i++) {
164  ss << float(i);
165  }
166  BOOST_CHECK(Hash(ss.begin(), ss.end()) == uint256S("8e8b4cf3e4df8b332057e3e23af42ebc663b61e0495d5e7e32d85099d7f3fe0c"));
167 
168  // decode
169  for (int i = 0; i < 1000; i++) {
170  float j;
171  ss >> j;
172  BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
173  }
174 }
175 
177 {
178  CDataStream ss(SER_DISK, 0);
179  // encode
180  for (int i = 0; i < 1000; i++) {
181  ss << double(i);
182  }
183  BOOST_CHECK(Hash(ss.begin(), ss.end()) == uint256S("43d0c82591953c4eafe114590d392676a01585d25b25d433557f0d7878b23f96"));
184 
185  // decode
186  for (int i = 0; i < 1000; i++) {
187  double j;
188  ss >> j;
189  BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
190  }
191 }
192 
193 BOOST_AUTO_TEST_CASE(boost_optional)
194 {
195  check_ser_rep<Optional<unsigned char>>(0xff, {0x01, 0xff});
196  check_ser_rep<Optional<unsigned char>>(boost::none, {0x00});
197  check_ser_rep<Optional<std::string>>(std::string("Test"), {0x01, 0x04, 'T', 'e', 's', 't'});
198 }
199 
201 {
202  // encode
203 
204  CDataStream ss(SER_DISK, 0);
205  CDataStream::size_type size = 0;
206  for (int i = 0; i < 100000; i++) {
209  BOOST_CHECK(size == ss.size());
210  }
211 
212  for (uint64_t i = 0; i < 100000000000ULL; i += 999999937) {
213  ss << VARINT(i);
214  size += ::GetSerializeSize(VARINT(i), 0);
215  BOOST_CHECK(size == ss.size());
216  }
217 
218  // decode
219  for (int i = 0; i < 100000; i++) {
220  int j = -1;
222  BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
223  }
224 
225  for (uint64_t i = 0; i < 100000000000ULL; i += 999999937) {
226  uint64_t j = -1;
227  ss >> VARINT(j);
228  BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
229  }
230 }
231 
232 BOOST_AUTO_TEST_CASE(varints_bitpatterns)
233 {
234  CDataStream ss(SER_DISK, 0);
237  ss << VARINT_MODE((int8_t)0x7f, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "7f"); ss.clear();
239  ss << VARINT((uint8_t)0x80); BOOST_CHECK_EQUAL(HexStr(ss), "8000"); ss.clear();
240  ss << VARINT_MODE(0x1234, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "a334"); ss.clear();
241  ss << VARINT_MODE((int16_t)0x1234, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "a334"); ss.clear();
242  ss << VARINT_MODE(0xffff, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "82fe7f"); ss.clear();
243  ss << VARINT((uint16_t)0xffff); BOOST_CHECK_EQUAL(HexStr(ss), "82fe7f"); ss.clear();
244  ss << VARINT_MODE(0x123456, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "c7e756"); ss.clear();
245  ss << VARINT_MODE((int32_t)0x123456, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "c7e756"); ss.clear();
246  ss << VARINT(0x80123456U); BOOST_CHECK_EQUAL(HexStr(ss), "86ffc7e756"); ss.clear();
247  ss << VARINT((uint32_t)0x80123456U); BOOST_CHECK_EQUAL(HexStr(ss), "86ffc7e756"); ss.clear();
248  ss << VARINT(0xffffffff); BOOST_CHECK_EQUAL(HexStr(ss), "8efefefe7f"); ss.clear();
249  ss << VARINT_MODE(0x7fffffffffffffffLL, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "fefefefefefefefe7f"); ss.clear();
250  ss << VARINT(0xffffffffffffffffULL); BOOST_CHECK_EQUAL(HexStr(ss), "80fefefefefefefefe7f"); ss.clear();
251 }
252 
254 {
255  CDataStream ss(SER_DISK, 0);
256  std::vector<char>::size_type i, j;
257 
258  for (i = 1; i <= MAX_SIZE; i *= 2)
259  {
260  WriteCompactSize(ss, i-1);
261  WriteCompactSize(ss, i);
262  }
263  for (i = 1; i <= MAX_SIZE; i *= 2)
264  {
265  j = ReadCompactSize(ss);
266  BOOST_CHECK_MESSAGE((i-1) == j, "decoded:" << j << " expected:" << (i-1));
267  j = ReadCompactSize(ss);
268  BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
269  }
270 }
271 
272 static bool isCanonicalException(const std::ios_base::failure& ex)
273 {
274  std::ios_base::failure expectedException("non-canonical ReadCompactSize()");
275 
276  // The string returned by what() can be different for different platforms.
277  // Instead of directly comparing the ex.what() with an expected string,
278  // create an instance of exception to see if ex.what() matches
279  // the expected explanatory string returned by the exception instance.
280  return strcmp(expectedException.what(), ex.what()) == 0;
281 }
282 
284 {
285  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};
286  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};
287 
288  BOOST_CHECK(vec1 == std::vector<uint8_t>(vec2.begin(), vec2.end()));
289  BOOST_CHECK(SerializeHash(vec1) == SerializeHash(vec2));
290 }
291 
292 BOOST_AUTO_TEST_CASE(noncanonical)
293 {
294  // Write some non-canonical CompactSize encodings, and
295  // make sure an exception is thrown when read back.
296  CDataStream ss(SER_DISK, 0);
297  std::vector<char>::size_type n;
298 
299  // zero encoded with three bytes:
300  ss.write("\xfd\x00\x00", 3);
301  BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
302 
303  // 0xfc encoded with three bytes:
304  ss.write("\xfd\xfc\x00", 3);
305  BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
306 
307  // 0xfd encoded with three bytes is OK:
308  ss.write("\xfd\xfd\x00", 3);
309  n = ReadCompactSize(ss);
310  BOOST_CHECK(n == 0xfd);
311 
312  // zero encoded with five bytes:
313  ss.write("\xfe\x00\x00\x00\x00", 5);
314  BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
315 
316  // 0xffff encoded with five bytes:
317  ss.write("\xfe\xff\xff\x00\x00", 5);
318  BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
319 
320  // zero encoded with nine bytes:
321  ss.write("\xff\x00\x00\x00\x00\x00\x00\x00\x00", 9);
322  BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
323 
324  // 0x01ffffff encoded with nine bytes:
325  ss.write("\xff\xff\xff\xff\x01\x00\x00\x00\x00", 9);
326  BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
327 }
328 
329 BOOST_AUTO_TEST_CASE(insert_delete)
330 {
331  // Test inserting/deleting bytes.
332  CDataStream ss(SER_DISK, 0);
333  BOOST_CHECK_EQUAL(ss.size(), 0);
334 
335  ss.write("\x00\x01\x02\xff", 4);
336  BOOST_CHECK_EQUAL(ss.size(), 4);
337 
338  char c = (char)11;
339 
340  // Inserting at beginning/end/middle:
341  ss.insert(ss.begin(), c);
342  BOOST_CHECK_EQUAL(ss.size(), 5);
343  BOOST_CHECK_EQUAL(ss[0], c);
344  BOOST_CHECK_EQUAL(ss[1], 0);
345 
346  ss.insert(ss.end(), c);
347  BOOST_CHECK_EQUAL(ss.size(), 6);
348  BOOST_CHECK_EQUAL(ss[4], (char)0xff);
349  BOOST_CHECK_EQUAL(ss[5], c);
350 
351  ss.insert(ss.begin()+2, c);
352  BOOST_CHECK_EQUAL(ss.size(), 7);
353  BOOST_CHECK_EQUAL(ss[2], c);
354 
355  // Delete at beginning/end/middle
356  ss.erase(ss.begin());
357  BOOST_CHECK_EQUAL(ss.size(), 6);
358  BOOST_CHECK_EQUAL(ss[0], 0);
359 
360  ss.erase(ss.begin()+ss.size()-1);
361  BOOST_CHECK_EQUAL(ss.size(), 5);
362  BOOST_CHECK_EQUAL(ss[4], (char)0xff);
363 
364  ss.erase(ss.begin()+1);
365  BOOST_CHECK_EQUAL(ss.size(), 4);
366  BOOST_CHECK_EQUAL(ss[0], 0);
367  BOOST_CHECK_EQUAL(ss[1], 1);
368  BOOST_CHECK_EQUAL(ss[2], 2);
369  BOOST_CHECK_EQUAL(ss[3], (char)0xff);
370 
371  // Make sure GetAndClear does the right thing:
372  CSerializeData d;
373  ss.GetAndClear(d);
374  BOOST_CHECK_EQUAL(ss.size(), 0);
375 }
376 
377 BOOST_AUTO_TEST_CASE(class_methods)
378 {
379  int intval(100);
380  bool boolval(true);
381  std::string stringval("testing");
382  const char charstrval[16] = "testing charstr";
383  CMutableTransaction txval;
384  CSerializeMethodsTestSingle methodtest1(intval, boolval, stringval, charstrval, txval);
385  CSerializeMethodsTestMany methodtest2(intval, boolval, stringval, charstrval, txval);
386  CSerializeMethodsTestSingle methodtest3;
387  CSerializeMethodsTestMany methodtest4;
388  CDataStream ss(SER_DISK, PROTOCOL_VERSION);
389  BOOST_CHECK(methodtest1 == methodtest2);
390  ss << methodtest1;
391  ss >> methodtest4;
392  ss << methodtest2;
393  ss >> methodtest3;
394  BOOST_CHECK(methodtest1 == methodtest2);
395  BOOST_CHECK(methodtest2 == methodtest3);
396  BOOST_CHECK(methodtest3 == methodtest4);
397 
398  CDataStream ss2(SER_DISK, PROTOCOL_VERSION, intval, boolval, stringval, charstrval, txval);
399  ss2 >> methodtest3;
400  BOOST_CHECK(methodtest3 == methodtest4);
401 }
402 
#define ss2(x)
Definition: bmw.c:142
void write(const char *pch, size_t nSize)
Definition: streams.h:302
const_iterator end() const
Definition: streams.h:163
void GetAndClear(CSerializeData &data)
Definition: streams.h:332
iterator insert(iterator it, const char x=char())
Definition: streams.h:176
const_iterator begin() const
Definition: streams.h:161
vector_type::size_type size_type
Definition: streams.h:86
iterator erase(iterator it)
Definition: streams.h:205
size_type size() const
Definition: streams.h:165
void clear()
Definition: streams.h:171
SERIALIZE_METHODS(CSerializeMethodsTestMany, obj)
SERIALIZE_METHODS(CSerializeMethodsTestSingle, obj)
bool operator==(const CSerializeMethodsTestSingle &rhs)
CSerializeMethodsTestSingle(int intvalin, bool boolvalin, std::string stringvalin, const char *charstrvalin, CTransaction txvalin)
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:244
BOOST_AUTO_TEST_SUITE_END()
void * memcpy(void *a, const void *b, size_t c)
uint256 SerializeHash(const T &obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
Compute the 256-bit hash of an object's serialization.
Definition: hash.h:289
uint256 Hash(const T1 pbegin, const T1 pend)
Compute the 256-bit hash of an object.
Definition: hash.h:173
#define T(expected, seed, data)
Definition: uint256.h:212
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
#define BOOST_CHECK(expr)
Definition: object.cpp:17
@ SER_DISK
Definition: serialize.h:175
#define VARINT(obj)
Definition: serialize.h:513
#define VARINT_MODE(obj, mode)
Definition: serialize.h:512
float ser_uint32_to_float(uint32_t y)
Definition: serialize.h:155
@ NONNEGATIVE_SIGNED
unsigned int GetSerializeSize(const std::array< T, N > &item)
array
Definition: serialize.h:847
uint32_t ser_float_to_uint32(float x)
Definition: serialize.h:141
double ser_uint64_to_double(uint64_t y)
Definition: serialize.h:148
uint64_t ReadCompactSize(Stream &is, bool range_check=true)
Decode a CompactSize-encoded variable-length integer.
Definition: serialize.h:359
uint64_t ser_double_to_uint64(double x)
Definition: serialize.h:134
#define READWRITE(...)
Definition: serialize.h:183
void WriteCompactSize(CSizeComputer &os, uint64_t nSize)
Definition: serialize.h:1435
BOOST_AUTO_TEST_CASE(sizes)
void check_ser_rep(T thing, std::vector< unsigned char > expected)
Basic testing setup.
Definition: test_pivx.h:51
A mutable version of CTransaction.
Definition: transaction.h:409
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:456
uint256 uint256S(const char *str)
Definition: uint256.h:157
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
std::vector< char, zero_after_free_allocator< char > > CSerializeData
Definition: zeroafterfree.h:46