Skip to content

Commit 9f7661c

Browse files
author
MarcoFalke
committed
Merge bitcoin/bitcoin#19499: p2p: Make timeout mockable and type safe, speed up test
fadc0c8 p2p: Make timeout mockable and type safe, speed up test (MarcoFalke) fa6d5a2 scripted-diff: Rename m_last_send and m_last_recv (MarcoFalke) Pull request description: Use type-safe time for better code readability/maintainability and mockable time for better testability. This speeds up the p2p_timeout test. This is also a bugfix for intermittent test issues like: https://cirrus-ci.com/task/4769904156999680?command=ci#L2836 Fixes #20654 ACKs for top commit: laanwj: Code review ACK fadc0c8 naumenkogs: ACK fadc0c8 Tree-SHA512: 28c6544c97f188c8a0fbc80411c74ab74ffd055885322c325aa3d1c404b29c3fd70a737e86083eecae58ef394db1cb56bc122d06cff63742aa89a8e868730c64
2 parents d5724b8 + fadc0c8 commit 9f7661c

File tree

12 files changed

+66
-58
lines changed

12 files changed

+66
-58
lines changed

src/net.cpp

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -586,8 +586,8 @@ void CNode::CopyStats(CNodeStats& stats)
586586
} else {
587587
stats.fRelayTxes = false;
588588
}
589-
X(nLastSend);
590-
X(nLastRecv);
589+
X(m_last_send);
590+
X(m_last_recv);
591591
X(nLastTXTime);
592592
X(nLastBlockTime);
593593
X(nTimeConnected);
@@ -634,7 +634,7 @@ bool CNode::ReceiveMsgBytes(Span<const uint8_t> msg_bytes, bool& complete)
634634
complete = false;
635635
const auto time = GetTime<std::chrono::microseconds>();
636636
LOCK(cs_vRecv);
637-
nLastRecv = std::chrono::duration_cast<std::chrono::seconds>(time).count();
637+
m_last_recv = std::chrono::duration_cast<std::chrono::seconds>(time);
638638
nRecvBytes += msg_bytes.size();
639639
while (msg_bytes.size() > 0) {
640640
// absorb network data
@@ -805,7 +805,7 @@ size_t CConnman::SocketSendData(CNode& node) const
805805
nBytes = send(node.hSocket, reinterpret_cast<const char*>(data.data()) + node.nSendOffset, data.size() - node.nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
806806
}
807807
if (nBytes > 0) {
808-
node.nLastSend = GetTimeSeconds();
808+
node.m_last_send = GetTime<std::chrono::seconds>();
809809
node.nSendBytes += nBytes;
810810
node.nSendOffset += nBytes;
811811
nSentSize += nBytes;
@@ -1318,31 +1318,33 @@ void CConnman::NotifyNumConnectionsChanged()
13181318
}
13191319
}
13201320

1321-
bool CConnman::ShouldRunInactivityChecks(const CNode& node, int64_t now) const
1321+
bool CConnman::ShouldRunInactivityChecks(const CNode& node, std::chrono::seconds now) const
13221322
{
1323-
return node.nTimeConnected + m_peer_connect_timeout < now;
1323+
return std::chrono::seconds{node.nTimeConnected} + m_peer_connect_timeout < now;
13241324
}
13251325

13261326
bool CConnman::InactivityCheck(const CNode& node) const
13271327
{
1328-
// Use non-mockable system time (otherwise these timers will pop when we
1329-
// use setmocktime in the tests).
1330-
int64_t now = GetTimeSeconds();
1328+
// Tests that see disconnects after using mocktime can start nodes with a
1329+
// large timeout. For example, -peertimeout=999999999.
1330+
const auto now{GetTime<std::chrono::seconds>()};
1331+
const auto last_send{node.m_last_send.load()};
1332+
const auto last_recv{node.m_last_recv.load()};
13311333

13321334
if (!ShouldRunInactivityChecks(node, now)) return false;
13331335

1334-
if (node.nLastRecv == 0 || node.nLastSend == 0) {
1335-
LogPrint(BCLog::NET, "socket no message in first %i seconds, %d %d peer=%d\n", m_peer_connect_timeout, node.nLastRecv != 0, node.nLastSend != 0, node.GetId());
1336+
if (last_recv.count() == 0 || last_send.count() == 0) {
1337+
LogPrint(BCLog::NET, "socket no message in first %i seconds, %d %d peer=%d\n", count_seconds(m_peer_connect_timeout), last_recv.count() != 0, last_send.count() != 0, node.GetId());
13361338
return true;
13371339
}
13381340

1339-
if (now > node.nLastSend + TIMEOUT_INTERVAL) {
1340-
LogPrint(BCLog::NET, "socket sending timeout: %is peer=%d\n", now - node.nLastSend, node.GetId());
1341+
if (now > last_send + TIMEOUT_INTERVAL) {
1342+
LogPrint(BCLog::NET, "socket sending timeout: %is peer=%d\n", count_seconds(now - last_send), node.GetId());
13411343
return true;
13421344
}
13431345

1344-
if (now > node.nLastRecv + TIMEOUT_INTERVAL) {
1345-
LogPrint(BCLog::NET, "socket receive timeout: %is peer=%d\n", now - node.nLastRecv, node.GetId());
1346+
if (now > last_recv + TIMEOUT_INTERVAL) {
1347+
LogPrint(BCLog::NET, "socket receive timeout: %is peer=%d\n", count_seconds(now - last_recv), node.GetId());
13461348
return true;
13471349
}
13481350

src/net.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ static const bool DEFAULT_WHITELISTRELAY = true;
4848
static const bool DEFAULT_WHITELISTFORCERELAY = false;
4949

5050
/** Time after which to disconnect, after waiting for a ping response (or inactivity). */
51-
static const int TIMEOUT_INTERVAL = 20 * 60;
51+
static constexpr std::chrono::minutes TIMEOUT_INTERVAL{20};
5252
/** Run the feeler connection loop once every 2 minutes. **/
5353
static constexpr auto FEELER_INTERVAL = 2min;
5454
/** Run the extra block-relay-only connection loop once every 5 minutes. **/
@@ -241,8 +241,8 @@ class CNodeStats
241241
NodeId nodeid;
242242
ServiceFlags nServices;
243243
bool fRelayTxes;
244-
int64_t nLastSend;
245-
int64_t nLastRecv;
244+
std::chrono::seconds m_last_send;
245+
std::chrono::seconds m_last_recv;
246246
int64_t nLastTXTime;
247247
int64_t nLastBlockTime;
248248
int64_t nTimeConnected;
@@ -420,8 +420,8 @@ class CNode
420420

421421
uint64_t nRecvBytes GUARDED_BY(cs_vRecv){0};
422422

423-
std::atomic<int64_t> nLastSend{0};
424-
std::atomic<int64_t> nLastRecv{0};
423+
std::atomic<std::chrono::seconds> m_last_send{0s};
424+
std::atomic<std::chrono::seconds> m_last_recv{0s};
425425
//! Unix epoch time at peer connection, in seconds.
426426
const int64_t nTimeConnected;
427427
std::atomic<int64_t> nTimeOffset{0};
@@ -784,7 +784,7 @@ class CConnman
784784
m_msgproc = connOptions.m_msgproc;
785785
nSendBufferMaxSize = connOptions.nSendBufferMaxSize;
786786
nReceiveFloodSize = connOptions.nReceiveFloodSize;
787-
m_peer_connect_timeout = connOptions.m_peer_connect_timeout;
787+
m_peer_connect_timeout = std::chrono::seconds{connOptions.m_peer_connect_timeout};
788788
{
789789
LOCK(cs_totalBytesSent);
790790
nMaxOutboundLimit = connOptions.nMaxOutboundLimit;
@@ -942,7 +942,7 @@ class CConnman
942942
std::chrono::microseconds PoissonNextSendInbound(std::chrono::microseconds now, std::chrono::seconds average_interval);
943943

944944
/** Return true if we should disconnect the peer for failing an inactivity check. */
945-
bool ShouldRunInactivityChecks(const CNode& node, int64_t secs_now) const;
945+
bool ShouldRunInactivityChecks(const CNode& node, std::chrono::seconds now) const;
946946

947947
private:
948948
struct ListenSocket {
@@ -1084,7 +1084,7 @@ class CConnman
10841084
uint64_t nMaxOutboundLimit GUARDED_BY(cs_totalBytesSent);
10851085

10861086
// P2P timeout in seconds
1087-
int64_t m_peer_connect_timeout;
1087+
std::chrono::seconds m_peer_connect_timeout;
10881088

10891089
// Whitelisted ranges. Any node connecting from these is automatically
10901090
// whitelisted (as well as those connecting to whitelisted binds).

src/net_processing.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4357,9 +4357,10 @@ void PeerManagerImpl::CheckForStaleTipAndEvictPeers()
43574357

43584358
void PeerManagerImpl::MaybeSendPing(CNode& node_to, Peer& peer, std::chrono::microseconds now)
43594359
{
4360-
if (m_connman.ShouldRunInactivityChecks(node_to, std::chrono::duration_cast<std::chrono::seconds>(now).count()) &&
4360+
if (m_connman.ShouldRunInactivityChecks(node_to, std::chrono::duration_cast<std::chrono::seconds>(now)) &&
43614361
peer.m_ping_nonce_sent &&
4362-
now > peer.m_ping_start.load() + std::chrono::seconds{TIMEOUT_INTERVAL}) {
4362+
now > peer.m_ping_start.load() + TIMEOUT_INTERVAL)
4363+
{
43634364
// The ping timeout is using mocktime. To disable the check during
43644365
// testing, increase -peertimeout.
43654366
LogPrint(BCLog::NET, "ping timeout: %fs peer=%d\n", 0.000001 * count_microseconds(now - peer.m_ping_start.load()), peer.m_id);

src/qt/guiutil.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <script/script.h>
2121
#include <script/standard.h>
2222
#include <util/system.h>
23+
#include <util/time.h>
2324

2425
#ifdef WIN32
2526
#ifndef NOMINMAX
@@ -705,8 +706,9 @@ QString ConnectionTypeToQString(ConnectionType conn_type, bool prepend_direction
705706
assert(false);
706707
}
707708

708-
QString formatDurationStr(int secs)
709+
QString formatDurationStr(std::chrono::seconds dur)
709710
{
711+
const auto secs = count_seconds(dur);
710712
QStringList strList;
711713
int days = secs / 86400;
712714
int hours = (secs % 86400) / 3600;

src/qt/guiutil.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ namespace GUIUtil
221221
QString ConnectionTypeToQString(ConnectionType conn_type, bool prepend_direction);
222222

223223
/** Convert seconds into a QString with days, hours, mins, secs */
224-
QString formatDurationStr(int secs);
224+
QString formatDurationStr(std::chrono::seconds dur);
225225

226226
/** Format CNodeStats.nServices bitmask into a user-readable string */
227227
QString formatServicesStr(quint64 mask);

src/qt/rpcconsole.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,7 +1141,7 @@ void RPCConsole::on_sldGraphRange_valueChanged(int value)
11411141
void RPCConsole::setTrafficGraphRange(int mins)
11421142
{
11431143
ui->trafficGraph->setGraphRangeMins(mins);
1144-
ui->lblGraphRange->setText(GUIUtil::formatDurationStr(mins * 60));
1144+
ui->lblGraphRange->setText(GUIUtil::formatDurationStr(std::chrono::minutes{mins}));
11451145
}
11461146

11471147
void RPCConsole::updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut)
@@ -1172,12 +1172,12 @@ void RPCConsole::updateDetailWidget()
11721172
if (stats->nodeStats.m_bip152_highbandwidth_from) bip152_hb_settings += (bip152_hb_settings.isEmpty() ? ts.from : QLatin1Char('/') + ts.from);
11731173
if (bip152_hb_settings.isEmpty()) bip152_hb_settings = ts.no;
11741174
ui->peerHighBandwidth->setText(bip152_hb_settings);
1175-
const int64_t time_now{GetTimeSeconds()};
1176-
ui->peerConnTime->setText(GUIUtil::formatDurationStr(time_now - stats->nodeStats.nTimeConnected));
1177-
ui->peerLastBlock->setText(TimeDurationField(time_now, stats->nodeStats.nLastBlockTime));
1178-
ui->peerLastTx->setText(TimeDurationField(time_now, stats->nodeStats.nLastTXTime));
1179-
ui->peerLastSend->setText(TimeDurationField(time_now, stats->nodeStats.nLastSend));
1180-
ui->peerLastRecv->setText(TimeDurationField(time_now, stats->nodeStats.nLastRecv));
1175+
const auto time_now{GetTime<std::chrono::seconds>()};
1176+
ui->peerConnTime->setText(GUIUtil::formatDurationStr(time_now - std::chrono::seconds{stats->nodeStats.nTimeConnected}));
1177+
ui->peerLastBlock->setText(TimeDurationField(time_now, std::chrono::seconds{stats->nodeStats.nLastBlockTime}));
1178+
ui->peerLastTx->setText(TimeDurationField(time_now, std::chrono::seconds{stats->nodeStats.nLastTXTime}));
1179+
ui->peerLastSend->setText(TimeDurationField(time_now, stats->nodeStats.m_last_send));
1180+
ui->peerLastRecv->setText(TimeDurationField(time_now, stats->nodeStats.m_last_recv));
11811181
ui->peerBytesSent->setText(GUIUtil::formatBytes(stats->nodeStats.nSendBytes));
11821182
ui->peerBytesRecv->setText(GUIUtil::formatBytes(stats->nodeStats.nRecvBytes));
11831183
ui->peerPingTime->setText(GUIUtil::formatPingTime(stats->nodeStats.m_last_ping_time));

src/qt/rpcconsole.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,9 @@ public Q_SLOTS:
175175
void updateNetworkState();
176176

177177
/** Helper for the output of a time duration field. Inputs are UNIX epoch times. */
178-
QString TimeDurationField(uint64_t time_now, uint64_t time_at_event) const {
179-
return time_at_event ? GUIUtil::formatDurationStr(time_now - time_at_event) : tr("Never");
178+
QString TimeDurationField(std::chrono::seconds time_now, std::chrono::seconds time_at_event) const
179+
{
180+
return time_at_event.count() ? GUIUtil::formatDurationStr(time_now - time_at_event) : tr("Never");
180181
}
181182

182183
private Q_SLOTS:

src/rpc/net.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,8 @@ static RPCHelpMan getpeerinfo()
196196
obj.pushKV("services", strprintf("%016x", stats.nServices));
197197
obj.pushKV("servicesnames", GetServicesNames(stats.nServices));
198198
obj.pushKV("relaytxes", stats.fRelayTxes);
199-
obj.pushKV("lastsend", stats.nLastSend);
200-
obj.pushKV("lastrecv", stats.nLastRecv);
199+
obj.pushKV("lastsend", count_seconds(stats.m_last_send));
200+
obj.pushKV("lastrecv", count_seconds(stats.m_last_recv));
201201
obj.pushKV("last_transaction", stats.nLastTXTime);
202202
obj.pushKV("last_block", stats.nLastBlockTime);
203203
obj.pushKV("bytessent", stats.nSendBytes);

src/test/denialofservice_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
5353
const CChainParams& chainparams = Params();
5454
auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman);
5555
// Disable inactivity checks for this test to avoid interference
56-
static_cast<ConnmanTestMsg*>(connman.get())->SetPeerConnectTimeout(99999);
56+
static_cast<ConnmanTestMsg*>(connman.get())->SetPeerConnectTimeout(99999s);
5757
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, nullptr,
5858
*m_node.chainman, *m_node.mempool, false);
5959

src/test/util/net.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
struct ConnmanTestMsg : public CConnman {
1919
using CConnman::CConnman;
2020

21-
void SetPeerConnectTimeout(int64_t timeout)
21+
void SetPeerConnectTimeout(std::chrono::seconds timeout)
2222
{
2323
m_peer_connect_timeout = timeout;
2424
}

0 commit comments

Comments
 (0)