You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: recover stalled wallet syncs via idle watchdog and progress reorder
Two targeted changes to _refresh() in the base Wallet<T> class, which
affects all wallet types routing through the shared refresh flow
(BTC, LTC, Firo, Monero, ETH, Cardano, Solana, etc. — but NOT
MimbleWimbleCoin, ETH tokens, or SOL tokens, which override refresh()).
1. Idle watchdog on the refresh body. A Timer.periodic checks every
30s whether _fireRefreshPercentChange has been called within the
last 10 minutes. If not, the refresh is assumed wedged, the
watchdog throws TimeoutException, and the existing catch/finally
releases refreshMutex. Previously the mutex stayed locked forever
when any sub-operation hung, making every subsequent periodic
sync bail out at the isLocked check until the app was force-closed.
Idle-based (rather than wall-clock) means slow-but-active syncs
don't get killed: a full Spark anonymity set download on a poor
connection keeps firing per-sector progress and keeps the watchdog
fed. Only truly silent periods trip it. Per-call hang detection
is still the responsibility of the underlying adapters (e.g.
electrum's connectionTimeout / aliveTimerDuration at 60s each);
this watchdog only catches what slips through those layers.
Note: the watchdog does not cancel in-flight work; it only unblocks
the outer future so the mutex can be released. The orphaned work
eventually resolves or errors on its own.
2. Fire progress updates *after* the awaited work completes rather
than before. The 0.65 and 0.70 calls previously fired immediately
after kicking off updateUTXOs/updateTransactions, making the bar
appear stuck at those values while the real work was still running.
The ~65% stall in Firo syncs was the most visible manifestation of
this; other wallets had the same cosmetic issue.
The refresh body is also extracted to a private _doRefreshWork(viewOnly)
helper to keep _refresh() focused on mutex/event/watchdog/error handling.
No behavioural change from the extraction.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0 commit comments