Skip to content

fix: version-gate add_element_on_transaction (v0=Op::Put, v1=layered) - #759

Merged
shumkov merged 2 commits into
developfrom
claude/nostalgic-williams-23fb8d
Jun 4, 2026
Merged

fix: version-gate add_element_on_transaction (v0=Op::Put, v1=layered)#759
shumkov merged 2 commits into
developfrom
claude/nostalgic-williams-23fb8d

Conversation

@QuantumExplorer

@QuantumExplorer QuantumExplorer commented Jun 4, 2026

Copy link
Copy Markdown
Member

What

Splits the non-batch insert helper GroveDb::add_element_on_transaction into a versioned dispatch (Platform-style: dispatcher + frozen v0/v1 snapshots, each in its own file under grovedb/src/operations/insert/add_element_on_transaction/):

GroveVersion add_element_on_transaction slot behaviour for CountSumTree / ProvableCountTree / ProvableCountSumTree
GROVE_V1, GROVE_V2 0v0 plain value (Op::Put) — matches grovedb v4.1.0 / the live protocol-v11 chain
GROVE_V3 1v1 layered subtree (Op::PutLayeredReference) — current behaviour, consistent with the batch path

Only GROVE_V3's slot is bumped 0 → 1; v1/v2 stay 0.

Why — protocol-v11 consensus

add_element_on_transaction decides whether an element is written as a layered subtree (Op::PutLayeredReference) or a plain value (Op::Put). The two ops compute a different parent-node value_hash:

Op::Put                : value_hash = value_hash(serialized)
Op::PutLayeredReference: value_hash = combine_hash(value_hash(serialized), child_root_hash)
                                    = combine_hash(value_hash(serialized), NULL_HASH)   // empty tree

In grovedb v4.1.0, CountSumTree / ProvableCountTree / ProvableCountSumTree fell through _ => element.insert()Op::Put. #752 (subtree dump/restore primitives) broadened the tree arm to include them → Op::PutLayeredReference, changing the parent node hash and therefore the grovedb root.

These types are created on the protocol-v11 activation (transition_to_version_11 inserts an empty_provable_count_sum_tree and an empty_count_sum_tree via this non-batch path — testnet block 245,344), so the broadened dispatch makes a v11 node compute a different app-hash than the v4.1.0-era binaries that produced the canonical chain — a consensus divergence on replay.

Why versioned instead of an unconditional revert (cf. #757)

#757 reverts the three types to Op::Put for all versions. This PR instead preserves both behaviours and gates them, so:

  • GROVE_V1 / GROVE_V2 replay the protocol-v11 chain correctly (Op::Put), and
  • GROVE_V3+ keep the layered behaviour, which makes the non-batch path agree with the batch path on both root hash and fee (the batch path has always written these three types as layered, via insert_subtree_into_batch_operations + LayeredValueDefinedCost). That removes the long-standing batch/non-batch divergence going forward instead of freezing it.

v0/v1 are full frozen snapshots; they differ only in which match arm those three element types fall into. v0 is intentionally "current body with those three arms moved to Op::Put" rather than a literal v4.1.0 copy, so it still handles the newer element types (ProvableSumTree, CommitmentTree, the append-trees, NonCounted wrappers) that v4.1.0 predates, while reproducing the v4.1.0 consensus root exactly for every type that existed then.

Test

add_element_on_transaction_version_gate_provable_count_sum_tree_root replays the transition_to_version_11 shape (empty_sum_tree control at [56], then empty_provable_count_sum_tree at [56,'c']) under both versions and pins both roots:

Verification

  • cargo build -p grovedb — clean, no warnings
  • cargo clippy -p grovedb --lib — clean
  • cargo test -p grovedb --lib1853 passed, 0 failed, 1 ignored

Reviewer notes

  • latest() = GROVE_V3 = v1 = layered, which is today's behaviour, so all latest()-based tests are unaffected. The behaviour change is limited to GROVE_V1 / GROVE_V2, which now correctly use Op::Put for these three types (the regressed layered behaviour was never on the canonical chain for those versions).
  • The v12-only ProvableSumTree / ProvableCountProvableSumTree keep the layered behaviour in both v0 and v1 — they were never created via this path on the v11 chain.
  • Branch is rebased on deps(commitment-tree): migrate orchard to 0.14.0 (circuit soundness fix) #758 (the orchard 0.14.0 pin) so it builds.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Improvements

    • Enhanced versioning infrastructure for database insert operations with improved protocol-specific handling to ensure consistent behavior across all supported grove database versions.
  • Tests

    • Added comprehensive regression tests validating version-specific protocol behaviors for insert operations, including consensus root hash verification to prevent regressions across grove versions.

…layered)

PR #752 broadened the non-batch insert tree arm so CountSumTree /
ProvableCountTree / ProvableCountSumTree are written as layered subtrees
(Op::PutLayeredReference). grovedb <= v4.1.0 wrote them as plain values
(Op::Put), and that is the behaviour frozen into the live protocol-v11
activation chain (testnet block 245,344, transition_to_version_11). The
layered op computes a different parent value_hash —
combine_hash(value_hash(serialized), NULL_HASH) instead of
value_hash(serialized) — and therefore a different grovedb root, a consensus
divergence on replay.

Rather than revert unconditionally (cf. #757), split add_element_on_transaction
into a versioned dispatch, mirroring the proof v0/v1 pattern:

- v0: grovedb v4.1.0 behaviour — those three types take the Op::Put arm.
  Selected by GROVE_V1 / GROVE_V2, preserving the protocol-v11 root.
- v1: current behaviour — those three types are layered, consistent with the
  batch insert path (both root hash and fee). Selected by GROVE_V3.

v0/v1 live in their own files as frozen snapshots; they differ only in which
match arm those three element types fall into. GROVE_V3's
add_element_on_transaction version slot is bumped 0 -> 1; v1/v2 stay 0.

Adds a consensus-guard test that replays the transition_to_version_11 shape and
pins both roots: the v0 root is byte-identical to PR #757's protocol-v11 golden,
and the v1 (layered) root differs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR refactors the non-batch add_element_on_transaction operation into a versioned dispatch layer that routes count/provable-count tree insertion between two consensus-critical paths: v0 uses plain-value insertion (Op::Put) preserving protocol-v11, while v1 uses layered subtrees (Op::PutLayeredReference) matching batch semantics. The dispatcher is activated in GROVE_V3 with full coverage tests pinning root hash differences.

Changes

Versioned non-batch insert implementation

Layer / File(s) Summary
Enable add_element_on_transaction in GROVE_V3
grovedb-version/src/version/v3.rs
Enables the add_element_on_transaction operation in GROVE_V3 and documents the version-gated v1 behavior for count/provable-count trees and consensus compatibility.
Version dispatcher implementation
grovedb/src/operations/insert/add_element_on_transaction/mod.rs
Introduces the dispatch layer that routes to v0 or v1 based on grove version configuration, with comprehensive module documentation explaining the consensus-critical differences between versions.
V0 implementation: plain-value insertion
grovedb/src/operations/insert/add_element_on_transaction/v0.rs
Implements v0 behavior routing count/provable-count trees through element.insert (Op::Put) to preserve protocol-v11 consensus, with override validation and element-type dispatch for references, trees, and items.
V1 implementation: layered subtree insertion
grovedb/src/operations/insert/add_element_on_transaction/v1.rs
Implements v1 behavior inserting count/provable-count trees as empty subtrees (Op::PutLayeredReference) to match batch semantics, with reference resolution, tree initialization, and override validation.
Module integration and version-gated test suite
grovedb/src/operations/insert/mod.rs
Delegates non-batch insert logic to the new submodule and adds comprehensive test coverage verifying version-gated root hash differences, dispatcher match-arm coverage, and version error handling.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 A tree's split path, two roads to root—
v0 keeps the gold, v1 trees take fruit,
versioned routes now clearly sing,
layered subtrees for GROVE_V3's ring! 🌳✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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.
Title check ✅ Passed The title clearly and accurately describes the main change: version-gating the add_element_on_transaction operation with v0 using Op::Put and v1 using layered subtrees.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/nostalgic-williams-23fb8d

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

codecov Bot commented Jun 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.14066% with 19 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.47%. Comparing base (caa0ec7) to head (7905f76).

Files with missing lines Patch % Lines
...operations/insert/add_element_on_transaction/v0.rs 89.90% 11 Missing ⚠️
...operations/insert/add_element_on_transaction/v1.rs 92.85% 8 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop     #759      +/-   ##
===========================================
+ Coverage    91.44%   91.47%   +0.02%     
===========================================
  Files          237      240       +3     
  Lines        67298    67570     +272     
===========================================
+ Hits         61540    61807     +267     
- Misses        5758     5763       +5     
Components Coverage Δ
grovedb-core 89.06% <95.14%> (+0.09%) ⬆️
merk 92.26% <ø> (ø)
storage 86.20% <ø> (ø)
commitment-tree 96.03% <ø> (ø)
mmr 96.79% <ø> (ø)
bulk-append-tree 89.82% <ø> (ø)
element 97.38% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@QuantumExplorer QuantumExplorer left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Self Reviewed

Adds exhaustive non-batch-insert coverage for both frozen snapshots
(v0.rs / v1.rs): the layered-tree arm (every tree type), the commitment-tree
arm, the append-tree arm (MMR / bulk-append / dense), the item arm, the
reference arm, both override guards, and the empty-tree-only (value.is_some)
guard — driven under GROVE_V1 (v0 / Op::Put) and GROVE_V3 (v1 / layered).
Also asserts the dispatcher rejects an unknown version slot.

Closes the codecov/patch gap on the new add_element_on_transaction module.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@shumkov shumkov changed the title fix(insert): version-gate add_element_on_transaction (v0=Op::Put, v1=layered) — protocol-v11 consensus fix: version-gate add_element_on_transaction (v0=Op::Put, v1=layered) — protocol-v11 consensus Jun 4, 2026
@shumkov shumkov changed the title fix: version-gate add_element_on_transaction (v0=Op::Put, v1=layered) — protocol-v11 consensus fix: version-gate add_element_on_transaction (v0=Op::Put, v1=layered) Jun 4, 2026
@shumkov
shumkov merged commit 41786da into develop Jun 4, 2026
10 checks passed
@shumkov
shumkov deleted the claude/nostalgic-williams-23fb8d branch June 4, 2026 07:33
QuantumExplorer added a commit that referenced this pull request Jun 4, 2026
Resolves a conflict in grovedb/src/operations/insert/mod.rs where develop
PR #759 moved `add_element_on_transaction` out of the inline function
into a versioned dispatch submodule
(insert/add_element_on_transaction/{mod,v0,v1}.rs), version-gated to
preserve the grovedb v4.1.0 / protocol-v11 consensus root for the three
grandfathered tree types.

Resolution: accept develop's `insert/mod.rs` skeleton (the function is
gone from this file - it lives in the submodule), and port my
ProvableCountIndexedTree / ProvableSumIndexedTree /
ProvableCountProvableSumIndexedTree match arms identically into both
v0.rs and v1.rs. The v0/v1 divergence applies only to the three
grandfathered types (CountSumTree / ProvableCountTree /
ProvableCountSumTree); the new indexed-tree variants are v12-only, were
never live on the v11 chain, and have identical layered-subtree behavior
in both versions.

4060 workspace lib tests pass, clippy clean.

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.

2 participants