fix(db/web): the identity wipe runs outside the Web Locks section a concurrent patch can resurrect wiped rows
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 52/100
Research direction
Start in rust/src/db/indexeddb.rs with exclusive(), clear_identity_data, and the three patch/update cycles named in the issue; then read web_lock.rs for the origin-wide lock behavior. Implement the specified lock ordering and cover the wipe-versus-write races, including mark_messages_read. Done when these storage-layer cycles cannot resurrect wiped rows, without changing the stated out-of-scope behavior.
Written by the indexing model from the issue text.
Description
On web, clear_identity_data (rust/src/db/indexeddb.rs:500) erases the identity's stores — trades, messages, bond claims, outbox, orders, the identity-scoped settings keys — in one read-write transaction. But unlike the whole-document writes in that file, it never enters the exclusive section: exclusive() (indexeddb.rs:230) takes the in-process patch_serial mutex plus the origin-wide Web Lock (web_lock::acquire), and the wipe takes neither.
The read-modify-write cycles it races against read a document, change a field and write the document back whole. Interleaved with the wipe:
- Tab B — or a concurrent task in the same tab, since
patch_serialis not held either — reads trade document X. - Tab A's wipe commits: every store cleared.
- Tab B writes document X back whole.
The wiped row is resurrected into the next identity's session — exactly the leak delete_identity promises does not happen (issue #533). The wipe's own atomicity ("all of it commits or none does", indexeddb.rs:528) protects against a partial wipe, not against this: the resurrection happens after the transaction committed. Three cycles have the shape:
- Trade patches, under
TRADES_LOCK(patch_trade_by_order_id,indexeddb.rs:257). - Outbox status updates, under
OUTBOX_LOCK(update_queued_message_status,indexeddb.rs:431). mark_messages_read(indexeddb.rs:367), under no lock at all — not evenpatch_serial: it lists the trade's messages, flipsis_readand saves each back whole. This is also the easiest window to hit, since opening a chat is what triggers it.
An IndexedDB database is shared by every tab and worker of the origin (web_lock.rs:4), so two open tabs are enough.
Native is unaffected: SQLite does these as single atomic UPDATEs in one process (mark_messages_read at sqlite.rs:333, trade patches via json_set), which is why only the web store needs the locks.
Proposed fix
- Add a
MESSAGES_LOCKbesideTRADES_LOCKandOUTBOX_LOCK, and makemark_messages_readenter the exclusive section — that also closes its same-tab interleaving, which exists today independently of the wipe. - Make
clear_identity_dataenter the exclusive section before opening its transaction:patch_serialplus all three origin locks, acquired in a fixed, documented order so a future caller taking more than one lock cannot deadlock against it. - Orders, bond claims and settings need no lock of their own: at the storage layer they are plain puts/deletes (
save_order,save_bond_claim,set_setting).
Out of scope
- A tab still running the old identity can keep plain-writing (new chat messages, new rows) after another tab's wipe — a wider multi-tab identity-coherence question, not a locking gap.
- Read-modify-write cycles one layer above the storage API — e.g. a bond claim is read with
get_bond_claim, changed and written back withsave_bond_claim(orders.rs:4303), and thepush_registrationssettings family follows the same pattern — are cross-tab races of that same coherence question, not of the store's lock discipline. Noted here so they don't read as missed; this issue only covers the storage-layer cycles the existing locks were built for.
Related
Found while verifying #555 (itself from the review of #543 / issue #533).
- Dominant language
- Dart
- Stars
- 11
- Forks
- 9
- Avg merge
- 13h 4m
- Merged PRs (30d)
- 259
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from MostroP2P/app
-
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
Maintainers usually reply within 1 day
-
Add-invoice screen stays on "Sent, waiting for the node" after a late acceptance on a sell orderOpenbug priority: medium
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 85/100
Maintainers usually reply within 1 day
-
area: ui
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
MostroP2P/app#341 · 1 comment ·
Maintainers usually reply within 1 day
Similar issues
-
[BUG][All] VLESS URIs with flow=xtls-rprx-vision-udp443 are silently dropped on subscription importOpen
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
area::timeline needs::triage regression
Difficulty 2/5 1-3 hours Newbie friendliness 80/100
linagora/twake-on-matrix#3450 ·
Maintainers usually reply within 3 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
genkit-ai/genkit-dart#637 ·
Maintainers usually reply within 1 day
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
bggRGjQaUbCoE/PiliPlus#3235 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
lichess-org/mobile#3830 ·
Maintainers usually reply within 2 days