feat(lite): async wallet creation with server failover

Mirror the async-open path for wallet creation. beginOpenExisting() and
beginCreateWallet() now both delegate to beginAsyncLifecycle(bool create),
which runs the backend init on a detached thread and walks the failover
server list (preferred server first, then all usable defaults), reporting
the preferred server's error on total failure. The first-run wizard's
Create button drives this through a non-blocking "creating" poll state so
the UI no longer freezes while the backend contacts a (possibly flaky)
lightwalletd. The created seed response is securely wiped immediately and
read back via exportSeed for the reveal/verify steps.

Safe because litelib_initialize_new contacts the server before writing any
wallet file and LightClient::new errors if a wallet already exists, so a
failed candidate leaves no partial state.

Tests: fake backend's initialize_new now honors the dead/warmup server
substrings; testLiteWalletControllerOpenFailover gains a create-failover
case (preferred dead, fallback good -> walletOpen).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-08 11:29:59 -05:00
parent 6ff1fda870
commit 320c659689
5 changed files with 102 additions and 37 deletions

View File

@@ -64,8 +64,20 @@ inline bool liteFakeWalletExists(const char*) { return g_liteFakeWalletExists; }
// Match the real litelib_* return shapes so tests exercise the production walletReady path:
// create/restore return a seed object ({"seed":..,"birthday":..}); open returns the bare
// string "OK" (NOT JSON) — see litelib_initialize_existing.
inline char* liteFakeInitNew(bool, const char*)
inline char* liteFakeInitNew(bool, const char* server)
{
// Honor the dead/warmup substrings so create-with-failover can be exercised (mirrors how the
// real initialize_new contacts the server first and fails before writing a wallet).
if (server) {
const std::string s(server);
if (!g_liteFakeWarmupServerSubstr.empty() &&
s.find(g_liteFakeWarmupServerSubstr) != std::string::npos)
return liteFakeDup("Error: grpc-message: \"error requesting block: -28: "
"Activating best chain...\"");
if (!g_liteFakeDeadServerSubstr.empty() &&
s.find(g_liteFakeDeadServerSubstr) != std::string::npos)
return liteFakeDup("Error: could not connect to server");
}
return liteFakeDup("{\"seed\":\"fake seed phrase words\",\"birthday\":0}");
}
inline char* liteFakeInitFromPhrase(bool, const char*, const char*,