diff options
| author | Adam Soltys <[email protected]> | 2026-06-25 00:02:51 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-06-25 00:02:51 -0700 |
| commit | 26a5d52cd11adb22cd3cd3de4ead1b1f3fff38e6 (patch) | |
| tree | 2f442542d1c39382e785c69e0784b434a7ac8f11 | |
| parent | d4db7d545d51cde2f5a98426c1839e0fe0745efa (diff) | |
| download | coinosv3-26a5d52cd11adb22cd3cd3de4ead1b1f3fff38e6.tar.gz coinosv3-26a5d52cd11adb22cd3cd3de4ead1b1f3fff38e6.zip | |
Stop full-scanning the API on every load; go Live before Nostr
The refresh request storm (and the 429s) was a full API re-scan running on every
load even when the local cache or Nostr already held the complete state. Now the
full scan runs ONLY when there's neither cache nor Nostr (a seed on a fresh
device); otherwise the socket + frontier poll keep things current and reconcile
held coins — a handful of requests instead of re-querying every historical
address plus its utxos and txs.
Also reordered: startRealtime() now runs BEFORE syncFromNostr (which blocks up to
6s waiting on the relay) and before any discovery scan, so the wallet goes Live
immediately instead of sitting in Polling. retrack() after sync/scan re-subscribes
to the final frontier; a fresh open re-baselines its celebration against it.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
| -rw-r--r-- | src/app.js | 26 |
1 files changed, 17 insertions, 9 deletions
@@ -617,15 +617,6 @@ async function activateAccount(acc, opts = {}) { return; } try { - // Cross-device state: pull the latest from Nostr (may supply state on a - // device with no local cache, or a newer copy from another device). Skipped - // for watch-only accounts, which have no seed-derived sync key. - const hadNostr = wallet.watchOnly ? false : await wallet.syncFromNostr(); - // Always do a full scan to fully reconcile (balance, history confirmations, - // spends, stale cache/relay state). Cache/Nostr just gave us something to - // show instantly; a partial frontier-only refresh leaves the state stale and - // would let the celebration baseline before a known payment is even counted. - await wallet.scan({ silent: hadCache || hadNostr }); // Celebration baseline. Opening/importing/switching a wallet (opts.fresh) // baselines to the current frontier, so payments already received before // opening never trigger the "payment received" screen. A same-session @@ -643,7 +634,24 @@ async function activateAccount(acc, opts = {}) { } } ui.receiveSeenIndex = ack; + + // Go Live immediately: the socket must not wait on Nostr (up to 6s) or any + // discovery scan. The cache/Nostr state is already on screen. wallet.startRealtime(); + + // Cross-device state in the background. State comes from the local cache or + // Nostr — both restore the full balance, coins, and history — so a full API + // scan runs ONLY when we have neither (e.g. a seed imported on a fresh device + // with no synced state); that's what discovers the used addresses. Otherwise + // the socket + frontier poll keep us current with no refresh-time burst. + const hadNostr = wallet.watchOnly ? false : await wallet.syncFromNostr(); + if (!hadCache && !hadNostr) { + await wallet.scan({ silent: false }); + } + // Re-baseline a fresh open against the final frontier (Nostr or the discovery + // scan may have advanced it) so payments that predate the open don't celebrate. + if (opts.fresh) { ack = wallet.nextReceiveIndex; wallet.setReceiveAck(ack); ui.receiveSeenIndex = ack; } + wallet.retrack(); // re-subscribe to the latest frontier (Nostr/scan may have moved it) } catch { enterOfflineFallback(); } |
