Skip to content

test: cover low-coverage modules in dpp and drive#3506

Merged
QuantumExplorer merged 2 commits into
v3.1-devfrom
test/coverage-lowcov-shielded-factories-verify
Apr 21, 2026
Merged

test: cover low-coverage modules in dpp and drive#3506
QuantumExplorer merged 2 commits into
v3.1-devfrom
test/coverage-lowcov-shielded-factories-verify

Conversation

@QuantumExplorer
Copy link
Copy Markdown
Member

@QuantumExplorer QuantumExplorer commented Apr 21, 2026

Issue being fixed or feature implemented

Fourth PR in the push toward 90% global coverage (now 85.44% after #3503, #3504, #3505). PR #3505 only added +0.14% despite 168 tests, because many accessor tests overlap with integration test coverage.

Lesson applied: this round sorts targets by lowest coverage % (more untested error branches per line) rather than by missed-line count, and focuses the tests on error paths, overflow/underflow, corrupted-state arms, and edge cases.

What was done?

161 new unit tests across 8 modules and 30 files.

Target Prev cov Missed Tests added
rs-dpp/document/document_factory 55% 210 22
rs-drive/drive/shielded 64% 555 17
rs-drive/drive/prefunded_specialized_balances 64% 273 28
rs-dpp/state_transition/mod.rs 66% 312 34 (on top of PR #3504's 25)
rs-dpp/shielded/builder 72% 197 24
rs-dpp/document/extended_document 72% 352 13
rs-dpp/document/v0 77% 525 10
rs-drive/verify/state_transition 76% 472 13

Highlighted new coverage

  • document_factory: every DocumentError::* variant in create_state_transition (NoDocumentsSuppliedError, MismatchOwnerIdsError, RevisionAbsentError on Create/Replace/Delete, InvalidInitialRevisionError), factory construction with version 0/u32::MAX, failing entropy generators, create_extended_from_document_buffer roundtrip + malformed bytes.
  • drive/shielded: paths.rs pool_type 0/1/2 + unknown → InvalidInput; update_total_balance_v0 i64::MAX boundary + u64::MAX CorruptedDriveState; prune_anchors_v0 cutoff-exclusive boundary; record_anchor_if_changed_v0 zero-anchor short-circuit + corrupted-element error; nullifiers/types.rs bincode-garbage and wrong-length parse_key errors.
  • prefunded_specialized_balances: checked_add overflow → CriticalCorruptedState, MAX_CREDITS guard → CriticalBalanceOverflow, missing-id with carried (avail, req), CorruptedElementType on negative SumItem, v1 i64::MAX sentinel, error_if_does_not_exist true/false branches in empty_prefunded_specialized_balance_operations_v0.
  • state_transition/mod.rs: all previously-untested StateTransition variants (DataContractCreate/Update, IdentityCreate/TopUp/Update, Unshield, ShieldedTransfer/Withdrawal) across name(), is_identity_signed(), signature(), owner_id(), setters (incl. shielded no-op arms), required_asset_lock_balance_for_processing_start CorruptedCodeExecution for 8 non-asset-lock variants, and deserialize_from_bytes_in_version StateTransitionIsNotActiveError (ShieldedTransfer against protocol < 12).
  • verify/state_transition: empty-proof error arms for DataContractUpdate / MasternodeVote / ShieldedWithdrawal / ShieldedTransfer / Unshield / IdentityCreditTransferToAddresses, Batch::V1 Token(Burn) with missing contract provider → ProofError::UnknownContract, TryTransitionIntoPathQuery keeps_history branches (Burn/Freeze/Unfreeze/SetPriceForDirectPurchase).
  • shielded/builder: fee boundary matrix (below min, above 1000x, exact min, exact 1000x, None default), checked_add overflow via u64::MAX transfer, withdrawal_amount > i64::MAX branch in withdrawal/unshield, AnchorMismatch error, From<&OrchardAddress> delegation, deterministic empty-spends error.
  • document/v0: Display impl optional-field branches (every created_at/updated_at/transferred_at/block-height/core-block-height/creator_id/empty-properties conditional), DateTime::from_timestamp_millis None fallback for u64::MAX, DocumentV0Setters::bump_revision None no-op + Revision::MAX saturation guard (overflow regression guard).
  • document/extended_document: from_untrusted/trusted_platform_value missing-$type and unknown-type errors, serialize_specific_version_to_bytes UnknownVersionMismatch, from_bytes empty / unknown-version / truncated paths.

Production bug flagged

packages/rs-drive/src/drive/prefunded_specialized_balances/deduct_from_prefunded_specialized_balance/mod.rs top-level dispatcher only has a 0 => branch, but platform drive versions v3, v4, v5 all set deduct_from_prefunded_specialized_balance: 1. Grepping confirms there are no callers — the production state-transition code calls *_operations instead (which properly supports v0+v1). This is a dead-path bug; flagged for a follow-up PR to either add the v1 branch or remove the dispatcher entirely. Out of scope for this PR.

How Has This Been Tested?

  • cargo test -p dpp --lib 'document::v0' — 88 pass
  • cargo test -p dpp --lib 'document::extended_document' — 46 pass
  • cargo test -p dpp --lib 'document::document_factory' — 23 pass
  • cargo test -p dpp --all-features --lib 'shielded::builder' — 34 pass
  • cargo test -p dpp --lib 'state_transition::tests' — 63 pass
  • cargo test -p drive --lib 'shielded' — 136 pass
  • cargo test -p drive --lib 'prefunded_specialized_balances' — 28 pass
  • cargo test -p drive --lib 'verify::state_transition' — 35 pass
  • cargo check --tests -p dpp -p drive — clean
  • cargo fmt -p dpp -p drive — clean

Breaking Changes

None. Tests only.

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

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

Summary by CodeRabbit

Release Notes

  • Tests
    • Expanded test coverage across document factories, state transitions, and shielded operations to improve code reliability and error handling validation.
    • Added comprehensive test suites for specialized balance management, note operations, and proof verification across multiple feature implementations.
    • Strengthened validation of boundary conditions and error paths in core components.

Add 161 new unit tests across 8 modules identified as highest
leverage — sorted by lowest coverage %, not just highest missed
line count, since PR #3505 showed that accessor tests on high-cov
files add near-zero Codecov gain. This round targets error paths,
overflow/underflow branches, corrupted-state arms, and edge cases
that integration tests do not exercise.

Coverage targets (prev cov → covered here):

- rs-dpp/document/document_factory (54.64% → covered): 22 tests on
  construction errors (u32::MAX / 0 version), create_document
  errors (InvalidDocumentTypeError + entropy-generator failure),
  create_extended_document, create_extended_from_document_buffer
  roundtrip + malformed bytes, and all create_state_transition
  error branches (empty outer, outer-with-empty-inner, mismatched
  owners, InvalidInitialRevisionError, RevisionAbsentError on
  Create/Replace/Delete, and mixed Create+Replace merging).

- rs-drive/drive/shielded (64% → covered): 17 tests covering
  paths.rs pool_type branches + unknown-pool error, update/read
  total balance with i64::MAX boundary + CorruptedDriveState,
  has_anchor / has_nullifier / notes_count / insert_note /
  insert_nullifiers happy + empty paths, prune_anchors cutoff
  boundary, record_anchor_if_changed zero-anchor short-circuit +
  corrupted-element error, nullifiers/types serialization errors
  (bincode garbage, wrong-length parse_key).

- rs-drive/drive/prefunded_specialized_balances (64% → covered):
  28 tests including v1 StatefulDirectQuery vs StatelessDirectQuery
  branches, checked_add overflow (CriticalCorruptedState),
  MAX_CREDITS guard (CriticalBalanceOverflow), missing-id errors
  with carried (avail, req), CorruptedElementType on negative
  SumItem, i64::MAX sentinel in v1, estimation override, and
  empty_prefunded's three branches (missing-without-error-flag,
  missing-with-error-flag, existing-returns-prev-amount).

- rs-dpp/state_transition/mod.rs (66% → covered): 34 NEW tests on
  top of the 25 from PR #3504, covering all previously-untested
  variants (DataContractCreate/Update, IdentityCreate/TopUp/Update,
  Unshield, ShieldedTransfer/Withdrawal) across name(),
  state_transition_type(), is_identity_signed(), signature /
  owner_id / user_fee_increase accessors + setters (incl. shielded
  no-op arms), active_version_range() contract V1 + shielded
  ranges, inputs() None wildcard, optional_asset_lock_proof() _=>
  None, required_asset_lock_balance_for_processing_start's
  CorruptedCodeExecution for 8 non-asset-lock variants,
  security_level_requirement / purpose_requirement None-arms, and
  deserialize_from_bytes_in_version's StateTransitionIsNotActive
  error (ShieldedTransfer against protocol < 12).

- rs-drive/verify/state_transition (76% → covered): 13 tests on
  verify_state_transition_was_executed_with_proof_v0 for
  DataContractUpdate empty-proof, MasternodeVote UnknownContract,
  ShieldedWithdrawal/Transfer/Unshield empty-proof, Batch::V1
  Token(Burn) with missing contract provider, plus
  TryTransitionIntoPathQuery keeps_history branches
  (Burn/Freeze/Unfreeze/SetPriceForDirectPurchase) and the
  expected_token_configuration invalid-position error.

- rs-dpp/shielded/builder (72% → covered): 24 tests on
  build_output_only_bundle, serialize_authorized_bundle
  field preservation, From<&OrchardAddress> delegation,
  build_spend_bundle AnchorMismatch, deterministic empty-spends,
  shielded transfer overflow (checked_add u64::MAX), fee boundary
  matrix (below min, above 1000x, exact min, exact 1000x, None
  default), and withdrawal_amount > i64::MAX branch in
  shielded_withdrawal / unshield.

- rs-dpp/document/v0 (77% → covered): 10 tests covering Display's
  optional-field conditionals (created_at, updated_at,
  transferred_at, block/core-block heights, creator_id, empty
  properties), DateTime::from_timestamp_millis None fallback for
  u64::MAX, DocumentV0Setters::bump_revision (None no-op +
  Revision::MAX saturation guard), Default impl, PartialEq
  discrimination on creator_id.

- rs-dpp/document/extended_document (72% → covered): 13 tests on
  from_untrusted/trusted_platform_value missing-$type + unknown-
  type errors, set_untrusted non-identifier/non-binary branch,
  hash distinctness, serialize_specific_version_to_bytes v0
  success + UnknownVersionMismatch, from_bytes empty/unknown-
  version/truncated paths, to_json and to_json_with_identifiers_
  using_bytes inclusion of $type + $dataContract, and to_map_value
  $tokenPaymentInfo absence.

All 161 tests pass. A latent production bug in
deduct_from_prefunded_specialized_balance/mod.rs (dispatcher only
knows v0 but platform v3+ sets 1) was flagged via a follow-up task
— it's currently dead code and out of scope for this PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added this to the v3.1.0 milestone Apr 21, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 21, 2026

Warning

Rate limit exceeded

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

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 44 minutes and 0 seconds.

⌛ 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: 0113f456-8e0d-4589-b386-e14d47ff6735

📥 Commits

Reviewing files that changed from the base of the PR and between 9db5136 and fdf03e9.

📒 Files selected for processing (8)
  • packages/rs-dpp/src/document/v0/mod.rs
  • packages/rs-dpp/src/shielded/builder/shielded_transfer.rs
  • packages/rs-dpp/src/shielded/builder/shielded_withdrawal.rs
  • packages/rs-dpp/src/shielded/builder/unshield.rs
  • packages/rs-drive/src/drive/prefunded_specialized_balances/add_prefunded_specialized_balance_operations/v0/mod.rs
  • packages/rs-drive/src/drive/prefunded_specialized_balances/empty_prefunded_specialized_balance_operations/v0/mod.rs
  • packages/rs-drive/src/verify/state_transition/state_transition_execution_path_queries/token_transition.rs
  • packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs
📝 Walkthrough

Walkthrough

This PR adds comprehensive test coverage across rs-dpp and rs-drive modules without modifying production code. New tests exercise document factory construction, state transitions, shielded operations, prefunded specialized balance management, and verification logic across 30+ files with 4,100+ lines of test-only additions.

Changes

Cohort / File(s) Summary
Document and Extended Document Tests
packages/rs-dpp/src/document/document_factory/mod.rs, packages/rs-dpp/src/document/extended_document/v0/mod.rs, packages/rs-dpp/src/document/v0/mod.rs
Added test suites for document creation across success/error paths, including DocumentFactory construction with entropy generators, document type validation, timestamp handling, revision bumping, equality, and extended document serialization/deserialization with type and contract validation.
Shielded Builder Operations
packages/rs-dpp/src/shielded/builder/mod.rs, ...shield.rs, ...shield_from_asset_lock.rs, ...shielded_transfer.rs, ...shielded_withdrawal.rs, ...unshield.rs
Extended shielded builder test coverage with bundle construction, serialization, value balance conversion, fee boundary validation (1000x min-fee caps), overflow handling, empty input cases, and anchor mismatch error detection across shield, shielded transfer, shielded withdrawal, and unshield operations.
State Transition Tests
packages/rs-dpp/src/state_transition/mod.rs
Added comprehensive test helpers and cases for all StateTransition enum variants (DataContractCreate/Update, Batch, Identity operations, Unshield, ShieldedTransfer, ShieldedWithdrawal), covering naming, type identification, version ranges, signature/fee handling, asset lock proofs, identifier uniqueness, serialization round-trips, and feature-gated error paths.
Prefunded Specialized Balance Operations
packages/rs-drive/src/drive/prefunded_specialized_balances/.../v0/mod.rs, .../v1/mod.rs
Added tests for add/deduct/empty/fetch/prove operations verifying balance accumulation, overflow detection, missing balance handling, estimation path behavior, and boundary conditions across v0/v1 implementations.
Shielded Pool Drive Operations
packages/rs-drive/src/drive/shielded/.../v0/mod.rs, ...types.rs, ...paths.rs
Added tests for anchor presence checking, nullifier insertion/verification, note insertion and counting, serialization of compacted nullifiers and expiration ranges, path validation across pool types, anchor pruning with cutoff semantics, total balance reads/updates, and anchor recording with corruption detection.
State Transition Verification Tests
packages/rs-drive/src/verify/state_transition/.../token_transition.rs, .../verify_state_transition_was_executed_with_proof/v0/mod.rs
Extended coverage for token transition path queries with history-enabled contracts, invalid token positions, and verification failures for DataContractUpdate, MasternodeVote, ShieldedWithdrawal/Transfer, Unshield, IdentityCreditTransferToAddresses, and Batch transitions with missing proofs or invalid contracts.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

Possibly related PRs

  • dashpay/platform#3359: Adds extensive state-transition/unit tests in rs-dpp including batched/shielded transitions and token action_id/version updates, overlapping in the state_transition and token transition test areas.
  • dashpay/platform#3503: Extends test coverage to the rs-drive tokens subtree with token info fetchers, queries, mint operations, and system supply functions, related through token transition verification patterns.

Suggested reviewers

  • shumkov

Poem

🐰 A rabbit hops through tests so bright,
Document factories, states taking flight!
Shielded paths and balances blend,
With anchors and nullifiers to defend—
Coverage blooming, the tests now ascend! ✨

🚥 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 PR title 'test: cover low-coverage modules in dpp and drive' accurately describes the main objective: adding comprehensive test coverage to low-coverage modules across the dpp and drive packages. The title is concise, specific, and clearly summarizes the primary change.
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 test/coverage-lowcov-shielded-factories-verify

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.

@thepastaclaw
Copy link
Copy Markdown
Collaborator

thepastaclaw commented Apr 21, 2026

Review Gate

Commit: fdf03e92

  • Debounce: 7m ago (need 30m)

  • CI checks: checks still running (2 pending)

  • CodeRabbit review: comment found

  • Off-peak hours: off-peak (12:39 PM PT Tuesday)

  • Run review now (check to override)

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: 8

🧹 Nitpick comments (6)
packages/rs-drive/src/drive/shielded/nullifiers/types.rs (1)

168-260: Nit: move #[cfg(test)] mod tests to the bottom of the file.

The test module is inserted between CompactedNullifierChange (ends line 166) and NullifierChangePerBlock (line 262), splitting the production types. Conventionally mod tests sits at the end of the file so all public/production items stay contiguous.

♻️ Suggested reordering

Move the NullifierChangePerBlock declaration (lines 262–268) above the #[cfg(test)] mod tests { … } block so the test module is the final item in the file.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/rs-drive/src/drive/shielded/nullifiers/types.rs` around lines 168 -
260, The test module is splitting production types—move the entire #[cfg(test)]
mod tests block to the end of the file so production items remain contiguous;
specifically, relocate the declaration of NullifierChangePerBlock so it appears
before the tests (ensure CompactedNullifierChange and NullifierChangePerBlock
are adjacent), then place #[cfg(test)] mod tests { ... } as the final item in
the file.
packages/rs-drive/src/drive/shielded/prune_anchors/v0/mod.rs (1)

146-179: Rename test to reflect exclusive-cutoff semantics.

The test name prune_cutoff_excludes_anchors_at_cutoff_height reads as "excludes [from preservation]" i.e. prunes, but the body asserts the opposite (anchor at cutoff is preserved because RangeTo is exclusive). Consider cutoff_is_exclusive_anchor_at_cutoff_preserved or similar to avoid future confusion.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/rs-drive/src/drive/shielded/prune_anchors/v0/mod.rs` around lines
146 - 179, Rename the test function
prune_cutoff_excludes_anchors_at_cutoff_height to a name that reflects the
exclusive-cutoff behavior (e.g., cutoff_is_exclusive_anchor_at_cutoff_preserved)
so the name matches the assertion that an anchor at the cutoff
(prune_shielded_pool_anchors_v0 with cutoff 20) is preserved; update the test
declaration and any references to the function name, keeping the test body using
seed_anchor, has_shielded_anchor, prune_shielded_pool_anchors_v0, and
PlatformVersion::latest unchanged.
packages/rs-drive/src/drive/shielded/has_anchor/v0/mod.rs (1)

54-94: Consider dropping the unrelated transaction on test teardown.

Minor nit only: the Transaction started at line 60 is never committed or rolled back. That is harmless here (it drops at end of scope), but if future changes add a post-test assertion outside the transaction it could silently observe stale state. Optional.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/rs-drive/src/drive/shielded/has_anchor/v0/mod.rs` around lines 54 -
94, The test has_anchor_returns_true_after_direct_insert creates a Transaction
via drive.grove.start_transaction() but never closes it; explicitly close the
transaction before test exit to avoid leaking an open transaction. After the
assertions, call the appropriate transaction finalizer on the transaction
variable (e.g., rollback or commit using the grove/transaction API your codebase
provides) so the started transaction is deterministically ended.
packages/rs-drive/src/drive/shielded/insert_nullifiers/v0/mod.rs (1)

58-127: LGTM — tests cover empty, single (with apply + round-trip via has_nullifier), and multi-insert op-count paths.

Minor note: insert_many_nullifiers_produces_matching_op_count only asserts the returned ops length and never applies the batch or checks membership. Since the apply+read path is already covered by the single-insert test and by has_nullifier/v0's tests, this is fine as-is; consider applying the batch and asserting all five are discoverable if you want stronger coverage here later.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/rs-drive/src/drive/shielded/insert_nullifiers/v0/mod.rs` around
lines 58 - 127, The test insert_many_nullifiers_produces_matching_op_count only
asserts ops.len() and doesn't apply or verify persistence; to strengthen the
test, after calling insert_nullifiers_v0 in
insert_many_nullifiers_produces_matching_op_count capture the returned ops,
convert them via LowLevelDriveOperation::grovedb_operations_batch_consume, apply
the batch with drive.grove_apply_batch_with_add_costs (matching the
single-nullifier test) and then assert each nullifier is present using
drive.has_nullifier to ensure the inserts were persisted and discoverable; use
the same transaction and platform_version variables already in the test.
packages/rs-dpp/src/state_transition/mod.rs (1)

2120-2166: Nit: redundant rebinding of contract_v1_range.

contract_v1_range is declared identically at Line 2124 and again at Line 2129 before its second use. The second binding is a no-op; drop it (or reuse the first binding for both assertions).

Proposed tweak
         let contract_v1_range = 9..=LATEST_VERSION;
         assert_eq!(
             sample_data_contract_create_st().active_version_range(),
-            contract_v1_range
+            contract_v1_range.clone()
         );
-        let contract_v1_range = 9..=LATEST_VERSION;
         assert_eq!(
             sample_data_contract_update_st().active_version_range(),
             contract_v1_range
         );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/rs-dpp/src/state_transition/mod.rs` around lines 2120 - 2166, In
test_active_version_range_contract_and_shielded_branches, remove the redundant
re-declaration of contract_v1_range and reuse the initial binding
(contract_v1_range = 9..=LATEST_VERSION) for both asserts that call
sample_data_contract_create_st().active_version_range() and
sample_data_contract_update_st().active_version_range(); keep the single
contract_v1_range binding and leave the rest of the assertions unchanged.
packages/rs-dpp/src/document/document_factory/mod.rs (1)

155-675: Test suite looks solid — good error-path and dispatch coverage.

The new DocumentFactory tests cover construction error paths, entropy-generator failure propagation, create_document/create_extended_document happy and error paths, buffer roundtrip, and the full matrix of create_state_transition error arms (NoDocumentsSupplied, MismatchOwnerIds, InvalidInitialRevision, RevisionAbsent for Create/Replace/Delete) plus nonce-increment and mixed-action success. Shared helpers (setup_factory, build_doc, deterministic/failing entropy generators) keep the cases compact and consistent.

One trivial observation: new_variant_is_v0 at Lines 234-241 only performs an exhaustive-variant match with no explicit assertion, so it serves only as a compile-time guard that the enum still has a single V0 arm — consider making that intent explicit (e.g., assert!(matches!(factory, DocumentFactory::V0(_)))) or dropping the test since new_with_entropy_generator_valid_version_succeeds already asserts the variant. Non-blocking.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/rs-dpp/src/document/document_factory/mod.rs` around lines 155 - 675,
The test new_variant_is_v0 only pattern-matches the DocumentFactory enum without
asserting — make the intent explicit by replacing the match-only check with an
assertion like assert!(matches!(factory, DocumentFactory::V0(_))) (or remove the
test); locate the test function new_variant_is_v0 and update its body to assert
the factory variant is V0 (referencing DocumentFactory::V0) so the test fails if
the variant changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/rs-dpp/src/document/v0/mod.rs`:
- Around line 312-322: The test display_invalid_timestamp_uses_default_formatter
incorrectly uses doc.created_at = Some(u64::MAX) which becomes -1 when cast to
i64 and thus DateTime::from_timestamp_millis returns Some; update the test to
supply a created_at value outside chrono's supported millisecond range (e.g. set
doc.created_at to (i64::MAX as u64) + 1 or another u64 > i64::MAX) so
DateTime::from_timestamp_millis returns None and the Display impl's
unwrap_or_default() branch is exercised; refer to the test function
display_invalid_timestamp_uses_default_formatter, the doc.created_at field, and
the DateTime::from_timestamp_millis usage in the Display impl when making the
change.

In `@packages/rs-dpp/src/shielded/builder/shielded_transfer.rs`:
- Around line 265-305: The test currently accepts either an "overflow" message
or "exceeds total", which masks whether the checked-add overflow branch
(transfer_amount.checked_add(effective_fee)) was hit; update the assertion in
test_shielded_transfer_fee_plus_amount_overflow_errors to require the
overflow-specific error only (i.e., assert that the returned error string/from
build_shielded_transfer_transition contains the overflow indicator) so the test
explicitly verifies the checked_add overflow path rather than the "exceeds
total" branch.

In `@packages/rs-dpp/src/shielded/builder/shielded_withdrawal.rs`:
- Around line 316-338: The test currently calls unwrap_err() on the result of
build_shielded_withdrawal_transition which fails if the call actually returned
Ok; change the assertion to allow Ok results for exact-boundary fee cases by
checking result.is_ok() first and only converting to a string and asserting the
error message does not contain "exceeds 1000x" when result.is_err(); update the
same pattern for the second occurrence around the
build_shielded_withdrawal_transition call at the later block (lines ~357-377)
and reference the fee_at_boundary variable and
build_shielded_withdrawal_transition to locate the code.

In `@packages/rs-dpp/src/shielded/builder/unshield.rs`:
- Around line 299-318: The test currently calls build_unshield_transition(...)
and immediately does result.unwrap_err().to_string(), which will panic if the
function returns Ok; change it to handle both outcomes: match on result from
build_unshield_transition (the call with spends, output_address, 100,
&change_address, &fvk, &ask, Anchor::empty_tree(), &TestProver, [0u8; 36],
Some(boundary), platform_version) — if Ok(_) then treat the test as passed for
the accepted-path; if Err(e) then convert e.to_string() and assert that the
error does not contain the upper-bound message ("exceeds 1000x") as before.
Apply the same pattern to the other identical block (the second occurrence
around the 407-427 region).

In
`@packages/rs-drive/src/drive/prefunded_specialized_balances/add_prefunded_specialized_balance_operations/v0/mod.rs`:
- Around line 105-134: The test calls
add_prefunded_specialized_balance_operations_v0 and then uses seed_balance to
create the entry instead of applying the ops produced, so swap the seed_balance
step: apply the returned ops (the ops variable from
add_prefunded_specialized_balance_operations_v0) to the Drive using the
appropriate apply method for drive operations (replace the seed_balance call)
and then call fetch_prefunded_specialized_balance to assert the persisted value;
do the same fix for the other similar test around lines 245-267 so the test
verifies the actual ops emitted by
add_prefunded_specialized_balance_operations_v0.

In
`@packages/rs-drive/src/drive/prefunded_specialized_balances/empty_prefunded_specialized_balance_operations/v0/mod.rs`:
- Around line 96-116: The test
empty_missing_without_error_flag_returns_zero_and_no_ops currently ignores the
returned operations (_ops) which allows read/cost ops to mask the intended "no
delete op" behavior; update the test to capture the returned ops (rename _ops to
ops) from empty_prefunded_specialized_balance_operations_v0 and explicitly
assert that no delete operation targeting the Identifier id is present in ops
(e.g., search ops for a delete of id and assert not found). Apply the analogous
change to the other test mentioned (the one around lines 164-184) to explicitly
assert presence/absence of the delete op for id instead of only checking ops
non-emptiness.

In
`@packages/rs-drive/src/verify/state_transition/state_transition_execution_path_queries/token_transition.rs`:
- Around line 443-464: Add an assertion that the TokenHistory contract id
appears as an exact path segment (not just across segment boundaries) for every
history-enabled query (e.g., the Burn/Freeze/Unfreeze/SetPrice transition
checks) after successful SingleDocumentDriveQuery::construct_path_query;
implement a small helper that takes &path_query.path and
token_history_contract.id().into_buffer() and verifies that one of the path
segments equals the contract id bytes (rather than using flattened windows on
full_path), then invoke that helper wherever you currently verify successful
query construction for history-enabled token operations.

In
`@packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs`:
- Around line 2624-2668: The test for ShieldedWithdrawal named "no nullifiers"
should assert the specific InvalidTransition proof error instead of accepting
any Proof/GroveDB failure: update the assert! to match
Err(crate::error::Error::Proof(ProofError::InvalidTransition)) (referencing the
ProofError variant from the proof types used by
verify_state_transition_was_executed_with_proof and the first_nullifier guard in
ShieldedWithdrawalTransitionV0); locate the assertion near the call to
Drive::verify_state_transition_was_executed_with_proof and replace the broad
matches! with a pattern that specifically expects the InvalidTransition Proof
error (or, if you prefer the test to cover malformed proofs, rename the test to
reflect that intent).

---

Nitpick comments:
In `@packages/rs-dpp/src/document/document_factory/mod.rs`:
- Around line 155-675: The test new_variant_is_v0 only pattern-matches the
DocumentFactory enum without asserting — make the intent explicit by replacing
the match-only check with an assertion like assert!(matches!(factory,
DocumentFactory::V0(_))) (or remove the test); locate the test function
new_variant_is_v0 and update its body to assert the factory variant is V0
(referencing DocumentFactory::V0) so the test fails if the variant changes.

In `@packages/rs-dpp/src/state_transition/mod.rs`:
- Around line 2120-2166: In
test_active_version_range_contract_and_shielded_branches, remove the redundant
re-declaration of contract_v1_range and reuse the initial binding
(contract_v1_range = 9..=LATEST_VERSION) for both asserts that call
sample_data_contract_create_st().active_version_range() and
sample_data_contract_update_st().active_version_range(); keep the single
contract_v1_range binding and leave the rest of the assertions unchanged.

In `@packages/rs-drive/src/drive/shielded/has_anchor/v0/mod.rs`:
- Around line 54-94: The test has_anchor_returns_true_after_direct_insert
creates a Transaction via drive.grove.start_transaction() but never closes it;
explicitly close the transaction before test exit to avoid leaking an open
transaction. After the assertions, call the appropriate transaction finalizer on
the transaction variable (e.g., rollback or commit using the grove/transaction
API your codebase provides) so the started transaction is deterministically
ended.

In `@packages/rs-drive/src/drive/shielded/insert_nullifiers/v0/mod.rs`:
- Around line 58-127: The test insert_many_nullifiers_produces_matching_op_count
only asserts ops.len() and doesn't apply or verify persistence; to strengthen
the test, after calling insert_nullifiers_v0 in
insert_many_nullifiers_produces_matching_op_count capture the returned ops,
convert them via LowLevelDriveOperation::grovedb_operations_batch_consume, apply
the batch with drive.grove_apply_batch_with_add_costs (matching the
single-nullifier test) and then assert each nullifier is present using
drive.has_nullifier to ensure the inserts were persisted and discoverable; use
the same transaction and platform_version variables already in the test.

In `@packages/rs-drive/src/drive/shielded/nullifiers/types.rs`:
- Around line 168-260: The test module is splitting production types—move the
entire #[cfg(test)] mod tests block to the end of the file so production items
remain contiguous; specifically, relocate the declaration of
NullifierChangePerBlock so it appears before the tests (ensure
CompactedNullifierChange and NullifierChangePerBlock are adjacent), then place
#[cfg(test)] mod tests { ... } as the final item in the file.

In `@packages/rs-drive/src/drive/shielded/prune_anchors/v0/mod.rs`:
- Around line 146-179: Rename the test function
prune_cutoff_excludes_anchors_at_cutoff_height to a name that reflects the
exclusive-cutoff behavior (e.g., cutoff_is_exclusive_anchor_at_cutoff_preserved)
so the name matches the assertion that an anchor at the cutoff
(prune_shielded_pool_anchors_v0 with cutoff 20) is preserved; update the test
declaration and any references to the function name, keeping the test body using
seed_anchor, has_shielded_anchor, prune_shielded_pool_anchors_v0, and
PlatformVersion::latest unchanged.
🪄 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: 5ed24db9-feb8-4c8b-9cbf-5238781da8e0

📥 Commits

Reviewing files that changed from the base of the PR and between 4355c15 and 9db5136.

📒 Files selected for processing (30)
  • packages/rs-dpp/src/document/document_factory/mod.rs
  • packages/rs-dpp/src/document/extended_document/v0/mod.rs
  • packages/rs-dpp/src/document/v0/mod.rs
  • packages/rs-dpp/src/shielded/builder/mod.rs
  • packages/rs-dpp/src/shielded/builder/shield.rs
  • packages/rs-dpp/src/shielded/builder/shield_from_asset_lock.rs
  • packages/rs-dpp/src/shielded/builder/shielded_transfer.rs
  • packages/rs-dpp/src/shielded/builder/shielded_withdrawal.rs
  • packages/rs-dpp/src/shielded/builder/unshield.rs
  • packages/rs-dpp/src/state_transition/mod.rs
  • packages/rs-drive/src/drive/prefunded_specialized_balances/add_prefunded_specialized_balance_operations/v0/mod.rs
  • packages/rs-drive/src/drive/prefunded_specialized_balances/add_prefunded_specialized_balance_operations/v1/mod.rs
  • packages/rs-drive/src/drive/prefunded_specialized_balances/deduct_from_prefunded_specialized_balance_operations/v0/mod.rs
  • packages/rs-drive/src/drive/prefunded_specialized_balances/deduct_from_prefunded_specialized_balance_operations/v1/mod.rs
  • packages/rs-drive/src/drive/prefunded_specialized_balances/empty_prefunded_specialized_balance_operations/v0/mod.rs
  • packages/rs-drive/src/drive/prefunded_specialized_balances/fetch/single_balance/v0/mod.rs
  • packages/rs-drive/src/drive/prefunded_specialized_balances/prove/single_balance/v0/mod.rs
  • packages/rs-drive/src/drive/shielded/has_anchor/v0/mod.rs
  • packages/rs-drive/src/drive/shielded/has_nullifier/v0/mod.rs
  • packages/rs-drive/src/drive/shielded/insert_note/v0/mod.rs
  • packages/rs-drive/src/drive/shielded/insert_nullifiers/v0/mod.rs
  • packages/rs-drive/src/drive/shielded/notes_count/v0/mod.rs
  • packages/rs-drive/src/drive/shielded/nullifiers/types.rs
  • packages/rs-drive/src/drive/shielded/paths.rs
  • packages/rs-drive/src/drive/shielded/prune_anchors/v0/mod.rs
  • packages/rs-drive/src/drive/shielded/read_total_balance/v0/mod.rs
  • packages/rs-drive/src/drive/shielded/record_anchor_if_changed/v0/mod.rs
  • packages/rs-drive/src/drive/shielded/update_total_balance/v0/mod.rs
  • packages/rs-drive/src/verify/state_transition/state_transition_execution_path_queries/token_transition.rs
  • packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs

Comment thread packages/rs-dpp/src/document/v0/mod.rs
Comment thread packages/rs-dpp/src/shielded/builder/shielded_transfer.rs
Comment thread packages/rs-dpp/src/shielded/builder/shielded_withdrawal.rs Outdated
Comment on lines +299 to +318
let result = build_unshield_transition(
spends,
output_address,
100,
&change_address,
&fvk,
&ask,
Anchor::empty_tree(),
&TestProver,
[0u8; 36],
Some(boundary),
platform_version,
);
let err = result.unwrap_err().to_string();
// Must not trip the upper-bound branch.
assert!(
!err.contains("exceeds 1000x"),
"boundary fee should be accepted: {}",
err
);
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.

⚠️ Potential issue | 🟡 Minor

Don’t fail accepted-path tests on successful builds.

These cases are checking that validation is bypassed/reaches downstream logic. A future Ok result should satisfy that intent instead of panicking via unwrap_err().

Proposed test adjustment
-        let err = result.unwrap_err().to_string();
-        // Must not trip the upper-bound branch.
-        assert!(
-            !err.contains("exceeds 1000x"),
-            "boundary fee should be accepted: {}",
-            err
-        );
+        if let Err(err) = result {
+            let err = err.to_string();
+            // Must not trip the upper-bound branch.
+            assert!(
+                !err.contains("exceeds 1000x"),
+                "boundary fee should be accepted: {}",
+                err
+            );
+        }
@@
-        let err_msg = result.unwrap_err().to_string();
-        assert!(
-            err_msg.contains("failed to add spend")
-                || err_msg.contains("anchor")
-                || err_msg.contains("AnchorMismatch"),
-            "expected downstream add_spend error, got: {}",
-            err_msg
-        );
+        if let Err(err) = result {
+            let err_msg = err.to_string();
+            assert!(
+                err_msg.contains("failed to add spend")
+                    || err_msg.contains("anchor")
+                    || err_msg.contains("AnchorMismatch"),
+                "expected downstream add_spend error, got: {}",
+                err_msg
+            );
+        }

Also applies to: 407-427

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/rs-dpp/src/shielded/builder/unshield.rs` around lines 299 - 318, The
test currently calls build_unshield_transition(...) and immediately does
result.unwrap_err().to_string(), which will panic if the function returns Ok;
change it to handle both outcomes: match on result from
build_unshield_transition (the call with spends, output_address, 100,
&change_address, &fvk, &ask, Anchor::empty_tree(), &TestProver, [0u8; 36],
Some(boundary), platform_version) — if Ok(_) then treat the test as passed for
the accepted-path; if Err(e) then convert e.to_string() and assert that the
error does not contain the upper-bound message ("exceeds 1000x") as before.
Apply the same pattern to the other identical block (the second occurrence
around the 407-427 region).

Comment on lines +2624 to +2668
// --- ShieldedWithdrawal: no nullifiers → InvalidTransition error.
#[test]
fn verify_shielded_withdrawal_no_nullifiers_returns_invalid_transition() {
let platform_version = PlatformVersion::latest();
use dpp::identity::core_script::CoreScript;
use dpp::state_transition::shielded_withdrawal_transition::v0::ShieldedWithdrawalTransitionV0;
use dpp::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition;
use dpp::withdrawal::Pooling;

let st = StateTransition::ShieldedWithdrawal(ShieldedWithdrawalTransition::V0(
ShieldedWithdrawalTransitionV0 {
actions: vec![],
unshielding_amount: 0,
anchor: [0u8; 32],
proof: vec![],
binding_signature: [0u8; 64],
core_fee_per_byte: 1,
pooling: Pooling::Never,
output_script: CoreScript::from_bytes(vec![]),
},
));

let known_contracts_provider_fn: &ContractLookupFn = &|_id| Ok(None);

// The proof content doesn't matter: we expect the grove-db call to
// either fail or return with no spent nullifiers, but the path runs
// through several verify_shielded_nullifiers calls which typically
// error out first. The test only asserts the result is an Error.
let result = Drive::verify_state_transition_was_executed_with_proof(
&st,
&BlockInfo::default(),
&[],
known_contracts_provider_fn,
platform_version,
);

assert!(
matches!(
result,
Err(crate::error::Error::Proof(_)) | Err(crate::error::Error::GroveDB(_))
),
"expected error for shielded withdrawal with no nullifiers, got: {:?}",
result
);
}
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.

⚠️ Potential issue | 🟡 Minor

Match the test name by asserting InvalidTransition.

The test is named and commented as the “no nullifiers” invalid-transition case, but Lines 2660-2667 accept any proof/GroveDB failure. If the intent is to cover the first_nullifier guard, assert ProofError::InvalidTransition; otherwise rename it to an empty-proof/malformed-proof test.

Suggested assertion if the invalid-transition branch is intended
-        assert!(
-            matches!(
-                result,
-                Err(crate::error::Error::Proof(_)) | Err(crate::error::Error::GroveDB(_))
-            ),
-            "expected error for shielded withdrawal with no nullifiers, got: {:?}",
-            result
-        );
+        assert!(
+            matches!(
+                result,
+                Err(crate::error::Error::Proof(ProofError::InvalidTransition(msg)))
+                    if msg.contains("no nullifiers")
+            ),
+            "expected InvalidTransition for shielded withdrawal with no nullifiers, got: {:?}",
+            result
+        );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs`
around lines 2624 - 2668, The test for ShieldedWithdrawal named "no nullifiers"
should assert the specific InvalidTransition proof error instead of accepting
any Proof/GroveDB failure: update the assert! to match
Err(crate::error::Error::Proof(ProofError::InvalidTransition)) (referencing the
ProofError variant from the proof types used by
verify_state_transition_was_executed_with_proof and the first_nullifier guard in
ShieldedWithdrawalTransitionV0); locate the assertion near the call to
Drive::verify_state_transition_was_executed_with_proof and replace the broad
matches! with a pattern that specifically expects the InvalidTransition Proof
error (or, if you prefer the test to cover malformed proofs, rename the test to
reflect that intent).

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 21, 2026

Codecov Report

❌ Patch coverage is 96.43888% with 111 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.76%. Comparing base (4355c15) to head (fdf03e9).
⚠️ Report is 1 commits behind head on v3.1-dev.

Files with missing lines Patch % Lines
...state_transition_was_executed_with_proof/v0/mod.rs 92.82% 14 Missing ⚠️
...es/rs-dpp/src/document/extended_document/v0/mod.rs 92.94% 11 Missing ⚠️
...ckages/rs-dpp/src/document/document_factory/mod.rs 97.48% 9 Missing ⚠️
packages/rs-dpp/src/shielded/builder/mod.rs 90.12% 8 Missing ⚠️
packages/rs-dpp/src/shielded/builder/unshield.rs 94.07% 8 Missing ⚠️
packages/rs-dpp/src/document/v0/mod.rs 94.35% 7 Missing ⚠️
packages/rs-dpp/src/shielded/builder/shield.rs 90.76% 6 Missing ⚠️
...s/rs-dpp/src/shielded/builder/shielded_transfer.rs 94.59% 6 Missing ⚠️
...rs-dpp/src/shielded/builder/shielded_withdrawal.rs 94.44% 6 Missing ⚠️
...es/rs-drive/src/drive/shielded/nullifiers/types.rs 90.16% 6 Missing ⚠️
... and 12 more
Additional details and impacted files
@@             Coverage Diff              @@
##           v3.1-dev    #3506      +/-   ##
============================================
+ Coverage     85.30%   85.76%   +0.45%     
============================================
  Files          2476     2476              
  Lines        270705   276009    +5304     
============================================
+ Hits         230938   236728    +5790     
+ Misses        39767    39281     -486     
Components Coverage Δ
dpp 84.10% <96.13%> (+0.90%) ⬆️
drive 85.35% <96.80%> (+0.64%) ⬆️
drive-abci 87.49% <ø> (ø)
sdk ∅ <ø> (∅)
dapi-client ∅ <ø> (∅)
platform-version ∅ <ø> (∅)
platform-value 92.10% <ø> (ø)
platform-wallet ∅ <ø> (∅)
drive-proof-verifier 55.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.

Tighten 8 test assertions per CodeRabbit feedback:

- document/v0: use i64::MAX (outside chrono's range) instead of
  u64::MAX (which casts to -1i64, inside range) so the
  DateTime::from_timestamp_millis None branch + unwrap_or_default
  is actually exercised.
- shielded/builder/shielded_transfer: assert the specific
  "fee + transfer_amount overflows u64" message instead of the
  broader "overflow or exceeds total" or-pattern, so the test
  actually verifies checked_add's overflow branch.
- shielded/builder/shielded_withdrawal + unshield: boundary-fee
  tests now accept Ok as valid (exact-boundary values SHOULD pass
  validation) — only assert that any error message doesn't mention
  "exceeds 1000x" / "below minimum required fee".
- prefunded/add: apply the ops the function actually returned via
  apply_batch_low_level_drive_operations and fetch, rather than
  re-seeding through the dispatcher — so the insert branch's
  GroveDB write is what we verify.
- prefunded/empty: assert GroveDB delete op presence/absence
  directly via a local has_delete_op helper rather than checking
  ops.is_empty() (read/cost ops can satisfy non-empty alone).
- verify/state_transition/token_transition: assert the TokenHistory
  contract id appears as an exact path segment for every
  history-enabled transition (Burn/Freeze/Unfreeze/SetPrice) via
  new assert_path_targets_token_history helper. Replaces the old
  flatten+windows check which could match across segment boundaries.
- verify/state_transition/verify_..._with_proof: rename
  verify_shielded_withdrawal_no_nullifiers_returns_invalid_transition
  to verify_shielded_withdrawal_empty_proof_error since the empty
  proof fails before the first_nullifier guard is reachable.

All 185 touched tests still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@QuantumExplorer QuantumExplorer merged commit effa891 into v3.1-dev Apr 21, 2026
15 checks passed
@QuantumExplorer QuantumExplorer deleted the test/coverage-lowcov-shielded-factories-verify branch April 21, 2026 19:41
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