aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac13
-rw-r--r--src/Makefile.am2
-rw-r--r--src/arith_uint256.cpp9
-rw-r--r--src/compat/byteswap.h47
-rw-r--r--src/compat/endian.h194
-rw-r--r--src/crypto/common.h76
-rw-r--r--src/hash.cpp6
-rw-r--r--src/main.cpp3
-rw-r--r--src/net.cpp3
-rw-r--r--src/netbase.h2
-rw-r--r--src/primitives/block.cpp3
-rw-r--r--src/primitives/transaction.h3
-rw-r--r--src/script/script.h16
-rw-r--r--src/serialize.h201
-rw-r--r--src/test/serialize_tests.cpp114
-rw-r--r--src/txmempool.cpp4
16 files changed, 530 insertions, 166 deletions
diff --git a/configure.ac b/configure.ac
index f5bc1e3122..2c918218bb 100644
--- a/configure.ac
+++ b/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")])
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>]],
diff --git a/src/Makefile.am b/src/Makefile.am
index e1d467ff85..da65efa713 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -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 = \
diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp
index 1243823da5..2e61363576 100644
--- a/src/arith_uint256.cpp
+++ b/src/arith_uint256.cpp
@@ -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;
}
diff --git a/src/compat/byteswap.h b/src/compat/byteswap.h
new file mode 100644
index 0000000000..899220bdc5
--- /dev/null
+++ b/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
diff --git a/src/compat/endian.h b/src/compat/endian.h
new file mode 100644
index 0000000000..4d041d6554
--- /dev/null
+++ b/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
diff --git a/src/crypto/common.h b/src/crypto/common.h
index 8b04b1f728..580c72f5a6 100644
--- a/src/crypto/common.h
+++ b/src/crypto/common.h
@@ -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
diff --git a/src/hash.cpp b/src/hash.cpp
index a7eb5a2a0b..20d5d21777 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -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);
diff --git a/src/main.cpp b/src/main.cpp
index b6a61f7da1..9927ac7598 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -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",
diff --git a/src/net.cpp b/src/net.cpp
index d9f470b9e4..08d1d57408 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -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());
diff --git a/src/netbase.h b/src/netbase.h
index 5bf13a673f..b42c2dffa4 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -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);
}
diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp
index 3b4a360395..5b9c13d870 100644
--- a/src/primitives/block.cpp
+++ b/src/primitives/block.cpp
@@ -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
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 1b5a47e0da..0ba9affeda 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -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; }
diff --git a/src/script/script.h b/src/script/script.h
index 8b36aa2f50..ed456f5c5a 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -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)
diff --git a/src/serialize.h b/src/serialize.h
index a62760a793..741f78f8b4 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -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 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) { 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); }
+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; }
+
+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 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++;
diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp
index fe49af711b..de9510d54a 100644
--- a/src/test/serialize_tests.cpp
+++ b/src/test/serialize_tests.cpp
@@ -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
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 6e0f7e9c5a..0d50660327 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -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.");