From 99464bc38e9575ff47f8e33223b252dcea2055e3 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Thu, 19 Jan 2017 13:01:18 -0500 Subject: [PATCH] net: Consistently use GetTimeMicros() for inactivity checks The use of mocktime in test logic means that comparisons between GetTime() and GetTimeMicros()/1000000 are unreliable since the former can use mocktime values while the latter always gets the system clock; this changes the networking code's inactivity checks to consistently use the system clock for inactivity comparisons. Also remove some hacks from setmocktime() that are no longer needed, now that we're using the system clock for nLastSend and nLastRecv. --- src/net.cpp | 8 ++++---- src/qt/rpcconsole.cpp | 6 +++--- src/rpc/misc.cpp | 16 +++++----------- src/utiltime.cpp | 5 +++++ src/utiltime.h | 11 +++++++++++ 5 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index b275bdd80..97480df13 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -391,7 +391,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize(); CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, pszDest ? pszDest : "", false); pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices); - pnode->nTimeConnected = GetTime(); + pnode->nTimeConnected = GetSystemTimeInSeconds(); pnode->AddRef(); GetNodeSignals().InitializeNode(pnode, *this); { @@ -771,7 +771,7 @@ size_t CConnman::SocketSendData(CNode *pnode) assert(data.size() > pnode->nSendOffset); int nBytes = send(pnode->hSocket, reinterpret_cast(data.data()) + pnode->nSendOffset, data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT); if (nBytes > 0) { - pnode->nLastSend = GetTime(); + pnode->nLastSend = GetSystemTimeInSeconds(); pnode->nSendBytes += nBytes; pnode->nSendOffset += nBytes; nSentSize += nBytes; @@ -1284,7 +1284,7 @@ void CConnman::ThreadSocketHandler() // // Inactivity checking // - int64_t nTime = GetTime(); + int64_t nTime = GetSystemTimeInSeconds(); if (nTime - pnode->nTimeConnected > 60) { if (pnode->nLastRecv == 0 || pnode->nLastSend == 0) @@ -2570,7 +2570,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn nLastRecv = 0; nSendBytes = 0; nRecvBytes = 0; - nTimeConnected = GetTime(); + nTimeConnected = GetSystemTimeInSeconds(); nTimeOffset = 0; addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; nVersion = 0; diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 87d73b5f0..60406c205 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -1023,11 +1023,11 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats) peerAddrDetails += "
" + tr("via %1").arg(QString::fromStdString(stats->nodeStats.addrLocal)); ui->peerHeading->setText(peerAddrDetails); ui->peerServices->setText(GUIUtil::formatServicesStr(stats->nodeStats.nServices)); - ui->peerLastSend->setText(stats->nodeStats.nLastSend ? GUIUtil::formatDurationStr(GetTime() - stats->nodeStats.nLastSend) : tr("never")); - ui->peerLastRecv->setText(stats->nodeStats.nLastRecv ? GUIUtil::formatDurationStr(GetTime() - stats->nodeStats.nLastRecv) : tr("never")); + ui->peerLastSend->setText(stats->nodeStats.nLastSend ? GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nLastSend) : tr("never")); + ui->peerLastRecv->setText(stats->nodeStats.nLastRecv ? GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nLastRecv) : tr("never")); ui->peerBytesSent->setText(FormatBytes(stats->nodeStats.nSendBytes)); ui->peerBytesRecv->setText(FormatBytes(stats->nodeStats.nRecvBytes)); - ui->peerConnTime->setText(GUIUtil::formatDurationStr(GetTime() - stats->nodeStats.nTimeConnected)); + ui->peerConnTime->setText(GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nTimeConnected)); ui->peerPingTime->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingTime)); ui->peerPingWait->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingWait)); ui->peerMinPing->setText(GUIUtil::formatPingTime(stats->nodeStats.dMinPing)); diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 54d8c3e03..480c45516 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -431,22 +431,16 @@ UniValue setmocktime(const JSONRPCRequest& request) if (!Params().MineBlocksOnDemand()) throw runtime_error("setmocktime for regression testing (-regtest mode) only"); - // cs_vNodes is locked and node send/receive times are updated - // atomically with the time change to prevent peers from being - // disconnected because we think we haven't communicated with them - // in a long time. + // For now, don't change mocktime if we're in the middle of validation, as + // this could have an effect on mempool time-based eviction, as well as + // IsCurrentForFeeEstimation() and IsInitialBlockDownload(). + // TODO: figure out the right way to synchronize around mocktime, and + // ensure all callsites of GetTime() are accessing this safely. LOCK(cs_main); RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM)); SetMockTime(request.params[0].get_int64()); - uint64_t t = GetTime(); - if(g_connman) { - g_connman->ForEachNode([t](CNode* pnode) { - pnode->nLastSend = pnode->nLastRecv = t; - }); - } - return NullUniValue; } diff --git a/src/utiltime.cpp b/src/utiltime.cpp index 7c5ee7726..87a25866e 100644 --- a/src/utiltime.cpp +++ b/src/utiltime.cpp @@ -46,6 +46,11 @@ int64_t GetTimeMicros() return now; } +int64_t GetSystemTimeInSeconds() +{ + return GetTimeMicros()/1000000; +} + /** Return a time useful for the debug log */ int64_t GetLogTimeMicros() { diff --git a/src/utiltime.h b/src/utiltime.h index b2807267d..05c679049 100644 --- a/src/utiltime.h +++ b/src/utiltime.h @@ -9,9 +9,20 @@ #include #include +/** + * GetTimeMicros() and GetTimeMillis() both return the system time, but in + * different units. GetTime() returns the sytem time in seconds, but also + * supports mocktime, where the time can be specified by the user, eg for + * testing (eg with the setmocktime rpc, or -mocktime argument). + * + * TODO: Rework these functions to be type-safe (so that we don't inadvertently + * compare numbers with different units, or compare a mocktime to system time). + */ + int64_t GetTime(); int64_t GetTimeMillis(); int64_t GetTimeMicros(); +int64_t GetSystemTimeInSeconds(); // Like GetTime(), but not mockable int64_t GetLogTimeMicros(); void SetMockTime(int64_t nMockTimeIn); void MilliSleep(int64_t n);