From 3a597482da752961e4221a045aec26e9a6b565f7 Mon Sep 17 00:00:00 2001 From: DanS Date: Sat, 13 Jun 2026 08:16:25 -0500 Subject: [PATCH] fix(rescan): detect this daemon's completion ("rescan ms"), unstick 99% MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A rescan ran to completion but the status bar stayed at "Rescanning 99%" forever. The daemon-output parser only treated "Done rescanning"/"Rescan complete" as finished, but this daemon prints neither — it logs the rescan benchmark timing line exactly when the scan ends: 2026-... rescan 16760577ms then resumes normal block processing. So the parser saw the last "Still rescanning ... Progress=0.99" and never the finish, leaving it stuck. - Recognise the " rescan ms" bench line as completion (it ends in "ms", which the "Still rescanning"/"Rescanning..." progress lines never do). - When the parser reads "Still rescanning" straight from the daemon log, mark rescan_confirmed_active_ — hard proof the scan is running that doesn't depend on catching a getrescaninfo warmup error, so the RPC completion path can also fire after the daemon leaves warmup. Clear it on finish. The parser reads the daemon's debug.log via the controller (not RPC), so this completes the rescan UI even if the RPC connection hasn't re-established yet. Co-Authored-By: Claude Opus 4.8 --- src/app.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/app.cpp b/src/app.cpp index c2b4db2..f074bc6 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -752,6 +752,21 @@ void App::update() line.find("Rescan complete") != std::string::npos) { finished = true; } + + // This daemon prints no "Done rescanning" line; instead it logs the rescan + // benchmark timing exactly when the scan finishes, e.g.: + // "... rescan 16760577ms" + // Match the lowercase " rescan " bench category ending in "ms" (the + // progress lines are "Still rescanning"/"Rescanning...", which never end in ms). + if (line.find(" rescan ") != std::string::npos) { + std::string t = line; + while (!t.empty() && (t.back() == '\r' || t.back() == '\n' || t.back() == ' ')) + t.pop_back(); + if (t.size() >= 3 && t.compare(t.size() - 2, 2, "ms") == 0 && + std::isdigit(static_cast(t[t.size() - 3]))) { + finished = true; + } + } } // Return callback to apply results on main thread @@ -761,10 +776,15 @@ void App::update() ui::Notifications::instance().success("Blockchain rescan complete"); } state_.sync.rescanning = false; + rescan_confirmed_active_ = false; state_.sync.rescan_progress = 1.0f; state_.sync.rescan_status.clear(); } else if (foundRescan) { state_.sync.rescanning = true; + // Reading "Still rescanning" straight from the daemon log is hard proof the + // rescan is genuinely running — confirm it so the getrescaninfo poll's + // completion check can fire even if it never caught a warmup error. + rescan_confirmed_active_ = true; if (rescanPct > 0.0f) { state_.sync.rescan_progress = rescanPct / 100.0f; }