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.
This commit is contained in:
Suhas Daftuar 2017-01-19 13:01:18 -05:00
parent 054d664215
commit 99464bc38e
5 changed files with 28 additions and 18 deletions

View file

@ -391,7 +391,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize(); 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); CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, pszDest ? pszDest : "", false);
pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices); pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices);
pnode->nTimeConnected = GetTime(); pnode->nTimeConnected = GetSystemTimeInSeconds();
pnode->AddRef(); pnode->AddRef();
GetNodeSignals().InitializeNode(pnode, *this); GetNodeSignals().InitializeNode(pnode, *this);
{ {
@ -771,7 +771,7 @@ size_t CConnman::SocketSendData(CNode *pnode)
assert(data.size() > pnode->nSendOffset); assert(data.size() > pnode->nSendOffset);
int nBytes = send(pnode->hSocket, reinterpret_cast<const char*>(data.data()) + pnode->nSendOffset, data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT); int nBytes = send(pnode->hSocket, reinterpret_cast<const char*>(data.data()) + pnode->nSendOffset, data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
if (nBytes > 0) { if (nBytes > 0) {
pnode->nLastSend = GetTime(); pnode->nLastSend = GetSystemTimeInSeconds();
pnode->nSendBytes += nBytes; pnode->nSendBytes += nBytes;
pnode->nSendOffset += nBytes; pnode->nSendOffset += nBytes;
nSentSize += nBytes; nSentSize += nBytes;
@ -1284,7 +1284,7 @@ void CConnman::ThreadSocketHandler()
// //
// Inactivity checking // Inactivity checking
// //
int64_t nTime = GetTime(); int64_t nTime = GetSystemTimeInSeconds();
if (nTime - pnode->nTimeConnected > 60) if (nTime - pnode->nTimeConnected > 60)
{ {
if (pnode->nLastRecv == 0 || pnode->nLastSend == 0) if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
@ -2570,7 +2570,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
nLastRecv = 0; nLastRecv = 0;
nSendBytes = 0; nSendBytes = 0;
nRecvBytes = 0; nRecvBytes = 0;
nTimeConnected = GetTime(); nTimeConnected = GetSystemTimeInSeconds();
nTimeOffset = 0; nTimeOffset = 0;
addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
nVersion = 0; nVersion = 0;

View file

@ -1023,11 +1023,11 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
peerAddrDetails += "<br />" + tr("via %1").arg(QString::fromStdString(stats->nodeStats.addrLocal)); peerAddrDetails += "<br />" + tr("via %1").arg(QString::fromStdString(stats->nodeStats.addrLocal));
ui->peerHeading->setText(peerAddrDetails); ui->peerHeading->setText(peerAddrDetails);
ui->peerServices->setText(GUIUtil::formatServicesStr(stats->nodeStats.nServices)); ui->peerServices->setText(GUIUtil::formatServicesStr(stats->nodeStats.nServices));
ui->peerLastSend->setText(stats->nodeStats.nLastSend ? GUIUtil::formatDurationStr(GetTime() - stats->nodeStats.nLastSend) : tr("never")); ui->peerLastSend->setText(stats->nodeStats.nLastSend ? GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nLastSend) : tr("never"));
ui->peerLastRecv->setText(stats->nodeStats.nLastRecv ? GUIUtil::formatDurationStr(GetTime() - stats->nodeStats.nLastRecv) : tr("never")); ui->peerLastRecv->setText(stats->nodeStats.nLastRecv ? GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nLastRecv) : tr("never"));
ui->peerBytesSent->setText(FormatBytes(stats->nodeStats.nSendBytes)); ui->peerBytesSent->setText(FormatBytes(stats->nodeStats.nSendBytes));
ui->peerBytesRecv->setText(FormatBytes(stats->nodeStats.nRecvBytes)); 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->peerPingTime->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingTime));
ui->peerPingWait->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingWait)); ui->peerPingWait->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingWait));
ui->peerMinPing->setText(GUIUtil::formatPingTime(stats->nodeStats.dMinPing)); ui->peerMinPing->setText(GUIUtil::formatPingTime(stats->nodeStats.dMinPing));

View file

@ -431,22 +431,16 @@ UniValue setmocktime(const JSONRPCRequest& request)
if (!Params().MineBlocksOnDemand()) if (!Params().MineBlocksOnDemand())
throw runtime_error("setmocktime for regression testing (-regtest mode) only"); throw runtime_error("setmocktime for regression testing (-regtest mode) only");
// cs_vNodes is locked and node send/receive times are updated // For now, don't change mocktime if we're in the middle of validation, as
// atomically with the time change to prevent peers from being // this could have an effect on mempool time-based eviction, as well as
// disconnected because we think we haven't communicated with them // IsCurrentForFeeEstimation() and IsInitialBlockDownload().
// in a long time. // TODO: figure out the right way to synchronize around mocktime, and
// ensure all callsites of GetTime() are accessing this safely.
LOCK(cs_main); LOCK(cs_main);
RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM)); RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
SetMockTime(request.params[0].get_int64()); 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; return NullUniValue;
} }

View file

@ -46,6 +46,11 @@ int64_t GetTimeMicros()
return now; return now;
} }
int64_t GetSystemTimeInSeconds()
{
return GetTimeMicros()/1000000;
}
/** Return a time useful for the debug log */ /** Return a time useful for the debug log */
int64_t GetLogTimeMicros() int64_t GetLogTimeMicros()
{ {

View file

@ -9,9 +9,20 @@
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>
/**
* 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 GetTime();
int64_t GetTimeMillis(); int64_t GetTimeMillis();
int64_t GetTimeMicros(); int64_t GetTimeMicros();
int64_t GetSystemTimeInSeconds(); // Like GetTime(), but not mockable
int64_t GetLogTimeMicros(); int64_t GetLogTimeMicros();
void SetMockTime(int64_t nMockTimeIn); void SetMockTime(int64_t nMockTimeIn);
void MilliSleep(int64_t n); void MilliSleep(int64_t n);