From d1e26d4e71460ffd50c3190385c759b48ab343e9 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 20 Aug 2014 13:53:42 +0200 Subject: [PATCH 01/10] Move CMedianFilter to timedata.cpp Now that we no longer use the median filter to keep track of the number of blocks of peers, that's the only place it is used. --- src/Makefile.test.include | 1 + src/test/timedata_tests.cpp | 38 ++++++++++++++++++++++++ src/test/util_tests.cpp | 25 ---------------- src/timedata.h | 59 +++++++++++++++++++++++++++++++++++++ src/util.h | 56 ----------------------------------- 5 files changed, 98 insertions(+), 81 deletions(-) create mode 100644 src/test/timedata_tests.cpp diff --git a/src/Makefile.test.include b/src/Makefile.test.include index cc407f679f1..b4360831bb5 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -61,6 +61,7 @@ BITCOIN_TESTS =\ test/sigopcount_tests.cpp \ test/skiplist_tests.cpp \ test/test_bitcoin.cpp \ + test/timedata_tests.cpp \ test/transaction_tests.cpp \ test/uint256_tests.cpp \ test/univalue_tests.cpp \ diff --git a/src/test/timedata_tests.cpp b/src/test/timedata_tests.cpp new file mode 100644 index 00000000000..aa4fa0d500e --- /dev/null +++ b/src/test/timedata_tests.cpp @@ -0,0 +1,38 @@ +// Copyright (c) 2011-2014 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 "timedata.h" + +#include + +using namespace std; + +BOOST_AUTO_TEST_SUITE(timedata_tests) + +BOOST_AUTO_TEST_CASE(util_MedianFilter) +{ + CMedianFilter filter(5, 15); + + BOOST_CHECK_EQUAL(filter.median(), 15); + + filter.input(20); // [15 20] + BOOST_CHECK_EQUAL(filter.median(), 17); + + filter.input(30); // [15 20 30] + BOOST_CHECK_EQUAL(filter.median(), 20); + + filter.input(3); // [3 15 20 30] + BOOST_CHECK_EQUAL(filter.median(), 17); + + filter.input(7); // [3 7 15 20 30] + BOOST_CHECK_EQUAL(filter.median(), 15); + + filter.input(18); // [3 7 18 20 30] + BOOST_CHECK_EQUAL(filter.median(), 18); + + filter.input(0); // [0 3 7 18 30] + BOOST_CHECK_EQUAL(filter.median(), 7); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 068b9f29c81..31fcd3e92a4 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -36,31 +36,6 @@ BOOST_AUTO_TEST_CASE(util_criticalsection) } while(0); } -BOOST_AUTO_TEST_CASE(util_MedianFilter) -{ - CMedianFilter filter(5, 15); - - BOOST_CHECK_EQUAL(filter.median(), 15); - - filter.input(20); // [15 20] - BOOST_CHECK_EQUAL(filter.median(), 17); - - filter.input(30); // [15 20 30] - BOOST_CHECK_EQUAL(filter.median(), 20); - - filter.input(3); // [3 15 20 30] - BOOST_CHECK_EQUAL(filter.median(), 17); - - filter.input(7); // [3 7 15 20 30] - BOOST_CHECK_EQUAL(filter.median(), 15); - - filter.input(18); // [3 7 18 20 30] - BOOST_CHECK_EQUAL(filter.median(), 18); - - filter.input(0); // [0 3 7 18 30] - BOOST_CHECK_EQUAL(filter.median(), 7); -} - static const unsigned char ParseHex_expected[65] = { 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, diff --git a/src/timedata.h b/src/timedata.h index 0e7bdc2c1f0..d0c84b3183b 100644 --- a/src/timedata.h +++ b/src/timedata.h @@ -6,9 +6,68 @@ #define BITCOIN_TIMEDATA_H #include +#include +#include +#include class CNetAddr; +/** Median filter over a stream of values. + * Returns the median of the last N numbers + */ +template class CMedianFilter +{ +private: + std::vector vValues; + std::vector vSorted; + unsigned int nSize; +public: + CMedianFilter(unsigned int size, T initial_value): + nSize(size) + { + vValues.reserve(size); + vValues.push_back(initial_value); + vSorted = vValues; + } + + void input(T value) + { + if(vValues.size() == nSize) + { + vValues.erase(vValues.begin()); + } + vValues.push_back(value); + + vSorted.resize(vValues.size()); + std::copy(vValues.begin(), vValues.end(), vSorted.begin()); + std::sort(vSorted.begin(), vSorted.end()); + } + + T median() const + { + int size = vSorted.size(); + assert(size>0); + if(size & 1) // Odd number of elements + { + return vSorted[size/2]; + } + else // Even number of elements + { + return (vSorted[size/2-1] + vSorted[size/2]) / 2; + } + } + + int size() const + { + return vValues.size(); + } + + std::vector sorted () const + { + return vSorted; + } +}; + /* Functions to keep track of adjusted P2P time */ int64_t GetTimeOffset(); int64_t GetAdjustedTime(); diff --git a/src/util.h b/src/util.h index 1fb42a7b7ee..e813c86804c 100644 --- a/src/util.h +++ b/src/util.h @@ -356,62 +356,6 @@ bool TimingResistantEqual(const T& a, const T& b) return accumulator == 0; } -/** Median filter over a stream of values. - * Returns the median of the last N numbers - */ -template class CMedianFilter -{ -private: - std::vector vValues; - std::vector vSorted; - unsigned int nSize; -public: - CMedianFilter(unsigned int size, T initial_value): - nSize(size) - { - vValues.reserve(size); - vValues.push_back(initial_value); - vSorted = vValues; - } - - void input(T value) - { - if(vValues.size() == nSize) - { - vValues.erase(vValues.begin()); - } - vValues.push_back(value); - - vSorted.resize(vValues.size()); - std::copy(vValues.begin(), vValues.end(), vSorted.begin()); - std::sort(vSorted.begin(), vSorted.end()); - } - - T median() const - { - int size = vSorted.size(); - assert(size>0); - if(size & 1) // Odd number of elements - { - return vSorted[size/2]; - } - else // Even number of elements - { - return (vSorted[size/2-1] + vSorted[size/2]) / 2; - } - } - - int size() const - { - return vValues.size(); - } - - std::vector sorted () const - { - return vSorted; - } -}; - #ifdef WIN32 inline void SetThreadPriority(int nPriority) { From 121d6ad9dbedd6a13b12d75a4c48505797d8de9d Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 20 Aug 2014 16:32:14 +0200 Subject: [PATCH 02/10] Remove unused `alignup` function from util.h --- src/util.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/util.h b/src/util.h index e813c86804c..10fc5dd58e6 100644 --- a/src/util.h +++ b/src/util.h @@ -46,20 +46,6 @@ static const int64_t CENT = 1000000; // This is needed because the foreach macro can't get over the comma in pair #define PAIRTYPE(t1, t2) std::pair -// Align by increasing pointer, must have extra space at end of buffer -template -T* alignup(T* p) -{ - union - { - T* ptr; - size_t n; - } u; - u.ptr = p; - u.n = (u.n + (nBytes-1)) & ~(nBytes-1); - return u.ptr; -} - #ifdef WIN32 #define MSG_DONTWAIT 0 From f780e65ac632d2cad51d00c2b4a93248a5df91a6 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 20 Aug 2014 16:59:00 +0200 Subject: [PATCH 03/10] Remove unused function `ByteReverse` from util.h --- src/util.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/util.h b/src/util.h index 10fc5dd58e6..785d4056e74 100644 --- a/src/util.h +++ b/src/util.h @@ -372,12 +372,6 @@ inline void SetThreadPriority(int nPriority) void RenameThread(const char* name); -inline uint32_t ByteReverse(uint32_t value) -{ - value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8); - return (value<<16) | (value>>16); -} - // Standard wrapper for do-something-forever thread functions. // "Forever" really means until the thread is interrupted. // Use it like: From 610a8c075958aa95b97f62a7ab020a543694c23d Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 20 Aug 2014 17:43:56 +0200 Subject: [PATCH 04/10] Move SetThreadPriority implementation to util.cpp instead of the header Put the THREAD_* and PRIO_ constants in compat.h. --- src/compat.h | 11 +++++++++++ src/util.cpp | 13 +++++++++++++ src/util.h | 29 +---------------------------- 3 files changed, 25 insertions(+), 28 deletions(-) diff --git a/src/compat.h b/src/compat.h index 52c7817130f..3f0a8b6158c 100644 --- a/src/compat.h +++ b/src/compat.h @@ -59,4 +59,15 @@ typedef u_int SOCKET; #define SOCKET_ERROR -1 #endif +#ifndef WIN32 +// PRIO_MAX is not defined on Solaris +#ifndef PRIO_MAX +#define PRIO_MAX 20 +#endif +#define THREAD_PRIORITY_LOWEST PRIO_MAX +#define THREAD_PRIORITY_BELOW_NORMAL 2 +#define THREAD_PRIORITY_NORMAL 0 +#define THREAD_PRIORITY_ABOVE_NORMAL (-2) +#endif + #endif // _BITCOIN_COMPAT_H diff --git a/src/util.cpp b/src/util.cpp index ae2145a3a0b..606f5a60f95 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1286,3 +1286,16 @@ std::string FormatParagraph(const std::string in, size_t width, size_t indent) } return out.str(); } + +void SetThreadPriority(int nPriority) +{ +#ifdef WIN32 + SetThreadPriority(GetCurrentThread(), nPriority); +#else // WIN32 +#ifdef PRIO_THREAD + setpriority(PRIO_THREAD, 0, nPriority); +#else // PRIO_THREAD + setpriority(PRIO_PROCESS, 0, nPriority); +#endif // PRIO_THREAD +#endif // WIN32 +} diff --git a/src/util.h b/src/util.h index 785d4056e74..939e59c3013 100644 --- a/src/util.h +++ b/src/util.h @@ -342,34 +342,7 @@ bool TimingResistantEqual(const T& a, const T& b) return accumulator == 0; } -#ifdef WIN32 -inline void SetThreadPriority(int nPriority) -{ - SetThreadPriority(GetCurrentThread(), nPriority); -} -#else - -// PRIO_MAX is not defined on Solaris -#ifndef PRIO_MAX -#define PRIO_MAX 20 -#endif -#define THREAD_PRIORITY_LOWEST PRIO_MAX -#define THREAD_PRIORITY_BELOW_NORMAL 2 -#define THREAD_PRIORITY_NORMAL 0 -#define THREAD_PRIORITY_ABOVE_NORMAL (-2) - -inline void SetThreadPriority(int nPriority) -{ - // It's unclear if it's even possible to change thread priorities on Linux, - // but we really and truly need it for the generation threads. -#ifdef PRIO_THREAD - setpriority(PRIO_THREAD, 0, nPriority); -#else - setpriority(PRIO_PROCESS, 0, nPriority); -#endif -} -#endif - +void SetThreadPriority(int nPriority); void RenameThread(const char* name); // Standard wrapper for do-something-forever thread functions. From 651480c8e453e7df9d735f684e6a3e368c777ac0 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 21 Aug 2014 05:17:21 +0200 Subject: [PATCH 05/10] move functions in main and net to implementation files --- src/main.cpp | 61 ++++++++++++++++++++ src/main.h | 64 +-------------------- src/net.cpp | 154 +++++++++++++++++++++++++++++++++++++++++++++++++ src/net.h | 158 +++------------------------------------------------ 4 files changed, 226 insertions(+), 211 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 947494ce625..d9f897f4477 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4655,7 +4655,68 @@ bool SendMessages(CNode* pto, bool fSendTrickle) } +bool CBlockUndo::WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock) +{ + // Open history file to append + CAutoFile fileout = CAutoFile(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION); + if (!fileout) + return error("CBlockUndo::WriteToDisk : OpenUndoFile failed"); + // Write index header + unsigned int nSize = fileout.GetSerializeSize(*this); + fileout << FLATDATA(Params().MessageStart()) << nSize; + + // Write undo data + long fileOutPos = ftell(fileout); + if (fileOutPos < 0) + return error("CBlockUndo::WriteToDisk : ftell failed"); + pos.nPos = (unsigned int)fileOutPos; + fileout << *this; + + // calculate & write checksum + CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); + hasher << hashBlock; + hasher << *this; + fileout << hasher.GetHash(); + + // Flush stdio buffers and commit to disk before returning + fflush(fileout); + if (!IsInitialBlockDownload()) + FileCommit(fileout); + + return true; +} + +bool CBlockUndo::ReadFromDisk(const CDiskBlockPos &pos, const uint256 &hashBlock) +{ + // Open history file to read + CAutoFile filein = CAutoFile(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION); + if (!filein) + return error("CBlockUndo::ReadFromDisk : OpenBlockFile failed"); + + // Read block + uint256 hashChecksum; + try { + filein >> *this; + filein >> hashChecksum; + } + catch (std::exception &e) { + return error("%s : Deserialize or I/O error - %s", __func__, e.what()); + } + + // Verify checksum + CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); + hasher << hashBlock; + hasher << *this; + if (hashChecksum != hasher.GetHash()) + return error("CBlockUndo::ReadFromDisk : Checksum mismatch"); + + return true; +} + + std::string CBlockFileInfo::ToString() const { + return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst).c_str(), DateTimeStrFormat("%Y-%m-%d", nTimeLast).c_str()); + } diff --git a/src/main.h b/src/main.h index 886cac1507c..0db631f6d62 100644 --- a/src/main.h +++ b/src/main.h @@ -312,64 +312,8 @@ public: READWRITE(vtxundo); ) - bool WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock) - { - // Open history file to append - CAutoFile fileout = CAutoFile(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION); - if (!fileout) - return error("CBlockUndo::WriteToDisk : OpenUndoFile failed"); - - // Write index header - unsigned int nSize = fileout.GetSerializeSize(*this); - fileout << FLATDATA(Params().MessageStart()) << nSize; - - // Write undo data - long fileOutPos = ftell(fileout); - if (fileOutPos < 0) - return error("CBlockUndo::WriteToDisk : ftell failed"); - pos.nPos = (unsigned int)fileOutPos; - fileout << *this; - - // calculate & write checksum - CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); - hasher << hashBlock; - hasher << *this; - fileout << hasher.GetHash(); - - // Flush stdio buffers and commit to disk before returning - fflush(fileout); - if (!IsInitialBlockDownload()) - FileCommit(fileout); - - return true; - } - - bool ReadFromDisk(const CDiskBlockPos &pos, const uint256 &hashBlock) - { - // Open history file to read - CAutoFile filein = CAutoFile(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION); - if (!filein) - return error("CBlockUndo::ReadFromDisk : OpenBlockFile failed"); - - // Read block - uint256 hashChecksum; - try { - filein >> *this; - filein >> hashChecksum; - } - catch (std::exception &e) { - return error("%s : Deserialize or I/O error - %s", __func__, e.what()); - } - - // Verify checksum - CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); - hasher << hashBlock; - hasher << *this; - if (hashChecksum != hasher.GetHash()) - return error("CBlockUndo::ReadFromDisk : Checksum mismatch"); - - return true; - } + bool WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock); + bool ReadFromDisk(const CDiskBlockPos &pos, const uint256 &hashBlock); }; @@ -625,9 +569,7 @@ public: SetNull(); } - std::string ToString() const { - return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst).c_str(), DateTimeStrFormat("%Y-%m-%d", nTimeLast).c_str()); - } + std::string ToString() const; // update statistics (does not update nSize) void AddBlock(unsigned int nHeightIn, uint64_t nTimeIn) { diff --git a/src/net.cpp b/src/net.cpp index cae9b70da71..440c271a5e9 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2037,3 +2037,157 @@ bool CAddrDB::Read(CAddrMan& addr) return true; } + +unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); } +unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); } + +CNode::CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), setAddrKnown(5000) +{ + nServices = 0; + hSocket = hSocketIn; + nRecvVersion = INIT_PROTO_VERSION; + nLastSend = 0; + nLastRecv = 0; + nSendBytes = 0; + nRecvBytes = 0; + nTimeConnected = GetTime(); + addr = addrIn; + addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; + nVersion = 0; + strSubVer = ""; + fWhitelisted = false; + fOneShot = false; + fClient = false; // set by version message + fInbound = fInboundIn; + fNetworkNode = false; + fSuccessfullyConnected = false; + fDisconnect = false; + nRefCount = 0; + nSendSize = 0; + nSendOffset = 0; + hashContinue = 0; + pindexLastGetBlocksBegin = 0; + hashLastGetBlocksEnd = 0; + nStartingHeight = -1; + fStartSync = false; + fGetAddr = false; + fRelayTxes = false; + setInventoryKnown.max_size(SendBufferSize() / 1000); + pfilter = new CBloomFilter(); + nPingNonceSent = 0; + nPingUsecStart = 0; + nPingUsecTime = 0; + fPingQueued = false; + + { + LOCK(cs_nLastNodeId); + id = nLastNodeId++; + } + + if (fLogIPs) + LogPrint("net", "Added connection to %s peer=%d\n", addrName, id); + else + LogPrint("net", "Added connection peer=%d\n", id); + + // Be shy and don't send version until we hear + if (hSocket != INVALID_SOCKET && !fInbound) + PushVersion(); + + GetNodeSignals().InitializeNode(GetId(), this); +} + +CNode::~CNode() +{ + CloseSocket(hSocket); + + if (pfilter) + delete pfilter; + + GetNodeSignals().FinalizeNode(GetId()); +} + +void CNode::AskFor(const CInv& inv) +{ + // We're using mapAskFor as a priority queue, + // the key is the earliest time the request can be sent + int64_t nRequestTime; + limitedmap::const_iterator it = mapAlreadyAskedFor.find(inv); + if (it != mapAlreadyAskedFor.end()) + nRequestTime = it->second; + else + nRequestTime = 0; + LogPrint("net", "askfor %s %d (%s) peer=%d\n", inv.ToString(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000).c_str(), id); + + // Make sure not to reuse time indexes to keep things in the same order + int64_t nNow = GetTimeMicros() - 1000000; + static int64_t nLastTime; + ++nLastTime; + nNow = std::max(nNow, nLastTime); + nLastTime = nNow; + + // Each retry is 2 minutes after the last + nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow); + if (it != mapAlreadyAskedFor.end()) + mapAlreadyAskedFor.update(it, nRequestTime); + else + mapAlreadyAskedFor.insert(std::make_pair(inv, nRequestTime)); + mapAskFor.insert(std::make_pair(nRequestTime, inv)); +} + +void CNode::BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend) +{ + ENTER_CRITICAL_SECTION(cs_vSend); + assert(ssSend.size() == 0); + ssSend << CMessageHeader(pszCommand, 0); + LogPrint("net", "sending: %s ", pszCommand); +} + +void CNode::AbortMessage() UNLOCK_FUNCTION(cs_vSend) +{ + ssSend.clear(); + + LEAVE_CRITICAL_SECTION(cs_vSend); + + LogPrint("net", "(aborted)\n"); +} + +void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend) +{ + // The -*messagestest options are intentionally not documented in the help message, + // since they are only used during development to debug the networking code and are + // not intended for end-users. + if (mapArgs.count("-dropmessagestest") && GetRand(GetArg("-dropmessagestest", 2)) == 0) + { + LogPrint("net", "dropmessages DROPPING SEND MESSAGE\n"); + AbortMessage(); + return; + } + if (mapArgs.count("-fuzzmessagestest")) + Fuzz(GetArg("-fuzzmessagestest", 10)); + + if (ssSend.size() == 0) + return; + + // Set the size + unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE; + memcpy((char*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], &nSize, sizeof(nSize)); + + // Set the checksum + uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end()); + unsigned int nChecksum = 0; + memcpy(&nChecksum, &hash, sizeof(nChecksum)); + assert(ssSend.size () >= CMessageHeader::CHECKSUM_OFFSET + sizeof(nChecksum)); + memcpy((char*)&ssSend[CMessageHeader::CHECKSUM_OFFSET], &nChecksum, sizeof(nChecksum)); + + LogPrint("net", "(%d bytes) peer=%d\n", nSize, id); + + std::deque::iterator it = vSendMsg.insert(vSendMsg.end(), CSerializeData()); + ssSend.GetAndClear(*it); + nSendSize += (*it).size(); + + // If write queue empty, attempt "optimistic write" + if (it == vSendMsg.begin()) + SocketSendData(this); + + LEAVE_CRITICAL_SECTION(cs_vSend); +} diff --git a/src/net.h b/src/net.h index 1a7b3c00b89..2b4732c9dee 100644 --- a/src/net.h +++ b/src/net.h @@ -51,8 +51,8 @@ static const bool DEFAULT_UPNP = USE_UPNP; static const bool DEFAULT_UPNP = false; #endif -inline unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); } -inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); } +unsigned int ReceiveFloodSize(); +unsigned int SendBufferSize(); void AddOneShot(std::string strDest); bool RecvLine(SOCKET hSocket, std::string& strLine); @@ -300,70 +300,8 @@ public: // Whether a ping is requested. bool fPingQueued; - CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), setAddrKnown(5000) - { - nServices = 0; - hSocket = hSocketIn; - nRecvVersion = INIT_PROTO_VERSION; - nLastSend = 0; - nLastRecv = 0; - nSendBytes = 0; - nRecvBytes = 0; - nTimeConnected = GetTime(); - addr = addrIn; - addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; - nVersion = 0; - strSubVer = ""; - fWhitelisted = false; - fOneShot = false; - fClient = false; // set by version message - fInbound = fInboundIn; - fNetworkNode = false; - fSuccessfullyConnected = false; - fDisconnect = false; - nRefCount = 0; - nSendSize = 0; - nSendOffset = 0; - hashContinue = 0; - pindexLastGetBlocksBegin = 0; - hashLastGetBlocksEnd = 0; - nStartingHeight = -1; - fStartSync = false; - fGetAddr = false; - fRelayTxes = false; - setInventoryKnown.max_size(SendBufferSize() / 1000); - pfilter = new CBloomFilter(); - nPingNonceSent = 0; - nPingUsecStart = 0; - nPingUsecTime = 0; - fPingQueued = false; - - { - LOCK(cs_nLastNodeId); - id = nLastNodeId++; - } - - if (fLogIPs) - LogPrint("net", "Added connection to %s peer=%d\n", addrName, id); - else - LogPrint("net", "Added connection peer=%d\n", id); - - // Be shy and don't send version until we hear - if (hSocket != INVALID_SOCKET && !fInbound) - PushVersion(); - - GetNodeSignals().InitializeNode(GetId(), this); - } - - ~CNode() - { - CloseSocket(hSocket); - - if (pfilter) - delete pfilter; - - GetNodeSignals().FinalizeNode(GetId()); - } + CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false); + ~CNode(); private: // Network usage totals @@ -452,96 +390,16 @@ public: } } - void AskFor(const CInv& inv) - { - // We're using mapAskFor as a priority queue, - // the key is the earliest time the request can be sent - int64_t nRequestTime; - limitedmap::const_iterator it = mapAlreadyAskedFor.find(inv); - if (it != mapAlreadyAskedFor.end()) - nRequestTime = it->second; - else - nRequestTime = 0; - LogPrint("net", "askfor %s %d (%s) peer=%d\n", inv.ToString(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000).c_str(), id); - - // Make sure not to reuse time indexes to keep things in the same order - int64_t nNow = GetTimeMicros() - 1000000; - static int64_t nLastTime; - ++nLastTime; - nNow = std::max(nNow, nLastTime); - nLastTime = nNow; - - // Each retry is 2 minutes after the last - nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow); - if (it != mapAlreadyAskedFor.end()) - mapAlreadyAskedFor.update(it, nRequestTime); - else - mapAlreadyAskedFor.insert(std::make_pair(inv, nRequestTime)); - mapAskFor.insert(std::make_pair(nRequestTime, inv)); - } - - + void AskFor(const CInv& inv); // TODO: Document the postcondition of this function. Is cs_vSend locked? - void BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend) - { - ENTER_CRITICAL_SECTION(cs_vSend); - assert(ssSend.size() == 0); - ssSend << CMessageHeader(pszCommand, 0); - LogPrint("net", "sending: %s ", pszCommand); - } + void BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend); // TODO: Document the precondition of this function. Is cs_vSend locked? - void AbortMessage() UNLOCK_FUNCTION(cs_vSend) - { - ssSend.clear(); - - LEAVE_CRITICAL_SECTION(cs_vSend); - - LogPrint("net", "(aborted)\n"); - } + void AbortMessage() UNLOCK_FUNCTION(cs_vSend); // TODO: Document the precondition of this function. Is cs_vSend locked? - void EndMessage() UNLOCK_FUNCTION(cs_vSend) - { - // The -*messagestest options are intentionally not documented in the help message, - // since they are only used during development to debug the networking code and are - // not intended for end-users. - if (mapArgs.count("-dropmessagestest") && GetRand(GetArg("-dropmessagestest", 2)) == 0) - { - LogPrint("net", "dropmessages DROPPING SEND MESSAGE\n"); - AbortMessage(); - return; - } - if (mapArgs.count("-fuzzmessagestest")) - Fuzz(GetArg("-fuzzmessagestest", 10)); - - if (ssSend.size() == 0) - return; - - // Set the size - unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE; - memcpy((char*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], &nSize, sizeof(nSize)); - - // Set the checksum - uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end()); - unsigned int nChecksum = 0; - memcpy(&nChecksum, &hash, sizeof(nChecksum)); - assert(ssSend.size () >= CMessageHeader::CHECKSUM_OFFSET + sizeof(nChecksum)); - memcpy((char*)&ssSend[CMessageHeader::CHECKSUM_OFFSET], &nChecksum, sizeof(nChecksum)); - - LogPrint("net", "(%d bytes) peer=%d\n", nSize, id); - - std::deque::iterator it = vSendMsg.insert(vSendMsg.end(), CSerializeData()); - ssSend.GetAndClear(*it); - nSendSize += (*it).size(); - - // If write queue empty, attempt "optimistic write" - if (it == vSendMsg.begin()) - SocketSendData(this); - - LEAVE_CRITICAL_SECTION(cs_vSend); - } + void EndMessage() UNLOCK_FUNCTION(cs_vSend); void PushVersion(); From af8297c010154243cb11b27184a9badb4e03ecb0 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 21 Aug 2014 05:04:43 +0200 Subject: [PATCH 06/10] Move functions in wallet.h to implementation file Breaks compile-time dependency of wallet.h on util. --- src/wallet.cpp | 17 +++++++++++++++++ src/wallet.h | 18 +++--------------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/wallet.cpp b/src/wallet.cpp index 7c04743c0f0..ee4793b3f18 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -2168,3 +2168,20 @@ bool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, st } return false; } + +CKeyPool::CKeyPool() +{ + nTime = GetTime(); +} + +CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn) +{ + nTime = GetTime(); + vchPubKey = vchPubKeyIn; +} + +CWalletKey::CWalletKey(int64_t nExpires) +{ + nTimeCreated = (nExpires ? GetTime() : 0); + nTimeExpires = nExpires; +} diff --git a/src/wallet.h b/src/wallet.h index 34c699e979c..7cbbb2a6ed6 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -61,16 +61,8 @@ public: int64_t nTime; CPubKey vchPubKey; - CKeyPool() - { - nTime = GetTime(); - } - - CKeyPool(const CPubKey& vchPubKeyIn) - { - nTime = GetTime(); - vchPubKey = vchPubKeyIn; - } + CKeyPool(); + CKeyPool(const CPubKey& vchPubKeyIn); IMPLEMENT_SERIALIZE ( @@ -840,11 +832,7 @@ public: //// todo: add something to note what created it (user, getnewaddress, change) //// maybe should have a map property map - CWalletKey(int64_t nExpires=0) - { - nTimeCreated = (nExpires ? GetTime() : 0); - nTimeExpires = nExpires; - } + CWalletKey(int64_t nExpires=0); IMPLEMENT_SERIALIZE ( From b4aa769bcb82519024ee54fc84a37c34420d53b8 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 21 Aug 2014 15:50:59 +0200 Subject: [PATCH 07/10] Move `S_I*` constants and `MSG_NOSIGNAL` to compat.h --- src/compat.h | 14 ++++++++++++++ src/util.h | 14 -------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/compat.h b/src/compat.h index 3f0a8b6158c..4fc28a36e00 100644 --- a/src/compat.h +++ b/src/compat.h @@ -59,6 +59,20 @@ typedef u_int SOCKET; #define SOCKET_ERROR -1 #endif +#ifdef WIN32 +#ifndef S_IRUSR +#define S_IRUSR 0400 +#define S_IWUSR 0200 +#endif +#else +#define MAX_PATH 1024 +#endif + +// As Solaris does not have the MSG_NOSIGNAL flag for send(2) syscall, it is defined as 0 +#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL) +#define MSG_NOSIGNAL 0 +#endif + #ifndef WIN32 // PRIO_MAX is not defined on Solaris #ifndef PRIO_MAX diff --git a/src/util.h b/src/util.h index 939e59c3013..e0feca07ca9 100644 --- a/src/util.h +++ b/src/util.h @@ -46,20 +46,6 @@ static const int64_t CENT = 1000000; // This is needed because the foreach macro can't get over the comma in pair #define PAIRTYPE(t1, t2) std::pair -#ifdef WIN32 -#define MSG_DONTWAIT 0 - -#ifndef S_IRUSR -#define S_IRUSR 0400 -#define S_IWUSR 0200 -#endif -#else -#define MAX_PATH 1024 -#endif -// As Solaris does not have the MSG_NOSIGNAL flag for send(2) syscall, it is defined as 0 -#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL) -#define MSG_NOSIGNAL 0 -#endif inline void MilliSleep(int64_t n) { From 6e5fd003e04b81115b6b164b21f048472d575535 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 21 Aug 2014 16:11:05 +0200 Subject: [PATCH 08/10] Move `*Version()` functions to version.h/cpp --- src/bitcoin-cli.cpp | 1 + src/qt/utilitydialog.cpp | 2 +- src/rpcprotocol.cpp | 1 + src/tinyformat.h | 1 + src/util.cpp | 25 ------------------------- src/util.h | 2 -- src/version.cpp | 28 ++++++++++++++++++++++++++++ src/version.h | 4 ++++ 8 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 0609adcab3c..10ca26ff2bc 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -8,6 +8,7 @@ #include "rpcclient.h" #include "rpcprotocol.h" #include "chainparamsbase.h" +#include "version.h" #include diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index 5fb0da145de..1a39894c9bf 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -10,9 +10,9 @@ #include "clientmodel.h" #include "guiutil.h" -#include "clientversion.h" #include "init.h" #include "util.h" +#include "version.h" #include #include diff --git a/src/rpcprotocol.cpp b/src/rpcprotocol.cpp index 643208b3b67..a4deddbed36 100644 --- a/src/rpcprotocol.cpp +++ b/src/rpcprotocol.cpp @@ -6,6 +6,7 @@ #include "rpcprotocol.h" #include "util.h" +#include "version.h" #include diff --git a/src/tinyformat.h b/src/tinyformat.h index 929cb66e4d7..73d49a1fe4d 100644 --- a/src/tinyformat.h +++ b/src/tinyformat.h @@ -121,6 +121,7 @@ namespace tfm = tinyformat; #include #include #include +#include #ifndef TINYFORMAT_ERROR # define TINYFORMAT_ERROR(reason) assert(0 && reason) diff --git a/src/util.cpp b/src/util.cpp index 606f5a60f95..80d27d58264 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -13,7 +13,6 @@ #include "random.h" #include "sync.h" #include "uint256.h" -#include "version.h" #include @@ -1116,30 +1115,6 @@ void SetMockTime(int64_t nMockTimeIn) nMockTime = nMockTimeIn; } -string FormatVersion(int nVersion) -{ - if (nVersion%100 == 0) - return strprintf("%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100); - else - return strprintf("%d.%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100, nVersion%100); -} - -string FormatFullVersion() -{ - return CLIENT_BUILD; -} - -// Format the subversion field according to BIP 14 spec (https://en.bitcoin.it/wiki/BIP_0014) -std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector& comments) -{ - std::ostringstream ss; - ss << "/"; - ss << name << ":" << FormatVersion(nClientVersion); - if (!comments.empty()) - ss << "(" << boost::algorithm::join(comments, "; ") << ")"; - ss << "/"; - return ss.str(); -} #ifdef WIN32 boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate) diff --git a/src/util.h b/src/util.h index e0feca07ca9..cfbf30c6a4e 100644 --- a/src/util.h +++ b/src/util.h @@ -156,8 +156,6 @@ boost::filesystem::path GetTempPath(); void ShrinkDebugFile(); int64_t GetTime(); void SetMockTime(int64_t nMockTimeIn); -std::string FormatFullVersion(); -std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector& comments); void runCommand(std::string strCommand); inline std::string i64tostr(int64_t n) diff --git a/src/version.cpp b/src/version.cpp index d86caa3ac2e..8311041ed28 100644 --- a/src/version.cpp +++ b/src/version.cpp @@ -4,7 +4,10 @@ #include "version.h" +#include "tinyformat.h" + #include +#include // Name of client reported in the 'version' message. Report the same name // for both bitcoind and bitcoin-qt, to make it harder for attackers to @@ -69,3 +72,28 @@ const std::string CLIENT_NAME("Satoshi"); const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX); const std::string CLIENT_DATE(BUILD_DATE); + +static std::string FormatVersion(int nVersion) +{ + if (nVersion%100 == 0) + return strprintf("%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100); + else + return strprintf("%d.%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100, nVersion%100); +} + +std::string FormatFullVersion() +{ + return CLIENT_BUILD; +} + +// Format the subversion field according to BIP 14 spec (https://en.bitcoin.it/wiki/BIP_0014) +std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector& comments) +{ + std::ostringstream ss; + ss << "/"; + ss << name << ":" << FormatVersion(nClientVersion); + if (!comments.empty()) + ss << "(" << boost::algorithm::join(comments, "; ") << ")"; + ss << "/"; + return ss.str(); +} diff --git a/src/version.h b/src/version.h index fbb731c91d8..3a6c0f37193 100644 --- a/src/version.h +++ b/src/version.h @@ -7,6 +7,7 @@ #include "clientversion.h" #include +#include // // client versioning @@ -48,4 +49,7 @@ static const int BIP0031_VERSION = 60000; // "mempool" command, enhanced "getdata" behavior starts with this version static const int MEMPOOL_GD_VERSION = 60002; +std::string FormatFullVersion(); +std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector& comments); + #endif From f841aa2892ffd97d564deee103555149d9fbcd9a Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 20 Aug 2014 16:33:55 +0200 Subject: [PATCH 09/10] Move `COIN` and `CENT` to core.h Eventually these should end up in `money.h` after monetary amounts are typedef'ed, but at least they don't belong in `util.h`. --- src/core.h | 3 +++ src/util.h | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core.h b/src/core.h index 9552f702546..e3ceac97aa6 100644 --- a/src/core.h +++ b/src/core.h @@ -14,6 +14,9 @@ class CTransaction; +static const int64_t COIN = 100000000; +static const int64_t CENT = 1000000; + /** No amount larger than this (in satoshi) is valid */ static const int64_t MAX_MONEY = 21000000 * COIN; inline bool MoneyRange(int64_t nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } diff --git a/src/util.h b/src/util.h index cfbf30c6a4e..cbd311574a3 100644 --- a/src/util.h +++ b/src/util.h @@ -34,9 +34,6 @@ class uint256; -static const int64_t COIN = 100000000; -static const int64_t CENT = 1000000; - #define BEGIN(a) ((char*)&(a)) #define END(a) ((char*)&((&(a))[1])) #define UBEGIN(a) ((unsigned char*)&(a)) From ad49c256c33bfe4088fd3c7ecb7d28cb81a8fc70 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 21 Aug 2014 16:11:09 +0200 Subject: [PATCH 10/10] Split up util.cpp/h Split up util.cpp/h into: - string utilities (hex, base32, base64): no internal dependencies, no dependency on boost (apart from foreach) - money utilities (parsesmoney, formatmoney) - time utilities (gettime*, sleep, format date): - and the rest (logging, argument parsing, config file parsing) The latter is basically the environment and OS handling, and is stripped of all utility functions, so we may want to rename it to something else than util.cpp/h for clarity (Matt suggested osinterface). Breaks dependency of sha256.cpp on all the things pulled in by util. --- src/Makefile.am | 6 + src/alert.cpp | 1 + src/bitcoin-cli.cpp | 1 + src/bitcoin-tx.cpp | 1 + src/bitcoind.cpp | 1 + src/core_write.cpp | 1 + src/crypter.cpp | 1 + src/db.cpp | 2 + src/init.cpp | 2 + src/keystore.cpp | 1 + src/main.cpp | 1 + src/miner.cpp | 6 +- src/net.cpp | 1 + src/net.h | 3 +- src/netbase.cpp | 2 + src/noui.cpp | 1 + src/pow.cpp | 1 + src/qt/bitcoin.cpp | 1 + src/qt/bitcoingui.cpp | 1 + src/qt/clientmodel.cpp | 1 + src/qt/optionsdialog.cpp | 1 + src/qt/paymentserver.cpp | 1 + src/qt/transactiondesc.cpp | 1 + src/qt/utilitydialog.cpp | 3 +- src/random.cpp | 4 +- src/rpcblockchain.cpp | 1 + src/rpcdump.cpp | 2 + src/rpcmining.cpp | 1 + src/rpcprotocol.cpp | 3 + src/rpcserver.cpp | 6 + src/script.cpp | 3 +- src/script.h | 3 +- src/test/DoS_tests.cpp | 1 + src/test/alert_tests.cpp | 1 + src/test/allocator_tests.cpp | 2 + src/test/base32_tests.cpp | 2 +- src/test/base64_tests.cpp | 2 +- src/test/checkblock_tests.cpp | 1 + src/test/crypto_tests.cpp | 2 +- src/test/hash_tests.cpp | 2 +- src/test/test_bitcoin.cpp | 1 + src/test/util_tests.cpp | 3 + src/timedata.cpp | 6 + src/txdb.cpp | 1 + src/txmempool.cpp | 1 + src/uint256.cpp | 3 +- src/util.cpp | 551 +--------------------------------- src/util.h | 176 +---------- src/utilmoneystr.cpp | 75 +++++ src/utilmoneystr.h | 19 ++ src/utilstrencodings.cpp | 496 ++++++++++++++++++++++++++++++ src/utilstrencodings.h | 97 ++++++ src/utiltime.cpp | 66 ++++ src/utiltime.h | 20 ++ src/wallet.cpp | 8 + src/wallet.h | 6 +- src/walletdb.cpp | 3 + 57 files changed, 875 insertions(+), 734 deletions(-) create mode 100644 src/utilmoneystr.cpp create mode 100644 src/utilmoneystr.h create mode 100644 src/utilstrencodings.cpp create mode 100644 src/utilstrencodings.h create mode 100644 src/utiltime.cpp create mode 100644 src/utiltime.h diff --git a/src/Makefile.am b/src/Makefile.am index 6c67dee7d5b..655bfc88c3b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -109,6 +109,9 @@ BITCOIN_CORE_H = \ ui_interface.h \ uint256.h \ util.h \ + utilstrencodings.h \ + utilmoneystr.h \ + utiltime.h \ version.h \ walletdb.h \ wallet.h \ @@ -219,6 +222,9 @@ libbitcoin_util_a_SOURCES = \ sync.cpp \ uint256.cpp \ util.cpp \ + utilstrencodings.cpp \ + utilmoneystr.cpp \ + utiltime.cpp \ version.cpp \ $(BITCOIN_CORE_H) diff --git a/src/alert.cpp b/src/alert.cpp index 2cd684cc4c4..3271ecfbfd3 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -19,6 +19,7 @@ #include #include #include +#include using namespace std; diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 10ca26ff2bc..871aaf93df5 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -8,6 +8,7 @@ #include "rpcclient.h" #include "rpcprotocol.h" #include "chainparamsbase.h" +#include "utilstrencodings.h" #include "version.h" #include diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 6cd2768d700..75f0fb69f26 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -4,6 +4,7 @@ #include "base58.h" #include "util.h" +#include "utilmoneystr.h" #include "core.h" #include "main.h" // for MAX_BLOCK_SIZE #include "keystore.h" diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 880955481b0..5be8708979b 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -12,6 +12,7 @@ #include #include +#include /* Introduction text for doxygen: */ diff --git a/src/core_write.cpp b/src/core_write.cpp index 37dd69f7b83..b395b5c0908 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -8,6 +8,7 @@ #include "core.h" #include "serialize.h" #include "util.h" +#include "utilmoneystr.h" #include "base58.h" using namespace std; diff --git a/src/crypter.cpp b/src/crypter.cpp index 122e06d97ef..8aa2bb05177 100644 --- a/src/crypter.cpp +++ b/src/crypter.cpp @@ -5,6 +5,7 @@ #include "crypter.h" #include "script.h" +#include "util.h" #include #include diff --git a/src/db.cpp b/src/db.cpp index eb40f3cc405..8c139843a18 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -9,6 +9,7 @@ #include "hash.h" #include "protocol.h" #include "util.h" +#include "utilstrencodings.h" #include @@ -17,6 +18,7 @@ #endif #include +#include #include #include diff --git a/src/init.cpp b/src/init.cpp index 708e6386aaf..e972413c4b9 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -19,6 +19,7 @@ #include "txdb.h" #include "ui_interface.h" #include "util.h" +#include "utilmoneystr.h" #ifdef ENABLE_WALLET #include "db.h" #include "wallet.h" @@ -36,6 +37,7 @@ #include #include #include +#include #include using namespace boost; diff --git a/src/keystore.cpp b/src/keystore.cpp index 2a4c88d5656..c6322eadce8 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -8,6 +8,7 @@ #include "crypter.h" #include "key.h" #include "script.h" +#include "util.h" #include diff --git a/src/main.cpp b/src/main.cpp index d9f897f4477..322f580f10b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,6 +24,7 @@ #include #include #include +#include using namespace std; using namespace boost; diff --git a/src/miner.cpp b/src/miner.cpp index 06acff1c33e..8696edcf6e9 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -3,8 +3,6 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include - #include "miner.h" #include "core.h" @@ -12,10 +10,14 @@ #include "main.h" #include "net.h" #include "pow.h" +#include "util.h" +#include "utilmoneystr.h" #ifdef ENABLE_WALLET #include "wallet.h" #endif +#include + using namespace std; ////////////////////////////////////////////////////////////////////////////// diff --git a/src/net.cpp b/src/net.cpp index 440c271a5e9..e2adba85175 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -28,6 +28,7 @@ #endif #include +#include // Dump addresses to peers.dat every 15 minutes (900s) #define DUMP_ADDRESSES_INTERVAL 900 diff --git a/src/net.h b/src/net.h index 2b4732c9dee..bfad32b2c17 100644 --- a/src/net.h +++ b/src/net.h @@ -16,7 +16,7 @@ #include "random.h" #include "sync.h" #include "uint256.h" -#include "util.h" +#include "utilstrencodings.h" #include #include @@ -25,6 +25,7 @@ #include #endif +#include #include #include diff --git a/src/netbase.cpp b/src/netbase.cpp index e9207da3302..d5821d4465b 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -13,6 +13,7 @@ #include "sync.h" #include "uint256.h" #include "util.h" +#include "utilstrencodings.h" #ifdef HAVE_GETADDRINFO_A #include @@ -27,6 +28,7 @@ #include // for to_lower() #include // for startswith() and endswith() +#include #if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL) #define MSG_NOSIGNAL 0 diff --git a/src/noui.cpp b/src/noui.cpp index 32c861b0d9d..8b00fd40571 100644 --- a/src/noui.cpp +++ b/src/noui.cpp @@ -8,6 +8,7 @@ #include "ui_interface.h" #include "util.h" +#include #include #include diff --git a/src/pow.cpp b/src/pow.cpp index c0d0a7ca20f..b091cbec3dc 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -9,6 +9,7 @@ #include "core.h" #include "main.h" #include "uint256.h" +#include "util.h" unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock) { diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index a43e7cb7562..12277a8ad00 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #include #include diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index bfca5e8d1a2..d0a5ff13c3a 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -24,6 +24,7 @@ #endif #include "init.h" +#include "util.h" #include "ui_interface.h" #include diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 4c21eb5594e..9c9ff5b3a1a 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -13,6 +13,7 @@ #include "main.h" #include "net.h" #include "ui_interface.h" +#include "util.h" #include diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index fd1d446f9b8..c775a7f8d64 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -21,6 +21,7 @@ #include "wallet.h" // for CWallet::minTxFee #endif +#include #include #include #include diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index a9f1566d62b..f6a4b599de5 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -11,6 +11,7 @@ #include "base58.h" #include "ui_interface.h" +#include "util.h" #include "wallet.h" #include diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 4f6e3169f5a..8258e719a36 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -15,6 +15,7 @@ #include "transactionrecord.h" #include "timedata.h" #include "ui_interface.h" +#include "util.h" #include "wallet.h" #include diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index 1a39894c9bf..7df9d1bc2df 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -11,9 +11,10 @@ #include "guiutil.h" #include "init.h" -#include "util.h" #include "version.h" +#include + #include #include #include diff --git a/src/random.cpp b/src/random.cpp index 0d20d205ac6..22c942acc04 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -8,12 +8,14 @@ #ifdef WIN32 #include "compat.h" // for Windows API #endif +#include "serialize.h" // for begin_ptr(vec) #include "util.h" // for LogPrint() +#include "utilstrencodings.h" // for GetTime() #ifndef WIN32 #include #endif - +#include #include #include #include diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index e511fe4222d..58cab140454 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -7,6 +7,7 @@ #include "main.h" #include "rpcserver.h" #include "sync.h" +#include "util.h" #include diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index ff2361482b9..e68ddee0409 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -7,6 +7,8 @@ #include "init.h" #include "main.h" #include "sync.h" +#include "utiltime.h" +#include "util.h" #include "wallet.h" #include diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index edab427cbfa..6e508abcda4 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -11,6 +11,7 @@ #include "miner.h" #include "pow.h" #include "core_io.h" +#include "util.h" #ifdef ENABLE_WALLET #include "db.h" #include "wallet.h" diff --git a/src/rpcprotocol.cpp b/src/rpcprotocol.cpp index a4deddbed36..808b9bbd2a7 100644 --- a/src/rpcprotocol.cpp +++ b/src/rpcprotocol.cpp @@ -6,6 +6,9 @@ #include "rpcprotocol.h" #include "util.h" +#include "tinyformat.h" +#include "utilstrencodings.h" +#include "utiltime.h" #include "version.h" #include diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 524627e2dee..c9133bd3d27 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "json/json_spirit_writer_template.h" using namespace boost; @@ -82,6 +83,11 @@ void RPCTypeCheck(const Object& o, } } +static inline int64_t roundint64(double d) +{ + return (int64_t)(d > 0 ? d + 0.5 : d - 0.5); +} + int64_t AmountFromValue(const Value& value) { double dAmount = value.get_real(); diff --git a/src/script.cpp b/src/script.cpp index 942e8810db7..4c7bb10c372 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -18,8 +18,9 @@ #include "util.h" #include -#include +#include #include +#include using namespace std; using namespace boost; diff --git a/src/script.h b/src/script.h index 1e2cc94efe2..462e3f23028 100644 --- a/src/script.h +++ b/src/script.h @@ -7,7 +7,8 @@ #define H_BITCOIN_SCRIPT #include "key.h" -#include "util.h" +#include "utilstrencodings.h" +#include "tinyformat.h" #include #include diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 5e17555e7a8..4ecf6e25357 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -14,6 +14,7 @@ #include "pow.h" #include "script.h" #include "serialize.h" +#include "util.h" #include diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp index e3066a51ab9..4af87cf8ef7 100644 --- a/src/test/alert_tests.cpp +++ b/src/test/alert_tests.cpp @@ -11,6 +11,7 @@ #include "serialize.h" #include "util.h" +#include "utilstrencodings.h" #include "version.h" #include diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp index 2752a0b2158..69888da3dfa 100644 --- a/src/test/allocator_tests.cpp +++ b/src/test/allocator_tests.cpp @@ -4,6 +4,8 @@ #include "util.h" +#include "allocators.h" + #include BOOST_AUTO_TEST_SUITE(allocator_tests) diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp index 87473585e33..68617abbdd5 100644 --- a/src/test/base32_tests.cpp +++ b/src/test/base32_tests.cpp @@ -2,7 +2,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "util.h" +#include "utilstrencodings.h" #include diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp index d4a23d9aa0e..f2bf3326ad8 100644 --- a/src/test/base64_tests.cpp +++ b/src/test/base64_tests.cpp @@ -2,7 +2,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "util.h" +#include "utilstrencodings.h" #include diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp index 10352240f42..fdea12846a0 100644 --- a/src/test/checkblock_tests.cpp +++ b/src/test/checkblock_tests.cpp @@ -9,6 +9,7 @@ #include "main.h" +#include "utiltime.h" #include diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index a17278b8039..a3eec270ee9 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -6,7 +6,7 @@ #include "crypto/sha1.h" #include "crypto/sha2.h" #include "random.h" -#include "util.h" +#include "utilstrencodings.h" #include diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp index 4568c8769bc..b8e290f071f 100644 --- a/src/test/hash_tests.cpp +++ b/src/test/hash_tests.cpp @@ -3,7 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "hash.h" -#include "util.h" +#include "utilstrencodings.h" #include diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 443b5853b20..68fad8d038e 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -16,6 +16,7 @@ #include #include +#include CClientUIInterface uiInterface; CWallet* pwalletMain; diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 31fcd3e92a4..e077c9de3bf 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -4,8 +4,11 @@ #include "util.h" +#include "core.h" #include "random.h" #include "sync.h" +#include "utilstrencodings.h" +#include "utilmoneystr.h" #include #include diff --git a/src/timedata.cpp b/src/timedata.cpp index 4576786b965..40cdb33f7a8 100644 --- a/src/timedata.cpp +++ b/src/timedata.cpp @@ -8,6 +8,7 @@ #include "sync.h" #include "ui_interface.h" #include "util.h" +#include "utilstrencodings.h" #include @@ -35,6 +36,11 @@ int64_t GetAdjustedTime() return GetTime() + GetTimeOffset(); } +static int64_t abs64(int64_t n) +{ + return (n >= 0 ? n : -n); +} + void AddTimeData(const CNetAddr& ip, int64_t nTime) { int64_t nOffsetSample = nTime - GetTime(); diff --git a/src/txdb.cpp b/src/txdb.cpp index 7c0683aaf3d..a3a9b315347 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -9,6 +9,7 @@ #include "pow.h" #include "uint256.h" +#include #include using namespace std; diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 80cae682448..b327e1c732c 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -5,6 +5,7 @@ #include "core.h" #include "txmempool.h" +#include "util.h" #include diff --git a/src/uint256.cpp b/src/uint256.cpp index 08c05594fd9..feda0ca5a9d 100644 --- a/src/uint256.cpp +++ b/src/uint256.cpp @@ -4,7 +4,8 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "uint256.h" -#include "util.h" + +#include "utilstrencodings.h" #include #include diff --git a/src/util.cpp b/src/util.cpp index 80d27d58264..5a4e187f9e2 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -11,13 +11,13 @@ #include "chainparamsbase.h" #include "random.h" +#include "serialize.h" #include "sync.h" -#include "uint256.h" +#include "utilstrencodings.h" +#include "utiltime.h" #include -#include - #ifndef WIN32 // for posix_fallocate #ifdef __linux__ @@ -75,6 +75,7 @@ #include #include #include +#include #include #include @@ -243,148 +244,6 @@ int LogPrintStr(const std::string &str) return ret; } -string FormatMoney(int64_t n, bool fPlus) -{ - // Note: not using straight sprintf here because we do NOT want - // localized number formatting. - int64_t n_abs = (n > 0 ? n : -n); - int64_t quotient = n_abs/COIN; - int64_t remainder = n_abs%COIN; - string str = strprintf("%d.%08d", quotient, remainder); - - // Right-trim excess zeros before the decimal point: - int nTrim = 0; - for (int i = str.size()-1; (str[i] == '0' && isdigit(str[i-2])); --i) - ++nTrim; - if (nTrim) - str.erase(str.size()-nTrim, nTrim); - - if (n < 0) - str.insert((unsigned int)0, 1, '-'); - else if (fPlus && n > 0) - str.insert((unsigned int)0, 1, '+'); - return str; -} - - -bool ParseMoney(const string& str, int64_t& nRet) -{ - return ParseMoney(str.c_str(), nRet); -} - -bool ParseMoney(const char* pszIn, int64_t& nRet) -{ - string strWhole; - int64_t nUnits = 0; - const char* p = pszIn; - while (isspace(*p)) - p++; - for (; *p; p++) - { - if (*p == '.') - { - p++; - int64_t nMult = CENT*10; - while (isdigit(*p) && (nMult > 0)) - { - nUnits += nMult * (*p++ - '0'); - nMult /= 10; - } - break; - } - if (isspace(*p)) - break; - if (!isdigit(*p)) - return false; - strWhole.insert(strWhole.end(), *p); - } - for (; *p; p++) - if (!isspace(*p)) - return false; - if (strWhole.size() > 10) // guard against 63 bit overflow - return false; - if (nUnits < 0 || nUnits > COIN) - return false; - int64_t nWhole = atoi64(strWhole); - int64_t nValue = nWhole*COIN + nUnits; - - nRet = nValue; - return true; -} - -// safeChars chosen to allow simple messages/URLs/email addresses, but avoid anything -// even possibly remotely dangerous like & or > -static string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 .,;_/:?@"); -string SanitizeString(const string& str) -{ - string strResult; - for (std::string::size_type i = 0; i < str.size(); i++) - { - if (safeChars.find(str[i]) != std::string::npos) - strResult.push_back(str[i]); - } - return strResult; -} - -const signed char p_util_hexdigit[256] = -{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1, - -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, }; - -signed char HexDigit(char c) -{ - return p_util_hexdigit[(unsigned char)c]; -} - -bool IsHex(const string& str) -{ - BOOST_FOREACH(char c, str) - { - if (HexDigit(c) < 0) - return false; - } - return (str.size() > 0) && (str.size()%2 == 0); -} - -vector ParseHex(const char* psz) -{ - // convert hex dump to vector - vector vch; - while (true) - { - while (isspace(*psz)) - psz++; - signed char c = HexDigit(*psz++); - if (c == (signed char)-1) - break; - unsigned char n = (c << 4); - c = HexDigit(*psz++); - if (c == (signed char)-1) - break; - n |= c; - vch.push_back(n); - } - return vch; -} - -vector ParseHex(const string& str) -{ - return ParseHex(str.c_str()); -} - static void InterpretNegativeSetting(string name, map& mapSettingsRet) { // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set @@ -482,334 +341,6 @@ bool SoftSetBoolArg(const std::string& strArg, bool fValue) return SoftSetArg(strArg, std::string("0")); } - -string EncodeBase64(const unsigned char* pch, size_t len) -{ - static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - string strRet=""; - strRet.reserve((len+2)/3*4); - - int mode=0, left=0; - const unsigned char *pchEnd = pch+len; - - while (pch> 2]; - left = (enc & 3) << 4; - mode = 1; - break; - - case 1: // we have two bits - strRet += pbase64[left | (enc >> 4)]; - left = (enc & 15) << 2; - mode = 2; - break; - - case 2: // we have four bits - strRet += pbase64[left | (enc >> 6)]; - strRet += pbase64[enc & 63]; - mode = 0; - break; - } - } - - if (mode) - { - strRet += pbase64[left]; - strRet += '='; - if (mode == 1) - strRet += '='; - } - - return strRet; -} - -string EncodeBase64(const string& str) -{ - return EncodeBase64((const unsigned char*)str.c_str(), str.size()); -} - -vector DecodeBase64(const char* p, bool* pfInvalid) -{ - static const int decode64_table[256] = - { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, - -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 - }; - - if (pfInvalid) - *pfInvalid = false; - - vector vchRet; - vchRet.reserve(strlen(p)*3/4); - - int mode = 0; - int left = 0; - - while (1) - { - int dec = decode64_table[(unsigned char)*p]; - if (dec == -1) break; - p++; - switch (mode) - { - case 0: // we have no bits and get 6 - left = dec; - mode = 1; - break; - - case 1: // we have 6 bits and keep 4 - vchRet.push_back((left<<2) | (dec>>4)); - left = dec & 15; - mode = 2; - break; - - case 2: // we have 4 bits and get 6, we keep 2 - vchRet.push_back((left<<4) | (dec>>2)); - left = dec & 3; - mode = 3; - break; - - case 3: // we have 2 bits and get 6 - vchRet.push_back((left<<6) | dec); - mode = 0; - break; - } - } - - if (pfInvalid) - switch (mode) - { - case 0: // 4n base64 characters processed: ok - break; - - case 1: // 4n+1 base64 character processed: impossible - *pfInvalid = true; - break; - - case 2: // 4n+2 base64 characters processed: require '==' - if (left || p[0] != '=' || p[1] != '=' || decode64_table[(unsigned char)p[2]] != -1) - *pfInvalid = true; - break; - - case 3: // 4n+3 base64 characters processed: require '=' - if (left || p[0] != '=' || decode64_table[(unsigned char)p[1]] != -1) - *pfInvalid = true; - break; - } - - return vchRet; -} - -string DecodeBase64(const string& str) -{ - vector vchRet = DecodeBase64(str.c_str()); - return string((const char*)&vchRet[0], vchRet.size()); -} - -string EncodeBase32(const unsigned char* pch, size_t len) -{ - static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567"; - - string strRet=""; - strRet.reserve((len+4)/5*8); - - int mode=0, left=0; - const unsigned char *pchEnd = pch+len; - - while (pch> 3]; - left = (enc & 7) << 2; - mode = 1; - break; - - case 1: // we have three bits - strRet += pbase32[left | (enc >> 6)]; - strRet += pbase32[(enc >> 1) & 31]; - left = (enc & 1) << 4; - mode = 2; - break; - - case 2: // we have one bit - strRet += pbase32[left | (enc >> 4)]; - left = (enc & 15) << 1; - mode = 3; - break; - - case 3: // we have four bits - strRet += pbase32[left | (enc >> 7)]; - strRet += pbase32[(enc >> 2) & 31]; - left = (enc & 3) << 3; - mode = 4; - break; - - case 4: // we have two bits - strRet += pbase32[left | (enc >> 5)]; - strRet += pbase32[enc & 31]; - mode = 0; - } - } - - static const int nPadding[5] = {0, 6, 4, 3, 1}; - if (mode) - { - strRet += pbase32[left]; - for (int n=0; n DecodeBase32(const char* p, bool* pfInvalid) -{ - static const int decode32_table[256] = - { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 0, 1, 2, - 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 - }; - - if (pfInvalid) - *pfInvalid = false; - - vector vchRet; - vchRet.reserve((strlen(p))*5/8); - - int mode = 0; - int left = 0; - - while (1) - { - int dec = decode32_table[(unsigned char)*p]; - if (dec == -1) break; - p++; - switch (mode) - { - case 0: // we have no bits and get 5 - left = dec; - mode = 1; - break; - - case 1: // we have 5 bits and keep 2 - vchRet.push_back((left<<3) | (dec>>2)); - left = dec & 3; - mode = 2; - break; - - case 2: // we have 2 bits and keep 7 - left = left << 5 | dec; - mode = 3; - break; - - case 3: // we have 7 bits and keep 4 - vchRet.push_back((left<<1) | (dec>>4)); - left = dec & 15; - mode = 4; - break; - - case 4: // we have 4 bits, and keep 1 - vchRet.push_back((left<<4) | (dec>>1)); - left = dec & 1; - mode = 5; - break; - - case 5: // we have 1 bit, and keep 6 - left = left << 5 | dec; - mode = 6; - break; - - case 6: // we have 6 bits, and keep 3 - vchRet.push_back((left<<2) | (dec>>3)); - left = dec & 7; - mode = 7; - break; - - case 7: // we have 3 bits, and keep 0 - vchRet.push_back((left<<5) | dec); - mode = 0; - break; - } - } - - if (pfInvalid) - switch (mode) - { - case 0: // 8n base32 characters processed: ok - break; - - case 1: // 8n+1 base32 characters processed: impossible - case 3: // +3 - case 6: // +6 - *pfInvalid = true; - break; - - case 2: // 8n+2 base32 characters processed: require '======' - if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || p[4] != '=' || p[5] != '=' || decode32_table[(unsigned char)p[6]] != -1) - *pfInvalid = true; - break; - - case 4: // 8n+4 base32 characters processed: require '====' - if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || decode32_table[(unsigned char)p[4]] != -1) - *pfInvalid = true; - break; - - case 5: // 8n+5 base32 characters processed: require '===' - if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || decode32_table[(unsigned char)p[3]] != -1) - *pfInvalid = true; - break; - - case 7: // 8n+7 base32 characters processed: require '=' - if (left || p[0] != '=' || decode32_table[(unsigned char)p[1]] != -1) - *pfInvalid = true; - break; - } - - return vchRet; -} - -string DecodeBase32(const string& str) -{ - vector vchRet = DecodeBase32(str.c_str()); - return string((const char*)&vchRet[0], vchRet.size()); -} - static std::string FormatException(std::exception* pex, const char* pszThread) { #ifdef WIN32 @@ -1101,21 +632,6 @@ void ShrinkDebugFile() fclose(file); } -static int64_t nMockTime = 0; // For unit testing - -int64_t GetTime() -{ - if (nMockTime) return nMockTime; - - return time(NULL); -} - -void SetMockTime(int64_t nMockTimeIn) -{ - nMockTime = nMockTimeIn; -} - - #ifdef WIN32 boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate) { @@ -1186,20 +702,6 @@ void RenameThread(const char* name) #endif } -bool ParseInt32(const std::string& str, int32_t *out) -{ - char *endp = NULL; - errno = 0; // strtol will not set errno if valid - long int n = strtol(str.c_str(), &endp, 10); - if(out) *out = (int)n; - // Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow - // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit - // platforms the size of these types may be different. - return endp && *endp == 0 && !errno && - n >= std::numeric_limits::min() && - n <= std::numeric_limits::max(); -} - void SetupEnvironment() { #ifndef WIN32 @@ -1217,51 +719,6 @@ void SetupEnvironment() #endif } -std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime) -{ - // std::locale takes ownership of the pointer - std::locale loc(std::locale::classic(), new boost::posix_time::time_facet(pszFormat)); - std::stringstream ss; - ss.imbue(loc); - ss << boost::posix_time::from_time_t(nTime); - return ss.str(); -} - -std::string FormatParagraph(const std::string in, size_t width, size_t indent) -{ - std::stringstream out; - size_t col = 0; - size_t ptr = 0; - while(ptr < in.size()) - { - // Find beginning of next word - ptr = in.find_first_not_of(' ', ptr); - if (ptr == std::string::npos) - break; - // Find end of next word - size_t endword = in.find_first_of(' ', ptr); - if (endword == std::string::npos) - endword = in.size(); - // Add newline and indentation if this wraps over the allowed width - if (col > 0) - { - if ((col + endword - ptr) > width) - { - out << '\n'; - for(size_t i=0; i #include #include -#include #include #include -#include #include -#ifndef WIN32 -#include -#include -#include -#endif - #include -#include - -class uint256; - -#define BEGIN(a) ((char*)&(a)) -#define END(a) ((char*)&((&(a))[1])) -#define UBEGIN(a) ((unsigned char*)&(a)) -#define UEND(a) ((unsigned char*)&((&(a))[1])) -#define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0])) - -// This is needed because the foreach macro can't get over the comma in pair -#define PAIRTYPE(t1, t2) std::pair - - -inline void MilliSleep(int64_t n) -{ -// Boost's sleep_for was uninterruptable when backed by nanosleep from 1.50 -// until fixed in 1.52. Use the deprecated sleep method for the broken case. -// See: https://svn.boost.org/trac/boost/ticket/7238 -#if defined(HAVE_WORKING_BOOST_SLEEP_FOR) - boost::this_thread::sleep_for(boost::chrono::milliseconds(n)); -#elif defined(HAVE_WORKING_BOOST_SLEEP) - boost::this_thread::sleep(boost::posix_time::milliseconds(n)); -#else -//should never get here -#error missing boost sleep implementation -#endif -} +#include extern std::map mapArgs; extern std::map > mapMultiArgs; @@ -115,22 +83,6 @@ static inline bool error(const char* format) } void PrintExceptionContinue(std::exception* pex, const char* pszThread); -std::string FormatMoney(int64_t n, bool fPlus=false); -bool ParseMoney(const std::string& str, int64_t& nRet); -bool ParseMoney(const char* pszIn, int64_t& nRet); -std::string SanitizeString(const std::string& str); -std::vector ParseHex(const char* psz); -std::vector ParseHex(const std::string& str); -signed char HexDigit(char c); -bool IsHex(const std::string& str); -std::vector DecodeBase64(const char* p, bool* pfInvalid = NULL); -std::string DecodeBase64(const std::string& str); -std::string EncodeBase64(const unsigned char* pch, size_t len); -std::string EncodeBase64(const std::string& str); -std::vector DecodeBase32(const char* p, bool* pfInvalid = NULL); -std::string DecodeBase32(const std::string& str); -std::string EncodeBase32(const unsigned char* pch, size_t len); -std::string EncodeBase32(const std::string& str); void ParseParameters(int argc, const char*const argv[]); void FileCommit(FILE *fileout); bool TruncateFile(FILE *file, unsigned int length); @@ -151,109 +103,8 @@ boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true); #endif boost::filesystem::path GetTempPath(); void ShrinkDebugFile(); -int64_t GetTime(); -void SetMockTime(int64_t nMockTimeIn); void runCommand(std::string strCommand); -inline std::string i64tostr(int64_t n) -{ - return strprintf("%d", n); -} - -inline std::string itostr(int n) -{ - return strprintf("%d", n); -} - -inline int64_t atoi64(const char* psz) -{ -#ifdef _MSC_VER - return _atoi64(psz); -#else - return strtoll(psz, NULL, 10); -#endif -} - -inline int64_t atoi64(const std::string& str) -{ -#ifdef _MSC_VER - return _atoi64(str.c_str()); -#else - return strtoll(str.c_str(), NULL, 10); -#endif -} - -inline int atoi(const std::string& str) -{ - return atoi(str.c_str()); -} - -/** - * Convert string to signed 32-bit integer with strict parse error feedback. - * @returns true if the entire string could be parsed as valid integer, - * false if not the entire string could be parsed or when overflow or underflow occured. - */ -bool ParseInt32(const std::string& str, int32_t *out); - -inline int roundint(double d) -{ - return (int)(d > 0 ? d + 0.5 : d - 0.5); -} - -inline int64_t roundint64(double d) -{ - return (int64_t)(d > 0 ? d + 0.5 : d - 0.5); -} - -inline int64_t abs64(int64_t n) -{ - return (n >= 0 ? n : -n); -} - -template -std::string HexStr(const T itbegin, const T itend, bool fSpaces=false) -{ - std::string rv; - static const char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - rv.reserve((itend-itbegin)*3); - for(T it = itbegin; it < itend; ++it) - { - unsigned char val = (unsigned char)(*it); - if(fSpaces && it != itbegin) - rv.push_back(' '); - rv.push_back(hexmap[val>>4]); - rv.push_back(hexmap[val&15]); - } - - return rv; -} - -template -inline std::string HexStr(const T& vch, bool fSpaces=false) -{ - return HexStr(vch.begin(), vch.end(), fSpaces); -} - -/** Format a paragraph of text to a fixed width, adding spaces for - * indentation to any added line. - */ -std::string FormatParagraph(const std::string in, size_t width=79, size_t indent=0); - -inline int64_t GetTimeMillis() -{ - return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) - - boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds(); -} - -inline int64_t GetTimeMicros() -{ - return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) - - boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds(); -} - -std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime); - inline bool IsSwitchChar(char c) { #ifdef WIN32 @@ -308,21 +159,6 @@ bool SoftSetArg(const std::string& strArg, const std::string& strValue); */ bool SoftSetBoolArg(const std::string& strArg, bool fValue); -/** - * Timing-attack-resistant comparison. - * Takes time proportional to length - * of first argument. - */ -template -bool TimingResistantEqual(const T& a, const T& b) -{ - if (b.size() == 0) return a.size() == 0; - size_t accumulator = a.size() ^ b.size(); - for (size_t i = 0; i < a.size(); i++) - accumulator |= a[i] ^ b[i%b.size()]; - return accumulator == 0; -} - void SetThreadPriority(int nPriority); void RenameThread(const char* name); diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp new file mode 100644 index 00000000000..1bd48d8d4ce --- /dev/null +++ b/src/utilmoneystr.cpp @@ -0,0 +1,75 @@ +#include "utilmoneystr.h" + +#include "core.h" +#include "tinyformat.h" + +using namespace std; + +string FormatMoney(int64_t n, bool fPlus) +{ + // Note: not using straight sprintf here because we do NOT want + // localized number formatting. + int64_t n_abs = (n > 0 ? n : -n); + int64_t quotient = n_abs/COIN; + int64_t remainder = n_abs%COIN; + string str = strprintf("%d.%08d", quotient, remainder); + + // Right-trim excess zeros before the decimal point: + int nTrim = 0; + for (int i = str.size()-1; (str[i] == '0' && isdigit(str[i-2])); --i) + ++nTrim; + if (nTrim) + str.erase(str.size()-nTrim, nTrim); + + if (n < 0) + str.insert((unsigned int)0, 1, '-'); + else if (fPlus && n > 0) + str.insert((unsigned int)0, 1, '+'); + return str; +} + + +bool ParseMoney(const string& str, int64_t& nRet) +{ + return ParseMoney(str.c_str(), nRet); +} + +bool ParseMoney(const char* pszIn, int64_t& nRet) +{ + string strWhole; + int64_t nUnits = 0; + const char* p = pszIn; + while (isspace(*p)) + p++; + for (; *p; p++) + { + if (*p == '.') + { + p++; + int64_t nMult = CENT*10; + while (isdigit(*p) && (nMult > 0)) + { + nUnits += nMult * (*p++ - '0'); + nMult /= 10; + } + break; + } + if (isspace(*p)) + break; + if (!isdigit(*p)) + return false; + strWhole.insert(strWhole.end(), *p); + } + for (; *p; p++) + if (!isspace(*p)) + return false; + if (strWhole.size() > 10) // guard against 63 bit overflow + return false; + if (nUnits < 0 || nUnits > COIN) + return false; + int64_t nWhole = atoi64(strWhole); + int64_t nValue = nWhole*COIN + nUnits; + + nRet = nValue; + return true; +} diff --git a/src/utilmoneystr.h b/src/utilmoneystr.h new file mode 100644 index 00000000000..f0c61aa1382 --- /dev/null +++ b/src/utilmoneystr.h @@ -0,0 +1,19 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +/** + * Money parsing/formatting utilities. + */ +#ifndef BITCOIN_UTILMONEYSTR_H +#define BITCOIN_UTILMONEYSTR_H + +#include +#include + +std::string FormatMoney(int64_t n, bool fPlus=false); +bool ParseMoney(const std::string& str, int64_t& nRet); +bool ParseMoney(const char* pszIn, int64_t& nRet); + +#endif // BITCOIN_UTILMONEYSTR_H diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp new file mode 100644 index 00000000000..ef135551042 --- /dev/null +++ b/src/utilstrencodings.cpp @@ -0,0 +1,496 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "utilstrencodings.h" + +#include "tinyformat.h" + +#include +#include +#include + +using namespace std; + +// safeChars chosen to allow simple messages/URLs/email addresses, but avoid anything +// even possibly remotely dangerous like & or > +static string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 .,;_/:?@"); +string SanitizeString(const string& str) +{ + string strResult; + for (std::string::size_type i = 0; i < str.size(); i++) + { + if (safeChars.find(str[i]) != std::string::npos) + strResult.push_back(str[i]); + } + return strResult; +} + +const signed char p_util_hexdigit[256] = +{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1, + -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, }; + +signed char HexDigit(char c) +{ + return p_util_hexdigit[(unsigned char)c]; +} + +bool IsHex(const string& str) +{ + BOOST_FOREACH(char c, str) + { + if (HexDigit(c) < 0) + return false; + } + return (str.size() > 0) && (str.size()%2 == 0); +} + +vector ParseHex(const char* psz) +{ + // convert hex dump to vector + vector vch; + while (true) + { + while (isspace(*psz)) + psz++; + signed char c = HexDigit(*psz++); + if (c == (signed char)-1) + break; + unsigned char n = (c << 4); + c = HexDigit(*psz++); + if (c == (signed char)-1) + break; + n |= c; + vch.push_back(n); + } + return vch; +} + +vector ParseHex(const string& str) +{ + return ParseHex(str.c_str()); +} + +string EncodeBase64(const unsigned char* pch, size_t len) +{ + static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + string strRet=""; + strRet.reserve((len+2)/3*4); + + int mode=0, left=0; + const unsigned char *pchEnd = pch+len; + + while (pch> 2]; + left = (enc & 3) << 4; + mode = 1; + break; + + case 1: // we have two bits + strRet += pbase64[left | (enc >> 4)]; + left = (enc & 15) << 2; + mode = 2; + break; + + case 2: // we have four bits + strRet += pbase64[left | (enc >> 6)]; + strRet += pbase64[enc & 63]; + mode = 0; + break; + } + } + + if (mode) + { + strRet += pbase64[left]; + strRet += '='; + if (mode == 1) + strRet += '='; + } + + return strRet; +} + +string EncodeBase64(const string& str) +{ + return EncodeBase64((const unsigned char*)str.c_str(), str.size()); +} + +vector DecodeBase64(const char* p, bool* pfInvalid) +{ + static const int decode64_table[256] = + { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, + -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }; + + if (pfInvalid) + *pfInvalid = false; + + vector vchRet; + vchRet.reserve(strlen(p)*3/4); + + int mode = 0; + int left = 0; + + while (1) + { + int dec = decode64_table[(unsigned char)*p]; + if (dec == -1) break; + p++; + switch (mode) + { + case 0: // we have no bits and get 6 + left = dec; + mode = 1; + break; + + case 1: // we have 6 bits and keep 4 + vchRet.push_back((left<<2) | (dec>>4)); + left = dec & 15; + mode = 2; + break; + + case 2: // we have 4 bits and get 6, we keep 2 + vchRet.push_back((left<<4) | (dec>>2)); + left = dec & 3; + mode = 3; + break; + + case 3: // we have 2 bits and get 6 + vchRet.push_back((left<<6) | dec); + mode = 0; + break; + } + } + + if (pfInvalid) + switch (mode) + { + case 0: // 4n base64 characters processed: ok + break; + + case 1: // 4n+1 base64 character processed: impossible + *pfInvalid = true; + break; + + case 2: // 4n+2 base64 characters processed: require '==' + if (left || p[0] != '=' || p[1] != '=' || decode64_table[(unsigned char)p[2]] != -1) + *pfInvalid = true; + break; + + case 3: // 4n+3 base64 characters processed: require '=' + if (left || p[0] != '=' || decode64_table[(unsigned char)p[1]] != -1) + *pfInvalid = true; + break; + } + + return vchRet; +} + +string DecodeBase64(const string& str) +{ + vector vchRet = DecodeBase64(str.c_str()); + return string((const char*)&vchRet[0], vchRet.size()); +} + +string EncodeBase32(const unsigned char* pch, size_t len) +{ + static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567"; + + string strRet=""; + strRet.reserve((len+4)/5*8); + + int mode=0, left=0; + const unsigned char *pchEnd = pch+len; + + while (pch> 3]; + left = (enc & 7) << 2; + mode = 1; + break; + + case 1: // we have three bits + strRet += pbase32[left | (enc >> 6)]; + strRet += pbase32[(enc >> 1) & 31]; + left = (enc & 1) << 4; + mode = 2; + break; + + case 2: // we have one bit + strRet += pbase32[left | (enc >> 4)]; + left = (enc & 15) << 1; + mode = 3; + break; + + case 3: // we have four bits + strRet += pbase32[left | (enc >> 7)]; + strRet += pbase32[(enc >> 2) & 31]; + left = (enc & 3) << 3; + mode = 4; + break; + + case 4: // we have two bits + strRet += pbase32[left | (enc >> 5)]; + strRet += pbase32[enc & 31]; + mode = 0; + } + } + + static const int nPadding[5] = {0, 6, 4, 3, 1}; + if (mode) + { + strRet += pbase32[left]; + for (int n=0; n DecodeBase32(const char* p, bool* pfInvalid) +{ + static const int decode32_table[256] = + { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 0, 1, 2, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }; + + if (pfInvalid) + *pfInvalid = false; + + vector vchRet; + vchRet.reserve((strlen(p))*5/8); + + int mode = 0; + int left = 0; + + while (1) + { + int dec = decode32_table[(unsigned char)*p]; + if (dec == -1) break; + p++; + switch (mode) + { + case 0: // we have no bits and get 5 + left = dec; + mode = 1; + break; + + case 1: // we have 5 bits and keep 2 + vchRet.push_back((left<<3) | (dec>>2)); + left = dec & 3; + mode = 2; + break; + + case 2: // we have 2 bits and keep 7 + left = left << 5 | dec; + mode = 3; + break; + + case 3: // we have 7 bits and keep 4 + vchRet.push_back((left<<1) | (dec>>4)); + left = dec & 15; + mode = 4; + break; + + case 4: // we have 4 bits, and keep 1 + vchRet.push_back((left<<4) | (dec>>1)); + left = dec & 1; + mode = 5; + break; + + case 5: // we have 1 bit, and keep 6 + left = left << 5 | dec; + mode = 6; + break; + + case 6: // we have 6 bits, and keep 3 + vchRet.push_back((left<<2) | (dec>>3)); + left = dec & 7; + mode = 7; + break; + + case 7: // we have 3 bits, and keep 0 + vchRet.push_back((left<<5) | dec); + mode = 0; + break; + } + } + + if (pfInvalid) + switch (mode) + { + case 0: // 8n base32 characters processed: ok + break; + + case 1: // 8n+1 base32 characters processed: impossible + case 3: // +3 + case 6: // +6 + *pfInvalid = true; + break; + + case 2: // 8n+2 base32 characters processed: require '======' + if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || p[4] != '=' || p[5] != '=' || decode32_table[(unsigned char)p[6]] != -1) + *pfInvalid = true; + break; + + case 4: // 8n+4 base32 characters processed: require '====' + if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || decode32_table[(unsigned char)p[4]] != -1) + *pfInvalid = true; + break; + + case 5: // 8n+5 base32 characters processed: require '===' + if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || decode32_table[(unsigned char)p[3]] != -1) + *pfInvalid = true; + break; + + case 7: // 8n+7 base32 characters processed: require '=' + if (left || p[0] != '=' || decode32_table[(unsigned char)p[1]] != -1) + *pfInvalid = true; + break; + } + + return vchRet; +} + +string DecodeBase32(const string& str) +{ + vector vchRet = DecodeBase32(str.c_str()); + return string((const char*)&vchRet[0], vchRet.size()); +} + +bool ParseInt32(const std::string& str, int32_t *out) +{ + char *endp = NULL; + errno = 0; // strtol will not set errno if valid + long int n = strtol(str.c_str(), &endp, 10); + if(out) *out = (int)n; + // Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow + // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit + // platforms the size of these types may be different. + return endp && *endp == 0 && !errno && + n >= std::numeric_limits::min() && + n <= std::numeric_limits::max(); +} + +std::string FormatParagraph(const std::string in, size_t width, size_t indent) +{ + std::stringstream out; + size_t col = 0; + size_t ptr = 0; + while(ptr < in.size()) + { + // Find beginning of next word + ptr = in.find_first_not_of(' ', ptr); + if (ptr == std::string::npos) + break; + // Find end of next word + size_t endword = in.find_first_of(' ', ptr); + if (endword == std::string::npos) + endword = in.size(); + // Add newline and indentation if this wraps over the allowed width + if (col > 0) + { + if ((col + endword - ptr) > width) + { + out << '\n'; + for(size_t i=0; i +#include +#include + +#define BEGIN(a) ((char*)&(a)) +#define END(a) ((char*)&((&(a))[1])) +#define UBEGIN(a) ((unsigned char*)&(a)) +#define UEND(a) ((unsigned char*)&((&(a))[1])) +#define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0])) + +// This is needed because the foreach macro can't get over the comma in pair +#define PAIRTYPE(t1, t2) std::pair + +std::string SanitizeString(const std::string& str); +std::vector ParseHex(const char* psz); +std::vector ParseHex(const std::string& str); +signed char HexDigit(char c); +bool IsHex(const std::string& str); +std::vector DecodeBase64(const char* p, bool* pfInvalid = NULL); +std::string DecodeBase64(const std::string& str); +std::string EncodeBase64(const unsigned char* pch, size_t len); +std::string EncodeBase64(const std::string& str); +std::vector DecodeBase32(const char* p, bool* pfInvalid = NULL); +std::string DecodeBase32(const std::string& str); +std::string EncodeBase32(const unsigned char* pch, size_t len); +std::string EncodeBase32(const std::string& str); + +std::string i64tostr(int64_t n); +std::string itostr(int n); +int64_t atoi64(const char* psz); +int64_t atoi64(const std::string& str); +int atoi(const std::string& str); + +/** + * Convert string to signed 32-bit integer with strict parse error feedback. + * @returns true if the entire string could be parsed as valid integer, + * false if not the entire string could be parsed or when overflow or underflow occured. + */ +bool ParseInt32(const std::string& str, int32_t *out); + +template +std::string HexStr(const T itbegin, const T itend, bool fSpaces=false) +{ + std::string rv; + static const char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + rv.reserve((itend-itbegin)*3); + for(T it = itbegin; it < itend; ++it) + { + unsigned char val = (unsigned char)(*it); + if(fSpaces && it != itbegin) + rv.push_back(' '); + rv.push_back(hexmap[val>>4]); + rv.push_back(hexmap[val&15]); + } + + return rv; +} + +template +inline std::string HexStr(const T& vch, bool fSpaces=false) +{ + return HexStr(vch.begin(), vch.end(), fSpaces); +} + +/** Format a paragraph of text to a fixed width, adding spaces for + * indentation to any added line. + */ +std::string FormatParagraph(const std::string in, size_t width=79, size_t indent=0); + +/** + * Timing-attack-resistant comparison. + * Takes time proportional to length + * of first argument. + */ +template +bool TimingResistantEqual(const T& a, const T& b) +{ + if (b.size() == 0) return a.size() == 0; + size_t accumulator = a.size() ^ b.size(); + for (size_t i = 0; i < a.size(); i++) + accumulator |= a[i] ^ b[i%b.size()]; + return accumulator == 0; +} + +#endif // BITCOIN_UTILSTRENCODINGS_H diff --git a/src/utiltime.cpp b/src/utiltime.cpp new file mode 100644 index 00000000000..78f0342cbab --- /dev/null +++ b/src/utiltime.cpp @@ -0,0 +1,66 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#if defined(HAVE_CONFIG_H) +#include "config/bitcoin-config.h" +#endif + +#include "utiltime.h" + +#include +#include + +using namespace std; + +static int64_t nMockTime = 0; // For unit testing + +int64_t GetTime() +{ + if (nMockTime) return nMockTime; + + return time(NULL); +} + +void SetMockTime(int64_t nMockTimeIn) +{ + nMockTime = nMockTimeIn; +} + +int64_t GetTimeMillis() +{ + return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) - + boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds(); +} + +int64_t GetTimeMicros() +{ + return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) - + boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds(); +} + +void MilliSleep(int64_t n) +{ +// Boost's sleep_for was uninterruptable when backed by nanosleep from 1.50 +// until fixed in 1.52. Use the deprecated sleep method for the broken case. +// See: https://svn.boost.org/trac/boost/ticket/7238 +#if defined(HAVE_WORKING_BOOST_SLEEP_FOR) + boost::this_thread::sleep_for(boost::chrono::milliseconds(n)); +#elif defined(HAVE_WORKING_BOOST_SLEEP) + boost::this_thread::sleep(boost::posix_time::milliseconds(n)); +#else +//should never get here +#error missing boost sleep implementation +#endif +} + +std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime) +{ + // std::locale takes ownership of the pointer + std::locale loc(std::locale::classic(), new boost::posix_time::time_facet(pszFormat)); + std::stringstream ss; + ss.imbue(loc); + ss << boost::posix_time::from_time_t(nTime); + return ss.str(); +} diff --git a/src/utiltime.h b/src/utiltime.h new file mode 100644 index 00000000000..500ae4dab97 --- /dev/null +++ b/src/utiltime.h @@ -0,0 +1,20 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_UTILTIME_H +#define BITCOIN_UTILTIME_H + +#include +#include + +int64_t GetTime(); +int64_t GetTimeMillis(); +int64_t GetTimeMicros(); +void SetMockTime(int64_t nMockTimeIn); +void MilliSleep(int64_t n); + +std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime); + +#endif diff --git a/src/wallet.cpp b/src/wallet.cpp index ee4793b3f18..91f7eaa560a 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -10,8 +10,11 @@ #include "coincontrol.h" #include "net.h" #include "timedata.h" +#include "util.h" +#include "utilmoneystr.h" #include +#include using namespace std; @@ -37,6 +40,11 @@ struct CompareValueOnly } }; +std::string COutput::ToString() const +{ + return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->vout[i].nValue).c_str()); +} + const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const { LOCK(cs_wallet); diff --git a/src/wallet.h b/src/wallet.h index 7cbbb2a6ed6..bdb02647293 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -11,7 +11,6 @@ #include "keystore.h" #include "main.h" #include "ui_interface.h" -#include "util.h" #include "walletdb.h" #include @@ -812,10 +811,7 @@ public: tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; } - std::string ToString() const - { - return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->vout[i].nValue).c_str()); - } + std::string ToString() const; }; diff --git a/src/walletdb.cpp b/src/walletdb.cpp index a95baf83d0d..2fa60716585 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -9,10 +9,13 @@ #include "protocol.h" #include "serialize.h" #include "sync.h" +#include "utiltime.h" +#include "util.h" #include "wallet.h" #include #include +#include using namespace std; using namespace boost;