On Windows, stop() with no live process of its own looked up the first
"dragonxd.exe" by name and TerminateProcess'd it after the grace period:
an old node still shutting down (how an in-progress shutdown was killed),
a node on another datadir, or the user's main node. It was reached on a
lock-gated close, for an external node, after the tracked process had
exited, and from ~EmbeddedDaemon's stop(3000).
- Windows stop(): drop the by-name branch; with no tracked process it
logs and returns. findProcessByName is detection only.
- ~EmbeddedDaemon no longer calls stop(); it stops watching and releases
its handles. stop() returns whether the process exited on its own.
- SeedWalletCreator never sent its isolated node an RPC stop, so on
Windows that node was always force-killed holding the wallet.dat it
had just created, and the stack object's destructor could then kill
the main node by name. It now stops the node over the node's own RPC
on every path. A node that still had to be force-killed fails the
creation (seed wiped; nothing has been swept into it yet), so an
uncleanly closed wallet is never adopted.
- Reinstall waited only for the RPC port, which closes long before the
process exits (locked exe on Windows, held datadir lock everywhere).
It now waits for the process to exit and otherwise aborts without
touching the binaries or starting a second node.
- Linux isDaemonProcessRunning also matches /proc/<pid>/exe, so a node
whose main thread is already renamed "hush-shutoff" (still holding the
datadir lock) counts as running.
Tests: a Windows real-process test (a fake dragonxd.exe on an isolated
datadir survives stop() and the destructor), a POSIX test that the
destructor leaves the process running, and the pure identity rule.
scripts/test-windows.sh passes the stub path to the Windows suite.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>