Files
ObsidianDragon/src/wallet/lite_wallet_sync_app_refresh_integration.cpp
DanS 5a27a13628 feat(lite): lite wallet foundation (inherited working-tree state)
Preserve the previously-uncommitted lite wallet implementation and related dev WIP
under version control:
- src/wallet/ lite services: client bridge, bridge runtime, connection, lifecycle,
  sync, gateway, result parsers, state mapper, artifact contract/resolver, refresh
  services, UI adapters, wallet_backend/capabilities. (Includes two small M1 fixes:
  lifecycle walletReady now parses the response; default chain name -> "main".)
- src/chat/ chat protocol; tests/fixtures/ (lite + hushchat); tools/hushchat_fixture_check.cpp;
  scripts/build-lite-backend-artifact.sh.
- Pre-existing modified app_network/security/wizard, network_refresh_service, sidebar,
  mining_tab, bootstrap dialog, and version headers captured as-is.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 21:15:28 -05:00

344 lines
16 KiB
C++

#include "wallet/lite_wallet_sync_app_refresh_integration.h"
#include <utility>
namespace dragonx::wallet {
namespace {
void addIssue(LiteWalletSyncAppRefreshIntegrationResult& result,
LiteWalletSyncAppRefreshIntegrationIssue issue,
std::string message)
{
result.issues.push_back(LiteWalletSyncAppRefreshIntegrationIssueInfo{issue, std::move(message)});
}
std::string statusMessageOrDefault(const WalletBackendStatus& status,
const std::string& fallback)
{
return status.message.empty() ? fallback : status.message;
}
bool refreshReportIsUnsafe(const LiteWalletAppRefreshOrchestrationResult& refresh)
{
return !refresh.dryRunOnly ||
!refresh.noNetwork ||
refresh.stateMutationRequested ||
refresh.stateMutationAllowed ||
refresh.stateMutated ||
refresh.walletStateWritten;
}
bool syncStartPlanIsValid(const LiteSyncPlan& plan)
{
return plan.ok && plan.operation == LiteSyncOperation::StartSync && plan.command == "sync";
}
bool syncStatusPlanIsValid(const LiteSyncPlan& plan)
{
return plan.ok && plan.operation == LiteSyncOperation::PollSyncStatus && plan.command == "syncstatus";
}
LiteWalletSyncAppRefreshIntegrationResult stoppedResult(
LiteWalletSyncAppRefreshIntegrationResult result,
LiteWalletSyncAppRefreshIntegrationStatus status,
LiteWalletSyncAppRefreshIntegrationIssue issue,
std::string message)
{
result.status = status;
addIssue(result, issue, std::move(message));
result.error = result.issues.back().message;
return result;
}
LiteWalletSyncAppRefreshIntegrationResult skippedResult(
LiteWalletSyncAppRefreshIntegrationResult result,
LiteWalletSyncAppRefreshIntegrationIssue issue,
std::string message)
{
result.ok = true;
result.status = LiteWalletSyncAppRefreshIntegrationStatus::RefreshNotQueued;
addIssue(result, issue, std::move(message));
return result;
}
void copyRecoveryFlags(LiteWalletSyncAppRefreshIntegrationResult& result,
const LiteSyncRecoveryDecision& decision)
{
result.recoveryDecision = decision;
result.futureClearRequired = decision.shouldClear;
result.futureRescanRequired = decision.shouldRescan;
result.futureRestartSyncRequired = decision.shouldRestartSync;
result.requiresUserAttention = decision.requiresUserAttention;
}
} // namespace
const char* liteWalletSyncAppRefreshIntegrationStatusName(
LiteWalletSyncAppRefreshIntegrationStatus status)
{
switch (status) {
case LiteWalletSyncAppRefreshIntegrationStatus::FutureWorkerQueueFeedReady: return "FutureWorkerQueueFeedReady";
case LiteWalletSyncAppRefreshIntegrationStatus::WaitingForLifecycle: return "WaitingForLifecycle";
case LiteWalletSyncAppRefreshIntegrationStatus::WaitingForSyncPlan: return "WaitingForSyncPlan";
case LiteWalletSyncAppRefreshIntegrationStatus::WaitingForSyncStatus: return "WaitingForSyncStatus";
case LiteWalletSyncAppRefreshIntegrationStatus::WaitingForRecovery: return "WaitingForRecovery";
case LiteWalletSyncAppRefreshIntegrationStatus::WaitingForCancellation: return "WaitingForCancellation";
case LiteWalletSyncAppRefreshIntegrationStatus::RefreshNotQueued: return "RefreshNotQueued";
case LiteWalletSyncAppRefreshIntegrationStatus::WorkerQueueUnavailable: return "WorkerQueueUnavailable";
case LiteWalletSyncAppRefreshIntegrationStatus::UnsafePlan: return "UnsafePlan";
}
return "Unknown";
}
const char* liteWalletSyncAppRefreshIntegrationIssueName(
LiteWalletSyncAppRefreshIntegrationIssue issue)
{
switch (issue) {
case LiteWalletSyncAppRefreshIntegrationIssue::LifecycleNotReady: return "LifecycleNotReady";
case LiteWalletSyncAppRefreshIntegrationIssue::MissingSyncStartPlan: return "MissingSyncStartPlan";
case LiteWalletSyncAppRefreshIntegrationIssue::InvalidSyncStartPlan: return "InvalidSyncStartPlan";
case LiteWalletSyncAppRefreshIntegrationIssue::SyncStartWouldExecute: return "SyncStartWouldExecute";
case LiteWalletSyncAppRefreshIntegrationIssue::MissingSyncStatusPlan: return "MissingSyncStatusPlan";
case LiteWalletSyncAppRefreshIntegrationIssue::InvalidSyncStatusPlan: return "InvalidSyncStatusPlan";
case LiteWalletSyncAppRefreshIntegrationIssue::SyncStatusWouldExecute: return "SyncStatusWouldExecute";
case LiteWalletSyncAppRefreshIntegrationIssue::MissingRecoveryDecision: return "MissingRecoveryDecision";
case LiteWalletSyncAppRefreshIntegrationIssue::SyncStillPolling: return "SyncStillPolling";
case LiteWalletSyncAppRefreshIntegrationIssue::SyncRecoveryRequired: return "SyncRecoveryRequired";
case LiteWalletSyncAppRefreshIntegrationIssue::SyncRecoveryNeedsUserAttention: return "SyncRecoveryNeedsUserAttention";
case LiteWalletSyncAppRefreshIntegrationIssue::CancellationRequired: return "CancellationRequired";
case LiteWalletSyncAppRefreshIntegrationIssue::CancellationUnsupported: return "CancellationUnsupported";
case LiteWalletSyncAppRefreshIntegrationIssue::RefreshReportRejected: return "RefreshReportRejected";
case LiteWalletSyncAppRefreshIntegrationIssue::RefreshReportUnsafe: return "RefreshReportUnsafe";
case LiteWalletSyncAppRefreshIntegrationIssue::RefreshSkipped: return "RefreshSkipped";
case LiteWalletSyncAppRefreshIntegrationIssue::RefreshBlocked: return "RefreshBlocked";
case LiteWalletSyncAppRefreshIntegrationIssue::FutureWorkerQueueDisabled: return "FutureWorkerQueueDisabled";
case LiteWalletSyncAppRefreshIntegrationIssue::FutureWorkerQueuePressure: return "FutureWorkerQueuePressure";
}
return "Unknown";
}
LiteWalletSyncAppRefreshIntegrationResult planLiteWalletSyncAppRefreshIntegration(
const LiteWalletSyncAppRefreshIntegrationInput& input,
LiteWalletSyncAppRefreshIntegrationOptions options)
{
LiteWalletSyncAppRefreshIntegrationResult result;
result.lifecycleStatus = input.lifecycle.status;
result.refreshOrchestration = input.refreshOrchestration;
result.route = input.refreshOrchestration.route;
result.refreshWouldQueue = input.refreshOrchestration.wouldQueueRefresh;
result.refreshSkipped = input.refreshOrchestration.skipped;
result.refreshBlocked = input.refreshOrchestration.blocked;
result.futureWorkerQueuePlan.laneName = input.futureWorkerQueue.laneName;
result.futureWorkerQueuePlan.trigger = input.refreshOrchestration.trigger;
result.futureWorkerQueuePlan.route = input.refreshOrchestration.route;
result.futureWorkerQueuePlan.queueDepth = input.futureWorkerQueue.queueDepth;
result.futureWorkerQueuePlan.maxQueueDepth = input.futureWorkerQueue.maxQueueDepth;
if (input.sync.haveStartPlan) {
result.syncStartPlan = input.sync.startPlan;
result.futureWorkerQueuePlan.startSyncCommand = input.sync.startPlan.command;
}
if (input.sync.haveStatusPlan) {
result.syncStatusPlan = input.sync.statusPlan;
result.futureWorkerQueuePlan.syncStatusCommand = input.sync.statusPlan.command;
}
if (input.sync.haveRecoveryDecision) {
copyRecoveryFlags(result, input.sync.recoveryDecision);
}
if (options.requireLifecycleReady && !input.lifecycle.ready) {
return stoppedResult(
std::move(result),
LiteWalletSyncAppRefreshIntegrationStatus::WaitingForLifecycle,
LiteWalletSyncAppRefreshIntegrationIssue::LifecycleNotReady,
statusMessageOrDefault(input.lifecycle.status, "lite wallet lifecycle is not ready"));
}
result.lifecycleAccepted = true;
if (options.requireSyncStartPlan && !input.sync.haveStartPlan) {
return stoppedResult(
std::move(result),
LiteWalletSyncAppRefreshIntegrationStatus::WaitingForSyncPlan,
LiteWalletSyncAppRefreshIntegrationIssue::MissingSyncStartPlan,
"lite sync start plan is required before app refresh integration");
}
if (input.sync.haveStartPlan) {
if (!syncStartPlanIsValid(input.sync.startPlan)) {
return stoppedResult(
std::move(result),
LiteWalletSyncAppRefreshIntegrationStatus::WaitingForSyncPlan,
LiteWalletSyncAppRefreshIntegrationIssue::InvalidSyncStartPlan,
input.sync.startPlan.error.empty()
? "lite sync start plan is invalid"
: input.sync.startPlan.error);
}
if (options.rejectExecutableSyncPlans && input.sync.startPlan.bridgeExecutionAllowed) {
return stoppedResult(
std::move(result),
LiteWalletSyncAppRefreshIntegrationStatus::UnsafePlan,
LiteWalletSyncAppRefreshIntegrationIssue::SyncStartWouldExecute,
"lite sync start plan would allow bridge execution");
}
result.syncStartPlanAccepted = true;
}
if (options.requireSyncStatusPlan && !input.sync.haveStatusPlan) {
return stoppedResult(
std::move(result),
LiteWalletSyncAppRefreshIntegrationStatus::WaitingForSyncStatus,
LiteWalletSyncAppRefreshIntegrationIssue::MissingSyncStatusPlan,
"lite syncstatus plan is required before app refresh integration");
}
if (input.sync.haveStatusPlan) {
if (!syncStatusPlanIsValid(input.sync.statusPlan)) {
return stoppedResult(
std::move(result),
LiteWalletSyncAppRefreshIntegrationStatus::WaitingForSyncStatus,
LiteWalletSyncAppRefreshIntegrationIssue::InvalidSyncStatusPlan,
input.sync.statusPlan.error.empty()
? "lite syncstatus plan is invalid"
: input.sync.statusPlan.error);
}
if (options.rejectExecutableSyncPlans && input.sync.statusPlan.bridgeExecutionAllowed) {
return stoppedResult(
std::move(result),
LiteWalletSyncAppRefreshIntegrationStatus::UnsafePlan,
LiteWalletSyncAppRefreshIntegrationIssue::SyncStatusWouldExecute,
"lite syncstatus plan would allow bridge execution");
}
result.syncStatusPlanAccepted = true;
}
if (options.requireRecoveryDecision && !input.sync.haveRecoveryDecision) {
return stoppedResult(
std::move(result),
LiteWalletSyncAppRefreshIntegrationStatus::WaitingForSyncStatus,
LiteWalletSyncAppRefreshIntegrationIssue::MissingRecoveryDecision,
"lite sync recovery decision is required before app refresh integration");
}
if (input.sync.haveRecoveryDecision) {
const auto& decision = input.sync.recoveryDecision;
if (decision.kind == LiteSyncRecoveryDecisionKind::InvalidStatus) {
result.recoveryRequired = true;
return stoppedResult(
std::move(result),
LiteWalletSyncAppRefreshIntegrationStatus::WaitingForRecovery,
LiteWalletSyncAppRefreshIntegrationIssue::SyncRecoveryNeedsUserAttention,
decision.reason.empty()
? "lite sync status is invalid and needs user attention"
: decision.reason);
}
if (decision.kind == LiteSyncRecoveryDecisionKind::Stuck ||
decision.kind == LiteSyncRecoveryDecisionKind::ReorgDetected) {
result.recoveryRequired = true;
return stoppedResult(
std::move(result),
LiteWalletSyncAppRefreshIntegrationStatus::WaitingForRecovery,
LiteWalletSyncAppRefreshIntegrationIssue::SyncRecoveryRequired,
decision.reason.empty()
? "lite sync recovery must be modeled before refresh can feed a queue"
: decision.reason);
}
if (options.requireSyncCompleteForRefresh && decision.kind == LiteSyncRecoveryDecisionKind::KeepPolling) {
return stoppedResult(
std::move(result),
LiteWalletSyncAppRefreshIntegrationStatus::WaitingForSyncStatus,
LiteWalletSyncAppRefreshIntegrationIssue::SyncStillPolling,
decision.reason.empty()
? "lite sync is still polling"
: decision.reason);
}
result.recoveryAccepted = true;
}
if (input.cancellation.cancellationRequested && input.cancellation.syncInProgress) {
result.cancellationRequired = true;
if (!input.cancellation.cancellationSupported) {
return stoppedResult(
std::move(result),
LiteWalletSyncAppRefreshIntegrationStatus::WaitingForCancellation,
LiteWalletSyncAppRefreshIntegrationIssue::CancellationUnsupported,
"lite sync cancellation is requested but no cancellation path is available");
}
return stoppedResult(
std::move(result),
LiteWalletSyncAppRefreshIntegrationStatus::WaitingForCancellation,
LiteWalletSyncAppRefreshIntegrationIssue::CancellationRequired,
"lite sync cancellation must complete before app refresh can feed a queue");
}
result.cancellationAccepted = true;
if (refreshReportIsUnsafe(input.refreshOrchestration)) {
return stoppedResult(
std::move(result),
LiteWalletSyncAppRefreshIntegrationStatus::UnsafePlan,
LiteWalletSyncAppRefreshIntegrationIssue::RefreshReportUnsafe,
"lite app refresh orchestration report is not a no-network dry-run report");
}
if (!input.refreshOrchestration.ok) {
const auto issue = input.refreshOrchestration.blocked
? LiteWalletSyncAppRefreshIntegrationIssue::RefreshBlocked
: LiteWalletSyncAppRefreshIntegrationIssue::RefreshReportRejected;
return stoppedResult(
std::move(result),
LiteWalletSyncAppRefreshIntegrationStatus::RefreshNotQueued,
issue,
input.refreshOrchestration.error.empty()
? "lite app refresh orchestration report is not queued"
: input.refreshOrchestration.error);
}
result.refreshReportAccepted = true;
if (input.refreshOrchestration.skipped || !input.refreshOrchestration.wouldQueueRefresh) {
return skippedResult(
std::move(result),
LiteWalletSyncAppRefreshIntegrationIssue::RefreshSkipped,
input.refreshOrchestration.issues.empty()
? "lite app refresh orchestration skipped queueing"
: input.refreshOrchestration.issues.front().message);
}
if (options.requireFutureWorkerQueue && !input.futureWorkerQueue.enabled) {
return stoppedResult(
std::move(result),
LiteWalletSyncAppRefreshIntegrationStatus::WorkerQueueUnavailable,
LiteWalletSyncAppRefreshIntegrationIssue::FutureWorkerQueueDisabled,
"future lite app refresh worker queue is disabled");
}
if (input.futureWorkerQueue.maxQueueDepth > 0 &&
input.futureWorkerQueue.queueDepth >= input.futureWorkerQueue.maxQueueDepth) {
return stoppedResult(
std::move(result),
LiteWalletSyncAppRefreshIntegrationStatus::WorkerQueueUnavailable,
LiteWalletSyncAppRefreshIntegrationIssue::FutureWorkerQueuePressure,
"future lite app refresh worker queue is at capacity");
}
result.ok = true;
result.status = LiteWalletSyncAppRefreshIntegrationStatus::FutureWorkerQueueFeedReady;
result.futureWorkerQueueFeedReady = true;
result.wouldFeedFutureWorkerQueue = true;
result.futureWorkerQueuePlan.readyToFeed = true;
result.futureWorkerQueuePlan.wouldFeed = true;
return result;
}
LiteWalletSyncAppRefreshIntegrationPlanner::LiteWalletSyncAppRefreshIntegrationPlanner(
LiteWalletSyncAppRefreshIntegrationOptions options)
: options_(options)
{
}
LiteWalletSyncAppRefreshIntegrationResult LiteWalletSyncAppRefreshIntegrationPlanner::plan(
const LiteWalletSyncAppRefreshIntegrationInput& input) const
{
return planLiteWalletSyncAppRefreshIntegration(input, options_);
}
} // namespace dragonx::wallet