Skip to content

fix(drive): bind and bound proof decoding - #4165

Merged
QuantumExplorer merged 14 commits into
v4.1-devfrom
codex/fix-proof-decode-bounds
Jul 22, 2026
Merged

fix(drive): bind and bound proof decoding#4165
QuantumExplorer merged 14 commits into
v4.1-devfrom
codex/fix-proof-decode-bounds

Conversation

@QuantumExplorer

@QuantumExplorer QuantumExplorer commented Jul 20, 2026

Copy link
Copy Markdown
Member

Summary

  • authenticate the compacted-balance predecessor before deriving the forward proof query, and require both proof halves to commit to the same root
  • apply bounded, exact-consumption decoding to proof-derived vote references, compacted rows, recent per-block balance rows, and data contracts
  • fail closed on the legacy adaptive single-proof payload

This addresses security review findings DS-CAND-008, 009, 037, 104, and 127 through 130.

Compatibility

The compacted-balance proof payload is now a two-proof envelope. Producers and verifiers should be deployed together; this does not change consensus state or protobuf schema.

Validation

  • cargo check -p drive --lib
  • cargo check -p drive --no-default-features --features verify
  • cargo test -p drive --lib bounded_decode
  • cargo test -p drive --lib verify::address_funds (24 passed, including the non-containing-predecessor fallback, mixed-root envelope rejection, and hostile/trailing recent-row decode cases)
  • cargo clippy -p drive --lib --no-deps -- -D warnings
  • cargo fmt --all
  • git diff --check

Summary by CodeRabbit

  • Bug Fixes

    • Improved compacted address-balance proof verification, including queries beginning within ranges and requests beyond the final range.
    • Rejects mismatched, malformed, oversized, or trailing proof data.
    • Strengthened validation of contract, voting, and recent balance proof data to prevent invalid or unsafe decoding.
  • Reliability

    • Android emulator authentication tests now complete PIN entry automatically.
    • Extended macOS test timeouts and made cleanup more resilient.
    • Hardened iOS build cleanup against unsafe empty paths.

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@QuantumExplorer, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 49 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: badbf6f0-8157-47db-bab2-2b4bc51fd85e

📥 Commits

Reviewing files that changed from the base of the PR and between 6cb6576 and f1f63eb.

📒 Files selected for processing (3)
  • .github/workflows/kotlin-sdk-build.yml
  • .github/workflows/tests-rs-workspace.yml
  • packages/swift-sdk/run_tests.sh
📝 Walkthrough

Walkthrough

The PR adds two-part authenticated compacted-balance proofs, bounded decoding for proof-derived data, shared decoder integration across contract and voting verification, and resilience updates for CI, emulator tests, SDK cleanup, and JNI formatting.

Changes

Proof verification hardening

Layer / File(s) Summary
Compacted balance proof envelope
packages/rs-drive/src/drive/saved_block_transactions/..., packages/rs-drive/src/verify/address_funds/...
Compacted balance proof generation and verification now use authenticated predecessor and forward proofs, matching roots, fallback range selection, bounded row decoding, and expanded coverage.
Shared bounded proof decoders
packages/rs-drive/src/verify/bounded_decode.rs, packages/rs-drive/src/verify/address_funds/verify_recent_address_balance_changes/v0/mod.rs, packages/rs-drive/src/verify/mod.rs
Proof data contracts, vote references, and recent balance rows enforce size limits, exact byte consumption, and corrupted-input errors.
Verifier integration
packages/rs-drive/src/verify/contract/..., packages/rs-drive/src/verify/voting/...
Contract and voting verification paths use the shared bounded decoding helpers.

Build and SDK tooling

Layer / File(s) Summary
CI and SDK maintenance
.github/workflows/*, packages/swift-sdk/build_ios.sh, packages/rs-unified-sdk-jni/src/tx_decode.rs
The Android emulator submits its PIN, macOS CI allows longer execution and retries cleanup, iOS cleanup paths guard required variables, and JNI changes reformat unchanged calls and test setup.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Prover
  participant GroveDB
  participant Verifier
  Prover->>GroveDB: Generate predecessor proof
  Prover->>GroveDB: Generate forward proof
  Prover->>Verifier: Submit encoded proof envelope
  Verifier->>Verifier: Verify both proofs and compare roots
  Verifier->>Verifier: Decode authenticated balance rows
Loading

Suggested labels: Client Only

Suggested reviewers: shumkov, llbartekll, zocolini, thepastaclaw

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the two main themes: binding compacted proof derivation and bounding proof decoding.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/fix-proof-decode-bounds

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 this to the v4.1.0 milestone Jul 20, 2026
@QuantumExplorer
QuantumExplorer marked this pull request as ready for review July 21, 2026 02:04
@thepastaclaw

thepastaclaw commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

🕓 Ready for review — 32 ahead in queue (commit f1f63eb)
Queue position: 33/72 · 2 reviews active
ETA: start ~03:23 UTC · complete ~03:52 UTC (median 28m across 30 recent reviews; 2 slots)
Queued 18h 34m ago · Last checked: 2026-07-22 19:40 UTC

@codecov

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.06818% with 42 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.46%. Comparing base (ce8aecb) to head (f1f63eb).
⚠️ Report is 9 commits behind head on v4.1-dev.

Files with missing lines Patch % Lines
...verify_compacted_address_balance_changes/v0/mod.rs 87.11% 25 Missing ⚠️
packages/rs-drive/src/verify/bounded_decode.rs 92.30% 7 Missing ⚠️
...actions/fetch_compacted_address_balances/v0/mod.rs 71.42% 6 Missing ⚠️
...ds/verify_recent_address_balance_changes/v0/mod.rs 92.50% 3 Missing ⚠️
...ds/verify_compacted_address_balance_changes/mod.rs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           v4.1-dev    #4165      +/-   ##
============================================
- Coverage     87.63%   87.46%   -0.17%     
============================================
  Files          2624     2652      +28     
  Lines        331678   334936    +3258     
============================================
+ Hits         290659   292968    +2309     
- Misses        41019    41968     +949     
Components Coverage Δ
dpp 88.44% <ø> (+<0.01%) ⬆️
drive 86.16% <88.06%> (+0.02%) ⬆️
drive-abci 89.58% <ø> (+0.01%) ⬆️
sdk ∅ <ø> (∅)
dapi-client ∅ <ø> (∅)
platform-version ∅ <ø> (∅)
platform-value 92.90% <ø> (ø)
platform-wallet ∅ <ø> (∅)
drive-proof-verifier 49.66% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Preliminary review — Codex only

The proof-envelope and vote-reference changes are sound, but the contract-proof paths now use a decoder with a 15,000-byte resource limit even though the protocol accepts serialized contracts up to 65,000 bytes. This creates a blocking availability regression for valid contracts and also leaves the proof decoder accepting trailing bytes instead of enforcing exact consumption.

Validated blockers were found in the Codex precheck. Sonnet is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (failed), gpt-5.6-sol — general (failed), gpt-5.6-sol — general (failed), gpt-5.6-sol — general (failed), gpt-5.6-sol — general (completed), gpt-5.6-sol — security-auditor (failed), gpt-5.6-sol — security-auditor (failed), gpt-5.6-sol — security-auditor (failed), gpt-5.6-sol — security-auditor (failed), gpt-5.6-sol — security-auditor (completed), gpt-5.6-sol — rust-quality (failed), gpt-5.6-sol — rust-quality (failed), gpt-5.6-sol — rust-quality (failed), gpt-5.6-sol — rust-quality (failed), gpt-5.6-sol — rust-quality (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 1 blocking

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-drive/src/verify/contract/verify_contract/v0/mod.rs`:
- [BLOCKING] packages/rs-drive/src/verify/contract/verify_contract/v0/mod.rs:140-143: Use a protocol-sized, exact-consumption contract decoder
  The newly selected `DataContract::versioned_limit_deserialize` helper is incompatible with contracts accepted into authenticated state. It applies `CONTRACT_DESERIALIZATION_LIMIT = 15000`, while all current platform versions set `platform_version.dpp.contract_versions.max_serialized_size` to 65,000 and Drive permits serialized contracts up to that value. Bincode's limit also accounts for nested container allocation claims, so the decoder can reject valid contracts even before their serialized length reaches 15,000 bytes. Such contracts remain valid and stored by Platform but become unavailable through `verify_contract`, `verify_contract_history`, and `verify_contract_return_serialization`, causing a targeted denial of service for proof-verifying clients. The helper also discards the consumed-byte count returned by `borrow_decode_from_slice`, so it accepts a complete contract followed by trailing bytes. Replace these three calls with a proof-specific bounded decoder whose budget is compatible with the protocol-version-specific contract limit and which rejects input unless the decoder consumes the entire byte slice.

Comment thread packages/rs-drive/src/verify/contract/verify_contract/v0/mod.rs Outdated
QuantumExplorer and others added 8 commits July 21, 2026 20:44
…ecode-bounds

# Conflicts:
#	packages/swift-sdk/build_ios.sh
…failure branches

Review follow-ups on the proof-decoding hardening:

- verify_recent_address_balance_changes (both the inclusive and _after
  variants) still decoded proof-derived per-block rows with an unlimited
  bincode budget — the same hostile-length-prefix exposure this branch closes
  in the compacted verifier. Route both sites through a bounded,
  exact-consumption row decoder with the same 1 MiB semantic budget, and pin
  it with a hostile-prefix + trailing-bytes test.
- Cover the two untested verifier branches of the compacted two-proof
  envelope: a predecessor that exists but does not contain the requested
  height must fall back to the request-derived start key, and envelope halves
  committing to different roots must be rejected (exercised by splicing
  proofs generated across a state mutation that leaves the derived start key
  unchanged, so only the root binding can catch the mix).
- The 16 MiB envelope budget's comment claimed to match the DAPI transport
  limit; no transport tier uses that number (tonic clients default to 4 MiB,
  the server encodes at most 32 MiB). Reword it as the standalone bound it is.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/v0/mod.rs (1)

160-181: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider sharing the bounded row decoder instead of inlining it.

This inline size-guard + with_limit decode + trailing-byte check duplicates the pattern already extracted as decode_address_balance_row in verify_recent_address_balance_changes/v0/mod.rs (and mirrors bounded_decode.rs). Since these are security-critical decode limits, keeping duplicate copies risks divergence if one budget changes. A small shared generic helper over the row map type would keep the limits in one place.

🤖 Prompt for 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.

In
`@packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/v0/mod.rs`
around lines 160 - 181, The compacted address balance verification path should
reuse a shared bounded row decoder instead of duplicating the size guard,
limited bincode configuration, and trailing-byte validation. Generalize or reuse
decode_address_balance_row from the recent address balance verification module
so it supports the BTreeMap<PlatformAddress, BlockAwareCreditOperation> row
type, then replace the inline decoding block while preserving its existing
corrupted-proof error behavior.
🤖 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 @.github/workflows/kotlin-sdk-build.yml:
- Around line 175-176: Update the keyguard dismissal sequence around `adb shell
input text` and `KEYCODE_ENTER` so the workflow waits until the bouncer is ready
before injecting the PIN. Move the existing delay before PIN entry or add an
equivalent readiness check, while preserving the subsequent unlock steps.

---

Nitpick comments:
In
`@packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/v0/mod.rs`:
- Around line 160-181: The compacted address balance verification path should
reuse a shared bounded row decoder instead of duplicating the size guard,
limited bincode configuration, and trailing-byte validation. Generalize or reuse
decode_address_balance_row from the recent address balance verification module
so it supports the BTreeMap<PlatformAddress, BlockAwareCreditOperation> row
type, then replace the inline decoding block while preserving its existing
corrupted-proof error behavior.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 378dbf13-55e2-49fe-a4c1-26466f84fdb9

📥 Commits

Reviewing files that changed from the base of the PR and between 2b3e3fc and 6cb6576.

📒 Files selected for processing (15)
  • .github/workflows/kotlin-sdk-build.yml
  • .github/workflows/tests-rs-workspace.yml
  • packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_address_balances/v0/mod.rs
  • packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/mod.rs
  • packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/v0/mod.rs
  • packages/rs-drive/src/verify/address_funds/verify_recent_address_balance_changes/v0/mod.rs
  • packages/rs-drive/src/verify/bounded_decode.rs
  • packages/rs-drive/src/verify/contract/verify_contract/v0/mod.rs
  • packages/rs-drive/src/verify/contract/verify_contract_history/v0/mod.rs
  • packages/rs-drive/src/verify/contract/verify_contract_return_serialization/v0/mod.rs
  • packages/rs-drive/src/verify/mod.rs
  • packages/rs-drive/src/verify/voting/verify_identity_votes_given_proof/v0/mod.rs
  • packages/rs-drive/src/verify/voting/verify_masternode_vote/v0/mod.rs
  • packages/rs-unified-sdk-jni/src/tx_decode.rs
  • packages/swift-sdk/build_ios.sh

Comment thread .github/workflows/kotlin-sdk-build.yml Outdated
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