Skip to content

feat(grovedb,merk): no-prove query_aggregate_count_and_sum accumulator#676

Merged
QuantumExplorer merged 6 commits into
developfrom
claude/fervent-hofstadter-bf4862
May 20, 2026
Merged

feat(grovedb,merk): no-prove query_aggregate_count_and_sum accumulator#676
QuantumExplorer merged 6 commits into
developfrom
claude/fervent-hofstadter-bf4862

Conversation

@QuantumExplorer
Copy link
Copy Markdown
Member

@QuantumExplorer QuantumExplorer commented May 20, 2026

Summary

Adds the no-prove sibling of Query::new_aggregate_count_and_sum_on_range: GroveDb::query_aggregate_count_and_sum returns (u64 count, i64 sum) from a single merk-internal walk over a ProvableCountProvableSumTree (PCPS) terminator. Same call shape as query_aggregate_sum / query_aggregate_count, but yields both metrics at once.

Why

Consumers that need both metrics on the no-proof path currently issue two parallel accumulator calls under a shared read transaction. Same cost class (two O(log n) merk walks), but two grovedb round-trips and two merk-internal traversals. Dash Platform's AVG no-prove dispatcher (dashpay/platform#3690) does this today — see flat_aggregate_count_and_sum at packages/rs-drive/src/query/drive_document_count_and_sum_query/executors/range_no_proof.rs. A combined no-prove primitive collapses those into one call, mirroring what the proof-side combined primitive already does for the prove path.

What changed

  • merk/.../aggregate_count_and_sum/walk.rs (new) — walk_count_and_sum classification walker accumulating (u128, i128) end-to-end so adversarial intermediate states cannot wrap mid-walk.
  • merk/.../aggregate_count_and_sum/prove.rsRefWalker::count_and_sum_aggregate_on_range narrowing to (u64, i64) with the same overflow check sum_aggregate_on_range uses.
  • merk/src/merk/get.rsMerk::count_and_sum_aggregate_on_range with PCPS-only tree-type gate (same shape the proof-side primitive rejects single-axis hosts with) and (0, 0) on empty merk.
  • grovedb/src/operations/get/query.rsGroveDb::query_aggregate_count_and_sum mirroring query_aggregate_sum's body. Up-front leaf-shape validation via the pre-existing validate_leaf_aggregate_count_and_sum_on_range, opens leaf merk, delegates, wraps merk error with path context.
  • grovedb-version — new query_aggregate_count_and_sum_on_range slot (0 in v1/v2/v3) — V0-routed like the count/sum siblings.

Tests

  • 10 merk-level no-prove tests covering each Range* variant, full-range happy path, empty merk, disjoint range, mixed-sign sums, and PCPS-only enforcement across every other tree type. Each cross-checks the no-prove walker against the prove-side primitive on the same merk so the two paths cannot silently diverge.
  • 16 grovedb-level no-prove tests covering the same range-shape sweep end-to-end, plus carrier-shape rejection (the leaf-only validator must fire even when the dispatcher would accept the same query), empty-path rejection, NormalTree-at-merk rejection, single-axis ProvableCountSumTree rejection, and GROVE_V2 version-gate routing. Each fixture call asserts (count, sum) against what the prove-side verifier extracts for the same path query, pinning prove/no-prove equivalence the way the existing sum/count tests do.

Out of scope

  • Carrier (query_aggregate_count_and_sum_per_key) variant — not needed for Dash Platform's AVG no-prove dispatcher (the carrier-AVG case is prove-only) and explicitly deferred to a separate PR. The entry-point docstring notes this.
  • No changes to Query::new_aggregate_count_and_sum_on_range, the proof-side primitive, the verifier, or the carrier shape.

Test plan

  • cargo test -p grovedb-merk --features minimal — 667 passed (10 new)
  • cargo test -p grovedb --features minimal — 1849 passed (16 new)
  • cargo clippy -p grovedb-merk --features minimal -- -D warnings — clean
  • cargo clippy -p grovedb --features minimal -- -D warnings — clean

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Introduced a new query operation that retrieves both count and sum statistics in a single execution across a specified data range, eliminating the need for separate count and sum queries.
  • Tests

    • Added comprehensive test coverage for the new operation, including inclusive/exclusive range tests, edge cases with empty trees and mixed values, version compatibility validation, and error handling scenarios.

Review Change Stack

Mirror Query::new_aggregate_count_and_sum_on_range on the no-proof
path. One merk-internal walk returns the in-range (u64 count, i64 sum)
pair from a ProvableCountProvableSumTree terminator, collapsing what
consumers previously did as two parallel query_aggregate_count +
query_aggregate_sum calls under a shared read transaction. Same cost
class as the proof primitive (two O(log n) merk walks), but one
round-trip instead of two.

Adds:
- merk/.../aggregate_count_and_sum/walk.rs: walk_count_and_sum
  classification walker accumulating (u128, i128) end-to-end so
  adversarial intermediate states cannot wrap mid-walk; narrowed at
  the public entry point.
- merk/.../aggregate_count_and_sum/prove.rs: RefWalker entry point
  count_and_sum_aggregate_on_range narrowing to (u64, i64) with the
  same overflow check sum_aggregate_on_range uses.
- merk/src/merk/get.rs: Merk::count_and_sum_aggregate_on_range with
  PCPS-only tree-type gate (same shape the proof-side primitive
  rejects single-axis hosts with) and (0, 0) on empty merk.
- grovedb/src/operations/get/query.rs:
  GroveDb::query_aggregate_count_and_sum mirroring query_aggregate_sum
  body — upfront leaf-shape validation, opens leaf merk, delegates,
  wraps merk error with path context.
- grovedb-version: new query_aggregate_count_and_sum_on_range slot
  (0 in v1/v2/v3) — V0-routed like the count/sum siblings.

Tests:
- 10 merk-level no-prove tests covering each Range* variant, the
  full-range happy path, empty merk, disjoint range, mixed-sign sums,
  and PCPS-only enforcement across every other tree type. Each test
  cross-checks the no-prove walker against the prove-side primitive
  on the same merk so the two paths cannot silently diverge.
- 16 grovedb-level no-prove tests covering the same range-shape sweep
  end-to-end, plus carrier-shape rejection (the leaf-only validator
  must fire even when the dispatcher would accept the same query),
  empty-path rejection, NormalTree-at-merk rejection, single-axis
  ProvableCountSumTree rejection, and GROVE_V2 version-gate routing.
  Each fixture call asserts (count, sum) against what the prove-side
  verifier extracts for the same path query, pinning prove/no-prove
  equivalence the way the existing sum/count tests do.

Carrier (per-key) variant is deferred — not needed for Dash Platform's
AVG no-prove dispatcher and noted as out-of-scope in the entry-point
docstring.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 20, 2026

Warning

Rate limit exceeded

@QuantumExplorer has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 5 minutes and 44 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 93b1f1dc-3df9-4dad-bf40-b1a08bffa1f6

📥 Commits

Reviewing files that changed from the base of the PR and between 9db515e and 4a144ec.

📒 Files selected for processing (4)
  • grovedb/src/operations/get/query.rs
  • grovedb/src/tests/aggregate_count_and_sum_query_tests.rs
  • merk/src/proofs/query/aggregate_count_and_sum/prove.rs
  • merk/src/proofs/query/aggregate_count_and_sum/tests.rs
📝 Walkthrough

Walkthrough

This PR adds a combined no-proof count-and-sum aggregate range query API (query_aggregate_count_and_sum) across GroveDB and Merk. The implementation adds version plumbing, a core subtree walk function, wrapper entry points at the RefWalker and Merk levels, a high-level GroveDB API, and comprehensive tests validating all range shapes and error paths.

Changes

Count-and-Sum Aggregate Range Query

Layer / File(s) Summary
Version plumbing for count-and-sum query
grovedb-version/src/version/grovedb_versions.rs, grovedb-version/src/version/v1.rs, grovedb-version/src/version/v2.rs, grovedb-version/src/version/v3.rs
query_aggregate_count_and_sum_on_range: FeatureVersion field added to GroveDBOperationsQueryVersions struct definition and initialized to 0 across all Grove version constants.
Merk walk implementation for count-and-sum traversal
merk/src/proofs/query/aggregate_count_and_sum/mod.rs, merk/src/proofs/query/aggregate_count_and_sum/walk.rs
Core walk_count_and_sum function classifies subtree regions as Disjoint/Contained/Boundary, recursively accumulates child counts and sums, and conditionally adds current-node contribution for in-range keys using checked subtraction for counts and wrapping subtraction for signed sums.
RefWalker and Merk entry points
merk/src/proofs/query/aggregate_count_and_sum/prove.rs, merk/src/merk/get.rs
RefWalker::count_and_sum_aggregate_on_range wraps the walk function, narrows results from (u128, i128) to (u64, i64), and maps overflow to CorruptedData. Merk::count_and_sum_aggregate_on_range validates tree type (PCPS only), returns (0, 0) for empty trees, and delegates to the RefWalker method.
GroveDB public query_aggregate_count_and_sum API
grovedb/src/operations/get/query.rs
GroveDb::query_aggregate_count_and_sum validates query leaf-shape constraints, opens the target subtree, invokes Merk's count-and-sum method, maps read errors with path context, and returns the (count, sum) pair with accumulated operation cost.
Merk no-proof walk and RefWalker tests
merk/src/proofs/query/aggregate_count_and_sum/tests.rs
Test suite validates count_and_sum_aggregate_on_range no-proof API against prover output across inclusive/exclusive/open-ended ranges, empty PCPS trees, non-PCPS tree rejection, and mixed-sign arithmetic (including negative sums).
GroveDB end-to-end no-proof tests
grovedb/src/tests/aggregate_count_and_sum_query_tests.rs, grovedb/src/tests/mod.rs
Comprehensive test suite for GroveDb::query_aggregate_count_and_sum with 15-key fixture, range-shape sweeps, empty-tree and mixed-negative coverage, validation/rejection tests for invalid inner ranges/empty paths/carrier shapes, merk-level tree-type rejections, and version-gating for GROVE_V2.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • dashpay/grovedb#662: Both PRs extend the same query-version plumbing (GroveDBOperationsQueryVersions and GROVE_V1/V2/V3) and add parallel no-proof Aggregate*OnRange entrypoints in grovedb/src/operations/get/query.rs/merk, with the main PR implementing the new count_and_sum variant alongside the retrieved count-only variant.

  • dashpay/grovedb#670: The main PR's new no-proof query_aggregate_count_and_sum plumbing and RefWalker::count_and_sum_aggregate_on_range reuse/extend the same PCPS "aggregate_count_and_sum" proof infrastructure added in PR #670 (notably the merk/src/proofs/query/aggregate_count_and_sum/* module/prover wiring), so the changes are directly related.

Poem

A hop, skip, and sum away,
Count and tally now both play—
🐰 One walk, two results in a single bound,
No proofs needed, just aggregates found!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a no-proof variant of the aggregate count-and-sum query API across grovedb and merk, which aligns with all the substantial changes in the PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/fervent-hofstadter-bf4862

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 and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 20, 2026

Codecov Report

❌ Patch coverage is 95.67568% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.42%. Comparing base (ad2492d) to head (4a144ec).

Files with missing lines Patch % Lines
...k/src/proofs/query/aggregate_count_and_sum/walk.rs 92.66% 8 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop     #676      +/-   ##
===========================================
+ Coverage    91.41%   91.42%   +0.01%     
===========================================
  Files          235      236       +1     
  Lines        66867    67053     +186     
===========================================
+ Hits         61127    61305     +178     
- Misses        5740     5748       +8     
Components Coverage Δ
grovedb-core 88.94% <100.00%> (+0.01%) ⬆️
merk 92.26% <94.80%> (+0.02%) ⬆️
storage 86.36% <ø> (ø)
commitment-tree 96.43% <ø> (ø)
mmr 96.76% <ø> (ø)
bulk-append-tree 89.26% <ø> (ø)
element 97.36% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@grovedb/src/tests/aggregate_count_and_sum_query_tests.rs`:
- Around line 496-520: The test function
no_proof_combined_v0_envelope_rejected_by_version_gate is misnamed because it
asserts the query succeeds under GROVE_V2; rename the test to reflect the
asserted success (for example
no_proof_combined_v0_envelope_allowed_by_version_gate or
no_proof_combined_v0_envelope_succeeds_under_v2) so the function name aligns
with the assertions in PathQuery::new_aggregate_count_and_sum_on_range and the
subsequent call to grove_db.query_aggregate_count_and_sum that expects success.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 696403ab-7a9a-483f-8987-af946da64661

📥 Commits

Reviewing files that changed from the base of the PR and between ad2492d and 9db515e.

📒 Files selected for processing (12)
  • grovedb-version/src/version/grovedb_versions.rs
  • grovedb-version/src/version/v1.rs
  • grovedb-version/src/version/v2.rs
  • grovedb-version/src/version/v3.rs
  • grovedb/src/operations/get/query.rs
  • grovedb/src/tests/aggregate_count_and_sum_query_tests.rs
  • grovedb/src/tests/mod.rs
  • merk/src/merk/get.rs
  • merk/src/proofs/query/aggregate_count_and_sum/mod.rs
  • merk/src/proofs/query/aggregate_count_and_sum/prove.rs
  • merk/src/proofs/query/aggregate_count_and_sum/tests.rs
  • merk/src/proofs/query/aggregate_count_and_sum/walk.rs

Comment thread grovedb/src/tests/aggregate_count_and_sum_query_tests.rs Outdated
QuantumExplorer and others added 2 commits May 20, 2026 10:01
…nd_sum

The `open_transactional_merk_at_path` error arm was untested — codecov
flagged 6 uncovered lines in the new entry point. Add a test that
queries a non-existent intermediate path to exercise the wrap-and-return
branch before the merk walker is invoked.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CodeRabbit pointed out the test name said "rejected by version gate"
but the body asserts success under GROVE_V2 (the slot is 0). Rename to
no_proof_combined_v0_envelope_accepted_under_v2 so the name matches the
assertion — avoids false signal during failure triage.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
QuantumExplorer added a commit to dashpay/platform that referenced this pull request May 20, 2026
…call

Bumps the grovedb pin to 9db515ef (head of dashpay/grovedb#676), which
adds the combined no-prove `query_aggregate_count_and_sum` accumulator
— a merk-internal `(u128, i128)` walk narrowed to `(u64, i64)` at the
entry point, mirroring the proof-side `AggregateCountAndSumOnRange`
shape.

Rewires `flat_aggregate_count_and_sum` in the joint count+sum executor
to issue one combined accumulator call against
`aggregate_count_and_sum_path_query` instead of two parallel
`query_aggregate_count` + `query_aggregate_sum` calls. Same cost class
(O(log n) at the merk layer either way) but halves the round-trip
count and removes the need for the shared-tx-across-two-reads
plumbing on the flat branch. Compound `In + range` per-In fan-out
still issues one accumulator call per branch under a shared read
transaction — now one call per branch instead of two.

The integration lands ahead of the grovedb PR's review so the platform
side can exercise the primitive end-to-end. If the grovedb PR's
review surfaces changes, the platform pin re-bumps trivially.

Updated docstrings on `drive_document_count_and_sum_query/mod.rs`,
`drive_dispatcher.rs`, `executors/range_no_proof.rs`, and the
`book/src/drive/average-index-examples.md` chapter section to reflect
the single-call aggregate branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Member Author

@QuantumExplorer QuantumExplorer left a comment

Choose a reason for hiding this comment

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

Reviewed

QuantumExplorer and others added 3 commits May 20, 2026 10:23
Local binding instead of a multi-line macro argument expression — easier
for llvm-cov line attribution and otherwise equivalent. The macro
behavior is unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…range

Two consecutive `match try_from { Ok(v) => v, Err(_) => return ... }`
arms collapse to one `.map_err()...and_then(...)` chain. Same behavior
(both narrowing failures still surface as `CorruptedData` with a
descriptive message), fewer instrumented lines for llvm-cov to track on
unreachable defense-in-depth branches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The `(u128, i128) → (u64, i64)` narrow inside
`count_and_sum_aggregate_on_range` was the last defense-in-depth path
codecov was flagging — practically unreachable on an honest merk (PCPS
maintains every aggregate as (u64, i64) at every level), but still
worth pinning so the diagnostic doesn't bitrot.

Extract the narrow into a free `narrow_count_and_sum(u128, i128) ->
Result<(u64, i64), Error>` helper so it can be exercised without
scaffolding a corrupted tree, and add 4 unit tests:
- happy-path for boundary values (0, u64::MAX, i64::MAX, i64::MIN)
- count overflow (count_u128 > u64::MAX)
- sum positive overflow (sum_i128 > i64::MAX)
- sum negative overflow (sum_i128 < i64::MIN)

Bumps patch coverage past the 90% threshold.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@QuantumExplorer QuantumExplorer merged commit 60f2968 into develop May 20, 2026
10 checks passed
@QuantumExplorer QuantumExplorer deleted the claude/fervent-hofstadter-bf4862 branch May 20, 2026 03:58
QuantumExplorer added a commit to dashpay/platform that referenced this pull request May 20, 2026
dashpay/grovedb#676 (the no-prove `query_aggregate_count_and_sum`
primitive) was squash-merged into develop as commit 60f29685. The
content is identical to the PR-branch head 9db515ef that the previous
commit pinned; just moves to the canonical develop ancestry.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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