Skip to content

test(dpp,drive-abci): pin keepHistory + canBeDeleted contradiction#3928

Draft
thephez wants to merge 2 commits into
dashpay:v3.1-devfrom
thephez:test/doc-history-deletion
Draft

test(dpp,drive-abci): pin keepHistory + canBeDeleted contradiction#3928
thephez wants to merge 2 commits into
dashpay:v3.1-devfrom
thephez:test/doc-history-deletion

Conversation

@thephez

@thephez thephez commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Issue being fixed or feature implemented

Reproduces #3927. A document type can set both documentsKeepHistory: true and canBeDeleted: true, but rs-drive unconditionally refuses to delete a document whose type keeps history — so canBeDeleted: true advertises a capability the storage layer always rejects. Nothing catches this contradiction up front: contract creation accepts it, the delete-transition structure validator only checks documents_can_be_deleted() (not documents_keep_history()), and the delete fails deep in Drive as an ExecutionResult::InternalError (neither valid nor invalid) instead of a clean rejection.

This PR adds failing tests that pin the bug and mark exactly where each guard belongs. It does not include the fix — it's a red-test reproduction to anchor the follow-up.

What was done?

Added failing tests across the three layers where the contradiction should be caught but currently isn't, plus passing companions so a future guard can't be over-broad.

Contract creation — rs-dpp try_from_schema/v2/mod.rs:

  • doctype_keep_history_with_can_be_deleted_rejected: explicit documentsKeepHistory: true + canBeDeleted: true on the document schema must be rejected, naming both flags (fails today).
  • Inherited/default-flag variants — because canBeDeleted defaults to true, a type that only sets documentsKeepHistory: true still hits the contradiction. These pin that the guard must inspect the resolved booleans, not just the raw schema keys: doctype_keep_history_with_can_be_deleted_inherited_from_defaults_rejected (both from contract defaults), doctype_keep_history_default_with_explicit_can_be_deleted_rejected and doctype_explicit_keep_history_with_can_be_deleted_default_rejected (each one-sided mix). All fail today.
  • doctype_keep_history_with_can_be_deleted_false_accepted: keepHistory + canBeDeleted: false stays valid (passes — over-broad guard rejected).

Local transition build — rs-dpp document factories:

  • DocumentFactoryV0 (delete_keep_history_document_is_rejected_locally) and SpecializedDocumentFactoryV0 (create_state_transition_delete_with_keep_history_document_returns_error) must reject a delete transition for a keep-history document type locally, before it can be signed and broadcast (fail today). This is the layer the SDK-side fix would surface at.

Node delete validation — rs-drive-abci batch/tests/document/deletion.rs:

  • test_document_delete_on_document_type_that_keeps_history_is_rejected asserts the delete is refused up front as an invalid (paid) transition, mirroring the existing can_not_be_deleted test (fails today; the doomed delete is currently classified as an internal error).
  • Parametrized so an inherited-defaults variant (...inherits_keep_history_and_can_be_deleted...) runs the same path against a contract whose flags come from config defaults — the structure validator only sees the resolved DocumentTypeRef, so the guard must cover this too.
  • Fixtures tests/supporting_files/contract/note/note-contract-keep-history-and-can-be-deleted.json (explicit flags, mirroring live testnet contract 5CBPiadGmx3Zsjc26g5onopcx7pdxHPbrRAUD2T2yAbC note type) and ...-by-default.json (flags from contract defaults).

Suggested fix (separate PR): reject the resolved flag combination in DocumentType::try_from_schema, reject the delete in the DPP document factories / SDK before broadcast, and add a documents_keep_history() check next to the documents_can_be_deleted() check in the delete-transition structure validator.

How Has This Been Tested?

Run at PlatformVersion::latest():

  • cargo test -p dpp --lib keep_history — the six rejection tests above fail as intended; the passing companions and unrelated keep-history tests stay green (no regressions).
  • cargo test -p drive-abci --lib keep_history — the keep-history delete tests fail on the invalid_paid_count == 1 assertion, confirming the delete is not rejected at validation today.

Also reproduced end-to-end against testnet via @dashevo/evo-sdk (documents.create then documents.delete against the contract above; the delete returns InvalidDeletionOfDocumentThatKeepsHistory).

Note: this PR is intentionally red — the new tests fail until the guards land (tracked in #3927).

Breaking Changes

None — tests and test fixtures 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

Add failing tests reproducing a contradictory document-type config that nothing currently catches up front: documentsKeepHistory: true together with canBeDeleted: true. rs-drive unconditionally refuses deleting a keep-history document, so canBeDeleted: true advertises a capability the storage layer always rejects.

The dpp tests assert contract creation should reject the combination (and that keepHistory + canBeDeleted: false stays valid), pinning the missing guard to the try_from_schema flag-parsing region.

The drive-abci test asserts the delete transition should be refused up front as an invalid (paid) transition. It fails because the delete-transition structure validator only checks documents_can_be_deleted(), so the doomed delete passes validation and the Drive-layer InvalidDeletionOfDocumentThatKeepsHistory surfaces as an ExecutionResult::InternalError (neither valid nor invalid) — the root of the "delete hangs on the network" symptom.

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

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 00a77681-6748-44e3-8227-13617f6d80b4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

…pHistory + canBeDeleted

Extend the keepHistory + canBeDeleted reproduction beyond explicit document-schema flags.

Add contract-default cases to the dpp try_from_schema tests: both flags inherited from contract defaults, and each one-sided mix (one explicit, one inherited). canBeDeleted defaults to true, so a type that only sets documentsKeepHistory: true still hits the contradiction — the guard must inspect the resolved booleans, not the raw schema keys. Refactor the existing tests onto basic_message_schema / parse_with_config helpers.

Add a third layer: DocumentFactoryV0 and SpecializedDocumentFactoryV0 must reject a delete transition for a keep-history document type locally, before it can be signed and broadcast.

Parametrize the drive-abci delete test and add an inherited-defaults variant with a matching fixture, so the structure validator path is covered for resolved (not just explicit) flags.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant