Skip to content

test: improve coverage for dpp and drive-proof-verifier#3504

Merged
QuantumExplorer merged 2 commits into
v3.1-devfrom
test/coverage-proof-verifier-and-dpp-factories
Apr 21, 2026
Merged

test: improve coverage for dpp and drive-proof-verifier#3504
QuantumExplorer merged 2 commits into
v3.1-devfrom
test/coverage-proof-verifier-and-dpp-factories

Conversation

@QuantumExplorer
Copy link
Copy Markdown
Member

@QuantumExplorer QuantumExplorer commented Apr 21, 2026

Issue being fixed or feature implemented

After merging #3503, global coverage sits at 85.05%. This is the first of a planned multi-PR push toward 90%. Targets the files with the lowest coverage-to-line-count ratio identified from the Codecov tree:

File / module Prev cov Missed lines
rs-drive-proof-verifier/src/proof.rs 45.30% 948
rs-dpp/state_transition/mod.rs 55.42% 325
rs-dpp/document/specialized_document_factory 44.40% 298
rs-dpp/identity/identity_public_key 51.89% 216
rs-dpp/identity/identity_factory.rs 42.91% 145
rs-dpp/data_contract/created_data_contract 20.34% 141

What was done?

171 new unit tests added across 10 files. All inline #[cfg(test)] mod tests blocks — no new integration dependencies, no mocks feature required.

rs-drive-proof-verifier/proof.rs — 31 tests

  • Length trait impls for Vec<Option<T>>, Option<T>, Vec<(K, Option<T>)>, BTreeMap<K, Option<T>>, IndexMap<K, Option<T>>
  • IntoOption absence-preserving semantics (empty→None, non-empty→Some(self))
  • parse_key_request_type — all 3 error branches + 3 happy paths (AllKeys, SpecificKeys, SearchKey)
  • FromProof decode-error paths that fire before any crypto: Identity (4 error arms), Identity by public_key_hash (wrong length), Identity by non-unique public_key_hash (4 decode paths), IdentityBalances, DataContracts, GetProtocolVersionUpgradeVoteStatus, GetPathElements, GetPrefundedSpecializedBalance, GetEpochsInfo overflow, BroadcastStateTransition garbage bytes. A module-scoped UnreachableContextProvider panics on any method call, proving error paths exit before verification.

rs-dpp/state_transition/mod.rs — 25 tests

Covers name(), state_transition_type(), is_identity_signed(), signature(), owner_id(), signature_public_key_id(), user_fee_increase() and their setters, required_number_of_private_keys() default arm, active_version_range() ALL_VERSIONS arm, unique_identifiers() / transaction_id() determinism + mutation sensitivity, From<IdentityCreditTransferTransition>, From<MasternodeVoteTransition>, and PlatformSerializable/PlatformDeserializable roundtrip.

rs-dpp/data_contract/created_data_contract — 14 tests

Tests from_contract_and_identity_nonce, all accessors (data_contract, data_contract_owned, data_contract_mut, data_contract_and_identity_nonce), set_identity_nonce, From<CreatedDataContract> for DataContract, both PlatformSerializableWithPlatformVersion paths produce identical bytes, and PlatformDeserializableWithPotentialValidationFromVersionedStructure roundtrip + garbage/empty error arms.

rs-dpp/identity/identity_public_key/ — 69 tests across 5 files

  • purpose.rs (13): TryFrom<u8> / TryFrom<i32> valid + invalid, From<Purpose> for byte arrays, Display, Default, ordering, full_range(), searchable_purposes()
  • security_level.rs (15): TryFrom<u8> happy + UnknownSecurityLevelError, byte conversions, Default is HIGH, stronger_security_than full matrix (not reflexive), stronger_or_equal_security_than (reflexive)
  • contract_bounds/mod.rs (9): new_from_type(0) / new_from_type(1) happy + error paths, contract_bounds_type_from_str, all accessors
  • v0/methods/mod.rs (9): public_key_hash() ECDSA/BLS/HASH160/BIP13 branches + EmptyPublicKeyDataError + ParsingError on wrong-length; validate_private_key_bytes for BIP13_SCRIPT_HASH returns NotSupported; invalid secret-key bytes return Ok(false) (not Err)
  • mod.rs (23): is_master across all security levels, max_possible_size_key structure, default_versioned, enum wrapper getters/setters (set_disabled_at / remove_disabled_at / data_owned), random key generators (deterministic seed, correct attributes for master/critical/high/voting/owner/transfer), main_keys_with_random_authentication_keys_with_rng error path (count < 2) and positional assertions

rs-dpp/identity/identity_factory.rs — 14 tests

  • create_from_buffer happy + SerializedObjectParsingError
  • create_identity_create_transition_from_identity, create_identity_with_create_transition_computes_id_from_asset_lock_proof
  • create_identity_topup_transition, create_identity_credit_transfer_transition
  • create_identity_credit_withdrawal_transition V0 missing-output-script ProtocolError::Generic + V0 with-script + V1 (None script accepted) + UnknownVersionMismatch
  • create_identity_update_transition with adds + with disabled keys
  • create_instant_lock_proof_preserves_output_index

rs-dpp/document/specialized_document_factory/v0/mod.rs — 18 tests

  • PlatformVersion::get error paths for new, create_document, create_document_without_time_based_properties
  • create_document entropy generator determinism + time-based property injection
  • create_state_transition Create/Delete/Replace happy paths including document_create_transitions, document_delete_transitions, document_replace_transitions
  • NoDocumentsSuppliedError, mismatched-owners error, RevisionAbsentError in all 3 helpers, InvalidInitialRevisionError, nonce accumulator increments
  • create_extended_from_document_buffer roundtrip + invalid-type + bad-bytes error branches

How Has This Been Tested?

  • cargo test -p drive-proof-verifier67 passed (31 new + 36 pre-existing)
  • cargo test -p dpp --lib identity_public_key124 passed
  • cargo test -p dpp --lib identity_factory12 passed
  • cargo test -p dpp --lib specialized_document_factory29 passed
  • cargo test -p dpp --lib created_data_contract17 passed
  • cargo test -p dpp --lib 'state_transition::tests'31 passed
  • cargo check --tests -p dpp / cargo check --tests -p drive-proof-verifier — clean (no new warnings)
  • cargo fmt -p dpp -p drive-proof-verifier — clean

No production bugs were surfaced. One documented quirk preserved in tests: Purpose::full_range() intentionally excludes SYSTEM despite its name.

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

  • Tests
    • Expanded comprehensive unit test coverage across core modules including data contracts, documents, identity management, public keys, state transitions, and proof verification, covering serialization/deserialization round-trips, validation error paths, state management, and cryptographic operations.

Add 171 new unit tests across 10 files targeting the highest
bang-for-buck coverage gaps identified from Codecov:

- rs-drive-proof-verifier/proof.rs (45% → covered): 31 tests exercising
  the Length trait impls for all four container variants, IntoOption
  semantics, parse_key_request_type happy/error branches, and
  FromProof decode-error paths for Identity (NoProofInResult,
  EmptyResponseMetadata, EmptyVersion, ProtocolError),
  Identity by public_key_hash, Identity by non-unique hash (all four
  decode branches), IdentityBalances/DataContracts bad id length,
  GetProtocolVersionUpgradeVoteStatus, GetPathElements,
  GetPrefundedSpecializedBalance, GetEpochsInfo overflow, and
  BroadcastStateTransition garbage bytes. A module-scoped
  UnreachableContextProvider proves errors exit before any crypto.

- rs-dpp/state_transition/mod.rs (55% → covered): 25 tests hitting
  name(), state_transition_type(), is_identity_signed(),
  signature/owner_id/signature_public_key_id accessors, setters
  (including MasternodeVote no-op), required_number_of_private_keys
  default arm, active_version_range ALL_VERSIONS arm,
  unique_identifiers/transaction_id determinism, From impls via
  derive_more, and PlatformSerializable roundtrip.

- rs-dpp/data_contract/created_data_contract (20% → covered): 14 tests
  covering from_contract_and_identity_nonce, all accessors, From impl
  to DataContract, both serialize paths producing identical bytes,
  deserialize roundtrip + garbage/empty error arms.

- rs-dpp/identity/identity_public_key/ (52% → covered): 69 tests
  across 5 files. purpose.rs (13), security_level.rs (15),
  contract_bounds (9), v0/methods (9 for public_key_hash +
  validate_private_key_bytes error paths), mod.rs (23 for
  is_master/max_possible_size_key/default_versioned/random key
  generators/main_keys helpers).

- rs-dpp/identity/identity_factory.rs (43% → covered): 14 tests across
  create_from_buffer happy+error paths, all create_identity_*_transition
  variants including V0/V1 withdrawal branches and UnknownVersionMismatch.

- rs-dpp/document/specialized_document_factory (44% → covered): 18 tests
  hitting get-version error arms, create_document happy paths,
  create_state_transition Create/Delete/Replace branches,
  NoDocumentsSupplied/MismatchedOwners/RevisionAbsent/InvalidInitialRevision
  error arms, nonce accumulator, and extended-document roundtrip.

No production bugs surfaced. All tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@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 47 minutes and 11 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 47 minutes and 11 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: 4fa59727-2e3e-4f17-936a-c4fa08bc0c15

📥 Commits

Reviewing files that changed from the base of the PR and between 55cad9f and 44316a2.

📒 Files selected for processing (1)
  • packages/rs-drive-proof-verifier/src/proof.rs
📝 Walkthrough

Walkthrough

This pull request adds comprehensive unit test coverage across multiple modules in the rs-dpp and rs-drive-proof-verifier packages, including tests for data contracts, document factories, identity systems, public keys, state transitions, and proof verification. No production code was modified.

Changes

Cohort / File(s) Summary
CreatedDataContract Tests
packages/rs-dpp/src/data_contract/created_data_contract/mod.rs
Added unit tests validating construction via from_contract_and_identity_nonce, getter/setter correctness, serialization round-trips with bincode, conversion from CreatedDataContract to DataContract, handling of invalid/empty inputs, and clone/equality behavior.
SpecializedDocumentFactory Tests
packages/rs-dpp/src/document/specialized_document_factory/v0/mod.rs
Added tests for factory construction without protocol version validation, negative paths for invalid versions, document ID derivation consistency, state transition creation (create/replace/delete) with nonce accounting, and extended document serialization/deserialization.
Identity Factory & Public Key Tests
packages/rs-dpp/src/identity/identity_factory.rs, packages/rs-dpp/src/identity/identity_public_key/mod.rs
Added tests for identity serialization round-trips, state transition factory construction from identity/asset-lock proofs, topup/credit transfer/withdrawal/identity update transitions, and randomized public key generation with determinism validation.
Public Key Contract Bounds Tests
packages/rs-dpp/src/identity/identity_public_key/contract_bounds/mod.rs
Added tests for ContractBounds variant construction, type/identifier accessors, error handling for invalid types/lengths, string parsing round-trips, and equality/clone semantics.
Public Key Purpose & Security Level Tests
packages/rs-dpp/src/identity/identity_public_key/purpose.rs, packages/rs-dpp/src/identity/identity_public_key/security_level.rs
Added tests validating enum variant conversions (TryFrom<u8>, From to byte forms), Display formatting, default values, helper method contents (full_range, lowest_level, strongest_security_than), and round-trip behavior.
Public Key Methods Tests
packages/rs-dpp/src/identity/identity_public_key/v0/methods/mod.rs
Added tests for public_key_hash() covering empty data errors and hashing logic per key type, and validate_private_key_bytes() covering unsupported/invalid key material handling.
StateTransition Tests
packages/rs-dpp/src/state_transition/mod.rs
Added tests for StateTransition enum methods (name(), state_transition_type(), signature(), owner_id()), setters (set_signature(), set_user_fee_increase()), protocol requirements (security_level_requirement(), purpose_requirement()), serialization round-trips, and deterministic hashing.
Proof Verifier Tests
packages/rs-drive-proof-verifier/src/proof.rs
Added tests for Length trait across multiple container shapes, IntoOption trait behavior, parse_key_request_type with valid/invalid key kinds, and FromProof decode error paths validating early failure on missing proof/metadata/invalid request fields.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰✨ From hopping through code with test-y delight,
Comprehensive coverage brings bugs to light!
Each module now guarded by assertions so keen,
The finest test suite a rabbit has seen! 🧪

🚥 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 pull request title accurately and clearly describes the main objective: adding test coverage improvements for dpp and drive-proof-verifier modules.
Docstring Coverage ✅ Passed Docstring coverage is 95.54% 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-proof-verifier-and-dpp-factories

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.

@github-actions github-actions Bot added this to the v3.1.0 milestone Apr 21, 2026
@thepastaclaw
Copy link
Copy Markdown
Collaborator

thepastaclaw commented Apr 21, 2026

Review Gate

Commit: 44316a2a

  • Debounce: 22m ago (need 30m)

  • CI checks: builds passed, 0/2 tests passed

  • CodeRabbit review: comment found

  • Off-peak hours: peak window (5am-11am PT) — currently 06:14 AM PT Tuesday

  • Run review now (check to override)

@QuantumExplorer QuantumExplorer changed the title test(dpp, drive-proof-verifier): improve coverage on low-cov files test: improve coverage for dpp and drive-proof-verifier Apr 21, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 21, 2026

Codecov Report

❌ Patch coverage is 98.49138% with 21 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.30%. Comparing base (2e135bf) to head (44316a2).
⚠️ Report is 1 commits behind head on v3.1-dev.

Files with missing lines Patch % Lines
...rc/document/specialized_document_factory/v0/mod.rs 98.18% 6 Missing ⚠️
packages/rs-dpp/src/identity/identity_factory.rs 97.12% 6 Missing ⚠️
...src/identity/identity_public_key/v0/methods/mod.rs 98.11% 3 Missing ⚠️
...dentity/identity_public_key/contract_bounds/mod.rs 97.18% 2 Missing ⚠️
packages/rs-dpp/src/state_transition/mod.rs 99.00% 2 Missing ⚠️
...dpp/src/data_contract/created_data_contract/mod.rs 99.16% 1 Missing ⚠️
...ges/rs-dpp/src/identity/identity_public_key/mod.rs 99.66% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           v3.1-dev    #3504      +/-   ##
============================================
+ Coverage     85.05%   85.30%   +0.25%     
============================================
  Files          2476     2476              
  Lines        269313   270705    +1392     
============================================
+ Hits         229062   230938    +1876     
+ Misses        40251    39767     -484     
Components Coverage Δ
dpp 83.20% <98.49%> (+1.19%) ⬆️
drive 84.71% <ø> (ø)
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.

@QuantumExplorer
Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 21, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (10)
packages/rs-dpp/src/identity/identity_public_key/v0/methods/mod.rs (1)

244-445: Optional: extract a test helper to reduce duplicated IdentityPublicKeyV0 literals.

The new tests repeat the full IdentityPublicKeyV0 { id: 0, purpose: …, security_level: …, contract_bounds: None, key_type, data, read_only: false, disabled_at: None } literal 9 times, differing only in key_type and data. A small helper (or a ..Default::default() spread, since IdentityPublicKeyV0 derives Default) would make intent clearer and reduce churn if the struct gains new fields.

♻️ Example refactor
fn key_with(key_type: KeyType, data: Vec<u8>) -> IdentityPublicKeyV0 {
    IdentityPublicKeyV0 {
        key_type,
        data: platform_value::BinaryData::new(data),
        ..Default::default()
    }
}

Then each test becomes a one-liner like:

let key = key_with(KeyType::ECDSA_SECP256K1, vec![1u8; 32]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/rs-dpp/src/identity/identity_public_key/v0/methods/mod.rs` around
lines 244 - 445, Extract a small test helper to avoid repeating the
IdentityPublicKeyV0 literal: add a function like key_with(key_type: KeyType,
data: Vec<u8>) -> IdentityPublicKeyV0 that constructs an IdentityPublicKeyV0
using the provided key_type and data (wrapping data with
platform_value::BinaryData::new) and fills the rest via ..Default::default();
then replace the repeated literals in tests like
test_public_key_hash_empty_data_errors,
test_public_key_hash_ecdsa_wrong_length_errors,
test_public_key_hash_bls_wrong_length_errors,
test_public_key_hash_bls_returns_ripemd160_sha256_of_data,
test_public_key_hash_ecdsa_hash160_returns_data_itself,
test_public_key_hash_bip13_script_hash_returns_data_itself,
test_public_key_hash_hash160_wrong_length_errors,
test_validate_private_key_bytes_bip13_script_hash_is_unsupported,
test_validate_private_key_bytes_ecdsa_secret_key_parse_error_returns_false, and
test_validate_private_key_bytes_ecdsa_hash160_secret_key_parse_error_returns_false
to call key_with(...) with the differing key_type and data.
packages/rs-dpp/src/identity/identity_public_key/purpose.rs (1)

223-236: Consider renaming full_range() or adding a doc comment to clarify SYSTEM is excluded.

The method returns 6 of 7 Purpose variants, intentionally omitting SYSTEM (which appears to be system-internal only). The doc comment "The full range of purposes" is misleading; consider either renaming to assignable_purposes() / user_purposes() or adding a doc comment explaining that SYSTEM is excluded by design.

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

In `@packages/rs-dpp/src/identity/identity_public_key/purpose.rs` around lines 223
- 236, Rename or clarify Purpose::full_range() to indicate it excludes SYSTEM by
either renaming the method (e.g., assignable_purposes() or user_purposes()) or
keeping the name but adding a doc comment explicitly stating that SYSTEM is
intentionally omitted; update any callers/tests (e.g., the
test_purpose_full_range_contents test and references to full_range()) to use the
new name or reflect the clarified behavior and ensure the doc comment mentions
that full_range()/assignable_purposes() returns the six purpose variants
(AUTHENTICATION, ENCRYPTION, DECRYPTION, TRANSFER, VOTING, OWNER) and excludes
SYSTEM which is system-internal only.
packages/rs-dpp/src/data_contract/created_data_contract/mod.rs (2)

328-340: Assert the full round-trip value, not just nonce and ID.

This can pass even if serialization drops or mutates other contract fields. Since CreatedDataContract already implements PartialEq, compare the restored value directly.

Strengthen the round-trip assertion
         let restored = CreatedDataContract::versioned_deserialize(&bytes, false, platform_version)
             .expect("deserialize should succeed");
-        assert_eq!(restored.identity_nonce(), created.identity_nonce());
-        assert_eq!(restored.data_contract().id(), created.data_contract().id());
+        assert_eq!(restored, created);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/rs-dpp/src/data_contract/created_data_contract/mod.rs` around lines
328 - 340, The test serialize_roundtrip_via_platform_version only compares
identity_nonce() and data_contract().id(), which can miss other mutated fields;
update the assertion to compare the whole CreatedDataContract using PartialEq by
replacing the two field-level asserts with a single assert_eq!(restored,
created) after versioned_deserialize (keep the same setup using sample_created,
serialize_to_bytes_with_platform_version, and
CreatedDataContract::versioned_deserialize to perform the round-trip).

386-405: Validate both values returned by the helper.

data_contract_and_identity_nonce_owned() returns the contract format and nonce, but this test ignores the contract. A swapped or wrong contract payload would still pass.

Cover the returned contract format too
-        let (decoded, _consumed) = bincode::borrow_decode_from_slice::<
+        let (decoded, consumed) = bincode::borrow_decode_from_slice::<
             CreatedDataContractInSerializationFormat,
             _,
         >(&bytes, config)
         .expect("raw bincode decode should succeed");
-        let (_contract_fmt, nonce) = decoded.data_contract_and_identity_nonce_owned();
+        assert_eq!(consumed, bytes.len());
+        let (contract_fmt, nonce) = decoded.data_contract_and_identity_nonce_owned();
+        let contract = DataContract::try_from_platform_versioned(
+            contract_fmt,
+            false,
+            &mut vec![],
+            platform_version,
+        )
+        .expect("contract format should convert back");
+        assert_eq!(contract.id(), created.data_contract().id());
         assert_eq!(nonce, created.identity_nonce());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/rs-dpp/src/data_contract/created_data_contract/mod.rs` around lines
386 - 405, The test only asserts the returned nonce from
data_contract_and_identity_nonce_owned(); update it to also validate the
returned contract format: destructure as let (contract_fmt, nonce) =
decoded.data_contract_and_identity_nonce_owned(); then assert_eq!(nonce,
created.identity_nonce()) and assert_eq!(contract_fmt, created.data_contract())
(or the appropriate accessor on sample_created() that returns the expected
contract) so the contract payload is also verified; use
CreatedDataContractInSerializationFormat::data_contract_and_identity_nonce_owned(),
sample_created(), and created.identity_nonce() to locate the code to change.
packages/rs-dpp/src/document/specialized_document_factory/v0/mod.rs (3)

930-954: Assertion doesn't cover what the test name claims.

create_state_transition_replace_on_mutable_document_increments_revision doesn't actually assert that the revision was incremented — it only checks transitions_len and the nonce. Consider reaching into the produced transition (DocumentReplaceTransition) and asserting revision == INITIAL_REVISION + 1, otherwise a regression in document.set_revision(...revision + 1) inside document_replace_transitions would silently slip through.

Example assertion
             let batch = factory
                 .create_state_transition(entries, &mut nonce_counter)
                 .expect("replace transition should be built");
             assert_eq!(batch.transitions_len(), 1);
             assert_eq!(batch.owner_id(), owner_id);
+            // Replace must bump the revision from INITIAL_REVISION to INITIAL_REVISION + 1.
+            match batch.transitions().first().expect("one transition") {
+                DocumentTransition::Replace(r) => {
+                    assert_eq!(r.base().revision(), INITIAL_REVISION + 1);
+                }
+                other => panic!("expected Replace, got {other:?}"),
+            }
             let key = (owner_id, data_contract.id());
             assert_eq!(*nonce_counter.get(&key).unwrap(), 1);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/rs-dpp/src/document/specialized_document_factory/v0/mod.rs` around
lines 930 - 954, The test
create_state_transition_replace_on_mutable_document_increments_revision
currently never checks the produced transition's revision; update the test to
extract the created transition from batch (the result of
factory.create_state_transition), cast/inspect it as a
DocumentReplaceTransition, and assert its revision equals INITIAL_REVISION + 1
(i.e., the document's revision was incremented). Locate this in the test body
after batch is built and add an assertion against the transition's revision
field on the DocumentReplaceTransition to prevent regressions in the
document.set_revision logic.

1161-1183: Negative-path tests are a bit permissive.

Both create_extended_from_document_buffer_invalid_type_fails and create_extended_from_document_buffer_bad_bytes_fails only assert is_err(). Since the two code paths produce distinctly shaped errors (InvalidDocumentTypeError vs. a deserialization error from Document::from_bytes), matching on the specific variant would better protect against future refactors silently collapsing them into a generic error.

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

In `@packages/rs-dpp/src/document/specialized_document_factory/v0/mod.rs` around
lines 1161 - 1183, Update the two tests so they assert the specific error
variants instead of only is_err(): in
create_extended_from_document_buffer_invalid_type_fails call
factory.create_extended_from_document_buffer and assert the error is the
InvalidDocumentTypeError variant (e.g., by pattern matching or using
assert_matches!), and in create_extended_from_document_buffer_bad_bytes_fails
assert that the error comes from the deserialization failure raised by
Document::from_bytes (match the deserialization/error variant returned by
create_extended_from_document_buffer). Use the actual enum/variant names
returned by the factory error type when matching to ensure the tests fail if the
error shape changes.

801-828: Test name promises more than it asserts.

create_document_uses_given_time_based_properties never checks that block_time (12345) or core_block_height (67) actually ended up on the document. As written this is really just "create works with non-zero block time". Consider asserting doc.created_at() / any core-height-derived field to match the test name, or rename to e.g. create_document_with_block_time_succeeds.

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

In `@packages/rs-dpp/src/document/specialized_document_factory/v0/mod.rs` around
lines 801 - 828, The test create_document_uses_given_time_based_properties
currently never verifies the supplied block_time/core_block_height; update the
test to assert that the document's time fields reflect the inputs by checking
doc.created_at() and doc.updated_at() equal Some(block_time) (or the concrete
return type used by Document) and also assert the core-height-derived field
(e.g., doc.core_height() or the specific getter used in this codebase) equals
core_block_height; if those accessors do not exist, either add the appropriate
getters or rename the test to create_document_with_block_time_succeeds to match
the current assertions.
packages/rs-dpp/src/identity/identity_factory.rs (2)

452-474: Good negative-path coverage for create_from_buffer.

Both the garbage-bytes and empty-buffer branches exercise the SerializedObjectParsingError mapping. Asserting result.is_err() is acceptable, but if you want to lock in the error shape (so a future refactor can't silently swallow the deserialization error into a different variant), matching on Err(ProtocolError::ConsensusError(...)) / BasicError::SerializedObjectParsingError would be stronger.

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

In `@packages/rs-dpp/src/identity/identity_factory.rs` around lines 452 - 474,
Update the two tests (create_from_buffer_fails_on_garbage and
create_from_buffer_fails_on_empty) to assert the specific error shape instead of
only is_err(); call IdentityFactory::create_from_buffer and match the returned
Result to
Err(ProtocolError::ConsensusError(BasicError::SerializedObjectParsingError(_)))
(or use matches!/assert_matches! to keep it concise), preserving the existing
#[cfg(feature = "validation")] argument; this locks the expectation to the
SerializedObjectParsingError variant wrapped in ProtocolError::ConsensusError so
future changes won't silently change the error type.

688-711: Revision assertion is coincidentally correct — make intent explicit.

create_identity_update_transition does identity.revision() + 1, so pre-seeding v0.revision = 5 and asserting update.revision() == 6 is fine. Consider adding a brief assertion on the starting revision (e.g. assert_eq!(identity.revision(), 5); before calling create_identity_update_transition) so a future change to IdentityV0::revision default or the +1 arithmetic fails loudly at the right spot rather than producing a confusing equality failure.

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

In `@packages/rs-dpp/src/identity/identity_factory.rs` around lines 688 - 711, Add
an explicit assertion of the identity's starting revision before calling
create_identity_update_transition so the test documents and locks the
precondition: after seeding v0.revision = 5, add assert_eq!(identity.revision(),
5); immediately before calling
IdentityFactory::create_identity_update_transition(identity, 33, ...), then keep
the existing check that update.revision() == 6; this makes the intent around
IdentityV0::revision and the +1 behavior explicit and fails closer to the root
if defaults change.
packages/rs-dpp/src/state_transition/mod.rs (1)

1808-1818: Consider also covering the error branch of deserialize_from_bytes_in_version.

The happy-path is covered, but the interesting branch (version not in active_version_range and protocol_version <= 268435456) only fires under all(feature = "state-transitions", feature = "validation"). A feature-gated negative test would close the real coverage gap on this function; as written, under configurations without both features, the function is effectively a thin wrapper.

🤖 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 1808 - 1818, Add a
feature-gated negative test that exercises
StateTransition::deserialize_from_bytes_in_version's error branch when the
provided protocol version is outside the active_version_range and
protocol_version <= 268435456; specifically, create a test (annotated with
#[cfg(all(feature = "state-transitions", feature = "validation"))]) that
serializes a sample StateTransition (e.g., sample_transfer_st()), mutates the
serialized bytes or the passed PlatformVersion to a version not included in
active_version_range, calls
StateTransition::deserialize_from_bytes_in_version(&bytes,
PlatformVersion::new(<small_or_invalid_version>)) and asserts that it returns
the expected error (rather than Ok), referencing the functions
StateTransition::deserialize_from_bytes_in_version, PlatformVersion, and the
active_version_range check so the test fails if the error branch is not taken.
🤖 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-drive-proof-verifier/src/proof.rs`:
- Around line 3310-3328: The test currently triggers a decode error path
(NoProofInResult) because it uses default platform::GetIdentityRequest/Response;
change the test to construct a response that successfully decodes but yields
None from maybe_from_proof so that Identity::from_proof maps that None to
Error::NotFound. Specifically, keep using Identity and the FromProof::from_proof
wrapper but replace the response (and/or request) so maybe_from_proof would
return Ok(None) (for example, a valid GetIdentityResponse with an empty
proof/result), then call <Identity as
FromProof<platform::GetIdentityRequest>>::from_proof(...) and assert that the
returned error matches Error::NotFound; keep provider as unreachable_provider(),
Network::Testnet and default_platform_version() unchanged.

---

Nitpick comments:
In `@packages/rs-dpp/src/data_contract/created_data_contract/mod.rs`:
- Around line 328-340: The test serialize_roundtrip_via_platform_version only
compares identity_nonce() and data_contract().id(), which can miss other mutated
fields; update the assertion to compare the whole CreatedDataContract using
PartialEq by replacing the two field-level asserts with a single
assert_eq!(restored, created) after versioned_deserialize (keep the same setup
using sample_created, serialize_to_bytes_with_platform_version, and
CreatedDataContract::versioned_deserialize to perform the round-trip).
- Around line 386-405: The test only asserts the returned nonce from
data_contract_and_identity_nonce_owned(); update it to also validate the
returned contract format: destructure as let (contract_fmt, nonce) =
decoded.data_contract_and_identity_nonce_owned(); then assert_eq!(nonce,
created.identity_nonce()) and assert_eq!(contract_fmt, created.data_contract())
(or the appropriate accessor on sample_created() that returns the expected
contract) so the contract payload is also verified; use
CreatedDataContractInSerializationFormat::data_contract_and_identity_nonce_owned(),
sample_created(), and created.identity_nonce() to locate the code to change.

In `@packages/rs-dpp/src/document/specialized_document_factory/v0/mod.rs`:
- Around line 930-954: The test
create_state_transition_replace_on_mutable_document_increments_revision
currently never checks the produced transition's revision; update the test to
extract the created transition from batch (the result of
factory.create_state_transition), cast/inspect it as a
DocumentReplaceTransition, and assert its revision equals INITIAL_REVISION + 1
(i.e., the document's revision was incremented). Locate this in the test body
after batch is built and add an assertion against the transition's revision
field on the DocumentReplaceTransition to prevent regressions in the
document.set_revision logic.
- Around line 1161-1183: Update the two tests so they assert the specific error
variants instead of only is_err(): in
create_extended_from_document_buffer_invalid_type_fails call
factory.create_extended_from_document_buffer and assert the error is the
InvalidDocumentTypeError variant (e.g., by pattern matching or using
assert_matches!), and in create_extended_from_document_buffer_bad_bytes_fails
assert that the error comes from the deserialization failure raised by
Document::from_bytes (match the deserialization/error variant returned by
create_extended_from_document_buffer). Use the actual enum/variant names
returned by the factory error type when matching to ensure the tests fail if the
error shape changes.
- Around line 801-828: The test create_document_uses_given_time_based_properties
currently never verifies the supplied block_time/core_block_height; update the
test to assert that the document's time fields reflect the inputs by checking
doc.created_at() and doc.updated_at() equal Some(block_time) (or the concrete
return type used by Document) and also assert the core-height-derived field
(e.g., doc.core_height() or the specific getter used in this codebase) equals
core_block_height; if those accessors do not exist, either add the appropriate
getters or rename the test to create_document_with_block_time_succeeds to match
the current assertions.

In `@packages/rs-dpp/src/identity/identity_factory.rs`:
- Around line 452-474: Update the two tests (create_from_buffer_fails_on_garbage
and create_from_buffer_fails_on_empty) to assert the specific error shape
instead of only is_err(); call IdentityFactory::create_from_buffer and match the
returned Result to
Err(ProtocolError::ConsensusError(BasicError::SerializedObjectParsingError(_)))
(or use matches!/assert_matches! to keep it concise), preserving the existing
#[cfg(feature = "validation")] argument; this locks the expectation to the
SerializedObjectParsingError variant wrapped in ProtocolError::ConsensusError so
future changes won't silently change the error type.
- Around line 688-711: Add an explicit assertion of the identity's starting
revision before calling create_identity_update_transition so the test documents
and locks the precondition: after seeding v0.revision = 5, add
assert_eq!(identity.revision(), 5); immediately before calling
IdentityFactory::create_identity_update_transition(identity, 33, ...), then keep
the existing check that update.revision() == 6; this makes the intent around
IdentityV0::revision and the +1 behavior explicit and fails closer to the root
if defaults change.

In `@packages/rs-dpp/src/identity/identity_public_key/purpose.rs`:
- Around line 223-236: Rename or clarify Purpose::full_range() to indicate it
excludes SYSTEM by either renaming the method (e.g., assignable_purposes() or
user_purposes()) or keeping the name but adding a doc comment explicitly stating
that SYSTEM is intentionally omitted; update any callers/tests (e.g., the
test_purpose_full_range_contents test and references to full_range()) to use the
new name or reflect the clarified behavior and ensure the doc comment mentions
that full_range()/assignable_purposes() returns the six purpose variants
(AUTHENTICATION, ENCRYPTION, DECRYPTION, TRANSFER, VOTING, OWNER) and excludes
SYSTEM which is system-internal only.

In `@packages/rs-dpp/src/identity/identity_public_key/v0/methods/mod.rs`:
- Around line 244-445: Extract a small test helper to avoid repeating the
IdentityPublicKeyV0 literal: add a function like key_with(key_type: KeyType,
data: Vec<u8>) -> IdentityPublicKeyV0 that constructs an IdentityPublicKeyV0
using the provided key_type and data (wrapping data with
platform_value::BinaryData::new) and fills the rest via ..Default::default();
then replace the repeated literals in tests like
test_public_key_hash_empty_data_errors,
test_public_key_hash_ecdsa_wrong_length_errors,
test_public_key_hash_bls_wrong_length_errors,
test_public_key_hash_bls_returns_ripemd160_sha256_of_data,
test_public_key_hash_ecdsa_hash160_returns_data_itself,
test_public_key_hash_bip13_script_hash_returns_data_itself,
test_public_key_hash_hash160_wrong_length_errors,
test_validate_private_key_bytes_bip13_script_hash_is_unsupported,
test_validate_private_key_bytes_ecdsa_secret_key_parse_error_returns_false, and
test_validate_private_key_bytes_ecdsa_hash160_secret_key_parse_error_returns_false
to call key_with(...) with the differing key_type and data.

In `@packages/rs-dpp/src/state_transition/mod.rs`:
- Around line 1808-1818: Add a feature-gated negative test that exercises
StateTransition::deserialize_from_bytes_in_version's error branch when the
provided protocol version is outside the active_version_range and
protocol_version <= 268435456; specifically, create a test (annotated with
#[cfg(all(feature = "state-transitions", feature = "validation"))]) that
serializes a sample StateTransition (e.g., sample_transfer_st()), mutates the
serialized bytes or the passed PlatformVersion to a version not included in
active_version_range, calls
StateTransition::deserialize_from_bytes_in_version(&bytes,
PlatformVersion::new(<small_or_invalid_version>)) and asserts that it returns
the expected error (rather than Ok), referencing the functions
StateTransition::deserialize_from_bytes_in_version, PlatformVersion, and the
active_version_range check so the test fails if the error branch is not taken.
🪄 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: b07eba3f-8e4f-4161-a0fc-9d3b9eea62c9

📥 Commits

Reviewing files that changed from the base of the PR and between 2e135bf and 55cad9f.

📒 Files selected for processing (10)
  • packages/rs-dpp/src/data_contract/created_data_contract/mod.rs
  • packages/rs-dpp/src/document/specialized_document_factory/v0/mod.rs
  • packages/rs-dpp/src/identity/identity_factory.rs
  • packages/rs-dpp/src/identity/identity_public_key/contract_bounds/mod.rs
  • packages/rs-dpp/src/identity/identity_public_key/mod.rs
  • packages/rs-dpp/src/identity/identity_public_key/purpose.rs
  • packages/rs-dpp/src/identity/identity_public_key/security_level.rs
  • packages/rs-dpp/src/identity/identity_public_key/v0/methods/mod.rs
  • packages/rs-dpp/src/state_transition/mod.rs
  • packages/rs-drive-proof-verifier/src/proof.rs

Comment thread packages/rs-drive-proof-verifier/src/proof.rs Outdated
Per CodeRabbit review: the old test used default request/response which
triggered NoProofInResult before the from_proof wrapper could map a real
Ok(None) to Error::NotFound — so it was actually testing decode-error
propagation, not the wrapper's None-to-NotFound logic.

Introduce a local MissingFromProof impl whose
maybe_from_proof_with_metadata returns Ok((None, ..)), and assert the
wrapper maps that to Error::NotFound.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@QuantumExplorer QuantumExplorer merged commit 9e338b8 into v3.1-dev Apr 21, 2026
38 checks passed
@QuantumExplorer QuantumExplorer deleted the test/coverage-proof-verifier-and-dpp-factories branch April 21, 2026 13:13
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