diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/Makefile.test.include | 1 | ||||
-rw-r--r-- | src/base58.cpp | 4 | ||||
-rw-r--r-- | src/checkpoints.cpp | 7 | ||||
-rw-r--r-- | src/checkpoints.h | 7 | ||||
-rw-r--r-- | src/init.h | 2 | ||||
-rw-r--r-- | src/key.cpp | 3 | ||||
-rw-r--r-- | src/main.cpp | 121 | ||||
-rw-r--r-- | src/main.h | 13 | ||||
-rw-r--r-- | src/net.h | 3 | ||||
-rw-r--r-- | src/qt/utilitydialog.cpp | 1 | ||||
-rw-r--r-- | src/rpcblockchain.cpp | 2 | ||||
-rw-r--r-- | src/rpcmining.cpp | 2 | ||||
-rw-r--r-- | src/rpcnet.cpp | 1 | ||||
-rw-r--r-- | src/rpcprotocol.cpp | 42 | ||||
-rw-r--r-- | src/rpcprotocol.h | 2 | ||||
-rw-r--r-- | src/rpcserver.cpp | 18 | ||||
-rw-r--r-- | src/rpcserver.h | 1 | ||||
-rw-r--r-- | src/script.cpp | 5 | ||||
-rw-r--r-- | src/test/skiplist_tests.cpp | 45 | ||||
-rw-r--r-- | src/uint256.cpp | 292 | ||||
-rw-r--r-- | src/uint256.h | 262 | ||||
-rw-r--r-- | src/util.cpp | 8 | ||||
-rw-r--r-- | src/util.h | 1 |
24 files changed, 540 insertions, 304 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 3643e60201..9c7b294d35 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -192,6 +192,7 @@ libbitcoin_util_a_SOURCES = \ chainparamsbase.cpp \ rpcprotocol.cpp \ sync.cpp \ + uint256.cpp \ util.cpp \ version.cpp \ compat/glibc_sanity.cpp \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 4dab1773f4..8685452c7b 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -47,6 +47,7 @@ BITCOIN_TESTS =\ test/script_tests.cpp \ test/serialize_tests.cpp \ test/sigopcount_tests.cpp \ + test/skiplist_tests.cpp \ test/test_bitcoin.cpp \ test/transaction_tests.cpp \ test/uint256_tests.cpp \ diff --git a/src/base58.cpp b/src/base58.cpp index 1bd64684e5..c9e91beef1 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -186,6 +186,7 @@ int CBase58Data::CompareTo(const CBase58Data& b58) const { } namespace { + class CBitcoinAddressVisitor : public boost::static_visitor<bool> { private: CBitcoinAddress *addr; @@ -196,7 +197,8 @@ namespace { bool operator()(const CScriptID &id) const { return addr->Set(id); } bool operator()(const CNoDestination &no) const { return false; } }; -}; + +} // anon namespace bool CBitcoinAddress::Set(const CKeyID &id) { SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20); diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 75ac418916..80479b47fb 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -12,8 +12,8 @@ #include <boost/assign/list_of.hpp> // for 'map_list_of()' #include <boost/foreach.hpp> -namespace Checkpoints -{ +namespace Checkpoints { + typedef std::map<int, uint256> MapCheckpoints; // How many times we expect transactions after the last checkpoint to @@ -161,4 +161,5 @@ namespace Checkpoints } return NULL; } -} + +} // namespace Checkpoints diff --git a/src/checkpoints.h b/src/checkpoints.h index 1b4aacee20..2cf8d41b9d 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -13,8 +13,8 @@ class uint256; /** Block-chain checkpoints are compiled-in sanity checks. * They are updated every release or three. */ -namespace Checkpoints -{ +namespace Checkpoints { + // Returns true if block passes checkpoint checks bool CheckBlock(int nHeight, const uint256& hash); @@ -27,6 +27,7 @@ namespace Checkpoints double GuessVerificationProgress(CBlockIndex *pindex, bool fSigchecks = true); extern bool fEnabled; -} + +} //namespace Checkpoints #endif diff --git a/src/init.h b/src/init.h index 52daa47616..626525c9ad 100644 --- a/src/init.h +++ b/src/init.h @@ -12,7 +12,7 @@ class CWallet; namespace boost { class thread_group; -}; +} // namespace boost extern CWallet* pwalletMain; diff --git a/src/key.cpp b/src/key.cpp index 96b1ac439c..784085da34 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -377,8 +377,7 @@ const unsigned char vchMaxModHalfOrder[32] = { const unsigned char vchZero[0] = {}; - -}; // end of anonymous namespace +} // anon namespace bool CKey::Check(const unsigned char *vch) { return CompareBigEndian(vch, 32, vchZero, 0) > 0 && diff --git a/src/main.cpp b/src/main.cpp index df810f575f..04d9523e26 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -73,6 +73,7 @@ const string strMessageMagic = "Bitcoin Signed Message:\n"; // Internal stuff namespace { + struct CBlockIndexWorkComparator { bool operator()(CBlockIndex *pa, CBlockIndex *pb) { @@ -121,7 +122,8 @@ namespace { }; map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight; map<uint256, pair<NodeId, list<uint256>::iterator> > mapBlocksToDownload; -} + +} // anon namespace // Forward reference functions defined here: static const unsigned int MAX_DOUBLESPEND_BLOOM = 1000; @@ -135,6 +137,7 @@ static void RelayDoubleSpend(const COutPoint& outPoint, const CTransaction& doub // These functions dispatch to one or all registered wallets namespace { + struct CMainSignals { // Notifies listeners of updated transaction data (transaction, and optionally the block it is found in. boost::signals2::signal<void (const CTransaction &, const CBlock *)> SyncTransaction; @@ -155,7 +158,8 @@ struct CMainSignals { // then the double-spend simply fails when we try to lookup the inputs in the current UTXO set. boost::signals2::signal<void (const COutPoint&, const CTransaction&, bool)> DetectedDoubleSpend; } g_signals; -} + +} // anon namespace void RegisterInternalSignals() { static CBloomFilter doubleSpendFilter; @@ -223,6 +227,10 @@ struct CNodeState { std::string name; // List of asynchronously-determined block rejections to notify this peer about. std::vector<CBlockReject> rejects; + // The best known block we know this peer has announced. + CBlockIndex *pindexBestKnownBlock; + // The hash of the last unknown block this peer has announced. + uint256 hashLastUnknownBlock; list<QueuedBlock> vBlocksInFlight; int nBlocksInFlight; list<uint256> vBlocksToDownload; @@ -233,6 +241,8 @@ struct CNodeState { CNodeState() { nMisbehavior = 0; fShouldBan = false; + pindexBestKnownBlock = NULL; + hashLastUnknownBlock = uint256(0); nBlocksToDownload = 0; nBlocksInFlight = 0; nLastBlockReceive = 0; @@ -294,7 +304,6 @@ void MarkBlockAsReceived(const uint256 &hash, NodeId nodeFrom = -1) { state->nLastBlockReceive = GetTimeMicros(); mapBlocksInFlight.erase(itInFlight); } - } // Requires cs_main. @@ -330,14 +339,48 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256 &hash) { mapBlocksInFlight[hash] = std::make_pair(nodeid, it); } +/** Check whether the last unknown block a peer advertized is not yet known. */ +void ProcessBlockAvailability(NodeId nodeid) { + CNodeState *state = State(nodeid); + assert(state != NULL); + + if (state->hashLastUnknownBlock != 0) { + map<uint256, CBlockIndex*>::iterator itOld = mapBlockIndex.find(state->hashLastUnknownBlock); + if (itOld != mapBlockIndex.end() && itOld->second->nChainWork > 0) { + if (state->pindexBestKnownBlock == NULL || itOld->second->nChainWork >= state->pindexBestKnownBlock->nChainWork) + state->pindexBestKnownBlock = itOld->second; + state->hashLastUnknownBlock = uint256(0); + } + } +} + +/** Update tracking information about which blocks a peer is assumed to have. */ +void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) { + CNodeState *state = State(nodeid); + assert(state != NULL); + + ProcessBlockAvailability(nodeid); + + map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(hash); + if (it != mapBlockIndex.end() && it->second->nChainWork > 0) { + // An actually better block was announced. + if (state->pindexBestKnownBlock == NULL || it->second->nChainWork >= state->pindexBestKnownBlock->nChainWork) + state->pindexBestKnownBlock = it->second; + } else { + // An unknown block was announced; just assume that the latest one is the best one. + state->hashLastUnknownBlock = hash; + } } +} // anon namespace + bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) { LOCK(cs_main); CNodeState *state = State(nodeid); if (state == NULL) return false; stats.nMisbehavior = state->nMisbehavior; + stats.nSyncHeight = state->pindexBestKnownBlock ? state->pindexBestKnownBlock->nHeight : -1; return true; } @@ -391,8 +434,11 @@ CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const { break; // Exponentially larger steps back, plus the genesis block. int nHeight = std::max(pindex->nHeight - nStep, 0); + // Jump back quickly to the same height as the chain. + if (pindex->nHeight > nHeight) + pindex = pindex->GetAncestor(nHeight); // In case pindex is not in this chain, iterate pindex->pprev to find blocks. - while (pindex->nHeight > nHeight && !Contains(pindex)) + while (!Contains(pindex)) pindex = pindex->pprev; // If pindex is in this chain, use direct height-based access. if (pindex->nHeight > nHeight) @@ -419,6 +465,8 @@ CBlockIndex *CChain::FindFork(const CBlockLocator &locator) const { } CBlockIndex *CChain::FindFork(CBlockIndex *pindex) const { + if (pindex->nHeight > Height()) + pindex = pindex->GetAncestor(Height()); while (pindex && !Contains(pindex)) pindex = pindex->pprev; return pindex; @@ -508,7 +556,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason) // Treat non-final transactions as non-standard to prevent a specific type // of double-spend attack, as well as DoS attacks. (if the transaction // can't be mined, the attacker isn't expending resources broadcasting it) - // Basically we don't want to propagate transactions that can't included in + // Basically we don't want to propagate transactions that can't be included in // the next block. // // However, IsFinalTx() is confusing... Without arguments, it uses @@ -541,7 +589,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason) { // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed // keys. (remember the 520 byte limit on redeemScript size) That works - // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)=1624 + // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627 // bytes of scriptSig, which we round off to 1650 bytes for some minor // future-proofing. That's also enough to spend a 20-of-20 // CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not @@ -2178,6 +2226,7 @@ CBlockIndex* AddToBlockIndex(CBlockHeader& block) { pindexNew->pprev = (*miPrev).second; pindexNew->nHeight = pindexNew->pprev->nHeight + 1; + pindexNew->BuildSkip(); } pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + pindexNew->GetBlockWork(); pindexNew->RaiseValidity(BLOCK_VALID_TREE); @@ -2535,6 +2584,55 @@ bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, uns return (nFound >= nRequired); } +/** Turn the lowest '1' bit in the binary representation of a number into a '0'. */ +int static inline InvertLowestOne(int n) { return n & (n - 1); } + +/** Compute what height to jump back to with the CBlockIndex::pskip pointer. */ +int static inline GetSkipHeight(int height) { + if (height < 2) + return 0; + + // Determine which height to jump back to. Any number strictly lower than height is acceptable, + // but the following expression seems to perform well in simulations (max 110 steps to go back + // up to 2**18 blocks). + return (height & 1) ? InvertLowestOne(InvertLowestOne(height - 1)) + 1 : InvertLowestOne(height); +} + +CBlockIndex* CBlockIndex::GetAncestor(int height) +{ + if (height > nHeight || height < 0) + return NULL; + + CBlockIndex* pindexWalk = this; + int heightWalk = nHeight; + while (heightWalk > height) { + int heightSkip = GetSkipHeight(heightWalk); + int heightSkipPrev = GetSkipHeight(heightWalk - 1); + if (heightSkip == height || + (heightSkip > height && !(heightSkipPrev < heightSkip - 2 && + heightSkipPrev >= height))) { + // Only follow pskip if pprev->pskip isn't better than pskip->pprev. + pindexWalk = pindexWalk->pskip; + heightWalk = heightSkip; + } else { + pindexWalk = pindexWalk->pprev; + heightWalk--; + } + } + return pindexWalk; +} + +const CBlockIndex* CBlockIndex::GetAncestor(int height) const +{ + return const_cast<CBlockIndex*>(this)->GetAncestor(height); +} + +void CBlockIndex::BuildSkip() +{ + if (pprev) + pskip = pprev->GetAncestor(GetSkipHeight(nHeight)); +} + void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd) { AssertLockHeld(cs_main); @@ -2885,6 +2983,8 @@ bool static LoadBlockIndexDB() setBlockIndexValid.insert(pindex); if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork)) pindexBestInvalid = pindex; + if (pindex->pprev) + pindex->BuildSkip(); } // Load block file info @@ -3680,6 +3780,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) PushGetBlocks(pfrom, chainActive.Tip(), GetOrphanRoot(inv.hash)); } + if (inv.type == MSG_BLOCK) + UpdateBlockAvailability(pfrom->GetId(), inv.hash); + // Track requests for our stuff g_signals.Inventory(inv.hash); } @@ -3722,7 +3825,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if (pindex) pindex = chainActive.Next(pindex); int nLimit = 500; - LogPrint("net", "getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString(), nLimit); + LogPrint("net", "getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop==uint256(0) ? "end" : hashStop.ToString(), nLimit); for (; pindex; pindex = chainActive.Next(pindex)) { if (pindex->GetBlockHash() == hashStop) @@ -4111,6 +4214,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) else { // Ignore unknown commands for extensibility + LogPrint("net", "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->id); } @@ -4425,6 +4529,9 @@ bool SendMessages(CNode* pto, bool fSendTrickle) pto->fDisconnect = true; } + // Update knowledge of peer's block availability. + ProcessBlockAvailability(pto->GetId()); + // // Message: getdata (blocks) // diff --git a/src/main.h b/src/main.h index c7f3dc4388..19f4469008 100644 --- a/src/main.h +++ b/src/main.h @@ -188,6 +188,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa struct CNodeStateStats { int nMisbehavior; + int nSyncHeight; }; struct CDiskBlockPos @@ -679,6 +680,9 @@ public: // pointer to the index of the predecessor of this block CBlockIndex* pprev; + // pointer to the index of some further predecessor of this block + CBlockIndex* pskip; + // height of the entry in the chain. The genesis block has height 0 int nHeight; @@ -718,6 +722,7 @@ public: { phashBlock = NULL; pprev = NULL; + pskip = NULL; nHeight = 0; nFile = 0; nDataPos = 0; @@ -739,6 +744,7 @@ public: { phashBlock = NULL; pprev = NULL; + pskip = NULL; nHeight = 0; nFile = 0; nDataPos = 0; @@ -871,9 +877,14 @@ public: } return false; } -}; + // Build the skiplist pointer for this entry. + void BuildSkip(); + // Efficiently find an ancestor of this block. + CBlockIndex* GetAncestor(int height); + const CBlockIndex* GetAncestor(int height) const; +}; /** Used to marshal pointers into hashes for db storage. */ class CDiskBlockIndex : public CBlockIndex @@ -28,14 +28,13 @@ #include <boost/signals2/signal.hpp> #include <openssl/rand.h> - class CAddrMan; class CBlockIndex; class CNode; namespace boost { class thread_group; -} +} // namespace boost /** Time between pings automatically sent out for latency probing and keepalive (in seconds). */ static const int PING_INTERVAL = 2 * 60; diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index eb647d0170..5fb0da145d 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -117,6 +117,7 @@ void ShutdownWindow::showShutdownWindow(BitcoinGUI *window) tr("Bitcoin Core is shutting down...") + "<br /><br />" + tr("Do not shut down the computer until this window disappears."))); shutdownWindow->setLayout(layout); + shutdownWindow->setWindowTitle(window->windowTitle()); // Center shutdown window at where main window was const QPoint global = window->mapToGlobal(window->rect().center()); diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 580c6bd5ba..a67f266a13 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -66,7 +66,7 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) result.push_back(Pair("tx", txs)); result.push_back(Pair("time", block.GetBlockTime())); result.push_back(Pair("nonce", (uint64_t)block.nNonce)); - result.push_back(Pair("bits", HexBits(block.nBits))); + result.push_back(Pair("bits", strprintf("%08x", block.nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 98caf704ee..db60ef3592 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -443,7 +443,7 @@ Value getblocktemplate(const Array& params, bool fHelp) result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS)); result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE)); result.push_back(Pair("curtime", (int64_t)pblock->nTime)); - result.push_back(Pair("bits", HexBits(pblock->nBits))); + result.push_back(Pair("bits", strprintf("%08x", pblock->nBits))); result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); return result; diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index a54872ccc4..2d7abb2d58 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -134,6 +134,7 @@ Value getpeerinfo(const Array& params, bool fHelp) obj.push_back(Pair("startingheight", stats.nStartingHeight)); if (fStateStats) { obj.push_back(Pair("banscore", statestats.nMisbehavior)); + obj.push_back(Pair("syncheight", statestats.nSyncHeight)); } obj.push_back(Pair("syncnode", stats.fSyncNode)); diff --git a/src/rpcprotocol.cpp b/src/rpcprotocol.cpp index 2cb4a35c4b..dd8692e802 100644 --- a/src/rpcprotocol.cpp +++ b/src/rpcprotocol.cpp @@ -54,8 +54,19 @@ static string rfc1123Time() return DateTimeStrFormat("%a, %d %b %Y %H:%M:%S +0000", GetTime()); } -string HTTPReply(int nStatus, const string& strMsg, bool keepalive, - bool headersOnly, const char *contentType) +static const char *httpStatusDescription(int nStatus) +{ + switch (nStatus) { + case HTTP_OK: return "OK"; + case HTTP_BAD_REQUEST: return "Bad Request"; + case HTTP_FORBIDDEN: return "Forbidden"; + case HTTP_NOT_FOUND: return "Not Found"; + case HTTP_INTERNAL_SERVER_ERROR: return "Internal Server Error"; + default: return ""; + } +} + +string HTTPError(int nStatus, bool keepalive, bool headersOnly) { if (nStatus == HTTP_UNAUTHORIZED) return strprintf("HTTP/1.0 401 Authorization Required\r\n" @@ -75,20 +86,13 @@ string HTTPReply(int nStatus, const string& strMsg, bool keepalive, "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n" "</HTML>\r\n", rfc1123Time(), FormatFullVersion()); - const char *cStatus; - if (nStatus == HTTP_OK) cStatus = "OK"; - else if (nStatus == HTTP_BAD_REQUEST) cStatus = "Bad Request"; - else if (nStatus == HTTP_FORBIDDEN) cStatus = "Forbidden"; - else if (nStatus == HTTP_NOT_FOUND) cStatus = "Not Found"; - else if (nStatus == HTTP_INTERNAL_SERVER_ERROR) cStatus = "Internal Server Error"; - else cStatus = ""; - - bool useInternalContent = false; - if (nStatus != HTTP_OK) { - contentType = "text/plain"; - useInternalContent = true; - } + return HTTPReply(nStatus, httpStatusDescription(nStatus), keepalive, + headersOnly, "text/plain"); +} +string HTTPReply(int nStatus, const string& strMsg, bool keepalive, + bool headersOnly, const char *contentType) +{ return strprintf( "HTTP/1.1 %d %s\r\n" "Date: %s\r\n" @@ -99,14 +103,14 @@ string HTTPReply(int nStatus, const string& strMsg, bool keepalive, "\r\n" "%s", nStatus, - cStatus, + httpStatusDescription(nStatus), rfc1123Time(), keepalive ? "keep-alive" : "close", - strMsg.size(), + (headersOnly ? 0 : strMsg.size()), contentType, FormatFullVersion(), - (headersOnly ? "" : - (useInternalContent ? cStatus : strMsg.c_str()))); + (headersOnly ? "" : strMsg.c_str()) + ); } bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto, diff --git a/src/rpcprotocol.h b/src/rpcprotocol.h index f1317e9c28..5627077bfb 100644 --- a/src/rpcprotocol.h +++ b/src/rpcprotocol.h @@ -141,6 +141,8 @@ private: }; std::string HTTPPost(const std::string& strMsg, const std::map<std::string,std::string>& mapRequestHeaders); +std::string HTTPError(int nStatus, bool keepalive, + bool headerOnly = false); std::string HTTPReply(int nStatus, const std::string& strMsg, bool keepalive, bool headerOnly = false, const char *contentType = "application/json"); diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 54043458d5..f47b3385da 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -97,16 +97,6 @@ Value ValueFromAmount(int64_t amount) return (double)amount / (double)COIN; } -std::string HexBits(unsigned int nBits) -{ - union { - int32_t nBits; - char cBits[4]; - } uBits; - uBits.nBits = htonl((int32_t)nBits); - return HexStr(BEGIN(uBits.cBits), END(uBits.cBits)); -} - uint256 ParseHashV(const Value& v, string strName) { string strHex; @@ -491,7 +481,7 @@ static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol, { // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake. if (!fUseSSL) - conn->stream() << HTTPReply(HTTP_FORBIDDEN, "", false) << std::flush; + conn->stream() << HTTPError(HTTP_FORBIDDEN, false) << std::flush; conn->close(); } else { @@ -817,7 +807,7 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn, // Check authorization if (mapHeaders.count("authorization") == 0) { - conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush; + conn->stream() << HTTPError(HTTP_UNAUTHORIZED, false) << std::flush; return false; } @@ -830,7 +820,7 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn, if (mapArgs["-rpcpassword"].size() < 20) MilliSleep(250); - conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush; + conn->stream() << HTTPError(HTTP_UNAUTHORIZED, false) << std::flush; return false; } @@ -898,7 +888,7 @@ void ServiceConnection(AcceptedConnection *conn) if (!HTTPReq_JSONRPC(conn, strRequest, mapHeaders, fRun)) break; } else { - conn->stream() << HTTPReply(HTTP_NOT_FOUND, "", false) << std::flush; + conn->stream() << HTTPError(HTTP_NOT_FOUND, false) << std::flush; break; } } diff --git a/src/rpcserver.h b/src/rpcserver.h index fcd293663f..01e77163c4 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -116,7 +116,6 @@ extern int64_t nWalletUnlockTime; extern int64_t AmountFromValue(const json_spirit::Value& value); extern json_spirit::Value ValueFromAmount(int64_t amount); extern double GetDifficulty(const CBlockIndex* blockindex = NULL); -extern std::string HexBits(unsigned int nBits); extern std::string HelpRequiringPassphrase(); extern std::string HelpExampleCli(std::string methodname, std::string args); extern std::string HelpExampleRpc(std::string methodname, std::string args); diff --git a/src/script.cpp b/src/script.cpp index bc4705abe7..e1b6985408 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -974,6 +974,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co namespace { + /** Wrapper that serializes like CTransaction, but with the modifications * required for the signature hash done in-place */ @@ -1066,7 +1067,8 @@ public: ::Serialize(s, txTo.nLockTime, nType, nVersion); } }; -} + +} // anon namespace uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) { @@ -1092,7 +1094,6 @@ uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsig return ss.GetHash(); } - // Valid signature cache, to avoid doing expensive ECDSA signature checking // twice for every transaction (once when accepted into memory pool, and // again when accepted into the block chain) diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp new file mode 100644 index 0000000000..ea301685c9 --- /dev/null +++ b/src/test/skiplist_tests.cpp @@ -0,0 +1,45 @@ +// Copyright (c) 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 <boost/test/unit_test.hpp> +#include <vector> +#include "main.h" +#include "util.h" + + +#define SKIPLIST_LENGTH 300000 + +BOOST_AUTO_TEST_SUITE(skiplist_tests) + +BOOST_AUTO_TEST_CASE(skiplist_test) +{ + std::vector<CBlockIndex> vIndex(SKIPLIST_LENGTH); + + for (int i=0; i<SKIPLIST_LENGTH; i++) { + vIndex[i].nHeight = i; + vIndex[i].pprev = (i == 0) ? NULL : &vIndex[i - 1]; + vIndex[i].BuildSkip(); + } + + for (int i=0; i<SKIPLIST_LENGTH; i++) { + if (i > 0) { + BOOST_CHECK(vIndex[i].pskip == &vIndex[vIndex[i].pskip->nHeight]); + BOOST_CHECK(vIndex[i].pskip->nHeight < i); + } else { + BOOST_CHECK(vIndex[i].pskip == NULL); + } + } + + for (int i=0; i < 1000; i++) { + int from = insecure_rand() % (SKIPLIST_LENGTH - 1); + int to = insecure_rand() % (from + 1); + + BOOST_CHECK(vIndex[SKIPLIST_LENGTH - 1].GetAncestor(from) == &vIndex[from]); + BOOST_CHECK(vIndex[from].GetAncestor(to) == &vIndex[to]); + BOOST_CHECK(vIndex[from].GetAncestor(0) == &vIndex[0]); + } +} + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/src/uint256.cpp b/src/uint256.cpp new file mode 100644 index 0000000000..3392f1e9bc --- /dev/null +++ b/src/uint256.cpp @@ -0,0 +1,292 @@ +// 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 "uint256.h" +#include "util.h" + +#include <stdio.h> +#include <string.h> + +template<unsigned int BITS> +base_uint<BITS>::base_uint(const std::string& str) +{ + SetHex(str); +} + +template<unsigned int BITS> +base_uint<BITS>::base_uint(const std::vector<unsigned char>& vch) +{ + if (vch.size() != sizeof(pn)) + throw uint_error("Converting vector of wrong size to base_uint"); + memcpy(pn, &vch[0], sizeof(pn)); +} + +template<unsigned int BITS> +base_uint<BITS>& base_uint<BITS>::operator<<=(unsigned int shift) +{ + base_uint<BITS> a(*this); + for (int i = 0; i < WIDTH; i++) + pn[i] = 0; + int k = shift / 32; + shift = shift % 32; + for (int i = 0; i < WIDTH; i++) { + if (i+k+1 < WIDTH && shift != 0) + pn[i+k+1] |= (a.pn[i] >> (32-shift)); + if (i+k < WIDTH) + pn[i+k] |= (a.pn[i] << shift); + } + return *this; +} + +template<unsigned int BITS> +base_uint<BITS>& base_uint<BITS>::operator>>=(unsigned int shift) +{ + base_uint<BITS> a(*this); + for (int i = 0; i < WIDTH; i++) + pn[i] = 0; + int k = shift / 32; + shift = shift % 32; + for (int i = 0; i < WIDTH; i++) { + if (i-k-1 >= 0 && shift != 0) + pn[i-k-1] |= (a.pn[i] << (32-shift)); + if (i-k >= 0) + pn[i-k] |= (a.pn[i] >> shift); + } + return *this; +} + +template<unsigned int BITS> +base_uint<BITS>& base_uint<BITS>::operator*=(uint32_t b32) +{ + uint64_t carry = 0; + for (int i = 0; i < WIDTH; i++) { + uint64_t n = carry + (uint64_t)b32 * pn[i]; + pn[i] = n & 0xffffffff; + carry = n >> 32; + } + return *this; +} + +template<unsigned int BITS> +base_uint<BITS>& base_uint<BITS>::operator*=(const base_uint& b) +{ + base_uint<BITS> a = *this; + *this = 0; + for (int j = 0; j < WIDTH; j++) { + uint64_t carry = 0; + for (int i = 0; i + j < WIDTH; i++) { + uint64_t n = carry + pn[i + j] + (uint64_t)a.pn[j] * b.pn[i]; + pn[i + j] = n & 0xffffffff; + carry = n >> 32; + } + } + return *this; +} + +template<unsigned int BITS> +base_uint<BITS>& base_uint<BITS>::operator/=(const base_uint& b) +{ + base_uint<BITS> div = b; // make a copy, so we can shift. + base_uint<BITS> num = *this; // make a copy, so we can subtract. + *this = 0; // the quotient. + int num_bits = num.bits(); + int div_bits = div.bits(); + if (div_bits == 0) + throw uint_error("Division by zero"); + if (div_bits > num_bits) // the result is certainly 0. + return *this; + int shift = num_bits - div_bits; + div <<= shift; // shift so that div and nun align. + while (shift >= 0) { + if (num >= div) { + num -= div; + pn[shift / 32] |= (1 << (shift & 31)); // set a bit of the result. + } + div >>= 1; // shift back. + shift--; + } + // num now contains the remainder of the division. + return *this; +} + +template<unsigned int BITS> +int base_uint<BITS>::CompareTo(const base_uint<BITS>& b) const { + for (int i = WIDTH-1; i >= 0; i--) { + if (pn[i] < b.pn[i]) + return -1; + if (pn[i] > b.pn[i]) + return 1; + } + return 0; +} + +template<unsigned int BITS> +bool base_uint<BITS>::EqualTo(uint64_t b) const { + for (int i = WIDTH-1; i >= 2; i--) { + if (pn[i]) + return false; + } + if (pn[1] != (b >> 32)) + return false; + if (pn[0] != (b & 0xfffffffful)) + return false; + return true; +} + +template<unsigned int BITS> +double base_uint<BITS>::getdouble() const +{ + double ret = 0.0; + double fact = 1.0; + for (int i = 0; i < WIDTH; i++) { + ret += fact * pn[i]; + fact *= 4294967296.0; + } + return ret; +} + +template<unsigned int BITS> +std::string base_uint<BITS>::GetHex() const +{ + char psz[sizeof(pn)*2 + 1]; + for (unsigned int i = 0; i < sizeof(pn); i++) + sprintf(psz + i*2, "%02x", ((unsigned char*)pn)[sizeof(pn) - i - 1]); + return std::string(psz, psz + sizeof(pn)*2); +} + +template<unsigned int BITS> +void base_uint<BITS>::SetHex(const char* psz) +{ + memset(pn,0,sizeof(pn)); + + // skip leading spaces + while (isspace(*psz)) + psz++; + + // skip 0x + if (psz[0] == '0' && tolower(psz[1]) == 'x') + psz += 2; + + // hex string to uint + const char* pbegin = psz; + while (::HexDigit(*psz) != -1) + psz++; + psz--; + unsigned char* p1 = (unsigned char*)pn; + unsigned char* pend = p1 + WIDTH * 4; + while (psz >= pbegin && p1 < pend) { + *p1 = ::HexDigit(*psz--); + if (psz >= pbegin) { + *p1 |= ((unsigned char)::HexDigit(*psz--) << 4); + p1++; + } + } +} + +template<unsigned int BITS> +void base_uint<BITS>::SetHex(const std::string& str) +{ + SetHex(str.c_str()); +} + +template<unsigned int BITS> +std::string base_uint<BITS>::ToString() const +{ + return (GetHex()); +} + +template<unsigned int BITS> +unsigned int base_uint<BITS>::bits() const +{ + for (int pos = WIDTH-1; pos >= 0; pos--) { + if (pn[pos]) { + for (int bits = 31; bits > 0; bits--) { + if (pn[pos] & 1<<bits) + return 32*pos + bits + 1; + } + return 32*pos + 1; + } + } + return 0; +} + +// Explicit instantiations for base_uint<160> +template base_uint<160>::base_uint(const std::string&); +template base_uint<160>::base_uint(const std::vector<unsigned char>&); +template base_uint<160>& base_uint<160>::operator<<=(unsigned int); +template base_uint<160>& base_uint<160>::operator>>=(unsigned int); +template base_uint<160>& base_uint<160>::operator*=(uint32_t b32); +template base_uint<160>& base_uint<160>::operator*=(const base_uint<160>& b); +template base_uint<160>& base_uint<160>::operator/=(const base_uint<160>& b); +template int base_uint<160>::CompareTo(const base_uint<160>&) const; +template bool base_uint<160>::EqualTo(uint64_t) const; +template double base_uint<160>::getdouble() const; +template std::string base_uint<160>::GetHex() const; +template std::string base_uint<160>::ToString() const; +template void base_uint<160>::SetHex(const char*); +template void base_uint<160>::SetHex(const std::string&); +template unsigned int base_uint<160>::bits() const; + +// Explicit instantiations for base_uint<256> +template base_uint<256>::base_uint(const std::string&); +template base_uint<256>::base_uint(const std::vector<unsigned char>&); +template base_uint<256>& base_uint<256>::operator<<=(unsigned int); +template base_uint<256>& base_uint<256>::operator>>=(unsigned int); +template base_uint<256>& base_uint<256>::operator*=(uint32_t b32); +template base_uint<256>& base_uint<256>::operator*=(const base_uint<256>& b); +template base_uint<256>& base_uint<256>::operator/=(const base_uint<256>& b); +template int base_uint<256>::CompareTo(const base_uint<256>&) const; +template bool base_uint<256>::EqualTo(uint64_t) const; +template double base_uint<256>::getdouble() const; +template std::string base_uint<256>::GetHex() const; +template std::string base_uint<256>::ToString() const; +template void base_uint<256>::SetHex(const char*); +template void base_uint<256>::SetHex(const std::string&); +template unsigned int base_uint<256>::bits() const; + +// This implementation directly uses shifts instead of going +// through an intermediate MPI representation. +uint256& uint256::SetCompact(uint32_t nCompact, bool *pfNegative, bool *pfOverflow) +{ + int nSize = nCompact >> 24; + uint32_t nWord = nCompact & 0x007fffff; + if (nSize <= 3) { + nWord >>= 8*(3-nSize); + *this = nWord; + } else { + *this = nWord; + *this <<= 8*(nSize-3); + } + if (pfNegative) + *pfNegative = nWord != 0 && (nCompact & 0x00800000) != 0; + if (pfOverflow) + *pfOverflow = nWord != 0 && ((nSize > 34) || + (nWord > 0xff && nSize > 33) || + (nWord > 0xffff && nSize > 32)); + return *this; +} + +uint32_t uint256::GetCompact(bool fNegative) const +{ + int nSize = (bits() + 7) / 8; + uint32_t nCompact = 0; + if (nSize <= 3) { + nCompact = GetLow64() << 8*(3-nSize); + } else { + uint256 bn = *this >> 8*(nSize-3); + nCompact = bn.GetLow64(); + } + // The 0x00800000 bit denotes the sign. + // Thus, if it is already set, divide the mantissa by 256 and increase the exponent. + if (nCompact & 0x00800000) { + nCompact >>= 8; + nSize++; + } + assert((nCompact & ~0x007fffff) == 0); + assert(nSize < 256); + nCompact |= nSize << 24; + nCompact |= (fNegative && (nCompact & 0x007fffff) ? 0x00800000 : 0); + return nCompact; +} diff --git a/src/uint256.h b/src/uint256.h index 1acedd14bf..82db7758c9 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -9,18 +9,9 @@ #include <assert.h> #include <stdexcept> #include <stdint.h> -#include <stdio.h> #include <string> -#include <string.h> #include <vector> -extern const signed char p_util_hexdigit[256]; // defined in util.cpp - -inline signed char HexDigit(char c) -{ - return p_util_hexdigit[(unsigned char)c]; -} - class uint_error : public std::runtime_error { public: explicit uint_error(const std::string& str) : std::runtime_error(str) {} @@ -62,17 +53,8 @@ public: pn[i] = 0; } - explicit base_uint(const std::string& str) - { - SetHex(str); - } - - explicit base_uint(const std::vector<unsigned char>& vch) - { - if (vch.size() != sizeof(pn)) - throw uint_error("Converting vector of wrong size to base_uint"); - memcpy(pn, &vch[0], sizeof(pn)); - } + explicit base_uint(const std::string& str); + explicit base_uint(const std::vector<unsigned char>& vch); bool operator!() const { @@ -99,16 +81,7 @@ public: return ret; } - double getdouble() const - { - double ret = 0.0; - double fact = 1.0; - for (int i = 0; i < WIDTH; i++) { - ret += fact * pn[i]; - fact *= 4294967296.0; - } - return ret; - } + double getdouble() const; base_uint& operator=(uint64_t b) { @@ -154,39 +127,8 @@ public: return *this; } - base_uint& operator<<=(unsigned int shift) - { - base_uint a(*this); - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; - int k = shift / 32; - shift = shift % 32; - for (int i = 0; i < WIDTH; i++) - { - if (i+k+1 < WIDTH && shift != 0) - pn[i+k+1] |= (a.pn[i] >> (32-shift)); - if (i+k < WIDTH) - pn[i+k] |= (a.pn[i] << shift); - } - return *this; - } - - base_uint& operator>>=(unsigned int shift) - { - base_uint a(*this); - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; - int k = shift / 32; - shift = shift % 32; - for (int i = 0; i < WIDTH; i++) - { - if (i-k-1 >= 0 && shift != 0) - pn[i-k-1] |= (a.pn[i] << (32-shift)); - if (i-k >= 0) - pn[i-k] |= (a.pn[i] >> shift); - } - return *this; - } + base_uint& operator<<=(unsigned int shift); + base_uint& operator>>=(unsigned int shift); base_uint& operator+=(const base_uint& b) { @@ -222,57 +164,9 @@ public: return *this; } - base_uint& operator*=(uint32_t b32) - { - uint64_t carry = 0; - for (int i = 0; i < WIDTH; i++) - { - uint64_t n = carry + (uint64_t)b32 * pn[i]; - pn[i] = n & 0xffffffff; - carry = n >> 32; - } - return *this; - } - - base_uint& operator*=(const base_uint& b) - { - base_uint a = *this; - *this = 0; - for (int j = 0; j < WIDTH; j++) { - uint64_t carry = 0; - for (int i = 0; i + j < WIDTH; i++) { - uint64_t n = carry + pn[i + j] + (uint64_t)a.pn[j] * b.pn[i]; - pn[i + j] = n & 0xffffffff; - carry = n >> 32; - } - } - return *this; - } - - base_uint& operator/=(const base_uint& b) - { - base_uint div = b; // make a copy, so we can shift. - base_uint num = *this; // make a copy, so we can subtract. - *this = 0; // the quotient. - int num_bits = num.bits(); - int div_bits = div.bits(); - if (div_bits == 0) - throw uint_error("Division by zero"); - if (div_bits > num_bits) // the result is certainly 0. - return *this; - int shift = num_bits - div_bits; - div <<= shift; // shift so that div and nun align. - while (shift >= 0) { - if (num >= div) { - num -= div; - pn[shift / 32] |= (1 << (shift & 31)); // set a bit of the result. - } - div >>= 1; // shift back. - shift--; - } - // num now contains the remainder of the division. - return *this; - } + base_uint& operator*=(uint32_t b32); + base_uint& operator*=(const base_uint& b); + base_uint& operator/=(const base_uint& b); base_uint& operator++() { @@ -308,27 +202,8 @@ public: return ret; } - int CompareTo(const base_uint& b) const { - for (int i = base_uint::WIDTH-1; i >= 0; i--) { - if (pn[i] < b.pn[i]) - return -1; - if (pn[i] > b.pn[i]) - return 1; - } - return 0; - } - - bool EqualTo(uint64_t b) const { - for (int i = base_uint::WIDTH-1; i >= 2; i--) { - if (pn[i]) - return false; - } - if (pn[1] != (b >> 32)) - return false; - if (pn[0] != (b & 0xfffffffful)) - return false; - return true; - } + int CompareTo(const base_uint& b) const; + bool EqualTo(uint64_t b) const; friend inline const base_uint operator+(const base_uint& a, const base_uint& b) { return base_uint(a) += b; } friend inline const base_uint operator-(const base_uint& a, const base_uint& b) { return base_uint(a) -= b; } @@ -349,53 +224,10 @@ public: friend inline bool operator==(const base_uint& a, uint64_t b) { return a.EqualTo(b); } friend inline bool operator!=(const base_uint& a, uint64_t b) { return !a.EqualTo(b); } - std::string GetHex() const - { - char psz[sizeof(pn)*2 + 1]; - for (unsigned int i = 0; i < sizeof(pn); i++) - sprintf(psz + i*2, "%02x", ((unsigned char*)pn)[sizeof(pn) - i - 1]); - return std::string(psz, psz + sizeof(pn)*2); - } - - void SetHex(const char* psz) - { - memset(pn,0,sizeof(pn)); - - // skip leading spaces - while (isspace(*psz)) - psz++; - - // skip 0x - if (psz[0] == '0' && tolower(psz[1]) == 'x') - psz += 2; - - // hex string to uint - const char* pbegin = psz; - while (::HexDigit(*psz) != -1) - psz++; - psz--; - unsigned char* p1 = (unsigned char*)pn; - unsigned char* pend = p1 + WIDTH * 4; - while (psz >= pbegin && p1 < pend) - { - *p1 = ::HexDigit(*psz--); - if (psz >= pbegin) - { - *p1 |= ((unsigned char)::HexDigit(*psz--) << 4); - p1++; - } - } - } - - void SetHex(const std::string& str) - { - SetHex(str.c_str()); - } - - std::string ToString() const - { - return (GetHex()); - } + std::string GetHex() const; + void SetHex(const char* psz); + void SetHex(const std::string& str); + std::string ToString() const; unsigned char* begin() { @@ -424,19 +256,7 @@ public: // Returns the position of the highest bit set plus one, or zero if the // value is zero. - unsigned int bits() const - { - for (int pos = WIDTH-1; pos >= 0; pos--) { - if (pn[pos]) { - for (int bits = 31; bits > 0; bits--) { - if (pn[pos] & 1<<bits) - return 32*pos + bits + 1; - } - return 32*pos + 1; - } - } - return 0; - } + unsigned int bits() const; uint64_t GetLow64() const { @@ -500,56 +320,8 @@ public: // targets, which are unsigned 256bit quantities. Thus, all the // complexities of the sign bit and using base 256 are probably an // implementation accident. - // - // This implementation directly uses shifts instead of going - // through an intermediate MPI representation. - uint256& SetCompact(uint32_t nCompact, bool *pfNegative = NULL, bool *pfOverflow = NULL) - { - int nSize = nCompact >> 24; - uint32_t nWord = nCompact & 0x007fffff; - if (nSize <= 3) - { - nWord >>= 8*(3-nSize); - *this = nWord; - } - else - { - *this = nWord; - *this <<= 8*(nSize-3); - } - if (pfNegative) - *pfNegative = nWord != 0 && (nCompact & 0x00800000) != 0; - if (pfOverflow) - *pfOverflow = nWord != 0 && ((nSize > 34) || - (nWord > 0xff && nSize > 33) || - (nWord > 0xffff && nSize > 32)); - return *this; - } - - uint32_t GetCompact(bool fNegative = false) const - { - int nSize = (bits() + 7) / 8; - uint32_t nCompact = 0; - if (nSize <= 3) - nCompact = GetLow64() << 8*(3-nSize); - else - { - uint256 bn = *this >> 8*(nSize-3); - nCompact = bn.GetLow64(); - } - // The 0x00800000 bit denotes the sign. - // Thus, if it is already set, divide the mantissa by 256 and increase the exponent. - if (nCompact & 0x00800000) - { - nCompact >>= 8; - nSize++; - } - assert((nCompact & ~0x007fffff) == 0); - assert(nSize < 256); - nCompact |= nSize << 24; - nCompact |= (fNegative && (nCompact & 0x007fffff) ? 0x00800000 : 0); - return nCompact; - } + uint256& SetCompact(uint32_t nCompact, bool *pfNegative = NULL, bool *pfOverflow = NULL); + uint32_t GetCompact(bool fNegative = false) const; }; #endif diff --git a/src/util.cpp b/src/util.cpp index 9e4b2b787e..5a8f85ade7 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -77,11 +77,12 @@ // See also: http://stackoverflow.com/questions/10020179/compilation-fail-in-boost-librairies-program-options // http://clang.debian.net/status.php?version=3.0&key=CANNOT_FIND_FUNCTION namespace boost { + namespace program_options { std::string to_internal(const std::string&); } -} +} // namespace boost using namespace std; @@ -419,6 +420,11 @@ 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, }; +signed char HexDigit(char c) +{ + return p_util_hexdigit[(unsigned char)c]; +} + bool IsHex(const string& str) { BOOST_FOREACH(char c, str) diff --git a/src/util.h b/src/util.h index 6057c72e66..707b8f2d76 100644 --- a/src/util.h +++ b/src/util.h @@ -156,6 +156,7 @@ 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); |