diff options
author | Pieter Wuille <pieter.wuille@gmail.com> | 2014-08-26 16:52:58 +0200 |
---|---|---|
committer | Pieter Wuille <pieter.wuille@gmail.com> | 2014-08-26 16:57:05 +0200 |
commit | 3da58b216b5726461b45685aa99cab9deb78c6fd (patch) | |
tree | 6c5b2a258ba5e80e30b23fea85fc3d23934bbcc9 /src | |
parent | 727298cef34005c523117adbb2249c8df2c7f89d (diff) | |
parent | ad49c256c33bfe4088fd3c7ecb7d28cb81a8fc70 (diff) |
Merge pull request #4748
ad49c25 Split up util.cpp/h (Wladimir J. van der Laan)
f841aa2 Move `COIN` and `CENT` to core.h (Wladimir J. van der Laan)
6e5fd00 Move `*Version()` functions to version.h/cpp (Wladimir J. van der Laan)
b4aa769 Move `S_I*` constants and `MSG_NOSIGNAL` to compat.h (Wladimir J. van der Laan)
af8297c Move functions in wallet.h to implementation file (Wladimir J. van der Laan)
651480c move functions in main and net to implementation files (Wladimir J. van der Laan)
610a8c0 Move SetThreadPriority implementation to util.cpp instead of the header (Wladimir J. van der Laan)
f780e65 Remove unused function `ByteReverse` from util.h (Wladimir J. van der Laan)
121d6ad Remove unused `alignup` function from util.h (Wladimir J. van der Laan)
d1e26d4 Move CMedianFilter to timedata.cpp (Wladimir J. van der Laan)
Diffstat (limited to 'src')
66 files changed, 1294 insertions, 1131 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 6c67dee7d5..655bfc88c3 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/Makefile.test.include b/src/Makefile.test.include index cc407f679f..b4360831bb 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/alert.cpp b/src/alert.cpp index 2cd684cc4c..3271ecfbfd 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -19,6 +19,7 @@ #include <boost/algorithm/string/classification.hpp> #include <boost/algorithm/string/replace.hpp> #include <boost/foreach.hpp> +#include <boost/thread.hpp> using namespace std; diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 0609adcab3..871aaf93df 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -8,6 +8,8 @@ #include "rpcclient.h" #include "rpcprotocol.h" #include "chainparamsbase.h" +#include "utilstrencodings.h" +#include "version.h" #include <boost/filesystem/operations.hpp> diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 6cd2768d70..75f0fb69f2 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 880955481b..5be8708979 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -12,6 +12,7 @@ #include <boost/algorithm/string/predicate.hpp> #include <boost/filesystem.hpp> +#include <boost/thread.hpp> /* Introduction text for doxygen: */ diff --git a/src/compat.h b/src/compat.h index 52c7817130..4fc28a36e0 100644 --- a/src/compat.h +++ b/src/compat.h @@ -59,4 +59,29 @@ 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 +#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/core.h b/src/core.h index 9552f70254..e3ceac97aa 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/core_write.cpp b/src/core_write.cpp index 37dd69f7b8..b395b5c090 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 122e06d97e..8aa2bb0517 100644 --- a/src/crypter.cpp +++ b/src/crypter.cpp @@ -5,6 +5,7 @@ #include "crypter.h" #include "script.h" +#include "util.h" #include <string> #include <vector> diff --git a/src/db.cpp b/src/db.cpp index eb40f3cc40..8c139843a1 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 <stdint.h> @@ -17,6 +18,7 @@ #endif #include <boost/filesystem.hpp> +#include <boost/thread.hpp> #include <boost/version.hpp> #include <openssl/rand.h> diff --git a/src/init.cpp b/src/init.cpp index 708e6386aa..e972413c4b 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 <boost/algorithm/string/predicate.hpp> #include <boost/filesystem.hpp> #include <boost/interprocess/sync/file_lock.hpp> +#include <boost/thread.hpp> #include <openssl/crypto.h> using namespace boost; diff --git a/src/keystore.cpp b/src/keystore.cpp index 2a4c88d565..c6322eadce 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 <boost/foreach.hpp> diff --git a/src/main.cpp b/src/main.cpp index 1c9b3f861b..6567c77e93 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,6 +24,7 @@ #include <boost/algorithm/string/replace.hpp> #include <boost/filesystem.hpp> #include <boost/filesystem/fstream.hpp> +#include <boost/thread.hpp> using namespace std; using namespace boost; @@ -4655,7 +4656,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 f93b78d8e5..e5357cbfdd 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/miner.cpp b/src/miner.cpp index 06acff1c33..8696edcf6e 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 <inttypes.h> - #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 <boost/thread.hpp> + using namespace std; ////////////////////////////////////////////////////////////////////////////// diff --git a/src/net.cpp b/src/net.cpp index cae9b70da7..e2adba8517 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -28,6 +28,7 @@ #endif #include <boost/filesystem.hpp> +#include <boost/thread.hpp> // Dump addresses to peers.dat every 15 minutes (900s) #define DUMP_ADDRESSES_INTERVAL 900 @@ -2037,3 +2038,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<CInv, int64_t>::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<CSerializeData>::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); +} @@ -16,7 +16,7 @@ #include "random.h" #include "sync.h" #include "uint256.h" -#include "util.h" +#include "utilstrencodings.h" #include <deque> #include <stdint.h> @@ -25,6 +25,7 @@ #include <arpa/inet.h> #endif +#include <boost/filesystem/path.hpp> #include <boost/foreach.hpp> #include <boost/signals2/signal.hpp> @@ -51,8 +52,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 +301,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 +391,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<CInv, int64_t>::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<CSerializeData>::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(); diff --git a/src/netbase.cpp b/src/netbase.cpp index e9207da330..d5821d4465 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 <netdb.h> @@ -27,6 +28,7 @@ #include <boost/algorithm/string/case_conv.hpp> // for to_lower() #include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith() +#include <boost/thread.hpp> #if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL) #define MSG_NOSIGNAL 0 diff --git a/src/noui.cpp b/src/noui.cpp index 32c861b0d9..8b00fd4057 100644 --- a/src/noui.cpp +++ b/src/noui.cpp @@ -8,6 +8,7 @@ #include "ui_interface.h" #include "util.h" +#include <cstdio> #include <stdint.h> #include <string> diff --git a/src/pow.cpp b/src/pow.cpp index c0d0a7ca20..b091cbec3d 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 a43e7cb756..12277a8ad0 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -33,6 +33,7 @@ #include <stdint.h> #include <boost/filesystem/operations.hpp> +#include <boost/thread.hpp> #include <QApplication> #include <QDebug> #include <QLibraryInfo> diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index bfca5e8d1a..d0a5ff13c3 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 <iostream> diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 4c21eb5594..9c9ff5b3a1 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 <stdint.h> diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index fd1d446f9b..c775a7f8d6 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -21,6 +21,7 @@ #include "wallet.h" // for CWallet::minTxFee #endif +#include <boost/thread.hpp> #include <QDir> #include <QIntValidator> #include <QLocale> diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index a9f1566d62..f6a4b599de 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 <cstdlib> diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 4f6e3169f5..8258e719a3 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 <stdint.h> diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index 5fb0da145d..7df9d1bc2d 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -10,9 +10,10 @@ #include "clientmodel.h" #include "guiutil.h" -#include "clientversion.h" #include "init.h" -#include "util.h" +#include "version.h" + +#include <stdio.h> #include <QLabel> #include <QRegExp> diff --git a/src/random.cpp b/src/random.cpp index 0d20d205ac..22c942acc0 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 <sys/time.h> #endif - +#include <limits> #include <openssl/crypto.h> #include <openssl/err.h> #include <openssl/rand.h> diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index e511fe4222..58cab14045 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 <stdint.h> diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index ff2361482b..e68ddee040 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 <fstream> diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index edab427cbf..6e508abcda 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 643208b3b6..808b9bbd2a 100644 --- a/src/rpcprotocol.cpp +++ b/src/rpcprotocol.cpp @@ -6,6 +6,10 @@ #include "rpcprotocol.h" #include "util.h" +#include "tinyformat.h" +#include "utilstrencodings.h" +#include "utiltime.h" +#include "version.h" #include <stdint.h> diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 524627e2de..c9133bd3d2 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -23,6 +23,7 @@ #include <boost/iostreams/concepts.hpp> #include <boost/iostreams/stream.hpp> #include <boost/shared_ptr.hpp> +#include <boost/thread.hpp> #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 d6d6684f44..28c50a1358 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -18,8 +18,9 @@ #include "util.h" #include <boost/foreach.hpp> -#include <boost/tuple/tuple.hpp> +#include <boost/thread.hpp> #include <boost/tuple/tuple_comparison.hpp> +#include <boost/tuple/tuple.hpp> using namespace std; using namespace boost; diff --git a/src/script.h b/src/script.h index 1e2cc94efe..462e3f2302 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 <stdexcept> #include <stdint.h> diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 5e17555e7a..4ecf6e2535 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 <stdint.h> diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp index e3066a51ab..4af87cf8ef 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 <fstream> diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp index 2752a0b215..69888da3df 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/test/unit_test.hpp> BOOST_AUTO_TEST_SUITE(allocator_tests) diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp index 87473585e3..68617abbdd 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 <boost/test/unit_test.hpp> diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp index d4a23d9aa0..f2bf3326ad 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 <boost/test/unit_test.hpp> diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp index 10352240f4..fdea12846a 100644 --- a/src/test/checkblock_tests.cpp +++ b/src/test/checkblock_tests.cpp @@ -9,6 +9,7 @@ #include "main.h" +#include "utiltime.h" #include <cstdio> diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index a17278b803..a3eec270ee 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 <vector> diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp index 4568c8769b..b8e290f071 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 <vector> diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 443b5853b2..68fad8d038 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -16,6 +16,7 @@ #include <boost/filesystem.hpp> #include <boost/test/unit_test.hpp> +#include <boost/thread.hpp> CClientUIInterface uiInterface; CWallet* pwalletMain; diff --git a/src/test/timedata_tests.cpp b/src/test/timedata_tests.cpp new file mode 100644 index 0000000000..aa4fa0d500 --- /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 <boost/test/unit_test.hpp> + +using namespace std; + +BOOST_AUTO_TEST_SUITE(timedata_tests) + +BOOST_AUTO_TEST_CASE(util_MedianFilter) +{ + CMedianFilter<int> 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 068b9f29c8..e077c9de3b 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 <stdint.h> #include <vector> @@ -36,31 +39,6 @@ BOOST_AUTO_TEST_CASE(util_criticalsection) } while(0); } -BOOST_AUTO_TEST_CASE(util_MedianFilter) -{ - CMedianFilter<int> 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.cpp b/src/timedata.cpp index 4576786b96..40cdb33f7a 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 <boost/foreach.hpp> @@ -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/timedata.h b/src/timedata.h index 0e7bdc2c1f..d0c84b3183 100644 --- a/src/timedata.h +++ b/src/timedata.h @@ -6,9 +6,68 @@ #define BITCOIN_TIMEDATA_H #include <stdint.h> +#include <vector> +#include <algorithm> +#include <assert.h> class CNetAddr; +/** Median filter over a stream of values. + * Returns the median of the last N numbers + */ +template <typename T> class CMedianFilter +{ +private: + std::vector<T> vValues; + std::vector<T> 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<T> sorted () const + { + return vSorted; + } +}; + /* Functions to keep track of adjusted P2P time */ int64_t GetTimeOffset(); int64_t GetAdjustedTime(); diff --git a/src/tinyformat.h b/src/tinyformat.h index 929cb66e4d..73d49a1fe4 100644 --- a/src/tinyformat.h +++ b/src/tinyformat.h @@ -121,6 +121,7 @@ namespace tfm = tinyformat; #include <cassert> #include <iostream> #include <sstream> +#include <stdexcept> #ifndef TINYFORMAT_ERROR # define TINYFORMAT_ERROR(reason) assert(0 && reason) diff --git a/src/txdb.cpp b/src/txdb.cpp index 2349514def..d4c6007558 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -9,6 +9,7 @@ #include "pow.h" #include "uint256.h" +#include <boost/thread.hpp> #include <stdint.h> using namespace std; diff --git a/src/txmempool.cpp b/src/txmempool.cpp index f75e2212d5..8af1f1c91b 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -5,6 +5,7 @@ #include "core.h" #include "txmempool.h" +#include "util.h" #include <boost/circular_buffer.hpp> diff --git a/src/uint256.cpp b/src/uint256.cpp index 08c05594fd..feda0ca5a9 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 <stdio.h> #include <string.h> diff --git a/src/util.cpp b/src/util.cpp index ae2145a3a0..5a4e187f9e 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -11,14 +11,13 @@ #include "chainparamsbase.h" #include "random.h" +#include "serialize.h" #include "sync.h" -#include "uint256.h" -#include "version.h" +#include "utilstrencodings.h" +#include "utiltime.h" #include <stdarg.h> -#include <boost/date_time/posix_time/posix_time.hpp> - #ifndef WIN32 // for posix_fallocate #ifdef __linux__ @@ -76,6 +75,7 @@ #include <boost/foreach.hpp> #include <boost/program_options/detail/config_file.hpp> #include <boost/program_options/parsers.hpp> +#include <boost/thread.hpp> #include <openssl/crypto.h> #include <openssl/rand.h> @@ -244,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<unsigned char> ParseHex(const char* psz) -{ - // convert hex dump to vector - vector<unsigned char> 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<unsigned char> ParseHex(const string& str) -{ - return ParseHex(str.c_str()); -} - static void InterpretNegativeSetting(string name, map<string, string>& mapSettingsRet) { // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set @@ -483,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<pchEnd) - { - int enc = *(pch++); - switch (mode) - { - case 0: // we have no bits - strRet += pbase64[enc >> 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<unsigned char> 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<unsigned char> 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<unsigned char> 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<pchEnd) - { - int enc = *(pch++); - switch (mode) - { - case 0: // we have no bits - strRet += pbase32[enc >> 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<nPadding[mode]; n++) - strRet += '='; - } - - return strRet; -} - -string EncodeBase32(const string& str) -{ - return EncodeBase32((const unsigned char*)str.c_str(), str.size()); -} - -vector<unsigned char> 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<unsigned char> 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<unsigned char> 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 @@ -1102,45 +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; -} - -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<std::string>& 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) { @@ -1211,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<int32_t>::min() && - n <= std::numeric_limits<int32_t>::max(); -} - void SetupEnvironment() { #ifndef WIN32 @@ -1242,47 +719,15 @@ void SetupEnvironment() #endif } -std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime) +void SetThreadPriority(int nPriority) { - // 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<indent; ++i) - out << ' '; - col = 0; - } else - out << ' '; - } - // Append word - out << in.substr(ptr, endword - ptr); - col += endword - ptr; - ptr = endword; - } - return out.str(); +#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 1fb42a7b7e..30f7c15c89 100644 --- a/src/util.h +++ b/src/util.h @@ -3,6 +3,10 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +/** + * Server/client environment: argument handling, config file parsing, + * logging, thread wrappers + */ #ifndef BITCOIN_UTIL_H #define BITCOIN_UTIL_H @@ -11,84 +15,17 @@ #endif #include "compat.h" -#include "serialize.h" +#include "utiltime.h" #include "tinyformat.h" -#include <cstdio> #include <exception> #include <map> -#include <stdarg.h> #include <stdint.h> #include <string> -#include <utility> #include <vector> -#ifndef WIN32 -#include <sys/resource.h> -#include <sys/time.h> -#include <sys/types.h> -#endif - #include <boost/filesystem/path.hpp> -#include <boost/thread.hpp> - -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)) -#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<t1, t2> -#define PAIRTYPE(t1, t2) std::pair<t1, t2> - -// Align by increasing pointer, must have extra space at end of buffer -template <size_t nBytes, typename T> -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 - -#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) -{ -// 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 <boost/thread/exceptions.hpp> extern std::map<std::string, std::string> mapArgs; extern std::map<std::string, std::vector<std::string> > mapMultiArgs; @@ -146,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<unsigned char> ParseHex(const char* psz); -std::vector<unsigned char> ParseHex(const std::string& str); -signed char HexDigit(char c); -bool IsHex(const std::string& str); -std::vector<unsigned char> 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<unsigned char> 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); @@ -182,111 +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); -std::string FormatFullVersion(); -std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments); 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<typename T> -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<typename T> -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 @@ -341,113 +159,9 @@ 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 <typename T> -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; -} - -/** Median filter over a stream of values. - * Returns the median of the last N numbers - */ -template <typename T> class CMedianFilter -{ -private: - std::vector<T> vValues; - std::vector<T> 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<T> sorted () const - { - return vSorted; - } -}; - -#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); -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: diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp new file mode 100644 index 0000000000..1bd48d8d4c --- /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 0000000000..f0c61aa138 --- /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 <stdint.h> +#include <string> + +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 0000000000..ef13555104 --- /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 <boost/foreach.hpp> +#include <errno.h> +#include <limits> + +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<unsigned char> ParseHex(const char* psz) +{ + // convert hex dump to vector + vector<unsigned char> 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<unsigned char> 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<pchEnd) + { + int enc = *(pch++); + switch (mode) + { + case 0: // we have no bits + strRet += pbase64[enc >> 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<unsigned char> 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<unsigned char> 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<unsigned char> 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<pchEnd) + { + int enc = *(pch++); + switch (mode) + { + case 0: // we have no bits + strRet += pbase32[enc >> 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<nPadding[mode]; n++) + strRet += '='; + } + + return strRet; +} + +string EncodeBase32(const string& str) +{ + return EncodeBase32((const unsigned char*)str.c_str(), str.size()); +} + +vector<unsigned char> 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<unsigned char> 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<unsigned char> 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<int32_t>::min() && + n <= std::numeric_limits<int32_t>::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<indent; ++i) + out << ' '; + col = 0; + } else + out << ' '; + } + // Append word + out << in.substr(ptr, endword - ptr); + col += endword - ptr; + ptr = endword; + } + return out.str(); +} + +std::string i64tostr(int64_t n) +{ + return strprintf("%d", n); +} + +std::string itostr(int n) +{ + return strprintf("%d", n); +} + +int64_t atoi64(const char* psz) +{ +#ifdef _MSC_VER + return _atoi64(psz); +#else + return strtoll(psz, NULL, 10); +#endif +} + +int64_t atoi64(const std::string& str) +{ +#ifdef _MSC_VER + return _atoi64(str.c_str()); +#else + return strtoll(str.c_str(), NULL, 10); +#endif +} + +int atoi(const std::string& str) +{ + return atoi(str.c_str()); +} diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h new file mode 100644 index 0000000000..0b8c1a1781 --- /dev/null +++ b/src/utilstrencodings.h @@ -0,0 +1,97 @@ +// 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. + +/** + * Utilities for converting data from/to strings. + */ +#ifndef BITCOIN_UTILSTRENCODINGS_H +#define BITCOIN_UTILSTRENCODINGS_H + +#include <stdint.h> +#include <string> +#include <vector> + +#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<t1, t2> +#define PAIRTYPE(t1, t2) std::pair<t1, t2> + +std::string SanitizeString(const std::string& str); +std::vector<unsigned char> ParseHex(const char* psz); +std::vector<unsigned char> ParseHex(const std::string& str); +signed char HexDigit(char c); +bool IsHex(const std::string& str); +std::vector<unsigned char> 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<unsigned char> 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<typename T> +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<typename T> +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 <typename T> +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 0000000000..78f0342cba --- /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 <boost/date_time/posix_time/posix_time.hpp> +#include <boost/thread.hpp> + +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 0000000000..500ae4dab9 --- /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 <stdint.h> +#include <string> + +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/version.cpp b/src/version.cpp index d86caa3ac2..8311041ed2 100644 --- a/src/version.cpp +++ b/src/version.cpp @@ -4,7 +4,10 @@ #include "version.h" +#include "tinyformat.h" + #include <string> +#include <boost/algorithm/string/join.hpp> // 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<std::string>& 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 fbb731c91d..3a6c0f3719 100644 --- a/src/version.h +++ b/src/version.h @@ -7,6 +7,7 @@ #include "clientversion.h" #include <string> +#include <vector> // // 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<std::string>& comments); + #endif diff --git a/src/wallet.cpp b/src/wallet.cpp index 7c04743c0f..91f7eaa560 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 <boost/algorithm/string/replace.hpp> +#include <boost/thread.hpp> 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); @@ -2168,3 +2176,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 34c699e979..bdb0264729 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 <algorithm> @@ -61,16 +60,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 ( @@ -820,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; }; @@ -840,11 +828,7 @@ public: //// todo: add something to note what created it (user, getnewaddress, change) //// maybe should have a map<string, string> property map - CWalletKey(int64_t nExpires=0) - { - nTimeCreated = (nExpires ? GetTime() : 0); - nTimeExpires = nExpires; - } + CWalletKey(int64_t nExpires=0); IMPLEMENT_SERIALIZE ( diff --git a/src/walletdb.cpp b/src/walletdb.cpp index a95baf83d0..2fa6071658 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 <boost/filesystem.hpp> #include <boost/foreach.hpp> +#include <boost/thread.hpp> using namespace std; using namespace boost; |