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
|
# 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
|
set(APP_SOURCES
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/app.cpp
|
src/app.cpp
|
||||||
@@ -418,17 +398,8 @@ set(APP_SOURCES
|
|||||||
src/wallet/lite_result_parsers.cpp
|
src/wallet/lite_result_parsers.cpp
|
||||||
src/wallet/lite_sync_service.cpp
|
src/wallet/lite_sync_service.cpp
|
||||||
src/wallet/lite_wallet_gateway.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_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
|
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_selection_adapter.cpp
|
||||||
src/wallet/lite_wallet_server_lifecycle_readiness.cpp
|
src/wallet/lite_wallet_server_lifecycle_readiness.cpp
|
||||||
src/wallet/lite_wallet_lifecycle_service.cpp
|
src/wallet/lite_wallet_lifecycle_service.cpp
|
||||||
@@ -542,15 +513,7 @@ set(APP_HEADERS
|
|||||||
src/wallet/lite_result_parsers.h
|
src/wallet/lite_result_parsers.h
|
||||||
src/wallet/lite_sync_service.h
|
src/wallet/lite_sync_service.h
|
||||||
src/wallet/lite_wallet_gateway.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_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_lifecycle_ui_adapter.h
|
||||||
src/wallet/lite_wallet_server_selection_adapter.h
|
src/wallet/lite_wallet_server_selection_adapter.h
|
||||||
src/wallet/lite_wallet_server_lifecycle_readiness.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_result_parsers.cpp
|
||||||
src/wallet/lite_sync_service.cpp
|
src/wallet/lite_sync_service.cpp
|
||||||
src/wallet/lite_wallet_gateway.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_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
|
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_selection_adapter.cpp
|
||||||
src/wallet/lite_wallet_server_lifecycle_readiness.cpp
|
src/wallet/lite_wallet_server_lifecycle_readiness.cpp
|
||||||
src/wallet/lite_wallet_lifecycle_service.cpp
|
src/wallet/lite_wallet_lifecycle_service.cpp
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "lite_connection_service.h"
|
#include "lite_connection_service.h" // pulls wallet_backend.h (WalletBackendStatus)
|
||||||
#include "lite_wallet_sync_execution_readiness.h"
|
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -9,6 +8,37 @@
|
|||||||
|
|
||||||
namespace dragonx::wallet {
|
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 {
|
enum class LiteBackendArtifactPlatform {
|
||||||
Current,
|
Current,
|
||||||
Linux,
|
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));
|
addIssue(result, issue, std::move(message));
|
||||||
result.error = result.issues.back().message;
|
result.error = result.issues.back().message;
|
||||||
result.lifecycleStatus = WalletBackendStatus{WalletBackendState::Unavailable, result.error, {}, {}, 0.0};
|
result.lifecycleStatus = WalletBackendStatus{WalletBackendState::Unavailable, result.error, {}, {}, 0.0};
|
||||||
result.syncLifecycleInput.status = result.lifecycleStatus;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,17 +380,9 @@ LiteWalletServerLifecycleReadinessResult evaluateLiteWalletServerLifecycleReadin
|
|||||||
result.futureLifecycleCouldBeEnabled = true;
|
result.futureLifecycleCouldBeEnabled = true;
|
||||||
result.lifecycleReportCouldFeedSyncPlanners = true;
|
result.lifecycleReportCouldFeedSyncPlanners = true;
|
||||||
result.lifecycleStatus = readyLifecycleStatus(result.selectedServerDisplay);
|
result.lifecycleStatus = readyLifecycleStatus(result.selectedServerDisplay);
|
||||||
result.syncLifecycleInput.ready = true;
|
|
||||||
result.syncLifecycleInput.status = result.lifecycleStatus;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
LiteWalletSyncAppRefreshLifecycleInput liteWalletSyncLifecycleInputFromServerLifecycleReadiness(
|
|
||||||
const LiteWalletServerLifecycleReadinessResult& result)
|
|
||||||
{
|
|
||||||
return result.syncLifecycleInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
LiteWalletServerLifecycleReadinessPlanner::LiteWalletServerLifecycleReadinessPlanner(
|
LiteWalletServerLifecycleReadinessPlanner::LiteWalletServerLifecycleReadinessPlanner(
|
||||||
LiteWalletServerLifecycleReadinessOptions options)
|
LiteWalletServerLifecycleReadinessOptions options)
|
||||||
: options_(options)
|
: options_(options)
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "lite_wallet_lifecycle_service.h"
|
#include "lite_wallet_lifecycle_service.h"
|
||||||
#include "lite_wallet_sync_app_refresh_integration.h"
|
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -163,7 +162,6 @@ struct LiteWalletServerLifecycleReadinessResult {
|
|||||||
LiteWalletSelectedServerDisplayReport selectedServerDisplay;
|
LiteWalletSelectedServerDisplayReport selectedServerDisplay;
|
||||||
LiteWalletServerSelectionPersistencePlan persistencePlan;
|
LiteWalletServerSelectionPersistencePlan persistencePlan;
|
||||||
LiteWalletLifecycleUiRequestPlan requestPlan;
|
LiteWalletLifecycleUiRequestPlan requestPlan;
|
||||||
LiteWalletSyncAppRefreshLifecycleInput syncLifecycleInput;
|
|
||||||
WalletBackendStatus lifecycleStatus;
|
WalletBackendStatus lifecycleStatus;
|
||||||
std::vector<LiteWalletServerLifecycleReadinessIssueInfo> issues;
|
std::vector<LiteWalletServerLifecycleReadinessIssueInfo> issues;
|
||||||
std::string error;
|
std::string error;
|
||||||
@@ -179,8 +177,6 @@ const char* liteWalletSelectedServerDisplayStatusName(
|
|||||||
LiteWalletServerLifecycleReadinessResult evaluateLiteWalletServerLifecycleReadiness(
|
LiteWalletServerLifecycleReadinessResult evaluateLiteWalletServerLifecycleReadiness(
|
||||||
const LiteWalletServerLifecycleReadinessInput& input,
|
const LiteWalletServerLifecycleReadinessInput& input,
|
||||||
LiteWalletServerLifecycleReadinessOptions options = {});
|
LiteWalletServerLifecycleReadinessOptions options = {});
|
||||||
LiteWalletSyncAppRefreshLifecycleInput liteWalletSyncLifecycleInputFromServerLifecycleReadiness(
|
|
||||||
const LiteWalletServerLifecycleReadinessResult& result);
|
|
||||||
|
|
||||||
class LiteWalletServerLifecycleReadinessPlanner {
|
class LiteWalletServerLifecycleReadinessPlanner {
|
||||||
public:
|
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);
|
return mapLiteWalletRefreshBundle(result.bundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
LiteWalletStateMapResult mapLiteWalletRefreshServiceResult(const LiteWalletRefreshServiceResult& result)
|
|
||||||
{
|
|
||||||
return mapLiteWalletRefreshBundle(result.bundle);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace dragonx::wallet
|
} // namespace dragonx::wallet
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "lite_wallet_refresh_service.h"
|
#include "lite_wallet_gateway.h" // LiteWalletRefreshBundle / LiteWalletRefreshResult
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@@ -134,6 +134,5 @@ const char* liteWalletStateMapIssueName(LiteWalletStateMapIssue issue);
|
|||||||
|
|
||||||
LiteWalletStateMapResult mapLiteWalletRefreshBundle(const LiteWalletRefreshBundle& bundle);
|
LiteWalletStateMapResult mapLiteWalletRefreshBundle(const LiteWalletRefreshBundle& bundle);
|
||||||
LiteWalletStateMapResult mapLiteWalletRefreshResult(const LiteWalletRefreshResult& result);
|
LiteWalletStateMapResult mapLiteWalletRefreshResult(const LiteWalletRefreshResult& result);
|
||||||
LiteWalletStateMapResult mapLiteWalletRefreshServiceResult(const LiteWalletRefreshServiceResult& result);
|
|
||||||
|
|
||||||
} // namespace dragonx::wallet
|
} // 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