Repository navigation
Conversation
…the refresh lock on error
Their rescanBlockchain runs the whole blocking rescan in an isolate, so awaiting it held the refresh lock and delayed startSyncing until the rescan finished. The Monero call returns once the async rescan starts, so only Monero keeps the reordered reset.
This was referenced Nov 3, 2026
sneurlax
added a commit
to sneurlax/stack_wallet
that referenced
this pull request
Nov 10, 2026
refresh() in the Monero, Wownero and Salvium wallets acquires refreshMutex and released it only on the success path. Anything thrown after the acquire (the Tor and clearnet mismatch check, or wallet being null because open() failed) left the lock held for the rest of the session. Later refreshes returned early on the isLocked check and recover()'s refreshMutex.protect waited forever, which is the stuck rescan dialog in stack-wallet cypherstack#103. The body now runs under refreshMutex.protect, which releases in a finally and rethrows, the same way the other wallets and recover() in these files already use it. That makes the release-at-100% workaround in onSyncingUpdate redundant, so it is gone from all three wallets. In the Monero wallet highestPercentCached is reset on both sides of rescanBlockchain: before it, so a throw leaves the guard at zero, and after it, so a progress reading from before the rescan cannot be ordered after the reset. Wownero and Salvium call rescanBlockchain unawaited, so the second reset would change nothing there and they keep their order. This is the wallet-layer part of the closed PR cypherstack#1490, taken on its own.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Tester report: on desktop, after starting a Monero rescan the exit button is not clickable.
Cause
_attemptRescanshowed a non-dismissableRescanningDialogover the Network dialog untilrecover(isRescan: true)returned, andrecoverfirst waits onrefreshMutex.refresh()took that lock without try/finally, so a throw (including the Tor/clearnet mismatch guard) or a hang instartSyncingheld it indefinitely and the dialog never went away. The tester's log showsrefresh()stuck right after Windows Defender quarantinedmonero_libwallet2_api_c.dll(Taiga #103).Changes
rescanning_dialog.dart: arescansInBackgroundflag. When set, the dialog says the rescan continues in the background, has a Close button, and back pops it.wallet_network_settings_view.dart: sets the flag for Cryptonote and Epic wallets, tracks whether the dialog is still open, and only pops it if it is.lib_monero_wallet.dart,lib_wownero_wallet.dart,lib_salvium_wallet.dart:refresh()releases the lock in a finally.highestPercentCachedis reset afterrescanBlockchainreturns. Monero's call returns as soon as the async rescan starts, and resetting before it let a stale ~99.8% reading land after the reset and freeze the progress bar. Wownero and Salvium run the whole rescan in a blocking isolate call, so they keep the old order (awaiting would hold the lock for the whole rescan); the same race can still happen there.Tested
flutter test: 687 passed, 8 skipped, 0 failed.refresh(): the old build traps the user and the new one lets both dialogs close.