mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-08 10:31:50 -05:00
[net processing] Move ping data fields to net processing
This commit is contained in:
parent
dd2646d12c
commit
45dcf22661
6 changed files with 66 additions and 51 deletions
15
src/net.cpp
15
src/net.cpp
|
@ -601,21 +601,8 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap)
|
|||
stats.minFeeFilter = 0;
|
||||
}
|
||||
|
||||
// It is common for nodes with good ping times to suddenly become lagged,
|
||||
// due to a new block arriving or other large transfer.
|
||||
// Merely reporting pingtime might fool the caller into thinking the node was still responsive,
|
||||
// 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.
|
||||
std::chrono::microseconds ping_wait{0};
|
||||
if ((0 != nPingNonceSent) && (0 != m_ping_start.load().count())) {
|
||||
ping_wait = GetTime<std::chrono::microseconds>() - m_ping_start.load();
|
||||
}
|
||||
|
||||
// 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 :)
|
||||
stats.m_ping_usec = nPingUsecTime;
|
||||
stats.m_min_ping_usec = nMinPingUsecTime;
|
||||
stats.m_ping_wait_usec = count_microseconds(ping_wait);
|
||||
stats.m_min_ping_usec = nMinPingUsecTime;
|
||||
|
||||
// Leave string empty if addrLocal invalid (not filled in yet)
|
||||
CService addrLocalUnlocked = GetAddrLocal();
|
||||
|
|
20
src/net.h
20
src/net.h
|
@ -260,7 +260,6 @@ public:
|
|||
mapMsgCmdSize mapRecvBytesPerMsgCmd;
|
||||
NetPermissionFlags m_permissionFlags;
|
||||
int64_t m_ping_usec;
|
||||
int64_t m_ping_wait_usec;
|
||||
int64_t m_min_ping_usec;
|
||||
CAmount minFeeFilter;
|
||||
// Our address, as reported by the peer
|
||||
|
@ -591,17 +590,12 @@ public:
|
|||
* in CConnman::AttemptToEvictConnection. */
|
||||
std::atomic<int64_t> nLastTXTime{0};
|
||||
|
||||
// Ping time measurement:
|
||||
// The pong reply we're expecting, or 0 if no pong expected.
|
||||
std::atomic<uint64_t> nPingNonceSent{0};
|
||||
/** When the last ping was sent, or 0 if no ping was ever sent */
|
||||
std::atomic<std::chrono::microseconds> m_ping_start{0us};
|
||||
// Last measured round-trip time.
|
||||
/** Last measured round-trip time. Used only for RPC/GUI stats/debugging.*/
|
||||
std::atomic<int64_t> nPingUsecTime{0};
|
||||
// Best measured round-trip time.
|
||||
|
||||
/** Lowest measured round-trip time. Used as an inbound peer eviction
|
||||
* criterium in CConnman::AttemptToEvictConnection. */
|
||||
std::atomic<int64_t> nMinPingUsecTime{std::numeric_limits<int64_t>::max()};
|
||||
// Whether a ping is requested.
|
||||
std::atomic<bool> fPingQueued{false};
|
||||
|
||||
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);
|
||||
~CNode();
|
||||
|
@ -721,6 +715,12 @@ public:
|
|||
|
||||
std::string ConnectionTypeAsString() const { return ::ConnectionTypeAsString(m_conn_type); }
|
||||
|
||||
/** A ping-pong round trip has completed successfully. Update latest and minimum ping times. */
|
||||
void PongReceived(std::chrono::microseconds ping_time) {
|
||||
nPingUsecTime = count_microseconds(ping_time);
|
||||
nMinPingUsecTime = std::min(nMinPingUsecTime.load(), count_microseconds(ping_time));
|
||||
}
|
||||
|
||||
private:
|
||||
const NodeId id;
|
||||
const uint64_t nLocalHostNonce;
|
||||
|
|
|
@ -219,6 +219,13 @@ struct Peer {
|
|||
/** This peer's reported block height when we connected */
|
||||
std::atomic<int> m_starting_height{-1};
|
||||
|
||||
/** The pong reply we're expecting, or 0 if no pong expected. */
|
||||
std::atomic<uint64_t> nPingNonceSent{0};
|
||||
/** When the last ping was sent, or 0 if no ping was ever sent */
|
||||
std::atomic<std::chrono::microseconds> m_ping_start{0us};
|
||||
/** Whether a ping has been requested by the user */
|
||||
std::atomic<bool> fPingQueued{false};
|
||||
|
||||
/** Set of txids to reconsider once their parent transactions have been accepted **/
|
||||
std::set<uint256> m_orphan_work_set GUARDED_BY(g_cs_orphans);
|
||||
|
||||
|
@ -256,6 +263,7 @@ public:
|
|||
void CheckForStaleTipAndEvictPeers() override;
|
||||
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) override;
|
||||
bool IgnoresIncomingTxs() override { return m_ignore_incoming_txs; }
|
||||
void SendPings() override;
|
||||
void SetBestHeight(int height) override { m_best_height = height; };
|
||||
void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message) override;
|
||||
void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv,
|
||||
|
@ -326,7 +334,7 @@ private:
|
|||
|
||||
/** Send a ping message every PING_INTERVAL or if requested via RPC. May
|
||||
* mark the peer to be disconnected if a ping has timed out. */
|
||||
void MaybeSendPing(CNode& node_to);
|
||||
void MaybeSendPing(CNode& node_to, Peer& peer);
|
||||
|
||||
const CChainParams& m_chainparams;
|
||||
CConnman& m_connman;
|
||||
|
@ -1093,6 +1101,18 @@ bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats)
|
|||
PeerRef peer = GetPeerRef(nodeid);
|
||||
if (peer == nullptr) return false;
|
||||
stats.m_starting_height = peer->m_starting_height;
|
||||
// It is common for nodes with good ping times to suddenly become lagged,
|
||||
// due to a new block arriving or other large transfer.
|
||||
// Merely reporting pingtime might fool the caller into thinking the node was still responsive,
|
||||
// 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.
|
||||
std::chrono::microseconds ping_wait{0};
|
||||
if ((0 != peer->nPingNonceSent) && (0 != peer->m_ping_start.load().count())) {
|
||||
ping_wait = GetTime<std::chrono::microseconds>() - peer->m_ping_start.load();
|
||||
}
|
||||
|
||||
stats.m_ping_wait_usec = count_microseconds(ping_wait);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1632,6 +1652,12 @@ bool static AlreadyHaveBlock(const uint256& block_hash) EXCLUSIVE_LOCKS_REQUIRED
|
|||
return g_chainman.m_blockman.LookupBlockIndex(block_hash) != nullptr;
|
||||
}
|
||||
|
||||
void PeerManagerImpl::SendPings()
|
||||
{
|
||||
LOCK(m_peer_mutex);
|
||||
for(auto& it : m_peer_map) it.second->fPingQueued = true;
|
||||
}
|
||||
|
||||
void RelayTransaction(const uint256& txid, const uint256& wtxid, const CConnman& connman)
|
||||
{
|
||||
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,
|
|||
vRecv >> nonce;
|
||||
|
||||
// Only process pong message if there is an outstanding ping (old ping without nonce should never pong)
|
||||
if (pfrom.nPingNonceSent != 0) {
|
||||
if (nonce == pfrom.nPingNonceSent) {
|
||||
if (peer->nPingNonceSent != 0) {
|
||||
if (nonce == peer->nPingNonceSent) {
|
||||
// Matching pong received, this ping is no longer outstanding
|
||||
bPingFinished = true;
|
||||
const auto ping_time = ping_end - pfrom.m_ping_start.load();
|
||||
const auto ping_time = ping_end - peer->m_ping_start.load();
|
||||
if (ping_time.count() >= 0) {
|
||||
// Successful ping time measurement, replace previous
|
||||
pfrom.nPingUsecTime = count_microseconds(ping_time);
|
||||
pfrom.nMinPingUsecTime = std::min(pfrom.nMinPingUsecTime.load(), count_microseconds(ping_time));
|
||||
// Let connman know about this successful ping-pong
|
||||
pfrom.PongReceived(ping_time);
|
||||
} else {
|
||||
// This should never happen
|
||||
sProblem = "Timing mishap";
|
||||
|
@ -3877,12 +3902,12 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
|
|||
LogPrint(BCLog::NET, "pong peer=%d: %s, %x expected, %x received, %u bytes\n",
|
||||
pfrom.GetId(),
|
||||
sProblem,
|
||||
pfrom.nPingNonceSent,
|
||||
peer->nPingNonceSent,
|
||||
nonce,
|
||||
nAvail);
|
||||
}
|
||||
if (bPingFinished) {
|
||||
pfrom.nPingNonceSent = 0;
|
||||
peer->nPingNonceSent = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -4296,15 +4321,15 @@ void PeerManagerImpl::CheckForStaleTipAndEvictPeers()
|
|||
}
|
||||
}
|
||||
|
||||
void PeerManagerImpl::MaybeSendPing(CNode& node_to)
|
||||
void PeerManagerImpl::MaybeSendPing(CNode& node_to, Peer& peer)
|
||||
{
|
||||
// Use mockable time for ping timeouts.
|
||||
// This means that setmocktime may cause pings to time out.
|
||||
auto now = GetTime<std::chrono::microseconds>();
|
||||
|
||||
if (m_connman.RunInactivityChecks(node_to) && node_to.nPingNonceSent &&
|
||||
now > node_to.m_ping_start.load() + std::chrono::seconds{TIMEOUT_INTERVAL}) {
|
||||
LogPrint(BCLog::NET, "ping timeout: %fs peer=%d\n", 0.000001 * count_microseconds(now - node_to.m_ping_start.load()), node_to.GetId());
|
||||
if (m_connman.RunInactivityChecks(node_to) && peer.nPingNonceSent &&
|
||||
now > peer.m_ping_start.load() + std::chrono::seconds{TIMEOUT_INTERVAL}) {
|
||||
LogPrint(BCLog::NET, "ping timeout: %fs peer=%d\n", 0.000001 * count_microseconds(now - peer.m_ping_start.load()), peer.m_id);
|
||||
node_to.fDisconnect = true;
|
||||
return;
|
||||
}
|
||||
|
@ -4312,12 +4337,12 @@ void PeerManagerImpl::MaybeSendPing(CNode& node_to)
|
|||
const CNetMsgMaker msgMaker(node_to.GetCommonVersion());
|
||||
bool pingSend = false;
|
||||
|
||||
if (node_to.fPingQueued) {
|
||||
if (peer.fPingQueued) {
|
||||
// RPC ping request by user
|
||||
pingSend = true;
|
||||
}
|
||||
|
||||
if (node_to.nPingNonceSent == 0 && now > node_to.m_ping_start.load() + PING_INTERVAL) {
|
||||
if (peer.nPingNonceSent == 0 && now > peer.m_ping_start.load() + PING_INTERVAL) {
|
||||
// Ping automatically sent as a latency probe & keepalive.
|
||||
pingSend = true;
|
||||
}
|
||||
|
@ -4327,14 +4352,14 @@ void PeerManagerImpl::MaybeSendPing(CNode& node_to)
|
|||
while (nonce == 0) {
|
||||
GetRandBytes((unsigned char*)&nonce, sizeof(nonce));
|
||||
}
|
||||
node_to.fPingQueued = false;
|
||||
node_to.m_ping_start = now;
|
||||
peer.fPingQueued = false;
|
||||
peer.m_ping_start = now;
|
||||
if (node_to.GetCommonVersion() > BIP0031_VERSION) {
|
||||
node_to.nPingNonceSent = nonce;
|
||||
peer.nPingNonceSent = nonce;
|
||||
m_connman.PushMessage(&node_to, msgMaker.Make(NetMsgType::PING, nonce));
|
||||
} else {
|
||||
// Peer is too old to support ping command with nonce, pong will never arrive.
|
||||
node_to.nPingNonceSent = 0;
|
||||
peer.nPingNonceSent = 0;
|
||||
m_connman.PushMessage(&node_to, msgMaker.Make(NetMsgType::PING));
|
||||
}
|
||||
}
|
||||
|
@ -4378,7 +4403,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
|
|||
// If we get here, the outgoing message serialization version is set and can't change.
|
||||
const CNetMsgMaker msgMaker(pto->GetCommonVersion());
|
||||
|
||||
MaybeSendPing(*pto);
|
||||
MaybeSendPing(*pto, *peer);
|
||||
|
||||
// MaybeSendPing may have marked peer for disconnection
|
||||
if (pto->fDisconnect) return true;
|
||||
|
|
|
@ -30,6 +30,7 @@ struct CNodeStateStats {
|
|||
int nSyncHeight = -1;
|
||||
int nCommonHeight = -1;
|
||||
int m_starting_height = -1;
|
||||
int64_t m_ping_wait_usec;
|
||||
std::vector<int> vHeightInFlight;
|
||||
};
|
||||
|
||||
|
@ -47,6 +48,9 @@ public:
|
|||
/** Whether this node ignores txs received over p2p. */
|
||||
virtual bool IgnoresIncomingTxs() = 0;
|
||||
|
||||
/** Send ping message to all peers */
|
||||
virtual void SendPings() = 0;
|
||||
|
||||
/** Set the best height */
|
||||
virtual void SetBestHeight(int height) = 0;
|
||||
|
||||
|
|
|
@ -1115,7 +1115,6 @@ void RPCConsole::updateDetailWidget()
|
|||
ui->peerBytesRecv->setText(GUIUtil::formatBytes(stats->nodeStats.nRecvBytes));
|
||||
ui->peerConnTime->setText(GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nTimeConnected));
|
||||
ui->peerPingTime->setText(GUIUtil::formatPingTime(stats->nodeStats.m_ping_usec));
|
||||
ui->peerPingWait->setText(GUIUtil::formatPingTime(stats->nodeStats.m_ping_wait_usec));
|
||||
ui->peerMinPing->setText(GUIUtil::formatPingTime(stats->nodeStats.m_min_ping_usec));
|
||||
ui->timeoffset->setText(GUIUtil::formatTimeOffset(stats->nodeStats.nTimeOffset));
|
||||
ui->peerVersion->setText(QString::number(stats->nodeStats.nVersion));
|
||||
|
@ -1149,6 +1148,7 @@ void RPCConsole::updateDetailWidget()
|
|||
ui->peerCommonHeight->setText(tr("Unknown"));
|
||||
|
||||
ui->peerHeight->setText(QString::number(stats->nodeStateStats.m_starting_height));
|
||||
ui->peerPingWait->setText(GUIUtil::formatPingTime(stats->nodeStateStats.m_ping_wait_usec));
|
||||
}
|
||||
|
||||
ui->detailWidget->show();
|
||||
|
|
|
@ -77,13 +77,12 @@ static RPCHelpMan ping()
|
|||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
NodeContext& node = EnsureNodeContext(request.context);
|
||||
if(!node.connman)
|
||||
if (!node.peerman) {
|
||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
||||
}
|
||||
|
||||
// Request that each node send a ping during next message processing pass
|
||||
node.connman->ForEachNode([](CNode* pnode) {
|
||||
pnode->fPingQueued = true;
|
||||
});
|
||||
node.peerman->SendPings();
|
||||
return NullUniValue;
|
||||
},
|
||||
};
|
||||
|
@ -209,8 +208,8 @@ static RPCHelpMan getpeerinfo()
|
|||
if (stats.m_min_ping_usec < std::numeric_limits<int64_t>::max()) {
|
||||
obj.pushKV("minping", ((double)stats.m_min_ping_usec) / 1e6);
|
||||
}
|
||||
if (stats.m_ping_wait_usec > 0) {
|
||||
obj.pushKV("pingwait", ((double)stats.m_ping_wait_usec) / 1e6);
|
||||
if (fStateStats && statestats.m_ping_wait_usec > 0) {
|
||||
obj.pushKV("pingwait", ((double)statestats.m_ping_wait_usec) / 1e6);
|
||||
}
|
||||
obj.pushKV("version", stats.nVersion);
|
||||
// Use the sanitized form of subver here, to avoid tricksy remote peers from
|
||||
|
|
Loading…
Add table
Reference in a new issue