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>
This commit is contained in:
2026-06-04 22:24:18 -05:00
co-authored by Claude Opus 4.8
parent 5586f334a4
commit 012341b1a4
11 changed files with 159 additions and 33 deletions
+7 -7
View File
@@ -119,11 +119,11 @@ std::string redactLitePrivateDataValue(const std::string& value)
LiteWalletLifecycleService::LiteWalletLifecycleService(WalletCapabilities capabilities,
LiteConnectionSettings connectionSettings,
LiteClientBridge bridge,
LiteClientBridge* bridge,
LiteWalletLifecycleOptions options)
: capabilities_(capabilities),
connectionSettings_(std::move(connectionSettings)),
bridge_(std::move(bridge)),
bridge_(bridge),
options_(options)
{
}
@@ -132,7 +132,7 @@ LiteWalletLifecycleAvailability LiteWalletLifecycleService::availability() const
{
if (!isLiteBuild(capabilities_)) return LiteWalletLifecycleAvailability::UnsupportedBuild;
if (!supportsLiteBackend(capabilities_)) return LiteWalletLifecycleAvailability::BackendUnavailable;
if (!bridge_.available()) return LiteWalletLifecycleAvailability::BridgeUnavailable;
if (!bridge_ || !bridge_->available()) return LiteWalletLifecycleAvailability::BridgeUnavailable;
if (!selectLiteServer(connectionSettings_).ok) return LiteWalletLifecycleAvailability::NoUsableServer;
if (!options_.allowBridgeCalls) return LiteWalletLifecycleAvailability::BridgeCallsDisabled;
return LiteWalletLifecycleAvailability::Ready;
@@ -291,7 +291,7 @@ WalletBackendStatus LiteWalletLifecycleService::statusFor(
case LiteWalletLifecycleAvailability::BridgeUnavailable:
return WalletBackendStatus{
WalletBackendState::Unavailable,
detail.empty() ? bridge_.unavailableReason() : detail,
detail.empty() ? (bridge_ ? bridge_->unavailableReason() : "lite bridge is unavailable") : detail,
{},
{},
0.0
@@ -321,7 +321,7 @@ LiteWalletLifecycleResult LiteWalletLifecycleService::executeCreate(
const LiteWalletCreateRequest& request,
const LiteWalletLifecyclePlan& plan)
{
auto bridgeCall = bridge_.initializeNew(request.dangerous, plan.server.url);
auto bridgeCall = bridge_->initializeNew(request.dangerous, plan.server.url);
return bridgeResult(plan, lifecycleCompletedStatus(), bridgeCall);
}
@@ -329,7 +329,7 @@ LiteWalletLifecycleResult LiteWalletLifecycleService::executeOpen(
const LiteWalletOpenRequest& request,
const LiteWalletLifecyclePlan& plan)
{
auto bridgeCall = bridge_.initializeExisting(request.dangerous, plan.server.url);
auto bridgeCall = bridge_->initializeExisting(request.dangerous, plan.server.url);
return bridgeResult(plan, lifecycleCompletedStatus(), bridgeCall);
}
@@ -337,7 +337,7 @@ LiteWalletLifecycleResult LiteWalletLifecycleService::executeRestore(
const LiteWalletRestoreRequest& request,
const LiteWalletLifecyclePlan& plan)
{
auto bridgeCall = bridge_.initializeNewFromPhrase(
auto bridgeCall = bridge_->initializeNewFromPhrase(
request.dangerous,
plan.server.url,
request.seedPhrase,