From 7ee20bb497ebc47e332fa8646b7b4f8ad65f799b Mon Sep 17 00:00:00 2001 From: DanS Date: Tue, 7 Jul 2026 14:17:00 -0500 Subject: [PATCH] fix(wallet): connect the isolated seed node over plaintext RPC + add smoke MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The seed-wallet creator forced TLS on its RPC client, but the DRAGONX RPC is plaintext HTTP on localhost (-tls=only applies to P2P, not the RPC; the main GUI's conf has no rpctls key and connects over http too). Forcing https made every connect fail with "SSL connect error", so the isolated create never completed. Connect without TLS, matching the main daemon path. Also add an env-gated (DRAGONX_SEED_CREATE_SMOKE=1) headless smoke in main() that runs SeedWalletCreator::create() before GUI init and prints ok/word-count/address (never the seed words) — used to validate the full C++ creator path without the GUI. Harmless in normal runs. Validated end-to-end against the hd-transparent-keys (v1.0.3-dc45e7d9) daemon: ok=1, words=24, a shielded z-address returned, temp datadir cleaned up. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/daemon/seed_wallet_creator.cpp | 7 ++++--- src/main.cpp | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/daemon/seed_wallet_creator.cpp b/src/daemon/seed_wallet_creator.cpp index 53dd0f8..2a4fa61 100644 --- a/src/daemon/seed_wallet_creator.cpp +++ b/src/daemon/seed_wallet_creator.cpp @@ -64,8 +64,9 @@ SeedWalletResult SeedWalletCreator::create(bool keepDatadir, const std::string user = randomToken(16); const std::string pass = randomToken(32); - // 3. Minimal conf for the isolated node (own creds/port; -tls=only comes from the chain args, - // so the RPC client below connects with TLS just like the main daemon does). + // 3. Minimal conf for the isolated node (own creds/port). The DRAGONX RPC is plaintext HTTP on + // localhost — `-tls=only` applies to P2P, not the RPC — so the client below connects without + // TLS, exactly as the main GUI does (its conf has no rpctls key either). const std::string conf = "rpcuser=" + user + "\n" "rpcpassword=" + pass + "\n" "rpcport=" + std::to_string(port) + "\n" @@ -94,7 +95,7 @@ SeedWalletResult SeedWalletCreator::create(bool keepDatadir, rpc::RPCClient cli; bool ready = false; for (int i = 0; i < 90 && !ready; ++i) { - if (cli.connect("127.0.0.1", std::to_string(port), user, pass, /*useTls=*/true)) { + if (cli.connect("127.0.0.1", std::to_string(port), user, pass, /*useTls=*/false)) { try { cli.call("getinfo"); ready = true; } // succeeds only once past warmup (-28) catch (...) { cli.disconnect(); } } diff --git a/src/main.cpp b/src/main.cpp index e0872a9..5f70a87 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,7 +25,9 @@ #include "ui/effects/theme_effects.h" #include "util/texture_loader.h" #include "util/platform.h" +#include "daemon/seed_wallet_creator.h" #include "resources/embedded_resources.h" +#include // Backend-specific headers #ifdef DRAGONX_USE_DX11 @@ -652,6 +654,22 @@ int main(int argc, char* argv[]) DEBUG_LOGF("Built with Dear ImGui %s\n", IMGUI_VERSION); fflush(stdout); + // Env-gated headless smoke for the isolated seed-wallet creator (migrate-to-seed Phase 1). + // Exercises SeedWalletCreator::create() end-to-end without the GUI, then exits. Secret-safe: + // it never prints the seed words — only ok/word-count/address/error. Run with an isolated HOME. + if (const char* smk = std::getenv("DRAGONX_SEED_CREATE_SMOKE"); smk && std::string(smk) == "1") { + sodium_init(); + printf("[seed-create-smoke] starting isolated create...\n"); fflush(stdout); + auto r = dragonx::daemon::SeedWalletCreator::create(/*keepDatadir=*/false, + [](const std::string& m) { printf("[seed-create-smoke] %s\n", m.c_str()); fflush(stdout); }); + int words = 0; bool inWord = false; + for (char c : r.seedPhrase) { bool sp = (c == ' '); if (!sp && !inWord) { inWord = true; ++words; } else if (sp) inWord = false; } + printf("[seed-create-smoke] ok=%d words=%d addr=%s err=%s\n", + r.ok ? 1 : 0, words, r.destAddress.c_str(), r.error.c_str()); + if (!r.seedPhrase.empty()) sodium_memzero(&r.seedPhrase[0], r.seedPhrase.size()); + return r.ok ? 0 : 1; + } + // Check for existing instance if (!g_single_instance.tryLock()) { fprintf(stderr, "Another instance of ObsidianDragon is already running.\n");