fix(fullnode): make witness sub-phase upgrade-only to stop progress thrash

The initial-witness pass ("Setting Initial Sapling Witness") and the cache walk
("Building Witnesses for block … remaining") interleave during a rescan — the daemon
does both per block. The phase selector picked phase 1 whenever a batch had only
initial-pass lines, so once the cache walk started an interleaved initial line would
flip the phase back to 1 and reset the bar to 0 every batch. Make the phase
upgrade-only (once the cache walk is seen it never drops back), so the reset happens
at most twice (→1, →2) and the cache-walk percentage advances monotonically.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-22 13:09:29 -05:00
parent 25ee1496b4
commit a5bd2dadd7

View File

@@ -898,15 +898,19 @@ void App::update()
rescan_confirmed_active_ = true;
state_.sync.building_witnesses = true;
// Which sub-phase is this batch? A "<n> remaining" token means the
// cache walk (phase 2); otherwise per-tx "Setting Initial" lines are the
// initial pass (phase 1). When both appear in one batch the walk wins —
// it always runs after the initial pass within a BuildWitnessCache call.
const int phase = (witnessRemaining >= 0) ? 2
: (!witnessTxids.empty() ? 1 : state_.sync.witness_phase);
// Which sub-phase is this batch? A "<n> remaining" token means the cache
// walk (phase 2); otherwise per-tx "Setting Initial" lines are the initial
// pass (phase 1). The two INTERLEAVE during a rescan (the daemon does both
// per block), so the phase is UPGRADE-ONLY: once the cache walk is seen it
// never drops back to the initial pass. Otherwise an interleaved initial
// line would flip the phase back and reset the bar every batch (thrash).
int phase = state_.sync.witness_phase;
if (witnessRemaining >= 0) phase = 2;
else if (!witnessTxids.empty() && phase < 2) phase = 1;
// Entering a new sub-phase → reset its progress + accumulators so the bar
// restarts from 0 instead of inheriting the previous phase's value.
// Entering a higher sub-phase → reset its progress + accumulators so the
// bar restarts from 0 (the two phases have different scales). Upgrade-only,
// so this happens at most twice (→1, →2), never repeatedly.
if (phase != state_.sync.witness_phase) {
state_.sync.witness_phase = phase;
state_.sync.witness_progress = 0.0f;