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
This commit is contained in:
Patrick Lodder 2022-06-07 11:19:08 +02:00
parent ed487e80c7
commit a31fa4ff01
No known key found for this signature in database
GPG Key ID: 2D3A345B98D0DC1F
3 changed files with 14 additions and 5 deletions

View File

@ -2888,16 +2888,18 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& 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<CAddress> 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<bool>& 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;

View File

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

View File

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