- LiteWalletController owns a background std::thread worker that, once a wallet is ready,
refreshes every ~4s and publishes a copyable LiteWalletAppRefreshModel under a mutex.
Worker auto-starts on lifecycle-ready and is stopped+joined in the destructor. status_
is written only on the main thread; walletOpen_/syncStarted_ are atomic.
- App::update() calls takeRefreshedModel() and applies it into state_ on the main thread
(WalletState is non-copyable, so the model crosses the thread boundary, not the state),
so the existing Balance/Receive/Transactions tabs populate from lite data.
- refreshWalletState() refactored onto refreshModel() (pure, worker-safe).
- testLiteWalletControllerWorkerProducesModel verifies the worker publishes a populated
model (stable across repeated runs). Builds clean in all configs.
Real-backend smoke (lite_smoke --refresh now runs real output through the parsers) found
two integration bugs, documented in the plan for follow-up:
- syncstatus parser requires synced_blocks/total_blocks but the real idle response is
{"syncing":"false"} (string), so it fails to parse when not actively syncing.
- the first data query (balance/list) blocks on a full chain sync, which would hang the
worker's shutdown join — needs a cancel/timeout path.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
117 lines
5.4 KiB
C++
117 lines
5.4 KiB
C++
// DragonX Wallet - ImGui Edition
|
|
// Copyright 2024-2026 The Hush Developers
|
|
// Released under the GPLv3
|
|
//
|
|
// Real-backend smoke harness for the lite wallet bridge. Links the actual SDXL
|
|
// litelib_* backend (via the same imported CMake target the app uses) and exercises
|
|
// LiteClientBridge against a real lightwalletd server. This is the "real backend smoke
|
|
// test" the implementation plan gates behind passing fake-backend tests.
|
|
//
|
|
// lite_smoke [server-url] [--create]
|
|
//
|
|
// Read-only by default (available / checkServerOnline / walletExists). Pass --create to
|
|
// also attempt a real litelib_initialize_new (writes wallet state — run with an isolated
|
|
// HOME, e.g. HOME=/tmp/lite_smoke env, so it cannot clobber a real wallet).
|
|
|
|
#include "wallet/lite_client_bridge.h"
|
|
#include "wallet/lite_connection_service.h"
|
|
#include "wallet/lite_result_parsers.h"
|
|
|
|
#include <cstdio>
|
|
#include <string>
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
using namespace dragonx::wallet;
|
|
std::setvbuf(stdout, nullptr, _IONBF, 0); // unbuffered so output survives a timeout kill
|
|
|
|
std::string server = "https://lite.dragonx.is";
|
|
bool doCreate = false;
|
|
bool doRefresh = false;
|
|
bool doFull = false;
|
|
for (int i = 1; i < argc; ++i) {
|
|
const std::string arg = argv[i];
|
|
if (arg == "--create") doCreate = true;
|
|
else if (arg == "--refresh") doRefresh = true;
|
|
else if (arg == "--full") doFull = true;
|
|
else server = arg;
|
|
}
|
|
|
|
std::printf("[lite-smoke] server = %s\n", server.c_str());
|
|
|
|
auto bridge = LiteClientBridge::linkedSdxl();
|
|
std::printf("[lite-smoke] available() = %s\n", bridge.available() ? "true" : "false");
|
|
if (!bridge.available()) {
|
|
std::printf("[lite-smoke] reason = %s\n", bridge.unavailableReason().c_str());
|
|
std::printf("[lite-smoke] FAIL: backend not linked\n");
|
|
return 2;
|
|
}
|
|
|
|
const bool walletExists = bridge.walletExists(kDragonXLiteChainName);
|
|
std::printf("[lite-smoke] walletExists(%s) = %s\n", kDragonXLiteChainName, walletExists ? "true" : "false");
|
|
|
|
const bool online = bridge.checkServerOnline(server);
|
|
std::printf("[lite-smoke] checkServerOnline() = %s\n", online ? "true" : "false");
|
|
|
|
if (doCreate) {
|
|
std::printf("[lite-smoke] initializeNew() ... (real network + writes wallet state)\n");
|
|
auto result = bridge.initializeNew(false, server);
|
|
std::printf("[lite-smoke] initializeNew ok = %s\n", result.ok ? "true" : "false");
|
|
if (result.ok) {
|
|
// The response is the new wallet's SEED PHRASE — never print it. Report only
|
|
// that a well-formed, non-empty response came back.
|
|
std::printf("[lite-smoke] wallet created; response len = %zu (seed redacted)\n",
|
|
result.value.size());
|
|
} else {
|
|
std::printf("[lite-smoke] error = %s\n", result.error.c_str());
|
|
}
|
|
}
|
|
|
|
if (doRefresh) {
|
|
// Run each refresh command through the real parser to verify the LIVE backend's
|
|
// JSON shapes match what the gateway expects. Prints flags/counts only (no secrets,
|
|
// addresses, or amounts).
|
|
std::printf("[lite-smoke] --- refresh shape check (real backend output -> parsers) ---\n");
|
|
{
|
|
auto r = bridge.execute("info", "");
|
|
auto p = parseLiteInfoResponse(r.value);
|
|
std::printf("[lite-smoke] info bridge_ok=%d parse_ok=%d err=%s\n",
|
|
r.ok, p.ok, liteResultParserErrorName(p.error));
|
|
}
|
|
{
|
|
auto r = bridge.execute("syncstatus", "");
|
|
auto p = parseLiteSyncStatusResponse(r.value);
|
|
std::printf("[lite-smoke] syncstatus bridge_ok=%d parse_ok=%d err=%s synced=%llu/%llu\n",
|
|
r.ok, p.ok, liteResultParserErrorName(p.error),
|
|
(unsigned long long)p.syncStatus.syncedBlocks, (unsigned long long)p.syncStatus.totalBlocks);
|
|
std::printf("[lite-smoke] syncstatus RAW = %.200s\n", r.value.c_str());
|
|
}
|
|
// The data commands below trigger a blocking full-chain sync on a fresh wallet;
|
|
// gate them behind --full so the shape check stays fast by default.
|
|
if (!doFull) { bridge.shutdown(); std::printf("[lite-smoke] (skipping balance/addresses/list; pass --full)\n"); return 0; }
|
|
{
|
|
auto r = bridge.execute("balance", "");
|
|
auto p = parseLiteBalanceResponse(r.value);
|
|
std::printf("[lite-smoke] balance bridge_ok=%d parse_ok=%d err=%s\n",
|
|
r.ok, p.ok, liteResultParserErrorName(p.error));
|
|
}
|
|
{
|
|
auto r = bridge.execute("addresses", "");
|
|
auto p = parseLiteAddressesResponse(r.value);
|
|
std::printf("[lite-smoke] addresses bridge_ok=%d parse_ok=%d err=%s z=%zu t=%zu\n",
|
|
r.ok, p.ok, liteResultParserErrorName(p.error),
|
|
p.addresses.zAddresses.size(), p.addresses.tAddresses.size());
|
|
}
|
|
{
|
|
auto r = bridge.execute("list", "");
|
|
auto p = parseLiteTransactionsResponse(r.value);
|
|
std::printf("[lite-smoke] list bridge_ok=%d parse_ok=%d err=%s count=%zu\n",
|
|
r.ok, p.ok, liteResultParserErrorName(p.error), p.transactions.transactions.size());
|
|
}
|
|
}
|
|
|
|
bridge.shutdown();
|
|
std::printf("[lite-smoke] done (real litelib_* symbols are callable; results above are live)\n");
|
|
return 0;
|
|
}
|