diff options
| author | Adam Soltys <[email protected]> | 2026-09-04 08:41:47 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-09-04 08:41:47 -0700 |
| commit | 174ce1027327230154b37b80e44c6b2d45929101 (patch) | |
| tree | 4cf0fa5ff6a70be44393af5277856e261297e20f /src/features/sync.js | |
| parent | e887bac97cf292b3f92c19aeba6fc9fa2f98d174 (diff) | |
| download | coinosv3-174ce1027327230154b37b80e44c6b2d45929101.tar.gz coinosv3-174ce1027327230154b37b80e44c6b2d45929101.zip | |
On-chain tx history now UNIONS across every device's core snapshot (+ local state) at sync time, newest-first per txid, instead of adopting the newest core's list wholesale. The wholesale apply lost history: a device whose history fetch keeps failing (mobile 429 storms — the balance scan is cheap per-address calls, history is the heavy /txs pulls) publishes a THIN core with txs:[] and a fine balance, and every fresh device then adopted the newest=thin core and showed a balance with no transactions — adam's phone today, with three ~2KB thin cores on the relay shadowing the fat 7KB core from Aug 18 that still holds the history. Union is safe because history is append-mostly and every SUCCESSFUL local scan still prunes rows its addresses no longer report; a wiped device also self-heals the fleet, since its republished core carries the union'd txs back to the relay
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MGzU12QrAA4G6BYGzGVdXz
Diffstat (limited to 'src/features/sync.js')
| -rw-r--r-- | src/features/sync.js | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/src/features/sync.js b/src/features/sync.js index 93451df..4b011c4 100644 --- a/src/features/sync.js +++ b/src/features/sync.js @@ -141,10 +141,29 @@ export function installSyncWallet(wallet) { // full snapshot — they'd blank the core fields they don't carry. const fulls = mine.filter((s) => isCoreDtag(s.dtag, this.netName)); const newest = fulls[0] && fulls[0].state; // fetchAllStates returns newest-first + const localTxs = this.txs || []; if (newest && (newest.savedAt || 0) > (this._savedAt || 0)) { this._applySnapshot(newest); // re-runs extension loads (idempotent merge) this.emit(); } + // On-chain tx history: UNION across every device's core and what this + // device already had, newest-first so the freshest confirmation data + // wins per txid. Newest-core-wholesale alone lost history: a device + // whose history fetch keeps failing (mobile 429 storms) publishes a + // THIN core — balance present, txs empty — and every fresh device then + // adopted it and showed a balance with no transactions (adam's phone, + // 2026-09-04) while a fat core sat shadowed in an older device slot. + // Safe because history is append-mostly and every SUCCESSFUL local + // scan still prunes rows its addresses no longer report. + const byId = new Map(); + for (const list of [this.txs || [], localTxs, ...fulls.map((s) => s.state.txs || [])]) { + for (const t of list) if (t && t.txid && !byId.has(t.txid)) byId.set(t.txid, t); + } + if (byId.size > (this.txs || []).length) { + this.txs = [...byId.values()]; + this._sortTxs(); + this.emit(); + } this.saveCache(); // persist the merged result + republish our own slot return true; }, |
