Draft: Add PIR spendability support to zcash_client_sqlite#13
Closed
p0mvn wants to merge 10 commits into
Closed
Conversation
Nullifier PIR lets the wallet discover Orchard note spendability by querying an external server for nullifier inclusion and Merkle authentication paths, rather than waiting for sequential shard-tree scanning to complete. This significantly reduces the time before notes become spendable. The implementation is gated behind the `spendability-pir` feature flag and comprises: - A `wallet::spendability_pir` module with queries for unspent notes eligible for PIR checking, witness storage/retrieval/validation, and helper types. - A `pir_witness_data` table via the `spendability_pir_tables` migration (unconditional, not feature-gated, to keep the migration DAG identical across all builds). - `WalletCommitmentTrees::get_pir_orchard_merkle_path` trait method (with default no-op) in zcash_client_backend, implemented for `WalletDb` backed by the `pir_witness_data` table. - Changes to `get_wallet_summary` and note selection that treat Orchard notes with PIR witnesses as spendable even when their shard is not fully scanned. - Unconditional `pir_witness_data` cleanup in `truncate_to_height` to invalidate authentication paths after reorgs. Made-with: Cursor
Replace intra-doc link to `zcash_client_sqlite::WalletDb` (unresolvable from zcash_client_backend) with plain text, and apply rustfmt. Made-with: Cursor
The feature flag and its optional dependencies (spend-client, spend-types, witness-client from spendability-pir) were present in the local wired Cargo.toml but missing from the committed version, causing unexpected-cfg lint failures in CI. Made-with: Cursor
Tests that call create_proposed_transactions_pir need cfg(feature = "spendability-pir") in addition to cfg(feature = "orchard"), since the method only exists when the feature is enabled. Made-with: Cursor
Declare the feature flag so check-cfg recognizes it. The PIR network client dependencies (spend-client, spend-types, witness-client) are only available in the local wired build and are not included in the committed Cargo.toml — they pull in transitive deps (valar-ypir, spiral-rs) whose version requirements conflict with the existing lockfile. Made-with: Cursor
check_nullifiers_via_pir and fetch_witnesses_via_pir were never called — the SDK's FFI layer in zcash-swift-wallet-sdk/rust/src/spendability.rs calls spend_client and witness_client directly. Removing these also eliminates the only use of spend-client and witness-client within zcash_client_sqlite, so those crate dependencies are no longer needed here. Made-with: Cursor
The PCZT creation path doesn't need PIR witness selection — it always uses the local ShardTree. The parameter was threaded through from the FFI but never meaningfully varied; the caller (SDK) hardcoded the value based on sync status, which is the wrong layer for that decision. The shared build_proposed_transaction still accepts the parameter behind cfg(spendability-pir) for the create_proposed_transactions path. Made-with: Cursor
These tests exercise the PIR witness path in get_wallet_summary, which is guarded by cfg!(feature = "spendability-pir") at compile time. When built with only the orchard feature, the PIR path is dead and notes are never promoted to spendable, causing the assertions to fail. Made-with: Cursor
get_pir_witnessed_notes and PirWitnessedNote were unused by any caller outside of tests. delete_all_pir_witnesses was debug scaffolding marked for removal before merge. Drop all three along with their SQL, tests, and the WalletDb forwarding methods. Made-with: Cursor
This was referenced Apr 10, 2026
greg0x
pushed a commit
that referenced
this pull request
Apr 14, 2026
…f0768ea4..dd0ea2c3c5 dd0ea2c3c5 Merge pull request #23 from zcash/2026-03-doc-fixes 93b26b7db1 v0.4.1 release - minor doc fixups d528fa82e3 Merge pull request #22 from zcash/2025-12-doc-git-subtree b421ef0b34 Merge pull request #22 from zcash/2025-12-doc-git-subtree 4a26e54c36 Fix git subtree command syntax in README 34bb38b606 Merge pull request #20 from zcash/doc/get_block a507182f92 Document GetBlock transparent data behavior and clarify nullifier RPCs fc5cc9a4b1 Merge pull request #19 from zcash/deprecate_get_nullifiers f0ebc72cad Mark `GetBlockNullifiers` and `GetBlockRangeNullifiers` as deprecated. 9a5f7a0eec Merge pull request #16 from zcash/2026-01-remove-fullHeader f1095897d9 revert the previous PR that added BlockID.fullHeader 99d9bf9fff Merge pull request #15 from zcash/2025-12-compactblock-doc bbdd689d73 either CompactBlock.{hash, prevHash}, or CompactBlock.header aa42926ed3 Merge pull request #13 from pacu/add-README da4d3d57d8 Add rationale suggested by @LarryRuane 4edd22465b fix type e36df314b8 clean up whitespace and line width 215cb5a3f3 Add PR suggestions. Organize Clients section 3e78d5d872 Apply suggestions from code review 96b86544db Apply suggestion from @LarryRuane 6259b97df0 Apply suggestion from @nuttycom f2fcef3e42 Apply suggestion from @nuttycom 8cc1e66b11 Apply suggestion from @LarryRuane 99132222dd Apply suggestion from @nuttycom 207cc5e6f9 create a README file with context and instructions 7392b9706f Merge pull request #12 from zcash/release/v0.4.0 git-subtree-dir: zcash_client_backend/lightwallet-protocol git-subtree-split: dd0ea2c3c5827a433e62c2f936b89efa2dec5a9a
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Use Private Information Retrieval to detect spent notes and fetch witnesses before sync completes, giving users early visibility into pending spends. Adds the full data flow (SDK synchronizer interface, Root reducer orchestration, shared state), a PIR setup screen in Advanced Settings with a persisted user toggle, and pending-spend UI treatment in transaction rows.
Motivation
During normal wallet sync, Orchard notes are not spendable until the
shard-tree scanner has processed enough blocks to construct a Merkle
authentication path for each note. For wallets that are catching up after
being offline, this can mean a significant delay before funds become
available.
Nullifier PIR (Private Information Retrieval) sidesteps this by querying
an external server for two pieces of information:
wallet mark notes as spent before the scanner confirms it.
needed to spend a note, so the wallet does not need to wait for its
local shard to be fully scanned.
Together, these allow the wallet to display accurate spendable balances
and build transactions within seconds of startup, rather than waiting for
a full scan.
Design Assumptions
Video Demo
https://screen.studio/share/tm6q8yUz
Screenshots
Related PRs
Changes
zcash_client_backendWalletCommitmentTrees::get_pir_orchard_merkle_path— new traitmethod (with default no-op returning
Ok(None)) for retrieving aPIR-provided Orchard Merkle path by commitment tree position.
PirOrchardWitnesstype alias for the witness tuple.spendability-pirfeature flag gating the above.create_proposed_transactionsgains ause_pir_witnessesparameter(feature-gated) that switches the Orchard witness source from the
local ShardTree to stored PIR witnesses.
zcash_client_sqlitewallet::spendability_pirmodule with:get_unspent_orchard_notes_for_pir)insert_pir_witness,get_pir_witness,validate_orchard_witness, etc.)UnspentOrchardNote,NoteNeedingWitness,PirWitnessRow,PirWitnessedNote,PirWitnessValidationspendability_pir_tablesmigration creating thepir_witness_datatable. The migration is unconditional (not feature-gated) to keep the
migration DAG identical across all builds; the table is empty and
unused when the feature is off.
get_wallet_summarytreats Orchard notes with PIR witnesses asspendable even when their shard is not fully scanned.
select_spendable_notes) accepts Orchard notes withPIR witnesses, bypassing the shard-scanned gate.
truncate_to_heightunconditionally clearspir_witness_datatoinvalidate authentication paths after reorgs.
WalletCommitmentTrees::get_pir_orchard_merkle_pathimplemented forWalletDb, backed by thepir_witness_datatable.[Unreleased].