fix(daemon): never restart, delete or swap under a node that hasn't exited

Every operation that stops the node (restart, rescan, repair, delete
chain data, reinstall, bootstrap, wallet switch/adopt/restore/rebuild,
wizard restart, encrypt, decrypt) now:

- refuses up front while the node is rebuilding witnesses or has not
  answered for 30s, with a "try again when it's done" warning, and sends
  no stop;
- goes ahead only once the node's PROCESS has exited, not its RPC port.
  A stop that doesn't finish within 120s cancels the operation (warning;
  a cancelled rescan/repair disarms its flags); nothing is started over
  the old node, chain data isn't deleted, wallet.dat isn't swapped.

Specifics:
- stopDaemonForWalletSwitch() no longer reports "stopped" when the app
  is quitting (adopt could swap wallet.dat under a live node).
- Decrypt waited a fixed 3s after "stop" before renaming wallet.dat; it
  now waits for the process to exit, and scrubs the key export if not.
- Bootstrap waits for the process before cleanChainData and stops the
  node through the stop routine instead of the shared RPC client.
- StopScope::Connected lets switch/reinstall/decrypt stop an adopted or
  external node through the same never-kill routine.
- A bounded stop that can't reach the node (a foreign node refusing our
  credentials) gives up after 5s instead of 120s.
- macOS: isDaemonProcessRunning() checks processes (libproc), not the
  RPC port.
- rpcBusyWhileAlive() also reads the busy gate: since the gate, the
  first timeout usually lands on another lane and the 30s clock never
  started (also weakened the quit prompt for a silent rebuild).
- Notifications render during the first-run wizard.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-02 11:22:39 -05:00
co-authored by Claude Opus 5.5
parent 1215ded1a0
commit e20b70d73f
22 changed files with 320 additions and 122 deletions
+2
View File
@@ -616,6 +616,8 @@ void I18n::loadBuiltinEnglish()
strings_["stopconfirm_busy_body"] = "It has been too busy to answer the wallet for %s, probably because of a long operation such as a witness rebuild. Stopping it now can make its next start redo that work.\n\nRecommended: close the wallet and leave the node running. It finishes on its own.";
strings_["stopconfirm_stop_wait"] = "Stop node & wait";
strings_["appx_daemon_reinstall_node_busy"] = "The node is still running, so the daemon was not reinstalled. Try again once it has stopped.";
strings_["appx_node_busy_try_later"] = "The node is busy finishing a long task (such as rebuilding note witnesses). Try again when it is done; stopping it now could make it start that work over.";
strings_["appx_node_not_stopped"] = "The node didn't stop in time, so nothing was changed. Try again in a few minutes.";
strings_["reduce_motion"] = "Reduce Motion";
strings_["tt_reduce_motion"] = "Disable animated transitions and balance lerp for accessibility";
strings_["ago"] = "ago";