Skip to content

perf(drive-abci): read shielded encrypted notes in one chunk-aligned range read - #5030

Merged
QuantumExplorer merged 1 commit into
v4.2-devfrom
claude/nostalgic-wright-727ec6
Sep 27, 2026
Merged

QuantumExplorer merged 1 commit into
v4.2-devfrom
claude/nostalgic-wright-727ec6

Conversation

@QuantumExplorer

@QuantumExplorer QuantumExplorer commented Sep 27, 2026 •

Copy link
Copy Markdown
Member

Basic explanation

What this does: A wallet that holds shielded funds finds its notes by asking a node for pages of encrypted notes and trying to decrypt each one. The node stores finished notes in bundles of 2048. To answer one page, the old code unpacked a whole bundle again for every single note it returned, so a full page unpacked the same bundle up to 2048 times. The node now unpacks each bundle once per page.

Value: Serving a page gets much cheaper. In a debug build, reading 8192 notes went from 64 s to under 3 s. Wallets scanning for shielded funds get answers sooner, and nodes spend far less CPU on this request.

Risks: Low. Wallets get exactly the same answer as before, and nothing here touches consensus, so nodes cannot disagree because of it. The one visible difference is on a node whose database is already damaged: it now returns an error instead of a quietly shortened page. The new test is slow (about a minute in a debug build) because it reruns the old note-by-note read to compare against.

Issue being fixed or feature implemented

The non-proved branch of getShieldedEncryptedNotes read one note at a time with commitment_tree_get_value. For a position inside a compacted chunk, that call reads and deserializes the whole chunk blob (2048 entries of about 344 bytes) to return a single entry. A page can hold up to max_query_chunks × 2048 notes (8192 with DRIVE_ABCI_QUERY_VERSIONS v1), so serving one page deserialized each chunk it covered once per note in it.

Measured in a debug build on a pool of 8192 notes: 64 s reading one position at a time, against 2.9 s for a full walk with the range read (and that walk also inserted every note).

What was done?

The non-proved branch in packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs now makes one commitment_tree_get_range(pool_path, &[SHIELDED_NOTES_KEY], start_index, limit, ..) call. GroveDB's range read is chunk-aligned: it reads and deserializes each chunk the page overlaps once, then reads the buffered notes one by one.

Unchanged:

  • Validation: start_index must be chunk-aligned, count == 0 or count > max becomes max, and the limit is clamped to u16.
  • Mapping: each stored value (cmx 32 || rho 32 || cv_net 32 || encrypted_note rest) becomes an EncryptedNote exactly as before, still stopping at the first value of 96 bytes or less.
  • End of tree: the page stops at the last note. get_range already clamps to the tree's total_count.
  • Proved branch, response metadata, and the query version.

Example, on a pool holding 2048 + 5 notes (one compacted chunk plus five buffered notes):

Request: getShieldedEncryptedNotes { start_index: 0, count: 0, prove: false }

Before: 2053 commitment_tree_get_value calls
        2048 of them each deserialize the full 2048-entry chunk blob
After:  1 commitment_tree_get_range call
        the chunk blob is deserialized once, then 5 buffer reads

Response: identical, 2053 EncryptedNote entries in position order
Request: getShieldedEncryptedNotes { start_index: 2048, count: 3, prove: false }

Before: 3 commitment_tree_get_value calls (buffer only)
After:  1 commitment_tree_get_range call, 3 buffer reads

Response: identical, the notes at positions 2048, 2049, 2050

Notes for reviewers

The response is the same for every request on healthy state. It differs only in cases a valid request on healthy state cannot reach:

  • Missing buffer value, or a chunk blob with the wrong entry count (storage corruption): the old loop quietly returned a shortened page. The range read returns a GroveDB error, which the query surfaces through the existing error mapping.
  • start_index near u64::MAX: the old loop's start_index + limit panicked on overflow in debug builds and gave an empty page in release. The range read saturates, so the page is empty in both.

Queries are not consensus, so there is no protocol version change.

How Has This Been Tested?

New test test_v0_range_read_matches_per_position_reads_across_chunk_and_buffer:

  • Inserts 2048 + 5 notes whose cmx, rho, cv_net and ciphertext each carry the note's position.
  • Walks the whole pool with the old per-position commitment_tree_get_value loop to build a reference, and checks every note's cmx, rho and cv_net against its tags.
  • Queries nine pages and checks that each response equals the matching slice of the reference: the default count, 1, one short of the chunk, exactly the chunk, the chunk plus part of the buffer, over the cap, part of the buffer, buffer to the end, and past the end.

The test takes about 60 s in a debug build. Nearly all of that is the one-at-a-time reference walk over the compacted chunk, which is the cost this PR removes from the query.

Ran locally:

  • cargo test -p drive-abci --lib query::shielded: 37 passed, 0 failed
  • cargo clippy -p drive-abci --all-targets -- -D warnings: clean

Breaking Changes

None. Query responses are unchanged, and no consensus code or protocol version is touched.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed
  • If I added or changed GroveDB structure, I described it in the area's structure.rs, regenerated grovedb-structure.json, and checked the structure viewer link posted on this pull request

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

🤖 Generated with Claude Code

PR Hygiene · 24efe07

  • Bots — coderabbitai skipped after its own rate limit · thepastaclaw not yet — /skip-bots proceeds without the ones not yet reported
  • Self-review — post /self-reviewed once the bots are done
  • Within your 5 open PRs
  • Build green
  • Approvals — you own every area touched; none needed

When every box is checked the PR Hygiene check passes and this can merge.

…range read

The non-proved branch of getShieldedEncryptedNotes called
commitment_tree_get_value once per position. For a position inside a
compacted chunk that call reads and deserializes the whole chunk blob
(2048 entries) to return one entry, so a single page of up to
max_query_chunks x 2048 notes deserialized each chunk once per note.

The branch now makes one commitment_tree_get_range call, which reads and
deserializes each chunk the page overlaps once. Validation, the note
mapping, and the stop at the end of the tree are unchanged, so every
request on healthy state gets the same response as before.

A new test inserts one compacted chunk plus five buffered notes and
checks nine pages against the old per-position read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added this to the v4.2.0 milestone Sep 27, 2026
@coderabbitai

coderabbitai Bot commented Sep 27, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

Next included review available in 50 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository: dashpay/platform/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 774145c8-dd59-4157-ac13-0345ef3c73a1

📥 Commits

Reviewing files that changed from the base of the PR and between 5e4b799 and 24efe07.

📒 Files selected for processing (1)
  • packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the waiting-bots Waiting for the review bots to report on this head label Sep 27, 2026
@thepastaclaw

thepastaclaw commented Sep 27, 2026 •

Copy link
Copy Markdown
Collaborator

🔍 Review in progress — actively reviewing now (commit 24efe07) · triage: low

@github-actions github-actions Bot added the bot-review-skipped A required review bot did not report; it was skipped by the window or by a person. label Sep 27, 2026
@QuantumExplorer
QuantumExplorer merged commit fb73ef8 into v4.2-dev Sep 27, 2026
22 of 23 checks passed
@QuantumExplorer
QuantumExplorer deleted the claude/nostalgic-wright-727ec6 branch September 27, 2026 04:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot-review-skipped A required review bot did not report; it was skipped by the window or by a person. waiting-bots Waiting for the review bots to report on this head

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants