feat(wallet): migrate-to-seed, Phase 1 — isolated seed-wallet creation
First, fund-safe step of "migrate a legacy wallet to a seed wallet": mint a brand-new BIP39 mnemonic wallet in an ISOLATED throwaway datadir so the user can later sweep funds into it. No funds move and the real wallet.dat / main daemon are never touched — the isolated node runs concurrently on its own port. - EmbeddedDaemon: one-shot isolated-datadir override (setNextStartOverride) consumed on the next start(); a skip-default-port-check for an isolated instance beside the main daemon; and a tcpPortInUse() probe. The datadir's basename must be the assetchain name (DRAGONX) and the daemon reads <datadir>/DRAGONX.conf itself, so no -conf is passed (both learned from live testing against the hd-transparent-keys daemon). - SeedWalletCreator (src/daemon): picks a free port, writes a throwaway conf, starts an isolated dragonxd with -usemnemonic=1 -connect=0, waits for RPC, calls z_exportmnemonic + z_getnewaddress (the sweep target), stops it, and keeps/scrubs the temp datadir. Off-thread; the seed is wiped after use. - App: beginCreateSeedWallet (background) -> pumpSeedMigration (main-thread handoff) -> renderSeedMigrationDialog (Intro -> Working -> Show seed -> Error), reusing the seed_display grid + clipboard auto-clear. - Settings: "Migrate to seed…" button (full-node gated) + persisted pending migration state (dest address + temp datadir) for Phase 2 to adopt. Validated end-to-end against the hd-transparent-keys daemon: the isolated node comes up in ~4s and returns a 24-word mnemonic + a shielded z-address. Requires that daemon (the bundled Jun-28 build lacks z_exportmnemonic). The migration modal uses English literals for now (as renderBackupDialog does); the whole flow gets translated once Phase 2 finalizes it. Phase 2 (sweep + adopt) is next. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -448,9 +448,10 @@ bool EmbeddedDaemon::start(const std::string& binary_path)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if something is already listening on the RPC port
|
||||
// Check if something is already listening on the RPC port. An isolated instance (migrate-to-
|
||||
// seed) runs on its own non-default port alongside the main daemon, so it skips this bail.
|
||||
int rpc_port = std::atoi(DRAGONX_DEFAULT_RPC_PORT);
|
||||
if (isPortInUse(rpc_port)) {
|
||||
if (!skip_port_check_ && isPortInUse(rpc_port)) {
|
||||
std::string owner = getPortOwnerInfo(rpc_port);
|
||||
VERBOSE_LOGF("[INFO] Port %d is already in use by %s — external daemon detected, will connect to it.\\n", rpc_port, owner.c_str());
|
||||
external_daemon_detected_ = true;
|
||||
@@ -498,7 +499,20 @@ bool EmbeddedDaemon::start(const std::string& binary_path)
|
||||
DEBUG_LOGF("[INFO] Adding -rescan flag for blockchain rescan\n");
|
||||
args.push_back("-rescan");
|
||||
}
|
||||
|
||||
|
||||
// One-shot isolated-datadir override (migrate-to-seed flow): run this start against a
|
||||
// throwaway datadir, plus any extra args (e.g. -connect=0). Consumed here so later starts
|
||||
// revert to the normal datadir. The datadir's basename MUST be the assetchain name (DRAGONX)
|
||||
// or the daemon mis-resolves its conf/port; it reads <datadir>/DRAGONX.conf automatically, so
|
||||
// no -conf is passed (an explicit -conf confuses the Komodo/Hush path resolution).
|
||||
if (!override_datadir_.empty()) {
|
||||
DEBUG_LOGF("[INFO] Isolated start override: -datadir=%s\n", override_datadir_.c_str());
|
||||
args.push_back("-datadir=" + override_datadir_);
|
||||
}
|
||||
for (const auto& a : override_extra_args_) args.push_back(a);
|
||||
override_datadir_.clear();
|
||||
override_extra_args_.clear();
|
||||
|
||||
if (!startProcess(daemon_path, args)) {
|
||||
DEBUG_LOGF("[ERROR] Failed to start dragonxd process: %s\\n", last_error_.c_str());
|
||||
setState(State::Error, "Failed to start dragonxd process");
|
||||
@@ -1220,5 +1234,10 @@ bool EmbeddedDaemon::isRpcPortInUse()
|
||||
return isPortInUse(port);
|
||||
}
|
||||
|
||||
bool EmbeddedDaemon::tcpPortInUse(int port)
|
||||
{
|
||||
return isPortInUse(port);
|
||||
}
|
||||
|
||||
} // namespace daemon
|
||||
} // namespace dragonx
|
||||
|
||||
Reference in New Issue
Block a user