Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
5ccce35
feat(WIP): Element::ProvableCountProvableSumTree foundation
QuantumExplorer May 17, 2026
6064508
fix(tests): bump discriminant-pinning tests for slot 20
QuantumExplorer May 17, 2026
1584284
feat: ProvableCountProvableSumTree tests + integration completion
QuantumExplorer May 17, 2026
60c82ee
feat: dual-axis Node emission unblocks crossover proofs against PCPS
QuantumExplorer May 17, 2026
264d9a7
fix(clippy): indent continuation lines in doc comment
QuantumExplorer May 17, 2026
1532939
test: add coverage for dual-axis Node variants + TreeFeatureType + pr…
QuantumExplorer May 17, 2026
b0d62bc
style: cargo fmt
QuantumExplorer May 17, 2026
f2514e7
test: constructors + helpers for ProvableCountProvableSumTree
QuantumExplorer May 17, 2026
2c14b8e
ci: empty commit to retry codecov shard merge
QuantumExplorer May 17, 2026
0d2330b
test: more PCPS coverage — proof_node_type + dual-axis verifier paths
QuantumExplorer May 17, 2026
7acc7e2
test: encoding_length + regular-query reject paths for dual-axis Nodes
QuantumExplorer May 17, 2026
643816b
fix(test): use fully-qualified Encode method calls
QuantumExplorer May 17, 2026
0b716e9
test: regular-prove-on-PCPS tests cover the dual-axis helper methods
QuantumExplorer May 17, 2026
527e3af
test: shape-walk rejection paths + dual-axis Node variant coverage
QuantumExplorer May 17, 2026
979d1c0
fix: address CodeRabbit findings for ProvableCountProvableSumTree PR
QuantumExplorer May 17, 2026
47964dc
ci: empty commit to retry codecov shard merge
QuantumExplorer May 17, 2026
73637a4
test: cover top-3 patch-coverage gaps to reach 90%
QuantumExplorer May 17, 2026
6825810
fix: 3 PCPS findings — ref proof downgrade, chunk allowlist, trunk_qu…
QuantumExplorer May 17, 2026
7b045cf
test: cover v0 ref-rewrite + write_chunk arms (90% patch coverage)
QuantumExplorer May 17, 2026
ceb52cb
test: tighten 2 CodeRabbit nitpicks on PCPS coverage tests
QuantumExplorer May 17, 2026
7507285
Merge develop, extend PR #672 (reject suppression wrappers) to PCPS
QuantumExplorer May 17, 2026
ee8b431
Merge remote-tracking branch 'origin/develop' into feat/provable-coun…
QuantumExplorer May 17, 2026
7f9fba7
Merge develop (PR #669), extend count-offset paginated proofs to PCPS
QuantumExplorer May 17, 2026
a776695
test: cover dual-axis arms in count_offset emit/verify (90%+ patch)
QuantumExplorer May 17, 2026
745672b
fix: include KVCountSum in GroveDB post-processing for PCPS Items
QuantumExplorer May 17, 2026
3b28a0e
fix: revert V0 prover modifications, reject PCPS at V0 dispatch
QuantumExplorer May 17, 2026
3ccc593
test: cover PCPS batch propagation path (+0.1% patch coverage)
QuantumExplorer May 17, 2026
79d45a7
feat(query,merk,grovedb): AggregateCountAndSumOnRange — PCPS-only com…
QuantumExplorer May 17, 2026
517f327
test(pcps): cover combined-aggregate negative paths to lift patch cov…
QuantumExplorer May 17, 2026
2d675c0
fix: iter_is_valid_for_type wrapper arms preserve cost (CodeRabbit)
QuantumExplorer May 17, 2026
a4e9b41
test(pcps): broaden patch coverage for combined-aggregate / cross-agg…
QuantumExplorer May 17, 2026
6f05958
test(pcps): broaden patch coverage to 91% — add 7 PCPS tests
QuantumExplorer May 17, 2026
5e4bcae
test(merk): fail forged-KVDigestCountSum tests if no op found
QuantumExplorer May 17, 2026
8bcb975
refactor(grovedb-query): split aggregate_sum & aggregate_count_and_su…
QuantumExplorer May 17, 2026
e69df59
feat(grovedb,query): carrier-shape AggregateSumOnRange & AggregateCou…
QuantumExplorer May 17, 2026
52e413c
fix(grovedb): two carrier-aggregate post-merge audit findings
QuantumExplorer May 17, 2026
f376510
refactor(grovedb): dedupe shared aggregate-proof helpers into aggrega…
QuantumExplorer May 18, 2026
94d3662
refactor(grovedb): dedupe AggregateClassification and require_v1_enve…
QuantumExplorer May 18, 2026
65fda0b
docs: scrub PR-event / review-process references from comments
QuantumExplorer May 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
821 changes: 821 additions & 0 deletions docs/PROVABLE_COUNT_PROVABLE_SUM_TREE_IMPLEMENTATION.md

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions grovedb-bulk-append-tree/src/proof/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,13 @@ fn query_to_ranges(query: &Query, total_count: u64) -> Result<Vec<(u64, u64)>, B
.into(),
));
}
QueryItem::AggregateCountAndSumOnRange(_) => {
return Err(BulkAppendError::InvalidInput(
"AggregateCountAndSumOnRange is only supported on \
ProvableCountProvableSumTree, not on BulkAppendTree"
.into(),
));
}
};
ranges.push((start, end));
}
Expand Down
7 changes: 7 additions & 0 deletions grovedb-dense-fixed-sized-merkle-tree/src/proof/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,13 @@ pub(crate) fn query_to_positions(query: &Query, count: u16) -> Result<Vec<u16>,
.into(),
));
}
QueryItem::AggregateCountAndSumOnRange(_) => {
return Err(DenseMerkleError::InvalidProof(
"AggregateCountAndSumOnRange is only supported on \
ProvableCountProvableSumTree, not on dense fixed-size merkle trees"
.into(),
));
}
}
}

Expand Down
83 changes: 66 additions & 17 deletions grovedb-element/src/element/constructor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,47 @@ impl Element {
Element::ProvableSumTree(maybe_root_key, sum_value, flags)
}

/// Set element to default empty provable count provable sum tree without
/// flags.
///
/// `ProvableCountProvableSumTree` bakes BOTH the per-node count AND the
/// per-node sum into the node hash, enabling both
/// `AggregateCountOnRange` and `AggregateSumOnRange` proofs against the
/// same tree.
pub fn empty_provable_count_provable_sum_tree() -> Self {
Element::new_provable_count_provable_sum_tree(Default::default())
}

/// Set element to default empty provable count provable sum tree with
/// flags.
pub fn empty_provable_count_provable_sum_tree_with_flags(flags: Option<ElementFlags>) -> Self {
Element::new_provable_count_provable_sum_tree_with_flags(Default::default(), flags)
}

/// Set element to a provable count provable sum tree without flags.
pub fn new_provable_count_provable_sum_tree(maybe_root_key: Option<Vec<u8>>) -> Self {
Element::ProvableCountProvableSumTree(maybe_root_key, 0, 0, None)
}

/// Set element to a provable count provable sum tree with flags.
pub fn new_provable_count_provable_sum_tree_with_flags(
maybe_root_key: Option<Vec<u8>>,
flags: Option<ElementFlags>,
) -> Self {
Element::ProvableCountProvableSumTree(maybe_root_key, 0, 0, flags)
}

/// Set element to a provable count provable sum tree with flags, count,
/// and sum value.
pub fn new_provable_count_provable_sum_tree_with_flags_and_sum_and_count_value(
maybe_root_key: Option<Vec<u8>>,
count_value: CountValue,
sum_value: SumValue,
flags: Option<ElementFlags>,
) -> Self {
Element::ProvableCountProvableSumTree(maybe_root_key, count_value, sum_value, flags)
}

/// Set element to an empty commitment tree.
///
/// Returns `InvalidInput` if `chunk_power > 31`.
Expand Down Expand Up @@ -515,22 +556,24 @@ impl Element {
/// parent sum tree's running sum when inserted. Counts (if any) still
/// propagate.
///
/// Only the five sum-bearing tree variants are accepted: `SumTree`,
/// Only the six sum-bearing tree variants are accepted: `SumTree`,
/// `BigSumTree`, `CountSumTree`, `ProvableCountSumTree`,
/// `ProvableSumTree`. Any other element — including items, sum items,
/// references, non-sum trees, and any wrapper (`NonCounted`,
/// `NotSummed`, `NotCountedOrSummed`) — is rejected with
/// `InvalidInput`.
/// `ProvableSumTree`, `ProvableCountProvableSumTree`. Any other
/// element — including items, sum items, references, non-sum trees, and
/// any wrapper (`NonCounted`, `NotSummed`, `NotCountedOrSummed`) — is
/// rejected with `InvalidInput`.
pub fn new_not_summed(inner: Element) -> Result<Self, ElementError> {
match inner {
Element::SumTree(..)
| Element::BigSumTree(..)
| Element::CountSumTree(..)
| Element::ProvableCountSumTree(..)
| Element::ProvableSumTree(..) => Ok(Element::NotSummed(Box::new(inner))),
| Element::ProvableSumTree(..)
| Element::ProvableCountProvableSumTree(..) => Ok(Element::NotSummed(Box::new(inner))),
_ => Err(ElementError::InvalidInput(
"NotSummed inner element must be a sum-tree variant (SumTree, BigSumTree, \
CountSumTree, ProvableCountSumTree, or ProvableSumTree)",
CountSumTree, ProvableCountSumTree, ProvableSumTree, or \
ProvableCountProvableSumTree)",
)),
}
}
Expand Down Expand Up @@ -563,27 +606,33 @@ impl Element {
/// to BOTH its parent's running sum AND its parent's count when
/// inserted.
///
/// Only the five sum-bearing tree variants are accepted: `SumTree`,
/// Only the six sum-bearing tree variants are accepted: `SumTree`,
/// `BigSumTree`, `CountSumTree`, `ProvableCountSumTree`,
/// `ProvableSumTree`. Any other element — including items, sum items,
/// references, non-sum trees, and any wrapper (`NonCounted`,
/// `NotSummed`, `NotCountedOrSummed`) — is rejected with
/// `InvalidInput`.
/// `ProvableSumTree`, `ProvableCountProvableSumTree`. Any other
/// element — including items, sum items, references, non-sum trees, and
/// any wrapper (`NonCounted`, `NotSummed`, `NotCountedOrSummed`) — is
/// rejected with `InvalidInput`.
///
/// Note: at insert time the parent must be `CountSumTree`. Provable
/// count-and-sum parents (`ProvableCountSumTree`) reject the wrapper
/// at the merk-layer insert guard — they cryptographically commit the
/// count into every node hash and must reflect actual contents.
/// count-and-sum parents (`ProvableCountSumTree`,
/// `ProvableCountProvableSumTree`) reject the wrapper at the
/// merk-layer insert guard — they cryptographically commit the
/// count (and, for PCPS, the sum) into every node hash and must
/// reflect actual contents.
pub fn new_not_counted_or_summed(inner: Element) -> Result<Self, ElementError> {
match inner {
Element::SumTree(..)
| Element::BigSumTree(..)
| Element::CountSumTree(..)
| Element::ProvableCountSumTree(..)
| Element::ProvableSumTree(..) => Ok(Element::NotCountedOrSummed(Box::new(inner))),
| Element::ProvableSumTree(..)
| Element::ProvableCountProvableSumTree(..) => {
Ok(Element::NotCountedOrSummed(Box::new(inner)))
}
_ => Err(ElementError::InvalidInput(
"NotCountedOrSummed inner element must be a sum-bearing tree variant (SumTree, \
BigSumTree, CountSumTree, ProvableCountSumTree, or ProvableSumTree)",
BigSumTree, CountSumTree, ProvableCountSumTree, ProvableSumTree, or \
ProvableCountProvableSumTree)",
)),
}
}
Expand Down
42 changes: 40 additions & 2 deletions grovedb-element/src/element/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ impl Element {
| Element::CountSumTree(_, _, sum_value, _)
| Element::ProvableCountSumTree(_, _, sum_value, _)
| Element::ProvableSumTree(_, sum_value, _)
| Element::ProvableCountProvableSumTree(_, _, sum_value, _)
| Element::ReferenceWithSumItem(_, _, sum_value, _) => *sum_value,
_ => 0,
}
Expand All @@ -119,7 +120,8 @@ impl Element {
Element::CountTree(_, count_value, _)
| Element::CountSumTree(_, count_value, ..)
| Element::ProvableCountTree(_, count_value, _)
| Element::ProvableCountSumTree(_, count_value, ..) => *count_value,
| Element::ProvableCountSumTree(_, count_value, ..)
| Element::ProvableCountProvableSumTree(_, count_value, ..) => *count_value,
_ => 1,
}
}
Expand All @@ -146,7 +148,8 @@ impl Element {
| Element::ReferenceWithSumItem(_, _, sum_value, _) => (1, *sum_value),
Element::CountTree(_, count_value, _) => (*count_value, 0),
Element::CountSumTree(_, count_value, sum_value, _)
| Element::ProvableCountSumTree(_, count_value, sum_value, _) => {
| Element::ProvableCountSumTree(_, count_value, sum_value, _)
| Element::ProvableCountProvableSumTree(_, count_value, sum_value, _) => {
(*count_value, *sum_value)
}
Element::ProvableCountTree(_, count_value, _) => (*count_value, 0),
Expand All @@ -168,6 +171,7 @@ impl Element {
| Element::CountSumTree(_, _, sum_value, _)
| Element::ProvableCountSumTree(_, _, sum_value, _)
| Element::ProvableSumTree(_, sum_value, _)
| Element::ProvableCountProvableSumTree(_, _, sum_value, _)
| Element::ReferenceWithSumItem(_, _, sum_value, _) => *sum_value as i128,
Element::BigSumTree(_, sum_value, _) => *sum_value,
_ => 0,
Expand Down Expand Up @@ -282,6 +286,33 @@ impl Element {
}
}

/// Check if the element is a `ProvableCountProvableSumTree`. Looks through
/// wrappers.
pub fn is_provable_count_provable_sum_tree(&self) -> bool {
matches!(self.underlying(), Element::ProvableCountProvableSumTree(..))
}

/// Decoded (count, sum) from a `ProvableCountProvableSumTree`. Looks
/// through wrappers.
pub fn as_provable_count_provable_sum_tree_value(&self) -> Result<(u64, i64), ElementError> {
match self.underlying() {
Element::ProvableCountProvableSumTree(_, count, sum, _) => Ok((*count, *sum)),
_ => Err(ElementError::WrongElementType(
"expected a provable count provable sum tree",
)),
}
}

/// Owned variant of [`as_provable_count_provable_sum_tree_value`].
pub fn into_provable_count_provable_sum_tree_value(self) -> Result<(u64, i64), ElementError> {
match self.into_underlying() {
Element::ProvableCountProvableSumTree(_, count, sum, _) => Ok((count, sum)),
_ => Err(ElementError::WrongElementType(
"expected a provable count provable sum tree",
)),
}
}

/// Check if the element is a tree but not a sum tree. Looks through
/// `NonCounted`.
pub fn is_basic_tree(&self) -> bool {
Expand All @@ -300,6 +331,7 @@ impl Element {
| Element::ProvableCountTree(..)
| Element::ProvableCountSumTree(..)
| Element::ProvableSumTree(..)
| Element::ProvableCountProvableSumTree(..)
| Element::CommitmentTree(..)
| Element::MmrTree(..)
| Element::BulkAppendTree(..)
Expand Down Expand Up @@ -379,6 +411,7 @@ impl Element {
| Element::ProvableCountTree(Some(_), ..)
| Element::ProvableCountSumTree(Some(_), ..)
| Element::ProvableSumTree(Some(_), ..)
| Element::ProvableCountProvableSumTree(Some(_), ..)
| Element::CommitmentTree(..)
| Element::MmrTree(..)
| Element::BulkAppendTree(..)
Expand All @@ -404,6 +437,7 @@ impl Element {
| Element::ProvableCountTree(Some(_), ..)
| Element::ProvableCountSumTree(Some(_), ..)
| Element::ProvableSumTree(Some(_), ..)
| Element::ProvableCountProvableSumTree(Some(_), ..)
)
}

Expand Down Expand Up @@ -478,6 +512,7 @@ impl Element {
| Element::ProvableCountTree(.., flags)
| Element::ProvableCountSumTree(.., flags)
| Element::ProvableSumTree(.., flags)
| Element::ProvableCountProvableSumTree(.., flags)
| Element::ItemWithSumItem(.., flags)
| Element::CommitmentTree(.., flags)
| Element::MmrTree(.., flags)
Expand Down Expand Up @@ -505,6 +540,7 @@ impl Element {
| Element::ProvableCountTree(.., flags)
| Element::ProvableCountSumTree(.., flags)
| Element::ProvableSumTree(.., flags)
| Element::ProvableCountProvableSumTree(.., flags)
| Element::ItemWithSumItem(.., flags)
| Element::CommitmentTree(.., flags)
| Element::MmrTree(.., flags)
Expand Down Expand Up @@ -532,6 +568,7 @@ impl Element {
| Element::ProvableCountTree(.., flags)
| Element::ProvableCountSumTree(.., flags)
| Element::ProvableSumTree(.., flags)
| Element::ProvableCountProvableSumTree(.., flags)
| Element::ItemWithSumItem(.., flags)
| Element::CommitmentTree(.., flags)
| Element::MmrTree(.., flags)
Expand Down Expand Up @@ -559,6 +596,7 @@ impl Element {
| Element::ProvableCountTree(.., flags)
| Element::ProvableCountSumTree(.., flags)
| Element::ProvableSumTree(.., flags)
| Element::ProvableCountProvableSumTree(.., flags)
| Element::ItemWithSumItem(.., flags)
| Element::CommitmentTree(.., flags)
| Element::MmrTree(.., flags)
Expand Down
Loading
Loading