From cd6edfc2c234db71d9b68f96702ad08a56cc3127 Mon Sep 17 00:00:00 2001 From: bitflash-maintainer Date: Wed, 2 Sep 2026 16:10:24 +0000 Subject: net: only use the 15s block retry spacing at the tip nRequestTime lives in mapAlreadyAskedFor, which is global to the inv, so the spacing AskFor applies is not per-peer pacing: it is what strings the getdatas for one block across its announcers. Shortening it to 15s was right at the tip and wrong everywhere else, and the eight-entry cap that made the failover table safe for catch-up does not cover this at all -- it is a different mechanism. At two minutes a second announcer's queued request almost always fired after the block had arrived, so AlreadyHave dropped it. At fifteen seconds, with a peer working through a 500-deep queue and block N legitimately minutes away, the second announcer is asked at +15s, the third at +30s, and the bulk download arrives once per announcer -- up to eight times over, with nothing bounding it. So the fast spacing is now conditional on tracking the tip, measured off the age of our own best block. Not off a peer-reported height: nStartingHeight is optional in the version message and every node released so far sends the short form, so it is -1 for essentially every peer, and where it does get filled in later it comes from the height of a block that peer served us, which during catch-up tracks our own height and would answer "at the tip" for the entire download. Block timestamps are the one clock a peer cannot move, being bounded above by CheckBlock and below by AcceptBlock's median-time rule. Thirty block intervals is the threshold: far longer than any stall worth failing over from, far shorter than catching up. Failover at the tip does not rest on this in any case -- mapBlockFetch re-issues a stalled getdata to the next peer on its own 15s timer, and that is what actually answers #33. --- src/main.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index 9ab1f44..be89416 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -101,6 +101,29 @@ static const int BLOCK_FETCH_TRACK_MAX = 8; // forever; a re-announcement recreates it. static const int BLOCK_FETCH_GIVEUP_SECS = 10 * 60; +// How stale our own best block may be before we stop calling this the tip. +// Blocks target two minutes, so this is thirty intervals: far longer than any +// stall worth failing over from -- the one in #33 ran sixteen minutes -- and +// far shorter than catching up, which starts hours or days back. +static const int BLOCK_FETCH_TIP_AGE_SECS = 60 * 60; + +// Whether this node is tracking the tip rather than still catching up. +// +// Measured off the age of our own best block, not off any height a peer told +// us. nStartingHeight is optional in the version message and every node +// released so far sends the short form, so it is -1 for essentially every +// peer; and where it is filled in later it is filled in from the height of a +// block that peer served us, which during catch-up tracks our own height and +// would report "at the tip" for the whole download. Block timestamps are the +// one clock here that peers cannot move: CheckBlock refuses anything more than +// two hours ahead and AcceptBlock refuses anything at or before the previous +// median, so the only way to make this read "at the tip" falsely is to mine, +// and all that buys is the 15s spacing this code had unconditionally anyway. +bool IsBlockFetchNearTip() +{ + return pindexBest && (int64)pindexBest->nTime > GetTime() - BLOCK_FETCH_TIP_AGE_SECS; +} + // Drop one entry so a hash announced by addrNew can be tracked. // // Refusing the insertion instead was a remote off-switch for the whole -- cgit v1.2.3