Files
ObsidianDragon/src/wallet/lite_wallet_gateway.h
DanS fb481dee81 feat(lite): M2b-1/2 — shared-bridge refactor + sync/refresh into WalletState
Shared-bridge refactor (litelib is a global singleton; every LiteClientBridge calls
litelib_shutdown() on destruction, so services must not each own one):
- LiteWalletLifecycleService, LiteWalletGateway, LiteSyncService now take a non-owning
  LiteClientBridge*; LiteWalletController owns the single bridge and passes &bridge_.

Sync + controller refresh:
- LiteSyncService::startSync executes the real "sync" command (was a stub).
- LiteWalletController: startSync() (auto-fires when a wallet becomes ready) and
  refreshWalletState(WalletState&) — polls syncstatus, runs gateway.refresh(), maps the
  bundle, applies balances/addresses/transactions/sync into WalletState.

Tests:
- fake_lite_backend.h returns command-shaped JSON (per tests/fixtures/lite/result_parsers.json).
- testLiteWalletControllerRefreshPopulatesState drives the full path against the fake.
- Surfaced + worked around a real integration issue: parseLiteInfoResponse requires
  latest_block_height and the gateway aborts the whole refresh on the first command's
  parse failure (fragile vs partial backend responses; hardening tracked for M2b-3).

Verified: ctest green; lite+backend, full-node, lite-no-backend apps + lite_smoke build clean.

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

163 lines
5.2 KiB
C++

#pragma once
#include "lite_client_bridge.h"
#include "lite_connection_service.h"
#include "lite_result_parsers.h"
#include "lite_sync_service.h"
#include "wallet_backend.h"
#include "wallet_capabilities.h"
#include <cstddef>
#include <string>
#include <vector>
namespace dragonx::wallet {
enum class LiteWalletGatewayCommand {
Info,
Height,
Balance,
Addresses,
Notes,
List,
};
enum class LiteWalletGatewayAvailability {
Ready,
UnsupportedBuild,
BackendUnavailable,
BridgeUnavailable,
BridgeCallsDisabled,
NoUsableServer,
};
struct LiteWalletGatewayRequest {
LiteWalletGatewayCommand command = LiteWalletGatewayCommand::Info;
std::string serverUrl;
};
struct LiteWalletGatewayPlan {
bool ok = false;
LiteWalletGatewayCommand command = LiteWalletGatewayCommand::Info;
LiteServerEndpoint server;
std::size_t serverIndex = 0;
bool customServer = false;
bool bridgeExecutionAllowed = false;
std::string commandName;
std::string args;
std::string error;
};
struct LiteWalletGatewayCommandResult {
bool ok = false;
bool attempted = false;
bool bridgeAccepted = false;
LiteWalletGatewayPlan plan;
LiteResultParserError parserError = LiteResultParserError::None;
WalletBackendStatus status;
std::string bridgeResponseRedacted = "<empty>";
std::string error;
LiteInfoResponse info;
LiteHeightResponse height;
LiteBalanceResponse balance;
LiteAddressesResponse addresses;
LiteNotesResponse notes;
LiteTransactionsResponse transactions;
};
struct LiteWalletRefreshRequest {
std::string serverUrl;
bool includeInfo = true;
bool includeHeight = true;
bool includeBalance = true;
bool includeAddresses = true;
bool includeNotes = true;
bool includeTransactions = true;
bool haveSyncStatus = false;
LiteSyncStatusResponse syncStatus;
};
struct LiteWalletRefreshPlan {
bool ok = false;
std::vector<LiteWalletGatewayPlan> commands;
std::string error;
};
struct LiteWalletRefreshBundle {
bool hasInfo = false;
bool hasHeight = false;
bool hasBalance = false;
bool hasAddresses = false;
bool hasNotes = false;
bool hasTransactions = false;
bool hasSyncStatus = false;
bool complete = false;
std::size_t successfulCommandCount = 0;
LiteInfoResponse info;
LiteHeightResponse height;
LiteBalanceResponse balance;
LiteAddressesResponse addresses;
LiteNotesResponse notes;
LiteTransactionsResponse transactions;
LiteSyncStatusResponse syncStatus;
};
struct LiteWalletRefreshResult {
bool ok = false;
bool attempted = false;
LiteWalletRefreshPlan plan;
std::vector<LiteWalletGatewayCommandResult> commandResults;
LiteWalletRefreshBundle bundle;
WalletBackendStatus status;
std::string error;
};
struct LiteWalletGatewayOptions {
bool allowBridgeCalls = false;
};
const char* liteWalletGatewayCommandName(LiteWalletGatewayCommand command);
const char* liteWalletGatewayAvailabilityName(LiteWalletGatewayAvailability availability);
std::vector<LiteWalletGatewayCommand> liteWalletRefreshCommands(const LiteWalletRefreshRequest& request);
LiteWalletRefreshBundle assembleLiteWalletRefreshBundle(const std::vector<LiteWalletGatewayCommandResult>& results,
const LiteWalletRefreshRequest& request);
class LiteWalletGateway {
public:
LiteWalletGateway(WalletCapabilities capabilities,
LiteConnectionSettings connectionSettings,
LiteClientBridge* bridge,
LiteWalletGatewayOptions options = {});
const WalletCapabilities& capabilities() const { return capabilities_; }
const LiteConnectionSettings& connectionSettings() const { return connectionSettings_; }
const LiteWalletGatewayOptions& options() const { return options_; }
LiteWalletGatewayAvailability availability() const;
WalletBackendStatus status() const;
LiteWalletGatewayPlan planCommand(const LiteWalletGatewayRequest& request) const;
LiteWalletRefreshPlan planRefresh(const LiteWalletRefreshRequest& request) const;
LiteWalletGatewayCommandResult fetchCommand(const LiteWalletGatewayRequest& request);
LiteWalletRefreshResult refresh(const LiteWalletRefreshRequest& request);
private:
LiteServerSelectionResult selectServerForRequest(const std::string& serverUrl) const;
WalletBackendStatus statusFor(LiteWalletGatewayAvailability availability,
const std::string& detail = {}) const;
LiteWalletGatewayCommandResult blockedCommandResult(const LiteWalletGatewayPlan& plan,
const WalletBackendStatus& blockedStatus) const;
LiteWalletGatewayCommandResult executePlannedCommand(const LiteWalletGatewayPlan& plan);
LiteWalletGatewayCommandResult parseBridgeResponse(const LiteWalletGatewayPlan& plan,
const std::string& response) const;
WalletCapabilities capabilities_;
LiteConnectionSettings connectionSettings_;
LiteClientBridge* bridge_ = nullptr; // non-owning; owned by LiteWalletController
LiteWalletGatewayOptions options_;
};
} // namespace dragonx::wallet