diff options
| author | Adam Soltys <[email protected]> | 2026-08-31 13:10:07 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-08-31 13:10:07 -0700 |
| commit | 21418741adfa8d16c53a20a5cc0d2d78a758ed89 (patch) | |
| tree | be989ab21ad3e41c90d0f43d8250bbd548378d0e /src/features/ark.js | |
| parent | 193f49a7a4fb73ef7bfa405c17e8da3ab94f4205 (diff) | |
| download | coinosv3-21418741adfa8d16c53a20a5cc0d2d78a758ed89.tar.gz coinosv3-21418741adfa8d16c53a20a5cc0d2d78a758ed89.zip | |
Cold boots stop lying for a few seconds: an empty profile answer (relays still dialing) no longer clobbers a remembered avatar with a punk — stale fields hold while the refresh does its rounds — and the ark merge marks coins spent the moment a synced movement or done action names them as consumed inputs, instead of double-counting a sleeping device's view (output merged in, inputs still 'spendable') until the reconcile caught up and the balance visibly ticked
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
Diffstat (limited to 'src/features/ark.js')
| -rw-r--r-- | src/features/ark.js | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/src/features/ark.js b/src/features/ark.js index b123458..ba566ee 100644 --- a/src/features/ark.js +++ b/src/features/ark.js @@ -227,6 +227,24 @@ export function mergeArkStates(a, b) { else { lg.claimed = lg.claimed || rg.claimed; lg.revoked = lg.revoked || rg.revoked; } } out.gifts = [...gifts.values()]; + // Targeted spend knowledge beats waiting for a reconcile: a completed + // movement or done action that names its consumed inputs is direct + // evidence those coins are gone. A device waking cold used to merge in + // another device's renewal/send OUTPUT while still counting the consumed + // inputs as spendable — the balance visibly ticked high, then dropped + // when the reconcile caught up. (This is narrow, evidence-based state — + // not the blanket remote-state adoption the rule above forbids.) + const consumed = new Set(); + for (const x of out.actions || []) { + if (x.step !== 'done') continue; + for (const id of x.inputIds || []) consumed.add(id); + for (const part of x.parts || []) if (part.inputId) consumed.add(part.inputId); + } + for (const m of out.movements || []) { + if (m.status !== 'complete') continue; + for (const id of m.inputIds || []) consumed.add(id); + } + for (const v of out.vtxos) if (v.state === 'spendable' && consumed.has(v.id)) v.state = 'spent'; // The checkpoint is READING PROGRESS, not state: adopting a remote one // skips every message this device never processed — balance appears (the // vtxo unions in) but its receive movement and celebration never happen. |
