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);