From 3d7c30ebb6ac0c586635c693a40bc39180f539b9 Mon Sep 17 00:00:00 2001 From: bitflash-maintainer Date: Tue, 11 Aug 2026 20:52:09 +0000 Subject: pool: refuse jobs when no peer has reported a height for 20 minutes The peer-height gate replaced a tip-age check that was wrong in both directions. It is a strict improvement and it is still blind in the one case that matters most. When the node goes deaf -- peers still in vNodes, nothing arriving -- no peer announces anything, GetPeerMedianHeight() returns -1, and the fallback mines our best chain. That fallback is right for a node that has not been told yet and wrong for a node that has stopped being able to hear, and a height nobody sent cannot tell those apart. A wedged node is exactly a node with no peer height information, so the gate was silent for the whole of heights 3966-4085: 120 blocks, 5890.50 BTF voided. Time can tell them apart. GetPeerHeightAgeSecs() measures how long since any peer reported a height, counting from first use rather than the epoch so a starting node does not refuse jobs before its first handshake. Past 20 minutes the pool stops issuing jobs and says so unconditionally in the log. /poolmineblind overrides it: without an escape hatch a genuinely isolated pool that is 90% of the hashrate could never restart its own chain, which is the deadlock the tip-age check used to cause. Also stop nStartingHeight from going stale. It was a snapshot taken once during the version handshake and never touched again, so on a long-lived connection the median is built from heights the peers had hours ago, and the behind-the-network check drifts toward 'everyone is behind us' and quietly stops firing. A peer that hands us a block is demonstrably at least at that block's height. (cherry picked from commit 0800c18faf703b4acde1b131d0b742d37a86d92b) --- src/net.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 5cf2f8c..964097b 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1700,6 +1700,13 @@ void ThreadMessageHandler(void* parg) } } +// When any peer last told us a height. A wedged node -- one that still has +// peers but has stopped hearing them -- is exactly a node where this stops +// advancing, and that is the one thing the height comparison itself cannot +// see: there is no height to compare. +static int64 nLastPeerHeightSeen = 0; +static int64 nPeerHeightFirstAsked = 0; + int GetPeerMedianHeight() { vector vHeights; @@ -1711,10 +1718,26 @@ int GetPeerMedianHeight() if (vHeights.empty()) return -1; + nLastPeerHeightSeen = GetTime(); sort(vHeights.begin(), vHeights.end()); return vHeights[vHeights.size() / 2]; } +// Seconds since any peer last reported a height. +// +// Before ever hearing one, measure from the first time somebody asked rather +// than from the epoch -- otherwise a node refuses jobs the instant it starts, +// before it has had a chance to complete a single handshake. +int64 GetPeerHeightAgeSecs() +{ + int64 nNow = GetTime(); + if (nPeerHeightFirstAsked == 0) + nPeerHeightFirstAsked = nNow; + if (nLastPeerHeightSeen == 0) + return nNow - nPeerHeightFirstAsked; + return nNow - nLastPeerHeightSeen; +} + // Say out loud when we are behind the network. // -- cgit v1.2.3