upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/net.h
AgeCommit message (Collapse)Author
2026-08-19net: time the stall, not the wait, before dropping an unreadable peerbitflash-maintainer
Found auditing the previous commit for the push. Timing from the first rewind would drop a peer whose message is large and merely slow, which would be a fault of our own making rather than one we fixed. Restart the clock whenever the buffer has grown by even one byte since the last look. A transfer still making progress is never dropped however long it takes; only one that has stopped growing while the node goes on expecting more is, which is the actual failure. (cherry picked from commit 5dddb26bae02013ce87719b11953aadf0bfa2594)
2026-08-19net: give up waiting for a message body that is never going to arrivebitflash-maintainer
THIS IS THE WEDGE, and the note asking for this fix has been in the file since Bitcoin 0.1: 'need a mechanism to give up waiting for overlong message size error'. ProcessMessages reads a header, finds the body has not all arrived, pushes the header back onto the front of vRecv and breaks. Correct for a message still in flight. For one that never completes it is permanent: every later pass re-reads the same header and breaks in the same place, so that peer is never parsed again for the life of the process -- no blocks, no inv, not even its version message. Nothing rescues it: - a header may claim up to 256 MB (0x10000000) and still pass CMessageHeader::IsValid(), so a garbage or truncated header is accepted and then waited on forever; - nLastRecv is refreshed by any byte that arrives (net.cpp), whether or not it parses, so the inactivity timeout that drops a silent peer never fires on a peer that is merely unreadable; - the socket stays ESTABLISHED and select() keeps offering it, so nothing at the socket layer notices either. It also explains the signature that made no sense. A peer stuck before its version message is parsed keeps nStartingHeight == -1, so a node with a full vNodes still reports GetPeerMedianHeight() == -1 -- which is exactly what was observed, and exactly what disabled the pool's behind-the-network gate and let it fork. Evidence, from two wedges captured on the pool by the watchdog: MESSAGE-BREAK 2 ran 2014 times in the deaf window against 607 in the healthy window before it, while blocks received went to zero and the node kept processing miner traffic normally throughout. Now: a peer that announces a body and does not deliver it within two minutes is dropped, and says so in the log unconditionally. Two minutes is far beyond any legitimate header-to-body gap and well inside BTF_RECV_TIMEOUT_SECS. (cherry picked from commit ca1e99288e03ac7beb2b97cf615a3255b4635d95)
2026-08-19pool: refuse jobs when no peer has reported a height for 20 minutesbitflash-maintainer
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)
2026-08-04public commitbitflash-coin