fix(wallet-switch): cluster B — daemon-switch robustness
From the wallet-switching audit: - Revert on failure (HIGH): switchToWallet persisted active_wallet_file before confirming the new daemon started, so a missing/corrupt wallet wedged across restarts. The switch worker now confirms dragonxd survives a grace period; on failure it flags the main thread (processWalletSwitchRevert), which restores the previous wallet file + re-scopes the vault + re-arms reconnect (settings writes stay on the main thread). - Cross-guard concurrent lifecycle ops (HIGH): switchToWallet now refuses during a rescan/repair (state_.sync.rescanning) or seed migration; rescan/repair now refuse while daemon_restarting_; and restartDaemonAfterEncryption now sets daemon_restarting_ (which also fixes a latent reconnect-to-a-stopped-daemon race during the encryption restart). So the switch/adopt/restart/rescan/repair/ encryption ops are mutually exclusive. - Quit during switch (MED): beginShutdown now joins the "Switch wallet" task (like the adopt task) so quitting can't orphan a freshly-started dragonxd. - Reset the daemon crash count on switch (LOW) so a prior crash-wedge can't block reconnecting to the new wallet. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -241,16 +241,19 @@ void App::restartDaemonAfterEncryption(const char* taskName, bool announceRestar
|
||||
// the daemon is restarting.
|
||||
connection_status_ = TR("restarting_after_encryption");
|
||||
}
|
||||
// Gate the main-loop reconnect while the daemon is down (so tryConnect can't hit the stopped
|
||||
// node or start a duplicate) and block a concurrent wallet switch/rescan, which check this flag.
|
||||
daemon_restarting_ = true;
|
||||
// Give daemon a moment to shut down, then restart
|
||||
// (do this off the main thread to avoid stalling the UI)
|
||||
async_tasks_.submit(taskName, [this](const util::AsyncTaskManager::Token& token) {
|
||||
for (int i = 0; i < 20 && !token.cancelled() && !shutting_down_; ++i)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
if (token.cancelled() || shutting_down_) return;
|
||||
if (token.cancelled() || shutting_down_) { daemon_restarting_ = false; return; }
|
||||
stopEmbeddedDaemon();
|
||||
if (token.cancelled() || shutting_down_) return;
|
||||
if (token.cancelled() || shutting_down_) { daemon_restarting_ = false; return; }
|
||||
startEmbeddedDaemon();
|
||||
// tryConnect will be called by the update loop
|
||||
daemon_restarting_ = false; // re-arm reconnect (tryConnect runs from the update loop)
|
||||
});
|
||||
} else {
|
||||
ui::Notifications::instance().warning(
|
||||
|
||||
Reference in New Issue
Block a user