Skip to content

Hold lookups a reply queues until the next chain tip - #212

Merged
p0mvn merged 7 commits into
mainfrom
ai-dev/t-276f632e7b4942b7/a1/l1-receipt-next-tip
Oct 15, 2026
Merged

p0mvn merged 7 commits into
mainfrom
ai-dev/t-276f632e7b4942b7/a1/l1-receipt-next-tip

Conversation

@p0mvn

@p0mvn p0mvn commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

At a given chain tip, a private reply should only change what the wallet asks at a later tip. Txid display lookups ("receipts") broke that rule: when transparent recovery found a receive, or an Enhance reply marked a transaction mixed, the new lookup was due at once and sorted first, so the display service could see another service's reply turn into a query seconds later in the same sync.

This holds such lookups back until the chain tip changes:

  • A new in-memory TransparentPirSession, shaped like EnhancePirSession, records the chain tip at which each lookup was newly queued. WalletDb gets a fresh one by default; with_transparent_pir_session, set_transparent_pir_session and transparent_pir_session let an app's handles on one wallet share it.
  • Every path that queues a lookup records the transactions it newly queues: recovery commits and activation, Enhance replies that mark a transaction mixed, status replies that mark a mixed transaction mined, receiver PIR restore, a policy change, and scanning. Adding a reason to a lookup that was already queued records nothing, so older work keeps its place.
  • The lookup listing leaves the recorded transactions out until the tip differs, whether it rose or a reorg lowered it. A preferred transaction (the user opened its receipt) is held back too, so a reply and a tap cannot reveal the row together. Filtering in the listing, rather than in the app, keeps held rows from using up the listing limit.
  • Records follow the wallet transaction that queued the work, like the Enhance session's journal: a rolled-back write, including a recovery commit whose facts were refused, records nothing.
  • The parked listing and the display views are unchanged.

Existing tests that queued a lookup and listed it at the same tip now check that it is held and listed after the next block, or release it as a restart would when they test later stages of the lookup. The PIR adapter's end-to-end receipt test does the same: it checks that the lookups activation queued are held, then releases them as a restart would, so the account keeps its tip and private authority for the rest of the flow.

Breaking changes

  • DB: None. No tables, columns or migrations; the record is in memory and a restart starts empty.
  • API: New TransparentPirSession and three WalletDb methods. Handles opened on the same wallet should share one session, as they share the Enhance session; a handle with its own session lists work another handle queued at the same tip. Several crate-internal storage functions take the session.
  • Other: Lookups that a reply or a scan queues now appear in transparent_detail_work one chain tip later. After a restart they are listed at once; a restart is visible to the services anyway.

Validation

The tests were committed first and run against main, where the new behaviour tests fail:

  • a receive recovered at the current tip is still listed at that tip (assert!(!listing(&st).contains(&txid)) fails), and likewise when a reorg is about to lower the tip;
  • an Enhance reply that marks a transaction mixed queues a lookup that is listed at once (assert!(!lookups(&case.st).contains(&case.txid)) fails);
  • work queued before the tip stays listed, but the listing also gains the new receive, so the before/after comparison fails;
  • the test that shares the session between two handles does not compile on main, because the session accessors are new; it was set aside for that run.

With the change, the SQLite detail and recovery tests in the transparent configuration and the transparent PIR adapter's test-support suite pass locally, and Clippy reports no new warnings in the default, orchard or transparent configurations. CI passes on this head in every configuration.

🤖 Generated with Claude Code

p0mvn and others added 2 commits October 15, 2026 01:32
Recovery and Enhance replies can queue a txid lookup that the listing
returns at once, so the display service sees another service's reply
turn into a query within one sync. These tests expect such work to be
held back until the tip changes, including when the user prefers it,
and released by a reorg, a restart, or the next block.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A recovery, Enhance or status reply can queue a txid lookup that the
detail listing returned at once, so the display service saw another
service's reply turn into a query in the same sync.

A new in-memory TransparentPirSession, shared by a wallet's handles like
EnhancePirSession, records the chain tip at which each lookup was newly
queued. The listing leaves those out, preferred or not, until the tip
changes. Records are journaled with the wallet transaction that queued
the work, and a savepoint's journal is dropped with its rollback. No
table, column or migration.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
p0mvn and others added 3 commits October 15, 2026 03:07
Activation queues the recovered receives' lookups at the current tip,
so the listing now holds them back. The test checks that, then
releases them as a restart would, keeping its tip so the account
keeps private authority for the rest of the flow. A by-reference
set_transparent_pir_session matches the other handle setters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without Orchard, storing a sent transaction queues no lookup, so the
parameter is gated like the gap limits beside it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@p0mvn

p0mvn commented Oct 15, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-15T23:54:44.725881Z ad83ce5 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

…on-fix

# Conflicts:
#	librustzcash/zcash_client_sqlite/CHANGELOG.md
#	librustzcash/zcash_client_sqlite/src/lib.rs
#	librustzcash/zcash_client_sqlite/src/wallet.rs
#	librustzcash/zcash_client_sqlite/src/wallet/init/migrations/fix_broken_commitment_trees.rs
@p0mvn

p0mvn commented Oct 15, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

Reviewed commit: ad83ce5a73

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@p0mvn
p0mvn marked this pull request as ready for review October 15, 2026 23:58
@p0mvn
p0mvn merged commit 073fbca into main Oct 15, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant