diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/init.cpp | 32 | ||||
-rw-r--r-- | src/main.cpp | 24 | ||||
-rw-r--r-- | src/main.h | 2 | ||||
-rw-r--r-- | src/net.cpp | 60 | ||||
-rw-r--r-- | src/net.h | 13 | ||||
-rw-r--r-- | src/qt/bitcoingui.cpp | 6 | ||||
-rw-r--r-- | src/rpcmining.cpp | 60 | ||||
-rw-r--r-- | src/rpcnet.cpp | 1 | ||||
-rw-r--r-- | src/rpcserver.cpp | 11 | ||||
-rw-r--r-- | src/rpcserver.h | 2 | ||||
-rw-r--r-- | src/sync.h | 3 | ||||
-rw-r--r-- | src/wallet.cpp | 6 |
12 files changed, 184 insertions, 36 deletions
diff --git a/src/init.cpp b/src/init.cpp index 3f068da89f..9daad6ac89 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -58,7 +58,8 @@ CWallet* pwalletMain; enum BindFlags { BF_NONE = 0, BF_EXPLICIT = (1U << 0), - BF_REPORT_ERROR = (1U << 1) + BF_REPORT_ERROR = (1U << 1), + BF_WHITELIST = (1U << 2), }; static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat"; @@ -192,7 +193,7 @@ bool static Bind(const CService &addr, unsigned int flags) { if (!(flags & BF_EXPLICIT) && IsLimited(addr)) return false; std::string strError; - if (!BindListenPort(addr, strError)) { + if (!BindListenPort(addr, strError, flags & BF_WHITELIST)) { if (flags & BF_REPORT_ERROR) return InitError(strError); return false; @@ -252,6 +253,8 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += " -upnp " + _("Use UPnP to map the listening port (default: 0)") + "\n"; #endif #endif + strUsage += " -whitebind=<addr> " + _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6") + "\n"; + strUsage += " -whitelist=<netmask> " + _("Whitelist peers connecting from the given netmask or ip. Can be specified multiple times.") + "\n"; #ifdef ENABLE_WALLET strUsage += "\n" + _("Wallet options:") + "\n"; @@ -506,11 +509,11 @@ bool AppInit2(boost::thread_group& threadGroup) // ********************************************************* Step 2: parameter interactions - if (mapArgs.count("-bind")) { + if (mapArgs.count("-bind") || mapArgs.count("-whitebind")) { // when specifying an explicit binding address, you want to listen on it // even when -connect or -proxy is specified if (SoftSetBoolArg("-listen", true)) - LogPrintf("AppInit2 : parameter interaction: -bind set -> setting -listen=1\n"); + LogPrintf("AppInit2 : parameter interaction: -bind or -whitebind set -> setting -listen=1\n"); } if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) { @@ -554,7 +557,7 @@ bool AppInit2(boost::thread_group& threadGroup) } // Make sure enough file descriptors are available - int nBind = std::max((int)mapArgs.count("-bind"), 1); + int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1); nMaxConnections = GetArg("-maxconnections", 125); nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0); int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS); @@ -771,6 +774,15 @@ bool AppInit2(boost::thread_group& threadGroup) } } + if (mapArgs.count("-whitelist")) { + BOOST_FOREACH(const std::string& net, mapMultiArgs["-whitelist"]) { + CSubNet subnet(net); + if (!subnet.IsValid()) + return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net)); + CNode::AddWhitelistedRange(subnet); + } + } + CService addrProxy; bool fProxy = false; if (mapArgs.count("-proxy")) { @@ -807,13 +819,21 @@ bool AppInit2(boost::thread_group& threadGroup) bool fBound = false; if (fListen) { - if (mapArgs.count("-bind")) { + if (mapArgs.count("-bind") || mapArgs.count("-whitebind")) { BOOST_FOREACH(std::string strBind, mapMultiArgs["-bind"]) { CService addrBind; if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false)) return InitError(strprintf(_("Cannot resolve -bind address: '%s'"), strBind)); fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR)); } + BOOST_FOREACH(std::string strBind, mapMultiArgs["-whitebind"]) { + CService addrBind; + if (!Lookup(strBind.c_str(), addrBind, 0, false)) + return InitError(strprintf(_("Cannot resolve -whitebind address: '%s'"), strBind)); + if (addrBind.GetPort() == 0) + return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind)); + fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST)); + } } else { struct in_addr inaddr_any; diff --git a/src/main.cpp b/src/main.cpp index a9c080ffae..c5a3b284e8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -41,6 +41,8 @@ CCriticalSection cs_main; map<uint256, CBlockIndex*> mapBlockIndex; CChain chainActive; int64_t nTimeBestReceived = 0; +CWaitableCriticalSection csBestBlock; +CConditionVariable cvBlockChange; int nScriptCheckThreads = 0; bool fImporting = false; bool fReindex = false; @@ -210,7 +212,7 @@ struct CBlockReject { struct CNodeState { // Accumulated misbehaviour score for this peer. int nMisbehavior; - // Whether this peer should be disconnected and banned. + // Whether this peer should be disconnected and banned (unless whitelisted). bool fShouldBan; // String name of this peer (debugging/logging purposes). std::string name; @@ -1425,7 +1427,8 @@ void Misbehaving(NodeId pnode, int howmuch) return; state->nMisbehavior += howmuch; - if (state->nMisbehavior >= GetArg("-banscore", 100)) + int banscore = GetArg("-banscore", 100); + if (state->nMisbehavior >= banscore && state->nMisbehavior - howmuch < banscore) { LogPrintf("Misbehaving: %s (%d -> %d) BAN THRESHOLD EXCEEDED\n", state->name, state->nMisbehavior-howmuch, state->nMisbehavior); state->fShouldBan = true; @@ -1944,11 +1947,14 @@ void static UpdateTip(CBlockIndex *pindexNew) { // New best block nTimeBestReceived = GetTime(); mempool.AddTransactionsUpdated(1); + LogPrintf("UpdateTip: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f\n", chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx, DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), Checkpoints::GuessVerificationProgress(chainActive.Tip())); + cvBlockChange.notify_all(); + // Check the version of the last 100 blocks to see if we need to upgrade: if (!fIsInitialDownload) { @@ -3947,6 +3953,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, unsigned int nEvicted = LimitOrphanTxSize(MAX_ORPHAN_TRANSACTIONS); if (nEvicted > 0) LogPrint("mempool", "mapOrphan overflow, removed %u tx\n", nEvicted); + } else if (pfrom->fWhitelisted) { + // Always relay transactions received from whitelisted peers, even + // if they are already in the mempool (allowing the node to function + // as a gateway for nodes hidden behind it). + RelayTransaction(tx); } int nDoS = 0; if (state.IsInvalid(nDoS)) @@ -4440,11 +4451,14 @@ bool SendMessages(CNode* pto, bool fSendTrickle) CNodeState &state = *State(pto->GetId()); if (state.fShouldBan) { - if (pto->addr.IsLocal()) - LogPrintf("Warning: not banning local node %s!\n", pto->addr.ToString()); + if (pto->fWhitelisted) + LogPrintf("Warning: not punishing whitelisted peer %s!\n", pto->addr.ToString()); else { pto->fDisconnect = true; - CNode::Ban(pto->addr); + if (pto->addr.IsLocal()) + LogPrintf("Warning: not banning local peer %s!\n", pto->addr.ToString()); + else + CNode::Ban(pto->addr); } state.fShouldBan = false; } diff --git a/src/main.h b/src/main.h index f6bac889be..a683412571 100644 --- a/src/main.h +++ b/src/main.h @@ -87,6 +87,8 @@ extern uint64_t nLastBlockTx; extern uint64_t nLastBlockSize; extern const std::string strMessageMagic; extern int64_t nTimeBestReceived; +extern CWaitableCriticalSection csBestBlock; +extern CConditionVariable cvBlockChange; extern bool fImporting; extern bool fReindex; extern bool fBenchmark; diff --git a/src/net.cpp b/src/net.cpp index 6a660dc9bd..6a6d9df6af 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -50,7 +50,16 @@ using namespace std; using namespace boost; -static const int MAX_OUTBOUND_CONNECTIONS = 8; +namespace { + const int MAX_OUTBOUND_CONNECTIONS = 8; + + struct ListenSocket { + SOCKET socket; + bool whitelisted; + + ListenSocket(SOCKET socket, bool whitelisted) : socket(socket), whitelisted(whitelisted) {} + }; +} // // Global state variables @@ -65,7 +74,7 @@ static bool vfLimited[NET_MAX] = {}; static CNode* pnodeLocalHost = NULL; static CNode* pnodeSync = NULL; uint64_t nLocalHostNonce = 0; -static std::vector<SOCKET> vhListenSocket; +static std::vector<ListenSocket> vhListenSocket; CAddrMan addrman; int nMaxConnections = 125; @@ -593,6 +602,24 @@ bool CNode::Ban(const CNetAddr &addr) { return true; } + +std::vector<CSubNet> CNode::vWhitelistedRange; +CCriticalSection CNode::cs_vWhitelistedRange; + +bool CNode::IsWhitelistedRange(const CNetAddr &addr) { + LOCK(cs_vWhitelistedRange); + BOOST_FOREACH(const CSubNet& subnet, vWhitelistedRange) { + if (subnet.Match(addr)) + return true; + } + return false; +} + +void CNode::AddWhitelistedRange(const CSubNet &subnet) { + LOCK(cs_vWhitelistedRange); + vWhitelistedRange.push_back(subnet); +} + #undef X #define X(name) stats.name = name void CNode::copyStats(CNodeStats &stats) @@ -609,6 +636,7 @@ void CNode::copyStats(CNodeStats &stats) X(nStartingHeight); X(nSendBytes); X(nRecvBytes); + X(fWhitelisted); stats.fSyncNode = (this == pnodeSync); // It is common for nodes with good ping times to suddenly become lagged, @@ -848,9 +876,9 @@ void ThreadSocketHandler() SOCKET hSocketMax = 0; bool have_fds = false; - BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) { - FD_SET(hListenSocket, &fdsetRecv); - hSocketMax = max(hSocketMax, hListenSocket); + BOOST_FOREACH(const ListenSocket& hListenSocket, vhListenSocket) { + FD_SET(hListenSocket.socket, &fdsetRecv); + hSocketMax = max(hSocketMax, hListenSocket.socket); have_fds = true; } @@ -917,13 +945,13 @@ void ThreadSocketHandler() // // Accept new connections // - BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) + BOOST_FOREACH(const ListenSocket& hListenSocket, vhListenSocket) { - if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv)) + if (hListenSocket.socket != INVALID_SOCKET && FD_ISSET(hListenSocket.socket, &fdsetRecv)) { struct sockaddr_storage sockaddr; socklen_t len = sizeof(sockaddr); - SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len); + SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len); CAddress addr; int nInbound = 0; @@ -931,6 +959,7 @@ void ThreadSocketHandler() if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) LogPrintf("Warning: Unknown socket family\n"); + bool whitelisted = hListenSocket.whitelisted || CNode::IsWhitelistedRange(addr); { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) @@ -948,7 +977,7 @@ void ThreadSocketHandler() { closesocket(hSocket); } - else if (CNode::IsBanned(addr)) + else if (CNode::IsBanned(addr) && !whitelisted) { LogPrintf("connection from %s dropped (banned)\n", addr.ToString()); closesocket(hSocket); @@ -957,6 +986,7 @@ void ThreadSocketHandler() { CNode* pnode = new CNode(hSocket, addr, "", true); pnode->AddRef(); + pnode->fWhitelisted = whitelisted; { LOCK(cs_vNodes); @@ -1580,7 +1610,7 @@ void ThreadMessageHandler() -bool BindListenPort(const CService &addrBind, string& strError) +bool BindListenPort(const CService &addrBind, string& strError, bool fWhitelisted) { strError = ""; int nOne = 1; @@ -1661,9 +1691,9 @@ bool BindListenPort(const CService &addrBind, string& strError) return false; } - vhListenSocket.push_back(hListenSocket); + vhListenSocket.push_back(ListenSocket(hListenSocket, fWhitelisted)); - if (addrBind.IsRoutable() && fDiscover) + if (addrBind.IsRoutable() && fDiscover && !fWhitelisted) AddLocal(addrBind, LOCAL_BIND); return true; @@ -1788,9 +1818,9 @@ public: BOOST_FOREACH(CNode* pnode, vNodes) if (pnode->hSocket != INVALID_SOCKET) closesocket(pnode->hSocket); - BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) - if (hListenSocket != INVALID_SOCKET) - if (closesocket(hListenSocket) == SOCKET_ERROR) + BOOST_FOREACH(ListenSocket& hListenSocket, vhListenSocket) + if (hListenSocket.socket != INVALID_SOCKET) + if (closesocket(hListenSocket.socket) == SOCKET_ERROR) LogPrintf("closesocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError())); // clean up some globals (to help leak detection) @@ -64,7 +64,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest = NULL); bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false); void MapPort(bool fUseUPnP); unsigned short GetListenPort(); -bool BindListenPort(const CService &bindAddr, std::string& strError); +bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); void StartNode(boost::thread_group& threadGroup); bool StopNode(); void SocketSendData(CNode *pnode); @@ -154,6 +154,7 @@ public: uint64_t nSendBytes; uint64_t nRecvBytes; bool fSyncNode; + bool fWhitelisted; double dPingTime; double dPingWait; std::string addrLocal; @@ -236,6 +237,7 @@ public: // store the sanitized version in cleanSubVer. The original should be used when dealing with // the network or wire types and the cleaned string used when displayed or logged. std::string strSubVer, cleanSubVer; + bool fWhitelisted; // This peer can bypass DoS banning. bool fOneShot; bool fClient; bool fInbound; @@ -259,6 +261,11 @@ protected: static std::map<CNetAddr, int64_t> setBanned; static CCriticalSection cs_setBanned; + // Whitelisted ranges. Any node connecting from these is automatically + // whitelisted (as well as those connecting to whitelisted binds). + static std::vector<CSubNet> vWhitelistedRange; + static CCriticalSection cs_vWhitelistedRange; + // Basic fuzz-testing void Fuzz(int nChance); // modifies ssSend @@ -305,6 +312,7 @@ public: addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; nVersion = 0; strSubVer = ""; + fWhitelisted = false; fOneShot = false; fClient = false; // set by version message fInbound = fInboundIn; @@ -720,6 +728,9 @@ public: static bool Ban(const CNetAddr &ip); void copyStats(CNodeStats &stats); + static bool IsWhitelistedRange(const CNetAddr &ip); + static void AddWhitelistedRange(const CSubNet &subnet); + // Network stats static void RecordBytesRecv(uint64_t bytes); static void RecordBytesSent(uint64_t bytes); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 3ef04d96ac..4fabc2a5de 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1015,7 +1015,7 @@ UnitDisplayStatusBarControl::UnitDisplayStatusBarControl():QLabel() setToolTip(tr("Unit to show amounts in. Click to select another unit.")); } -/** So that it responds to left-button clicks */ +/** So that it responds to button clicks */ void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent *event) { onDisplayUnitsClicked(event->pos()); @@ -1032,10 +1032,6 @@ void UnitDisplayStatusBarControl::createContextMenu() menu->addAction(menuAction); } connect(menu,SIGNAL(triggered(QAction*)),this,SLOT(onMenuSelection(QAction*))); - - // what happens on right click. - setContextMenuPolicy(Qt::CustomContextMenu); - connect(this,SIGNAL(customContextMenuRequested(const QPoint&)),this,SLOT(onDisplayUnitsClicked(const QPoint&))); } /** Lets the control know about the Options Model (and its signals) */ diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index c7621dc137..6f72ea7404 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -324,6 +324,7 @@ Value getblocktemplate(const Array& params, bool fHelp) ); std::string strMode = "template"; + Value lpval = Value::null; if (params.size() > 0) { const Object& oparam = params[0].get_obj(); @@ -336,6 +337,7 @@ Value getblocktemplate(const Array& params, bool fHelp) } else throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); + lpval = find_value(oparam, "longpollid"); } if (strMode != "template") @@ -347,8 +349,63 @@ Value getblocktemplate(const Array& params, bool fHelp) if (IsInitialBlockDownload()) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Bitcoin is downloading blocks..."); - // Update block static unsigned int nTransactionsUpdatedLast; + + if (lpval.type() != null_type) + { + // Wait to respond until either the best block changes, OR a minute has passed and there are more transactions + uint256 hashWatchedChain; + boost::system_time checktxtime; + unsigned int nTransactionsUpdatedLastLP; + + if (lpval.type() == str_type) + { + // Format: <hashBestChain><nTransactionsUpdatedLast> + std::string lpstr = lpval.get_str(); + + hashWatchedChain.SetHex(lpstr.substr(0, 64)); + nTransactionsUpdatedLastLP = atoi64(lpstr.substr(64)); + } + else + { + // NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier + hashWatchedChain = chainActive.Tip()->GetBlockHash(); + nTransactionsUpdatedLastLP = nTransactionsUpdatedLast; + } + + // Release the wallet and main lock while waiting +#ifdef ENABLE_WALLET + if(pwalletMain) + LEAVE_CRITICAL_SECTION(pwalletMain->cs_wallet); +#endif + LEAVE_CRITICAL_SECTION(cs_main); + { + checktxtime = boost::get_system_time() + boost::posix_time::minutes(1); + + boost::unique_lock<boost::mutex> lock(csBestBlock); + while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning()) + { + if (!cvBlockChange.timed_wait(lock, checktxtime)) + { + // Timeout: Check transactions for update + if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP) + break; + checktxtime += boost::posix_time::seconds(10); + } + } + } + ENTER_CRITICAL_SECTION(cs_main); +#ifdef ENABLE_WALLET + if(pwalletMain) + ENTER_CRITICAL_SECTION(pwalletMain->cs_wallet); +#endif + + if (!IsRPCRunning()) + throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down"); + // TODO: Maybe recheck connections/IBD and (if something wrong) send an expires-immediately template to stop miners? + } + + // Update block static CBlockIndex* pindexPrev; static int64_t nStart; static CBlockTemplate* pblocktemplate; @@ -436,6 +493,7 @@ Value getblocktemplate(const Array& params, bool fHelp) result.push_back(Pair("transactions", transactions)); result.push_back(Pair("coinbaseaux", aux)); result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue)); + result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast))); result.push_back(Pair("target", hashTarget.GetHex())); result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); result.push_back(Pair("mutable", aMutable)); diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index cf2c293caf..680717930b 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -137,6 +137,7 @@ Value getpeerinfo(const Array& params, bool fHelp) obj.push_back(Pair("syncheight", statestats.nSyncHeight)); } obj.push_back(Pair("syncnode", stats.fSyncNode)); + obj.push_back(Pair("whitelisted", stats.fWhitelisted)); ret.push_back(obj); } diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 48b87f5139..7d7e03d96b 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -32,6 +32,7 @@ using namespace std; static std::string strRPCUserColonPass; +static bool fRPCRunning = false; // These are created by StartRPCThreads, destroyed in StopRPCThreads static asio::io_service* rpc_io_service = NULL; static map<string, boost::shared_ptr<deadline_timer> > deadlineTimers; @@ -659,6 +660,7 @@ void StartRPCThreads() rpc_worker_group = new boost::thread_group(); for (int i = 0; i < GetArg("-rpcthreads", 4); i++) rpc_worker_group->create_thread(boost::bind(&asio::io_service::run, rpc_io_service)); + fRPCRunning = true; } void StartDummyRPCThread() @@ -671,12 +673,15 @@ void StartDummyRPCThread() rpc_dummy_work = new asio::io_service::work(*rpc_io_service); rpc_worker_group = new boost::thread_group(); rpc_worker_group->create_thread(boost::bind(&asio::io_service::run, rpc_io_service)); + fRPCRunning = true; } } void StopRPCThreads() { if (rpc_io_service == NULL) return; + // Set this to false first, so that longpolling loops will exit when woken up + fRPCRunning = false; // First, cancel all timers and acceptors // This is not done automatically by ->stop(), and in some cases the destructor of @@ -698,6 +703,7 @@ void StopRPCThreads() deadlineTimers.clear(); rpc_io_service->stop(); + cvBlockChange.notify_all(); if (rpc_worker_group != NULL) rpc_worker_group->join_all(); delete rpc_dummy_work; rpc_dummy_work = NULL; @@ -706,6 +712,11 @@ void StopRPCThreads() delete rpc_io_service; rpc_io_service = NULL; } +bool IsRPCRunning() +{ + return fRPCRunning; +} + void RPCRunHandler(const boost::system::error_code& err, boost::function<void(void)> func) { if (!err) diff --git a/src/rpcserver.h b/src/rpcserver.h index e32eb975a1..31badadd6d 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -40,6 +40,8 @@ void StartRPCThreads(); void StartDummyRPCThread(); /* Stop RPC threads */ void StopRPCThreads(); +/* Query whether RPC is running */ +bool IsRPCRunning(); /* Type-check arguments; throws JSONRPCError if wrong type given. Does not check that diff --git a/src/sync.h b/src/sync.h index 077ed59b89..cd319e0171 100644 --- a/src/sync.h +++ b/src/sync.h @@ -84,6 +84,9 @@ typedef AnnotatedMixin<boost::recursive_mutex> CCriticalSection; /** Wrapped boost mutex: supports waiting but not recursive locking */ typedef AnnotatedMixin<boost::mutex> CWaitableCriticalSection; +/** Just a typedef for boost::condition_variable, can be wrapped later if desired */ +typedef boost::condition_variable CConditionVariable; + #ifdef DEBUG_LOCKORDER void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false); void LeaveCritical(); diff --git a/src/wallet.cpp b/src/wallet.cpp index 8fdc5f4b20..560cbc10b9 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1075,7 +1075,7 @@ int64_t CWallet::GetWatchOnlyBalance() const { int64_t nTotal = 0; { - LOCK(cs_wallet); + LOCK2(cs_main, cs_wallet); for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; @@ -1091,7 +1091,7 @@ int64_t CWallet::GetUnconfirmedWatchOnlyBalance() const { int64_t nTotal = 0; { - LOCK(cs_wallet); + LOCK2(cs_main, cs_wallet); for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; @@ -1106,7 +1106,7 @@ int64_t CWallet::GetImmatureWatchOnlyBalance() const { int64_t nTotal = 0; { - LOCK(cs_wallet); + LOCK2(cs_main, cs_wallet); for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; |