Browse Source

Merge pull request #5510

a0ae79d Replace CBlockHeader::GetHash with call to SerializeHash (Wladimir J. van der Laan)
62b30f0 Add serialize float/double tests (Wladimir J. van der Laan)
9f4fac9 src/txmempool.cpp: make numEntries a uint32_t (Wladimir J. van der Laan)
f4e6487 src/arith_256.cpp: bigendian compatibility (Wladimir J. van der Laan)
aac3205 src/netbase.h: Fix endian in CNetAddr serialization (Wladimir J. van der Laan)
01f9c34 src/serialize.h: base serialization level endianness neutrality (Wladimir J. van der Laan)
4e853aa src/script/script.h: endian compatibility for PUSHDATA sizes (Wladimir J. van der Laan)
4f92773 src/primitives/transaction.h: endian compatibility in serialization (Wladimir J. van der Laan)
81aeb28 src/primitives/block.cpp: endian compatibility in GetHash (Wladimir J. van der Laan)
dec84ca src/net.cpp: endian compatibility in EndMessage (Wladimir J. van der Laan)
556814e src/main.cpp: endian compatibility in packet checksum check (Wladimir J. van der Laan)
3ca5852 src/hash.cpp: endian compatibility (Wladimir J. van der Laan)
4414f5f build: Endian compatibility (Wladimir J. van der Laan)
0.13
Wladimir J. van der Laan 10 years ago
parent
commit
7c3fbc34ae
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6
  1. 13
      configure.ac
  2. 2
      src/Makefile.am
  3. 9
      src/arith_uint256.cpp
  4. 47
      src/compat/byteswap.h
  5. 194
      src/compat/endian.h
  6. 76
      src/crypto/common.h
  7. 6
      src/hash.cpp
  8. 3
      src/main.cpp
  9. 3
      src/net.cpp
  10. 2
      src/netbase.h
  11. 3
      src/primitives/block.cpp
  12. 3
      src/primitives/transaction.h
  13. 16
      src/script/script.h
  14. 201
      src/serialize.h
  15. 114
      src/test/serialize_tests.cpp
  16. 4
      src/txmempool.cpp

13
configure.ac

@ -350,8 +350,8 @@ if test x$use_lcov = xyes; then
[AC_MSG_ERROR("lcov testing requested but --coverage flag does not work")]) [AC_MSG_ERROR("lcov testing requested but --coverage flag does not work")])
fi fi
dnl Require little endian dnl Check for endianness
AC_C_BIGENDIAN([AC_MSG_ERROR("Big Endian not supported")]) AC_C_BIGENDIAN
dnl Check for pthread compile/link requirements dnl Check for pthread compile/link requirements
AX_PTHREAD AX_PTHREAD
@ -438,17 +438,22 @@ if test x$TARGET_OS = xdarwin; then
AX_CHECK_LINK_FLAG([[-Wl,-dead_strip]], [LDFLAGS="$LDFLAGS -Wl,-dead_strip"]) AX_CHECK_LINK_FLAG([[-Wl,-dead_strip]], [LDFLAGS="$LDFLAGS -Wl,-dead_strip"])
fi fi
AC_CHECK_HEADERS([endian.h stdio.h stdlib.h unistd.h strings.h sys/types.h sys/stat.h sys/select.h sys/prctl.h]) AC_CHECK_HEADERS([endian.h byteswap.h stdio.h stdlib.h unistd.h strings.h sys/types.h sys/stat.h sys/select.h sys/prctl.h])
AC_SEARCH_LIBS([getaddrinfo_a], [anl], [AC_DEFINE(HAVE_GETADDRINFO_A, 1, [Define this symbol if you have getaddrinfo_a])]) AC_SEARCH_LIBS([getaddrinfo_a], [anl], [AC_DEFINE(HAVE_GETADDRINFO_A, 1, [Define this symbol if you have getaddrinfo_a])])
AC_SEARCH_LIBS([inet_pton], [nsl resolv], [AC_DEFINE(HAVE_INET_PTON, 1, [Define this symbol if you have inet_pton])]) AC_SEARCH_LIBS([inet_pton], [nsl resolv], [AC_DEFINE(HAVE_INET_PTON, 1, [Define this symbol if you have inet_pton])])
AC_CHECK_DECLS([strnlen]) AC_CHECK_DECLS([strnlen])
AC_CHECK_DECLS([le32toh, le64toh, htole32, htole64, be32toh, be64toh, htobe32, htobe64],,, AC_CHECK_DECLS([le16toh, le32toh, le64toh, htole16, htole32, htole64, be16toh, be32toh, be64toh, htobe16, htobe32, htobe64],,,
[#if HAVE_ENDIAN_H [#if HAVE_ENDIAN_H
#include <endian.h> #include <endian.h>
#endif]) #endif])
AC_CHECK_DECLS([bswap_16, bswap_32, bswap_64],,,
[#if HAVE_BYTESWAP_H
#include <byteswap.h>
#endif])
dnl Check for MSG_NOSIGNAL dnl Check for MSG_NOSIGNAL
AC_MSG_CHECKING(for MSG_NOSIGNAL) AC_MSG_CHECKING(for MSG_NOSIGNAL)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/socket.h>]], AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/socket.h>]],

2
src/Makefile.am

@ -141,6 +141,8 @@ BITCOIN_CORE_H = \
walletdb.h \ walletdb.h \
wallet.h \ wallet.h \
wallet_ismine.h \ wallet_ismine.h \
compat/byteswap.h \
compat/endian.h \
compat/sanity.h compat/sanity.h
JSON_H = \ JSON_H = \

9
src/arith_uint256.cpp

@ -7,6 +7,7 @@
#include "uint256.h" #include "uint256.h"
#include "utilstrencodings.h" #include "utilstrencodings.h"
#include "crypto/common.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -246,14 +247,14 @@ uint32_t arith_uint256::GetCompact(bool fNegative) const
uint256 ArithToUint256(const arith_uint256 &a) uint256 ArithToUint256(const arith_uint256 &a)
{ {
uint256 b; uint256 b;
// TODO: needs bswap32 on big-endian for(int x=0; x<a.WIDTH; ++x)
memcpy(b.begin(), a.pn, a.size()); WriteLE32(b.begin() + x*4, a.pn[x]);
return b; return b;
} }
arith_uint256 UintToArith256(const uint256 &a) arith_uint256 UintToArith256(const uint256 &a)
{ {
arith_uint256 b; arith_uint256 b;
// TODO: needs bswap32 on big-endian for(int x=0; x<b.WIDTH; ++x)
memcpy(b.pn, a.begin(), a.size()); b.pn[x] = ReadLE32(a.begin() + x*4);
return b; return b;
} }

47
src/compat/byteswap.h

@ -0,0 +1,47 @@
// Copyright (c) 2014 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_COMPAT_BYTESWAP_H
#define BITCOIN_COMPAT_BYTESWAP_H
#if defined(HAVE_CONFIG_H)
#include "config/bitcoin-config.h"
#endif
#include <stdint.h>
#if defined(HAVE_BYTESWAP_H)
#include <byteswap.h>
#endif
#if HAVE_DECL_BSWAP_16 == 0
inline uint16_t bswap_16(uint16_t x)
{
return (x >> 8) | ((x & 0x00ff) << 8);
}
#endif // HAVE_DECL_BSWAP16
#if HAVE_DECL_BSWAP_32 == 0
inline uint32_t bswap_32(uint32_t x)
{
return (((x & 0xff000000U) >> 24) | ((x & 0x00ff0000U) >> 8) |
((x & 0x0000ff00U) << 8) | ((x & 0x000000ffU) << 24));
}
#endif // HAVE_DECL_BSWAP32
#if HAVE_DECL_BSWAP_64 == 0
inline uint64_t bswap_64(uint64_t x)
{
return (((x & 0xff00000000000000ull) >> 56)
| ((x & 0x00ff000000000000ull) >> 40)
| ((x & 0x0000ff0000000000ull) >> 24)
| ((x & 0x000000ff00000000ull) >> 8)
| ((x & 0x00000000ff000000ull) << 8)
| ((x & 0x0000000000ff0000ull) << 24)
| ((x & 0x000000000000ff00ull) << 40)
| ((x & 0x00000000000000ffull) << 56));
}
#endif // HAVE_DECL_BSWAP64
#endif // BITCOIN_COMPAT_BYTESWAP_H

194
src/compat/endian.h

@ -0,0 +1,194 @@
// Copyright (c) 2014 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_COMPAT_ENDIAN_H
#define BITCOIN_COMPAT_ENDIAN_H
#if defined(HAVE_CONFIG_H)
#include "config/bitcoin-config.h"
#endif
#include <stdint.h>
#include "compat/byteswap.h"
#if defined(HAVE_ENDIAN_H)
#include <endian.h>
#endif
#if defined(WORDS_BIGENDIAN)
#if HAVE_DECL_HTOBE16 == 0
inline uint16_t htobe16(uint16_t host_16bits)
{
return host_16bits;
}
#endif // HAVE_DECL_HTOBE16
#if HAVE_DECL_HTOLE16 == 0
inline uint16_t htole16(uint16_t host_16bits)
{
return bswap_16(host_16bits);
}
#endif // HAVE_DECL_HTOLE16
#if HAVE_DECL_BE16TOH == 0
inline uint16_t be16toh(uint16_t big_endian_16bits)
{
return big_endian_16bits;
}
#endif // HAVE_DECL_BE16TOH
#if HAVE_DECL_LE16TOH == 0
inline uint16_t le16toh(uint16_t little_endian_16bits)
{
return bswap_16(little_endian_16bits);
}
#endif // HAVE_DECL_LE16TOH
#if HAVE_DECL_HTOBE32 == 0
inline uint32_t htobe32(uint32_t host_32bits)
{
return host_32bits;
}
#endif // HAVE_DECL_HTOBE32
#if HAVE_DECL_HTOLE32 == 0
inline uint32_t htole32(uint32_t host_32bits)
{
return bswap_32(host_32bits);
}
#endif // HAVE_DECL_HTOLE32
#if HAVE_DECL_BE32TOH == 0
inline uint32_t be32toh(uint32_t big_endian_32bits)
{
return big_endian_32bits;
}
#endif // HAVE_DECL_BE32TOH
#if HAVE_DECL_LE32TOH == 0
inline uint32_t le32toh(uint32_t little_endian_32bits)
{
return bswap_32(little_endian_32bits);
}
#endif // HAVE_DECL_LE32TOH
#if HAVE_DECL_HTOBE64 == 0
inline uint64_t htobe64(uint64_t host_64bits)
{
return host_64bits;
}
#endif // HAVE_DECL_HTOBE64
#if HAVE_DECL_HTOLE64 == 0
inline uint64_t htole64(uint64_t host_64bits)
{
return bswap_64(host_64bits);
}
#endif // HAVE_DECL_HTOLE64
#if HAVE_DECL_BE64TOH == 0
inline uint64_t be64toh(uint64_t big_endian_64bits)
{
return big_endian_64bits;
}
#endif // HAVE_DECL_BE64TOH
#if HAVE_DECL_LE64TOH == 0
inline uint64_t le64toh(uint64_t little_endian_64bits)
{
return bswap_64(little_endian_64bits);
}
#endif // HAVE_DECL_LE64TOH
#else // WORDS_BIGENDIAN
#if HAVE_DECL_HTOBE16 == 0
inline uint16_t htobe16(uint16_t host_16bits)
{
return bswap_16(host_16bits);
}
#endif // HAVE_DECL_HTOBE16
#if HAVE_DECL_HTOLE16 == 0
inline uint16_t htole16(uint16_t host_16bits)
{
return host_16bits;
}
#endif // HAVE_DECL_HTOLE16
#if HAVE_DECL_BE16TOH == 0
inline uint16_t be16toh(uint16_t big_endian_16bits)
{
return bswap_16(big_endian_16bits);
}
#endif // HAVE_DECL_BE16TOH
#if HAVE_DECL_LE16TOH == 0
inline uint16_t le16toh(uint16_t little_endian_16bits)
{
return little_endian_16bits;
}
#endif // HAVE_DECL_LE16TOH
#if HAVE_DECL_HTOBE32 == 0
inline uint32_t htobe32(uint32_t host_32bits)
{
return bswap_32(host_32bits);
}
#endif // HAVE_DECL_HTOBE32
#if HAVE_DECL_HTOLE32 == 0
inline uint32_t htole32(uint32_t host_32bits)
{
return host_32bits;
}
#endif // HAVE_DECL_HTOLE32
#if HAVE_DECL_BE32TOH == 0
inline uint32_t be32toh(uint32_t big_endian_32bits)
{
return bswap_32(big_endian_32bits);
}
#endif // HAVE_DECL_BE32TOH
#if HAVE_DECL_LE32TOH == 0
inline uint32_t le32toh(uint32_t little_endian_32bits)
{
return little_endian_32bits;
}
#endif // HAVE_DECL_LE32TOH
#if HAVE_DECL_HTOBE64 == 0
inline uint64_t htobe64(uint64_t host_64bits)
{
return bswap_64(host_64bits);
}
#endif // HAVE_DECL_HTOBE64
#if HAVE_DECL_HTOLE64 == 0
inline uint64_t htole64(uint64_t host_64bits)
{
return host_64bits;
}
#endif // HAVE_DECL_HTOLE64
#if HAVE_DECL_BE64TOH == 0
inline uint64_t be64toh(uint64_t big_endian_64bits)
{
return bswap_64(big_endian_64bits);
}
#endif // HAVE_DECL_BE64TOH
#if HAVE_DECL_LE64TOH == 0
inline uint64_t le64toh(uint64_t little_endian_64bits)
{
return little_endian_64bits;
}
#endif // HAVE_DECL_LE64TOH
#endif // WORDS_BIGENDIAN
#endif // BITCOIN_COMPAT_ENDIAN_H

76
src/crypto/common.h

@ -11,110 +11,56 @@
#include <stdint.h> #include <stdint.h>
#if defined(HAVE_ENDIAN_H) #include "compat/endian.h"
#include <endian.h>
#endif uint16_t static inline ReadLE16(const unsigned char* ptr)
{
return le16toh(*((uint16_t*)ptr));
}
uint32_t static inline ReadLE32(const unsigned char* ptr) uint32_t static inline ReadLE32(const unsigned char* ptr)
{ {
#if HAVE_DECL_LE32TOH == 1
return le32toh(*((uint32_t*)ptr)); return le32toh(*((uint32_t*)ptr));
#elif !defined(WORDS_BIGENDIAN)
return *((uint32_t*)ptr);
#else
return ((uint32_t)ptr[3] << 24 | (uint32_t)ptr[2] << 16 | (uint32_t)ptr[1] << 8 | (uint32_t)ptr[0]);
#endif
} }
uint64_t static inline ReadLE64(const unsigned char* ptr) uint64_t static inline ReadLE64(const unsigned char* ptr)
{ {
#if HAVE_DECL_LE64TOH == 1
return le64toh(*((uint64_t*)ptr)); return le64toh(*((uint64_t*)ptr));
#elif !defined(WORDS_BIGENDIAN) }
return *((uint64_t*)ptr);
#else void static inline WriteLE16(unsigned char* ptr, uint16_t x)
return ((uint64_t)ptr[7] << 56 | (uint64_t)ptr[6] << 48 | (uint64_t)ptr[5] << 40 | (uint64_t)ptr[4] << 32 | {
(uint64_t)ptr[3] << 24 | (uint64_t)ptr[2] << 16 | (uint64_t)ptr[1] << 8 | (uint64_t)ptr[0]); *((uint16_t*)ptr) = htole16(x);
#endif
} }
void static inline WriteLE32(unsigned char* ptr, uint32_t x) void static inline WriteLE32(unsigned char* ptr, uint32_t x)
{ {
#if HAVE_DECL_HTOLE32 == 1
*((uint32_t*)ptr) = htole32(x); *((uint32_t*)ptr) = htole32(x);
#elif !defined(WORDS_BIGENDIAN)
*((uint32_t*)ptr) = x;
#else
ptr[3] = x >> 24;
ptr[2] = x >> 16;
ptr[1] = x >> 8;
ptr[0] = x;
#endif
} }
void static inline WriteLE64(unsigned char* ptr, uint64_t x) void static inline WriteLE64(unsigned char* ptr, uint64_t x)
{ {
#if HAVE_DECL_HTOLE64 == 1
*((uint64_t*)ptr) = htole64(x); *((uint64_t*)ptr) = htole64(x);
#elif !defined(WORDS_BIGENDIAN)
*((uint64_t*)ptr) = x;
#else
ptr[7] = x >> 56;
ptr[6] = x >> 48;
ptr[5] = x >> 40;
ptr[4] = x >> 32;
ptr[3] = x >> 24;
ptr[2] = x >> 16;
ptr[1] = x >> 8;
ptr[0] = x;
#endif
} }
uint32_t static inline ReadBE32(const unsigned char* ptr) uint32_t static inline ReadBE32(const unsigned char* ptr)
{ {
#if HAVE_DECL_BE32TOH == 1
return be32toh(*((uint32_t*)ptr)); return be32toh(*((uint32_t*)ptr));
#else
return ((uint32_t)ptr[0] << 24 | (uint32_t)ptr[1] << 16 | (uint32_t)ptr[2] << 8 | (uint32_t)ptr[3]);
#endif
} }
uint64_t static inline ReadBE64(const unsigned char* ptr) uint64_t static inline ReadBE64(const unsigned char* ptr)
{ {
#if HAVE_DECL_BE64TOH == 1
return be64toh(*((uint64_t*)ptr)); return be64toh(*((uint64_t*)ptr));
#else
return ((uint64_t)ptr[0] << 56 | (uint64_t)ptr[1] << 48 | (uint64_t)ptr[2] << 40 | (uint64_t)ptr[3] << 32 |
(uint64_t)ptr[4] << 24 | (uint64_t)ptr[5] << 16 | (uint64_t)ptr[6] << 8 | (uint64_t)ptr[7]);
#endif
} }
void static inline WriteBE32(unsigned char* ptr, uint32_t x) void static inline WriteBE32(unsigned char* ptr, uint32_t x)
{ {
#if HAVE_DECL_HTOBE32 == 1
*((uint32_t*)ptr) = htobe32(x); *((uint32_t*)ptr) = htobe32(x);
#else
ptr[0] = x >> 24;
ptr[1] = x >> 16;
ptr[2] = x >> 8;
ptr[3] = x;
#endif
} }
void static inline WriteBE64(unsigned char* ptr, uint64_t x) void static inline WriteBE64(unsigned char* ptr, uint64_t x)
{ {
#if HAVE_DECL_HTOBE64 == 1
*((uint64_t*)ptr) = htobe64(x); *((uint64_t*)ptr) = htobe64(x);
#else
ptr[0] = x >> 56;
ptr[1] = x >> 48;
ptr[2] = x >> 40;
ptr[3] = x >> 32;
ptr[4] = x >> 24;
ptr[5] = x >> 16;
ptr[6] = x >> 8;
ptr[7] = x;
#endif
} }
#endif // BITCOIN_CRYPTO_COMMON_H #endif // BITCOIN_CRYPTO_COMMON_H

6
src/hash.cpp

@ -3,8 +3,10 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "hash.h" #include "hash.h"
#include "crypto/common.h"
#include "crypto/hmac_sha512.h" #include "crypto/hmac_sha512.h"
inline uint32_t ROTL32(uint32_t x, int8_t r) inline uint32_t ROTL32(uint32_t x, int8_t r)
{ {
return (x << r) | (x >> (32 - r)); return (x << r) | (x >> (32 - r));
@ -23,10 +25,10 @@ unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char
//---------- //----------
// body // body
const uint32_t* blocks = (const uint32_t*)(&vDataToHash[0] + nblocks * 4); const uint8_t* blocks = &vDataToHash[0] + nblocks * 4;
for (int i = -nblocks; i; i++) { for (int i = -nblocks; i; i++) {
uint32_t k1 = blocks[i]; uint32_t k1 = ReadLE32(blocks + i*4);
k1 *= c1; k1 *= c1;
k1 = ROTL32(k1, 15); k1 = ROTL32(k1, 15);

3
src/main.cpp

@ -4318,8 +4318,7 @@ bool ProcessMessages(CNode* pfrom)
// Checksum // Checksum
CDataStream& vRecv = msg.vRecv; CDataStream& vRecv = msg.vRecv;
uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize); uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
unsigned int nChecksum = 0; unsigned int nChecksum = ReadLE32((unsigned char*)&hash);
memcpy(&nChecksum, &hash, sizeof(nChecksum));
if (nChecksum != hdr.nChecksum) if (nChecksum != hdr.nChecksum)
{ {
LogPrintf("ProcessMessages(%s, %u bytes): CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n", LogPrintf("ProcessMessages(%s, %u bytes): CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",

3
src/net.cpp

@ -14,6 +14,7 @@
#include "clientversion.h" #include "clientversion.h"
#include "primitives/transaction.h" #include "primitives/transaction.h"
#include "ui_interface.h" #include "ui_interface.h"
#include "crypto/common.h"
#ifdef WIN32 #ifdef WIN32
#include <string.h> #include <string.h>
@ -2007,7 +2008,7 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend)
// Set the size // Set the size
unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE; unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE;
memcpy((char*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], &nSize, sizeof(nSize)); WriteLE32((uint8_t*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize);
// Set the checksum // Set the checksum
uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end()); uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end());

2
src/netbase.h

@ -162,7 +162,7 @@ class CService : public CNetAddr
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(FLATDATA(ip)); READWRITE(FLATDATA(ip));
unsigned short portN = htons(port); unsigned short portN = htons(port);
READWRITE(portN); READWRITE(FLATDATA(portN));
if (ser_action.ForRead()) if (ser_action.ForRead())
port = ntohs(portN); port = ntohs(portN);
} }

3
src/primitives/block.cpp

@ -8,10 +8,11 @@
#include "hash.h" #include "hash.h"
#include "tinyformat.h" #include "tinyformat.h"
#include "utilstrencodings.h" #include "utilstrencodings.h"
#include "crypto/common.h"
uint256 CBlockHeader::GetHash() const uint256 CBlockHeader::GetHash() const
{ {
return Hash(BEGIN(nVersion), END(nNonce)); return SerializeHash(*this);
} }
uint256 CBlock::BuildMerkleTree(bool* fMutated) const uint256 CBlock::BuildMerkleTree(bool* fMutated) const

3
src/primitives/transaction.h

@ -25,7 +25,8 @@ public:
template <typename Stream, typename Operation> template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(FLATDATA(*this)); READWRITE(hash);
READWRITE(n);
} }
void SetNull() { hash.SetNull(); n = (uint32_t) -1; } void SetNull() { hash.SetNull(); n = (uint32_t) -1; }

16
src/script/script.h

@ -14,6 +14,7 @@
#include <string.h> #include <string.h>
#include <string> #include <string>
#include <vector> #include <vector>
#include "crypto/common.h"
static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes
@ -416,14 +417,16 @@ public:
else if (b.size() <= 0xffff) else if (b.size() <= 0xffff)
{ {
insert(end(), OP_PUSHDATA2); insert(end(), OP_PUSHDATA2);
unsigned short nSize = b.size(); uint8_t data[2];
insert(end(), (unsigned char*)&nSize, (unsigned char*)&nSize + sizeof(nSize)); WriteLE16(data, b.size());
insert(end(), data, data + sizeof(data));
} }
else else
{ {
insert(end(), OP_PUSHDATA4); insert(end(), OP_PUSHDATA4);
unsigned int nSize = b.size(); uint8_t data[4];
insert(end(), (unsigned char*)&nSize, (unsigned char*)&nSize + sizeof(nSize)); WriteLE32(data, b.size());
insert(end(), data, data + sizeof(data));
} }
insert(end(), b.begin(), b.end()); insert(end(), b.begin(), b.end());
return *this; return *this;
@ -496,15 +499,14 @@ public:
{ {
if (end() - pc < 2) if (end() - pc < 2)
return false; return false;
nSize = 0; nSize = ReadLE16(&pc[0]);
memcpy(&nSize, &pc[0], 2);
pc += 2; pc += 2;
} }
else if (opcode == OP_PUSHDATA4) else if (opcode == OP_PUSHDATA4)
{ {
if (end() - pc < 4) if (end() - pc < 4)
return false; return false;
memcpy(&nSize, &pc[0], 4); nSize = ReadLE32(&pc[0]);
pc += 4; pc += 4;
} }
if (end() - pc < 0 || (unsigned int)(end() - pc) < nSize) if (end() - pc < 0 || (unsigned int)(end() - pc) < nSize)

201
src/serialize.h

@ -18,6 +18,8 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "compat/endian.h"
class CScript; class CScript;
static const unsigned int MAX_SIZE = 0x02000000; static const unsigned int MAX_SIZE = 0x02000000;
@ -71,6 +73,79 @@ inline const T* end_ptr(const std::vector<T,TAl>& v)
return v.empty() ? NULL : (&v[0] + v.size()); return v.empty() ? NULL : (&v[0] + v.size());
} }
/*
* Lowest-level serialization and conversion.
* @note Sizes of these types are verified in the tests
*/
template<typename Stream> inline void ser_writedata8(Stream &s, uint8_t obj)
{
s.write((char*)&obj, 1);
}
template<typename Stream> inline void ser_writedata16(Stream &s, uint16_t obj)
{
obj = htole16(obj);
s.write((char*)&obj, 2);
}
template<typename Stream> inline void ser_writedata32(Stream &s, uint32_t obj)
{
obj = htole32(obj);
s.write((char*)&obj, 4);
}
template<typename Stream> inline void ser_writedata64(Stream &s, uint64_t obj)
{
obj = htole64(obj);
s.write((char*)&obj, 8);
}
template<typename Stream> inline uint8_t ser_readdata8(Stream &s)
{
uint8_t obj;
s.read((char*)&obj, 1);
return obj;
}
template<typename Stream> inline uint16_t ser_readdata16(Stream &s)
{
uint16_t obj;
s.read((char*)&obj, 2);
return le16toh(obj);
}
template<typename Stream> inline uint32_t ser_readdata32(Stream &s)
{
uint32_t obj;
s.read((char*)&obj, 4);
return le32toh(obj);
}
template<typename Stream> inline uint64_t ser_readdata64(Stream &s)
{
uint64_t obj;
s.read((char*)&obj, 8);
return le64toh(obj);
}
inline uint64_t ser_double_to_uint64(double x)
{
union { double x; uint64_t y; } tmp;
tmp.x = x;
return tmp.y;
}
inline uint32_t ser_float_to_uint32(float x)
{
union { float x; uint32_t y; } tmp;
tmp.x = x;
return tmp.y;
}
inline double ser_uint64_to_double(uint64_t y)
{
union { double x; uint64_t y; } tmp;
tmp.y = y;
return tmp.x;
}
inline float ser_uint32_to_float(uint32_t y)
{
union { float x; uint32_t y; } tmp;
tmp.y = y;
return tmp.x;
}
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// //
// Templates for serializing to anything that looks like a stream, // Templates for serializing to anything that looks like a stream,
@ -108,59 +183,48 @@ enum
SerializationOp(s, CSerActionUnserialize(), nType, nVersion); \ SerializationOp(s, CSerActionUnserialize(), nType, nVersion); \
} }
/* /*
* Basic Types * Basic Types
*/ */
#define WRITEDATA(s, obj) s.write((char*)&(obj), sizeof(obj)) inline unsigned int GetSerializeSize(char a, int, int=0) { return 1; }
#define READDATA(s, obj) s.read((char*)&(obj), sizeof(obj)) inline unsigned int GetSerializeSize(int8_t a, int, int=0) { return 1; }
inline unsigned int GetSerializeSize(uint8_t a, int, int=0) { return 1; }
inline unsigned int GetSerializeSize(char a, int, int=0) { return sizeof(a); } inline unsigned int GetSerializeSize(int16_t a, int, int=0) { return 2; }
inline unsigned int GetSerializeSize(signed char a, int, int=0) { return sizeof(a); } inline unsigned int GetSerializeSize(uint16_t a, int, int=0) { return 2; }
inline unsigned int GetSerializeSize(unsigned char a, int, int=0) { return sizeof(a); } inline unsigned int GetSerializeSize(int32_t a, int, int=0) { return 4; }
inline unsigned int GetSerializeSize(signed short a, int, int=0) { return sizeof(a); } inline unsigned int GetSerializeSize(uint32_t a, int, int=0) { return 4; }
inline unsigned int GetSerializeSize(unsigned short a, int, int=0) { return sizeof(a); } inline unsigned int GetSerializeSize(int64_t a, int, int=0) { return 8; }
inline unsigned int GetSerializeSize(signed int a, int, int=0) { return sizeof(a); } inline unsigned int GetSerializeSize(uint64_t a, int, int=0) { return 8; }
inline unsigned int GetSerializeSize(unsigned int a, int, int=0) { return sizeof(a); } inline unsigned int GetSerializeSize(float a, int, int=0) { return 4; }
inline unsigned int GetSerializeSize(signed long a, int, int=0) { return sizeof(a); } inline unsigned int GetSerializeSize(double a, int, int=0) { return 8; }
inline unsigned int GetSerializeSize(unsigned long a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(signed long long a, int, int=0) { return sizeof(a); } template<typename Stream> inline void Serialize(Stream& s, char a, int, int=0) { ser_writedata8(s, a); } // TODO Get rid of bare char
inline unsigned int GetSerializeSize(unsigned long long a, int, int=0) { return sizeof(a); } template<typename Stream> inline void Serialize(Stream& s, int8_t a, int, int=0) { ser_writedata8(s, a); }
inline unsigned int GetSerializeSize(float a, int, int=0) { return sizeof(a); } template<typename Stream> inline void Serialize(Stream& s, uint8_t a, int, int=0) { ser_writedata8(s, a); }
inline unsigned int GetSerializeSize(double a, int, int=0) { return sizeof(a); } template<typename Stream> inline void Serialize(Stream& s, int16_t a, int, int=0) { ser_writedata16(s, a); }
template<typename Stream> inline void Serialize(Stream& s, uint16_t a, int, int=0) { ser_writedata16(s, a); }
template<typename Stream> inline void Serialize(Stream& s, char a, int, int=0) { WRITEDATA(s, a); } template<typename Stream> inline void Serialize(Stream& s, int32_t a, int, int=0) { ser_writedata32(s, a); }
template<typename Stream> inline void Serialize(Stream& s, signed char a, int, int=0) { WRITEDATA(s, a); } template<typename Stream> inline void Serialize(Stream& s, uint32_t a, int, int=0) { ser_writedata32(s, a); }
template<typename Stream> inline void Serialize(Stream& s, unsigned char a, int, int=0) { WRITEDATA(s, a); } template<typename Stream> inline void Serialize(Stream& s, int64_t a, int, int=0) { ser_writedata64(s, a); }
template<typename Stream> inline void Serialize(Stream& s, signed short a, int, int=0) { WRITEDATA(s, a); } template<typename Stream> inline void Serialize(Stream& s, uint64_t a, int, int=0) { ser_writedata64(s, a); }
template<typename Stream> inline void Serialize(Stream& s, unsigned short a, int, int=0) { WRITEDATA(s, a); } template<typename Stream> inline void Serialize(Stream& s, float a, int, int=0) { ser_writedata32(s, ser_float_to_uint32(a)); }
template<typename Stream> inline void Serialize(Stream& s, signed int a, int, int=0) { WRITEDATA(s, a); } template<typename Stream> inline void Serialize(Stream& s, double a, int, int=0) { ser_writedata64(s, ser_double_to_uint64(a)); }
template<typename Stream> inline void Serialize(Stream& s, unsigned int a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, signed long a, int, int=0) { WRITEDATA(s, a); } template<typename Stream> inline void Unserialize(Stream& s, char& a, int, int=0) { a = ser_readdata8(s); } // TODO Get rid of bare char
template<typename Stream> inline void Serialize(Stream& s, unsigned long a, int, int=0) { WRITEDATA(s, a); } template<typename Stream> inline void Unserialize(Stream& s, int8_t& a, int, int=0) { a = ser_readdata8(s); }
template<typename Stream> inline void Serialize(Stream& s, signed long long a, int, int=0) { WRITEDATA(s, a); } template<typename Stream> inline void Unserialize(Stream& s, uint8_t& a, int, int=0) { a = ser_readdata8(s); }
template<typename Stream> inline void Serialize(Stream& s, unsigned long long a, int, int=0) { WRITEDATA(s, a); } template<typename Stream> inline void Unserialize(Stream& s, int16_t& a, int, int=0) { a = ser_readdata16(s); }
template<typename Stream> inline void Serialize(Stream& s, float a, int, int=0) { WRITEDATA(s, a); } template<typename Stream> inline void Unserialize(Stream& s, uint16_t& a, int, int=0) { a = ser_readdata16(s); }
template<typename Stream> inline void Serialize(Stream& s, double a, int, int=0) { WRITEDATA(s, a); } template<typename Stream> inline void Unserialize(Stream& s, int32_t& a, int, int=0) { a = ser_readdata32(s); }
template<typename Stream> inline void Unserialize(Stream& s, uint32_t& a, int, int=0) { a = ser_readdata32(s); }
template<typename Stream> inline void Unserialize(Stream& s, char& a, int, int=0) { READDATA(s, a); } template<typename Stream> inline void Unserialize(Stream& s, int64_t& a, int, int=0) { a = ser_readdata64(s); }
template<typename Stream> inline void Unserialize(Stream& s, signed char& a, int, int=0) { READDATA(s, a); } template<typename Stream> inline void Unserialize(Stream& s, uint64_t& a, int, int=0) { a = ser_readdata64(s); }
template<typename Stream> inline void Unserialize(Stream& s, unsigned char& a, int, int=0) { READDATA(s, a); } template<typename Stream> inline void Unserialize(Stream& s, float& a, int, int=0) { a = ser_uint32_to_float(ser_readdata32(s)); }
template<typename Stream> inline void Unserialize(Stream& s, signed short& a, int, int=0) { READDATA(s, a); } template<typename Stream> inline void Unserialize(Stream& s, double& a, int, int=0) { a = ser_uint64_to_double(ser_readdata64(s)); }
template<typename Stream> inline void Unserialize(Stream& s, unsigned short& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, signed int& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, unsigned int& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, signed long& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, unsigned long& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, signed long long& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, unsigned long long& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, float& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, double& a, int, int=0) { READDATA(s, a); }
inline unsigned int GetSerializeSize(bool a, int, int=0) { return sizeof(char); } inline unsigned int GetSerializeSize(bool a, int, int=0) { return sizeof(char); }
template<typename Stream> inline void Serialize(Stream& s, bool a, int, int=0) { char f=a; WRITEDATA(s, f); } template<typename Stream> inline void Serialize(Stream& s, bool a, int, int=0) { char f=a; ser_writedata8(s, f); }
template<typename Stream> inline void Unserialize(Stream& s, bool& a, int, int=0) { char f; READDATA(s, f); a=f; } template<typename Stream> inline void Unserialize(Stream& s, bool& a, int, int=0) { char f=ser_readdata8(s); a=f; }
@ -187,29 +251,22 @@ void WriteCompactSize(Stream& os, uint64_t nSize)
{ {
if (nSize < 253) if (nSize < 253)
{ {
unsigned char chSize = nSize; ser_writedata8(os, nSize);
WRITEDATA(os, chSize);
} }
else if (nSize <= std::numeric_limits<unsigned short>::max()) else if (nSize <= std::numeric_limits<unsigned short>::max())
{ {
unsigned char chSize = 253; ser_writedata8(os, 253);
unsigned short xSize = nSize; ser_writedata16(os, nSize);
WRITEDATA(os, chSize);
WRITEDATA(os, xSize);
} }
else if (nSize <= std::numeric_limits<unsigned int>::max()) else if (nSize <= std::numeric_limits<unsigned int>::max())
{ {
unsigned char chSize = 254; ser_writedata8(os, 254);
unsigned int xSize = nSize; ser_writedata32(os, nSize);
WRITEDATA(os, chSize);
WRITEDATA(os, xSize);
} }
else else
{ {
unsigned char chSize = 255; ser_writedata8(os, 255);
uint64_t xSize = nSize; ser_writedata64(os, nSize);
WRITEDATA(os, chSize);
WRITEDATA(os, xSize);
} }
return; return;
} }
@ -217,8 +274,7 @@ void WriteCompactSize(Stream& os, uint64_t nSize)
template<typename Stream> template<typename Stream>
uint64_t ReadCompactSize(Stream& is) uint64_t ReadCompactSize(Stream& is)
{ {
unsigned char chSize; uint8_t chSize = ser_readdata8(is);
READDATA(is, chSize);
uint64_t nSizeRet = 0; uint64_t nSizeRet = 0;
if (chSize < 253) if (chSize < 253)
{ {
@ -226,25 +282,19 @@ uint64_t ReadCompactSize(Stream& is)
} }
else if (chSize == 253) else if (chSize == 253)
{ {
unsigned short xSize; nSizeRet = ser_readdata16(is);
READDATA(is, xSize);
nSizeRet = xSize;
if (nSizeRet < 253) if (nSizeRet < 253)
throw std::ios_base::failure("non-canonical ReadCompactSize()"); throw std::ios_base::failure("non-canonical ReadCompactSize()");
} }
else if (chSize == 254) else if (chSize == 254)
{ {
unsigned int xSize; nSizeRet = ser_readdata32(is);
READDATA(is, xSize);
nSizeRet = xSize;
if (nSizeRet < 0x10000u) if (nSizeRet < 0x10000u)
throw std::ios_base::failure("non-canonical ReadCompactSize()"); throw std::ios_base::failure("non-canonical ReadCompactSize()");
} }
else else
{ {
uint64_t xSize; nSizeRet = ser_readdata64(is);
READDATA(is, xSize);
nSizeRet = xSize;
if (nSizeRet < 0x100000000ULL) if (nSizeRet < 0x100000000ULL)
throw std::ios_base::failure("non-canonical ReadCompactSize()"); throw std::ios_base::failure("non-canonical ReadCompactSize()");
} }
@ -303,7 +353,7 @@ void WriteVarInt(Stream& os, I n)
len++; len++;
} }
do { do {
WRITEDATA(os, tmp[len]); ser_writedata8(os, tmp[len]);
} while(len--); } while(len--);
} }
@ -312,8 +362,7 @@ I ReadVarInt(Stream& is)
{ {
I n = 0; I n = 0;
while(true) { while(true) {
unsigned char chData; unsigned char chData = ser_readdata8(is);
READDATA(is, chData);
n = (n << 7) | (chData & 0x7F); n = (n << 7) | (chData & 0x7F);
if (chData & 0x80) if (chData & 0x80)
n++; n++;

114
src/test/serialize_tests.cpp

@ -4,6 +4,7 @@
#include "serialize.h" #include "serialize.h"
#include "streams.h" #include "streams.h"
#include "hash.h"
#include <stdint.h> #include <stdint.h>
@ -13,6 +14,119 @@ using namespace std;
BOOST_AUTO_TEST_SUITE(serialize_tests) BOOST_AUTO_TEST_SUITE(serialize_tests)
BOOST_AUTO_TEST_CASE(sizes)
{
BOOST_CHECK_EQUAL(sizeof(char), GetSerializeSize(char(0), 0));
BOOST_CHECK_EQUAL(sizeof(int8_t), GetSerializeSize(int8_t(0), 0));
BOOST_CHECK_EQUAL(sizeof(uint8_t), GetSerializeSize(uint8_t(0), 0));
BOOST_CHECK_EQUAL(sizeof(int16_t), GetSerializeSize(int16_t(0), 0));
BOOST_CHECK_EQUAL(sizeof(uint16_t), GetSerializeSize(uint16_t(0), 0));
BOOST_CHECK_EQUAL(sizeof(int32_t), GetSerializeSize(int32_t(0), 0));
BOOST_CHECK_EQUAL(sizeof(uint32_t), GetSerializeSize(uint32_t(0), 0));
BOOST_CHECK_EQUAL(sizeof(int64_t), GetSerializeSize(int64_t(0), 0));
BOOST_CHECK_EQUAL(sizeof(uint64_t), GetSerializeSize(uint64_t(0), 0));
BOOST_CHECK_EQUAL(sizeof(float), GetSerializeSize(float(0), 0));
BOOST_CHECK_EQUAL(sizeof(double), GetSerializeSize(double(0), 0));
// Bool is serialized as char
BOOST_CHECK_EQUAL(sizeof(char), GetSerializeSize(bool(0), 0));
// Sanity-check GetSerializeSize and c++ type matching
BOOST_CHECK_EQUAL(GetSerializeSize(char(0), 0), 1);
BOOST_CHECK_EQUAL(GetSerializeSize(int8_t(0), 0), 1);
BOOST_CHECK_EQUAL(GetSerializeSize(uint8_t(0), 0), 1);
BOOST_CHECK_EQUAL(GetSerializeSize(int16_t(0), 0), 2);
BOOST_CHECK_EQUAL(GetSerializeSize(uint16_t(0), 0), 2);
BOOST_CHECK_EQUAL(GetSerializeSize(int32_t(0), 0), 4);
BOOST_CHECK_EQUAL(GetSerializeSize(uint32_t(0), 0), 4);
BOOST_CHECK_EQUAL(GetSerializeSize(int64_t(0), 0), 8);
BOOST_CHECK_EQUAL(GetSerializeSize(uint64_t(0), 0), 8);
BOOST_CHECK_EQUAL(GetSerializeSize(float(0), 0), 4);
BOOST_CHECK_EQUAL(GetSerializeSize(double(0), 0), 8);
BOOST_CHECK_EQUAL(GetSerializeSize(bool(0), 0), 1);
}
BOOST_AUTO_TEST_CASE(floats_conversion)
{
// Choose values that map unambigiously to binary floating point to avoid
// rounding issues at the compiler side.
BOOST_CHECK_EQUAL(ser_uint32_to_float(0x00000000), 0.0F);
BOOST_CHECK_EQUAL(ser_uint32_to_float(0x3f000000), 0.5F);
BOOST_CHECK_EQUAL(ser_uint32_to_float(0x3f800000), 1.0F);
BOOST_CHECK_EQUAL(ser_uint32_to_float(0x40000000), 2.0F);
BOOST_CHECK_EQUAL(ser_uint32_to_float(0x40800000), 4.0F);
BOOST_CHECK_EQUAL(ser_uint32_to_float(0x44444444), 785.066650390625F);
BOOST_CHECK_EQUAL(ser_float_to_uint32(0.0F), 0x00000000);
BOOST_CHECK_EQUAL(ser_float_to_uint32(0.5F), 0x3f000000);
BOOST_CHECK_EQUAL(ser_float_to_uint32(1.0F), 0x3f800000);
BOOST_CHECK_EQUAL(ser_float_to_uint32(2.0F), 0x40000000);
BOOST_CHECK_EQUAL(ser_float_to_uint32(4.0F), 0x40800000);
BOOST_CHECK_EQUAL(ser_float_to_uint32(785.066650390625F), 0x44444444);
}
BOOST_AUTO_TEST_CASE(doubles_conversion)
{
// Choose values that map unambigiously to binary floating point to avoid
// rounding issues at the compiler side.
BOOST_CHECK_EQUAL(ser_uint64_to_double(0x0000000000000000ULL), 0.0);
BOOST_CHECK_EQUAL(ser_uint64_to_double(0x3fe0000000000000ULL), 0.5);
BOOST_CHECK_EQUAL(ser_uint64_to_double(0x3ff0000000000000ULL), 1.0);
BOOST_CHECK_EQUAL(ser_uint64_to_double(0x4000000000000000ULL), 2.0);
BOOST_CHECK_EQUAL(ser_uint64_to_double(0x4010000000000000ULL), 4.0);
BOOST_CHECK_EQUAL(ser_uint64_to_double(0x4088888880000000ULL), 785.066650390625);
BOOST_CHECK_EQUAL(ser_double_to_uint64(0.0), 0x0000000000000000ULL);
BOOST_CHECK_EQUAL(ser_double_to_uint64(0.5), 0x3fe0000000000000ULL);
BOOST_CHECK_EQUAL(ser_double_to_uint64(1.0), 0x3ff0000000000000ULL);
BOOST_CHECK_EQUAL(ser_double_to_uint64(2.0), 0x4000000000000000ULL);
BOOST_CHECK_EQUAL(ser_double_to_uint64(4.0), 0x4010000000000000ULL);
BOOST_CHECK_EQUAL(ser_double_to_uint64(785.066650390625), 0x4088888880000000ULL);
}
/*
Python code to generate the below hashes:
def reversed_hex(x):
return binascii.hexlify(''.join(reversed(x)))
def dsha256(x):
return hashlib.sha256(hashlib.sha256(x).digest()).digest()
reversed_hex(dsha256(''.join(struct.pack('<f', x) for x in range(0,1000)))) == '8e8b4cf3e4df8b332057e3e23af42ebc663b61e0495d5e7e32d85099d7f3fe0c'
reversed_hex(dsha256(''.join(struct.pack('<d', x) for x in range(0,1000)))) == '43d0c82591953c4eafe114590d392676a01585d25b25d433557f0d7878b23f96'
*/
BOOST_AUTO_TEST_CASE(floats)
{
CDataStream ss(SER_DISK, 0);
// encode
for (int i = 0; i < 1000; i++) {
ss << float(i);
}
BOOST_CHECK(Hash(ss.begin(), ss.end()) == uint256S("8e8b4cf3e4df8b332057e3e23af42ebc663b61e0495d5e7e32d85099d7f3fe0c"));
// decode
for (int i = 0; i < 1000; i++) {
float j;
ss >> j;
BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
}
}
BOOST_AUTO_TEST_CASE(doubles)
{
CDataStream ss(SER_DISK, 0);
// encode
for (int i = 0; i < 1000; i++) {
ss << double(i);
}
BOOST_CHECK(Hash(ss.begin(), ss.end()) == uint256S("43d0c82591953c4eafe114590d392676a01585d25b25d433557f0d7878b23f96"));
// decode
for (int i = 0; i < 1000; i++) {
double j;
ss >> j;
BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
}
}
BOOST_AUTO_TEST_CASE(varints) BOOST_AUTO_TEST_CASE(varints)
{ {
// encode // encode

4
src/txmempool.cpp

@ -337,7 +337,7 @@ public:
void Write(CAutoFile& fileout) const void Write(CAutoFile& fileout) const
{ {
fileout << nBestSeenHeight; fileout << nBestSeenHeight;
fileout << history.size(); fileout << (uint32_t)history.size();
BOOST_FOREACH(const CBlockAverage& entry, history) BOOST_FOREACH(const CBlockAverage& entry, history)
{ {
entry.Write(fileout); entry.Write(fileout);
@ -348,7 +348,7 @@ public:
{ {
int nFileBestSeenHeight; int nFileBestSeenHeight;
filein >> nFileBestSeenHeight; filein >> nFileBestSeenHeight;
size_t numEntries; uint32_t numEntries;
filein >> numEntries; filein >> numEntries;
if (numEntries <= 0 || numEntries > 10000) if (numEntries <= 0 || numEntries > 10000)
throw runtime_error("Corrupt estimates file. Must have between 1 and 10k entries."); throw runtime_error("Corrupt estimates file. Must have between 1 and 10k entries.");

Loading…
Cancel
Save