Skip to content

zcash_client_sqlite: Add WalletDb::get_unspent_orchard_notes_at_historical_height#2284

Merged
nuttycom merged 4 commits into
zcash:mainfrom
valargroup:roman/zcash_client_sqlite-0.19.x/get-unspent-notes-historical
Apr 24, 2026
Merged

zcash_client_sqlite: Add WalletDb::get_unspent_orchard_notes_at_historical_height#2284
nuttycom merged 4 commits into
zcash:mainfrom
valargroup:roman/zcash_client_sqlite-0.19.x/get-unspent-notes-historical

Conversation

@p0mvn
Copy link
Copy Markdown
Collaborator

@p0mvn p0mvn commented Apr 11, 2026

Summary

  • Add WalletDb::get_unspent_orchard_notes_at_historical_height, which returns all Orchard notes that existed and were unspent at a given block height for a specific account.

See the full integration note: https://hackmd.io/HstXV5RfSdOSPdEauotrXw

Branching note

This PR targets maint/zcash_client_sqlite-0.19.x as a
SemVer-compatible addition (new public method, no breaking changes).

How We Use It

Token Holder Voting.

Query the set of notes a wallet held at a governance snapshot height, then
pair with witnesses from generate_orchard_witnesses_at_historical_height
to construct voting proofs. See #2283

Changes

  • zcash_client_sqlite/src/wallet/orchard.rs — new pub(crate) fn get_unspent_orchard_notes_at_historical_height query that selects received notes
    mined at or before the given height, excluding any spent at or before
    that height.
  • zcash_client_sqlite/src/lib.rs — public
    WalletDb::get_unspent_orchard_notes_at_historical_height method that delegates
    to the above.
  • zcash_client_sqlite/CHANGELOG.md — added entry under [Unreleased].
  • Unit test (get_unspent_orchard_notes_at_historical_height_boundary_heights)
    verifying correct note visibility across receive, spend, and subsequent
    receive heights.

@p0mvn p0mvn marked this pull request as ready for review April 11, 2026 19:09
@nuttycom nuttycom changed the base branch from maint/zcash_client_sqlite-0.19.x to main April 23, 2026 17:35
…otes

`WalletDb::get_unspent_orchard_notes_at_historical_height` returns all
Orchard notes that existed and were unspent at a given block height for
a specified account. Unlike `select_unspent_notes` (which applies
confirmation, dust, and expiry filters for transaction construction),
this provides an unfiltered view of the historical note set—useful for
auditing or reconstructing wallet state at a past point in time.

Made-with: Cursor
Copy link
Copy Markdown
Collaborator

@nuttycom nuttycom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The suggestions in this review don't necessarily require changes, but I'd like to get responses to the questions they raise before ACK'ing.

Comment thread zcash_client_sqlite/src/wallet/orchard.rs Outdated
Comment thread zcash_client_sqlite/src/wallet/orchard.rs Outdated
Comment thread zcash_client_sqlite/src/wallet/orchard.rs Outdated
Comment thread zcash_client_sqlite/src/wallet/orchard.rs Outdated
Comment thread zcash_client_sqlite/src/wallet/orchard.rs Outdated
Comment thread zcash_client_sqlite/src/wallet/orchard.rs
p0mvn and others added 3 commits April 24, 2026 16:11
…uery

Switch `get_unspent_orchard_notes_at_historical_height` to filter on
`transactions.mined_height` instead of `transactions.block`, and drop
the now-redundant `IS NOT NULL` guards on both the receive and spend
sides.

`block` is set only after the containing compact block has been
scanned, whereas `mined_height` is set as soon as the wallet learns of
the mined height (including through paths such as transparent UTXO
graph retrieval). For the notes this query can return the two are
equivalent in practice (`nf` and `commitment_tree_position` already
require a scan of the receiving block), but `mined_height` is the
right column to filter on semantically, and matches the existing
`mark_orchard_note_spent` and `get_spendable_note` queries.

The `IS NOT NULL` guards were dead code: `NULL <= :height` is always
false in SQLite, so `mined_height <= :height` already excludes
transactions the wallet has not observed as mined.

Addresses review feedback from @nuttycom on zcash#2284.

Made-with: Cursor
Co-Authored-By: Claude <noreply@anthropic.com>
…spent-notes query

Replace `rn.recipient_key_scope IN (0, 1)` with an `IN` clause that
interpolates `KeyScope::EXTERNAL.encode()` and
`KeyScope::INTERNAL.encode()` via `format!`, matching the pattern used
in `wallet/transparent.rs` and
`wallet/init/migrations/transparent_gap_limit_handling.rs`. This keeps
the SQL filter in sync with the `KeyScope` definition if its encoding
ever changes.

Addresses review feedback from @nuttycom on zcash#2284.

Made-with: Cursor
Co-Authored-By: Claude <noreply@anthropic.com>
…n for historical note getter

Clarify in the rustdoc of both the `pub(crate)` helper in
`wallet::orchard` and the public `WalletDb::get_unspent_orchard_notes_at_historical_height`
wrapper that this function does not verify whether a Merkle witness
can be constructed for each returned note at `height`. Witness
construction is a separate concern intended to be handled by callers;
as an example, a companion `WalletDb::generate_orchard_witnesses_at_historical_height`
method returns an actionable error for any position the wallet cannot
witness at the given height (wallet not synced through that height,
checkpoint pruned, or position not in the wallet).

The companion method is referenced by name only rather than via an
intra-doc link because it is introduced in a separate change.

Addresses review feedback from @nuttycom on zcash#2284.

Made-with: Cursor
Co-Authored-By: Claude <noreply@anthropic.com>
@p0mvn p0mvn requested a review from nuttycom April 24, 2026 19:46
@p0mvn
Copy link
Copy Markdown
Collaborator Author

p0mvn commented Apr 24, 2026

@nuttycom thanks for the review. All suggestions have been addressed in three follow-up commits.

Each inline thread has a reply with the specific commit that addresses it.

cargo fmt, cargo clippy --all-features --all-targets -- -D warnings, and the existing get_unspent_orchard_notes_at_historical_height_boundary_heights test all pass locally.

Ready for another look when you have a moment.

Copy link
Copy Markdown
Collaborator

@nuttycom nuttycom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK 268b726

@nuttycom nuttycom enabled auto-merge April 24, 2026 19:54
@nuttycom nuttycom disabled auto-merge April 24, 2026 19:54
p0mvn added a commit to valargroup/librustzcash that referenced this pull request Apr 24, 2026
…uery

Switch `get_unspent_orchard_notes_at_historical_height` to filter on
`transactions.mined_height` instead of `transactions.block`, and drop
the now-redundant `IS NOT NULL` guards on both the receive and spend
sides.

`block` is set only after the containing compact block has been
scanned, whereas `mined_height` is set as soon as the wallet learns of
the mined height (including through paths such as transparent UTXO
graph retrieval). For the notes this query can return the two are
equivalent in practice (`nf` and `commitment_tree_position` already
require a scan of the receiving block), but `mined_height` is the
right column to filter on semantically, and matches the existing
`mark_orchard_note_spent` and `get_spendable_note` queries.

The `IS NOT NULL` guards were dead code: `NULL <= :height` is always
false in SQLite, so `mined_height <= :height` already excludes
transactions the wallet has not observed as mined.

Addresses review feedback from @nuttycom on zcash#2284.

Made-with: Cursor
Co-Authored-By: Claude <noreply@anthropic.com>
p0mvn added a commit to valargroup/librustzcash that referenced this pull request Apr 24, 2026
…spent-notes query

Replace `rn.recipient_key_scope IN (0, 1)` with an `IN` clause that
interpolates `KeyScope::EXTERNAL.encode()` and
`KeyScope::INTERNAL.encode()` via `format!`, matching the pattern used
in `wallet/transparent.rs` and
`wallet/init/migrations/transparent_gap_limit_handling.rs`. This keeps
the SQL filter in sync with the `KeyScope` definition if its encoding
ever changes.

Addresses review feedback from @nuttycom on zcash#2284.

Made-with: Cursor
Co-Authored-By: Claude <noreply@anthropic.com>
p0mvn added a commit to valargroup/librustzcash that referenced this pull request Apr 24, 2026
…n for historical note getter

Clarify in the rustdoc of both the `pub(crate)` helper in
`wallet::orchard` and the public `WalletDb::get_unspent_orchard_notes_at_historical_height`
wrapper that this function does not verify whether a Merkle witness
can be constructed for each returned note at `height`. Witness
construction is a separate concern intended to be handled by callers;
as an example, a companion `WalletDb::generate_orchard_witnesses_at_historical_height`
method returns an actionable error for any position the wallet cannot
witness at the given height (wallet not synced through that height,
checkpoint pruned, or position not in the wallet).

The companion method is referenced by name only rather than via an
intra-doc link because it is introduced in a separate change.

Addresses review feedback from @nuttycom on zcash#2284.

Made-with: Cursor
Co-Authored-By: Claude <noreply@anthropic.com>
@nuttycom nuttycom merged commit 5f91a7c into zcash:main Apr 24, 2026
48 checks passed
@nuttycom nuttycom deleted the roman/zcash_client_sqlite-0.19.x/get-unspent-notes-historical branch April 24, 2026 21:27
p0mvn added a commit to valargroup/librustzcash that referenced this pull request Apr 24, 2026
…tness-historical

Resolves conflicts in zcash_client_sqlite/CHANGELOG.md and
zcash_client_sqlite/src/lib.rs, both caused by
get_unspent_orchard_notes_at_historical_height (added upstream in zcash#2284)
and generate_orchard_witnesses_at_historical_height (added in this branch)
landing side-by-side in the same `## [Unreleased] ### Added` block and
the same `#[cfg(feature = "orchard")] impl WalletDb<...>` block. Both
methods are kept; the upstream method is listed/declared first to
preserve the upstream ordering, with the witness-generation API
following it. The cross-reference in
get_unspent_orchard_notes_at_historical_height to the companion
generate_orchard_witnesses_at_historical_height now points at a method
that actually exists on this branch.

Co-Authored-By: Claude <noreply@anthropic.com>
Made-with: Cursor
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.

2 participants