feat(wallet): one-click "switch to the built-in node and compact"

When connected to an external/standalone dragonxd (the wallet adopted a running
node, so daemon_controller_ is null), Compact couldn't run. Add a path that does
it in one click: compactViaEmbeddedSwitch() gates the connect loop, drops the RPC
connection, and on the worker gracefully stops the external node (RPC "stop" with
our credentials, via stopDaemonForWalletSwitch) and waits for the port; back on
the main thread it switches the wallet to its built-in node and starts it with a
one-shot compact_on_embedded_start_ flag that arms -salvagewallet, so the fresh
node rewrites wallet.dat (and rescans). On stop failure nothing is changed and
the external node stays up.

The Compact button is now enabled whenever the build can run the embedded node;
its confirmation branches — direct compact when the wallet already runs the
built-in node (canCompactWallet), else a clear message (confirm_compact_switch_
msg) that it will stop the external node, switch to the built-in one, and that
this changes which node binary runs. New strings confirm_compact_switch_msg /
compact_switching / compact_switch_stop_failed.

Mirrors restartDaemon's disconnect + background stop pattern; controller creation
stays on the main thread. Can't be runtime-verified here (no live daemon). Build
+ tests + hygiene green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-10-27 11:41:49 -05:00
co-authored by Claude Opus 4.8
parent a5cd211e89
commit 16d60a72f2
5 changed files with 73 additions and 5 deletions
+8
View File
@@ -6222,6 +6222,14 @@ bool App::startEmbeddedDaemon()
});
}
// Compact-via-switch: the user chose to compact after switching from an external node to this built-in
// one. Arm -salvagewallet on this start so the fresh node rewrites wallet.dat into a compact file
// (-salvagewallet implies a rescan). One-shot: it fires only for the start that follows the switch.
if (compact_on_embedded_start_.exchange(false)) {
daemon_controller_->setSalvageOnNextStart(true);
user_initiated_rescan_ = true; // the implied rescan is wallet-triggered → its completion should toast
}
// Only a process we actually launched starts a new story: a start that finds a node already running (and
// launches nothing) must not wipe what the tracker knows about that node from its debug.log.
const bool launched = daemon_controller_->start(