diff options
-rw-r--r-- | .travis.yml | 1 | ||||
-rw-r--r-- | configure.ac | 13 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/Makefile.test.include | 1 | ||||
-rw-r--r-- | src/arith_uint256.cpp | 9 | ||||
-rw-r--r-- | src/chainparams.h | 6 | ||||
-rw-r--r-- | src/compat/byteswap.h | 47 | ||||
-rw-r--r-- | src/compat/endian.h | 194 | ||||
-rw-r--r-- | src/crypto/common.h | 76 | ||||
-rw-r--r-- | src/hash.cpp | 6 | ||||
-rw-r--r-- | src/main.cpp | 5 | ||||
-rw-r--r-- | src/net.cpp | 12 | ||||
-rw-r--r-- | src/net.h | 4 | ||||
-rw-r--r-- | src/netbase.h | 2 | ||||
-rw-r--r-- | src/pow.cpp | 7 | ||||
-rw-r--r-- | src/pow.h | 1 | ||||
-rw-r--r-- | src/primitives/block.cpp | 3 | ||||
-rw-r--r-- | src/primitives/transaction.h | 3 | ||||
-rw-r--r-- | src/protocol.cpp | 13 | ||||
-rw-r--r-- | src/protocol.h | 8 | ||||
-rw-r--r-- | src/qt/guiutil.cpp | 46 | ||||
-rw-r--r-- | src/script/script.h | 16 | ||||
-rw-r--r-- | src/serialize.h | 201 | ||||
-rw-r--r-- | src/test/pow_tests.cpp | 66 | ||||
-rw-r--r-- | src/test/serialize_tests.cpp | 114 | ||||
-rw-r--r-- | src/txmempool.cpp | 4 |
26 files changed, 664 insertions, 196 deletions
diff --git a/.travis.yml b/.travis.yml index e08e78dabf..9c18729b42 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ env: global: - MAKEJOBS=-j3 - RUN_TESTS=false + - BOOST_TEST_RANDOM=1$TRAVIS_BUILD_ID - CCACHE_SIZE=100M - CCACHE_TEMPDIR=/tmp/.ccache-temp - CCACHE_COMPRESS=1 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/Makefile.test.include b/src/Makefile.test.include index 90494439fa..6774745de2 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -55,6 +55,7 @@ BITCOIN_TESTS =\ test/multisig_tests.cpp \ test/netbase_tests.cpp \ test/pmt_tests.cpp \ + test/pow_tests.cpp \ test/rpc_tests.cpp \ test/sanity_tests.cpp \ test/script_P2SH_tests.cpp \ 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/chainparams.h b/src/chainparams.h index 86b84df667..78b575d8f3 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -14,8 +14,6 @@ #include <vector> -typedef unsigned char MessageStartChars[MESSAGE_START_SIZE]; - struct CDNSSeedData { std::string name, host; CDNSSeedData(const std::string &strName, const std::string &strHost) : name(strName), host(strHost) {} @@ -42,7 +40,7 @@ public: }; const uint256& HashGenesisBlock() const { return hashGenesisBlock; } - const MessageStartChars& MessageStart() const { return pchMessageStart; } + const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; } const std::vector<unsigned char>& AlertKey() const { return vAlertPubKey; } int GetDefaultPort() const { return nDefaultPort; } const arith_uint256& ProofOfWorkLimit() const { return bnProofOfWorkLimit; } @@ -83,7 +81,7 @@ protected: CChainParams() {} uint256 hashGenesisBlock; - MessageStartChars pchMessageStart; + CMessageHeader::MessageStartChars pchMessageStart; //! Raw pub key bytes for the broadcast alert signing key. std::vector<unsigned char> vAlertPubKey; int nDefaultPort; 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..fdbcfa52fa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4305,7 +4305,7 @@ bool ProcessMessages(CNode* pfrom) // Read header CMessageHeader& hdr = msg.hdr; - if (!hdr.IsValid()) + if (!hdr.IsValid(Params().MessageStart())) { LogPrintf("PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", SanitizeString(hdr.GetCommand()), pfrom->id); continue; @@ -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 3c3666615e..0723ee218a 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> @@ -509,7 +510,7 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes) // get current incomplete message, or create a new one if (vRecvMsg.empty() || vRecvMsg.back().complete()) - vRecvMsg.push_back(CNetMessage(SER_NETWORK, nRecvVersion)); + vRecvMsg.push_back(CNetMessage(Params().MessageStart(), SER_NETWORK, nRecvVersion)); CNetMessage& msg = vRecvMsg.back(); @@ -523,6 +524,11 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes) if (handled < 0) return false; + if (msg.in_data && msg.hdr.nMessageSize > MAX_PROTOCOL_MESSAGE_LENGTH) { + LogPrint("net", "Oversized message from peer=%i, disconnecting", GetId()); + return false; + } + pch += handled; nBytes -= handled; @@ -1970,7 +1976,7 @@ void CNode::BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSen { ENTER_CRITICAL_SECTION(cs_vSend); assert(ssSend.size() == 0); - ssSend << CMessageHeader(pszCommand, 0); + ssSend << CMessageHeader(Params().MessageStart(), pszCommand, 0); LogPrint("net", "sending: %s ", SanitizeString(pszCommand)); } @@ -2002,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()); @@ -46,6 +46,8 @@ static const int TIMEOUT_INTERVAL = 20 * 60; static const unsigned int MAX_INV_SZ = 50000; /** The maximum number of new addresses to accumulate before announcing. */ static const unsigned int MAX_ADDR_TO_SEND = 1000; +/** Maximum length of incoming protocol messages (no message over 2 MiB is currently acceptable). */ +static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 2 * 1024 * 1024; /** -listen default */ static const bool DEFAULT_LISTEN = true; /** -upnp default */ @@ -183,7 +185,7 @@ public: int64_t nTime; // time (in microseconds) of message receipt. - CNetMessage(int nTypeIn, int nVersionIn) : hdrbuf(nTypeIn, nVersionIn), vRecv(nTypeIn, nVersionIn) { + CNetMessage(const CMessageHeader::MessageStartChars& pchMessageStartIn, int nTypeIn, int nVersionIn) : hdrbuf(nTypeIn, nVersionIn), hdr(pchMessageStartIn), vRecv(nTypeIn, nVersionIn) { hdrbuf.resize(24); in_data = false; nHdrPos = 0; 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/pow.cpp b/src/pow.cpp index 6dd5c4c12c..b75b293c90 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -48,8 +48,13 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead pindexFirst = pindexFirst->pprev; assert(pindexFirst); + return CalculateNextWorkRequired(pindexLast, pindexFirst->GetBlockTime()); +} + +unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime) +{ // Limit adjustment step - int64_t nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime(); + int64_t nActualTimespan = pindexLast->GetBlockTime() - nFirstBlockTime; LogPrintf(" nActualTimespan = %d before bounds\n", nActualTimespan); if (nActualTimespan < Params().TargetTimespan()/4) nActualTimespan = Params().TargetTimespan()/4; @@ -14,6 +14,7 @@ class uint256; class arith_uint256; unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock); +unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime); /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ bool CheckProofOfWork(uint256 hash, unsigned int nBits); 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/protocol.cpp b/src/protocol.cpp index 74ac706d60..568580a595 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -5,7 +5,6 @@ #include "protocol.h" -#include "chainparams.h" #include "util.h" #include "utilstrencodings.h" @@ -21,17 +20,17 @@ static const char* ppszTypeName[] = "filtered block" }; -CMessageHeader::CMessageHeader() +CMessageHeader::CMessageHeader(const MessageStartChars& pchMessageStartIn) { - memcpy(pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE); + memcpy(pchMessageStart, pchMessageStartIn, MESSAGE_START_SIZE); memset(pchCommand, 0, sizeof(pchCommand)); nMessageSize = -1; nChecksum = 0; } -CMessageHeader::CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn) +CMessageHeader::CMessageHeader(const MessageStartChars& pchMessageStartIn, const char* pszCommand, unsigned int nMessageSizeIn) { - memcpy(pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE); + memcpy(pchMessageStart, pchMessageStartIn, MESSAGE_START_SIZE); memset(pchCommand, 0, sizeof(pchCommand)); strncpy(pchCommand, pszCommand, COMMAND_SIZE); nMessageSize = nMessageSizeIn; @@ -43,10 +42,10 @@ std::string CMessageHeader::GetCommand() const return std::string(pchCommand, pchCommand + strnlen(pchCommand, COMMAND_SIZE)); } -bool CMessageHeader::IsValid() const +bool CMessageHeader::IsValid(const MessageStartChars& pchMessageStartIn) const { // Check start string - if (memcmp(pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE) != 0) + if (memcmp(pchMessageStart, pchMessageStartIn, MESSAGE_START_SIZE) != 0) return false; // Check the command string for errors diff --git a/src/protocol.h b/src/protocol.h index f8394ce52f..e838c0d363 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -29,11 +29,13 @@ class CMessageHeader { public: - CMessageHeader(); - CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn); + typedef unsigned char MessageStartChars[MESSAGE_START_SIZE]; + + CMessageHeader(const MessageStartChars& pchMessageStartIn); + CMessageHeader(const MessageStartChars& pchMessageStartIn, const char* pszCommand, unsigned int nMessageSizeIn); std::string GetCommand() const; - bool IsValid() const; + bool IsValid(const MessageStartChars& messageStart) const; ADD_SERIALIZE_METHODS; diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 2a13f43ea4..9db0a75971 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -40,6 +40,7 @@ #if BOOST_FILESYSTEM_VERSION >= 3 #include <boost/filesystem/detail/utf8_codecvt_facet.hpp> #endif +#include <boost/scoped_array.hpp> #include <QAbstractItemView> #include <QApplication> @@ -567,12 +568,17 @@ TableViewLastColumnResizingFixer::TableViewLastColumnResizingFixer(QTableView* t #ifdef WIN32 boost::filesystem::path static StartupShortcutPath() { + if (GetBoolArg("-testnet", false)) + return GetSpecialFolderPath(CSIDL_STARTUP) / "Bitcoin (testnet).lnk"; + else if (GetBoolArg("-regtest", false)) + return GetSpecialFolderPath(CSIDL_STARTUP) / "Bitcoin (regtest).lnk"; + return GetSpecialFolderPath(CSIDL_STARTUP) / "Bitcoin.lnk"; } bool GetStartOnSystemStartup() { - // check for Bitcoin.lnk + // check for Bitcoin*.lnk return boost::filesystem::exists(StartupShortcutPath()); } @@ -588,8 +594,8 @@ bool SetStartOnSystemStartup(bool fAutoStart) // Get a pointer to the IShellLink interface. IShellLink* psl = NULL; HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, - CLSCTX_INPROC_SERVER, IID_IShellLink, - reinterpret_cast<void**>(&psl)); + CLSCTX_INPROC_SERVER, IID_IShellLink, + reinterpret_cast<void**>(&psl)); if (SUCCEEDED(hres)) { @@ -597,20 +603,34 @@ bool SetStartOnSystemStartup(bool fAutoStart) TCHAR pszExePath[MAX_PATH]; GetModuleFileName(NULL, pszExePath, sizeof(pszExePath)); - TCHAR pszArgs[5] = TEXT("-min"); + // Start client minimized + QString strArgs = "-min"; + // Set -testnet /-regtest options + strArgs += QString::fromStdString(strprintf(" -testnet=%d -regtest=%d", GetBoolArg("-testnet", false), GetBoolArg("-regtest", false))); + +#ifdef UNICODE + boost::scoped_array<TCHAR> args(new TCHAR[strArgs.length() + 1]); + // Convert the QString to TCHAR* + strArgs.toWCharArray(args.get()); + // Add missing '\0'-termination to string + args[strArgs.length()] = '\0'; +#endif // Set the path to the shortcut target psl->SetPath(pszExePath); PathRemoveFileSpec(pszExePath); psl->SetWorkingDirectory(pszExePath); psl->SetShowCmd(SW_SHOWMINNOACTIVE); - psl->SetArguments(pszArgs); +#ifndef UNICODE + psl->SetArguments(strArgs.toStdString().c_str()); +#else + psl->SetArguments(args.get()); +#endif // Query IShellLink for the IPersistFile interface for // saving the shortcut in persistent storage. IPersistFile* ppf = NULL; - hres = psl->QueryInterface(IID_IPersistFile, - reinterpret_cast<void**>(&ppf)); + hres = psl->QueryInterface(IID_IPersistFile, reinterpret_cast<void**>(&ppf)); if (SUCCEEDED(hres)) { WCHAR pwsz[MAX_PATH]; @@ -630,11 +650,10 @@ bool SetStartOnSystemStartup(bool fAutoStart) } return true; } - #elif defined(Q_OS_LINUX) // Follow the Desktop Application Autostart Spec: -// http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html +// http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html boost::filesystem::path static GetAutostartDir() { @@ -690,8 +709,13 @@ bool SetStartOnSystemStartup(bool fAutoStart) // Write a bitcoin.desktop file to the autostart directory: optionFile << "[Desktop Entry]\n"; optionFile << "Type=Application\n"; - optionFile << "Name=Bitcoin\n"; - optionFile << "Exec=" << pszExePath << " -min\n"; + if (GetBoolArg("-testnet", false)) + optionFile << "Name=Bitcoin (testnet)\n"; + else if (GetBoolArg("-regtest", false)) + optionFile << "Name=Bitcoin (regtest)\n"; + else + optionFile << "Name=Bitcoin\n"; + optionFile << "Exec=" << pszExePath << strprintf(" -min -testnet=%d -regtest=%d\n", GetBoolArg("-testnet", false), GetBoolArg("-regtest", false)); optionFile << "Terminal=false\n"; optionFile << "Hidden=false\n"; optionFile.close(); 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/pow_tests.cpp b/src/test/pow_tests.cpp new file mode 100644 index 0000000000..e42c1b0a8b --- /dev/null +++ b/src/test/pow_tests.cpp @@ -0,0 +1,66 @@ +// Copyright (c) 2015 The Bitcoin Core developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "main.h" +#include "pow.h" +#include "util.h" + +#include <boost/test/unit_test.hpp> + +using namespace std; + +BOOST_AUTO_TEST_SUITE(pow_tests) + +/* Test calculation of next difficulty target with no constraints applying */ +BOOST_AUTO_TEST_CASE(get_next_work) +{ + SelectParams(CBaseChainParams::MAIN); + + int64_t nLastRetargetTime = 1261130161; // Block #30240 + CBlockIndex pindexLast; + pindexLast.nHeight = 32255; + pindexLast.nTime = 1262152739; // Block #32255 + pindexLast.nBits = 0x1d00ffff; + BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime), 0x1d00d86a); +} + +/* Test the constraint on the upper bound for next work */ +BOOST_AUTO_TEST_CASE(get_next_work_pow_limit) +{ + SelectParams(CBaseChainParams::MAIN); + + int64_t nLastRetargetTime = 1231006505; // Block #0 + CBlockIndex pindexLast; + pindexLast.nHeight = 2015; + pindexLast.nTime = 1233061996; // Block #2015 + pindexLast.nBits = 0x1d00ffff; + BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime), 0x1d00ffff); +} + +/* Test the constraint on the lower bound for actual time taken */ +BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual) +{ + SelectParams(CBaseChainParams::MAIN); + + int64_t nLastRetargetTime = 1279008237; // Block #66528 + CBlockIndex pindexLast; + pindexLast.nHeight = 68543; + pindexLast.nTime = 1279297671; // Block #68543 + pindexLast.nBits = 0x1c05a3f4; + BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime), 0x1c0168fd); +} + +/* Test the constraint on the upper bound for actual time taken */ +BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual) +{ + SelectParams(CBaseChainParams::MAIN); + int64_t nLastRetargetTime = 1263163443; // NOTE: Not an actual block time + CBlockIndex pindexLast; + pindexLast.nHeight = 46367; + pindexLast.nTime = 1269211443; // Block #46367 + pindexLast.nBits = 0x1c387f6f; + BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime), 0x1d00e1fd); +} + +BOOST_AUTO_TEST_SUITE_END() 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."); |