refactor(lite): remove dead parallel refresh/readiness scaffolding (~3.1k lines)
The lite-wallet tree carried a second, unused refresh+readiness architecture
that never reached the shipping binary — exactly the churn CLAUDE.md warns
against. The live refresh path is controller -> gateway.refresh ->
mapLiteWalletRefreshResult -> applyLiteRefreshModelToWalletState; this parallel
stack was dead weight.
Verified unused (their public types/functions are referenced only within the
cluster), then deleted (8 files / 16 incl. headers):
- lite_wallet_refresh_service (LiteWalletRefreshService + gateway adapters)
- lite_wallet_app_refresh_coordinator
- lite_wallet_app_refresh_orchestrator
- lite_wallet_refresh_readiness_policy
- lite_wallet_state_apply_plan
- lite_wallet_state_apply_executor
- lite_wallet_sync_app_refresh_integration
- lite_wallet_sync_execution_readiness
Severed three thin couplings into the cluster from live files:
- state_mapper: dropped the dead mapLiteWalletRefreshServiceResult and switched
its include from refresh_service.h to gateway.h (where the live
LiteWalletRefreshResult/Bundle DTOs actually live).
- server_lifecycle_readiness: dropped the unused syncLifecycleInput member +
converter and the sync_app_refresh_integration include.
- artifact_resolver: relocated the three LIVE artifact-input structs
(LiteWalletSdxlArtifact{Symbols,}Input, LiteWalletLinkedBackendReadinessInput)
out of sync_execution_readiness.h — their only real consumers — into
artifact_resolver.h, then dropped the include.
Also removed the dead DRAGONX_LONG_LITE_BATCH CMake machinery (its source var
was empty; on Windows it generated a broken lite_batch90_receipt_plan.cpp that
#included an empty path) and the stale .cpp/.h entries in CMakeLists.
Lite source files: 44 -> 30. Lite + full-node configure, both targets build,
test suite passes, source-hygiene clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -377,26 +377,6 @@ set(QRCODE_SOURCES
|
||||
# Application Sources
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# MinGW writes .obj.d dependency files, so this overlong generated source name
|
||||
# needs a short wrapper to stay under the Windows filename component limit.
|
||||
set(DRAGONX_LONG_LITE_BATCH_SOURCE
|
||||
)
|
||||
set(DRAGONX_LONG_LITE_BATCH_COMPILE_SOURCE ${DRAGONX_LONG_LITE_BATCH_SOURCE})
|
||||
if(WIN32)
|
||||
set(DRAGONX_LONG_LITE_BATCH_COMPILE_SOURCE
|
||||
${CMAKE_BINARY_DIR}/generated/short_sources/lite_batch90_receipt_plan.cpp
|
||||
)
|
||||
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/generated/short_sources)
|
||||
file(WRITE ${DRAGONX_LONG_LITE_BATCH_COMPILE_SOURCE}
|
||||
"#include \"${CMAKE_SOURCE_DIR}/${DRAGONX_LONG_LITE_BATCH_SOURCE}\"\n"
|
||||
)
|
||||
set_source_files_properties(${DRAGONX_LONG_LITE_BATCH_COMPILE_SOURCE}
|
||||
PROPERTIES
|
||||
GENERATED TRUE
|
||||
OBJECT_DEPENDS ${CMAKE_SOURCE_DIR}/${DRAGONX_LONG_LITE_BATCH_SOURCE}
|
||||
)
|
||||
endif()
|
||||
|
||||
set(APP_SOURCES
|
||||
src/main.cpp
|
||||
src/app.cpp
|
||||
@@ -418,17 +398,8 @@ set(APP_SOURCES
|
||||
src/wallet/lite_result_parsers.cpp
|
||||
src/wallet/lite_sync_service.cpp
|
||||
src/wallet/lite_wallet_gateway.cpp
|
||||
src/wallet/lite_wallet_refresh_service.cpp
|
||||
src/wallet/lite_wallet_state_mapper.cpp
|
||||
src/wallet/lite_wallet_state_apply_plan.cpp
|
||||
src/wallet/lite_wallet_state_apply_executor.cpp
|
||||
src/wallet/lite_wallet_app_refresh_coordinator.cpp
|
||||
src/wallet/lite_wallet_refresh_readiness_policy.cpp
|
||||
src/wallet/lite_wallet_app_refresh_orchestrator.cpp
|
||||
src/wallet/lite_wallet_sync_app_refresh_integration.cpp
|
||||
src/wallet/lite_wallet_sync_execution_readiness.cpp
|
||||
src/wallet/lite_wallet_lifecycle_ui_adapter.cpp
|
||||
${DRAGONX_LONG_LITE_BATCH_COMPILE_SOURCE}
|
||||
src/wallet/lite_wallet_server_selection_adapter.cpp
|
||||
src/wallet/lite_wallet_server_lifecycle_readiness.cpp
|
||||
src/wallet/lite_wallet_lifecycle_service.cpp
|
||||
@@ -542,15 +513,7 @@ set(APP_HEADERS
|
||||
src/wallet/lite_result_parsers.h
|
||||
src/wallet/lite_sync_service.h
|
||||
src/wallet/lite_wallet_gateway.h
|
||||
src/wallet/lite_wallet_refresh_service.h
|
||||
src/wallet/lite_wallet_state_mapper.h
|
||||
src/wallet/lite_wallet_state_apply_plan.h
|
||||
src/wallet/lite_wallet_state_apply_executor.h
|
||||
src/wallet/lite_wallet_app_refresh_coordinator.h
|
||||
src/wallet/lite_wallet_refresh_readiness_policy.h
|
||||
src/wallet/lite_wallet_app_refresh_orchestrator.h
|
||||
src/wallet/lite_wallet_sync_app_refresh_integration.h
|
||||
src/wallet/lite_wallet_sync_execution_readiness.h
|
||||
src/wallet/lite_wallet_lifecycle_ui_adapter.h
|
||||
src/wallet/lite_wallet_server_selection_adapter.h
|
||||
src/wallet/lite_wallet_server_lifecycle_readiness.h
|
||||
@@ -985,17 +948,8 @@ if(BUILD_TESTING)
|
||||
src/wallet/lite_result_parsers.cpp
|
||||
src/wallet/lite_sync_service.cpp
|
||||
src/wallet/lite_wallet_gateway.cpp
|
||||
src/wallet/lite_wallet_refresh_service.cpp
|
||||
src/wallet/lite_wallet_state_mapper.cpp
|
||||
src/wallet/lite_wallet_state_apply_plan.cpp
|
||||
src/wallet/lite_wallet_state_apply_executor.cpp
|
||||
src/wallet/lite_wallet_app_refresh_coordinator.cpp
|
||||
src/wallet/lite_wallet_refresh_readiness_policy.cpp
|
||||
src/wallet/lite_wallet_app_refresh_orchestrator.cpp
|
||||
src/wallet/lite_wallet_sync_app_refresh_integration.cpp
|
||||
src/wallet/lite_wallet_sync_execution_readiness.cpp
|
||||
src/wallet/lite_wallet_lifecycle_ui_adapter.cpp
|
||||
${DRAGONX_LONG_LITE_BATCH_COMPILE_SOURCE}
|
||||
src/wallet/lite_wallet_server_selection_adapter.cpp
|
||||
src/wallet/lite_wallet_server_lifecycle_readiness.cpp
|
||||
src/wallet/lite_wallet_lifecycle_service.cpp
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "lite_connection_service.h"
|
||||
#include "lite_wallet_sync_execution_readiness.h"
|
||||
#include "lite_connection_service.h" // pulls wallet_backend.h (WalletBackendStatus)
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
@@ -9,6 +8,37 @@
|
||||
|
||||
namespace dragonx::wallet {
|
||||
|
||||
// Validated-artifact inputs for the linked-backend resolver/contract. (Previously these lived in
|
||||
// lite_wallet_sync_execution_readiness.h alongside a parallel, unused sync-readiness planner;
|
||||
// they were relocated here — their only live home — when that scaffolding was removed.)
|
||||
struct LiteWalletSdxlArtifactSymbolsInput {
|
||||
bool walletExists = false;
|
||||
bool initializeNew = false;
|
||||
bool initializeNewFromPhrase = false;
|
||||
bool initializeExisting = false;
|
||||
bool execute = false;
|
||||
bool freeString = false;
|
||||
bool checkServerOnline = false;
|
||||
bool shutdown = false;
|
||||
};
|
||||
|
||||
struct LiteWalletSdxlArtifactInput {
|
||||
bool pathConfigured = false;
|
||||
bool exists = false;
|
||||
bool readable = false;
|
||||
bool sdxlCompatible = false;
|
||||
std::string artifactPath;
|
||||
std::string versionLabel;
|
||||
LiteWalletSdxlArtifactSymbolsInput symbols;
|
||||
};
|
||||
|
||||
struct LiteWalletLinkedBackendReadinessInput {
|
||||
bool linked = false;
|
||||
bool bridgeAvailable = false;
|
||||
WalletBackendStatus status;
|
||||
std::string bridgeUnavailableReason;
|
||||
};
|
||||
|
||||
enum class LiteBackendArtifactPlatform {
|
||||
Current,
|
||||
Linux,
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
#include "wallet/lite_wallet_app_refresh_coordinator.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace dragonx::wallet {
|
||||
namespace {
|
||||
|
||||
void addIssue(LiteWalletAppRefreshCoordinationResult& result,
|
||||
LiteWalletAppRefreshCoordinationIssue issue,
|
||||
std::string message)
|
||||
{
|
||||
result.issues.push_back(LiteWalletAppRefreshCoordinationIssueInfo{issue, std::move(message)});
|
||||
}
|
||||
|
||||
std::string refreshFailureMessage(const LiteWalletRefreshServiceResult& refreshResult)
|
||||
{
|
||||
if (!refreshResult.error.empty()) return refreshResult.error;
|
||||
if (!refreshResult.status.message.empty()) return refreshResult.status.message;
|
||||
return "lite wallet refresh service result is not successful";
|
||||
}
|
||||
|
||||
void copyExecutionSummary(LiteWalletAppRefreshCoordinationResult& result)
|
||||
{
|
||||
result.stateMutationRequested = result.executionResult.stateMutationRequested;
|
||||
result.stateMutationAllowed = result.applyPlan.stateMutationAllowed ||
|
||||
result.executionResult.stateMutationAllowed;
|
||||
result.stateMutated = result.executionResult.stateMutated;
|
||||
result.walletStateWritten = result.stateMutated;
|
||||
result.dryRunOnly = result.applyPlan.dryRunOnly && result.executionResult.dryRunOnly;
|
||||
result.noNetwork = result.executionResult.noNetwork;
|
||||
result.fieldPlanCount = result.executionResult.fieldPlanCount;
|
||||
result.collectionPlanCount = result.executionResult.collectionPlanCount;
|
||||
result.plannedChangeCount = result.executionResult.plannedChangeCount;
|
||||
result.planIssueCount = result.executionResult.planIssueCount;
|
||||
result.executionIssueCount = result.executionResult.issues.size();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const char* liteWalletAppRefreshCoordinationStatusName(
|
||||
LiteWalletAppRefreshCoordinationStatus status)
|
||||
{
|
||||
switch (status) {
|
||||
case LiteWalletAppRefreshCoordinationStatus::DryRunReported: return "DryRunReported";
|
||||
case LiteWalletAppRefreshCoordinationStatus::Rejected: return "Rejected";
|
||||
case LiteWalletAppRefreshCoordinationStatus::ApplyUnavailable: return "ApplyUnavailable";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
const char* liteWalletAppRefreshCoordinationIssueName(
|
||||
LiteWalletAppRefreshCoordinationIssue issue)
|
||||
{
|
||||
switch (issue) {
|
||||
case LiteWalletAppRefreshCoordinationIssue::RefreshResultFailed: return "RefreshResultFailed";
|
||||
case LiteWalletAppRefreshCoordinationIssue::FullNodeRefreshDelegated: return "FullNodeRefreshDelegated";
|
||||
case LiteWalletAppRefreshCoordinationIssue::MappingFailed: return "MappingFailed";
|
||||
case LiteWalletAppRefreshCoordinationIssue::ApplyPlanFailed: return "ApplyPlanFailed";
|
||||
case LiteWalletAppRefreshCoordinationIssue::ApplyExecutionRejected: return "ApplyExecutionRejected";
|
||||
case LiteWalletAppRefreshCoordinationIssue::StateMutationDisabled: return "StateMutationDisabled";
|
||||
case LiteWalletAppRefreshCoordinationIssue::StateMutationImplementationMissing: return "StateMutationImplementationMissing";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
LiteWalletAppRefreshCoordinationResult coordinateLiteWalletAppRefresh(
|
||||
const LiteWalletRefreshServiceResult& refreshResult,
|
||||
const dragonx::WalletState& walletState,
|
||||
LiteWalletAppRefreshCoordinatorOptions options)
|
||||
{
|
||||
LiteWalletAppRefreshCoordinationResult result;
|
||||
result.route = refreshResult.plan.route;
|
||||
result.refreshStatus = refreshResult.status;
|
||||
result.refreshAttempted = refreshResult.attempted;
|
||||
result.fullNodeRefreshDelegated = refreshResult.fullNodeRefreshDelegated;
|
||||
result.liteGatewayCalled = refreshResult.liteGatewayCalled;
|
||||
result.stateMutationRequested = options.executorOptions.requestStateMutation;
|
||||
|
||||
if (refreshResult.fullNodeRefreshDelegated) {
|
||||
addIssue(result,
|
||||
LiteWalletAppRefreshCoordinationIssue::FullNodeRefreshDelegated,
|
||||
"full-node refresh remains delegated; lite app refresh coordinator did not run");
|
||||
result.error = result.issues.back().message;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!refreshResult.ok) {
|
||||
addIssue(result,
|
||||
LiteWalletAppRefreshCoordinationIssue::RefreshResultFailed,
|
||||
refreshFailureMessage(refreshResult));
|
||||
result.error = result.issues.back().message;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.refreshAccepted = true;
|
||||
result.mapResult = mapLiteWalletRefreshServiceResult(refreshResult);
|
||||
result.mapIssueCount = result.mapResult.issues.size();
|
||||
if (!result.mapResult.ok) {
|
||||
addIssue(result,
|
||||
LiteWalletAppRefreshCoordinationIssue::MappingFailed,
|
||||
result.mapResult.error.empty()
|
||||
? "lite wallet refresh service result could not be mapped"
|
||||
: result.mapResult.error);
|
||||
result.error = result.issues.back().message;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.mapped = true;
|
||||
result.successfulCommandCount = result.mapResult.model.successfulCommandCount;
|
||||
result.applyPlan = planLiteWalletStateApply(result.mapResult.model, walletState);
|
||||
if (!result.applyPlan.ok) {
|
||||
result.fieldPlanCount = result.applyPlan.fieldPlans.size();
|
||||
result.collectionPlanCount = result.applyPlan.collectionPlans.size();
|
||||
result.planIssueCount = result.applyPlan.issues.size();
|
||||
addIssue(result,
|
||||
LiteWalletAppRefreshCoordinationIssue::ApplyPlanFailed,
|
||||
result.applyPlan.error.empty()
|
||||
? "lite WalletState apply plan could not be built"
|
||||
: result.applyPlan.error);
|
||||
result.error = result.issues.back().message;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.planned = true;
|
||||
LiteWalletStateApplyExecutor executor(options.executorOptions);
|
||||
result.executionResult = executor.execute(result.applyPlan);
|
||||
result.executionReported = true;
|
||||
copyExecutionSummary(result);
|
||||
|
||||
if (!result.executionResult.ok) {
|
||||
result.error = result.executionResult.error;
|
||||
if (result.executionResult.status == LiteWalletStateApplyExecutionStatus::ImplementationMissing) {
|
||||
result.status = LiteWalletAppRefreshCoordinationStatus::ApplyUnavailable;
|
||||
addIssue(result,
|
||||
LiteWalletAppRefreshCoordinationIssue::StateMutationImplementationMissing,
|
||||
result.executionResult.error.empty()
|
||||
? "real lite WalletState application requires a future explicit implementation"
|
||||
: result.executionResult.error);
|
||||
} else {
|
||||
result.status = LiteWalletAppRefreshCoordinationStatus::Rejected;
|
||||
addIssue(result,
|
||||
LiteWalletAppRefreshCoordinationIssue::ApplyExecutionRejected,
|
||||
result.executionResult.error.empty()
|
||||
? "lite WalletState apply execution report was rejected"
|
||||
: result.executionResult.error);
|
||||
}
|
||||
if (result.error.empty()) result.error = result.issues.back().message;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.ok = true;
|
||||
result.status = LiteWalletAppRefreshCoordinationStatus::DryRunReported;
|
||||
addIssue(result,
|
||||
LiteWalletAppRefreshCoordinationIssue::StateMutationDisabled,
|
||||
"lite app refresh coordinator produced a dry-run report only; WalletState was not written");
|
||||
return result;
|
||||
}
|
||||
|
||||
LiteWalletAppRefreshCoordinator::LiteWalletAppRefreshCoordinator(
|
||||
LiteWalletAppRefreshCoordinatorOptions options)
|
||||
: options_(options)
|
||||
{
|
||||
}
|
||||
|
||||
LiteWalletAppRefreshCoordinationResult LiteWalletAppRefreshCoordinator::coordinate(
|
||||
const LiteWalletRefreshServiceResult& refreshResult,
|
||||
const dragonx::WalletState& walletState) const
|
||||
{
|
||||
return coordinateLiteWalletAppRefresh(refreshResult, walletState, options_);
|
||||
}
|
||||
|
||||
} // namespace dragonx::wallet
|
||||
@@ -1,96 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "data/wallet_state.h"
|
||||
#include "lite_wallet_refresh_service.h"
|
||||
#include "lite_wallet_state_apply_executor.h"
|
||||
#include "lite_wallet_state_mapper.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace dragonx::wallet {
|
||||
|
||||
enum class LiteWalletAppRefreshCoordinationStatus {
|
||||
DryRunReported,
|
||||
Rejected,
|
||||
ApplyUnavailable,
|
||||
};
|
||||
|
||||
enum class LiteWalletAppRefreshCoordinationIssue {
|
||||
RefreshResultFailed,
|
||||
FullNodeRefreshDelegated,
|
||||
MappingFailed,
|
||||
ApplyPlanFailed,
|
||||
ApplyExecutionRejected,
|
||||
StateMutationDisabled,
|
||||
StateMutationImplementationMissing,
|
||||
};
|
||||
|
||||
struct LiteWalletAppRefreshCoordinatorOptions {
|
||||
LiteWalletStateApplyExecutorOptions executorOptions;
|
||||
};
|
||||
|
||||
struct LiteWalletAppRefreshCoordinationIssueInfo {
|
||||
LiteWalletAppRefreshCoordinationIssue issue = LiteWalletAppRefreshCoordinationIssue::StateMutationDisabled;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
struct LiteWalletAppRefreshCoordinationResult {
|
||||
bool ok = false;
|
||||
bool refreshAccepted = false;
|
||||
bool refreshAttempted = false;
|
||||
bool fullNodeRefreshDelegated = false;
|
||||
bool liteGatewayCalled = false;
|
||||
bool mapped = false;
|
||||
bool planned = false;
|
||||
bool executionReported = false;
|
||||
bool dryRunOnly = true;
|
||||
bool noNetwork = true;
|
||||
bool stateMutationRequested = false;
|
||||
bool stateMutationAllowed = false;
|
||||
bool stateMutated = false;
|
||||
bool walletStateWritten = false;
|
||||
|
||||
LiteWalletAppRefreshCoordinationStatus status = LiteWalletAppRefreshCoordinationStatus::Rejected;
|
||||
LiteWalletRefreshRouteKind route = LiteWalletRefreshRouteKind::Unavailable;
|
||||
WalletBackendStatus refreshStatus;
|
||||
|
||||
std::size_t successfulCommandCount = 0;
|
||||
std::size_t mapIssueCount = 0;
|
||||
std::size_t fieldPlanCount = 0;
|
||||
std::size_t collectionPlanCount = 0;
|
||||
std::size_t plannedChangeCount = 0;
|
||||
std::size_t planIssueCount = 0;
|
||||
std::size_t executionIssueCount = 0;
|
||||
|
||||
LiteWalletStateMapResult mapResult;
|
||||
LiteWalletStateApplyPlan applyPlan;
|
||||
LiteWalletStateApplyExecutionResult executionResult;
|
||||
std::vector<LiteWalletAppRefreshCoordinationIssueInfo> issues;
|
||||
std::string error;
|
||||
};
|
||||
|
||||
const char* liteWalletAppRefreshCoordinationStatusName(
|
||||
LiteWalletAppRefreshCoordinationStatus status);
|
||||
const char* liteWalletAppRefreshCoordinationIssueName(
|
||||
LiteWalletAppRefreshCoordinationIssue issue);
|
||||
|
||||
LiteWalletAppRefreshCoordinationResult coordinateLiteWalletAppRefresh(
|
||||
const LiteWalletRefreshServiceResult& refreshResult,
|
||||
const dragonx::WalletState& walletState,
|
||||
LiteWalletAppRefreshCoordinatorOptions options = {});
|
||||
|
||||
class LiteWalletAppRefreshCoordinator {
|
||||
public:
|
||||
explicit LiteWalletAppRefreshCoordinator(LiteWalletAppRefreshCoordinatorOptions options = {});
|
||||
|
||||
LiteWalletAppRefreshCoordinationResult coordinate(
|
||||
const LiteWalletRefreshServiceResult& refreshResult,
|
||||
const dragonx::WalletState& walletState) const;
|
||||
|
||||
private:
|
||||
LiteWalletAppRefreshCoordinatorOptions options_;
|
||||
};
|
||||
|
||||
} // namespace dragonx::wallet
|
||||
@@ -1,197 +0,0 @@
|
||||
#include "wallet/lite_wallet_app_refresh_orchestrator.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace dragonx::wallet {
|
||||
namespace {
|
||||
|
||||
void addIssue(LiteWalletAppRefreshOrchestrationResult& result,
|
||||
LiteWalletAppRefreshOrchestrationIssue issue,
|
||||
std::string message)
|
||||
{
|
||||
result.issues.push_back(LiteWalletAppRefreshOrchestrationIssueInfo{issue, std::move(message)});
|
||||
}
|
||||
|
||||
bool readinessReportIsUnsafe(const LiteWalletRefreshReadinessResult& readiness)
|
||||
{
|
||||
return !readiness.dryRunOnly ||
|
||||
!readiness.noNetwork ||
|
||||
readiness.stateMutationRequested ||
|
||||
readiness.stateMutationAllowed ||
|
||||
readiness.stateMutated ||
|
||||
readiness.walletStateWritten;
|
||||
}
|
||||
|
||||
std::string readinessErrorOrDefault(const LiteWalletRefreshReadinessResult& readiness)
|
||||
{
|
||||
return readiness.error.empty()
|
||||
? "lite refresh readiness report is not eligible"
|
||||
: readiness.error;
|
||||
}
|
||||
|
||||
LiteWalletAppRefreshOrchestrationResult blockedResult(
|
||||
LiteWalletAppRefreshOrchestrationResult result,
|
||||
LiteWalletAppRefreshOrchestrationIssue issue,
|
||||
std::string message)
|
||||
{
|
||||
result.status = LiteWalletAppRefreshOrchestrationStatus::Blocked;
|
||||
result.blocked = true;
|
||||
addIssue(result, issue, std::move(message));
|
||||
result.error = result.issues.back().message;
|
||||
return result;
|
||||
}
|
||||
|
||||
LiteWalletAppRefreshOrchestrationResult skippedResult(
|
||||
LiteWalletAppRefreshOrchestrationResult result,
|
||||
LiteWalletAppRefreshOrchestrationIssue issue,
|
||||
std::string message)
|
||||
{
|
||||
result.ok = true;
|
||||
result.status = LiteWalletAppRefreshOrchestrationStatus::Skipped;
|
||||
result.skipped = true;
|
||||
addIssue(result, issue, std::move(message));
|
||||
return result;
|
||||
}
|
||||
|
||||
std::size_t effectiveMaxQueueDepth(const LiteWalletAppRefreshScheduleInput& schedule,
|
||||
const LiteWalletAppRefreshOrchestratorOptions& options)
|
||||
{
|
||||
return schedule.maxQueueDepth > 0 ? schedule.maxQueueDepth : options.maxQueueDepth;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const char* liteWalletAppRefreshOrchestrationStatusName(
|
||||
LiteWalletAppRefreshOrchestrationStatus status)
|
||||
{
|
||||
switch (status) {
|
||||
case LiteWalletAppRefreshOrchestrationStatus::Queued: return "Queued";
|
||||
case LiteWalletAppRefreshOrchestrationStatus::Skipped: return "Skipped";
|
||||
case LiteWalletAppRefreshOrchestrationStatus::Blocked: return "Blocked";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
const char* liteWalletAppRefreshScheduleTriggerName(
|
||||
LiteWalletAppRefreshScheduleTrigger trigger)
|
||||
{
|
||||
switch (trigger) {
|
||||
case LiteWalletAppRefreshScheduleTrigger::Periodic: return "Periodic";
|
||||
case LiteWalletAppRefreshScheduleTrigger::Manual: return "Manual";
|
||||
case LiteWalletAppRefreshScheduleTrigger::Startup: return "Startup";
|
||||
case LiteWalletAppRefreshScheduleTrigger::WalletOpened: return "WalletOpened";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
const char* liteWalletAppRefreshOrchestrationIssueName(
|
||||
LiteWalletAppRefreshOrchestrationIssue issue)
|
||||
{
|
||||
switch (issue) {
|
||||
case LiteWalletAppRefreshOrchestrationIssue::ReadinessRejected: return "ReadinessRejected";
|
||||
case LiteWalletAppRefreshOrchestrationIssue::UnsafeReadinessReport: return "UnsafeReadinessReport";
|
||||
case LiteWalletAppRefreshOrchestrationIssue::SchedulerDisabled: return "SchedulerDisabled";
|
||||
case LiteWalletAppRefreshOrchestrationIssue::RefreshNotDue: return "RefreshNotDue";
|
||||
case LiteWalletAppRefreshOrchestrationIssue::RefreshAlreadyQueued: return "RefreshAlreadyQueued";
|
||||
case LiteWalletAppRefreshOrchestrationIssue::RefreshInProgress: return "RefreshInProgress";
|
||||
case LiteWalletAppRefreshOrchestrationIssue::QueuePressure: return "QueuePressure";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
LiteWalletAppRefreshOrchestrationResult orchestrateLiteWalletAppRefresh(
|
||||
const LiteWalletRefreshReadinessResult& readiness,
|
||||
const LiteWalletAppRefreshScheduleInput& schedule,
|
||||
LiteWalletAppRefreshOrchestratorOptions options)
|
||||
{
|
||||
LiteWalletAppRefreshOrchestrationResult result;
|
||||
result.readinessResult = readiness;
|
||||
result.route = readiness.route;
|
||||
result.dryRunOnly = readiness.dryRunOnly;
|
||||
result.noNetwork = readiness.noNetwork;
|
||||
result.stateMutationRequested = readiness.stateMutationRequested;
|
||||
result.stateMutationAllowed = readiness.stateMutationAllowed;
|
||||
result.stateMutated = readiness.stateMutated;
|
||||
result.walletStateWritten = readiness.walletStateWritten;
|
||||
result.trigger = schedule.trigger;
|
||||
result.schedulerEnabled = schedule.schedulerEnabled;
|
||||
result.refreshDue = schedule.refreshDue;
|
||||
result.forceRefresh = schedule.forceRefresh;
|
||||
result.refreshAlreadyQueued = schedule.refreshAlreadyQueued;
|
||||
result.refreshInProgress = schedule.refreshInProgress;
|
||||
result.queueDepth = schedule.queueDepth;
|
||||
result.maxQueueDepth = effectiveMaxQueueDepth(schedule, options);
|
||||
|
||||
if (options.requireEligibleReadiness && (!readiness.ok || !readiness.eligibleForFutureUiRefresh)) {
|
||||
return blockedResult(
|
||||
std::move(result),
|
||||
LiteWalletAppRefreshOrchestrationIssue::ReadinessRejected,
|
||||
readinessErrorOrDefault(readiness));
|
||||
}
|
||||
|
||||
if (readinessReportIsUnsafe(readiness)) {
|
||||
return blockedResult(
|
||||
std::move(result),
|
||||
LiteWalletAppRefreshOrchestrationIssue::UnsafeReadinessReport,
|
||||
"lite refresh readiness report is not a no-network dry-run report");
|
||||
}
|
||||
|
||||
result.readinessAccepted = true;
|
||||
|
||||
if (!schedule.schedulerEnabled) {
|
||||
return blockedResult(
|
||||
std::move(result),
|
||||
LiteWalletAppRefreshOrchestrationIssue::SchedulerDisabled,
|
||||
"lite app refresh scheduler is disabled");
|
||||
}
|
||||
|
||||
result.schedulerAccepted = true;
|
||||
|
||||
if (result.maxQueueDepth > 0 && schedule.queueDepth >= result.maxQueueDepth) {
|
||||
return blockedResult(
|
||||
std::move(result),
|
||||
LiteWalletAppRefreshOrchestrationIssue::QueuePressure,
|
||||
"lite app refresh queue is at capacity");
|
||||
}
|
||||
|
||||
if (schedule.refreshAlreadyQueued) {
|
||||
return skippedResult(
|
||||
std::move(result),
|
||||
LiteWalletAppRefreshOrchestrationIssue::RefreshAlreadyQueued,
|
||||
"lite app refresh is already queued");
|
||||
}
|
||||
|
||||
if (schedule.refreshInProgress) {
|
||||
return skippedResult(
|
||||
std::move(result),
|
||||
LiteWalletAppRefreshOrchestrationIssue::RefreshInProgress,
|
||||
"lite app refresh is already in progress");
|
||||
}
|
||||
|
||||
if (!schedule.refreshDue && !schedule.forceRefresh) {
|
||||
return skippedResult(
|
||||
std::move(result),
|
||||
LiteWalletAppRefreshOrchestrationIssue::RefreshNotDue,
|
||||
"lite app refresh is not due");
|
||||
}
|
||||
|
||||
result.ok = true;
|
||||
result.status = LiteWalletAppRefreshOrchestrationStatus::Queued;
|
||||
result.wouldQueueRefresh = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
LiteWalletAppRefreshOrchestrator::LiteWalletAppRefreshOrchestrator(
|
||||
LiteWalletAppRefreshOrchestratorOptions options)
|
||||
: options_(options)
|
||||
{
|
||||
}
|
||||
|
||||
LiteWalletAppRefreshOrchestrationResult LiteWalletAppRefreshOrchestrator::evaluate(
|
||||
const LiteWalletRefreshReadinessResult& readiness,
|
||||
const LiteWalletAppRefreshScheduleInput& schedule) const
|
||||
{
|
||||
return orchestrateLiteWalletAppRefresh(readiness, schedule, options_);
|
||||
}
|
||||
|
||||
} // namespace dragonx::wallet
|
||||
@@ -1,109 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "lite_wallet_refresh_readiness_policy.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace dragonx::wallet {
|
||||
|
||||
enum class LiteWalletAppRefreshOrchestrationStatus {
|
||||
Queued,
|
||||
Skipped,
|
||||
Blocked,
|
||||
};
|
||||
|
||||
enum class LiteWalletAppRefreshScheduleTrigger {
|
||||
Periodic,
|
||||
Manual,
|
||||
Startup,
|
||||
WalletOpened,
|
||||
};
|
||||
|
||||
enum class LiteWalletAppRefreshOrchestrationIssue {
|
||||
ReadinessRejected,
|
||||
UnsafeReadinessReport,
|
||||
SchedulerDisabled,
|
||||
RefreshNotDue,
|
||||
RefreshAlreadyQueued,
|
||||
RefreshInProgress,
|
||||
QueuePressure,
|
||||
};
|
||||
|
||||
struct LiteWalletAppRefreshScheduleInput {
|
||||
LiteWalletAppRefreshScheduleTrigger trigger = LiteWalletAppRefreshScheduleTrigger::Periodic;
|
||||
bool schedulerEnabled = true;
|
||||
bool refreshDue = false;
|
||||
bool forceRefresh = false;
|
||||
bool refreshAlreadyQueued = false;
|
||||
bool refreshInProgress = false;
|
||||
std::size_t queueDepth = 0;
|
||||
std::size_t maxQueueDepth = 0;
|
||||
};
|
||||
|
||||
struct LiteWalletAppRefreshOrchestratorOptions {
|
||||
bool requireEligibleReadiness = true;
|
||||
std::size_t maxQueueDepth = 0;
|
||||
};
|
||||
|
||||
struct LiteWalletAppRefreshOrchestrationIssueInfo {
|
||||
LiteWalletAppRefreshOrchestrationIssue issue = LiteWalletAppRefreshOrchestrationIssue::ReadinessRejected;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
struct LiteWalletAppRefreshOrchestrationResult {
|
||||
bool ok = false;
|
||||
bool wouldQueueRefresh = false;
|
||||
bool skipped = false;
|
||||
bool blocked = false;
|
||||
bool readinessAccepted = false;
|
||||
bool schedulerAccepted = false;
|
||||
bool dryRunOnly = true;
|
||||
bool noNetwork = true;
|
||||
bool stateMutationRequested = false;
|
||||
bool stateMutationAllowed = false;
|
||||
bool stateMutated = false;
|
||||
bool walletStateWritten = false;
|
||||
|
||||
bool schedulerEnabled = true;
|
||||
bool refreshDue = false;
|
||||
bool forceRefresh = false;
|
||||
bool refreshAlreadyQueued = false;
|
||||
bool refreshInProgress = false;
|
||||
std::size_t queueDepth = 0;
|
||||
std::size_t maxQueueDepth = 0;
|
||||
|
||||
LiteWalletAppRefreshOrchestrationStatus status = LiteWalletAppRefreshOrchestrationStatus::Blocked;
|
||||
LiteWalletAppRefreshScheduleTrigger trigger = LiteWalletAppRefreshScheduleTrigger::Periodic;
|
||||
LiteWalletRefreshRouteKind route = LiteWalletRefreshRouteKind::Unavailable;
|
||||
LiteWalletRefreshReadinessResult readinessResult;
|
||||
std::vector<LiteWalletAppRefreshOrchestrationIssueInfo> issues;
|
||||
std::string error;
|
||||
};
|
||||
|
||||
const char* liteWalletAppRefreshOrchestrationStatusName(
|
||||
LiteWalletAppRefreshOrchestrationStatus status);
|
||||
const char* liteWalletAppRefreshScheduleTriggerName(
|
||||
LiteWalletAppRefreshScheduleTrigger trigger);
|
||||
const char* liteWalletAppRefreshOrchestrationIssueName(
|
||||
LiteWalletAppRefreshOrchestrationIssue issue);
|
||||
|
||||
LiteWalletAppRefreshOrchestrationResult orchestrateLiteWalletAppRefresh(
|
||||
const LiteWalletRefreshReadinessResult& readiness,
|
||||
const LiteWalletAppRefreshScheduleInput& schedule,
|
||||
LiteWalletAppRefreshOrchestratorOptions options = {});
|
||||
|
||||
class LiteWalletAppRefreshOrchestrator {
|
||||
public:
|
||||
explicit LiteWalletAppRefreshOrchestrator(LiteWalletAppRefreshOrchestratorOptions options = {});
|
||||
|
||||
LiteWalletAppRefreshOrchestrationResult evaluate(
|
||||
const LiteWalletRefreshReadinessResult& readiness,
|
||||
const LiteWalletAppRefreshScheduleInput& schedule) const;
|
||||
|
||||
private:
|
||||
LiteWalletAppRefreshOrchestratorOptions options_;
|
||||
};
|
||||
|
||||
} // namespace dragonx::wallet
|
||||
@@ -1,205 +0,0 @@
|
||||
#include "wallet/lite_wallet_refresh_readiness_policy.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace dragonx::wallet {
|
||||
namespace {
|
||||
|
||||
void addIssue(LiteWalletRefreshReadinessResult& result,
|
||||
LiteWalletRefreshReadinessIssue issue,
|
||||
std::string message)
|
||||
{
|
||||
result.issues.push_back(LiteWalletRefreshReadinessIssueInfo{issue, std::move(message)});
|
||||
}
|
||||
|
||||
std::string statusMessageOrDefault(const WalletBackendStatus& status,
|
||||
const std::string& fallback)
|
||||
{
|
||||
return status.message.empty() ? fallback : status.message;
|
||||
}
|
||||
|
||||
LiteWalletRefreshReadinessResult failReadiness(
|
||||
LiteWalletRefreshReadinessResult result,
|
||||
LiteWalletRefreshReadinessStatus status,
|
||||
LiteWalletRefreshReadinessIssue issue,
|
||||
std::string message)
|
||||
{
|
||||
result.status = status;
|
||||
addIssue(result, issue, std::move(message));
|
||||
result.error = result.issues.back().message;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool coordinatorReportIsUnsafe(const LiteWalletAppRefreshCoordinationResult& coordination)
|
||||
{
|
||||
return !coordination.dryRunOnly ||
|
||||
!coordination.noNetwork ||
|
||||
coordination.stateMutationRequested ||
|
||||
coordination.stateMutationAllowed ||
|
||||
coordination.stateMutated ||
|
||||
coordination.walletStateWritten;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const char* liteWalletRefreshReadinessStatusName(LiteWalletRefreshReadinessStatus status)
|
||||
{
|
||||
switch (status) {
|
||||
case LiteWalletRefreshReadinessStatus::EligibleDryRun: return "EligibleDryRun";
|
||||
case LiteWalletRefreshReadinessStatus::CoordinatorRejected: return "CoordinatorRejected";
|
||||
case LiteWalletRefreshReadinessStatus::UnsafeReport: return "UnsafeReport";
|
||||
case LiteWalletRefreshReadinessStatus::WaitingForLifecycle: return "WaitingForLifecycle";
|
||||
case LiteWalletRefreshReadinessStatus::WaitingForSync: return "WaitingForSync";
|
||||
case LiteWalletRefreshReadinessStatus::Stale: return "Stale";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
const char* liteWalletRefreshReadinessIssueName(LiteWalletRefreshReadinessIssue issue)
|
||||
{
|
||||
switch (issue) {
|
||||
case LiteWalletRefreshReadinessIssue::CoordinatorReportRejected: return "CoordinatorReportRejected";
|
||||
case LiteWalletRefreshReadinessIssue::CoordinatorReportIncomplete: return "CoordinatorReportIncomplete";
|
||||
case LiteWalletRefreshReadinessIssue::CoordinatorReportUnsafe: return "CoordinatorReportUnsafe";
|
||||
case LiteWalletRefreshReadinessIssue::FullNodeRouteRejected: return "FullNodeRouteRejected";
|
||||
case LiteWalletRefreshReadinessIssue::LifecycleNotReady: return "LifecycleNotReady";
|
||||
case LiteWalletRefreshReadinessIssue::SyncNotReady: return "SyncNotReady";
|
||||
case LiteWalletRefreshReadinessIssue::RefreshTimestampMissing: return "RefreshTimestampMissing";
|
||||
case LiteWalletRefreshReadinessIssue::RefreshTimestampInFuture: return "RefreshTimestampInFuture";
|
||||
case LiteWalletRefreshReadinessIssue::RefreshStale: return "RefreshStale";
|
||||
case LiteWalletRefreshReadinessIssue::StaleRefreshAllowed: return "StaleRefreshAllowed";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
LiteWalletRefreshReadinessResult evaluateLiteWalletRefreshReadiness(
|
||||
const LiteWalletAppRefreshCoordinationResult& coordination,
|
||||
const LiteWalletRefreshReadinessInputs& inputs,
|
||||
LiteWalletRefreshReadinessPolicyOptions options)
|
||||
{
|
||||
LiteWalletRefreshReadinessResult result;
|
||||
result.route = coordination.route;
|
||||
result.dryRunOnly = coordination.dryRunOnly;
|
||||
result.noNetwork = coordination.noNetwork;
|
||||
result.stateMutationRequested = coordination.stateMutationRequested;
|
||||
result.stateMutationAllowed = coordination.stateMutationAllowed;
|
||||
result.stateMutated = coordination.stateMutated;
|
||||
result.walletStateWritten = coordination.walletStateWritten;
|
||||
result.lifecycleReady = inputs.lifecycleReady;
|
||||
result.lifecycleStatus = inputs.lifecycleStatus;
|
||||
result.syncReady = inputs.syncReady;
|
||||
result.syncStatus = inputs.syncStatus;
|
||||
result.maxRefreshAgeSeconds = options.maxRefreshAgeSeconds;
|
||||
|
||||
if (coordination.fullNodeRefreshDelegated || coordination.route == LiteWalletRefreshRouteKind::FullNodeRpc) {
|
||||
return failReadiness(
|
||||
std::move(result),
|
||||
LiteWalletRefreshReadinessStatus::CoordinatorRejected,
|
||||
LiteWalletRefreshReadinessIssue::FullNodeRouteRejected,
|
||||
"full-node refresh reports are not eligible for lite UI refresh readiness");
|
||||
}
|
||||
|
||||
if (!coordination.ok) {
|
||||
return failReadiness(
|
||||
std::move(result),
|
||||
LiteWalletRefreshReadinessStatus::CoordinatorRejected,
|
||||
LiteWalletRefreshReadinessIssue::CoordinatorReportRejected,
|
||||
coordination.error.empty()
|
||||
? "lite app refresh coordinator report is not successful"
|
||||
: coordination.error);
|
||||
}
|
||||
|
||||
result.coordinatorReportAccepted = true;
|
||||
|
||||
if (!coordination.mapped || !coordination.planned || !coordination.executionReported ||
|
||||
coordination.successfulCommandCount == 0) {
|
||||
return failReadiness(
|
||||
std::move(result),
|
||||
LiteWalletRefreshReadinessStatus::CoordinatorRejected,
|
||||
LiteWalletRefreshReadinessIssue::CoordinatorReportIncomplete,
|
||||
"lite app refresh coordinator report is incomplete");
|
||||
}
|
||||
|
||||
if (coordinatorReportIsUnsafe(coordination)) {
|
||||
return failReadiness(
|
||||
std::move(result),
|
||||
LiteWalletRefreshReadinessStatus::UnsafeReport,
|
||||
LiteWalletRefreshReadinessIssue::CoordinatorReportUnsafe,
|
||||
"lite app refresh coordinator report is not a no-network dry-run report");
|
||||
}
|
||||
|
||||
if (options.requireLifecycleReady && !inputs.lifecycleReady) {
|
||||
return failReadiness(
|
||||
std::move(result),
|
||||
LiteWalletRefreshReadinessStatus::WaitingForLifecycle,
|
||||
LiteWalletRefreshReadinessIssue::LifecycleNotReady,
|
||||
statusMessageOrDefault(inputs.lifecycleStatus, "lite wallet lifecycle is not ready"));
|
||||
}
|
||||
|
||||
if (options.requireSyncReady && !inputs.syncReady) {
|
||||
return failReadiness(
|
||||
std::move(result),
|
||||
LiteWalletRefreshReadinessStatus::WaitingForSync,
|
||||
LiteWalletRefreshReadinessIssue::SyncNotReady,
|
||||
statusMessageOrDefault(inputs.syncStatus, "lite wallet sync is not ready"));
|
||||
}
|
||||
|
||||
if (options.requireFreshRefresh) {
|
||||
if (!inputs.freshness.haveSnapshotTime) {
|
||||
return failReadiness(
|
||||
std::move(result),
|
||||
LiteWalletRefreshReadinessStatus::Stale,
|
||||
LiteWalletRefreshReadinessIssue::RefreshTimestampMissing,
|
||||
"lite refresh snapshot time is not known");
|
||||
}
|
||||
|
||||
if (inputs.freshness.snapshotTimeSeconds > inputs.freshness.nowSeconds) {
|
||||
return failReadiness(
|
||||
std::move(result),
|
||||
LiteWalletRefreshReadinessStatus::Stale,
|
||||
LiteWalletRefreshReadinessIssue::RefreshTimestampInFuture,
|
||||
"lite refresh snapshot time is in the future");
|
||||
}
|
||||
|
||||
result.refreshAgeSeconds = inputs.freshness.nowSeconds - inputs.freshness.snapshotTimeSeconds;
|
||||
if (result.refreshAgeSeconds > options.maxRefreshAgeSeconds) {
|
||||
result.refreshStale = true;
|
||||
if (!options.allowStaleRefresh) {
|
||||
return failReadiness(
|
||||
std::move(result),
|
||||
LiteWalletRefreshReadinessStatus::Stale,
|
||||
LiteWalletRefreshReadinessIssue::RefreshStale,
|
||||
"lite refresh coordinator report is stale");
|
||||
}
|
||||
|
||||
result.staleRefreshAllowed = true;
|
||||
addIssue(result,
|
||||
LiteWalletRefreshReadinessIssue::StaleRefreshAllowed,
|
||||
"stale lite refresh coordinator report is allowed for reporting only");
|
||||
} else {
|
||||
result.refreshFresh = true;
|
||||
}
|
||||
} else {
|
||||
result.refreshFresh = true;
|
||||
}
|
||||
|
||||
result.ok = true;
|
||||
result.eligibleForFutureUiRefresh = true;
|
||||
result.status = LiteWalletRefreshReadinessStatus::EligibleDryRun;
|
||||
return result;
|
||||
}
|
||||
|
||||
LiteWalletRefreshReadinessPolicy::LiteWalletRefreshReadinessPolicy(
|
||||
LiteWalletRefreshReadinessPolicyOptions options)
|
||||
: options_(options)
|
||||
{
|
||||
}
|
||||
|
||||
LiteWalletRefreshReadinessResult LiteWalletRefreshReadinessPolicy::evaluate(
|
||||
const LiteWalletAppRefreshCoordinationResult& coordination,
|
||||
const LiteWalletRefreshReadinessInputs& inputs) const
|
||||
{
|
||||
return evaluateLiteWalletRefreshReadiness(coordination, inputs, options_);
|
||||
}
|
||||
|
||||
} // namespace dragonx::wallet
|
||||
@@ -1,106 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "lite_wallet_app_refresh_coordinator.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace dragonx::wallet {
|
||||
|
||||
enum class LiteWalletRefreshReadinessStatus {
|
||||
EligibleDryRun,
|
||||
CoordinatorRejected,
|
||||
UnsafeReport,
|
||||
WaitingForLifecycle,
|
||||
WaitingForSync,
|
||||
Stale,
|
||||
};
|
||||
|
||||
enum class LiteWalletRefreshReadinessIssue {
|
||||
CoordinatorReportRejected,
|
||||
CoordinatorReportIncomplete,
|
||||
CoordinatorReportUnsafe,
|
||||
FullNodeRouteRejected,
|
||||
LifecycleNotReady,
|
||||
SyncNotReady,
|
||||
RefreshTimestampMissing,
|
||||
RefreshTimestampInFuture,
|
||||
RefreshStale,
|
||||
StaleRefreshAllowed,
|
||||
};
|
||||
|
||||
struct LiteWalletRefreshFreshnessInput {
|
||||
bool haveSnapshotTime = false;
|
||||
std::uint64_t snapshotTimeSeconds = 0;
|
||||
std::uint64_t nowSeconds = 0;
|
||||
};
|
||||
|
||||
struct LiteWalletRefreshReadinessInputs {
|
||||
bool lifecycleReady = false;
|
||||
WalletBackendStatus lifecycleStatus;
|
||||
bool syncReady = false;
|
||||
WalletBackendStatus syncStatus;
|
||||
LiteWalletRefreshFreshnessInput freshness;
|
||||
};
|
||||
|
||||
struct LiteWalletRefreshReadinessPolicyOptions {
|
||||
bool requireLifecycleReady = true;
|
||||
bool requireSyncReady = true;
|
||||
bool requireFreshRefresh = true;
|
||||
bool allowStaleRefresh = false;
|
||||
std::uint64_t maxRefreshAgeSeconds = 120;
|
||||
};
|
||||
|
||||
struct LiteWalletRefreshReadinessIssueInfo {
|
||||
LiteWalletRefreshReadinessIssue issue = LiteWalletRefreshReadinessIssue::CoordinatorReportRejected;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
struct LiteWalletRefreshReadinessResult {
|
||||
bool ok = false;
|
||||
bool eligibleForFutureUiRefresh = false;
|
||||
bool coordinatorReportAccepted = false;
|
||||
bool dryRunOnly = true;
|
||||
bool noNetwork = true;
|
||||
bool stateMutationRequested = false;
|
||||
bool stateMutationAllowed = false;
|
||||
bool stateMutated = false;
|
||||
bool walletStateWritten = false;
|
||||
bool lifecycleReady = false;
|
||||
bool syncReady = false;
|
||||
bool refreshFresh = false;
|
||||
bool refreshStale = false;
|
||||
bool staleRefreshAllowed = false;
|
||||
|
||||
LiteWalletRefreshReadinessStatus status = LiteWalletRefreshReadinessStatus::CoordinatorRejected;
|
||||
LiteWalletRefreshRouteKind route = LiteWalletRefreshRouteKind::Unavailable;
|
||||
WalletBackendStatus lifecycleStatus;
|
||||
WalletBackendStatus syncStatus;
|
||||
std::uint64_t refreshAgeSeconds = 0;
|
||||
std::uint64_t maxRefreshAgeSeconds = 0;
|
||||
std::vector<LiteWalletRefreshReadinessIssueInfo> issues;
|
||||
std::string error;
|
||||
};
|
||||
|
||||
const char* liteWalletRefreshReadinessStatusName(LiteWalletRefreshReadinessStatus status);
|
||||
const char* liteWalletRefreshReadinessIssueName(LiteWalletRefreshReadinessIssue issue);
|
||||
|
||||
LiteWalletRefreshReadinessResult evaluateLiteWalletRefreshReadiness(
|
||||
const LiteWalletAppRefreshCoordinationResult& coordination,
|
||||
const LiteWalletRefreshReadinessInputs& inputs,
|
||||
LiteWalletRefreshReadinessPolicyOptions options = {});
|
||||
|
||||
class LiteWalletRefreshReadinessPolicy {
|
||||
public:
|
||||
explicit LiteWalletRefreshReadinessPolicy(LiteWalletRefreshReadinessPolicyOptions options = {});
|
||||
|
||||
LiteWalletRefreshReadinessResult evaluate(
|
||||
const LiteWalletAppRefreshCoordinationResult& coordination,
|
||||
const LiteWalletRefreshReadinessInputs& inputs) const;
|
||||
|
||||
private:
|
||||
LiteWalletRefreshReadinessPolicyOptions options_;
|
||||
};
|
||||
|
||||
} // namespace dragonx::wallet
|
||||
@@ -1,189 +0,0 @@
|
||||
#include "wallet/lite_wallet_refresh_service.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace dragonx::wallet {
|
||||
namespace {
|
||||
|
||||
WalletBackendStatus makeRefreshStatus(WalletBackendState state, std::string message)
|
||||
{
|
||||
WalletBackendStatus status;
|
||||
status.state = state;
|
||||
status.message = std::move(message);
|
||||
return status;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
LiteWalletGatewayRefreshAdapter::LiteWalletGatewayRefreshAdapter(LiteWalletGateway& gateway)
|
||||
: gateway_(gateway)
|
||||
{
|
||||
}
|
||||
|
||||
LiteWalletRefreshPlan LiteWalletGatewayRefreshAdapter::planRefresh(
|
||||
const LiteWalletRefreshRequest& request) const
|
||||
{
|
||||
return gateway_.planRefresh(request);
|
||||
}
|
||||
|
||||
LiteWalletRefreshResult LiteWalletGatewayRefreshAdapter::refresh(
|
||||
const LiteWalletRefreshRequest& request)
|
||||
{
|
||||
return gateway_.refresh(request);
|
||||
}
|
||||
|
||||
WalletBackendStatus LiteWalletGatewayRefreshAdapter::status() const
|
||||
{
|
||||
return gateway_.status();
|
||||
}
|
||||
|
||||
const char* liteWalletRefreshRouteKindName(LiteWalletRefreshRouteKind route)
|
||||
{
|
||||
switch (route) {
|
||||
case LiteWalletRefreshRouteKind::FullNodeRpc: return "FullNodeRpc";
|
||||
case LiteWalletRefreshRouteKind::LiteGateway: return "LiteGateway";
|
||||
case LiteWalletRefreshRouteKind::Unavailable: return "Unavailable";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
LiteWalletRefreshRouteKind liteWalletRefreshRouteForCapabilities(const WalletCapabilities& capabilities)
|
||||
{
|
||||
if (capabilities.fullNodeRpcAvailable) return LiteWalletRefreshRouteKind::FullNodeRpc;
|
||||
if (isLiteBuild(capabilities) && supportsLiteBackend(capabilities)) {
|
||||
return LiteWalletRefreshRouteKind::LiteGateway;
|
||||
}
|
||||
return LiteWalletRefreshRouteKind::Unavailable;
|
||||
}
|
||||
|
||||
LiteWalletRefreshService::LiteWalletRefreshService(WalletCapabilities capabilities,
|
||||
LiteWalletRefreshGateway* liteGateway,
|
||||
LiteWalletRefreshServiceOptions options)
|
||||
: capabilities_(capabilities), liteGateway_(liteGateway), options_(options)
|
||||
{
|
||||
}
|
||||
|
||||
LiteWalletRefreshRouteKind LiteWalletRefreshService::route() const
|
||||
{
|
||||
return liteWalletRefreshRouteForCapabilities(capabilities_);
|
||||
}
|
||||
|
||||
WalletBackendStatus LiteWalletRefreshService::status() const
|
||||
{
|
||||
const auto selectedRoute = route();
|
||||
if (selectedRoute == LiteWalletRefreshRouteKind::LiteGateway) {
|
||||
if (!liteGateway_) return statusForRoute(selectedRoute, "lite wallet gateway is not configured");
|
||||
return liteGateway_->status();
|
||||
}
|
||||
return statusForRoute(selectedRoute);
|
||||
}
|
||||
|
||||
LiteWalletRefreshServicePlan LiteWalletRefreshService::planRefresh(
|
||||
const LiteWalletRefreshRequest& request) const
|
||||
{
|
||||
LiteWalletRefreshServicePlan plan;
|
||||
plan.route = route();
|
||||
|
||||
if (plan.route == LiteWalletRefreshRouteKind::FullNodeRpc) {
|
||||
plan.ok = true;
|
||||
plan.fullNodeRefreshDelegated = true;
|
||||
plan.status = statusForRoute(plan.route);
|
||||
return plan;
|
||||
}
|
||||
|
||||
if (plan.route == LiteWalletRefreshRouteKind::Unavailable) {
|
||||
plan.status = statusForRoute(plan.route);
|
||||
plan.error = plan.status.message;
|
||||
return plan;
|
||||
}
|
||||
|
||||
if (!liteGateway_) {
|
||||
plan.status = statusForRoute(plan.route, "lite wallet gateway is not configured");
|
||||
plan.error = plan.status.message;
|
||||
return plan;
|
||||
}
|
||||
|
||||
plan.liteGatewayConfigured = true;
|
||||
plan.liteGatewayExecutionAllowed = options_.allowLiteGatewayRefresh;
|
||||
plan.liteGatewayPlan = liteGateway_->planRefresh(request);
|
||||
if (!plan.liteGatewayPlan.ok) {
|
||||
plan.status = makeRefreshStatus(WalletBackendState::Error, plan.liteGatewayPlan.error);
|
||||
plan.error = plan.status.message;
|
||||
return plan;
|
||||
}
|
||||
|
||||
plan.ok = true;
|
||||
plan.status = liteGateway_->status();
|
||||
return plan;
|
||||
}
|
||||
|
||||
LiteWalletRefreshServiceResult LiteWalletRefreshService::refresh(
|
||||
const LiteWalletRefreshRequest& request)
|
||||
{
|
||||
auto plan = planRefresh(request);
|
||||
if (!plan.ok) return resultFromPlan(plan);
|
||||
|
||||
if (plan.route == LiteWalletRefreshRouteKind::FullNodeRpc) {
|
||||
auto result = resultFromPlan(plan);
|
||||
result.ok = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!plan.liteGatewayExecutionAllowed) {
|
||||
plan.status = makeRefreshStatus(
|
||||
WalletBackendState::Unavailable,
|
||||
"lite wallet refresh gateway execution is disabled");
|
||||
plan.error = plan.status.message;
|
||||
return resultFromPlan(plan);
|
||||
}
|
||||
|
||||
LiteWalletRefreshServiceResult result;
|
||||
result.plan = plan;
|
||||
result.liteGatewayCalled = true;
|
||||
result.liteGatewayResult = liteGateway_->refresh(request);
|
||||
result.attempted = result.liteGatewayResult.attempted;
|
||||
result.bundle = result.liteGatewayResult.bundle;
|
||||
result.status = result.liteGatewayResult.status;
|
||||
result.error = result.liteGatewayResult.error;
|
||||
result.ok = result.liteGatewayResult.ok;
|
||||
return result;
|
||||
}
|
||||
|
||||
WalletBackendStatus LiteWalletRefreshService::statusForRoute(
|
||||
LiteWalletRefreshRouteKind selectedRoute,
|
||||
const std::string& detail) const
|
||||
{
|
||||
switch (selectedRoute) {
|
||||
case LiteWalletRefreshRouteKind::FullNodeRpc:
|
||||
return makeRefreshStatus(
|
||||
WalletBackendState::Disconnected,
|
||||
detail.empty()
|
||||
? "full-node refresh remains handled by existing NetworkRefreshService"
|
||||
: detail);
|
||||
case LiteWalletRefreshRouteKind::LiteGateway:
|
||||
return makeRefreshStatus(
|
||||
detail.empty() ? WalletBackendState::Disconnected : WalletBackendState::Unavailable,
|
||||
detail.empty()
|
||||
? "lite wallet refresh route is ready for gateway planning"
|
||||
: detail);
|
||||
case LiteWalletRefreshRouteKind::Unavailable:
|
||||
return makeRefreshStatus(
|
||||
WalletBackendState::Unavailable,
|
||||
detail.empty() ? "lite backend is not linked" : detail);
|
||||
}
|
||||
|
||||
return makeRefreshStatus(WalletBackendState::Unavailable, "unknown wallet refresh route");
|
||||
}
|
||||
|
||||
LiteWalletRefreshServiceResult LiteWalletRefreshService::resultFromPlan(
|
||||
const LiteWalletRefreshServicePlan& plan) const
|
||||
{
|
||||
LiteWalletRefreshServiceResult result;
|
||||
result.plan = plan;
|
||||
result.fullNodeRefreshDelegated = plan.fullNodeRefreshDelegated;
|
||||
result.status = plan.status;
|
||||
result.error = plan.error;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace dragonx::wallet
|
||||
@@ -1,92 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "lite_wallet_gateway.h"
|
||||
#include "wallet_backend.h"
|
||||
#include "wallet_capabilities.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace dragonx::wallet {
|
||||
|
||||
enum class LiteWalletRefreshRouteKind {
|
||||
FullNodeRpc,
|
||||
LiteGateway,
|
||||
Unavailable,
|
||||
};
|
||||
|
||||
struct LiteWalletRefreshServiceOptions {
|
||||
bool allowLiteGatewayRefresh = false;
|
||||
};
|
||||
|
||||
struct LiteWalletRefreshServicePlan {
|
||||
bool ok = false;
|
||||
LiteWalletRefreshRouteKind route = LiteWalletRefreshRouteKind::Unavailable;
|
||||
bool fullNodeRefreshDelegated = false;
|
||||
bool liteGatewayConfigured = false;
|
||||
bool liteGatewayExecutionAllowed = false;
|
||||
LiteWalletRefreshPlan liteGatewayPlan;
|
||||
WalletBackendStatus status;
|
||||
std::string error;
|
||||
};
|
||||
|
||||
struct LiteWalletRefreshServiceResult {
|
||||
bool ok = false;
|
||||
bool attempted = false;
|
||||
bool fullNodeRefreshDelegated = false;
|
||||
bool liteGatewayCalled = false;
|
||||
LiteWalletRefreshServicePlan plan;
|
||||
LiteWalletRefreshResult liteGatewayResult;
|
||||
LiteWalletRefreshBundle bundle;
|
||||
WalletBackendStatus status;
|
||||
std::string error;
|
||||
};
|
||||
|
||||
class LiteWalletRefreshGateway {
|
||||
public:
|
||||
virtual ~LiteWalletRefreshGateway() = default;
|
||||
|
||||
virtual LiteWalletRefreshPlan planRefresh(const LiteWalletRefreshRequest& request) const = 0;
|
||||
virtual LiteWalletRefreshResult refresh(const LiteWalletRefreshRequest& request) = 0;
|
||||
virtual WalletBackendStatus status() const = 0;
|
||||
};
|
||||
|
||||
class LiteWalletGatewayRefreshAdapter final : public LiteWalletRefreshGateway {
|
||||
public:
|
||||
explicit LiteWalletGatewayRefreshAdapter(LiteWalletGateway& gateway);
|
||||
|
||||
LiteWalletRefreshPlan planRefresh(const LiteWalletRefreshRequest& request) const override;
|
||||
LiteWalletRefreshResult refresh(const LiteWalletRefreshRequest& request) override;
|
||||
WalletBackendStatus status() const override;
|
||||
|
||||
private:
|
||||
LiteWalletGateway& gateway_;
|
||||
};
|
||||
|
||||
const char* liteWalletRefreshRouteKindName(LiteWalletRefreshRouteKind route);
|
||||
LiteWalletRefreshRouteKind liteWalletRefreshRouteForCapabilities(const WalletCapabilities& capabilities);
|
||||
|
||||
class LiteWalletRefreshService {
|
||||
public:
|
||||
LiteWalletRefreshService(WalletCapabilities capabilities,
|
||||
LiteWalletRefreshGateway* liteGateway = nullptr,
|
||||
LiteWalletRefreshServiceOptions options = {});
|
||||
|
||||
const WalletCapabilities& capabilities() const { return capabilities_; }
|
||||
const LiteWalletRefreshServiceOptions& options() const { return options_; }
|
||||
|
||||
LiteWalletRefreshRouteKind route() const;
|
||||
WalletBackendStatus status() const;
|
||||
LiteWalletRefreshServicePlan planRefresh(const LiteWalletRefreshRequest& request) const;
|
||||
LiteWalletRefreshServiceResult refresh(const LiteWalletRefreshRequest& request);
|
||||
|
||||
private:
|
||||
WalletBackendStatus statusForRoute(LiteWalletRefreshRouteKind route,
|
||||
const std::string& detail = {}) const;
|
||||
LiteWalletRefreshServiceResult resultFromPlan(const LiteWalletRefreshServicePlan& plan) const;
|
||||
|
||||
WalletCapabilities capabilities_;
|
||||
LiteWalletRefreshGateway* liteGateway_ = nullptr;
|
||||
LiteWalletRefreshServiceOptions options_;
|
||||
};
|
||||
|
||||
} // namespace dragonx::wallet
|
||||
@@ -34,7 +34,6 @@ LiteWalletServerLifecycleReadinessResult stoppedResult(
|
||||
addIssue(result, issue, std::move(message));
|
||||
result.error = result.issues.back().message;
|
||||
result.lifecycleStatus = WalletBackendStatus{WalletBackendState::Unavailable, result.error, {}, {}, 0.0};
|
||||
result.syncLifecycleInput.status = result.lifecycleStatus;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -381,17 +380,9 @@ LiteWalletServerLifecycleReadinessResult evaluateLiteWalletServerLifecycleReadin
|
||||
result.futureLifecycleCouldBeEnabled = true;
|
||||
result.lifecycleReportCouldFeedSyncPlanners = true;
|
||||
result.lifecycleStatus = readyLifecycleStatus(result.selectedServerDisplay);
|
||||
result.syncLifecycleInput.ready = true;
|
||||
result.syncLifecycleInput.status = result.lifecycleStatus;
|
||||
return result;
|
||||
}
|
||||
|
||||
LiteWalletSyncAppRefreshLifecycleInput liteWalletSyncLifecycleInputFromServerLifecycleReadiness(
|
||||
const LiteWalletServerLifecycleReadinessResult& result)
|
||||
{
|
||||
return result.syncLifecycleInput;
|
||||
}
|
||||
|
||||
LiteWalletServerLifecycleReadinessPlanner::LiteWalletServerLifecycleReadinessPlanner(
|
||||
LiteWalletServerLifecycleReadinessOptions options)
|
||||
: options_(options)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "lite_wallet_lifecycle_service.h"
|
||||
#include "lite_wallet_sync_app_refresh_integration.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
@@ -163,7 +162,6 @@ struct LiteWalletServerLifecycleReadinessResult {
|
||||
LiteWalletSelectedServerDisplayReport selectedServerDisplay;
|
||||
LiteWalletServerSelectionPersistencePlan persistencePlan;
|
||||
LiteWalletLifecycleUiRequestPlan requestPlan;
|
||||
LiteWalletSyncAppRefreshLifecycleInput syncLifecycleInput;
|
||||
WalletBackendStatus lifecycleStatus;
|
||||
std::vector<LiteWalletServerLifecycleReadinessIssueInfo> issues;
|
||||
std::string error;
|
||||
@@ -179,8 +177,6 @@ const char* liteWalletSelectedServerDisplayStatusName(
|
||||
LiteWalletServerLifecycleReadinessResult evaluateLiteWalletServerLifecycleReadiness(
|
||||
const LiteWalletServerLifecycleReadinessInput& input,
|
||||
LiteWalletServerLifecycleReadinessOptions options = {});
|
||||
LiteWalletSyncAppRefreshLifecycleInput liteWalletSyncLifecycleInputFromServerLifecycleReadiness(
|
||||
const LiteWalletServerLifecycleReadinessResult& result);
|
||||
|
||||
class LiteWalletServerLifecycleReadinessPlanner {
|
||||
public:
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
#include "wallet/lite_wallet_state_apply_executor.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace dragonx::wallet {
|
||||
namespace {
|
||||
|
||||
void addIssue(LiteWalletStateApplyExecutionResult& result,
|
||||
LiteWalletStateApplyExecutionIssue issue,
|
||||
std::string message)
|
||||
{
|
||||
result.issues.push_back(LiteWalletStateApplyExecutionIssueInfo{issue, std::move(message)});
|
||||
}
|
||||
|
||||
std::size_t countPlannedChanges(const LiteWalletStateApplyPlan& plan)
|
||||
{
|
||||
std::size_t count = 0;
|
||||
for (const auto& fieldPlan : plan.fieldPlans) {
|
||||
if (fieldPlan.wouldChange) ++count;
|
||||
}
|
||||
for (const auto& collectionPlan : plan.collectionPlans) {
|
||||
if (collectionPlan.wouldReplace) ++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
LiteWalletStateApplyExecutionResult baseResult(const LiteWalletStateApplyPlan& plan,
|
||||
LiteWalletStateApplyExecutorOptions options)
|
||||
{
|
||||
LiteWalletStateApplyExecutionResult result;
|
||||
result.stateMutationRequested = options.requestStateMutation;
|
||||
result.stateMutationAllowed = false;
|
||||
result.applyImplemented = false;
|
||||
result.fieldPlanCount = plan.fieldPlans.size();
|
||||
result.collectionPlanCount = plan.collectionPlans.size();
|
||||
result.plannedChangeCount = countPlannedChanges(plan);
|
||||
result.planIssueCount = plan.issues.size();
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const char* liteWalletStateApplyExecutionStatusName(LiteWalletStateApplyExecutionStatus status)
|
||||
{
|
||||
switch (status) {
|
||||
case LiteWalletStateApplyExecutionStatus::Disabled: return "Disabled";
|
||||
case LiteWalletStateApplyExecutionStatus::Rejected: return "Rejected";
|
||||
case LiteWalletStateApplyExecutionStatus::ImplementationMissing: return "ImplementationMissing";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
const char* liteWalletStateApplyExecutionIssueName(LiteWalletStateApplyExecutionIssue issue)
|
||||
{
|
||||
switch (issue) {
|
||||
case LiteWalletStateApplyExecutionIssue::InvalidPlan: return "InvalidPlan";
|
||||
case LiteWalletStateApplyExecutionIssue::MutablePlanRejected: return "MutablePlanRejected";
|
||||
case LiteWalletStateApplyExecutionIssue::StateMutationDisabled: return "StateMutationDisabled";
|
||||
case LiteWalletStateApplyExecutionIssue::StateMutationImplementationMissing: return "StateMutationImplementationMissing";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
LiteWalletStateApplyExecutionResult executeLiteWalletStateApplyPlan(
|
||||
const LiteWalletStateApplyPlan& plan,
|
||||
LiteWalletStateApplyExecutorOptions options)
|
||||
{
|
||||
auto result = baseResult(plan, options);
|
||||
|
||||
if (!plan.ok) {
|
||||
result.status = LiteWalletStateApplyExecutionStatus::Rejected;
|
||||
addIssue(result,
|
||||
LiteWalletStateApplyExecutionIssue::InvalidPlan,
|
||||
"lite WalletState apply plan is not valid");
|
||||
result.error = plan.error.empty() ? result.issues.back().message : plan.error;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!plan.dryRunOnly || plan.applyImplemented || plan.stateMutationAllowed) {
|
||||
result.status = LiteWalletStateApplyExecutionStatus::Rejected;
|
||||
addIssue(result,
|
||||
LiteWalletStateApplyExecutionIssue::MutablePlanRejected,
|
||||
"lite WalletState apply executor accepts dry-run-only plans only");
|
||||
result.error = result.issues.back().message;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.planAccepted = true;
|
||||
|
||||
if (options.requestStateMutation) {
|
||||
result.status = LiteWalletStateApplyExecutionStatus::ImplementationMissing;
|
||||
addIssue(result,
|
||||
LiteWalletStateApplyExecutionIssue::StateMutationImplementationMissing,
|
||||
"real lite WalletState application requires a future explicit implementation");
|
||||
result.error = result.issues.back().message;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.ok = true;
|
||||
result.status = LiteWalletStateApplyExecutionStatus::Disabled;
|
||||
addIssue(result,
|
||||
LiteWalletStateApplyExecutionIssue::StateMutationDisabled,
|
||||
"lite WalletState application is disabled; dry-run plan was accepted for reporting only");
|
||||
return result;
|
||||
}
|
||||
|
||||
LiteWalletStateApplyExecutor::LiteWalletStateApplyExecutor(LiteWalletStateApplyExecutorOptions options)
|
||||
: options_(options)
|
||||
{
|
||||
}
|
||||
|
||||
LiteWalletStateApplyExecutionResult LiteWalletStateApplyExecutor::execute(
|
||||
const LiteWalletStateApplyPlan& plan) const
|
||||
{
|
||||
return executeLiteWalletStateApplyPlan(plan, options_);
|
||||
}
|
||||
|
||||
} // namespace dragonx::wallet
|
||||
@@ -1,71 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "lite_wallet_state_apply_plan.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace dragonx::wallet {
|
||||
|
||||
enum class LiteWalletStateApplyExecutionStatus {
|
||||
Disabled,
|
||||
Rejected,
|
||||
ImplementationMissing,
|
||||
};
|
||||
|
||||
enum class LiteWalletStateApplyExecutionIssue {
|
||||
InvalidPlan,
|
||||
MutablePlanRejected,
|
||||
StateMutationDisabled,
|
||||
StateMutationImplementationMissing,
|
||||
};
|
||||
|
||||
struct LiteWalletStateApplyExecutorOptions {
|
||||
bool requestStateMutation = false;
|
||||
};
|
||||
|
||||
struct LiteWalletStateApplyExecutionIssueInfo {
|
||||
LiteWalletStateApplyExecutionIssue issue = LiteWalletStateApplyExecutionIssue::StateMutationDisabled;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
struct LiteWalletStateApplyExecutionResult {
|
||||
bool ok = false;
|
||||
bool planAccepted = false;
|
||||
bool attempted = false;
|
||||
bool applied = false;
|
||||
bool stateMutated = false;
|
||||
bool dryRunOnly = true;
|
||||
bool noNetwork = true;
|
||||
bool stateMutationRequested = false;
|
||||
bool stateMutationAllowed = false;
|
||||
bool applyImplemented = false;
|
||||
|
||||
LiteWalletStateApplyExecutionStatus status = LiteWalletStateApplyExecutionStatus::Disabled;
|
||||
std::size_t fieldPlanCount = 0;
|
||||
std::size_t collectionPlanCount = 0;
|
||||
std::size_t plannedChangeCount = 0;
|
||||
std::size_t planIssueCount = 0;
|
||||
std::vector<LiteWalletStateApplyExecutionIssueInfo> issues;
|
||||
std::string error;
|
||||
};
|
||||
|
||||
const char* liteWalletStateApplyExecutionStatusName(LiteWalletStateApplyExecutionStatus status);
|
||||
const char* liteWalletStateApplyExecutionIssueName(LiteWalletStateApplyExecutionIssue issue);
|
||||
|
||||
LiteWalletStateApplyExecutionResult executeLiteWalletStateApplyPlan(
|
||||
const LiteWalletStateApplyPlan& plan,
|
||||
LiteWalletStateApplyExecutorOptions options = {});
|
||||
|
||||
class LiteWalletStateApplyExecutor {
|
||||
public:
|
||||
explicit LiteWalletStateApplyExecutor(LiteWalletStateApplyExecutorOptions options = {});
|
||||
|
||||
LiteWalletStateApplyExecutionResult execute(const LiteWalletStateApplyPlan& plan) const;
|
||||
|
||||
private:
|
||||
LiteWalletStateApplyExecutorOptions options_;
|
||||
};
|
||||
|
||||
} // namespace dragonx::wallet
|
||||
@@ -1,405 +0,0 @@
|
||||
#include "wallet/lite_wallet_state_apply_plan.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
namespace dragonx::wallet {
|
||||
namespace {
|
||||
|
||||
constexpr double kZatoshisPerCoin = 100000000.0;
|
||||
|
||||
std::string stringValue(const std::string& value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
std::string intValue(std::int64_t value)
|
||||
{
|
||||
return std::to_string(value);
|
||||
}
|
||||
|
||||
std::string uintValue(std::uint64_t value)
|
||||
{
|
||||
return std::to_string(value);
|
||||
}
|
||||
|
||||
std::string doubleValue(double value)
|
||||
{
|
||||
std::ostringstream output;
|
||||
output << value;
|
||||
return output.str();
|
||||
}
|
||||
|
||||
std::string boolValue(bool value)
|
||||
{
|
||||
return value ? "true" : "false";
|
||||
}
|
||||
|
||||
std::uint64_t coinsToZatoshis(double coins)
|
||||
{
|
||||
if (coins <= 0.0) return 0;
|
||||
const double zatoshis = std::round(coins * kZatoshisPerCoin);
|
||||
const double maxValue = static_cast<double>(std::numeric_limits<std::uint64_t>::max());
|
||||
if (zatoshis >= maxValue) return std::numeric_limits<std::uint64_t>::max();
|
||||
return static_cast<std::uint64_t>(zatoshis);
|
||||
}
|
||||
|
||||
bool modelHasAnySection(const LiteWalletAppRefreshModel& model)
|
||||
{
|
||||
return model.hasChainInfo || model.hasHeight || model.hasBalance || model.hasAddresses ||
|
||||
model.hasSpendableOutputs || model.hasTransactions || model.hasSyncStatus;
|
||||
}
|
||||
|
||||
void addIssue(LiteWalletStateApplyPlan& plan,
|
||||
LiteWalletStateApplyIssue issue,
|
||||
std::string message)
|
||||
{
|
||||
plan.issues.push_back(LiteWalletStateApplyIssueInfo{issue, std::move(message)});
|
||||
}
|
||||
|
||||
void addFieldPlan(LiteWalletStateApplyPlan& plan,
|
||||
LiteWalletStateApplySection section,
|
||||
const std::string& fieldName,
|
||||
std::string currentValue,
|
||||
std::string proposedValue)
|
||||
{
|
||||
LiteWalletStateApplyFieldPlan fieldPlan;
|
||||
fieldPlan.section = section;
|
||||
fieldPlan.fieldName = fieldName;
|
||||
fieldPlan.currentValue = std::move(currentValue);
|
||||
fieldPlan.proposedValue = std::move(proposedValue);
|
||||
fieldPlan.wouldChange = fieldPlan.currentValue != fieldPlan.proposedValue;
|
||||
fieldPlan.action = fieldPlan.wouldChange
|
||||
? LiteWalletStateApplyAction::SetField
|
||||
: LiteWalletStateApplyAction::Noop;
|
||||
if (fieldPlan.wouldChange) plan.wouldChangeWalletState = true;
|
||||
plan.fieldPlans.push_back(std::move(fieldPlan));
|
||||
}
|
||||
|
||||
void addCollectionPlan(LiteWalletStateApplyPlan& plan,
|
||||
LiteWalletStateApplySection section,
|
||||
std::string collectionName,
|
||||
std::size_t currentCount,
|
||||
std::size_t proposedCount,
|
||||
bool hasWalletStateTarget,
|
||||
bool wouldReplace)
|
||||
{
|
||||
LiteWalletStateApplyCollectionPlan collectionPlan;
|
||||
collectionPlan.section = section;
|
||||
collectionPlan.collectionName = std::move(collectionName);
|
||||
collectionPlan.currentCount = currentCount;
|
||||
collectionPlan.proposedCount = proposedCount;
|
||||
collectionPlan.hasWalletStateTarget = hasWalletStateTarget;
|
||||
collectionPlan.wouldReplace = hasWalletStateTarget && wouldReplace;
|
||||
if (!hasWalletStateTarget) {
|
||||
collectionPlan.action = LiteWalletStateApplyAction::InspectOnly;
|
||||
} else {
|
||||
collectionPlan.action = collectionPlan.wouldReplace
|
||||
? LiteWalletStateApplyAction::ReplaceCollection
|
||||
: LiteWalletStateApplyAction::Noop;
|
||||
}
|
||||
if (collectionPlan.wouldReplace) plan.wouldChangeWalletState = true;
|
||||
plan.collectionPlans.push_back(std::move(collectionPlan));
|
||||
}
|
||||
|
||||
std::vector<std::string> mappedAddresses(const LiteWalletAppRefreshModel& model,
|
||||
LiteWalletAppAddressKind kind)
|
||||
{
|
||||
std::vector<std::string> addresses;
|
||||
for (const auto& address : model.addresses) {
|
||||
if (address.kind == kind) addresses.push_back(address.address);
|
||||
}
|
||||
return addresses;
|
||||
}
|
||||
|
||||
std::vector<std::string> mappedAddressStrings(const LiteWalletAppRefreshModel& model)
|
||||
{
|
||||
std::vector<std::string> addresses;
|
||||
addresses.reserve(model.addresses.size());
|
||||
for (const auto& address : model.addresses) addresses.push_back(address.address);
|
||||
return addresses;
|
||||
}
|
||||
|
||||
std::vector<std::string> stateAddressStrings(const std::vector<dragonx::AddressInfo>& addresses)
|
||||
{
|
||||
std::vector<std::string> values;
|
||||
values.reserve(addresses.size());
|
||||
for (const auto& address : addresses) values.push_back(address.address);
|
||||
return values;
|
||||
}
|
||||
|
||||
std::vector<std::string> mappedTransactionIds(const LiteWalletAppRefreshModel& model)
|
||||
{
|
||||
std::vector<std::string> txids;
|
||||
txids.reserve(model.transactions.size());
|
||||
for (const auto& transaction : model.transactions) txids.push_back(transaction.txid);
|
||||
return txids;
|
||||
}
|
||||
|
||||
std::vector<std::string> stateTransactionIds(const std::vector<dragonx::TransactionInfo>& transactions)
|
||||
{
|
||||
std::vector<std::string> txids;
|
||||
txids.reserve(transactions.size());
|
||||
for (const auto& transaction : transactions) txids.push_back(transaction.txid);
|
||||
return txids;
|
||||
}
|
||||
|
||||
void addChainInfoPlans(LiteWalletStateApplyPlan& plan,
|
||||
const LiteWalletAppRefreshModel& model,
|
||||
const dragonx::WalletState& state)
|
||||
{
|
||||
if (!model.hasChainInfo) return;
|
||||
plan.hasChainInfo = true;
|
||||
|
||||
if (model.chain.longestChain) {
|
||||
addFieldPlan(plan,
|
||||
LiteWalletStateApplySection::ChainInfo,
|
||||
"longestchain",
|
||||
intValue(state.longestchain),
|
||||
intValue(*model.chain.longestChain));
|
||||
}
|
||||
if (model.chain.notarized) {
|
||||
addFieldPlan(plan,
|
||||
LiteWalletStateApplySection::ChainInfo,
|
||||
"notarized",
|
||||
intValue(state.notarized),
|
||||
intValue(*model.chain.notarized));
|
||||
}
|
||||
if (model.chain.chainName) {
|
||||
addFieldPlan(plan,
|
||||
LiteWalletStateApplySection::ChainInfo,
|
||||
"chain_name",
|
||||
stringValue(state.mining.chain),
|
||||
stringValue(*model.chain.chainName));
|
||||
}
|
||||
}
|
||||
|
||||
void addHeightPlans(LiteWalletStateApplyPlan& plan,
|
||||
const LiteWalletAppRefreshModel& model,
|
||||
const dragonx::WalletState& state)
|
||||
{
|
||||
if (!model.hasHeight) return;
|
||||
plan.hasHeight = true;
|
||||
addFieldPlan(plan,
|
||||
LiteWalletStateApplySection::Height,
|
||||
"sync.blocks",
|
||||
intValue(state.sync.blocks),
|
||||
intValue(model.height.height));
|
||||
}
|
||||
|
||||
void addBalancePlans(LiteWalletStateApplyPlan& plan,
|
||||
const LiteWalletAppRefreshModel& model,
|
||||
const dragonx::WalletState& state)
|
||||
{
|
||||
if (!model.hasBalance) return;
|
||||
plan.hasBalance = true;
|
||||
addFieldPlan(plan,
|
||||
LiteWalletStateApplySection::Balance,
|
||||
"privateBalanceZatoshis",
|
||||
uintValue(coinsToZatoshis(state.privateBalance)),
|
||||
uintValue(model.balance.shieldedZatoshis));
|
||||
addFieldPlan(plan,
|
||||
LiteWalletStateApplySection::Balance,
|
||||
"transparentBalanceZatoshis",
|
||||
uintValue(coinsToZatoshis(state.transparentBalance)),
|
||||
uintValue(model.balance.transparentZatoshis));
|
||||
addFieldPlan(plan,
|
||||
LiteWalletStateApplySection::Balance,
|
||||
"totalBalanceZatoshis",
|
||||
uintValue(coinsToZatoshis(state.totalBalance)),
|
||||
uintValue(model.balance.totalZatoshis));
|
||||
addFieldPlan(plan,
|
||||
LiteWalletStateApplySection::Balance,
|
||||
"unconfirmedBalanceZatoshis",
|
||||
uintValue(coinsToZatoshis(state.unconfirmedBalance)),
|
||||
uintValue(model.balance.unconfirmedZatoshis));
|
||||
}
|
||||
|
||||
void addAddressPlans(LiteWalletStateApplyPlan& plan,
|
||||
const LiteWalletAppRefreshModel& model,
|
||||
const dragonx::WalletState& state)
|
||||
{
|
||||
if (!model.hasAddresses) return;
|
||||
plan.hasAddresses = true;
|
||||
|
||||
const auto proposedShielded = mappedAddresses(model, LiteWalletAppAddressKind::Shielded);
|
||||
const auto proposedTransparent = mappedAddresses(model, LiteWalletAppAddressKind::Transparent);
|
||||
const auto proposedCombined = mappedAddressStrings(model);
|
||||
const auto currentShielded = stateAddressStrings(state.z_addresses);
|
||||
const auto currentTransparent = stateAddressStrings(state.t_addresses);
|
||||
const auto currentCombined = stateAddressStrings(state.addresses);
|
||||
|
||||
addCollectionPlan(plan,
|
||||
LiteWalletStateApplySection::Addresses,
|
||||
"z_addresses",
|
||||
currentShielded.size(),
|
||||
proposedShielded.size(),
|
||||
true,
|
||||
currentShielded != proposedShielded);
|
||||
addCollectionPlan(plan,
|
||||
LiteWalletStateApplySection::Addresses,
|
||||
"t_addresses",
|
||||
currentTransparent.size(),
|
||||
proposedTransparent.size(),
|
||||
true,
|
||||
currentTransparent != proposedTransparent);
|
||||
addCollectionPlan(plan,
|
||||
LiteWalletStateApplySection::Addresses,
|
||||
"addresses",
|
||||
currentCombined.size(),
|
||||
proposedCombined.size(),
|
||||
true,
|
||||
currentCombined != proposedCombined);
|
||||
|
||||
const auto unknownSpendability = std::any_of(model.addresses.begin(), model.addresses.end(),
|
||||
[](const LiteWalletAppAddressModel& address) { return !address.spendabilityKnown; });
|
||||
if (unknownSpendability) {
|
||||
addIssue(plan,
|
||||
LiteWalletStateApplyIssue::AddressSpendabilityUnknown,
|
||||
"lite address rows do not yet carry wallet spendability policy");
|
||||
}
|
||||
}
|
||||
|
||||
void addSpendableOutputPlans(LiteWalletStateApplyPlan& plan,
|
||||
const LiteWalletAppRefreshModel& model)
|
||||
{
|
||||
if (!model.hasSpendableOutputs) return;
|
||||
plan.hasSpendableOutputs = true;
|
||||
addCollectionPlan(plan,
|
||||
LiteWalletStateApplySection::SpendableOutputs,
|
||||
"spendableOutputs",
|
||||
0,
|
||||
model.spendableOutputs.size(),
|
||||
false,
|
||||
false);
|
||||
addIssue(plan,
|
||||
LiteWalletStateApplyIssue::SpendableOutputsHaveNoWalletStateTarget,
|
||||
"lite spendable outputs remain source-only until an app apply target is designed");
|
||||
}
|
||||
|
||||
void addTransactionPlans(LiteWalletStateApplyPlan& plan,
|
||||
const LiteWalletAppRefreshModel& model,
|
||||
const dragonx::WalletState& state)
|
||||
{
|
||||
if (!model.hasTransactions) return;
|
||||
plan.hasTransactions = true;
|
||||
const auto proposedTxids = mappedTransactionIds(model);
|
||||
const auto currentTxids = stateTransactionIds(state.transactions);
|
||||
addCollectionPlan(plan,
|
||||
LiteWalletStateApplySection::Transactions,
|
||||
"transactions",
|
||||
currentTxids.size(),
|
||||
proposedTxids.size(),
|
||||
true,
|
||||
currentTxids != proposedTxids);
|
||||
}
|
||||
|
||||
void addSyncPlans(LiteWalletStateApplyPlan& plan,
|
||||
const LiteWalletAppRefreshModel& model,
|
||||
const dragonx::WalletState& state)
|
||||
{
|
||||
if (!model.hasSyncStatus) return;
|
||||
plan.hasSyncStatus = true;
|
||||
addFieldPlan(plan,
|
||||
LiteWalletStateApplySection::SyncStatus,
|
||||
"sync.blocks",
|
||||
intValue(state.sync.blocks),
|
||||
uintValue(model.sync.walletHeight));
|
||||
addFieldPlan(plan,
|
||||
LiteWalletStateApplySection::SyncStatus,
|
||||
"sync.headers",
|
||||
intValue(state.sync.headers),
|
||||
uintValue(model.sync.chainHeight));
|
||||
addFieldPlan(plan,
|
||||
LiteWalletStateApplySection::SyncStatus,
|
||||
"sync.verification_progress",
|
||||
doubleValue(state.sync.verification_progress),
|
||||
doubleValue(model.sync.progress));
|
||||
addFieldPlan(plan,
|
||||
LiteWalletStateApplySection::SyncStatus,
|
||||
"sync.syncing",
|
||||
boolValue(state.sync.syncing),
|
||||
boolValue(!model.sync.complete));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const char* liteWalletStateApplySectionName(LiteWalletStateApplySection section)
|
||||
{
|
||||
switch (section) {
|
||||
case LiteWalletStateApplySection::ChainInfo: return "ChainInfo";
|
||||
case LiteWalletStateApplySection::Height: return "Height";
|
||||
case LiteWalletStateApplySection::Balance: return "Balance";
|
||||
case LiteWalletStateApplySection::Addresses: return "Addresses";
|
||||
case LiteWalletStateApplySection::SpendableOutputs: return "SpendableOutputs";
|
||||
case LiteWalletStateApplySection::Transactions: return "Transactions";
|
||||
case LiteWalletStateApplySection::SyncStatus: return "SyncStatus";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
const char* liteWalletStateApplyActionName(LiteWalletStateApplyAction action)
|
||||
{
|
||||
switch (action) {
|
||||
case LiteWalletStateApplyAction::Noop: return "Noop";
|
||||
case LiteWalletStateApplyAction::SetField: return "SetField";
|
||||
case LiteWalletStateApplyAction::ReplaceCollection: return "ReplaceCollection";
|
||||
case LiteWalletStateApplyAction::InspectOnly: return "InspectOnly";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
const char* liteWalletStateApplyIssueName(LiteWalletStateApplyIssue issue)
|
||||
{
|
||||
switch (issue) {
|
||||
case LiteWalletStateApplyIssue::EmptyModel: return "EmptyModel";
|
||||
case LiteWalletStateApplyIssue::IncompleteModel: return "IncompleteModel";
|
||||
case LiteWalletStateApplyIssue::AddressSpendabilityUnknown: return "AddressSpendabilityUnknown";
|
||||
case LiteWalletStateApplyIssue::SpendableOutputsHaveNoWalletStateTarget: return "SpendableOutputsHaveNoWalletStateTarget";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
LiteWalletStateApplyPlan planLiteWalletStateApply(const LiteWalletAppRefreshModel& model,
|
||||
const dragonx::WalletState& state)
|
||||
{
|
||||
LiteWalletStateApplyPlan plan;
|
||||
plan.sourceComplete = model.complete;
|
||||
|
||||
if (!modelHasAnySection(model)) {
|
||||
addIssue(plan,
|
||||
LiteWalletStateApplyIssue::EmptyModel,
|
||||
"lite app refresh model has no sections to compare");
|
||||
plan.error = plan.issues.back().message;
|
||||
return plan;
|
||||
}
|
||||
|
||||
if (!model.complete) {
|
||||
addIssue(plan,
|
||||
LiteWalletStateApplyIssue::IncompleteModel,
|
||||
"lite app refresh model is partial; dry-run apply planning only");
|
||||
}
|
||||
|
||||
addChainInfoPlans(plan, model, state);
|
||||
addHeightPlans(plan, model, state);
|
||||
addBalancePlans(plan, model, state);
|
||||
addAddressPlans(plan, model, state);
|
||||
addSpendableOutputPlans(plan, model);
|
||||
addTransactionPlans(plan, model, state);
|
||||
addSyncPlans(plan, model, state);
|
||||
|
||||
plan.ok = true;
|
||||
return plan;
|
||||
}
|
||||
|
||||
LiteWalletStateApplyPlan LiteWalletStateApplyPlanner::buildPlan(
|
||||
const LiteWalletAppRefreshModel& model,
|
||||
const dragonx::WalletState& state) const
|
||||
{
|
||||
return planLiteWalletStateApply(model, state);
|
||||
}
|
||||
|
||||
} // namespace dragonx::wallet
|
||||
@@ -1,98 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "data/wallet_state.h"
|
||||
#include "lite_wallet_state_mapper.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace dragonx::wallet {
|
||||
|
||||
enum class LiteWalletStateApplySection {
|
||||
ChainInfo,
|
||||
Height,
|
||||
Balance,
|
||||
Addresses,
|
||||
SpendableOutputs,
|
||||
Transactions,
|
||||
SyncStatus,
|
||||
};
|
||||
|
||||
enum class LiteWalletStateApplyAction {
|
||||
Noop,
|
||||
SetField,
|
||||
ReplaceCollection,
|
||||
InspectOnly,
|
||||
};
|
||||
|
||||
enum class LiteWalletStateApplyIssue {
|
||||
EmptyModel,
|
||||
IncompleteModel,
|
||||
AddressSpendabilityUnknown,
|
||||
SpendableOutputsHaveNoWalletStateTarget,
|
||||
};
|
||||
|
||||
struct LiteWalletStateApplyIssueInfo {
|
||||
LiteWalletStateApplyIssue issue = LiteWalletStateApplyIssue::EmptyModel;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
struct LiteWalletStateApplyFieldPlan {
|
||||
LiteWalletStateApplySection section = LiteWalletStateApplySection::Balance;
|
||||
LiteWalletStateApplyAction action = LiteWalletStateApplyAction::Noop;
|
||||
std::string fieldName;
|
||||
std::string currentValue;
|
||||
std::string proposedValue;
|
||||
bool currentKnown = true;
|
||||
bool proposedKnown = true;
|
||||
bool wouldChange = false;
|
||||
};
|
||||
|
||||
struct LiteWalletStateApplyCollectionPlan {
|
||||
LiteWalletStateApplySection section = LiteWalletStateApplySection::Addresses;
|
||||
LiteWalletStateApplyAction action = LiteWalletStateApplyAction::Noop;
|
||||
std::string collectionName;
|
||||
std::size_t currentCount = 0;
|
||||
std::size_t proposedCount = 0;
|
||||
bool hasWalletStateTarget = true;
|
||||
bool wouldReplace = false;
|
||||
};
|
||||
|
||||
struct LiteWalletStateApplyPlan {
|
||||
bool ok = false;
|
||||
bool dryRunOnly = true;
|
||||
bool applyImplemented = false;
|
||||
bool stateMutationAllowed = false;
|
||||
bool wouldChangeWalletState = false;
|
||||
bool sourceComplete = false;
|
||||
|
||||
bool hasChainInfo = false;
|
||||
bool hasHeight = false;
|
||||
bool hasBalance = false;
|
||||
bool hasAddresses = false;
|
||||
bool hasSpendableOutputs = false;
|
||||
bool hasTransactions = false;
|
||||
bool hasSyncStatus = false;
|
||||
|
||||
std::vector<LiteWalletStateApplyFieldPlan> fieldPlans;
|
||||
std::vector<LiteWalletStateApplyCollectionPlan> collectionPlans;
|
||||
std::vector<LiteWalletStateApplyIssueInfo> issues;
|
||||
std::string error;
|
||||
};
|
||||
|
||||
const char* liteWalletStateApplySectionName(LiteWalletStateApplySection section);
|
||||
const char* liteWalletStateApplyActionName(LiteWalletStateApplyAction action);
|
||||
const char* liteWalletStateApplyIssueName(LiteWalletStateApplyIssue issue);
|
||||
|
||||
LiteWalletStateApplyPlan planLiteWalletStateApply(const LiteWalletAppRefreshModel& model,
|
||||
const dragonx::WalletState& state);
|
||||
|
||||
class LiteWalletStateApplyPlanner {
|
||||
public:
|
||||
LiteWalletStateApplyPlan buildPlan(const LiteWalletAppRefreshModel& model,
|
||||
const dragonx::WalletState& state) const;
|
||||
};
|
||||
|
||||
} // namespace dragonx::wallet
|
||||
@@ -209,9 +209,4 @@ LiteWalletStateMapResult mapLiteWalletRefreshResult(const LiteWalletRefreshResul
|
||||
return mapLiteWalletRefreshBundle(result.bundle);
|
||||
}
|
||||
|
||||
LiteWalletStateMapResult mapLiteWalletRefreshServiceResult(const LiteWalletRefreshServiceResult& result)
|
||||
{
|
||||
return mapLiteWalletRefreshBundle(result.bundle);
|
||||
}
|
||||
|
||||
} // namespace dragonx::wallet
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "lite_wallet_refresh_service.h"
|
||||
#include "lite_wallet_gateway.h" // LiteWalletRefreshBundle / LiteWalletRefreshResult
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
@@ -134,6 +134,5 @@ const char* liteWalletStateMapIssueName(LiteWalletStateMapIssue issue);
|
||||
|
||||
LiteWalletStateMapResult mapLiteWalletRefreshBundle(const LiteWalletRefreshBundle& bundle);
|
||||
LiteWalletStateMapResult mapLiteWalletRefreshResult(const LiteWalletRefreshResult& result);
|
||||
LiteWalletStateMapResult mapLiteWalletRefreshServiceResult(const LiteWalletRefreshServiceResult& result);
|
||||
|
||||
} // namespace dragonx::wallet
|
||||
@@ -1,344 +0,0 @@
|
||||
#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
|
||||
@@ -1,172 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "lite_sync_service.h"
|
||||
#include "lite_wallet_app_refresh_orchestrator.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace dragonx::wallet {
|
||||
|
||||
enum class LiteWalletSyncAppRefreshIntegrationStatus {
|
||||
FutureWorkerQueueFeedReady,
|
||||
WaitingForLifecycle,
|
||||
WaitingForSyncPlan,
|
||||
WaitingForSyncStatus,
|
||||
WaitingForRecovery,
|
||||
WaitingForCancellation,
|
||||
RefreshNotQueued,
|
||||
WorkerQueueUnavailable,
|
||||
UnsafePlan,
|
||||
};
|
||||
|
||||
enum class LiteWalletSyncAppRefreshIntegrationIssue {
|
||||
LifecycleNotReady,
|
||||
MissingSyncStartPlan,
|
||||
InvalidSyncStartPlan,
|
||||
SyncStartWouldExecute,
|
||||
MissingSyncStatusPlan,
|
||||
InvalidSyncStatusPlan,
|
||||
SyncStatusWouldExecute,
|
||||
MissingRecoveryDecision,
|
||||
SyncStillPolling,
|
||||
SyncRecoveryRequired,
|
||||
SyncRecoveryNeedsUserAttention,
|
||||
CancellationRequired,
|
||||
CancellationUnsupported,
|
||||
RefreshReportRejected,
|
||||
RefreshReportUnsafe,
|
||||
RefreshSkipped,
|
||||
RefreshBlocked,
|
||||
FutureWorkerQueueDisabled,
|
||||
FutureWorkerQueuePressure,
|
||||
};
|
||||
|
||||
struct LiteWalletSyncAppRefreshLifecycleInput {
|
||||
bool ready = false;
|
||||
WalletBackendStatus status;
|
||||
};
|
||||
|
||||
struct LiteWalletSyncAppRefreshSyncPlanInput {
|
||||
bool haveStartPlan = false;
|
||||
LiteSyncPlan startPlan;
|
||||
bool haveStatusPlan = false;
|
||||
LiteSyncPlan statusPlan;
|
||||
bool haveRecoveryDecision = false;
|
||||
LiteSyncRecoveryDecision recoveryDecision;
|
||||
};
|
||||
|
||||
struct LiteWalletSyncAppRefreshCancellationInput {
|
||||
bool cancellationRequested = false;
|
||||
bool syncInProgress = false;
|
||||
bool cancellationSupported = false;
|
||||
};
|
||||
|
||||
struct LiteWalletFutureWorkerQueueInput {
|
||||
bool enabled = true;
|
||||
std::size_t queueDepth = 0;
|
||||
std::size_t maxQueueDepth = 0;
|
||||
std::string laneName = "lite-app-refresh";
|
||||
};
|
||||
|
||||
struct LiteWalletSyncAppRefreshIntegrationInput {
|
||||
LiteWalletSyncAppRefreshLifecycleInput lifecycle;
|
||||
LiteWalletSyncAppRefreshSyncPlanInput sync;
|
||||
LiteWalletSyncAppRefreshCancellationInput cancellation;
|
||||
LiteWalletFutureWorkerQueueInput futureWorkerQueue;
|
||||
LiteWalletAppRefreshOrchestrationResult refreshOrchestration;
|
||||
};
|
||||
|
||||
struct LiteWalletSyncAppRefreshIntegrationOptions {
|
||||
bool requireLifecycleReady = true;
|
||||
bool requireSyncStartPlan = true;
|
||||
bool requireSyncStatusPlan = true;
|
||||
bool requireRecoveryDecision = true;
|
||||
bool requireSyncCompleteForRefresh = true;
|
||||
bool rejectExecutableSyncPlans = true;
|
||||
bool requireFutureWorkerQueue = true;
|
||||
};
|
||||
|
||||
struct LiteWalletFutureWorkerQueuePlan {
|
||||
bool readyToFeed = false;
|
||||
bool wouldFeed = false;
|
||||
bool enqueued = false;
|
||||
std::string laneName;
|
||||
LiteWalletAppRefreshScheduleTrigger trigger = LiteWalletAppRefreshScheduleTrigger::Periodic;
|
||||
LiteWalletRefreshRouteKind route = LiteWalletRefreshRouteKind::Unavailable;
|
||||
std::string startSyncCommand;
|
||||
std::string syncStatusCommand;
|
||||
std::size_t queueDepth = 0;
|
||||
std::size_t maxQueueDepth = 0;
|
||||
};
|
||||
|
||||
struct LiteWalletSyncAppRefreshIntegrationIssueInfo {
|
||||
LiteWalletSyncAppRefreshIntegrationIssue issue = LiteWalletSyncAppRefreshIntegrationIssue::LifecycleNotReady;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
struct LiteWalletSyncAppRefreshIntegrationResult {
|
||||
bool ok = false;
|
||||
bool dryRunOnly = true;
|
||||
bool noNetwork = true;
|
||||
bool noBridgeCalls = true;
|
||||
bool noSyncStarted = true;
|
||||
bool noWalletPersistence = true;
|
||||
bool stateMutationAllowed = false;
|
||||
bool stateMutated = false;
|
||||
bool walletStateWritten = false;
|
||||
bool workerQueueEnqueued = false;
|
||||
|
||||
bool lifecycleAccepted = false;
|
||||
bool syncStartPlanAccepted = false;
|
||||
bool syncStatusPlanAccepted = false;
|
||||
bool recoveryAccepted = false;
|
||||
bool cancellationAccepted = false;
|
||||
bool refreshReportAccepted = false;
|
||||
bool futureWorkerQueueFeedReady = false;
|
||||
bool wouldFeedFutureWorkerQueue = false;
|
||||
bool refreshWouldQueue = false;
|
||||
bool refreshSkipped = false;
|
||||
bool refreshBlocked = false;
|
||||
bool recoveryRequired = false;
|
||||
bool cancellationRequired = false;
|
||||
bool futureClearRequired = false;
|
||||
bool futureRescanRequired = false;
|
||||
bool futureRestartSyncRequired = false;
|
||||
bool requiresUserAttention = false;
|
||||
|
||||
LiteWalletSyncAppRefreshIntegrationStatus status = LiteWalletSyncAppRefreshIntegrationStatus::WaitingForLifecycle;
|
||||
LiteWalletRefreshRouteKind route = LiteWalletRefreshRouteKind::Unavailable;
|
||||
WalletBackendStatus lifecycleStatus;
|
||||
LiteSyncPlan syncStartPlan;
|
||||
LiteSyncPlan syncStatusPlan;
|
||||
LiteSyncRecoveryDecision recoveryDecision;
|
||||
LiteWalletAppRefreshOrchestrationResult refreshOrchestration;
|
||||
LiteWalletFutureWorkerQueuePlan futureWorkerQueuePlan;
|
||||
std::vector<LiteWalletSyncAppRefreshIntegrationIssueInfo> issues;
|
||||
std::string error;
|
||||
};
|
||||
|
||||
const char* liteWalletSyncAppRefreshIntegrationStatusName(
|
||||
LiteWalletSyncAppRefreshIntegrationStatus status);
|
||||
const char* liteWalletSyncAppRefreshIntegrationIssueName(
|
||||
LiteWalletSyncAppRefreshIntegrationIssue issue);
|
||||
|
||||
LiteWalletSyncAppRefreshIntegrationResult planLiteWalletSyncAppRefreshIntegration(
|
||||
const LiteWalletSyncAppRefreshIntegrationInput& input,
|
||||
LiteWalletSyncAppRefreshIntegrationOptions options = {});
|
||||
|
||||
class LiteWalletSyncAppRefreshIntegrationPlanner {
|
||||
public:
|
||||
explicit LiteWalletSyncAppRefreshIntegrationPlanner(
|
||||
LiteWalletSyncAppRefreshIntegrationOptions options = {});
|
||||
|
||||
LiteWalletSyncAppRefreshIntegrationResult plan(
|
||||
const LiteWalletSyncAppRefreshIntegrationInput& input) const;
|
||||
|
||||
private:
|
||||
LiteWalletSyncAppRefreshIntegrationOptions options_;
|
||||
};
|
||||
|
||||
} // namespace dragonx::wallet
|
||||
@@ -1,461 +0,0 @@
|
||||
#include "wallet/lite_wallet_sync_execution_readiness.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace dragonx::wallet {
|
||||
namespace {
|
||||
|
||||
void addIssue(LiteWalletSyncExecutionReadinessResult& result,
|
||||
LiteWalletSyncExecutionReadinessIssue issue,
|
||||
std::string message)
|
||||
{
|
||||
result.issues.push_back(LiteWalletSyncExecutionReadinessIssueInfo{issue, std::move(message)});
|
||||
}
|
||||
|
||||
LiteWalletSyncExecutionReadinessResult stoppedResult(
|
||||
LiteWalletSyncExecutionReadinessResult result,
|
||||
LiteWalletSyncExecutionReadinessStatus status,
|
||||
LiteWalletSyncExecutionReadinessIssue issue,
|
||||
std::string message)
|
||||
{
|
||||
result.status = status;
|
||||
addIssue(result, issue, std::move(message));
|
||||
result.error = result.issues.back().message;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool coreArtifactSymbolsReady(const LiteWalletSdxlArtifactSymbolsInput& symbols)
|
||||
{
|
||||
return symbols.walletExists &&
|
||||
symbols.initializeNew &&
|
||||
symbols.initializeNewFromPhrase &&
|
||||
symbols.initializeExisting &&
|
||||
symbols.execute &&
|
||||
symbols.checkServerOnline;
|
||||
}
|
||||
|
||||
bool integrationReportIsUnsafe(const LiteWalletSyncAppRefreshIntegrationResult& integration)
|
||||
{
|
||||
return !integration.dryRunOnly ||
|
||||
!integration.noNetwork ||
|
||||
!integration.noBridgeCalls ||
|
||||
!integration.noSyncStarted ||
|
||||
!integration.noWalletPersistence ||
|
||||
integration.stateMutationAllowed ||
|
||||
integration.stateMutated ||
|
||||
integration.walletStateWritten ||
|
||||
integration.workerQueueEnqueued;
|
||||
}
|
||||
|
||||
std::string backendMessageOrDefault(const WalletBackendStatus& status,
|
||||
const std::string& fallback)
|
||||
{
|
||||
return status.message.empty() ? fallback : status.message;
|
||||
}
|
||||
|
||||
bool recoveryRequiredByIntegration(const LiteWalletSyncAppRefreshIntegrationResult& integration)
|
||||
{
|
||||
return integration.recoveryRequired ||
|
||||
integration.futureClearRequired ||
|
||||
integration.futureRescanRequired ||
|
||||
integration.futureRestartSyncRequired ||
|
||||
integration.requiresUserAttention;
|
||||
}
|
||||
|
||||
bool cancellationRequiredByIntegration(const LiteWalletSyncAppRefreshIntegrationResult& integration)
|
||||
{
|
||||
return integration.cancellationRequired ||
|
||||
integration.status == LiteWalletSyncAppRefreshIntegrationStatus::WaitingForCancellation;
|
||||
}
|
||||
|
||||
void copyIntegrationSummary(LiteWalletSyncExecutionReadinessResult& result,
|
||||
const LiteWalletSyncAppRefreshIntegrationResult& integration)
|
||||
{
|
||||
result.integrationReport = integration;
|
||||
result.integrationFeedReady = integration.futureWorkerQueueFeedReady;
|
||||
result.recoveryRequired = recoveryRequiredByIntegration(integration);
|
||||
result.cancellationRequired = cancellationRequiredByIntegration(integration);
|
||||
result.futureClearRequired = integration.futureClearRequired;
|
||||
result.futureRescanRequired = integration.futureRescanRequired;
|
||||
result.futureRestartSyncRequired = integration.futureRestartSyncRequired;
|
||||
result.requiresUserAttention = integration.requiresUserAttention;
|
||||
result.enablementPlan.startSyncCommand = integration.syncStartPlan.command;
|
||||
result.enablementPlan.syncStatusCommand = integration.syncStatusPlan.command;
|
||||
result.enablementPlan.workerQueueLane = integration.futureWorkerQueuePlan.laneName;
|
||||
result.enablementPlan.route = integration.route;
|
||||
}
|
||||
|
||||
LiteWalletSyncExecutionReadinessResult evaluateRecoveryReadiness(
|
||||
LiteWalletSyncExecutionReadinessResult result,
|
||||
const LiteWalletSyncExecutionRecoveryReadinessInput& recovery,
|
||||
LiteWalletSyncExecutionReadinessOptions options)
|
||||
{
|
||||
if (!options.requireRecoveryExecutionReadiness) {
|
||||
result.recoveryExecutionReady = true;
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForRecovery,
|
||||
LiteWalletSyncExecutionReadinessIssue::IntegrationFeedNotReady,
|
||||
"lite sync recovery must complete before sync execution can be enabled");
|
||||
}
|
||||
|
||||
if (result.futureClearRequired && !recovery.clearActionReady) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForRecovery,
|
||||
LiteWalletSyncExecutionReadinessIssue::RecoveryClearMissing,
|
||||
"lite sync recovery requires a future clear action before sync execution");
|
||||
}
|
||||
if (result.futureRescanRequired && !recovery.rescanActionReady) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForRecovery,
|
||||
LiteWalletSyncExecutionReadinessIssue::RecoveryRescanMissing,
|
||||
"lite sync recovery requires a future rescan action before sync execution");
|
||||
}
|
||||
if (result.futureRestartSyncRequired && !recovery.restartSyncActionReady) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForRecovery,
|
||||
LiteWalletSyncExecutionReadinessIssue::RecoveryRestartMissing,
|
||||
"lite sync recovery requires a future restart-sync action before sync execution");
|
||||
}
|
||||
if (result.requiresUserAttention && !recovery.userAttentionPathReady) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForRecovery,
|
||||
LiteWalletSyncExecutionReadinessIssue::RecoveryUserAttentionMissing,
|
||||
"lite sync recovery requires a user-attention path before sync execution");
|
||||
}
|
||||
|
||||
result.recoveryExecutionReady = true;
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForRecovery,
|
||||
LiteWalletSyncExecutionReadinessIssue::IntegrationFeedNotReady,
|
||||
"lite sync recovery is ready to be modeled but must complete before sync execution");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const char* liteWalletSyncExecutionReadinessStatusName(
|
||||
LiteWalletSyncExecutionReadinessStatus status)
|
||||
{
|
||||
switch (status) {
|
||||
case LiteWalletSyncExecutionReadinessStatus::ReadyToEnableSyncExecution: return "ReadyToEnableSyncExecution";
|
||||
case LiteWalletSyncExecutionReadinessStatus::WaitingForLiteBuild: return "WaitingForLiteBuild";
|
||||
case LiteWalletSyncExecutionReadinessStatus::WaitingForArtifact: return "WaitingForArtifact";
|
||||
case LiteWalletSyncExecutionReadinessStatus::WaitingForBackendLink: return "WaitingForBackendLink";
|
||||
case LiteWalletSyncExecutionReadinessStatus::WaitingForBridge: return "WaitingForBridge";
|
||||
case LiteWalletSyncExecutionReadinessStatus::WaitingForIntegration: return "WaitingForIntegration";
|
||||
case LiteWalletSyncExecutionReadinessStatus::WaitingForExecutionOwner: return "WaitingForExecutionOwner";
|
||||
case LiteWalletSyncExecutionReadinessStatus::WaitingForCancellation: return "WaitingForCancellation";
|
||||
case LiteWalletSyncExecutionReadinessStatus::WaitingForShutdown: return "WaitingForShutdown";
|
||||
case LiteWalletSyncExecutionReadinessStatus::WaitingForRetry: return "WaitingForRetry";
|
||||
case LiteWalletSyncExecutionReadinessStatus::WaitingForRecovery: return "WaitingForRecovery";
|
||||
case LiteWalletSyncExecutionReadinessStatus::UnsafePlan: return "UnsafePlan";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
const char* liteWalletSyncExecutionReadinessIssueName(
|
||||
LiteWalletSyncExecutionReadinessIssue issue)
|
||||
{
|
||||
switch (issue) {
|
||||
case LiteWalletSyncExecutionReadinessIssue::FullNodeBuild: return "FullNodeBuild";
|
||||
case LiteWalletSyncExecutionReadinessIssue::LiteBackendCapabilityMissing: return "LiteBackendCapabilityMissing";
|
||||
case LiteWalletSyncExecutionReadinessIssue::ArtifactPathMissing: return "ArtifactPathMissing";
|
||||
case LiteWalletSyncExecutionReadinessIssue::ArtifactMissing: return "ArtifactMissing";
|
||||
case LiteWalletSyncExecutionReadinessIssue::ArtifactUnreadable: return "ArtifactUnreadable";
|
||||
case LiteWalletSyncExecutionReadinessIssue::ArtifactNotSdxlCompatible: return "ArtifactNotSdxlCompatible";
|
||||
case LiteWalletSyncExecutionReadinessIssue::ArtifactSymbolsMissing: return "ArtifactSymbolsMissing";
|
||||
case LiteWalletSyncExecutionReadinessIssue::ArtifactStringOwnershipUnverified: return "ArtifactStringOwnershipUnverified";
|
||||
case LiteWalletSyncExecutionReadinessIssue::ArtifactShutdownUnavailable: return "ArtifactShutdownUnavailable";
|
||||
case LiteWalletSyncExecutionReadinessIssue::BackendNotLinked: return "BackendNotLinked";
|
||||
case LiteWalletSyncExecutionReadinessIssue::BridgeUnavailable: return "BridgeUnavailable";
|
||||
case LiteWalletSyncExecutionReadinessIssue::IntegrationRejected: return "IntegrationRejected";
|
||||
case LiteWalletSyncExecutionReadinessIssue::IntegrationUnsafe: return "IntegrationUnsafe";
|
||||
case LiteWalletSyncExecutionReadinessIssue::IntegrationFeedNotReady: return "IntegrationFeedNotReady";
|
||||
case LiteWalletSyncExecutionReadinessIssue::WorkerQueueOwnerMissing: return "WorkerQueueOwnerMissing";
|
||||
case LiteWalletSyncExecutionReadinessIssue::SyncLoopOwnerMissing: return "SyncLoopOwnerMissing";
|
||||
case LiteWalletSyncExecutionReadinessIssue::StartSyncExecutionMissing: return "StartSyncExecutionMissing";
|
||||
case LiteWalletSyncExecutionReadinessIssue::SyncStatusExecutionMissing: return "SyncStatusExecutionMissing";
|
||||
case LiteWalletSyncExecutionReadinessIssue::CancellationPathMissing: return "CancellationPathMissing";
|
||||
case LiteWalletSyncExecutionReadinessIssue::CancellationPending: return "CancellationPending";
|
||||
case LiteWalletSyncExecutionReadinessIssue::ShutdownPathMissing: return "ShutdownPathMissing";
|
||||
case LiteWalletSyncExecutionReadinessIssue::ShutdownPending: return "ShutdownPending";
|
||||
case LiteWalletSyncExecutionReadinessIssue::RetryPolicyMissing: return "RetryPolicyMissing";
|
||||
case LiteWalletSyncExecutionReadinessIssue::RetryLimitReached: return "RetryLimitReached";
|
||||
case LiteWalletSyncExecutionReadinessIssue::UserVisibleStatusMissing: return "UserVisibleStatusMissing";
|
||||
case LiteWalletSyncExecutionReadinessIssue::RecoveryClearMissing: return "RecoveryClearMissing";
|
||||
case LiteWalletSyncExecutionReadinessIssue::RecoveryRescanMissing: return "RecoveryRescanMissing";
|
||||
case LiteWalletSyncExecutionReadinessIssue::RecoveryRestartMissing: return "RecoveryRestartMissing";
|
||||
case LiteWalletSyncExecutionReadinessIssue::RecoveryUserAttentionMissing: return "RecoveryUserAttentionMissing";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
LiteWalletSyncExecutionReadinessResult evaluateLiteWalletSyncExecutionReadiness(
|
||||
const LiteWalletSyncExecutionReadinessInput& input,
|
||||
LiteWalletSyncExecutionReadinessOptions options)
|
||||
{
|
||||
LiteWalletSyncExecutionReadinessResult result;
|
||||
result.capabilities = input.capabilities;
|
||||
result.backendStatus = input.backend.status;
|
||||
copyIntegrationSummary(result, input.integrationReport);
|
||||
|
||||
if (options.requireLiteBuild && !isLiteBuild(input.capabilities)) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForLiteBuild,
|
||||
LiteWalletSyncExecutionReadinessIssue::FullNodeBuild,
|
||||
"lite sync execution readiness requires a lite build");
|
||||
}
|
||||
result.liteBuildAccepted = true;
|
||||
|
||||
if (options.requireLiteBackendCapability && !supportsLiteBackend(input.capabilities)) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForBackendLink,
|
||||
LiteWalletSyncExecutionReadinessIssue::LiteBackendCapabilityMissing,
|
||||
"lite backend capability is not available");
|
||||
}
|
||||
|
||||
if (options.requireValidatedArtifact) {
|
||||
if (!input.artifact.pathConfigured || input.artifact.artifactPath.empty()) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForArtifact,
|
||||
LiteWalletSyncExecutionReadinessIssue::ArtifactPathMissing,
|
||||
"SDXL-compatible lite backend artifact path is not configured");
|
||||
}
|
||||
if (!input.artifact.exists) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForArtifact,
|
||||
LiteWalletSyncExecutionReadinessIssue::ArtifactMissing,
|
||||
"SDXL-compatible lite backend artifact does not exist");
|
||||
}
|
||||
if (!input.artifact.readable) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForArtifact,
|
||||
LiteWalletSyncExecutionReadinessIssue::ArtifactUnreadable,
|
||||
"SDXL-compatible lite backend artifact is not readable");
|
||||
}
|
||||
if (!input.artifact.sdxlCompatible) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForArtifact,
|
||||
LiteWalletSyncExecutionReadinessIssue::ArtifactNotSdxlCompatible,
|
||||
"lite backend artifact has not been validated as SDXL-compatible");
|
||||
}
|
||||
if (!coreArtifactSymbolsReady(input.artifact.symbols)) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForArtifact,
|
||||
LiteWalletSyncExecutionReadinessIssue::ArtifactSymbolsMissing,
|
||||
"lite backend artifact is missing required SDXL lifecycle or execute symbols");
|
||||
}
|
||||
if (!input.artifact.symbols.freeString) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForArtifact,
|
||||
LiteWalletSyncExecutionReadinessIssue::ArtifactStringOwnershipUnverified,
|
||||
"lite backend artifact string ownership cleanup is not validated");
|
||||
}
|
||||
if (!input.artifact.symbols.shutdown) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForArtifact,
|
||||
LiteWalletSyncExecutionReadinessIssue::ArtifactShutdownUnavailable,
|
||||
"lite backend artifact shutdown symbol is not validated");
|
||||
}
|
||||
}
|
||||
result.artifactAccepted = true;
|
||||
|
||||
if (options.requireLinkedBackend && !input.backend.linked) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForBackendLink,
|
||||
LiteWalletSyncExecutionReadinessIssue::BackendNotLinked,
|
||||
backendMessageOrDefault(input.backend.status, "lite backend is not linked"));
|
||||
}
|
||||
result.backendLinkedAccepted = true;
|
||||
|
||||
if (options.requireBridgeAvailable && !input.backend.bridgeAvailable) {
|
||||
const auto message = !input.backend.bridgeUnavailableReason.empty()
|
||||
? input.backend.bridgeUnavailableReason
|
||||
: backendMessageOrDefault(input.backend.status, "lite client bridge is unavailable");
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForBridge,
|
||||
LiteWalletSyncExecutionReadinessIssue::BridgeUnavailable,
|
||||
message);
|
||||
}
|
||||
result.bridgeAccepted = true;
|
||||
|
||||
if (integrationReportIsUnsafe(input.integrationReport)) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::UnsafePlan,
|
||||
LiteWalletSyncExecutionReadinessIssue::IntegrationUnsafe,
|
||||
"lite sync/app-refresh integration report is not a no-network dry-run report");
|
||||
}
|
||||
|
||||
if (result.recoveryRequired) {
|
||||
return evaluateRecoveryReadiness(std::move(result), input.recovery, options);
|
||||
}
|
||||
|
||||
if (result.cancellationRequired || input.cancellation.cancellationRequested) {
|
||||
result.cancellationRequired = true;
|
||||
if (!input.cancellation.cancellationPathReady) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForCancellation,
|
||||
LiteWalletSyncExecutionReadinessIssue::CancellationPathMissing,
|
||||
"lite sync cancellation path must be ready before sync execution");
|
||||
}
|
||||
if (!input.cancellation.cancellationComplete) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForCancellation,
|
||||
LiteWalletSyncExecutionReadinessIssue::CancellationPending,
|
||||
"lite sync cancellation must complete before sync execution");
|
||||
}
|
||||
}
|
||||
|
||||
if (!input.integrationReport.ok) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForIntegration,
|
||||
LiteWalletSyncExecutionReadinessIssue::IntegrationRejected,
|
||||
input.integrationReport.error.empty()
|
||||
? "lite sync/app-refresh integration report is not successful"
|
||||
: input.integrationReport.error);
|
||||
}
|
||||
|
||||
if (options.requireIntegrationFeedReady && !input.integrationReport.futureWorkerQueueFeedReady) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForIntegration,
|
||||
LiteWalletSyncExecutionReadinessIssue::IntegrationFeedNotReady,
|
||||
"lite sync/app-refresh integration report is not ready to feed future work");
|
||||
}
|
||||
result.integrationAccepted = true;
|
||||
|
||||
if (options.requireWorkerQueueOwner && !input.ownership.workerQueueOwnerReady) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForExecutionOwner,
|
||||
LiteWalletSyncExecutionReadinessIssue::WorkerQueueOwnerMissing,
|
||||
"lite sync execution requires explicit worker queue ownership");
|
||||
}
|
||||
result.workerQueueOwnerAccepted = true;
|
||||
|
||||
if (options.requireSyncLoopOwner && !input.ownership.syncLoopOwnerReady) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForExecutionOwner,
|
||||
LiteWalletSyncExecutionReadinessIssue::SyncLoopOwnerMissing,
|
||||
"lite sync execution requires explicit sync loop ownership");
|
||||
}
|
||||
result.syncLoopOwnerAccepted = true;
|
||||
|
||||
if (options.requireStartSyncExecution && !input.ownership.startSyncExecutionReady) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForExecutionOwner,
|
||||
LiteWalletSyncExecutionReadinessIssue::StartSyncExecutionMissing,
|
||||
"lite sync start execution path is not ready");
|
||||
}
|
||||
result.startSyncExecutionReady = true;
|
||||
|
||||
if (options.requireSyncStatusPolling && !input.ownership.syncStatusPollingReady) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForExecutionOwner,
|
||||
LiteWalletSyncExecutionReadinessIssue::SyncStatusExecutionMissing,
|
||||
"lite syncstatus polling execution path is not ready");
|
||||
}
|
||||
result.syncStatusPollingReady = true;
|
||||
|
||||
if (options.requireCancellationPath && !input.cancellation.cancellationPathReady) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForCancellation,
|
||||
LiteWalletSyncExecutionReadinessIssue::CancellationPathMissing,
|
||||
"lite sync cancellation path must be ready before sync execution");
|
||||
}
|
||||
result.cancellationReady = true;
|
||||
|
||||
if (options.requireShutdownHook && !input.shutdown.shutdownHookReady) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForShutdown,
|
||||
LiteWalletSyncExecutionReadinessIssue::ShutdownPathMissing,
|
||||
"lite sync shutdown hook must be ready before sync execution");
|
||||
}
|
||||
if (input.shutdown.shutdownRequested && !input.shutdown.shutdownComplete) {
|
||||
result.shutdownRequired = true;
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForShutdown,
|
||||
LiteWalletSyncExecutionReadinessIssue::ShutdownPending,
|
||||
"lite sync shutdown must complete before new sync execution");
|
||||
}
|
||||
result.shutdownReady = true;
|
||||
|
||||
if (options.requireRetryPolicy && !input.retry.retryPolicyReady) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForRetry,
|
||||
LiteWalletSyncExecutionReadinessIssue::RetryPolicyMissing,
|
||||
"lite sync retry policy must be ready before sync execution");
|
||||
}
|
||||
result.retryReady = true;
|
||||
|
||||
if (options.requireUserVisibleStatus && !input.ownership.userVisibleStatusReady) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForRetry,
|
||||
LiteWalletSyncExecutionReadinessIssue::UserVisibleStatusMissing,
|
||||
"lite sync execution requires user-visible status reporting");
|
||||
}
|
||||
result.userVisibleStatusReady = true;
|
||||
|
||||
if (input.retry.retryRequested) {
|
||||
result.retryRequired = true;
|
||||
if (input.retry.maxAttempts > 0 && input.retry.attempt >= input.retry.maxAttempts) {
|
||||
return stoppedResult(
|
||||
std::move(result),
|
||||
LiteWalletSyncExecutionReadinessStatus::WaitingForRetry,
|
||||
LiteWalletSyncExecutionReadinessIssue::RetryLimitReached,
|
||||
"lite sync retry limit has been reached");
|
||||
}
|
||||
}
|
||||
|
||||
result.ok = true;
|
||||
result.status = LiteWalletSyncExecutionReadinessStatus::ReadyToEnableSyncExecution;
|
||||
result.syncExecutionCouldStart = true;
|
||||
result.syncStatusPollingCouldStart = true;
|
||||
result.executionWouldUseBridge = true;
|
||||
result.enablementPlan.readyToEnable = true;
|
||||
result.enablementPlan.startSyncExecutionEnabled = true;
|
||||
result.enablementPlan.syncStatusPollingEnabled = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
LiteWalletSyncExecutionReadinessPlanner::LiteWalletSyncExecutionReadinessPlanner(
|
||||
LiteWalletSyncExecutionReadinessOptions options)
|
||||
: options_(options)
|
||||
{
|
||||
}
|
||||
|
||||
LiteWalletSyncExecutionReadinessResult LiteWalletSyncExecutionReadinessPlanner::evaluate(
|
||||
const LiteWalletSyncExecutionReadinessInput& input) const
|
||||
{
|
||||
return evaluateLiteWalletSyncExecutionReadiness(input, options_);
|
||||
}
|
||||
|
||||
} // namespace dragonx::wallet
|
||||
@@ -1,238 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "lite_wallet_sync_app_refresh_integration.h"
|
||||
#include "wallet_capabilities.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace dragonx::wallet {
|
||||
|
||||
enum class LiteWalletSyncExecutionReadinessStatus {
|
||||
ReadyToEnableSyncExecution,
|
||||
WaitingForLiteBuild,
|
||||
WaitingForArtifact,
|
||||
WaitingForBackendLink,
|
||||
WaitingForBridge,
|
||||
WaitingForIntegration,
|
||||
WaitingForExecutionOwner,
|
||||
WaitingForCancellation,
|
||||
WaitingForShutdown,
|
||||
WaitingForRetry,
|
||||
WaitingForRecovery,
|
||||
UnsafePlan,
|
||||
};
|
||||
|
||||
enum class LiteWalletSyncExecutionReadinessIssue {
|
||||
FullNodeBuild,
|
||||
LiteBackendCapabilityMissing,
|
||||
ArtifactPathMissing,
|
||||
ArtifactMissing,
|
||||
ArtifactUnreadable,
|
||||
ArtifactNotSdxlCompatible,
|
||||
ArtifactSymbolsMissing,
|
||||
ArtifactStringOwnershipUnverified,
|
||||
ArtifactShutdownUnavailable,
|
||||
BackendNotLinked,
|
||||
BridgeUnavailable,
|
||||
IntegrationRejected,
|
||||
IntegrationUnsafe,
|
||||
IntegrationFeedNotReady,
|
||||
WorkerQueueOwnerMissing,
|
||||
SyncLoopOwnerMissing,
|
||||
StartSyncExecutionMissing,
|
||||
SyncStatusExecutionMissing,
|
||||
CancellationPathMissing,
|
||||
CancellationPending,
|
||||
ShutdownPathMissing,
|
||||
ShutdownPending,
|
||||
RetryPolicyMissing,
|
||||
RetryLimitReached,
|
||||
UserVisibleStatusMissing,
|
||||
RecoveryClearMissing,
|
||||
RecoveryRescanMissing,
|
||||
RecoveryRestartMissing,
|
||||
RecoveryUserAttentionMissing,
|
||||
};
|
||||
|
||||
struct LiteWalletSdxlArtifactSymbolsInput {
|
||||
bool walletExists = false;
|
||||
bool initializeNew = false;
|
||||
bool initializeNewFromPhrase = false;
|
||||
bool initializeExisting = false;
|
||||
bool execute = false;
|
||||
bool freeString = false;
|
||||
bool checkServerOnline = false;
|
||||
bool shutdown = false;
|
||||
};
|
||||
|
||||
struct LiteWalletSdxlArtifactInput {
|
||||
bool pathConfigured = false;
|
||||
bool exists = false;
|
||||
bool readable = false;
|
||||
bool sdxlCompatible = false;
|
||||
std::string artifactPath;
|
||||
std::string versionLabel;
|
||||
LiteWalletSdxlArtifactSymbolsInput symbols;
|
||||
};
|
||||
|
||||
struct LiteWalletLinkedBackendReadinessInput {
|
||||
bool linked = false;
|
||||
bool bridgeAvailable = false;
|
||||
WalletBackendStatus status;
|
||||
std::string bridgeUnavailableReason;
|
||||
};
|
||||
|
||||
struct LiteWalletSyncExecutionOwnershipInput {
|
||||
bool workerQueueOwnerReady = false;
|
||||
bool syncLoopOwnerReady = false;
|
||||
bool startSyncExecutionReady = false;
|
||||
bool syncStatusPollingReady = false;
|
||||
bool userVisibleStatusReady = false;
|
||||
};
|
||||
|
||||
struct LiteWalletSyncExecutionCancellationReadinessInput {
|
||||
bool cancellationPathReady = false;
|
||||
bool cancellationRequested = false;
|
||||
bool cancellationComplete = false;
|
||||
};
|
||||
|
||||
struct LiteWalletSyncExecutionShutdownReadinessInput {
|
||||
bool shutdownHookReady = false;
|
||||
bool shutdownRequested = false;
|
||||
bool shutdownComplete = false;
|
||||
};
|
||||
|
||||
struct LiteWalletSyncExecutionRetryReadinessInput {
|
||||
bool retryPolicyReady = false;
|
||||
bool retryRequested = false;
|
||||
std::size_t attempt = 0;
|
||||
std::size_t maxAttempts = 0;
|
||||
};
|
||||
|
||||
struct LiteWalletSyncExecutionRecoveryReadinessInput {
|
||||
bool clearActionReady = false;
|
||||
bool rescanActionReady = false;
|
||||
bool restartSyncActionReady = false;
|
||||
bool userAttentionPathReady = false;
|
||||
};
|
||||
|
||||
struct LiteWalletSyncExecutionReadinessInput {
|
||||
WalletCapabilities capabilities;
|
||||
LiteWalletSdxlArtifactInput artifact;
|
||||
LiteWalletLinkedBackendReadinessInput backend;
|
||||
LiteWalletSyncExecutionOwnershipInput ownership;
|
||||
LiteWalletSyncExecutionCancellationReadinessInput cancellation;
|
||||
LiteWalletSyncExecutionShutdownReadinessInput shutdown;
|
||||
LiteWalletSyncExecutionRetryReadinessInput retry;
|
||||
LiteWalletSyncExecutionRecoveryReadinessInput recovery;
|
||||
LiteWalletSyncAppRefreshIntegrationResult integrationReport;
|
||||
};
|
||||
|
||||
struct LiteWalletSyncExecutionReadinessOptions {
|
||||
bool requireLiteBuild = true;
|
||||
bool requireLiteBackendCapability = true;
|
||||
bool requireValidatedArtifact = true;
|
||||
bool requireLinkedBackend = true;
|
||||
bool requireBridgeAvailable = true;
|
||||
bool requireIntegrationFeedReady = true;
|
||||
bool requireWorkerQueueOwner = true;
|
||||
bool requireSyncLoopOwner = true;
|
||||
bool requireStartSyncExecution = true;
|
||||
bool requireSyncStatusPolling = true;
|
||||
bool requireCancellationPath = true;
|
||||
bool requireShutdownHook = true;
|
||||
bool requireRetryPolicy = true;
|
||||
bool requireUserVisibleStatus = true;
|
||||
bool requireRecoveryExecutionReadiness = true;
|
||||
};
|
||||
|
||||
struct LiteWalletSyncExecutionEnablementPlan {
|
||||
bool readyToEnable = false;
|
||||
bool startSyncExecutionEnabled = false;
|
||||
bool syncStatusPollingEnabled = false;
|
||||
bool workerQueueEnqueued = false;
|
||||
std::string startSyncCommand;
|
||||
std::string syncStatusCommand;
|
||||
std::string workerQueueLane;
|
||||
LiteWalletRefreshRouteKind route = LiteWalletRefreshRouteKind::Unavailable;
|
||||
};
|
||||
|
||||
struct LiteWalletSyncExecutionReadinessIssueInfo {
|
||||
LiteWalletSyncExecutionReadinessIssue issue = LiteWalletSyncExecutionReadinessIssue::FullNodeBuild;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
struct LiteWalletSyncExecutionReadinessResult {
|
||||
bool ok = false;
|
||||
bool dryRunOnly = true;
|
||||
bool noNetwork = true;
|
||||
bool noBridgeCalls = true;
|
||||
bool noSyncStarted = true;
|
||||
bool noSyncStatusPolled = true;
|
||||
bool noWalletPersistence = true;
|
||||
bool stateMutationAllowed = false;
|
||||
bool stateMutated = false;
|
||||
bool walletStateWritten = false;
|
||||
bool workerQueueEnqueued = false;
|
||||
|
||||
bool liteBuildAccepted = false;
|
||||
bool artifactAccepted = false;
|
||||
bool backendLinkedAccepted = false;
|
||||
bool bridgeAccepted = false;
|
||||
bool integrationAccepted = false;
|
||||
bool workerQueueOwnerAccepted = false;
|
||||
bool syncLoopOwnerAccepted = false;
|
||||
bool startSyncExecutionReady = false;
|
||||
bool syncStatusPollingReady = false;
|
||||
bool cancellationReady = false;
|
||||
bool shutdownReady = false;
|
||||
bool retryReady = false;
|
||||
bool userVisibleStatusReady = false;
|
||||
bool recoveryExecutionReady = false;
|
||||
|
||||
bool syncExecutionCouldStart = false;
|
||||
bool syncStatusPollingCouldStart = false;
|
||||
bool executionWouldUseBridge = false;
|
||||
bool integrationFeedReady = false;
|
||||
bool recoveryRequired = false;
|
||||
bool cancellationRequired = false;
|
||||
bool shutdownRequired = false;
|
||||
bool retryRequired = false;
|
||||
bool futureClearRequired = false;
|
||||
bool futureRescanRequired = false;
|
||||
bool futureRestartSyncRequired = false;
|
||||
bool requiresUserAttention = false;
|
||||
|
||||
LiteWalletSyncExecutionReadinessStatus status = LiteWalletSyncExecutionReadinessStatus::WaitingForLiteBuild;
|
||||
WalletCapabilities capabilities;
|
||||
WalletBackendStatus backendStatus;
|
||||
LiteWalletSyncAppRefreshIntegrationResult integrationReport;
|
||||
LiteWalletSyncExecutionEnablementPlan enablementPlan;
|
||||
std::vector<LiteWalletSyncExecutionReadinessIssueInfo> issues;
|
||||
std::string error;
|
||||
};
|
||||
|
||||
const char* liteWalletSyncExecutionReadinessStatusName(
|
||||
LiteWalletSyncExecutionReadinessStatus status);
|
||||
const char* liteWalletSyncExecutionReadinessIssueName(
|
||||
LiteWalletSyncExecutionReadinessIssue issue);
|
||||
|
||||
LiteWalletSyncExecutionReadinessResult evaluateLiteWalletSyncExecutionReadiness(
|
||||
const LiteWalletSyncExecutionReadinessInput& input,
|
||||
LiteWalletSyncExecutionReadinessOptions options = {});
|
||||
|
||||
class LiteWalletSyncExecutionReadinessPlanner {
|
||||
public:
|
||||
explicit LiteWalletSyncExecutionReadinessPlanner(
|
||||
LiteWalletSyncExecutionReadinessOptions options = {});
|
||||
|
||||
LiteWalletSyncExecutionReadinessResult evaluate(
|
||||
const LiteWalletSyncExecutionReadinessInput& input) const;
|
||||
|
||||
private:
|
||||
LiteWalletSyncExecutionReadinessOptions options_;
|
||||
};
|
||||
|
||||
} // namespace dragonx::wallet
|
||||
Reference in New Issue
Block a user