diff options
| author | Adam Soltys <[email protected]> | 2026-06-15 12:56:36 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-06-15 12:56:36 -0700 |
| commit | 3ecb137cc4300e60f00fbb575441f34e01839a8e (patch) | |
| tree | 16169e758e281bd565600ed4ec12f183941aec3c | |
| parent | 769589f431725a275751bfc84a0d7e6bacee6d0d (diff) | |
| download | coinosv3-3ecb137cc4300e60f00fbb575441f34e01839a8e.tar.gz coinosv3-3ecb137cc4300e60f00fbb575441f34e01839a8e.zip | |
Apply WS tx payload instantly; faster reconcile
The mempool.space WebSocket push already contains the transaction, so parse
it on arrival to add the incoming UTXO and bump pending immediately, instead
of waiting on a debounced re-scan. The scan still follows (400ms) to
reconcile spends/confirmations. Removes the ~3s our handler added on top of
mempool.space's own push latency.
(Measured: mempool.space itself takes ~8s to see a coinos-broadcast tx due to
p2p propagation — the real fix for incoming-payment latency is the sender
pushing directly to the explorer.)
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
| -rw-r--r-- | src/wallet.js | 42 |
1 files changed, 41 insertions, 1 deletions
diff --git a/src/wallet.js b/src/wallet.js index 2f9fed7..0d24d61 100644 --- a/src/wallet.js +++ b/src/wallet.js @@ -490,6 +490,8 @@ export class Wallet { msg['block-transactions'] || msg['txConfirmed'] ) { + // Update instantly from the pushed tx data, then reconcile via a scan. + this._ingestWs(msg); this._scheduleRefresh(); } }; @@ -514,6 +516,44 @@ export class Wallet { } } + // Optimistically apply transactions from a WS push so an incoming deposit + // shows the instant mempool.space pushes it — no extra round-trip. The + // debounced scan that follows reconciles everything (spends, confirmations). + _ingestWs(msg) { + const txs = []; + const multi = msg['multi-address-transactions']; + if (multi && typeof multi === 'object') { + for (const addr of Object.keys(multi)) { + const g = multi[addr] || {}; + for (const t of g.mempool || []) txs.push(t); + for (const t of g.confirmed || []) txs.push(t); + } + } + const single = msg['address-transactions']; + if (Array.isArray(single)) txs.push(...single); + + let changed = false; + const have = new Set(this.utxos.map(utxoId)); + for (const tx of txs) { + if (!tx || !Array.isArray(tx.vout)) continue; + tx.vout.forEach((vo, i) => { + const a = vo && vo.scriptpubkey_address; + if (!a || !this.addrMap.has(a)) return; + const id = `${tx.txid}:${i}`; + if (have.has(id)) return; + const p = this.addrMap.get(a); + const confirmed = !!(tx.status && tx.status.confirmed); + this.utxos.push({ txid: tx.txid, vout: i, value: vo.value, address: a, chain: p.chain, index: p.index, confirmed }); + have.add(id); + if (confirmed) this.confirmed += vo.value; + else this.pending += vo.value; + changed = true; + }); + } + if (changed) this.emit(); + return changed; + } + _scheduleReconnect() { if (!this._wsWant) return; clearTimeout(this._wsRetry); @@ -528,7 +568,7 @@ export class Wallet { await this.scan({ silent: true }); this.retrack(); } catch {} - }, 800); + }, 400); } stopRealtime() { |
