Every operation that stops the node (restart, rescan, repair, delete chain data, reinstall, bootstrap, wallet switch/adopt/restore/rebuild, wizard restart, encrypt, decrypt) now: - refuses up front while the node is rebuilding witnesses or has not answered for 30s, with a "try again when it's done" warning, and sends no stop; - goes ahead only once the node's PROCESS has exited, not its RPC port. A stop that doesn't finish within 120s cancels the operation (warning; a cancelled rescan/repair disarms its flags); nothing is started over the old node, chain data isn't deleted, wallet.dat isn't swapped. Specifics: - stopDaemonForWalletSwitch() no longer reports "stopped" when the app is quitting (adopt could swap wallet.dat under a live node). - Decrypt waited a fixed 3s after "stop" before renaming wallet.dat; it now waits for the process to exit, and scrubs the key export if not. - Bootstrap waits for the process before cleanChainData and stops the node through the stop routine instead of the shared RPC client. - StopScope::Connected lets switch/reinstall/decrypt stop an adopted or external node through the same never-kill routine. - A bounded stop that can't reach the node (a foreign node refusing our credentials) gives up after 5s instead of 120s. - macOS: isDaemonProcessRunning() checks processes (libproc), not the RPC port. - rpcBusyWhileAlive() also reads the busy gate: since the gate, the first timeout usually lands on another lane and the 30s clock never started (also weakened the quit prompt for a silent rebuild). - Notifications render during the first-run wizard. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
83 lines
3.0 KiB
C++
83 lines
3.0 KiB
C++
#pragma once
|
|
|
|
#include "wallet_security_workflow.h"
|
|
|
|
#include <cstdint>
|
|
#include <functional>
|
|
#include <string>
|
|
|
|
namespace dragonx {
|
|
namespace services {
|
|
|
|
class WalletSecurityWorkflowExecutor {
|
|
public:
|
|
using WalletFilePlan = WalletSecurityWorkflow::WalletFilePlan;
|
|
|
|
struct Outcome {
|
|
bool ok = false;
|
|
std::string error;
|
|
bool passphraseRejected = false;
|
|
};
|
|
|
|
struct ExportOutcome : Outcome {
|
|
WalletFilePlan filePlan;
|
|
};
|
|
|
|
class RpcGateway {
|
|
public:
|
|
virtual ~RpcGateway() = default;
|
|
virtual bool unlockWallet(const std::string& passphrase, int timeoutSeconds, std::string& error) = 0;
|
|
virtual bool exportWallet(const std::string& fileName, long timeoutSeconds, std::string& error) = 0;
|
|
virtual bool requestDaemonStop(std::string& error) = 0;
|
|
virtual bool probeDaemon(std::string& error) = 0;
|
|
};
|
|
|
|
class ImportGateway {
|
|
public:
|
|
virtual ~ImportGateway() = default;
|
|
virtual bool importWallet(const std::string& exportPath, long timeoutSeconds, std::string& error) = 0;
|
|
};
|
|
|
|
class FileGateway {
|
|
public:
|
|
virtual ~FileGateway() = default;
|
|
virtual std::string dataDir() = 0;
|
|
virtual bool backupEncryptedWallet(const WalletFilePlan& filePlan, std::string& error) = 0;
|
|
};
|
|
|
|
class DaemonGateway {
|
|
public:
|
|
virtual ~DaemonGateway() = default;
|
|
virtual bool isUsingEmbeddedDaemon() const = 0;
|
|
virtual bool stopEmbeddedDaemon() = 0; // true: the node exited (false: still running; never killed)
|
|
virtual bool startEmbeddedDaemon() = 0;
|
|
virtual bool cancelled() const = 0;
|
|
virtual bool shuttingDown() const = 0;
|
|
virtual void sleepForMs(int milliseconds) = 0;
|
|
};
|
|
|
|
using VaultCleanupGateway = std::function<void()>;
|
|
|
|
static Outcome unlockWallet(const std::string& passphrase,
|
|
RpcGateway& rpc,
|
|
int timeoutSeconds = 600);
|
|
static ExportOutcome exportWallet(RpcGateway& rpc,
|
|
FileGateway& files,
|
|
std::uint64_t timestampSeconds,
|
|
long timeoutSeconds = 300L);
|
|
static Outcome stopDaemon(RpcGateway& rpc);
|
|
static Outcome backupEncryptedWallet(FileGateway& files,
|
|
const WalletFilePlan& filePlan);
|
|
static Outcome restartDaemonAndWait(DaemonGateway& daemon,
|
|
RpcGateway& rpc,
|
|
int preRestartDelayMs = 2000,
|
|
int embeddedRestartSettleMs = 1000,
|
|
int maxProbeSeconds = 60);
|
|
static Outcome importWallet(ImportGateway& importer,
|
|
const std::string& exportPath,
|
|
long timeoutSeconds = 1200L);
|
|
static void cleanupVaultAndPin(const VaultCleanupGateway& cleanup);
|
|
};
|
|
|
|
} // namespace services
|
|
} // namespace dragonx
|