Files
ObsidianDragon/src/wallet/lite_wallet_server_lifecycle_readiness.cpp
DanS a677c09984 refactor(lite): drop 4 unused OOP wrapper classes over free functions
Each of these classes wrapped an existing free function with a one-line
delegating method and was never instantiated anywhere (verified: no references
outside their own translation unit, not even within their own .cpp beyond the
definition) — the redundant "wrapper layer" pattern CLAUDE.md warns against:

- LiteWalletLifecycleUiExecutionAdapter      -> executeLiteWalletLifecycleUiRequest
- LiteWalletServerSelectionUiExecutionAdapter -> executeLiteWalletServerSelectionUi
- LiteWalletServerLifecycleReadinessPlanner   -> evaluateLiteWalletServerLifecycleReadiness
- LiteBackendActivationReadinessAdapter       -> evaluateLiteBackendActivationReadiness

The live free functions (the actual entry points used by the UI/runtime) are
unchanged. Both targets build, test suite passes, source-hygiene clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 12:40:26 -05:00

386 lines
18 KiB
C++

#include "wallet/lite_wallet_server_lifecycle_readiness.h"
#include <cctype>
#include <utility>
namespace dragonx::wallet {
namespace {
std::string trimCopy(const std::string& value)
{
auto begin = value.begin();
while (begin != value.end() && std::isspace(static_cast<unsigned char>(*begin))) ++begin;
auto end = value.end();
while (end != begin && std::isspace(static_cast<unsigned char>(*(end - 1)))) --end;
return std::string(begin, end);
}
void addIssue(LiteWalletServerLifecycleReadinessResult& result,
LiteWalletServerLifecycleReadinessIssue issue,
std::string message)
{
result.issues.push_back(LiteWalletServerLifecycleReadinessIssueInfo{issue, std::move(message)});
}
LiteWalletServerLifecycleReadinessResult stoppedResult(
LiteWalletServerLifecycleReadinessResult result,
LiteWalletServerLifecycleReadinessStatus status,
LiteWalletServerLifecycleReadinessIssue issue,
std::string message)
{
result.status = status;
addIssue(result, issue, std::move(message));
result.error = result.issues.back().message;
result.lifecycleStatus = WalletBackendStatus{WalletBackendState::Unavailable, result.error, {}, {}, 0.0};
return result;
}
LiteRedactedPrivateData redactedPrivateField(LitePrivateDataKind kind, const std::string& value)
{
return LiteRedactedPrivateData{kind, !trimCopy(value).empty(), redactLitePrivateDataValue(value)};
}
bool privateDataIsRedacted(const std::vector<LiteRedactedPrivateData>& privateData)
{
for (const auto& item : privateData) {
if (!item.present && item.redactedValue != "<empty>") return false;
if (item.present && item.redactedValue != "<redacted>") return false;
}
return true;
}
LiteWalletSelectedServerDisplayReport displayReportForSelection(
const LiteServerSelectionResult& selection)
{
LiteWalletSelectedServerDisplayReport report;
if (!selection.ok) {
report.status = LiteWalletSelectedServerDisplayStatus::Missing;
report.message = selection.error.empty() ? "no usable lite server is selected" : selection.error;
return report;
}
report.ok = true;
report.status = selection.customServer
? LiteWalletSelectedServerDisplayStatus::CustomServer
: LiteWalletSelectedServerDisplayStatus::SelectedServer;
report.label = selection.server.label;
report.url = selection.server.url;
report.serverIndex = selection.serverIndex;
report.customServer = selection.customServer;
report.message = selection.customServer
? "custom lite server selected for display"
: "configured lite server selected for display";
return report;
}
LiteWalletLifecyclePlan lifecyclePlanForRequest(
LiteWalletLifecycleOperation operation,
const LiteServerSelectionResult& selection)
{
LiteWalletLifecyclePlan plan;
plan.operation = operation;
plan.bridgeExecutionAllowed = false;
if (!selection.ok) {
plan.error = selection.error.empty() ? "no usable lite server is selected" : selection.error;
return plan;
}
plan.ok = true;
plan.server = selection.server;
plan.serverIndex = selection.serverIndex;
plan.customServer = selection.customServer;
return plan;
}
LiteWalletLifecycleUiRequestPlan requestPlanForInput(
const LiteWalletServerLifecycleReadinessInput& input,
const LiteServerSelectionResult& selection)
{
LiteWalletLifecycleUiRequestPlan plan;
plan.operation = input.operation;
plan.lifecyclePlan = lifecyclePlanForRequest(input.operation, selection);
if (!plan.lifecyclePlan.ok) {
plan.error = plan.lifecyclePlan.error;
return plan;
}
switch (input.operation) {
case LiteWalletLifecycleOperation::CreateNew:
plan.privateData.push_back(redactedPrivateField(
LitePrivateDataKind::Passphrase,
input.createRequest.passphrase));
plan.requestSummary = "operation=create;server=<selected>;passphrase=" +
std::string(input.createRequest.passphrase.empty() ? "<empty>" : "<redacted>");
break;
case LiteWalletLifecycleOperation::OpenExisting:
if (trimCopy(input.openRequest.walletPath).empty()) {
plan.error = "lite wallet open requires a wallet path selected by the UI";
return plan;
}
plan.privateData.push_back(redactedPrivateField(
LitePrivateDataKind::WalletPath,
input.openRequest.walletPath));
plan.privateData.push_back(redactedPrivateField(
LitePrivateDataKind::Passphrase,
input.openRequest.passphrase));
plan.requestSummary = "operation=open;server=<selected>;wallet_path=<redacted>;passphrase=" +
std::string(input.openRequest.passphrase.empty() ? "<empty>" : "<redacted>");
break;
case LiteWalletLifecycleOperation::RestoreFromSeed:
if (trimCopy(input.restoreRequest.seedPhrase).empty()) {
plan.error = "lite wallet restore requires redacted seed material metadata";
return plan;
}
plan.privateData.push_back(redactedPrivateField(
LitePrivateDataKind::SeedPhrase,
input.restoreRequest.seedPhrase));
plan.privateData.push_back(redactedPrivateField(
LitePrivateDataKind::WalletPath,
input.restoreRequest.walletPath));
plan.privateData.push_back(redactedPrivateField(
LitePrivateDataKind::Passphrase,
input.restoreRequest.passphrase));
plan.requestSummary = "operation=restore;server=<selected>;seed=<redacted>;wallet_path=" +
std::string(input.restoreRequest.walletPath.empty() ? "<empty>" : "<redacted>") +
";passphrase=" +
std::string(input.restoreRequest.passphrase.empty() ? "<empty>" : "<redacted>");
break;
}
plan.privateInputsRedacted = privateDataIsRedacted(plan.privateData);
plan.lifecyclePlan.privateData = plan.privateData;
plan.ok = plan.privateInputsRedacted;
if (!plan.ok) plan.error = "lite wallet lifecycle private inputs are not redacted";
return plan;
}
LiteWalletServerSelectionPersistencePlan persistencePlanForInput(
const LiteWalletServerLifecycleReadinessInput& input,
const LiteServerSelectionResult& selection)
{
LiteWalletServerSelectionPersistencePlan plan;
plan.settingsLoaded = input.persistence.settingsLoaded;
plan.persistedSelectionIntentAccepted = input.persistence.havePersistedSelectionIntent;
plan.wouldPersistSelectedServer = input.persistence.persistSelectedServer;
plan.persistenceOwnerAccepted = input.persistence.persistenceOwnerReady;
plan.selectionMode = input.settings.selectionMode;
if (selection.ok) {
plan.selectedServerUrl = selection.server.url;
plan.selectedServerIndex = selection.serverIndex;
plan.selectedServerCustom = selection.customServer;
}
plan.settingsWritten = false;
plan.ok = true;
return plan;
}
WalletBackendStatus readyLifecycleStatus(const LiteWalletSelectedServerDisplayReport& display)
{
const std::string serverLabel = display.label.empty() ? display.url : display.label;
return WalletBackendStatus{
WalletBackendState::Disconnected,
"lite lifecycle UI readiness accepted for " + serverLabel + "; wallet lifecycle execution is still disabled",
{},
{},
0.0
};
}
} // namespace
const char* liteWalletServerLifecycleReadinessStatusName(
LiteWalletServerLifecycleReadinessStatus status)
{
switch (status) {
case LiteWalletServerLifecycleReadinessStatus::ReadyForFutureLifecycle: return "ReadyForFutureLifecycle";
case LiteWalletServerLifecycleReadinessStatus::WaitingForLiteBuild: return "WaitingForLiteBuild";
case LiteWalletServerLifecycleReadinessStatus::WaitingForBackendCapability: return "WaitingForBackendCapability";
case LiteWalletServerLifecycleReadinessStatus::WaitingForServerSelection: return "WaitingForServerSelection";
case LiteWalletServerLifecycleReadinessStatus::WaitingForPersistenceIntent: return "WaitingForPersistenceIntent";
case LiteWalletServerLifecycleReadinessStatus::WaitingForDisplayStatus: return "WaitingForDisplayStatus";
case LiteWalletServerLifecycleReadinessStatus::WaitingForLifecycleUi: return "WaitingForLifecycleUi";
case LiteWalletServerLifecycleReadinessStatus::WaitingForPrivateDataRedaction: return "WaitingForPrivateDataRedaction";
case LiteWalletServerLifecycleReadinessStatus::WaitingForSyncPlannerFeed: return "WaitingForSyncPlannerFeed";
case LiteWalletServerLifecycleReadinessStatus::RuntimeExecutionDisabled: return "RuntimeExecutionDisabled";
}
return "Unknown";
}
const char* liteWalletServerLifecycleReadinessIssueName(
LiteWalletServerLifecycleReadinessIssue issue)
{
switch (issue) {
case LiteWalletServerLifecycleReadinessIssue::FullNodeBuild: return "FullNodeBuild";
case LiteWalletServerLifecycleReadinessIssue::LiteBackendCapabilityMissing: return "LiteBackendCapabilityMissing";
case LiteWalletServerLifecycleReadinessIssue::PersistedSettingsNotLoaded: return "PersistedSettingsNotLoaded";
case LiteWalletServerLifecycleReadinessIssue::PersistedServerSelectionIntentMissing: return "PersistedServerSelectionIntentMissing";
case LiteWalletServerLifecycleReadinessIssue::ServerSelectionMissing: return "ServerSelectionMissing";
case LiteWalletServerLifecycleReadinessIssue::ServerPersistenceOwnerMissing: return "ServerPersistenceOwnerMissing";
case LiteWalletServerLifecycleReadinessIssue::SelectedServerDisplayMissing: return "SelectedServerDisplayMissing";
case LiteWalletServerLifecycleReadinessIssue::LifecycleUiOwnerMissing: return "LifecycleUiOwnerMissing";
case LiteWalletServerLifecycleReadinessIssue::LifecycleOperationUnconfirmed: return "LifecycleOperationUnconfirmed";
case LiteWalletServerLifecycleReadinessIssue::OpenWalletPathMissing: return "OpenWalletPathMissing";
case LiteWalletServerLifecycleReadinessIssue::RestoreSeedMissing: return "RestoreSeedMissing";
case LiteWalletServerLifecycleReadinessIssue::PrivateDataRedactionMissing: return "PrivateDataRedactionMissing";
case LiteWalletServerLifecycleReadinessIssue::SyncPlannerFeedMissing: return "SyncPlannerFeedMissing";
case LiteWalletServerLifecycleReadinessIssue::RealLifecycleExecutionRequested: return "RealLifecycleExecutionRequested";
}
return "Unknown";
}
const char* liteWalletSelectedServerDisplayStatusName(
LiteWalletSelectedServerDisplayStatus status)
{
switch (status) {
case LiteWalletSelectedServerDisplayStatus::Hidden: return "Hidden";
case LiteWalletSelectedServerDisplayStatus::SelectedServer: return "SelectedServer";
case LiteWalletSelectedServerDisplayStatus::CustomServer: return "CustomServer";
case LiteWalletSelectedServerDisplayStatus::Missing: return "Missing";
}
return "Unknown";
}
LiteWalletServerLifecycleReadinessResult evaluateLiteWalletServerLifecycleReadiness(
const LiteWalletServerLifecycleReadinessInput& input,
LiteWalletServerLifecycleReadinessOptions options)
{
LiteWalletServerLifecycleReadinessResult result;
result.capabilities = input.capabilities;
result.persistencePlan = persistencePlanForInput(input, {});
if (options.requireLiteBuild && !isLiteBuild(input.capabilities)) {
return stoppedResult(
std::move(result),
LiteWalletServerLifecycleReadinessStatus::WaitingForLiteBuild,
LiteWalletServerLifecycleReadinessIssue::FullNodeBuild,
"lite server lifecycle readiness requires a lite build");
}
result.liteBuildAccepted = true;
if (options.requireLiteBackendCapability && !supportsLiteBackend(input.capabilities)) {
return stoppedResult(
std::move(result),
LiteWalletServerLifecycleReadinessStatus::WaitingForBackendCapability,
LiteWalletServerLifecycleReadinessIssue::LiteBackendCapabilityMissing,
"lite backend capability is required before lifecycle UI readiness can feed sync planners");
}
result.backendCapabilityAccepted = true;
if (options.requirePersistedSettingsLoaded && !input.persistence.settingsLoaded) {
return stoppedResult(
std::move(result),
LiteWalletServerLifecycleReadinessStatus::WaitingForPersistenceIntent,
LiteWalletServerLifecycleReadinessIssue::PersistedSettingsNotLoaded,
"lite server settings must be loaded before lifecycle UI readiness is evaluated");
}
if (options.requirePersistedSelectionIntent && !input.persistence.havePersistedSelectionIntent) {
return stoppedResult(
std::move(result),
LiteWalletServerLifecycleReadinessStatus::WaitingForPersistenceIntent,
LiteWalletServerLifecycleReadinessIssue::PersistedServerSelectionIntentMissing,
"lite server selection persistence intent is missing");
}
result.selectedServer = selectLiteServer(input.settings);
result.persistencePlan = persistencePlanForInput(input, result.selectedServer);
if (!result.selectedServer.ok) {
return stoppedResult(
std::move(result),
LiteWalletServerLifecycleReadinessStatus::WaitingForServerSelection,
LiteWalletServerLifecycleReadinessIssue::ServerSelectionMissing,
result.selectedServer.error.empty()
? "no usable lite server is selected"
: result.selectedServer.error);
}
result.serverSelectionAccepted = true;
if (input.persistence.persistSelectedServer && !input.persistence.persistenceOwnerReady) {
return stoppedResult(
std::move(result),
LiteWalletServerLifecycleReadinessStatus::WaitingForPersistenceIntent,
LiteWalletServerLifecycleReadinessIssue::ServerPersistenceOwnerMissing,
"lite server selection persistence owner is not ready");
}
result.persistenceIntentAccepted = true;
result.persistencePlan.ok = true;
result.selectedServerDisplay = displayReportForSelection(result.selectedServer);
if (options.requireSelectedServerDisplay && !input.ui.selectedServerDisplayReady) {
return stoppedResult(
std::move(result),
LiteWalletServerLifecycleReadinessStatus::WaitingForDisplayStatus,
LiteWalletServerLifecycleReadinessIssue::SelectedServerDisplayMissing,
"selected lite server display status is not ready");
}
result.selectedServerDisplayAccepted = true;
if (options.requireLifecycleUiOwner && !input.ui.lifecycleUiOwnerReady) {
return stoppedResult(
std::move(result),
LiteWalletServerLifecycleReadinessStatus::WaitingForLifecycleUi,
LiteWalletServerLifecycleReadinessIssue::LifecycleUiOwnerMissing,
"lite wallet lifecycle UI owner is not ready");
}
result.lifecycleUiOwnerAccepted = true;
if (input.ui.realLifecycleExecutionRequested) {
return stoppedResult(
std::move(result),
LiteWalletServerLifecycleReadinessStatus::RuntimeExecutionDisabled,
LiteWalletServerLifecycleReadinessIssue::RealLifecycleExecutionRequested,
"real lite wallet lifecycle execution is disabled in this scaffold");
}
if (options.requireOperationConfirmation && !input.ui.operationConfirmed) {
return stoppedResult(
std::move(result),
LiteWalletServerLifecycleReadinessStatus::WaitingForLifecycleUi,
LiteWalletServerLifecycleReadinessIssue::LifecycleOperationUnconfirmed,
"lite wallet lifecycle operation requires explicit UI confirmation");
}
result.requestPlan = requestPlanForInput(input, result.selectedServer);
if (!result.requestPlan.ok) {
const auto issue = input.operation == LiteWalletLifecycleOperation::OpenExisting
? LiteWalletServerLifecycleReadinessIssue::OpenWalletPathMissing
: LiteWalletServerLifecycleReadinessIssue::RestoreSeedMissing;
return stoppedResult(
std::move(result),
LiteWalletServerLifecycleReadinessStatus::WaitingForLifecycleUi,
issue,
result.requestPlan.error.empty()
? "lite wallet lifecycle UI request is incomplete"
: result.requestPlan.error);
}
result.requestAccepted = true;
if (options.requirePrivateDataRedaction && !input.ui.privateDataRedactionReady) {
return stoppedResult(
std::move(result),
LiteWalletServerLifecycleReadinessStatus::WaitingForPrivateDataRedaction,
LiteWalletServerLifecycleReadinessIssue::PrivateDataRedactionMissing,
"lite wallet lifecycle private-data redaction owner is not ready");
}
result.privateDataRedactionAccepted = true;
if (options.requireSyncPlannerFeed && !input.ui.syncPlannerFeedReady) {
return stoppedResult(
std::move(result),
LiteWalletServerLifecycleReadinessStatus::WaitingForSyncPlannerFeed,
LiteWalletServerLifecycleReadinessIssue::SyncPlannerFeedMissing,
"lite lifecycle readiness feed for sync planners is not ready");
}
result.syncPlannerFeedAccepted = true;
result.ok = true;
result.status = LiteWalletServerLifecycleReadinessStatus::ReadyForFutureLifecycle;
result.futureLifecycleCouldBeEnabled = true;
result.lifecycleReportCouldFeedSyncPlanners = true;
result.lifecycleStatus = readyLifecycleStatus(result.selectedServerDisplay);
return result;
}
} // namespace dragonx::wallet