fix(node): don't get stranded when the daemon can't start on startup

Two failure modes left the wallet stuck on a silent "connecting / Starting
dragonxd…" spinner with no path forward:

1. Stale external-daemon latch. EmbeddedDaemon::start() sets
   external_daemon_detected_ whenever the RPC port was busy at a prior attempt
   and never re-checks it, so tryConnect's no-config branch trusted that latch
   and waited forever for a config the phantom would never write — even after a
   stale/half-dead process freed the port. Now the port is re-evaluated LIVE
   (EmbeddedDaemon::isRpcPortInUse()) each attempt: if it's genuinely busy we
   keep waiting (and, after a bounded ~20s with no config, warn that whatever
   owns the port isn't a usable DragonX node and how to fix it); if it's free we
   fall through and start our own daemon.

2. Silent start failure. When startEmbeddedDaemon() failed (binary not found,
   Sapling params missing, spawn failure) the status stayed on "Starting
   dragonxd…" with the real reason only in a VERBOSE log. Now the reason
   (daemon_controller_->lastError()) is surfaced once as a sticky error
   notification, with a short "Couldn't start dragonxd" status.

Both counters reset on a successful connect so the messages re-arm for the next
disconnect. Lite is unaffected (tryConnect returns early for lite builds).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-09 20:55:41 -05:00
parent 4a65dce947
commit 41b380449e
3 changed files with 54 additions and 15 deletions

View File

@@ -4,6 +4,7 @@
#include "i18n.h"
#include "platform.h"
#include "../config/version.h" // DRAGONX_DEFAULT_RPC_PORT
#include <fstream>
#include <cstdio>
@@ -780,6 +781,11 @@ void I18n::loadBuiltinEnglish()
strings_["sb_connecting_generic"] = "Connecting to daemon...";
strings_["sb_connecting_err"] = "Connecting to daemon — %s";
strings_["sb_daemon_crashed"] = "Daemon crashed %d times";
strings_["sb_daemon_start_failed"] = "Couldn't start dragonxd";
strings_["daemon_port_busy_warn"] =
"Port " DRAGONX_DEFAULT_RPC_PORT " is in use but isn't responding as a DragonX node. "
"Close the program using it (or free the port), then restart — the wallet can't start "
"its own node while the port is taken.";
strings_["sb_extracting_sapling"] = "Extracting Sapling parameters...";
strings_["sb_sapling_failed"] = "Failed to extract Sapling parameters.";
strings_["sb_sapling_not_found"] = "Sapling parameters not found.";