|
27 | 27 | // re-requested, so an overlapping getheaders locator batch or a re-announce |
28 | 28 | // cannot double-download. |
29 | 29 | // |
30 | | -// NOT IN THIS SLICE (deferred per integrator 2026-06-18): in-flight timeout / |
31 | | -// eviction (a block requested but never delivered by a stalling peer). That is |
32 | | -// robustness hardening worth doing only once blocks are actually flowing; this |
33 | | -// slice builds the happy-path window first. |
| 30 | +// IN-FLIGHT TIMEOUT / EVICTION (expire()): a block getdata'd but never delivered |
| 31 | +// by a stalling peer is timed out, requeued oldest-first, and re-issued; an |
| 32 | +// evicted block the peer later delivers anyway is flagged via false_evict_count |
| 33 | +// and dropped from the queue so it is not re-downloaded. NodeP2P drives this on |
| 34 | +// a steady-clock timer (see p2p_node.hpp BLOCK_DL_TIMEOUT_SEC). |
34 | 35 | // |
35 | 36 | // p2pool-merged-v36 SURFACE: NONE -- pure SPV/IBD wire-sync plumbing; no PoW |
36 | 37 | // hash, share format, coinbase commitment, AuxPoW, or PPLNS math. PER-COIN |
@@ -109,7 +110,18 @@ class BlockDownloadWindow { |
109 | 110 | // On a healthy peer with a generous timeout NOTHING expires, so this |
110 | 111 | // stays 0 -- a non-zero value means the BLOCK_DL_TIMEOUT_SEC fired on a |
111 | 112 | // request the peer was merely slow to answer, not genuinely stalled. |
112 | | - if (m_evicted.erase(h)) ++m_false_evict_count; |
| 113 | + if (m_evicted.erase(h)) { |
| 114 | + ++m_false_evict_count; |
| 115 | + // expire() requeued this hash to the FRONT when it timed out; the |
| 116 | + // (merely slow) peer has now delivered it, so drop it from the pending |
| 117 | + // queue -- otherwise the next drain would re-getdata a block we already |
| 118 | + // hold. Linear scan is fine: eviction is rare (a healthy sync keeps |
| 119 | + // false_evict at 0). If it was already re-issued it is in m_in_flight, |
| 120 | + // not m_queue, and the scan simply finds nothing. |
| 121 | + for (auto qit = m_queue.begin(); qit != m_queue.end(); ++qit) { |
| 122 | + if (*qit == h) { m_queue.erase(qit); break; } |
| 123 | + } |
| 124 | + } |
113 | 125 | auto it = m_in_flight.find(h); |
114 | 126 | if (it == m_in_flight.end()) { |
115 | 127 | // Unsolicited or already handled: still remember it so a later |
|
0 commit comments