From a31fa4ff01a7914a454a3ebb1f7709d790826e33 Mon Sep 17 00:00:00 2001 From: Patrick Lodder Date: Tue, 7 Jun 2022 11:19:08 +0200 Subject: [PATCH] net: implement a mockable micro time Throughout the code, we use mockable time in places where we want to test things that are subject to timing constraints, but don't want to wait for great amounts of time when we use the regtest network to ensure nothing gets broken. Mockable time is a system time override that is only enabled on chains that have the fMineBlocksOnDemand parameter set (currently: regtest). Currently, only time expressed in seconds is able to be mocked, but we have a couple of places where time is evaluated in microseconds, one of them being the time between sending out addr messages. This introduces a mockable time in microseconds and refactors the time evaluation for addr messages to be mocked, so that we can more reliably (and faster) test that. Other protocol features may want to use this too, but currently the sending of addr messages is the only place we test. Bitcoin Core nowadays has a much better time system that we inherit in future versions, but for the current scope I found this not worth the effort of backporting, as these would impact a much larger part of the code base. Inspired by: 1a8f0d5a from Amiti Uttarwar --- src/net_processing.cpp | 12 +++++++----- src/utiltime.cpp | 6 ++++++ src/utiltime.h | 1 + 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index cc3b865e5..0bae0805a 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -2888,16 +2888,18 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic& interr // Address refresh broadcast int64_t nNow = GetTimeMicros(); - if (!IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) { + int64_t current_time = GetMockableTimeMicros(); // add a mockable time + + if (!IsInitialBlockDownload() && pto->nNextLocalAddrSend < current_time) { AdvertiseLocal(pto); - pto->nNextLocalAddrSend = PoissonNextSend(nNow, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL); + pto->nNextLocalAddrSend = PoissonNextSend(current_time, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL); } // // Message: addr // - if (pto->nNextAddrSend < nNow) { - pto->nNextAddrSend = PoissonNextSend(nNow, AVG_ADDRESS_BROADCAST_INTERVAL); + if (pto->nNextAddrSend < current_time) { + pto->nNextAddrSend = PoissonNextSend(current_time, AVG_ADDRESS_BROADCAST_INTERVAL); std::vector vAddr; vAddr.reserve(pto->vAddrToSend.size()); BOOST_FOREACH(const CAddress& addr, pto->vAddrToSend) @@ -3254,7 +3256,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic& interr (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads); if (nNow > state.nDownloadingSince + nCalculatedDlWindow) { LogPrint("net", "Timeout downloading block: window=%d; inFlight=%d; validHeaders=%d; otherDlPeers=%d;", - nCalculatedDlWindow, state.vBlocksInFlight.size(), + nCalculatedDlWindow, state.vBlocksInFlight.size(), state.nBlocksInFlightValidHeaders, nOtherPeersWithValidatedDownloads); LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", queuedBlock.hash.ToString(), pto->id); pto->fDisconnect = true; diff --git a/src/utiltime.cpp b/src/utiltime.cpp index cf5e7f848..6b3f11d59 100644 --- a/src/utiltime.cpp +++ b/src/utiltime.cpp @@ -25,6 +25,12 @@ int64_t GetTime() return now; } +int64_t GetMockableTimeMicros() +{ + if (nMockTime) return nMockTime * 1000000; + return GetTimeMicros(); +} + void SetMockTime(int64_t nMockTimeIn) { nMockTime = nMockTimeIn; diff --git a/src/utiltime.h b/src/utiltime.h index 05c679049..12e9046b3 100644 --- a/src/utiltime.h +++ b/src/utiltime.h @@ -24,6 +24,7 @@ int64_t GetTimeMillis(); int64_t GetTimeMicros(); int64_t GetSystemTimeInSeconds(); // Like GetTime(), but not mockable int64_t GetLogTimeMicros(); +int64_t GetMockableTimeMicros(); void SetMockTime(int64_t nMockTimeIn); void MilliSleep(int64_t n);