fix(fullnode): smooth witness-cache progress from the new daemon's done/total
Use the new daemon's "Reading blocks for witness rebuild: <done> / <total>" as an
exact fraction: the reported total is the denominator directly, so the bar sweeps
0..1 smoothly instead of being held near the top by the peak-anchored remaining
heuristic (kept only as a fallback for older daemons that log bare "<n> remaining").
Also snap to 100% on the parallel rebuild's completion line ("rebuilt <n> note
witness cache(s) … using <t> thread(s)"), which otherwise logs no progress, so the
bar visibly finishes before the rescan-complete signal clears it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
53
src/app.cpp
53
src/app.cpp
@@ -749,6 +749,8 @@ void App::update()
|
|||||||
bool foundWitness = false;
|
bool foundWitness = false;
|
||||||
float witnessPct = -1.0f; // -1 = no fraction parsed this batch
|
float witnessPct = -1.0f; // -1 = no fraction parsed this batch
|
||||||
int witnessRemaining = -1;
|
int witnessRemaining = -1;
|
||||||
|
int witnessReadTotal = -1; // new daemon: the <total> in "<done> / <total>"
|
||||||
|
bool witnessRebuilt = false; // new daemon's completion line seen this batch
|
||||||
std::vector<std::string> witnessTxids; // distinct-tx keys seen this batch
|
std::vector<std::string> witnessTxids; // distinct-tx keys seen this batch
|
||||||
int witnessTotalTxs = -1; // max N seen this batch
|
int witnessTotalTxs = -1; // max N seen this batch
|
||||||
|
|
||||||
@@ -845,9 +847,8 @@ void App::update()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Newer multi-threaded daemon: "Reading blocks for witness rebuild: <done> / <total>".
|
// Newer multi-threaded daemon: "Reading blocks for witness rebuild: <done> / <total>".
|
||||||
// This replaced the per-block "Building Witnesses" line. It's a clean done/total
|
// This replaced the per-block "Building Witnesses" line and is an exact done/total
|
||||||
// count, so map it onto the same phase-2 "remaining" signal (remaining = total -
|
// count, so capture BOTH (total drives the denominator directly — no peak anchoring).
|
||||||
// done) and the existing cache-walk logic yields progress = done/total.
|
|
||||||
auto rdIdx = line.find("Reading blocks for witness rebuild:");
|
auto rdIdx = line.find("Reading blocks for witness rebuild:");
|
||||||
if (rdIdx != std::string::npos) {
|
if (rdIdx != std::string::npos) {
|
||||||
foundWitness = true;
|
foundWitness = true;
|
||||||
@@ -865,14 +866,26 @@ void App::update()
|
|||||||
try {
|
try {
|
||||||
long done = std::stol(line.substr(dStart, dEnd - dStart));
|
long done = std::stol(line.substr(dStart, dEnd - dStart));
|
||||||
long total = std::stol(line.substr(tStart, tEnd - tStart));
|
long total = std::stol(line.substr(tStart, tEnd - tStart));
|
||||||
if (total > 0 && done >= 0 && done <= total)
|
if (total > 0 && done >= 0 && done <= total) {
|
||||||
witnessRemaining = static_cast<int>(total - done);
|
witnessRemaining = static_cast<int>(total - done);
|
||||||
|
witnessReadTotal = static_cast<int>(total);
|
||||||
|
}
|
||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastStatus = line;
|
lastStatus = line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New daemon's witness-rebuild completion line:
|
||||||
|
// "... rebuilt <n> note witness cache(s) to height <h> in <ms>ms using <t> thread(s)".
|
||||||
|
// The parallel rebuild logs no progress, so on completion snap the bar to 100%.
|
||||||
|
if (line.find("note witness cache") != std::string::npos &&
|
||||||
|
line.find("thread(s)") != std::string::npos) {
|
||||||
|
foundWitness = true;
|
||||||
|
witnessRebuilt = true;
|
||||||
|
lastStatus = line;
|
||||||
|
}
|
||||||
|
|
||||||
// Primary signal: "Setting Initial Sapling Witness for tx <hash>, <i> of <N>".
|
// Primary signal: "Setting Initial Sapling Witness for tx <hash>, <i> of <N>".
|
||||||
// <i> is the tx's slot in an unordered map (bounces — useless as progress), so
|
// <i> is the tx's slot in an unordered map (bounces — useless as progress), so
|
||||||
// we key on <hash> (one per tx) and count distinct txs against <N>. Extract the
|
// we key on <hash> (one per tx) and count distinct txs against <N>. Extract the
|
||||||
@@ -934,7 +947,7 @@ void App::update()
|
|||||||
// never drops back to the initial pass. Otherwise an interleaved initial
|
// never drops back to the initial pass. Otherwise an interleaved initial
|
||||||
// line would flip the phase back and reset the bar every batch (thrash).
|
// line would flip the phase back and reset the bar every batch (thrash).
|
||||||
int phase = state_.sync.witness_phase;
|
int phase = state_.sync.witness_phase;
|
||||||
if (witnessRemaining >= 0) phase = 2;
|
if (witnessRemaining >= 0 || witnessRebuilt) phase = 2;
|
||||||
else if (!witnessTxids.empty() && phase < 2) phase = 1;
|
else if (!witnessTxids.empty() && phase < 2) phase = 1;
|
||||||
|
|
||||||
// Entering a higher sub-phase → reset its progress + accumulators so the
|
// Entering a higher sub-phase → reset its progress + accumulators so the
|
||||||
@@ -950,17 +963,27 @@ void App::update()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (phase == 2) {
|
if (phase == 2) {
|
||||||
// Cache walk: derive a stable % from how far "remaining" has fallen
|
|
||||||
// from its peak (the first/largest value = the full walk span). The
|
|
||||||
// daemon re-invokes the walk per block, so "remaining" sawtooths; the
|
|
||||||
// peak anchor + monotonic clamp keep the bar advancing, never resetting.
|
|
||||||
state_.sync.witness_remaining = witnessRemaining;
|
state_.sync.witness_remaining = witnessRemaining;
|
||||||
if (witnessRemaining > witness_rebuild_total_blocks_)
|
float p = -1.0f;
|
||||||
witness_rebuild_total_blocks_ = witnessRemaining;
|
if (witnessRebuilt) {
|
||||||
if (witness_rebuild_total_blocks_ > 0) {
|
// Parallel rebuild finished (it logs no progress) — snap to 100%.
|
||||||
float p = 1.0f - static_cast<float>(witnessRemaining) /
|
p = 1.0f;
|
||||||
static_cast<float>(witness_rebuild_total_blocks_);
|
state_.sync.witness_remaining = 0;
|
||||||
if (p < 0.0f) p = 0.0f;
|
} else if (witnessReadTotal > 0) {
|
||||||
|
// New daemon: exact done/total. Use the reported total as the
|
||||||
|
// denominator directly (no peak anchoring) for a smooth 0..1 sweep.
|
||||||
|
int done = witnessReadTotal - (witnessRemaining >= 0 ? witnessRemaining : 0);
|
||||||
|
p = static_cast<float>(done) / static_cast<float>(witnessReadTotal);
|
||||||
|
} else if (witnessRemaining >= 0) {
|
||||||
|
// Older daemon: bare "<n> remaining" with no total — anchor the % to
|
||||||
|
// the largest remaining seen (its first/largest value ≈ the full span).
|
||||||
|
if (witnessRemaining > witness_rebuild_total_blocks_)
|
||||||
|
witness_rebuild_total_blocks_ = witnessRemaining;
|
||||||
|
if (witness_rebuild_total_blocks_ > 0)
|
||||||
|
p = 1.0f - static_cast<float>(witnessRemaining) /
|
||||||
|
static_cast<float>(witness_rebuild_total_blocks_);
|
||||||
|
}
|
||||||
|
if (p >= 0.0f) {
|
||||||
if (p > 1.0f) p = 1.0f;
|
if (p > 1.0f) p = 1.0f;
|
||||||
if (p > state_.sync.witness_progress) // monotonic within the phase
|
if (p > state_.sync.witness_progress) // monotonic within the phase
|
||||||
state_.sync.witness_progress = p;
|
state_.sync.witness_progress = p;
|
||||||
|
|||||||
Reference in New Issue
Block a user