Skip to content

Commit 45dcf22

Browse files
committed
[net processing] Move ping data fields to net processing
1 parent dd2646d commit 45dcf22

File tree

6 files changed

+66
-51
lines changed

6 files changed

+66
-51
lines changed

src/net.cpp

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -601,21 +601,8 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap)
601601
stats.minFeeFilter = 0;
602602
}
603603

604-
// It is common for nodes with good ping times to suddenly become lagged,
605-
// due to a new block arriving or other large transfer.
606-
// Merely reporting pingtime might fool the caller into thinking the node was still responsive,
607-
// since pingtime does not update until the ping is complete, which might take a while.
608-
// So, if a ping is taking an unusually long time in flight,
609-
// the caller can immediately detect that this is happening.
610-
std::chrono::microseconds ping_wait{0};
611-
if ((0 != nPingNonceSent) && (0 != m_ping_start.load().count())) {
612-
ping_wait = GetTime<std::chrono::microseconds>() - m_ping_start.load();
613-
}
614-
615-
// Raw ping time is in microseconds, but show it to user as whole seconds (Bitcoin users should be well used to small numbers with many decimal places by now :)
616604
stats.m_ping_usec = nPingUsecTime;
617-
stats.m_min_ping_usec = nMinPingUsecTime;
618-
stats.m_ping_wait_usec = count_microseconds(ping_wait);
605+
stats.m_min_ping_usec = nMinPingUsecTime;
619606

620607
// Leave string empty if addrLocal invalid (not filled in yet)
621608
CService addrLocalUnlocked = GetAddrLocal();

src/net.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,6 @@ class CNodeStats
260260
mapMsgCmdSize mapRecvBytesPerMsgCmd;
261261
NetPermissionFlags m_permissionFlags;
262262
int64_t m_ping_usec;
263-
int64_t m_ping_wait_usec;
264263
int64_t m_min_ping_usec;
265264
CAmount minFeeFilter;
266265
// Our address, as reported by the peer
@@ -591,17 +590,12 @@ class CNode
591590
* in CConnman::AttemptToEvictConnection. */
592591
std::atomic<int64_t> nLastTXTime{0};
593592

594-
// Ping time measurement:
595-
// The pong reply we're expecting, or 0 if no pong expected.
596-
std::atomic<uint64_t> nPingNonceSent{0};
597-
/** When the last ping was sent, or 0 if no ping was ever sent */
598-
std::atomic<std::chrono::microseconds> m_ping_start{0us};
599-
// Last measured round-trip time.
593+
/** Last measured round-trip time. Used only for RPC/GUI stats/debugging.*/
600594
std::atomic<int64_t> nPingUsecTime{0};
601-
// Best measured round-trip time.
595+
596+
/** Lowest measured round-trip time. Used as an inbound peer eviction
597+
* criterium in CConnman::AttemptToEvictConnection. */
602598
std::atomic<int64_t> nMinPingUsecTime{std::numeric_limits<int64_t>::max()};
603-
// Whether a ping is requested.
604-
std::atomic<bool> fPingQueued{false};
605599

606600
CNode(NodeId id, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress& addrBindIn, const std::string& addrNameIn, ConnectionType conn_type_in, bool inbound_onion);
607601
~CNode();
@@ -721,6 +715,12 @@ class CNode
721715

722716
std::string ConnectionTypeAsString() const { return ::ConnectionTypeAsString(m_conn_type); }
723717

718+
/** A ping-pong round trip has completed successfully. Update latest and minimum ping times. */
719+
void PongReceived(std::chrono::microseconds ping_time) {
720+
nPingUsecTime = count_microseconds(ping_time);
721+
nMinPingUsecTime = std::min(nMinPingUsecTime.load(), count_microseconds(ping_time));
722+
}
723+
724724
private:
725725
const NodeId id;
726726
const uint64_t nLocalHostNonce;

src/net_processing.cpp

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,13 @@ struct Peer {
219219
/** This peer's reported block height when we connected */
220220
std::atomic<int> m_starting_height{-1};
221221

222+
/** The pong reply we're expecting, or 0 if no pong expected. */
223+
std::atomic<uint64_t> nPingNonceSent{0};
224+
/** When the last ping was sent, or 0 if no ping was ever sent */
225+
std::atomic<std::chrono::microseconds> m_ping_start{0us};
226+
/** Whether a ping has been requested by the user */
227+
std::atomic<bool> fPingQueued{false};
228+
222229
/** Set of txids to reconsider once their parent transactions have been accepted **/
223230
std::set<uint256> m_orphan_work_set GUARDED_BY(g_cs_orphans);
224231

@@ -256,6 +263,7 @@ class PeerManagerImpl final : public PeerManager
256263
void CheckForStaleTipAndEvictPeers() override;
257264
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) override;
258265
bool IgnoresIncomingTxs() override { return m_ignore_incoming_txs; }
266+
void SendPings() override;
259267
void SetBestHeight(int height) override { m_best_height = height; };
260268
void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message) override;
261269
void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv,
@@ -326,7 +334,7 @@ class PeerManagerImpl final : public PeerManager
326334

327335
/** Send a ping message every PING_INTERVAL or if requested via RPC. May
328336
* mark the peer to be disconnected if a ping has timed out. */
329-
void MaybeSendPing(CNode& node_to);
337+
void MaybeSendPing(CNode& node_to, Peer& peer);
330338

331339
const CChainParams& m_chainparams;
332340
CConnman& m_connman;
@@ -1093,6 +1101,18 @@ bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats)
10931101
PeerRef peer = GetPeerRef(nodeid);
10941102
if (peer == nullptr) return false;
10951103
stats.m_starting_height = peer->m_starting_height;
1104+
// It is common for nodes with good ping times to suddenly become lagged,
1105+
// due to a new block arriving or other large transfer.
1106+
// Merely reporting pingtime might fool the caller into thinking the node was still responsive,
1107+
// since pingtime does not update until the ping is complete, which might take a while.
1108+
// So, if a ping is taking an unusually long time in flight,
1109+
// the caller can immediately detect that this is happening.
1110+
std::chrono::microseconds ping_wait{0};
1111+
if ((0 != peer->nPingNonceSent) && (0 != peer->m_ping_start.load().count())) {
1112+
ping_wait = GetTime<std::chrono::microseconds>() - peer->m_ping_start.load();
1113+
}
1114+
1115+
stats.m_ping_wait_usec = count_microseconds(ping_wait);
10961116

10971117
return true;
10981118
}
@@ -1632,6 +1652,12 @@ bool static AlreadyHaveBlock(const uint256& block_hash) EXCLUSIVE_LOCKS_REQUIRED
16321652
return g_chainman.m_blockman.LookupBlockIndex(block_hash) != nullptr;
16331653
}
16341654

1655+
void PeerManagerImpl::SendPings()
1656+
{
1657+
LOCK(m_peer_mutex);
1658+
for(auto& it : m_peer_map) it.second->fPingQueued = true;
1659+
}
1660+
16351661
void RelayTransaction(const uint256& txid, const uint256& wtxid, const CConnman& connman)
16361662
{
16371663
connman.ForEachNode([&txid, &wtxid](CNode* pnode) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
@@ -3842,15 +3868,14 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
38423868
vRecv >> nonce;
38433869

38443870
// Only process pong message if there is an outstanding ping (old ping without nonce should never pong)
3845-
if (pfrom.nPingNonceSent != 0) {
3846-
if (nonce == pfrom.nPingNonceSent) {
3871+
if (peer->nPingNonceSent != 0) {
3872+
if (nonce == peer->nPingNonceSent) {
38473873
// Matching pong received, this ping is no longer outstanding
38483874
bPingFinished = true;
3849-
const auto ping_time = ping_end - pfrom.m_ping_start.load();
3875+
const auto ping_time = ping_end - peer->m_ping_start.load();
38503876
if (ping_time.count() >= 0) {
3851-
// Successful ping time measurement, replace previous
3852-
pfrom.nPingUsecTime = count_microseconds(ping_time);
3853-
pfrom.nMinPingUsecTime = std::min(pfrom.nMinPingUsecTime.load(), count_microseconds(ping_time));
3877+
// Let connman know about this successful ping-pong
3878+
pfrom.PongReceived(ping_time);
38543879
} else {
38553880
// This should never happen
38563881
sProblem = "Timing mishap";
@@ -3877,12 +3902,12 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
38773902
LogPrint(BCLog::NET, "pong peer=%d: %s, %x expected, %x received, %u bytes\n",
38783903
pfrom.GetId(),
38793904
sProblem,
3880-
pfrom.nPingNonceSent,
3905+
peer->nPingNonceSent,
38813906
nonce,
38823907
nAvail);
38833908
}
38843909
if (bPingFinished) {
3885-
pfrom.nPingNonceSent = 0;
3910+
peer->nPingNonceSent = 0;
38863911
}
38873912
return;
38883913
}
@@ -4296,28 +4321,28 @@ void PeerManagerImpl::CheckForStaleTipAndEvictPeers()
42964321
}
42974322
}
42984323

4299-
void PeerManagerImpl::MaybeSendPing(CNode& node_to)
4324+
void PeerManagerImpl::MaybeSendPing(CNode& node_to, Peer& peer)
43004325
{
43014326
// Use mockable time for ping timeouts.
43024327
// This means that setmocktime may cause pings to time out.
43034328
auto now = GetTime<std::chrono::microseconds>();
43044329

4305-
if (m_connman.RunInactivityChecks(node_to) && node_to.nPingNonceSent &&
4306-
now > node_to.m_ping_start.load() + std::chrono::seconds{TIMEOUT_INTERVAL}) {
4307-
LogPrint(BCLog::NET, "ping timeout: %fs peer=%d\n", 0.000001 * count_microseconds(now - node_to.m_ping_start.load()), node_to.GetId());
4330+
if (m_connman.RunInactivityChecks(node_to) && peer.nPingNonceSent &&
4331+
now > peer.m_ping_start.load() + std::chrono::seconds{TIMEOUT_INTERVAL}) {
4332+
LogPrint(BCLog::NET, "ping timeout: %fs peer=%d\n", 0.000001 * count_microseconds(now - peer.m_ping_start.load()), peer.m_id);
43084333
node_to.fDisconnect = true;
43094334
return;
43104335
}
43114336

43124337
const CNetMsgMaker msgMaker(node_to.GetCommonVersion());
43134338
bool pingSend = false;
43144339

4315-
if (node_to.fPingQueued) {
4340+
if (peer.fPingQueued) {
43164341
// RPC ping request by user
43174342
pingSend = true;
43184343
}
43194344

4320-
if (node_to.nPingNonceSent == 0 && now > node_to.m_ping_start.load() + PING_INTERVAL) {
4345+
if (peer.nPingNonceSent == 0 && now > peer.m_ping_start.load() + PING_INTERVAL) {
43214346
// Ping automatically sent as a latency probe & keepalive.
43224347
pingSend = true;
43234348
}
@@ -4327,14 +4352,14 @@ void PeerManagerImpl::MaybeSendPing(CNode& node_to)
43274352
while (nonce == 0) {
43284353
GetRandBytes((unsigned char*)&nonce, sizeof(nonce));
43294354
}
4330-
node_to.fPingQueued = false;
4331-
node_to.m_ping_start = now;
4355+
peer.fPingQueued = false;
4356+
peer.m_ping_start = now;
43324357
if (node_to.GetCommonVersion() > BIP0031_VERSION) {
4333-
node_to.nPingNonceSent = nonce;
4358+
peer.nPingNonceSent = nonce;
43344359
m_connman.PushMessage(&node_to, msgMaker.Make(NetMsgType::PING, nonce));
43354360
} else {
43364361
// Peer is too old to support ping command with nonce, pong will never arrive.
4337-
node_to.nPingNonceSent = 0;
4362+
peer.nPingNonceSent = 0;
43384363
m_connman.PushMessage(&node_to, msgMaker.Make(NetMsgType::PING));
43394364
}
43404365
}
@@ -4378,7 +4403,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
43784403
// If we get here, the outgoing message serialization version is set and can't change.
43794404
const CNetMsgMaker msgMaker(pto->GetCommonVersion());
43804405

4381-
MaybeSendPing(*pto);
4406+
MaybeSendPing(*pto, *peer);
43824407

43834408
// MaybeSendPing may have marked peer for disconnection
43844409
if (pto->fDisconnect) return true;

src/net_processing.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ struct CNodeStateStats {
3030
int nSyncHeight = -1;
3131
int nCommonHeight = -1;
3232
int m_starting_height = -1;
33+
int64_t m_ping_wait_usec;
3334
std::vector<int> vHeightInFlight;
3435
};
3536

@@ -47,6 +48,9 @@ class PeerManager : public CValidationInterface, public NetEventsInterface
4748
/** Whether this node ignores txs received over p2p. */
4849
virtual bool IgnoresIncomingTxs() = 0;
4950

51+
/** Send ping message to all peers */
52+
virtual void SendPings() = 0;
53+
5054
/** Set the best height */
5155
virtual void SetBestHeight(int height) = 0;
5256

src/qt/rpcconsole.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1115,7 +1115,6 @@ void RPCConsole::updateDetailWidget()
11151115
ui->peerBytesRecv->setText(GUIUtil::formatBytes(stats->nodeStats.nRecvBytes));
11161116
ui->peerConnTime->setText(GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nTimeConnected));
11171117
ui->peerPingTime->setText(GUIUtil::formatPingTime(stats->nodeStats.m_ping_usec));
1118-
ui->peerPingWait->setText(GUIUtil::formatPingTime(stats->nodeStats.m_ping_wait_usec));
11191118
ui->peerMinPing->setText(GUIUtil::formatPingTime(stats->nodeStats.m_min_ping_usec));
11201119
ui->timeoffset->setText(GUIUtil::formatTimeOffset(stats->nodeStats.nTimeOffset));
11211120
ui->peerVersion->setText(QString::number(stats->nodeStats.nVersion));
@@ -1149,6 +1148,7 @@ void RPCConsole::updateDetailWidget()
11491148
ui->peerCommonHeight->setText(tr("Unknown"));
11501149

11511150
ui->peerHeight->setText(QString::number(stats->nodeStateStats.m_starting_height));
1151+
ui->peerPingWait->setText(GUIUtil::formatPingTime(stats->nodeStateStats.m_ping_wait_usec));
11521152
}
11531153

11541154
ui->detailWidget->show();

src/rpc/net.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,12 @@ static RPCHelpMan ping()
7777
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
7878
{
7979
NodeContext& node = EnsureNodeContext(request.context);
80-
if(!node.connman)
80+
if (!node.peerman) {
8181
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
82+
}
8283

8384
// Request that each node send a ping during next message processing pass
84-
node.connman->ForEachNode([](CNode* pnode) {
85-
pnode->fPingQueued = true;
86-
});
85+
node.peerman->SendPings();
8786
return NullUniValue;
8887
},
8988
};
@@ -209,8 +208,8 @@ static RPCHelpMan getpeerinfo()
209208
if (stats.m_min_ping_usec < std::numeric_limits<int64_t>::max()) {
210209
obj.pushKV("minping", ((double)stats.m_min_ping_usec) / 1e6);
211210
}
212-
if (stats.m_ping_wait_usec > 0) {
213-
obj.pushKV("pingwait", ((double)stats.m_ping_wait_usec) / 1e6);
211+
if (fStateStats && statestats.m_ping_wait_usec > 0) {
212+
obj.pushKV("pingwait", ((double)statestats.m_ping_wait_usec) / 1e6);
214213
}
215214
obj.pushKV("version", stats.nVersion);
216215
// Use the sanitized form of subver here, to avoid tricksy remote peers from

0 commit comments

Comments
 (0)