fix(fullnode): make witness/rescan progress work on the real daemon

Verified by running the app against a live node and watching a real rescan. Three
issues that only surfaced at runtime:

- Wrong RPC name: this daemon (hush/komodo) exposes the runtime rescan as
  "rescan <height>", not bitcoin's "rescanblockchain". runtimeRescan() and
  RPCClient::rescanBlockchain() used the bitcoin name and failed with "Method not
  found" on every node. Corrected to "rescan".

- Witness/rescan progress never surfaced during a rescan: the daemon-output parser
  that drives it was gated behind rpcConnected, but a heavy rescan holds cs_main so
  getinfo times out and the RPC reads disconnected — silencing the parser exactly
  when it's needed. The parser reads the daemon's stdout pipe (no RPC), so it now
  runs whenever the daemon process is alive. It also now parses INLINE on the main
  thread instead of via fast_worker_, so it can't be starved when the worker is
  blocked on a getrescaninfo call (which waits on cs_main during a witness rebuild).

- Witness rebuild has TWO sub-phases with different scales — the initial-witness
  pass ("Setting Initial Sapling Witness for tx <hash>, <i> of <N>") and the cache
  walk ("Building Witnesses for block <h> <frac> complete, <n> remaining"). Tracking
  them with one monotonic value pinned the bar at the initial pass's ~100% through
  the whole cache walk. They're now tracked as distinct phases (witness_phase) with
  their own monotonic progress and labels ("Setting witnesses" vs "Rebuilding
  witnesses"), so neither resets/bounces and the long phase shows real movement.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-22 13:00:36 -05:00
parent e2bc3623b6
commit 25ee1496b4
6 changed files with 134 additions and 49 deletions

View File

@@ -640,6 +640,13 @@ private:
// block, each walking from its own start height to the tip), so we derive a stable, monotonic
// overall percentage from how far "remaining" has fallen below this peak. Reset per phase.
int witness_rebuild_total_blocks_ = 0;
// The daemon's primary witness signal is "Setting Initial Sapling Witness for tx <hash>, <i>
// of <N>", logged once per wallet tx as its initial witness is set. The <i> is the tx's slot in
// an UNORDERED map, so it bounces wildly (was the cause of the resetting progress). The honest
// monotonic metric is how many DISTINCT txs have been witnessed (the set only grows; it also
// dedups the daemon's occasional double-prints) over the reported total N.
std::unordered_set<std::string> witness_seen_txids_;
int witness_total_txs_ = 0;
bool opid_poll_in_progress_ = false;
// Consecutive Core-refresh cycles where BOTH core RPCs failed → likely a dead
// connection. After kCoreFailuresBeforeDisconnect, tear down and reconnect.