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)
This commit is contained in:
Wladimir J. van der Laan 2015-03-06 18:23:45 +01:00
commit 7c3fbc34ae
No known key found for this signature in database
GPG key ID: 74810B012346C9A6
16 changed files with 528 additions and 164 deletions

View file

@ -350,8 +350,8 @@ if test x$use_lcov = xyes; then
[AC_MSG_ERROR("lcov testing requested but --coverage flag does not work")])
fi
dnl Require little endian
AC_C_BIGENDIAN([AC_MSG_ERROR("Big Endian not supported")])
dnl Check for endianness
AC_C_BIGENDIAN
dnl Check for pthread compile/link requirements
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"])
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([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([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
#include <endian.h>
#endif])
AC_CHECK_DECLS([bswap_16, bswap_32, bswap_64],,,
[#if HAVE_BYTESWAP_H
#include <byteswap.h>
#endif])
dnl Check for MSG_NOSIGNAL
AC_MSG_CHECKING(for MSG_NOSIGNAL)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/socket.h>]],

View file

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

View file

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

47
src/compat/byteswap.h Normal file
View file

@ -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 Normal file
View file

@ -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

View file

@ -11,110 +11,56 @@
#include <stdint.h>
#if defined(HAVE_ENDIAN_H)
#include <endian.h>
#endif
#include "compat/endian.h"
uint16_t static inline ReadLE16(const unsigned char* ptr)
{
return le16toh(*((uint16_t*)ptr));
}
uint32_t static inline ReadLE32(const unsigned char* ptr)
{
#if HAVE_DECL_LE32TOH == 1
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)
{
#if HAVE_DECL_LE64TOH == 1
return le64toh(*((uint64_t*)ptr));
#elif !defined(WORDS_BIGENDIAN)
return *((uint64_t*)ptr);
#else
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]);
#endif
}
void static inline WriteLE16(unsigned char* ptr, uint16_t x)
{
*((uint16_t*)ptr) = htole16(x);
}
void static inline WriteLE32(unsigned char* ptr, uint32_t x)
{
#if HAVE_DECL_HTOLE32 == 1
*((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)
{
#if HAVE_DECL_HTOLE64 == 1
*((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)
{
#if HAVE_DECL_BE32TOH == 1
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)
{
#if HAVE_DECL_BE64TOH == 1
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)
{
#if HAVE_DECL_HTOBE32 == 1
*((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)
{
#if HAVE_DECL_HTOBE64 == 1
*((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

View file

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

View file

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

View file

@ -14,6 +14,7 @@
#include "clientversion.h"
#include "primitives/transaction.h"
#include "ui_interface.h"
#include "crypto/common.h"
#ifdef WIN32
#include <string.h>
@ -2007,7 +2008,7 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend)
// Set the 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
uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end());

View file

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

View file

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

View file

@ -25,7 +25,8 @@ public:
template <typename Stream, typename Operation>
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; }

View file

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

View file

@ -18,6 +18,8 @@
#include <utility>
#include <vector>
#include "compat/endian.h"
class CScript;
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());
}
/*
* 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,
@ -108,59 +183,48 @@ enum
SerializationOp(s, CSerActionUnserialize(), nType, nVersion); \
}
/*
* Basic Types
*/
#define WRITEDATA(s, obj) s.write((char*)&(obj), sizeof(obj))
#define READDATA(s, obj) s.read((char*)&(obj), sizeof(obj))
inline unsigned int GetSerializeSize(char a, int, int=0) { return 1; }
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(int16_t a, int, int=0) { return 2; }
inline unsigned int GetSerializeSize(uint16_t a, int, int=0) { return 2; }
inline unsigned int GetSerializeSize(int32_t a, int, int=0) { return 4; }
inline unsigned int GetSerializeSize(uint32_t a, int, int=0) { return 4; }
inline unsigned int GetSerializeSize(int64_t a, int, int=0) { return 8; }
inline unsigned int GetSerializeSize(uint64_t a, int, int=0) { return 8; }
inline unsigned int GetSerializeSize(float a, int, int=0) { return 4; }
inline unsigned int GetSerializeSize(double a, int, int=0) { return 8; }
inline unsigned int GetSerializeSize(char a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(signed char a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(unsigned char a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(signed short a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(unsigned short a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(signed int a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(unsigned int a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(signed long a, int, int=0) { return sizeof(a); }
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); }
inline unsigned int GetSerializeSize(unsigned long long a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(float a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(double 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
template<typename Stream> inline void Serialize(Stream& s, int8_t a, int, int=0) { ser_writedata8(s, a); }
template<typename Stream> inline void Serialize(Stream& s, uint8_t a, int, int=0) { ser_writedata8(s, 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, int32_t a, int, int=0) { ser_writedata32(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, int64_t a, int, int=0) { ser_writedata64(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, float a, int, int=0) { ser_writedata32(s, ser_float_to_uint32(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, char a, int, int=0) { WRITEDATA(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, unsigned char a, int, int=0) { WRITEDATA(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, unsigned short a, int, int=0) { WRITEDATA(s, 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, 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 Serialize(Stream& s, unsigned long a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, signed long long a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, unsigned long long a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, float a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, double a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, char& a, int, int=0) { READDATA(s, a); }
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, unsigned char& a, int, int=0) { READDATA(s, a); }
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, 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); }
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 Unserialize(Stream& s, int8_t& a, int, int=0) { a = ser_readdata8(s); }
template<typename Stream> inline void Unserialize(Stream& s, uint8_t& a, int, int=0) { a = ser_readdata8(s); }
template<typename Stream> inline void Unserialize(Stream& s, int16_t& a, int, int=0) { a = ser_readdata16(s); }
template<typename Stream> inline void Unserialize(Stream& s, uint16_t& a, int, int=0) { a = ser_readdata16(s); }
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, int64_t& a, int, int=0) { a = ser_readdata64(s); }
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, float& a, int, int=0) { a = ser_uint32_to_float(ser_readdata32(s)); }
template<typename Stream> inline void Unserialize(Stream& s, double& a, int, int=0) { a = ser_uint64_to_double(ser_readdata64(s)); }
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 Unserialize(Stream& s, bool& a, int, int=0) { char f; READDATA(s, f); a=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=ser_readdata8(s); a=f; }
@ -187,29 +251,22 @@ void WriteCompactSize(Stream& os, uint64_t nSize)
{
if (nSize < 253)
{
unsigned char chSize = nSize;
WRITEDATA(os, chSize);
ser_writedata8(os, nSize);
}
else if (nSize <= std::numeric_limits<unsigned short>::max())
{
unsigned char chSize = 253;
unsigned short xSize = nSize;
WRITEDATA(os, chSize);
WRITEDATA(os, xSize);
ser_writedata8(os, 253);
ser_writedata16(os, nSize);
}
else if (nSize <= std::numeric_limits<unsigned int>::max())
{
unsigned char chSize = 254;
unsigned int xSize = nSize;
WRITEDATA(os, chSize);
WRITEDATA(os, xSize);
ser_writedata8(os, 254);
ser_writedata32(os, nSize);
}
else
{
unsigned char chSize = 255;
uint64_t xSize = nSize;
WRITEDATA(os, chSize);
WRITEDATA(os, xSize);
ser_writedata8(os, 255);
ser_writedata64(os, nSize);
}
return;
}
@ -217,8 +274,7 @@ void WriteCompactSize(Stream& os, uint64_t nSize)
template<typename Stream>
uint64_t ReadCompactSize(Stream& is)
{
unsigned char chSize;
READDATA(is, chSize);
uint8_t chSize = ser_readdata8(is);
uint64_t nSizeRet = 0;
if (chSize < 253)
{
@ -226,25 +282,19 @@ uint64_t ReadCompactSize(Stream& is)
}
else if (chSize == 253)
{
unsigned short xSize;
READDATA(is, xSize);
nSizeRet = xSize;
nSizeRet = ser_readdata16(is);
if (nSizeRet < 253)
throw std::ios_base::failure("non-canonical ReadCompactSize()");
}
else if (chSize == 254)
{
unsigned int xSize;
READDATA(is, xSize);
nSizeRet = xSize;
nSizeRet = ser_readdata32(is);
if (nSizeRet < 0x10000u)
throw std::ios_base::failure("non-canonical ReadCompactSize()");
}
else
{
uint64_t xSize;
READDATA(is, xSize);
nSizeRet = xSize;
nSizeRet = ser_readdata64(is);
if (nSizeRet < 0x100000000ULL)
throw std::ios_base::failure("non-canonical ReadCompactSize()");
}
@ -303,7 +353,7 @@ void WriteVarInt(Stream& os, I n)
len++;
}
do {
WRITEDATA(os, tmp[len]);
ser_writedata8(os, tmp[len]);
} while(len--);
}
@ -312,8 +362,7 @@ I ReadVarInt(Stream& is)
{
I n = 0;
while(true) {
unsigned char chData;
READDATA(is, chData);
unsigned char chData = ser_readdata8(is);
n = (n << 7) | (chData & 0x7F);
if (chData & 0x80)
n++;

View file

@ -4,6 +4,7 @@
#include "serialize.h"
#include "streams.h"
#include "hash.h"
#include <stdint.h>
@ -13,6 +14,119 @@ using namespace std;
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)
{
// encode

View file

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