From 401fbbd081a90cd190d2bd3cea93a8a3d6c50f01 Mon Sep 17 00:00:00 2001 From: Eric Chennells Date: Mon, 14 Sep 2026 16:29:13 +0000 Subject: [PATCH 1/2] Rewind the download window with the position on regression. A regression below the position rewound the position but not the window (requested_/advanced_), and a regression above the position but within the window was ignored. Either way set_unassociated() then deferred new work until the gap at the replaced height was filled, which only a request can do, so a tip reorg stopped block download until restart while headers continued. Guard on the window and rewind both with the position. --- src/chasers/chaser_check.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/chasers/chaser_check.cpp b/src/chasers/chaser_check.cpp index eedd6e1d..3daf235f 100644 --- a/src/chasers/chaser_check.cpp +++ b/src/chasers/chaser_check.cpp @@ -344,12 +344,15 @@ void chaser_check::do_regressed(height_t branch_point) NOEXCEPT { BC_ASSERT(stranded()); - // Inconsequential regression, work isn't there yet. - if (branch_point >= position()) + // Inconsequential regression, neither position nor window is there yet. + if (branch_point >= std::max(position(), requested_)) return; - // Update position, purge outstanding work, and wait on track completion. - set_position(branch_point); + // Update position and window, purge outstanding work, and wait on track + // completion. The window must follow the position or the gap it awaits + // is never requested. + set_position(std::min(branch_point, position())); + requested_ = advanced_ = position(); stop_tracking(); maps_.clear(); notify(error::success, chase::purge, branch_point); From 999f24296f34fda29d84e28fb2283d09557e43e5 Mon Sep 17 00:00:00 2001 From: echennells Date: Sat, 19 Sep 2026 02:11:29 +0000 Subject: [PATCH 2/2] Bump validation on regression as at start. --- include/bitcoin/node/impl/chasers/chaser_organize.ipp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/bitcoin/node/impl/chasers/chaser_organize.ipp b/include/bitcoin/node/impl/chasers/chaser_organize.ipp index 6175b99e..3b861c7b 100644 --- a/include/bitcoin/node/impl/chasers/chaser_organize.ipp +++ b/include/bitcoin/node/impl/chasers/chaser_organize.ipp @@ -315,13 +315,15 @@ void CLASS::do_organize(typename Block::cptr block, bool prioritized, // Checking currency before notify also avoids excessive work backlog. if (is_block() || current) { - if (!bumped_) + if (!bumped_ || regress) { // If at start the fork point is top of both chains, and next candidate // is already downloaded, then new header will arrive and download will // be skipped, resulting in stall until restart at which time the start // event will advance through all downloaded candidates and progress on - // arrivals. This bumps validation once for current strong headers. + // arrivals. This bumps validation once for current strong headers, and + // again on regression, as the candidate above the branch point may + // already be downloaded when reorganizing back to a stored branch. notify(error::success, chase::bump, add1(branch_point)); bumped_ = true; }