Files
ObsidianDragon/src/daemon/daemon_controller.cpp
DanS 37c8287a12 feat(fullnode): add "Repair Wallet" (-zapwallettxes=2) to Settings
When a note's stored record is corrupt or its tx isn't in the canonical chain,
z_sendmany fails to build a valid sapling spend proof even after a full -rescan,
because a plain rescan replays witnesses but keeps the existing tx/note records.
The zcashd repair for this is -zapwallettxes=2, which deletes all wallet tx/note
records and rebuilds them from the chain (keys/addresses preserved).

Adds a RepairWallet lifecycle operation that mirrors the existing -rescan plumbing
(one-shot zapOnNextStart flag on the embedded daemon; -zapwallettxes=2 implies and
supersedes -rescan), an App::repairWallet() that reuses the rescan status UI (so the
status bar + warmup-end completion detection apply), and a confirmed "Repair Wallet"
button + dialog in Settings → node maintenance (embedded daemon only).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 07:42:10 -05:00

129 lines
3.0 KiB
C++

#include "daemon_controller.h"
#include "../config/settings.h"
#include <algorithm>
namespace dragonx {
namespace daemon {
DaemonController::DaemonController()
: daemon_(std::make_unique<EmbeddedDaemon>())
{
}
DaemonController::~DaemonController() = default;
void DaemonController::setStateCallback(StateCallback callback)
{
daemon_->setStateCallback(std::move(callback));
}
void DaemonController::syncSettings(const config::Settings* settings)
{
if (!settings) return;
daemon_->setDebugCategories(settings->getDebugCategories());
daemon_->setMaxConnections(settings->getMaxConnections());
}
bool DaemonController::start(const config::Settings* settings)
{
syncSettings(settings);
return daemon_->start();
}
void DaemonController::stop(int waitMs)
{
daemon_->stop(waitMs);
}
bool DaemonController::isRunning() const
{
return daemon_->isRunning();
}
bool DaemonController::externalDaemonDetected() const
{
return daemon_->externalDaemonDetected();
}
DaemonController::State DaemonController::state() const
{
return daemon_->getState();
}
const std::string& DaemonController::lastError() const
{
return daemon_->getLastError();
}
int DaemonController::crashCount() const
{
return daemon_->getCrashCount();
}
int DaemonController::lastBlockHeight() const
{
return daemon_ ? daemon_->getLastBlockHeight() : 0;
}
double DaemonController::memoryUsageMB() const
{
return daemon_ ? daemon_->getMemoryUsageMB() : 0.0;
}
std::vector<std::string> DaemonController::recentLines(std::size_t count) const
{
return daemon_ ? daemon_->getRecentLines(count) : std::vector<std::string>{};
}
std::string DaemonController::outputSince(std::size_t& offset) const
{
return daemon_ ? daemon_->getOutputSince(offset) : std::string{};
}
void DaemonController::resetCrashCount()
{
daemon_->resetCrashCount();
}
void DaemonController::setRescanOnNextStart(bool enabled)
{
daemon_->setRescanOnNextStart(enabled);
}
bool DaemonController::rescanOnNextStart() const
{
return daemon_->rescanOnNextStart();
}
void DaemonController::setZapOnNextStart(bool enabled)
{
daemon_->setZapOnNextStart(enabled);
}
bool DaemonController::zapOnNextStart() const
{
return daemon_->zapOnNextStart();
}
void DaemonController::prepareLifecycleOperation(const LifecycleDecision& decision,
const config::Settings* settings)
{
if (settings) syncSettings(settings);
if (decision.resetCrashCount) resetCrashCount();
if (decision.setRescanOnNextStart) setRescanOnNextStart(true);
if (decision.setZapOnNextStart) setZapOnNextStart(true);
}
DaemonController::ShutdownDecision DaemonController::shutdownDecision(
bool keepDaemonRunning, bool stopExternalDaemon) const
{
return evaluateShutdownPolicy(static_cast<bool>(daemon_),
daemon_ && daemon_->externalDaemonDetected(),
keepDaemonRunning,
stopExternalDaemon);
}
} // namespace daemon
} // namespace dragonx