diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/addrman.cpp | 8 | ||||
-rw-r--r-- | src/addrman.h | 2 | ||||
-rw-r--r-- | src/init.cpp | 5 | ||||
-rw-r--r-- | src/main.cpp | 19 | ||||
-rw-r--r-- | src/main.h | 5 | ||||
-rw-r--r-- | src/net.cpp | 67 | ||||
-rw-r--r-- | src/net.h | 11 | ||||
-rw-r--r-- | src/netbase.cpp | 5 | ||||
-rw-r--r-- | src/netbase.h | 1 | ||||
-rw-r--r-- | src/qt/forms/rpcconsole.ui | 122 | ||||
-rw-r--r-- | src/qt/peertablemodel.cpp | 5 | ||||
-rw-r--r-- | src/qt/rpcconsole.cpp | 50 | ||||
-rw-r--r-- | src/qt/rpcconsole.h | 4 | ||||
-rw-r--r-- | src/rpcclient.cpp | 2 | ||||
-rw-r--r-- | src/rpcnet.cpp | 130 | ||||
-rw-r--r-- | src/rpcprotocol.h | 2 | ||||
-rw-r--r-- | src/rpcserver.cpp | 4 | ||||
-rw-r--r-- | src/rpcserver.h | 4 | ||||
-rw-r--r-- | src/scheduler.cpp | 4 | ||||
-rw-r--r-- | src/test/alert_tests.cpp | 10 | ||||
-rw-r--r-- | src/test/rpc_tests.cpp | 56 | ||||
-rw-r--r-- | src/wallet/db.cpp | 12 | ||||
-rw-r--r-- | src/wallet/db.h | 4 | ||||
-rw-r--r-- | src/wallet/rpcwallet.cpp | 6 |
24 files changed, 447 insertions, 91 deletions
diff --git a/src/addrman.cpp b/src/addrman.cpp index c41ee3f9fc..b605f4351d 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -8,8 +8,6 @@ #include "serialize.h" #include "streams.h" -using namespace std; - int CAddrInfo::GetTriedBucket(const uint256& nKey) const { uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetHash().GetCheapHash(); @@ -68,7 +66,7 @@ double CAddrInfo::GetChance(int64_t nNow) const fChance *= 0.01; // deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages. - fChance *= pow(0.66, min(nAttempts, 8)); + fChance *= pow(0.66, std::min(nAttempts, 8)); return fChance; } @@ -258,7 +256,7 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60); int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60); if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty)) - pinfo->nTime = max((int64_t)0, addr.nTime - nTimePenalty); + pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty); // add services pinfo->nServices |= addr.nServices; @@ -283,7 +281,7 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP return false; } else { pinfo = Create(addr, source, &nId); - pinfo->nTime = max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty); + pinfo->nTime = std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty); nNew++; fNew = true; } diff --git a/src/addrman.h b/src/addrman.h index 373b0f39f3..2623d89809 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -458,7 +458,7 @@ public: } //! Return the number of (unique) addresses in all tables. - int size() + size_t size() const { return vRandom.size(); } diff --git a/src/init.cpp b/src/init.cpp index 277a16ad0d..bcdd1f2f3d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -266,6 +266,7 @@ std::string HelpMessage(HelpMessageMode mode) // Do not translate _(...) -help-debug options, Many technical terms, and only a very small audience, so is unnecessary stress to translators. string strUsage = HelpMessageGroup(_("Options:")); strUsage += HelpMessageOpt("-?", _("This help message")); + strUsage += HelpMessageOpt("-alerts", strprintf(_("Receive and display P2P network alerts (default: %u)"), DEFAULT_ALERTS)); strUsage += HelpMessageOpt("-alertnotify=<cmd>", _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)")); strUsage += HelpMessageOpt("-blocknotify=<cmd>", _("Execute command when the best block changes (%s in cmd is replaced by block hash)")); strUsage += HelpMessageOpt("-checkblocks=<n>", strprintf(_("How many blocks to check at startup (default: %u, 0 = all)"), 288)); @@ -865,6 +866,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", true); nMaxDatacarrierBytes = GetArg("-datacarriersize", nMaxDatacarrierBytes); + fAlerts = GetBoolArg("-alerts", DEFAULT_ALERTS); + // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log // Initialize elliptic curve code @@ -1430,7 +1433,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // Monitor the chain, and alert if we get blocks much quicker or slower than expected int64_t nPowTargetSpacing = Params().GetConsensus().nPowTargetSpacing; CScheduler::Function f = boost::bind(&PartitionCheck, &IsInitialBlockDownload, - boost::ref(cs_main), boost::cref(chainActive), nPowTargetSpacing); + boost::ref(cs_main), boost::cref(pindexBestHeader), nPowTargetSpacing); scheduler.scheduleEvery(f, nPowTargetSpacing); #ifdef ENABLE_WALLET diff --git a/src/main.cpp b/src/main.cpp index 69c972a79f..0be54ebd41 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -61,6 +61,7 @@ bool fCheckBlockIndex = false; bool fCheckpointsEnabled = true; size_t nCoinCacheUsage = 5000 * 300; uint64_t nPruneTarget = 0; +bool fAlerts = DEFAULT_ALERTS; /** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */ CFeeRate minRelayTxFee = CFeeRate(1000); @@ -1723,9 +1724,10 @@ void ThreadScriptCheck() { // we're being fed a bad chain (blocks being generated much // too slowly or too quickly). // -void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CChain& chain, int64_t nPowTargetSpacing) +void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader, + int64_t nPowTargetSpacing) { - if (initialDownloadCheck()) return; + if (bestHeader == NULL || initialDownloadCheck()) return; static int64_t lastAlertTime = 0; int64_t now = GetAdjustedTime(); @@ -1741,10 +1743,13 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const int64_t startTime = GetAdjustedTime()-SPAN_SECONDS; LOCK(cs); - int h = chain.Height(); - while (h > 0 && chain[h]->GetBlockTime() >= startTime) - --h; - int nBlocks = chain.Height()-h; + const CBlockIndex* i = bestHeader; + int nBlocks = 0; + while (i->GetBlockTime() >= startTime) { + ++nBlocks; + i = i->pprev; + if (i == NULL) return; // Ran out of chain, we must not be fully sync'ed + } // How likely is it to find that many by chance? double p = boost::math::pdf(poisson, nBlocks); @@ -4622,7 +4627,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } - else if (strCommand == "alert") + else if (fAlerts && strCommand == "alert") { CAlert alert; vRecv >> alert; diff --git a/src/main.h b/src/main.h index 7eaf58d716..4e2efaada0 100644 --- a/src/main.h +++ b/src/main.h @@ -52,6 +52,8 @@ static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000; static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0; /** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/ static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 50000; +/** Default for accepting alerts from the P2P network. */ +static const bool DEFAULT_ALERTS = true; /** The maximum size for transactions we're willing to relay/mine */ static const unsigned int MAX_STANDARD_TX_SIZE = 100000; /** Maximum number of signature check operations in an IsStandard() P2SH script */ @@ -113,6 +115,7 @@ extern bool fCheckBlockIndex; extern bool fCheckpointsEnabled; extern size_t nCoinCacheUsage; extern CFeeRate minRelayTxFee; +extern bool fAlerts; /** Best header we've seen so far (used for getheaders queries' starting points). */ extern CBlockIndex *pindexBestHeader; @@ -186,7 +189,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle); /** Run an instance of the script checking thread */ void ThreadScriptCheck(); /** Try to detect Partition (network isolation) attacks against us */ -void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CChain& chain, int64_t nPowTargetSpacing); +void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader, int64_t nPowTargetSpacing); /** Check whether we are doing an initial block download (synchronizing from disk or network) */ bool IsInitialBlockDownload(); /** Format a string that describes several potential problems detected by the core */ diff --git a/src/net.cpp b/src/net.cpp index 42ac0e50ea..6b8a0a2b1e 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -332,6 +332,15 @@ CNode* FindNode(const CNetAddr& ip) return NULL; } +CNode* FindNode(const CSubNet& subNet) +{ + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + if (subNet.Match((CNetAddr)pnode->addr)) + return (pnode); + return NULL; +} + CNode* FindNode(const std::string& addrName) { LOCK(cs_vNodes); @@ -434,7 +443,7 @@ void CNode::PushVersion() -std::map<CNetAddr, int64_t> CNode::setBanned; +std::map<CSubNet, int64_t> CNode::setBanned; CCriticalSection CNode::cs_setBanned; void CNode::ClearBanned() @@ -447,7 +456,24 @@ bool CNode::IsBanned(CNetAddr ip) bool fResult = false; { LOCK(cs_setBanned); - std::map<CNetAddr, int64_t>::iterator i = setBanned.find(ip); + for (std::map<CSubNet, int64_t>::iterator it = setBanned.begin(); it != setBanned.end(); it++) + { + CSubNet subNet = (*it).first; + int64_t t = (*it).second; + + if(subNet.Match(ip) && GetTime() < t) + fResult = true; + } + } + return fResult; +} + +bool CNode::IsBanned(CSubNet subnet) +{ + bool fResult = false; + { + LOCK(cs_setBanned); + std::map<CSubNet, int64_t>::iterator i = setBanned.find(subnet); if (i != setBanned.end()) { int64_t t = (*i).second; @@ -458,14 +484,37 @@ bool CNode::IsBanned(CNetAddr ip) return fResult; } -bool CNode::Ban(const CNetAddr &addr) { +void CNode::Ban(const CNetAddr& addr, int64_t bantimeoffset, bool sinceUnixEpoch) { + CSubNet subNet(addr.ToString()+(addr.IsIPv4() ? "/32" : "/128")); + Ban(subNet, bantimeoffset, sinceUnixEpoch); +} + +void CNode::Ban(const CSubNet& subNet, int64_t bantimeoffset, bool sinceUnixEpoch) { int64_t banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban - { - LOCK(cs_setBanned); - if (setBanned[addr] < banTime) - setBanned[addr] = banTime; - } - return true; + if (bantimeoffset > 0) + banTime = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset; + + LOCK(cs_setBanned); + if (setBanned[subNet] < banTime) + setBanned[subNet] = banTime; +} + +bool CNode::Unban(const CNetAddr &addr) { + CSubNet subNet(addr.ToString()+(addr.IsIPv4() ? "/32" : "/128")); + return Unban(subNet); +} + +bool CNode::Unban(const CSubNet &subNet) { + LOCK(cs_setBanned); + if (setBanned.erase(subNet)) + return true; + return false; +} + +void CNode::GetBanned(std::map<CSubNet, int64_t> &banMap) +{ + LOCK(cs_setBanned); + banMap = setBanned; //create a thread safe copy } @@ -66,6 +66,7 @@ unsigned int SendBufferSize(); void AddOneShot(const std::string& strDest); void AddressCurrentlyConnected(const CService& addr); CNode* FindNode(const CNetAddr& ip); +CNode* FindNode(const CSubNet& subNet); CNode* FindNode(const std::string& addrName); CNode* FindNode(const CService& ip); CNode* ConnectNode(CAddress addrConnect, const char *pszDest = NULL); @@ -284,7 +285,7 @@ protected: // Denial-of-service detection/prevention // Key is IP address, value is banned-until-time - static std::map<CNetAddr, int64_t> setBanned; + static std::map<CSubNet, int64_t> setBanned; static CCriticalSection cs_setBanned; // Whitelisted ranges. Any node connecting from these is automatically @@ -606,7 +607,13 @@ public: // new code. static void ClearBanned(); // needed for unit testing static bool IsBanned(CNetAddr ip); - static bool Ban(const CNetAddr &ip); + static bool IsBanned(CSubNet subnet); + static void Ban(const CNetAddr &ip, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false); + static void Ban(const CSubNet &subNet, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false); + static bool Unban(const CNetAddr &ip); + static bool Unban(const CSubNet &ip); + static void GetBanned(std::map<CSubNet, int64_t> &banmap); + void copyStats(CNodeStats &stats); static bool IsWhitelistedRange(const CNetAddr &ip); diff --git a/src/netbase.cpp b/src/netbase.cpp index e3cb4e706f..adac5c2d07 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -1330,6 +1330,11 @@ bool operator!=(const CSubNet& a, const CSubNet& b) return !(a==b); } +bool operator<(const CSubNet& a, const CSubNet& b) +{ + return (a.network < b.network || (a.network == b.network && memcmp(a.netmask, b.netmask, 16) < 0)); +} + #ifdef WIN32 std::string NetworkErrorString(int err) { diff --git a/src/netbase.h b/src/netbase.h index 1f2957116e..27f0eac2a2 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -125,6 +125,7 @@ class CSubNet friend bool operator==(const CSubNet& a, const CSubNet& b); friend bool operator!=(const CSubNet& a, const CSubNet& b); + friend bool operator<(const CSubNet& a, const CSubNet& b); }; /** A combination of a network address (CNetAddr) and a (TCP) port */ diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui index c1eb185501..7ae8237476 100644 --- a/src/qt/forms/rpcconsole.ui +++ b/src/qt/forms/rpcconsole.ui @@ -745,13 +745,36 @@ </property> <layout class="QGridLayout" name="gridLayout_3"> <item row="0" column="0"> + <widget class="QLabel" name="label_30"> + <property name="text"> + <string>Whitelisted</string> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="peerWhitelisted"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="1" column="0"> <widget class="QLabel" name="label_23"> <property name="text"> <string>Direction</string> </property> </widget> </item> - <item row="0" column="2"> + <item row="1" column="2"> <widget class="QLabel" name="peerDirection"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -767,14 +790,14 @@ </property> </widget> </item> - <item row="1" column="0"> + <item row="2" column="0"> <widget class="QLabel" name="label_21"> <property name="text"> <string>Version</string> </property> </widget> </item> - <item row="1" column="2"> + <item row="2" column="2"> <widget class="QLabel" name="peerVersion"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -790,14 +813,14 @@ </property> </widget> </item> - <item row="2" column="0"> + <item row="3" column="0"> <widget class="QLabel" name="label_28"> <property name="text"> <string>User Agent</string> </property> </widget> </item> - <item row="2" column="2"> + <item row="3" column="2"> <widget class="QLabel" name="peerSubversion"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -813,14 +836,14 @@ </property> </widget> </item> - <item row="3" column="0"> + <item row="4" column="0"> <widget class="QLabel" name="label_4"> <property name="text"> <string>Services</string> </property> </widget> </item> - <item row="3" column="2"> + <item row="4" column="2"> <widget class="QLabel" name="peerServices"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -839,7 +862,7 @@ <item row="5" column="0"> <widget class="QLabel" name="label_29"> <property name="text"> - <string>Starting Height</string> + <string>Starting Block</string> </property> </widget> </item> @@ -862,7 +885,7 @@ <item row="6" column="0"> <widget class="QLabel" name="label_27"> <property name="text"> - <string>Sync Height</string> + <string>Synced Headers</string> </property> </widget> </item> @@ -883,13 +906,36 @@ </widget> </item> <item row="7" column="0"> + <widget class="QLabel" name="label_25"> + <property name="text"> + <string>Synced Blocks</string> + </property> + </widget> + </item> + <item row="7" column="2"> + <widget class="QLabel" name="peerCommonHeight"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="8" column="0"> <widget class="QLabel" name="label_24"> <property name="text"> <string>Ban Score</string> </property> </widget> </item> - <item row="7" column="2"> + <item row="8" column="2"> <widget class="QLabel" name="peerBanScore"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -905,14 +951,14 @@ </property> </widget> </item> - <item row="8" column="0"> + <item row="9" column="0"> <widget class="QLabel" name="label_22"> <property name="text"> <string>Connection Time</string> </property> </widget> </item> - <item row="8" column="2"> + <item row="9" column="2"> <widget class="QLabel" name="peerConnTime"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -928,14 +974,14 @@ </property> </widget> </item> - <item row="9" column="0"> + <item row="10" column="0"> <widget class="QLabel" name="label_15"> <property name="text"> <string>Last Send</string> </property> </widget> </item> - <item row="9" column="2"> + <item row="10" column="2"> <widget class="QLabel" name="peerLastSend"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -951,14 +997,14 @@ </property> </widget> </item> - <item row="10" column="0"> + <item row="11" column="0"> <widget class="QLabel" name="label_19"> <property name="text"> <string>Last Receive</string> </property> </widget> </item> - <item row="10" column="2"> + <item row="11" column="2"> <widget class="QLabel" name="peerLastRecv"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -974,14 +1020,14 @@ </property> </widget> </item> - <item row="11" column="0"> + <item row="12" column="0"> <widget class="QLabel" name="label_18"> <property name="text"> <string>Bytes Sent</string> </property> </widget> </item> - <item row="11" column="2"> + <item row="12" column="2"> <widget class="QLabel" name="peerBytesSent"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -997,14 +1043,14 @@ </property> </widget> </item> - <item row="12" column="0"> + <item row="13" column="0"> <widget class="QLabel" name="label_20"> <property name="text"> <string>Bytes Received</string> </property> </widget> </item> - <item row="12" column="2"> + <item row="13" column="2"> <widget class="QLabel" name="peerBytesRecv"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -1020,14 +1066,14 @@ </property> </widget> </item> - <item row="13" column="0"> + <item row="14" column="0"> <widget class="QLabel" name="label_26"> <property name="text"> <string>Ping Time</string> </property> </widget> </item> - <item row="13" column="2"> + <item row="14" column="2"> <widget class="QLabel" name="peerPingTime"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -1043,14 +1089,40 @@ </property> </widget> </item> - <item row="14" column="0"> + <item row="15" column="0"> + <widget class="QLabel" name="peerPingWaitLabel"> + <property name="toolTip"> + <string>The duration of a currently outstanding ping.</string> + </property> + <property name="text"> + <string>Ping Wait</string> + </property> + </widget> + </item> + <item row="15" column="2"> + <widget class="QLabel" name="peerPingWait"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="16" column="0"> <widget class="QLabel" name="label_timeoffset"> <property name="text"> <string>Time Offset</string> </property> </widget> </item> - <item row="14" column="2"> + <item row="16" column="2"> <widget class="QLabel" name="timeoffset"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -1066,7 +1138,7 @@ </property> </widget> </item> - <item row="15" column="1"> + <item row="17" column="1"> <spacer name="verticalSpacer_3"> <property name="orientation"> <enum>Qt::Vertical</enum> diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 220f273d02..f5904a4d8e 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -63,11 +63,12 @@ public: #if QT_VERSION >= 0x040700 cachedNodeStats.reserve(vNodes.size()); #endif - BOOST_FOREACH(CNode* pnode, vNodes) + foreach (CNode* pnode, vNodes) { CNodeCombinedStats stats; stats.nodeStateStats.nMisbehavior = 0; stats.nodeStateStats.nSyncHeight = -1; + stats.nodeStateStats.nCommonHeight = -1; stats.fNodeStateStatsAvailable = false; pnode->copyStats(stats.nodeStats); cachedNodeStats.append(stats); @@ -91,7 +92,7 @@ public: // build index map mapNodeRows.clear(); int row = 0; - BOOST_FOREACH(CNodeCombinedStats &stats, cachedNodeStats) + foreach (const CNodeCombinedStats& stats, cachedNodeStats) mapNodeRows.insert(std::pair<NodeId, int>(stats.nodeStats.nodeid, row++)); } diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index e99972d498..681617bd81 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -485,10 +485,10 @@ void RPCConsole::startExecutor() void RPCConsole::on_tabWidget_currentChanged(int index) { - if(ui->tabWidget->widget(index) == ui->tab_console) - { + if (ui->tabWidget->widget(index) == ui->tab_console) ui->lineEdit->setFocus(); - } + else if (ui->tabWidget->widget(index) != ui->tab_peers) + clearSelectedNode(); } void RPCConsole::on_openDebugLogfileButton_clicked() @@ -558,12 +558,11 @@ void RPCConsole::peerLayoutChanged() return; // find the currently selected row - int selectedRow; + int selectedRow = -1; QModelIndexList selectedModelIndex = ui->peerWidget->selectionModel()->selectedIndexes(); - if (selectedModelIndex.isEmpty()) - selectedRow = -1; - else + if (!selectedModelIndex.isEmpty()) { selectedRow = selectedModelIndex.first().row(); + } // check if our detail node has a row in the table (it may not necessarily // be at selectedRow since its position can change after a layout change) @@ -573,9 +572,6 @@ void RPCConsole::peerLayoutChanged() { // detail node dissapeared from table (node disconnected) fUnselect = true; - cachedNodeid = -1; - ui->detailWidget->hide(); - ui->peerHeading->setText(tr("Select a peer to view detailed information.")); } else { @@ -590,10 +586,8 @@ void RPCConsole::peerLayoutChanged() stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow); } - if (fUnselect && selectedRow >= 0) - { - ui->peerWidget->selectionModel()->select(QItemSelection(selectedModelIndex.first(), selectedModelIndex.last()), - QItemSelectionModel::Deselect); + if (fUnselect && selectedRow >= 0) { + clearSelectedNode(); } if (fReselect) @@ -611,7 +605,8 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats) cachedNodeid = stats->nodeStats.nodeid; // update the detail ui with latest node information - QString peerAddrDetails(QString::fromStdString(stats->nodeStats.addrName)); + QString peerAddrDetails(QString::fromStdString(stats->nodeStats.addrName) + " "); + peerAddrDetails += tr("(node id: %1)").arg(QString::number(stats->nodeStats.nodeid)); if (!stats->nodeStats.addrLocal.empty()) peerAddrDetails += "<br />" + tr("via %1").arg(QString::fromStdString(stats->nodeStats.addrLocal)); ui->peerHeading->setText(peerAddrDetails); @@ -622,11 +617,13 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats) ui->peerBytesRecv->setText(FormatBytes(stats->nodeStats.nRecvBytes)); ui->peerConnTime->setText(GUIUtil::formatDurationStr(GetTime() - stats->nodeStats.nTimeConnected)); ui->peerPingTime->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingTime)); + ui->peerPingWait->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingWait)); ui->timeoffset->setText(GUIUtil::formatTimeOffset(stats->nodeStats.nTimeOffset)); - ui->peerVersion->setText(QString("%1").arg(stats->nodeStats.nVersion)); + ui->peerVersion->setText(QString("%1").arg(QString::number(stats->nodeStats.nVersion))); ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer)); ui->peerDirection->setText(stats->nodeStats.fInbound ? tr("Inbound") : tr("Outbound")); - ui->peerHeight->setText(QString("%1").arg(stats->nodeStats.nStartingHeight)); + ui->peerHeight->setText(QString("%1").arg(QString::number(stats->nodeStats.nStartingHeight))); + ui->peerWhitelisted->setText(stats->nodeStats.fWhitelisted ? tr("Yes") : tr("No")); // This check fails for example if the lock was busy and // nodeStateStats couldn't be fetched. @@ -639,9 +636,12 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats) ui->peerSyncHeight->setText(QString("%1").arg(stats->nodeStateStats.nSyncHeight)); else ui->peerSyncHeight->setText(tr("Unknown")); - } else { - ui->peerBanScore->setText(tr("Fetching...")); - ui->peerSyncHeight->setText(tr("Fetching...")); + + // Common height is init to -1 + if (stats->nodeStateStats.nCommonHeight > -1) + ui->peerCommonHeight->setText(QString("%1").arg(stats->nodeStateStats.nCommonHeight)); + else + ui->peerCommonHeight->setText(tr("Unknown")); } ui->detailWidget->show(); @@ -688,6 +688,14 @@ void RPCConsole::disconnectSelectedNode() // Find the node, disconnect it and clear the selected node if (CNode *bannedNode = FindNode(strNode.toStdString())) { bannedNode->CloseSocketDisconnect(); - ui->peerWidget->selectionModel()->clearSelection(); + clearSelectedNode(); } } + +void RPCConsole::clearSelectedNode() +{ + ui->peerWidget->selectionModel()->clearSelection(); + cachedNodeid = -1; + ui->detailWidget->hide(); + ui->peerHeading->setText(tr("Select a peer to view detailed information.")); +} diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 767e9aaeea..a309df7ba7 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -76,7 +76,7 @@ public slots: void peerSelected(const QItemSelection &selected, const QItemSelection &deselected); /** Handle updated peer information */ void peerLayoutChanged(); - /** Disconnect a selected node on the Peers tab */ + /** Disconnect a selected node on the Peers tab */ void disconnectSelectedNode(); signals: @@ -90,6 +90,8 @@ private: void setTrafficGraphRange(int mins); /** show detailed information on ui about selected node */ void updateNodeDetail(const CNodeCombinedStats *stats); + /** clear the selected node */ + void clearSelectedNode(); enum ColumnWidths { diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index f254da5de0..1d94e4f61b 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -93,6 +93,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "estimatepriority", 0 }, { "prioritisetransaction", 1 }, { "prioritisetransaction", 2 }, + { "setban", 2 }, + { "setban", 3 }, }; class CRPCConvertTable diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index a36831de2a..5a26c7c3ae 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -214,6 +214,28 @@ UniValue addnode(const UniValue& params, bool fHelp) return NullUniValue; } +UniValue disconnectnode(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "disconnectnode \"node\" \n" + "\nImmediately disconnects from the specified node.\n" + "\nArguments:\n" + "1. \"node\" (string, required) The node (see getpeerinfo for nodes)\n" + "\nExamples:\n" + + HelpExampleCli("disconnectnode", "\"192.168.0.6:8333\"") + + HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"") + ); + + CNode* pNode = FindNode(params[0].get_str()); + if (pNode == NULL) + throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes"); + + pNode->CloseSocketDisconnect(); + + return NullUniValue; +} + UniValue getaddednodeinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) @@ -408,6 +430,7 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp) " }\n" " ,...\n" " ]\n" + " \"warnings\": \"...\" (string) any network warnings (such as alert messages) \n" "}\n" "\nExamples:\n" + HelpExampleCli("getnetworkinfo", "") @@ -439,5 +462,112 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp) } } obj.push_back(Pair("localaddresses", localAddresses)); + obj.push_back(Pair("warnings", GetWarnings("statusbar"))); return obj; } + +UniValue setban(const UniValue& params, bool fHelp) +{ + string strCommand; + if (params.size() >= 2) + strCommand = params[1].get_str(); + if (fHelp || params.size() < 2 || + (strCommand != "add" && strCommand != "remove")) + throw runtime_error( + "setban \"ip(/netmask)\" \"add|remove\" (bantime) (absolute)\n" + "\nAttempts add or remove a IP/Subnet from the banned list.\n" + "\nArguments:\n" + "1. \"ip(/netmask)\" (string, required) The IP/Subnet (see getpeerinfo for nodes ip) with a optional netmask (default is /32 = single ip)\n" + "2. \"command\" (string, required) 'add' to add a IP/Subnet to the list, 'remove' to remove a IP/Subnet from the list\n" + "3. \"bantime\" (numeric, optional) time in seconds how long (or until when if [absolute] is set) the ip is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)\n" + "4. \"absolute\" (boolean, optional) If set, the bantime must be a absolute timestamp in seconds since epoch (Jan 1 1970 GMT)\n" + "\nExamples:\n" + + HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400") + + HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"") + + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\" 86400") + ); + + CSubNet subNet; + CNetAddr netAddr; + bool isSubnet = false; + + if (params[0].get_str().find("/") != string::npos) + isSubnet = true; + + if (!isSubnet) + netAddr = CNetAddr(params[0].get_str()); + else + subNet = CSubNet(params[0].get_str()); + + if (! (isSubnet ? subNet.IsValid() : netAddr.IsValid()) ) + throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Invalid IP/Subnet"); + + if (strCommand == "add") + { + if (isSubnet ? CNode::IsBanned(subNet) : CNode::IsBanned(netAddr)) + throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned"); + + int64_t banTime = 0; //use standard bantime if not specified + if (params.size() >= 3 && !params[2].isNull()) + banTime = params[2].get_int64(); + + bool absolute = false; + if (params.size() == 4 && params[3].isTrue()) + absolute = true; + + isSubnet ? CNode::Ban(subNet, banTime, absolute) : CNode::Ban(netAddr, banTime, absolute); + + //disconnect possible nodes + while(CNode *bannedNode = (isSubnet ? FindNode(subNet) : FindNode(netAddr))) + bannedNode->CloseSocketDisconnect(); + } + else if(strCommand == "remove") + { + if (!( isSubnet ? CNode::Unban(subNet) : CNode::Unban(netAddr) )) + throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed"); + } + + return NullUniValue; +} + +UniValue listbanned(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "listbanned\n" + "\nList all banned IPs/Subnets.\n" + "\nExamples:\n" + + HelpExampleCli("listbanned", "") + + HelpExampleRpc("listbanned", "") + ); + + std::map<CSubNet, int64_t> banMap; + CNode::GetBanned(banMap); + + UniValue bannedAddresses(UniValue::VARR); + for (std::map<CSubNet, int64_t>::iterator it = banMap.begin(); it != banMap.end(); it++) + { + UniValue rec(UniValue::VOBJ); + rec.push_back(Pair("address", (*it).first.ToString())); + rec.push_back(Pair("banned_untill", (*it).second)); + bannedAddresses.push_back(rec); + } + + return bannedAddresses; +} + +UniValue clearbanned(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "clearbanned\n" + "\nClear all banned IPs.\n" + "\nExamples:\n" + + HelpExampleCli("clearbanned", "") + + HelpExampleRpc("clearbanned", "") + ); + + CNode::ClearBanned(); + + return NullUniValue; +} diff --git a/src/rpcprotocol.h b/src/rpcprotocol.h index b9fa091955..ccd2439c9f 100644 --- a/src/rpcprotocol.h +++ b/src/rpcprotocol.h @@ -63,6 +63,8 @@ enum RPCErrorCode RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, //! Still downloading initial blocks RPC_CLIENT_NODE_ALREADY_ADDED = -23, //! Node is already added RPC_CLIENT_NODE_NOT_ADDED = -24, //! Node has not been added before + RPC_CLIENT_NODE_NOT_CONNECTED = -29, //! Node to disconnect not found in connected nodes + RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //! Invalid IP/Subnet //! Wallet errors RPC_WALLET_ERROR = -4, //! Unspecified problem with wallet (key not found etc.) diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 3894dd08bb..6d089c6738 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -273,11 +273,15 @@ static const CRPCCommand vRPCCommands[] = /* P2P networking */ { "network", "getnetworkinfo", &getnetworkinfo, true }, { "network", "addnode", &addnode, true }, + { "network", "disconnectnode", &disconnectnode, true }, { "network", "getaddednodeinfo", &getaddednodeinfo, true }, { "network", "getconnectioncount", &getconnectioncount, true }, { "network", "getnettotals", &getnettotals, true }, { "network", "getpeerinfo", &getpeerinfo, true }, { "network", "ping", &ping, true }, + { "network", "setban", &setban, true }, + { "network", "listbanned", &listbanned, true }, + { "network", "clearbanned", &clearbanned, true }, /* Block chain and UTXO */ { "blockchain", "getblockchaininfo", &getblockchaininfo, true }, diff --git a/src/rpcserver.h b/src/rpcserver.h index 7b462a8b79..d08ae72f5c 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -151,8 +151,12 @@ extern UniValue getconnectioncount(const UniValue& params, bool fHelp); // in rp extern UniValue getpeerinfo(const UniValue& params, bool fHelp); extern UniValue ping(const UniValue& params, bool fHelp); extern UniValue addnode(const UniValue& params, bool fHelp); +extern UniValue disconnectnode(const UniValue& params, bool fHelp); extern UniValue getaddednodeinfo(const UniValue& params, bool fHelp); extern UniValue getnettotals(const UniValue& params, bool fHelp); +extern UniValue setban(const UniValue& params, bool fHelp); +extern UniValue listbanned(const UniValue& params, bool fHelp); +extern UniValue clearbanned(const UniValue& params, bool fHelp); extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpcdump.cpp extern UniValue importprivkey(const UniValue& params, bool fHelp); diff --git a/src/scheduler.cpp b/src/scheduler.cpp index c42eb7244d..d5bb588b71 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -50,8 +50,10 @@ void CScheduler::serviceQueue() // Keep waiting until timeout } #else + // Some boost versions have a conflicting overload of wait_until that returns void. + // Explicitly use a template here to avoid hitting that overload. while (!shouldStop() && !taskQueue.empty() && - newTaskScheduled.wait_until(lock, taskQueue.begin()->first) != boost::cv_status::timeout) { + newTaskScheduled.wait_until<>(lock, taskQueue.begin()->first) != boost::cv_status::timeout) { // Keep waiting until timeout } #endif diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp index 22cb475e02..38dcc6023c 100644 --- a/src/test/alert_tests.cpp +++ b/src/test/alert_tests.cpp @@ -201,7 +201,6 @@ BOOST_AUTO_TEST_CASE(PartitionAlert) { // Test PartitionCheck CCriticalSection csDummy; - CChain chainDummy; CBlockIndex indexDummy[100]; CChainParams& params = Params(CBaseChainParams::MAIN); int64_t nPowTargetSpacing = params.GetConsensus().nPowTargetSpacing; @@ -220,17 +219,16 @@ BOOST_AUTO_TEST_CASE(PartitionAlert) // Other members don't matter, the partition check code doesn't // use them } - chainDummy.SetTip(&indexDummy[99]); // Test 1: chain with blocks every nPowTargetSpacing seconds, // as normal, no worries: - PartitionCheck(falseFunc, csDummy, chainDummy, nPowTargetSpacing); + PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing); BOOST_CHECK(strMiscWarning.empty()); // Test 2: go 3.5 hours without a block, expect a warning: now += 3*60*60+30*60; SetMockTime(now); - PartitionCheck(falseFunc, csDummy, chainDummy, nPowTargetSpacing); + PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing); BOOST_CHECK(!strMiscWarning.empty()); BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning); strMiscWarning = ""; @@ -239,7 +237,7 @@ BOOST_AUTO_TEST_CASE(PartitionAlert) // code: now += 60*10; SetMockTime(now); - PartitionCheck(falseFunc, csDummy, chainDummy, nPowTargetSpacing); + PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing); BOOST_CHECK(strMiscWarning.empty()); // Test 4: get 2.5 times as many blocks as expected: @@ -248,7 +246,7 @@ BOOST_AUTO_TEST_CASE(PartitionAlert) int64_t quickSpacing = nPowTargetSpacing*2/5; for (int i = 0; i < 100; i++) // Tweak chain timestamps: indexDummy[i].nTime = now - (100-i)*quickSpacing; - PartitionCheck(falseFunc, csDummy, chainDummy, nPowTargetSpacing); + PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing); BOOST_CHECK(!strMiscWarning.empty()); BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning); strMiscWarning = ""; diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 08f988fdbf..e60281949e 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -177,4 +177,60 @@ BOOST_AUTO_TEST_CASE(rpc_boostasiotocnetaddr) BOOST_CHECK_EQUAL(BoostAsioToCNetAddr(boost::asio::ip::address::from_string("::ffff:127.0.0.1")).ToString(), "127.0.0.1"); } +BOOST_AUTO_TEST_CASE(rpc_ban) +{ + BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned"))); + + UniValue r; + BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0 add"))); + BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.0.0:8334")), runtime_error); //portnumber for setban not allowed + BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + UniValue ar = r.get_array(); + UniValue o1 = ar[0].get_obj(); + UniValue adr = find_value(o1, "address"); + BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/255.255.255.255"); + BOOST_CHECK_NO_THROW(CallRPC(string("setban 127.0.0.0 remove")));; + BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + ar = r.get_array(); + BOOST_CHECK_EQUAL(ar.size(), 0); + + BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/24 add 1607731200 true"))); + BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + ar = r.get_array(); + o1 = ar[0].get_obj(); + adr = find_value(o1, "address"); + UniValue banned_until = find_value(o1, "banned_untill"); + BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/255.255.255.0"); + BOOST_CHECK_EQUAL(banned_until.get_int64(), 1607731200); // absolute time check + + BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned"))); + + BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/24 add 200"))); + BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + ar = r.get_array(); + o1 = ar[0].get_obj(); + adr = find_value(o1, "address"); + banned_until = find_value(o1, "banned_untill"); + BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/255.255.255.0"); + int64_t now = GetTime(); + BOOST_CHECK(banned_until.get_int64() > now); + BOOST_CHECK(banned_until.get_int64()-now <= 200); + + // must throw an exception because 127.0.0.1 is in already banned suubnet range + BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.0.1 add")), runtime_error); + + BOOST_CHECK_NO_THROW(CallRPC(string("setban 127.0.0.0/24 remove")));; + BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + ar = r.get_array(); + BOOST_CHECK_EQUAL(ar.size(), 0); + + BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/255.255.0.0 add"))); + BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.1.1 add")), runtime_error); + + BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned"))); + BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + ar = r.get_array(); + BOOST_CHECK_EQUAL(ar.size(), 0); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index 53cfcf0961..e5bc653c33 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -43,7 +43,7 @@ void CDBEnv::EnvShutdown() if (ret != 0) LogPrintf("CDBEnv::EnvShutdown: Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret)); if (!fMockDb) - DbEnv(0).remove(path.string().c_str(), 0); + DbEnv(0).remove(strPath.c_str(), 0); } void CDBEnv::Reset() @@ -78,10 +78,10 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn) boost::this_thread::interruption_point(); - path = pathIn; - boost::filesystem::path pathLogDir = path / "database"; + strPath = pathIn.string(); + boost::filesystem::path pathLogDir = pathIn / "database"; TryCreateDirectory(pathLogDir); - boost::filesystem::path pathErrorFile = path / "db.log"; + boost::filesystem::path pathErrorFile = pathIn / "db.log"; LogPrintf("CDBEnv::Open: LogDir=%s ErrorFile=%s\n", pathLogDir.string(), pathErrorFile.string()); unsigned int nEnvFlags = 0; @@ -98,7 +98,7 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn) dbenv->set_flags(DB_AUTO_COMMIT, 1); dbenv->set_flags(DB_TXN_WRITE_NOSYNC, 1); dbenv->log_set_config(DB_LOG_AUTO_REMOVE, 1); - int ret = dbenv->open(path.string().c_str(), + int ret = dbenv->open(strPath.c_str(), DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | @@ -455,7 +455,7 @@ void CDBEnv::Flush(bool fShutdown) dbenv->log_archive(&listp, DB_ARCH_REMOVE); Close(); if (!fMockDb) - boost::filesystem::remove_all(path / "database"); + boost::filesystem::remove_all(boost::filesystem::path(strPath) / "database"); } } } diff --git a/src/wallet/db.h b/src/wallet/db.h index 2df6f6e5a9..64071caa3a 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -27,7 +27,9 @@ class CDBEnv private: bool fDbEnvInit; bool fMockDb; - boost::filesystem::path path; + // Don't change into boost::filesystem::path, as that can result in + // shutdown problems/crashes caused by a static initialized internal pointer. + std::string strPath; void EnvShutdown(); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index d284fcf15c..5404dd4aa0 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -733,12 +733,12 @@ UniValue getbalance(const UniValue& params, bool fHelp) if (params[0].get_str() == "*") { // Calculate total balance a different way from GetBalance() // (GetBalance() sums up all unspent TxOuts) - // getbalance and getbalance '*' 0 should return the same number + // getbalance and "getbalance * 1 true" should return the same number CAmount nBalance = 0; for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; - if (!wtx.IsTrusted() || wtx.GetBlocksToMaturity() > 0) + if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0) continue; CAmount allFee; @@ -2201,6 +2201,7 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp) " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n" " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n" " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n" + " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in btc/kb\n" "}\n" "\nExamples:\n" + HelpExampleCli("getwalletinfo", "") @@ -2219,6 +2220,7 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp) obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize())); if (pwalletMain->IsCrypted()) obj.push_back(Pair("unlocked_until", nWalletUnlockTime)); + obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()))); return obj; } |