From fa41e072b3bd1b755243e2f3dea617d6cb944ede Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Fri, 20 Mar 2026 10:48:38 +0100 Subject: [PATCH 1/9] refactor: Use NodeClock alias over deprecated GetTime GetTime returns a duration, but a time point is the correct type to use here. This refactor does not change any behavior. --- src/net_processing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 28d7d2c13ab..6377e3fac3d 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1564,7 +1564,7 @@ void PeerManagerImpl::PushNodeVersion(CNode& pnode, const Peer& peer) } else { const CAddress& addr{pnode.addr}; my_services = peer.m_our_services; - my_time = count_seconds(GetTime()); + my_time = TicksSinceEpoch(NodeClock::now()); your_services = addr.nServices; your_addr = addr.IsRoutable() && !IsProxy(addr) && addr.IsAddrV1Compatible() ? CService{addr} : CService{}; my_user_agent = strSubVersion; From facfce37f62ec8a4451cf27fe6dac15519d914bf Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Fri, 20 Mar 2026 11:24:34 +0100 Subject: [PATCH 2/9] util: Add NodeClock::epoch alias A default constructed time_point is the epoch, by definition. Existing code uses a default constructed (or explicitly constructed with a zero duration) chrono type to mean epoch. New code can now use NodeClock::epoch as an alias. --- src/util/time.cpp | 2 ++ src/util/time.h | 1 + 2 files changed, 3 insertions(+) diff --git a/src/util/time.cpp b/src/util/time.cpp index 9e0715e5250..1466dc01f85 100644 --- a/src/util/time.cpp +++ b/src/util/time.cpp @@ -27,6 +27,8 @@ static std::atomic g_mock_time{}; //!< For testing std::atomic g_used_system_time{false}; static std::atomic g_mock_steady_time{}; //!< For testing +static_assert(NodeClock::epoch.time_since_epoch().count() == 0); + NodeClock::time_point NodeClock::now() noexcept { const auto mocktime{g_mock_time.load(std::memory_order_relaxed)}; diff --git a/src/util/time.h b/src/util/time.h index 30d363bb612..15d00e80843 100644 --- a/src/util/time.h +++ b/src/util/time.h @@ -23,6 +23,7 @@ struct NodeClock : public std::chrono::system_clock { static time_point now() noexcept; static std::time_t to_time_t(const time_point&) = delete; // unused static time_point from_time_t(std::time_t) = delete; // unused + static constexpr time_point epoch{}; }; using NodeSeconds = std::chrono::time_point; From fab88884b7365f184cfe87e6976242da661b8c55 Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Tue, 24 Mar 2026 15:20:52 +0100 Subject: [PATCH 3/9] refactor: Avoid manual chrono casts with * or / Manual chrono casts, using multiplication or division is confusing and brittle. Also, when calling ShouldRunInactivityChecks remove a confusing and useless std::chrono::duration_cast. --- src/net_processing.cpp | 4 ++-- src/qt/guiutil.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 6377e3fac3d..d9cf3920e0e 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -5398,13 +5398,13 @@ void PeerManagerImpl::CheckForStaleTipAndEvictPeers() void PeerManagerImpl::MaybeSendPing(CNode& node_to, Peer& peer, std::chrono::microseconds now) { - if (m_connman.ShouldRunInactivityChecks(node_to, std::chrono::duration_cast(now)) && + if (m_connman.ShouldRunInactivityChecks(node_to, now) && peer.m_ping_nonce_sent && now > peer.m_ping_start.load() + TIMEOUT_INTERVAL) { // The ping timeout is using mocktime. To disable the check during // testing, increase -peertimeout. - LogDebug(BCLog::NET, "ping timeout: %fs, %s", 0.000001 * count_microseconds(now - peer.m_ping_start.load()), node_to.DisconnectMsg()); + LogDebug(BCLog::NET, "ping timeout: %fs, %s", Ticks(now - peer.m_ping_start.load()), node_to.DisconnectMsg()); node_to.fDisconnect = true; return; } diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 1619227a419..9fd46cfc1e1 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -771,7 +771,7 @@ QString formatPingTime(std::chrono::microseconds ping_time) { return (ping_time == std::chrono::microseconds::max() || ping_time == 0us) ? QObject::tr("N/A") : - QObject::tr("%1 ms").arg(QString::number((int)(count_microseconds(ping_time) / 1000), 10)); + QObject::tr("%1 ms").arg(QString::number(Ticks(ping_time))); } QString formatTimeOffset(int64_t time_offset) From fa54fb0129520c6aea1eab7628e12fbdd0ce8806 Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Tue, 24 Mar 2026 15:51:08 +0100 Subject: [PATCH 4/9] refactor: gui: Accept up to nanoseconds in formatDurationStr, but clarify they are ignored This refactor does not change any behavior. However, it helps future commits to avoid having to place manual std::chrono::duration_cast when calling this function. --- src/qt/guiutil.cpp | 2 +- src/qt/guiutil.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 9fd46cfc1e1..9cdfe2bcd24 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -728,7 +728,7 @@ QString ConnectionTypeToQString(ConnectionType conn_type, bool prepend_direction assert(false); } -QString formatDurationStr(std::chrono::seconds dur) +QString formatDurationStr(std::chrono::nanoseconds dur) { const auto d{std::chrono::duration_cast(dur)}; const auto h{std::chrono::duration_cast(dur - d)}; diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index bcde397d7ba..f34c4eac181 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -228,8 +228,8 @@ namespace GUIUtil /** Convert enum ConnectionType to QString */ QString ConnectionTypeToQString(ConnectionType conn_type, bool prepend_direction); - /** Convert seconds into a QString with days, hours, mins, secs */ - QString formatDurationStr(std::chrono::seconds dur); + /// Convert a duration into a QString with days, hours, mins, secs. This ignores sub-seconds. + QString formatDurationStr(std::chrono::nanoseconds dur); /** Convert peer connection time to a QString denominated in the most relevant unit. */ QString FormatPeerAge(std::chrono::seconds time_connected); From 333316f6bee84cf6947707f006ec4d514ef3f7ec Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Fri, 20 Mar 2026 16:48:28 +0100 Subject: [PATCH 5/9] doc: Fix typo "eviction criterium" -> "eviction criterion" Also, clarify round-trip time to mean round-trip duration. --- src/net.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/net.h b/src/net.h index d923e7b28fe..5f19074bddc 100644 --- a/src/net.h +++ b/src/net.h @@ -876,24 +876,24 @@ public: * eviction logic. */ std::atomic_bool m_bloom_filter_loaded{false}; - /** UNIX epoch time of the last block received from this peer that we had - * not yet seen (e.g. not already received from another peer), that passed - * preliminary validity checks and was saved to disk, even if we don't - * connect the block or it eventually fails connection. Used as an inbound - * peer eviction criterium in CConnman::AttemptToEvictConnection. */ + /// UNIX epoch time of the last block received from this peer that we had + /// not yet seen (e.g. not already received from another peer), that passed + /// preliminary validity checks and was saved to disk, even if we don't + /// connect the block or it eventually fails to connect. Used as an inbound + /// peer eviction criterion in CConnman::AttemptToEvictConnection. std::atomic m_last_block_time{0s}; - /** UNIX epoch time of the last transaction received from this peer that we - * had not yet seen (e.g. not already received from another peer) and that - * was accepted into our mempool. Used as an inbound peer eviction criterium - * in CConnman::AttemptToEvictConnection. */ + /// UNIX epoch time of the last transaction received from this peer that we + /// had not yet seen (e.g. not already received from another peer) and that + /// was accepted into our mempool. Used as an inbound peer eviction criterion + /// in CConnman::AttemptToEvictConnection. std::atomic m_last_tx_time{0s}; - /** Last measured round-trip time. Used only for RPC/GUI stats/debugging.*/ + /// Last measured round-trip duration. Used only for stats. std::atomic m_last_ping_time{0us}; - /** Lowest measured round-trip time. Used as an inbound peer eviction - * criterium in CConnman::AttemptToEvictConnection. */ + /// Lowest measured round-trip duration. Used as an inbound peer eviction + /// criterion in CConnman::AttemptToEvictConnection. std::atomic m_min_ping_time{std::chrono::microseconds::max()}; CNode(NodeId id, @@ -980,7 +980,7 @@ public: */ std::string DisconnectMsg() const; - /** A ping-pong round trip has completed successfully. Update latest and minimum ping times. */ + /// A ping-pong round trip has completed successfully. Update latest and minimum ping durations. void PongReceived(std::chrono::microseconds ping_time) { m_last_ping_time = ping_time; m_min_ping_time = std::min(m_min_ping_time.load(), ping_time); From fa644e625b0ced9aeeaacd4ebfb714ffa2cbfc17 Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Fri, 20 Mar 2026 14:10:50 +0100 Subject: [PATCH 6/9] refactor: Use NodeClock::duration for m_last_ping_time/m_min_ping_time/m_ping_wait This refactor does not change any behavior and is needed for a future commit, to avoid having to add duration casts. It also improves the docs to better document that this is not a time point, but a duration. Also, it uses decltype to explain where the _::max() is coming from. --- src/net.h | 11 ++++++----- src/net_processing.h | 2 +- src/node/eviction.h | 2 +- src/qt/guiutil.cpp | 4 ++-- src/qt/guiutil.h | 4 ++-- src/rpc/net.cpp | 2 +- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/net.h b/src/net.h index 5f19074bddc..135b1fc0a37 100644 --- a/src/net.h +++ b/src/net.h @@ -210,8 +210,8 @@ public: uint64_t nRecvBytes; mapMsgTypeSize mapRecvBytesPerMsgType; NetPermissionFlags m_permission_flags; - std::chrono::microseconds m_last_ping_time; - std::chrono::microseconds m_min_ping_time; + NodeClock::duration m_last_ping_time; + NodeClock::duration m_min_ping_time; // Our address, as reported by the peer std::string addrLocal; // Address of this peer @@ -890,11 +890,11 @@ public: std::atomic m_last_tx_time{0s}; /// Last measured round-trip duration. Used only for stats. - std::atomic m_last_ping_time{0us}; + std::atomic m_last_ping_time{0us}; /// Lowest measured round-trip duration. Used as an inbound peer eviction /// criterion in CConnman::AttemptToEvictConnection. - std::atomic m_min_ping_time{std::chrono::microseconds::max()}; + std::atomic m_min_ping_time{NodeClock::duration::max()}; CNode(NodeId id, std::shared_ptr sock, @@ -981,7 +981,8 @@ public: std::string DisconnectMsg() const; /// A ping-pong round trip has completed successfully. Update latest and minimum ping durations. - void PongReceived(std::chrono::microseconds ping_time) { + void PongReceived(NodeClock::duration ping_time) + { m_last_ping_time = ping_time; m_min_ping_time = std::min(m_min_ping_time.load(), ping_time); } diff --git a/src/net_processing.h b/src/net_processing.h index d2050d8f3d7..8b3f026d051 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -52,7 +52,7 @@ static const unsigned int MAX_HEADERS_RESULTS = 2000; struct CNodeStateStats { int nSyncHeight = -1; int nCommonHeight = -1; - std::chrono::microseconds m_ping_wait; + NodeClock::duration m_ping_wait; std::vector vHeightInFlight; bool m_relay_txs; int m_inv_to_send = 0; diff --git a/src/node/eviction.h b/src/node/eviction.h index 6ab726445f2..7230d959df2 100644 --- a/src/node/eviction.h +++ b/src/node/eviction.h @@ -18,7 +18,7 @@ typedef int64_t NodeId; struct NodeEvictionCandidate { NodeId id; std::chrono::seconds m_connected; - std::chrono::microseconds m_min_ping_time; + NodeClock::duration m_min_ping_time; std::chrono::seconds m_last_block_time; std::chrono::seconds m_last_tx_time; bool fRelevantServices; diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 9cdfe2bcd24..e0210b0570f 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -767,9 +767,9 @@ QString formatServicesStr(quint64 mask) return QObject::tr("None"); } -QString formatPingTime(std::chrono::microseconds ping_time) +QString formatPingTime(NodeClock::duration ping_time) { - return (ping_time == std::chrono::microseconds::max() || ping_time == 0us) ? + return (ping_time == decltype(CNode::m_min_ping_time.load())::max() || ping_time == 0us) ? QObject::tr("N/A") : QObject::tr("%1 ms").arg(QString::number(Ticks(ping_time))); } diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index f34c4eac181..90b8013ef0d 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -237,8 +237,8 @@ namespace GUIUtil /** Format CNodeStats.nServices bitmask into a user-readable string */ QString formatServicesStr(quint64 mask); - /** Format a CNodeStats.m_last_ping_time into a user-readable string or display N/A, if 0 */ - QString formatPingTime(std::chrono::microseconds ping_time); + /// Format a CNodeStats.m_last_ping_time/m_min_ping_time/m_ping_wait into a user-readable string if it exists, or display N/A + QString formatPingTime(NodeClock::duration ping_time); /** Format a CNodeStateStats.time_offset into a user-readable string */ QString formatTimeOffset(int64_t time_offset); diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 03786351388..9c71e4ee8ce 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -253,7 +253,7 @@ static RPCHelpMan getpeerinfo() if (stats.m_last_ping_time > 0us) { obj.pushKV("pingtime", Ticks(stats.m_last_ping_time)); } - if (stats.m_min_ping_time < std::chrono::microseconds::max()) { + if (stats.m_min_ping_time < decltype(CNode::m_min_ping_time.load())::max()) { obj.pushKV("minping", Ticks(stats.m_min_ping_time)); } if (statestats.m_ping_wait > 0s) { From fa2605b20471a225bd69f8516508dce78e018344 Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Fri, 20 Mar 2026 13:23:30 +0100 Subject: [PATCH 7/9] refactor: Use NodeClock::time_point for CNetMessage::m_time The field is not a duration, but a time point. This will add two temporary calls to time_since_epoch(), which are fixed in the next commit. --- src/net.cpp | 8 ++++---- src/net.h | 9 +++++---- src/net_processing.cpp | 6 +++--- src/test/fuzz/p2p_transport_serialization.cpp | 6 +++--- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 71befd292bd..399b41f3aa5 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -662,9 +662,9 @@ void CNode::CopyStats(CNodeStats& stats) bool CNode::ReceiveMsgBytes(std::span msg_bytes, bool& complete) { complete = false; - const auto time = GetTime(); + const auto time{NodeClock::now()}; LOCK(cs_vRecv); - m_last_recv = std::chrono::duration_cast(time); + m_last_recv = std::chrono::duration_cast(time.time_since_epoch()); nRecvBytes += msg_bytes.size(); while (msg_bytes.size() > 0) { // absorb network data @@ -800,7 +800,7 @@ const uint256& V1Transport::GetMessageHash() const return data_hash; } -CNetMessage V1Transport::GetReceivedMessage(const std::chrono::microseconds time, bool& reject_message) +CNetMessage V1Transport::GetReceivedMessage(NodeClock::time_point time, bool& reject_message) { AssertLockNotHeld(m_recv_mutex); // Initialize out parameter @@ -1452,7 +1452,7 @@ std::optional V2Transport::GetMessageType(std::span& return ret; } -CNetMessage V2Transport::GetReceivedMessage(std::chrono::microseconds time, bool& reject_message) noexcept +CNetMessage V2Transport::GetReceivedMessage(NodeClock::time_point time, bool& reject_message) noexcept { AssertLockNotHeld(m_recv_mutex); LOCK(m_recv_mutex); diff --git a/src/net.h b/src/net.h index 135b1fc0a37..acef9035c59 100644 --- a/src/net.h +++ b/src/net.h @@ -237,7 +237,8 @@ class CNetMessage { public: DataStream m_recv; //!< received message data - std::chrono::microseconds m_time{0}; //!< time of message receipt + /// time of message receipt + NodeClock::time_point m_time{NodeClock::epoch}; uint32_t m_message_size{0}; //!< size of the payload uint32_t m_raw_message_size{0}; //!< used wire size of the message (including header/checksum) std::string m_type; @@ -291,7 +292,7 @@ public: * If reject_message=true is returned the message itself is invalid, but (other than false * returned by ReceivedBytes) the transport is not in an inconsistent state. */ - virtual CNetMessage GetReceivedMessage(std::chrono::microseconds time, bool& reject_message) = 0; + virtual CNetMessage GetReceivedMessage(NodeClock::time_point time, bool& reject_message) = 0; // 2. Sending side functions, for converting messages into bytes to be sent over the wire. @@ -443,7 +444,7 @@ public: return ret >= 0; } - CNetMessage GetReceivedMessage(std::chrono::microseconds time, bool& reject_message) override EXCLUSIVE_LOCKS_REQUIRED(!m_recv_mutex); + CNetMessage GetReceivedMessage(NodeClock::time_point time, bool& reject_message) override EXCLUSIVE_LOCKS_REQUIRED(!m_recv_mutex); bool SetMessageToSend(CSerializedNetMsg& msg) noexcept override EXCLUSIVE_LOCKS_REQUIRED(!m_send_mutex); BytesToSend GetBytesToSend(bool have_next_message) const noexcept override EXCLUSIVE_LOCKS_REQUIRED(!m_send_mutex); @@ -652,7 +653,7 @@ public: // Receive side functions. bool ReceivedMessageComplete() const noexcept override EXCLUSIVE_LOCKS_REQUIRED(!m_recv_mutex); bool ReceivedBytes(std::span& msg_bytes) noexcept override EXCLUSIVE_LOCKS_REQUIRED(!m_recv_mutex, !m_send_mutex); - CNetMessage GetReceivedMessage(std::chrono::microseconds time, bool& reject_message) noexcept override EXCLUSIVE_LOCKS_REQUIRED(!m_recv_mutex); + CNetMessage GetReceivedMessage(NodeClock::time_point time, bool& reject_message) noexcept override EXCLUSIVE_LOCKS_REQUIRED(!m_recv_mutex); // Send side functions. bool SetMessageToSend(CSerializedNetMsg& msg) noexcept override EXCLUSIVE_LOCKS_REQUIRED(!m_send_mutex); diff --git a/src/net_processing.cpp b/src/net_processing.cpp index d9cf3920e0e..507be59cb7c 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -553,7 +553,7 @@ public: ServiceFlags GetDesirableServiceFlags(ServiceFlags services) const override; private: - void ProcessMessage(Peer& peer, CNode& pfrom, const std::string& msg_type, DataStream& vRecv, std::chrono::microseconds time_received, + void ProcessMessage(Peer& peer, CNode& pfrom, const std::string& msg_type, DataStream& vRecv, NodeClock::time_point time_received, const std::atomic& interruptMsgProc) EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex, !m_tx_download_mutex); @@ -3570,7 +3570,7 @@ void PeerManagerImpl::PushPrivateBroadcastTx(CNode& node) } void PeerManagerImpl::ProcessMessage(Peer& peer, CNode& pfrom, const std::string& msg_type, DataStream& vRecv, - const std::chrono::microseconds time_received, + const NodeClock::time_point time_received, const std::atomic& interruptMsgProc) { AssertLockHeld(g_msgproc_mutex); @@ -4900,7 +4900,7 @@ void PeerManagerImpl::ProcessMessage(Peer& peer, CNode& pfrom, const std::string } if (msg_type == NetMsgType::PONG) { - const auto ping_end = time_received; + const auto ping_end{time_received.time_since_epoch()}; uint64_t nonce = 0; size_t nAvail = vRecv.in_avail(); bool bPingFinished = false; diff --git a/src/test/fuzz/p2p_transport_serialization.cpp b/src/test/fuzz/p2p_transport_serialization.cpp index 88432ec1009..82b282d3eb0 100644 --- a/src/test/fuzz/p2p_transport_serialization.cpp +++ b/src/test/fuzz/p2p_transport_serialization.cpp @@ -78,13 +78,13 @@ FUZZ_TARGET(p2p_transport_serialization, .init = initialize_p2p_transport_serial break; } if (recv_transport.ReceivedMessageComplete()) { - const std::chrono::microseconds m_time{std::numeric_limits::max()}; + const auto time{NodeClock::time_point::max()}; bool reject_message{false}; - CNetMessage msg = recv_transport.GetReceivedMessage(m_time, reject_message); + CNetMessage msg = recv_transport.GetReceivedMessage(time, reject_message); assert(msg.m_type.size() <= CMessageHeader::MESSAGE_TYPE_SIZE); assert(msg.m_raw_message_size <= mutable_msg_bytes.size()); assert(msg.m_raw_message_size == CMessageHeader::HEADER_SIZE + msg.m_message_size); - assert(msg.m_time == m_time); + assert(msg.m_time == time); std::vector header; auto msg2 = NetMsg::Make(msg.m_type, std::span{msg.m_recv}); From fa244b984c04998a975c12dc1dcde93b27a08e1d Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Fri, 20 Mar 2026 14:59:34 +0100 Subject: [PATCH 8/9] refactor: Use NodeClock::time_point for m_last_send/recv and m_ping_start The two fields represent a time point, not a duration. Also, it is unclear why they use second precision. Fix both issues by using NodeClock::time_point. This refactor should not change any behavior. This resolves the two temporary calls to time_since_epoch() added in the previous commit. However, it adds one new call to time_since_epoch(), which is resolved in the next commit. --- src/net.cpp | 16 ++++++++-------- src/net.h | 12 ++++++------ src/net_processing.cpp | 19 ++++++++++--------- src/qt/rpcconsole.cpp | 5 +++-- src/qt/rpcconsole.h | 7 ++++++- src/rpc/net.cpp | 4 ++-- 6 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 399b41f3aa5..7152f62a691 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -664,7 +664,7 @@ bool CNode::ReceiveMsgBytes(std::span msg_bytes, bool& complete) complete = false; const auto time{NodeClock::now()}; LOCK(cs_vRecv); - m_last_recv = std::chrono::duration_cast(time.time_since_epoch()); + m_last_recv = time; nRecvBytes += msg_bytes.size(); while (msg_bytes.size() > 0) { // absorb network data @@ -1643,7 +1643,7 @@ std::pair CConnman::SocketSendData(CNode& node) const nBytes = node.m_sock->Send(data.data(), data.size(), flags); } if (nBytes > 0) { - node.m_last_send = GetTime(); + node.m_last_send = NodeClock::now(); node.nSendBytes += nBytes; // Notify transport that bytes have been processed. node.m_transport->MarkBytesSent(nBytes); @@ -2005,12 +2005,12 @@ void CConnman::NotifyNumConnectionsChanged() } } -bool CConnman::ShouldRunInactivityChecks(const CNode& node, std::chrono::microseconds now) const +bool CConnman::ShouldRunInactivityChecks(const CNode& node, NodeClock::time_point now) const { - return node.m_connected + m_peer_connect_timeout < now; + return node.m_connected + m_peer_connect_timeout < now.time_since_epoch(); } -bool CConnman::InactivityCheck(const CNode& node, std::chrono::microseconds now) const +bool CConnman::InactivityCheck(const CNode& node, NodeClock::time_point now) const { // Tests that see disconnects after using mocktime can start nodes with a // large timeout. For example, -peertimeout=999999999. @@ -2019,8 +2019,8 @@ bool CConnman::InactivityCheck(const CNode& node, std::chrono::microseconds now) if (!ShouldRunInactivityChecks(node, now)) return false; - bool has_received{last_recv.count() != 0}; - bool has_sent{last_send.count() != 0}; + bool has_received{last_recv > NodeClock::epoch}; + bool has_sent{last_send > NodeClock::epoch}; if (!has_received || !has_sent) { std::string has_never; @@ -2127,7 +2127,7 @@ void CConnman::SocketHandlerConnected(const std::vector& nodes, { AssertLockNotHeld(m_total_bytes_sent_mutex); - auto now = GetTime(); + const auto now{NodeClock::now()}; for (CNode* pnode : nodes) { if (m_interrupt_net->interrupted()) { diff --git a/src/net.h b/src/net.h index acef9035c59..4f082b4efde 100644 --- a/src/net.h +++ b/src/net.h @@ -192,8 +192,8 @@ class CNodeStats { public: NodeId nodeid; - std::chrono::seconds m_last_send; - std::chrono::seconds m_last_recv; + NodeClock::time_point m_last_send; + NodeClock::time_point m_last_recv; std::chrono::seconds m_last_tx_time; std::chrono::seconds m_last_block_time; std::chrono::seconds m_connected; @@ -707,8 +707,8 @@ public: uint64_t nRecvBytes GUARDED_BY(cs_vRecv){0}; - std::atomic m_last_send{0s}; - std::atomic m_last_recv{0s}; + std::atomic m_last_send{NodeClock::epoch}; + std::atomic m_last_recv{NodeClock::epoch}; //! Unix epoch time at peer connection const std::chrono::seconds m_connected; // Address of this peer @@ -1396,7 +1396,7 @@ public: void WakeMessageHandler() EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc); /** Return true if we should disconnect the peer for failing an inactivity check. */ - bool ShouldRunInactivityChecks(const CNode& node, std::chrono::microseconds now) const; + bool ShouldRunInactivityChecks(const CNode& node, NodeClock::time_point now) const; bool MultipleManualOrFullOutboundConns(Network net) const EXCLUSIVE_LOCKS_REQUIRED(m_nodes_mutex); @@ -1447,7 +1447,7 @@ private: void DisconnectNodes() EXCLUSIVE_LOCKS_REQUIRED(!m_reconnections_mutex, !m_nodes_mutex); void NotifyNumConnectionsChanged(); /** Return true if the peer is inactive and should be disconnected. */ - bool InactivityCheck(const CNode& node, std::chrono::microseconds now) const; + bool InactivityCheck(const CNode& node, NodeClock::time_point now) const; /** * Generate a collection of sockets to check for IO readiness. diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 507be59cb7c..6b35242608b 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -275,7 +275,7 @@ struct Peer { /** The pong reply we're expecting, or 0 if no pong expected. */ std::atomic m_ping_nonce_sent{0}; /** When the last ping was sent, or 0 if no ping was ever sent */ - std::atomic m_ping_start{0us}; + std::atomic m_ping_start{NodeClock::epoch}; /** Whether a ping has been requested by the user */ std::atomic m_ping_queued{false}; @@ -732,7 +732,7 @@ private: * May mark the peer to be disconnected if a ping has timed out. * We use mockable time for ping timeouts, so setmocktime may cause pings * to time out. */ - void MaybeSendPing(CNode& node_to, Peer& peer, std::chrono::microseconds now); + void MaybeSendPing(CNode& node_to, Peer& peer, NodeClock::time_point now); /** Send `addr` messages on a regular schedule. */ void MaybeSendAddr(CNode& node, Peer& peer, std::chrono::microseconds current_time) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex); @@ -1809,9 +1809,9 @@ bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) c // since pingtime does not update until the ping is complete, which might take a while. // So, if a ping is taking an unusually long time in flight, // the caller can immediately detect that this is happening. - auto ping_wait{0us}; - if ((0 != peer->m_ping_nonce_sent) && (0 != peer->m_ping_start.load().count())) { - ping_wait = GetTime() - peer->m_ping_start.load(); + NodeClock::duration ping_wait{0us}; + if ((0 != peer->m_ping_nonce_sent) && (peer->m_ping_start.load() > NodeClock::epoch)) { + ping_wait = NodeClock::now() - peer->m_ping_start.load(); } if (auto tx_relay = peer->GetTxRelay(); tx_relay != nullptr) { @@ -4158,7 +4158,7 @@ void PeerManagerImpl::ProcessMessage(Peer& peer, CNode& pfrom, const std::string MakeAndPushMessage(pfrom, NetMsgType::TX, TX_WITH_WITNESS(*pushed_tx)); peer.m_ping_queued = true; // Ensure a ping will be sent: mimic a request via RPC. - MaybeSendPing(pfrom, peer, GetTime()); + MaybeSendPing(pfrom, peer, NodeClock::now()); } else { LogDebug(BCLog::PRIVBROADCAST, "Disconnecting: got an unexpected GETDATA message, %s", pfrom.LogPeer()); @@ -4900,7 +4900,7 @@ void PeerManagerImpl::ProcessMessage(Peer& peer, CNode& pfrom, const std::string } if (msg_type == NetMsgType::PONG) { - const auto ping_end{time_received.time_since_epoch()}; + const auto ping_end{time_received}; uint64_t nonce = 0; size_t nAvail = vRecv.in_avail(); bool bPingFinished = false; @@ -5396,7 +5396,7 @@ void PeerManagerImpl::CheckForStaleTipAndEvictPeers() } } -void PeerManagerImpl::MaybeSendPing(CNode& node_to, Peer& peer, std::chrono::microseconds now) +void PeerManagerImpl::MaybeSendPing(CNode& node_to, Peer& peer, NodeClock::time_point now) { if (m_connman.ShouldRunInactivityChecks(node_to, now) && peer.m_ping_nonce_sent && @@ -5733,6 +5733,7 @@ bool PeerManagerImpl::SendMessages(CNode& node) if (!node.fSuccessfullyConnected || node.fDisconnect) return true; + const auto now{NodeClock::now()}; const auto current_time{GetTime()}; // The logic below does not apply to private broadcast peers, so skip it. @@ -5753,7 +5754,7 @@ bool PeerManagerImpl::SendMessages(CNode& node) return true; } - MaybeSendPing(node, peer, current_time); + MaybeSendPing(node, peer, now); // MaybeSendPing may have marked peer for disconnection if (node.fDisconnect) return true; diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index d30a8acff62..fef1f687208 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -1165,12 +1165,13 @@ void RPCConsole::updateDetailWidget() if (stats->nodeStats.m_bip152_highbandwidth_from) bip152_hb_settings += (bip152_hb_settings.isEmpty() ? ts.from : QLatin1Char('/') + ts.from); if (bip152_hb_settings.isEmpty()) bip152_hb_settings = ts.no; ui->peerHighBandwidth->setText(bip152_hb_settings); + const auto now{NodeClock::now()}; const auto time_now{GetTime()}; ui->peerConnTime->setText(GUIUtil::formatDurationStr(time_now - stats->nodeStats.m_connected)); ui->peerLastBlock->setText(TimeDurationField(time_now, stats->nodeStats.m_last_block_time)); ui->peerLastTx->setText(TimeDurationField(time_now, stats->nodeStats.m_last_tx_time)); - ui->peerLastSend->setText(TimeDurationField(time_now, stats->nodeStats.m_last_send)); - ui->peerLastRecv->setText(TimeDurationField(time_now, stats->nodeStats.m_last_recv)); + ui->peerLastSend->setText(TimeDurationField(now, stats->nodeStats.m_last_send)); + ui->peerLastRecv->setText(TimeDurationField(now, stats->nodeStats.m_last_recv)); ui->peerBytesSent->setText(GUIUtil::formatBytes(stats->nodeStats.nSendBytes)); ui->peerBytesRecv->setText(GUIUtil::formatBytes(stats->nodeStats.nRecvBytes)); ui->peerPingTime->setText(GUIUtil::formatPingTime(stats->nodeStats.m_last_ping_time)); diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index bbd469cd3dd..0c9f704090b 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -182,7 +182,12 @@ private: /** Update UI with latest network info from model. */ void updateNetworkState(); - /** Helper for the output of a time duration field. Inputs are UNIX epoch times. */ + /// Format the duration between now and event as a string. + QString TimeDurationField(NodeClock::time_point now, NodeClock::time_point event) const + { + return event > NodeClock::epoch ? GUIUtil::formatDurationStr(now - event) : tr("Never"); + } + /// DEPRECATED: Helper for the output of a time duration field. Inputs are UNIX epoch times. QString TimeDurationField(std::chrono::seconds time_now, std::chrono::seconds time_at_event) const { return time_at_event.count() ? GUIUtil::formatDurationStr(time_now - time_at_event) : tr("Never"); diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 9c71e4ee8ce..ff2adf82d37 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -242,8 +242,8 @@ static RPCHelpMan getpeerinfo() obj.pushKV("relaytxes", statestats.m_relay_txs); obj.pushKV("last_inv_sequence", statestats.m_last_inv_seq); obj.pushKV("inv_to_send", statestats.m_inv_to_send); - obj.pushKV("lastsend", count_seconds(stats.m_last_send)); - obj.pushKV("lastrecv", count_seconds(stats.m_last_recv)); + obj.pushKV("lastsend", TicksSinceEpoch(stats.m_last_send)); + obj.pushKV("lastrecv", TicksSinceEpoch(stats.m_last_recv)); obj.pushKV("last_transaction", count_seconds(stats.m_last_tx_time)); obj.pushKV("last_block", count_seconds(stats.m_last_block_time)); obj.pushKV("bytessent", stats.nSendBytes); From fa1015bbcb15453a4a47be51490d1d28c837151e Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Fri, 20 Mar 2026 15:52:03 +0100 Subject: [PATCH 9/9] refactor: Use NodeClock::time_point for m_connected Also, increase the precision to the native one, over prescribing second precision. --- src/bench/peer_eviction.cpp | 12 +++--- src/net.cpp | 8 ++-- src/net.h | 4 +- src/net_processing.cpp | 15 ++++---- src/node/eviction.cpp | 2 +- src/node/eviction.h | 2 +- src/qt/guiutil.cpp | 5 +-- src/qt/guiutil.h | 2 +- src/qt/rpcconsole.cpp | 2 +- src/rpc/net.cpp | 2 +- src/test/fuzz/node_eviction.cpp | 2 +- src/test/net_peer_eviction_tests.cpp | 56 ++++++++++++++-------------- src/test/util/net.cpp | 2 +- 13 files changed, 57 insertions(+), 57 deletions(-) diff --git a/src/bench/peer_eviction.cpp b/src/bench/peer_eviction.cpp index 2360fb49de7..24b78e3179c 100644 --- a/src/bench/peer_eviction.cpp +++ b/src/bench/peer_eviction.cpp @@ -41,7 +41,7 @@ static void EvictionProtection0Networks250Candidates(benchmark::Bench& bench) bench, /*num_candidates=*/250, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_network = NET_IPV4; }); } @@ -52,7 +52,7 @@ static void EvictionProtection1Networks250Candidates(benchmark::Bench& bench) bench, /*num_candidates=*/250, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = false; if (c.id >= 130 && c.id < 240) { // 110 Tor c.m_network = NET_ONION; @@ -68,7 +68,7 @@ static void EvictionProtection2Networks250Candidates(benchmark::Bench& bench) bench, /*num_candidates=*/250, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = false; if (c.id >= 90 && c.id < 160) { // 70 Tor c.m_network = NET_ONION; @@ -86,7 +86,7 @@ static void EvictionProtection3Networks050Candidates(benchmark::Bench& bench) bench, /*num_candidates=*/50, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id == 28 || c.id == 47); // 2 localhost if (c.id >= 30 && c.id < 47) { // 17 I2P c.m_network = NET_I2P; @@ -104,7 +104,7 @@ static void EvictionProtection3Networks100Candidates(benchmark::Bench& bench) bench, /*num_candidates=*/100, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id >= 55 && c.id < 60); // 5 localhost if (c.id >= 70 && c.id < 80) { // 10 I2P c.m_network = NET_I2P; @@ -122,7 +122,7 @@ static void EvictionProtection3Networks250Candidates(benchmark::Bench& bench) bench, /*num_candidates=*/250, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id >= 140 && c.id < 160); // 20 localhost if (c.id >= 170 && c.id < 180) { // 10 I2P c.m_network = NET_I2P; diff --git a/src/net.cpp b/src/net.cpp index 7152f62a691..d046c2a2722 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -566,7 +566,7 @@ void CNode::CloseSocketDisconnect() m_addr_name.c_str(), ConnectionTypeAsString().c_str(), ConnectedThroughNetwork(), - Ticks(m_connected)); + TicksSinceEpoch(m_connected)); } m_i2p_sam_session.reset(); } @@ -1727,7 +1727,7 @@ bool CConnman::AttemptToEvictConnection() pnode->m_addr_name.c_str(), pnode->ConnectionTypeAsString().c_str(), pnode->ConnectedThroughNetwork(), - Ticks(pnode->m_connected)); + TicksSinceEpoch(pnode->m_connected)); pnode->fDisconnect = true; return true; } @@ -2007,7 +2007,7 @@ void CConnman::NotifyNumConnectionsChanged() bool CConnman::ShouldRunInactivityChecks(const CNode& node, NodeClock::time_point now) const { - return node.m_connected + m_peer_connect_timeout < now.time_since_epoch(); + return node.m_connected + m_peer_connect_timeout < now; } bool CConnman::InactivityCheck(const CNode& node, NodeClock::time_point now) const @@ -3987,7 +3987,7 @@ CNode::CNode(NodeId idIn, : m_transport{MakeTransport(idIn, node_opts.use_v2transport, conn_type_in == ConnectionType::INBOUND)}, m_permission_flags{node_opts.permission_flags}, m_sock{sock}, - m_connected{GetTime()}, + m_connected{NodeClock::now()}, addr{addrIn}, addrBind{addrBindIn}, m_addr_name{addrNameIn.empty() ? addr.ToStringAddrPort() : addrNameIn}, diff --git a/src/net.h b/src/net.h index 4f082b4efde..928d518eda6 100644 --- a/src/net.h +++ b/src/net.h @@ -196,7 +196,7 @@ public: NodeClock::time_point m_last_recv; std::chrono::seconds m_last_tx_time; std::chrono::seconds m_last_block_time; - std::chrono::seconds m_connected; + NodeClock::time_point m_connected; std::string m_addr_name; int nVersion; std::string cleanSubVer; @@ -710,7 +710,7 @@ public: std::atomic m_last_send{NodeClock::epoch}; std::atomic m_last_recv{NodeClock::epoch}; //! Unix epoch time at peer connection - const std::chrono::seconds m_connected; + const NodeClock::time_point m_connected; // Address of this peer const CAddress addr; // Bind address of our side of the connection diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 6b35242608b..16d3f6112d3 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -561,7 +561,7 @@ private: void ConsiderEviction(CNode& pto, Peer& peer, std::chrono::seconds time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main, g_msgproc_mutex); /** If we have extra outbound peers, try to disconnect the one with the oldest block announcement */ - void EvictExtraOutboundPeers(std::chrono::seconds now) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + void EvictExtraOutboundPeers(NodeClock::time_point now) EXCLUSIVE_LOCKS_REQUIRED(cs_main); /** Retrieve unbroadcast transactions from the mempool and reattempt sending to peers */ void ReattemptInitialBroadcast(CScheduler& scheduler) EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); @@ -5261,7 +5261,7 @@ void PeerManagerImpl::ConsiderEviction(CNode& pto, Peer& peer, std::chrono::seco } } -void PeerManagerImpl::EvictExtraOutboundPeers(std::chrono::seconds now) +void PeerManagerImpl::EvictExtraOutboundPeers(NodeClock::time_point now) { // If we have any extra block-relay-only peers, disconnect the youngest unless // it's given us a block -- in which case, compare with the second-youngest, and @@ -5302,7 +5302,7 @@ void PeerManagerImpl::EvictExtraOutboundPeers(std::chrono::seconds now) return true; } else { LogDebug(BCLog::NET, "keeping block-relay-only peer=%d chosen for eviction (connect time: %d, blocks_in_flight: %d)\n", - pnode->GetId(), count_seconds(pnode->m_connected), node_state->vBlocksInFlight.size()); + pnode->GetId(), TicksSinceEpoch(pnode->m_connected), node_state->vBlocksInFlight.size()); } return false; }); @@ -5353,7 +5353,7 @@ void PeerManagerImpl::EvictExtraOutboundPeers(std::chrono::seconds now) return true; } else { LogDebug(BCLog::NET, "keeping outbound peer=%d chosen for eviction (connect time: %d, blocks_in_flight: %d)\n", - pnode->GetId(), count_seconds(pnode->m_connected), state.vBlocksInFlight.size()); + pnode->GetId(), TicksSinceEpoch(pnode->m_connected), state.vBlocksInFlight.size()); return false; } }); @@ -5373,9 +5373,10 @@ void PeerManagerImpl::CheckForStaleTipAndEvictPeers() { LOCK(cs_main); + const auto current_time{NodeClock::now()}; auto now{GetTime()}; - EvictExtraOutboundPeers(now); + EvictExtraOutboundPeers(current_time); if (now > m_stale_tip_check_time) { // Check whether our tip is stale, and if so, allow using an extra @@ -5740,7 +5741,7 @@ bool PeerManagerImpl::SendMessages(CNode& node) // Also in CConnman::PushMessage() we make sure that unwanted messages are // not sent. This here is just an optimization. if (node.IsPrivateBroadcastConn()) { - if (node.m_connected + PRIVATE_BROADCAST_MAX_CONNECTION_LIFETIME < current_time) { + if (node.m_connected + PRIVATE_BROADCAST_MAX_CONNECTION_LIFETIME < now) { LogDebug(BCLog::PRIVBROADCAST, "Disconnecting: did not complete the transaction send within %d seconds, %s", count_seconds(PRIVATE_BROADCAST_MAX_CONNECTION_LIFETIME), node.LogPeer()); node.fDisconnect = true; @@ -5748,7 +5749,7 @@ bool PeerManagerImpl::SendMessages(CNode& node) return true; } - if (node.IsAddrFetchConn() && current_time - node.m_connected > 10 * AVG_ADDRESS_BROADCAST_INTERVAL) { + if (node.IsAddrFetchConn() && now - node.m_connected > 10 * AVG_ADDRESS_BROADCAST_INTERVAL) { LogDebug(BCLog::NET, "addrfetch connection timeout, %s", node.DisconnectMsg()); node.fDisconnect = true; return true; diff --git a/src/node/eviction.cpp b/src/node/eviction.cpp index a2267813826..0914ed73a31 100644 --- a/src/node/eviction.cpp +++ b/src/node/eviction.cpp @@ -218,7 +218,7 @@ void ProtectEvictionCandidatesByRatio(std::vector& evicti // (vEvictionCandidates is already sorted by reverse connect time) uint64_t naMostConnections; unsigned int nMostConnections = 0; - std::chrono::seconds nMostConnectionsTime{0}; + NodeClock::time_point nMostConnectionsTime{NodeClock::epoch}; std::map > mapNetGroupNodes; for (const NodeEvictionCandidate &node : vEvictionCandidates) { std::vector &group = mapNetGroupNodes[node.nKeyedNetGroup]; diff --git a/src/node/eviction.h b/src/node/eviction.h index 7230d959df2..3cd40feb38f 100644 --- a/src/node/eviction.h +++ b/src/node/eviction.h @@ -17,7 +17,7 @@ typedef int64_t NodeId; struct NodeEvictionCandidate { NodeId id; - std::chrono::seconds m_connected; + NodeClock::time_point m_connected; NodeClock::duration m_min_ping_time; std::chrono::seconds m_last_block_time; std::chrono::seconds m_last_tx_time; diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index e0210b0570f..e0966b9c38e 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -743,10 +743,9 @@ QString formatDurationStr(std::chrono::nanoseconds dur) return str_list.join(" "); } -QString FormatPeerAge(std::chrono::seconds time_connected) +QString FormatPeerAge(NodeClock::time_point connected) { - const auto time_now{GetTime()}; - const auto age{time_now - time_connected}; + const auto age{NodeClock::now() - connected}; if (age >= 24h) return QObject::tr("%1 d").arg(age / 24h); if (age >= 1h) return QObject::tr("%1 h").arg(age / 1h); if (age >= 1min) return QObject::tr("%1 m").arg(age / 1min); diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 90b8013ef0d..57d042f6c82 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -232,7 +232,7 @@ namespace GUIUtil QString formatDurationStr(std::chrono::nanoseconds dur); /** Convert peer connection time to a QString denominated in the most relevant unit. */ - QString FormatPeerAge(std::chrono::seconds time_connected); + QString FormatPeerAge(NodeClock::time_point connected); /** Format CNodeStats.nServices bitmask into a user-readable string */ QString formatServicesStr(quint64 mask); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index fef1f687208..4c69ec29dd7 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -1167,7 +1167,7 @@ void RPCConsole::updateDetailWidget() ui->peerHighBandwidth->setText(bip152_hb_settings); const auto now{NodeClock::now()}; const auto time_now{GetTime()}; - ui->peerConnTime->setText(GUIUtil::formatDurationStr(time_now - stats->nodeStats.m_connected)); + ui->peerConnTime->setText(GUIUtil::formatDurationStr(now - stats->nodeStats.m_connected)); ui->peerLastBlock->setText(TimeDurationField(time_now, stats->nodeStats.m_last_block_time)); ui->peerLastTx->setText(TimeDurationField(time_now, stats->nodeStats.m_last_tx_time)); ui->peerLastSend->setText(TimeDurationField(now, stats->nodeStats.m_last_send)); diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index ff2adf82d37..08dafdeed23 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -248,7 +248,7 @@ static RPCHelpMan getpeerinfo() obj.pushKV("last_block", count_seconds(stats.m_last_block_time)); obj.pushKV("bytessent", stats.nSendBytes); obj.pushKV("bytesrecv", stats.nRecvBytes); - obj.pushKV("conntime", count_seconds(stats.m_connected)); + obj.pushKV("conntime", TicksSinceEpoch(stats.m_connected)); obj.pushKV("timeoffset", Ticks(statestats.time_offset)); if (stats.m_last_ping_time > 0us) { obj.pushKV("pingtime", Ticks(stats.m_last_ping_time)); diff --git a/src/test/fuzz/node_eviction.cpp b/src/test/fuzz/node_eviction.cpp index 2ecc91a05e3..562ece8be47 100644 --- a/src/test/fuzz/node_eviction.cpp +++ b/src/test/fuzz/node_eviction.cpp @@ -23,7 +23,7 @@ FUZZ_TARGET(node_eviction) { eviction_candidates.push_back({ /*id=*/fuzzed_data_provider.ConsumeIntegral(), - /*m_connected=*/ConsumeTime(fuzzed_data_provider).time_since_epoch(), + /*m_connected=*/ConsumeTime(fuzzed_data_provider), /*m_min_ping_time=*/ConsumeDuration(fuzzed_data_provider, /*min=*/std::chrono::years{-1}, /*max=*/decltype(CNode::m_min_ping_time.load())::max()), /*m_last_block_time=*/ConsumeTime(fuzzed_data_provider).time_since_epoch(), /*m_last_tx_time=*/ConsumeTime(fuzzed_data_provider).time_since_epoch(), diff --git a/src/test/net_peer_eviction_tests.cpp b/src/test/net_peer_eviction_tests.cpp index 5dc2061a188..ab55b75f1ac 100644 --- a/src/test/net_peer_eviction_tests.cpp +++ b/src/test/net_peer_eviction_tests.cpp @@ -68,7 +68,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // to be protected from eviction. BOOST_CHECK(IsProtected( num_peers, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = false; c.m_network = NET_IPV4; }, @@ -79,7 +79,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // Verify in the opposite direction. BOOST_CHECK(IsProtected( num_peers, [num_peers](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{num_peers - c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{num_peers - c.id}}; c.m_is_local = false; c.m_network = NET_IPV6; }, @@ -104,7 +104,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // sorted by longest uptime (lowest m_connected), if no localhost, I2P or CJDNS peers. BOOST_CHECK(IsProtected( num_peers, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = false; c.m_network = (c.id == 3 || c.id > 7) ? NET_ONION : NET_IPV6; }, @@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // sorted by longest uptime (lowest m_connected), if no onion, I2P, or CJDNS peers. BOOST_CHECK(IsProtected( num_peers, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id > 6); c.m_network = NET_IPV6; }, @@ -150,7 +150,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // by longest uptime (lowest m_connected), if no onion, localhost, or CJDNS peers. BOOST_CHECK(IsProtected( num_peers, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = false; c.m_network = (c.id == 4 || c.id > 8) ? NET_I2P : NET_IPV6; }, @@ -173,7 +173,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // by longest uptime (lowest m_connected), if no onion, localhost, or I2P peers. BOOST_CHECK(IsProtected( num_peers, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = false; c.m_network = (c.id == 4 || c.id > 8) ? NET_CJDNS : NET_IPV6; }, @@ -188,7 +188,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // stable sort breaks tie with array order of localhost first. BOOST_CHECK(IsProtected( 4, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id == 4); c.m_network = (c.id == 3) ? NET_ONION : NET_IPV4; }, @@ -201,7 +201,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // uptime; stable sort breaks tie with array order of localhost first. BOOST_CHECK(IsProtected( 7, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id == 6); c.m_network = (c.id == 5) ? NET_ONION : NET_IPV4; }, @@ -214,7 +214,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // by uptime; stable sort breaks tie with array order of localhost first. BOOST_CHECK(IsProtected( 8, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id == 6); c.m_network = (c.id == 5) ? NET_ONION : NET_IPV4; }, @@ -227,7 +227,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // uptime; stable sort breaks ties with the array order of localhost first. BOOST_CHECK(IsProtected( num_peers, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id == 6 || c.id == 9 || c.id == 11); c.m_network = (c.id == 7 || c.id == 8 || c.id == 10) ? NET_ONION : NET_IPV6; }, @@ -239,7 +239,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // protect 2 localhost and 1 onion, plus 3 other peers, sorted by longest uptime. BOOST_CHECK(IsProtected( num_peers, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id > 4 && c.id < 9); c.m_network = (c.id == 10) ? NET_ONION : NET_IPV4; }, @@ -251,7 +251,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // protect 2 localhost and 2 onions, plus 4 other peers, sorted by longest uptime. BOOST_CHECK(IsProtected( 16, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id == 6 || c.id == 9 || c.id == 11 || c.id == 12); c.m_network = (c.id == 8 || c.id == 10) ? NET_ONION : NET_IPV6; }, @@ -264,7 +264,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // others, sorted by longest uptime. BOOST_CHECK(IsProtected( 16, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id > 10); c.m_network = (c.id == 10) ? NET_ONION : NET_IPV4; }, @@ -277,7 +277,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // plus 4 others, sorted by longest uptime. BOOST_CHECK(IsProtected( 16, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id == 15); c.m_network = (c.id > 6 && c.id < 11) ? NET_ONION : NET_IPV6; }, @@ -290,7 +290,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // others, sorted by longest uptime. BOOST_CHECK(IsProtected( num_peers, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = false; if (c.id == 8 || c.id == 10) { c.m_network = NET_ONION; @@ -311,7 +311,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // by longest uptime; stable sort breaks tie with array order of I2P first. BOOST_CHECK(IsProtected( 4, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id == 2); if (c.id == 3) { c.m_network = NET_I2P; @@ -330,7 +330,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // by longest uptime; stable sort breaks tie with array order of I2P first. BOOST_CHECK(IsProtected( 7, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id == 4); if (c.id == 6) { c.m_network = NET_I2P; @@ -349,7 +349,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // by uptime; stable sort breaks tie with array order of I2P then localhost. BOOST_CHECK(IsProtected( 8, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id == 6); if (c.id == 5) { c.m_network = NET_I2P; @@ -368,7 +368,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // for 8 total, sorted by longest uptime. BOOST_CHECK(IsProtected( 16, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id == 6 || c.id > 11); if (c.id == 7 || c.id == 11) { c.m_network = NET_I2P; @@ -387,7 +387,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // sorted by longest uptime. BOOST_CHECK(IsProtected( 24, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id == 12); if (c.id > 14 && c.id < 23) { // 4 protected instead of usual 2 c.m_network = NET_I2P; @@ -406,7 +406,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // unused localhost slot), plus 6 others for 12/24 total, sorted by longest uptime. BOOST_CHECK(IsProtected( 24, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id == 15); if (c.id == 12 || c.id == 14 || c.id == 17) { c.m_network = NET_I2P; @@ -425,7 +425,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // for 12/24 total, sorted by longest uptime. BOOST_CHECK(IsProtected( 24, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id == 13); if (c.id > 16) { c.m_network = NET_I2P; @@ -444,7 +444,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // sorted by longest uptime. BOOST_CHECK(IsProtected( 24, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id > 15); if (c.id > 10 && c.id < 15) { c.m_network = NET_CJDNS; @@ -466,7 +466,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // order of CJDNS first. BOOST_CHECK(IsProtected( 5, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id == 3); if (c.id == 4) { c.m_network = NET_CJDNS; @@ -488,7 +488,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // array order of CJDNS first. BOOST_CHECK(IsProtected( 7, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id == 4); if (c.id == 6) { c.m_network = NET_CJDNS; @@ -510,7 +510,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // array order of CJDNS first. BOOST_CHECK(IsProtected( 8, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id == 3); if (c.id == 5) { c.m_network = NET_CJDNS; @@ -531,7 +531,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // total), plus 4 others for 8 total, sorted by longest uptime. BOOST_CHECK(IsProtected( 16, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id > 5); if (c.id == 11 || c.id == 15) { c.m_network = NET_CJDNS; @@ -552,7 +552,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // total), plus 6 others for 12/24 total, sorted by longest uptime. BOOST_CHECK(IsProtected( 24, [](NodeEvictionCandidate& c) { - c.m_connected = std::chrono::seconds{c.id}; + c.m_connected = NodeSeconds{std::chrono::seconds{c.id}}; c.m_is_local = (c.id == 13); if (c.id > 17) { c.m_network = NET_CJDNS; diff --git a/src/test/util/net.cpp b/src/test/util/net.cpp index 73e5a58d5d9..f20dda419bf 100644 --- a/src/test/util/net.cpp +++ b/src/test/util/net.cpp @@ -140,7 +140,7 @@ std::vector GetRandomNodeEvictionCandidates(int n_candida for (int id = 0; id < n_candidates; ++id) { candidates.push_back({ .id=id, - .m_connected=std::chrono::seconds{random_context.randrange(100)}, + .m_connected=NodeSeconds{std::chrono::seconds{random_context.randrange(100)}}, .m_min_ping_time=std::chrono::microseconds{random_context.randrange(100)}, .m_last_block_time=std::chrono::seconds{random_context.randrange(100)}, .m_last_tx_time=std::chrono::seconds{random_context.randrange(100)},