You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A document type that sets both documentsKeepHistory: true and canBeDeleted: true is self-contradictory: rs-drive unconditionally refuses to delete a document whose type keeps history, so canBeDeleted: true advertises a capability the storage layer will always reject.
The contradiction should be caught at the earliest possible point:
Contract creation — validation should reject a document type that sets both documentsKeepHistory: true and canBeDeleted: true, so the bad contract can never be deployed. (Mirrors the existing cross-flag rule ContestedUniqueIndexOnMutableDocumentTypeError.)
Delete state transition — even for already-deployed contracts, a delete targeting a keep-history document type should be rejected up front by the delete-transition structure validator as a normal invalid (paid) state transition, with a clear consensus error.
In both cases an SDK user should get an immediate, legible error instead of the delete failing as an internal error.
Current Behavior
Nothing catches the contradiction up front, and the delete fails as an internal error rather than a clean rejection:
Contract creation accepts the combination.DocumentType::try_from_schema parses documentsKeepHistory: true + canBeDeleted: true with no error. There is no cross-flag validation for this pair. (Live example: testnet contract 5CBPiadGmx3Zsjc26g5onopcx7pdxHPbrRAUD2T2yAbC, document type note, has all of documentsMutable, documentsKeepHistory, and canBeDeleted set to true.)
The delete-transition structure validator does not check documents_keep_history(). It only checks documents_can_be_deleted() (document_delete_transition_action/advanced_structure_v0/mod.rs), so the delete passes broadcast/structure validation.
At execution, Drive refuses the delete with a DriveError, not a consensus error.force_delete_document_for_contract_operations_v0 returns DriveError::InvalidDeletionOfDocumentThatKeepsHistory when documents_keep_history() is true. In the rs-drive-abci processing path this surfaces as ExecutionResult::InternalError — the transition is classified as neither valid nor invalid (valid_count == 0, invalid_paid_count == 0).
An internal error means "the node failed to process this", not "this transition is invalid". This is the wrong classification for what is really an invalid transition, and it offers no clean consensus accept/reject for a client to act on.
Observed processing-result classification for the doomed delete (from the reproduction test below):
valid=0 invalid_paid=0 invalid_unpaid=0
result[0]: InternalError("storage: drive: invalid deletion of document that keeps history error: this document type keeps history and therefore can not be deleted")
Possible Solution
Add guards at both upper layers:
rs-dpp — DocumentType::try_from_schema: reject documents_keep_history && documents_can_be_deleted in the flag-parsing region, next to the existing ContestedUniqueIndexOnMutableDocumentTypeError cross-flag check. (This is a consensus/validation change and cannot retroactively fix already-deployed contracts.)
rs-drive-abci — delete-transition structure validator: add a documents_keep_history() check beside the existing documents_can_be_deleted() check in document_delete_transition_action/advanced_structure_v0/mod.rs, returning a consensus error so a delete against a keep-history type becomes a normal invalid (paid) transition instead of an internal error. This fixes the classification even for contracts that already exist on-chain.
Together: (1) prevents new contradictory contracts; (2) makes any already-deployed contradictory contract fail fast and legibly as an invalid transition.
Steps to Reproduce (for bugs)
Register (or use the existing testnet) data contract with a document type setting both documentsKeepHistory: true and canBeDeleted: true — e.g. testnet contract 5CBPiadGmx3Zsjc26g5onopcx7pdxHPbrRAUD2T2yAbC, document type note. Contract creation succeeds (it should be rejected).
Create a document of that type. Succeeds.
Submit a delete state transition for that document. It passes structure validation.
At execution, Drive refuses it with InvalidDeletionOfDocumentThatKeepsHistory, surfaced as ExecutionResult::InternalError — valid_count == 0 and invalid_paid_count == 0. The transition is neither committed nor cleanly rejected as invalid.
Reproduced end-to-end against testnet via @dashevo/evo-sdk (sdk.documents.create then sdk.documents.delete against the contract above; the delete returns the InvalidDeletionOfDocumentThatKeepsHistory error), and in-process by failing tests that pin both layers:
packages/rs-dpp/.../try_from_schema/v2/mod.rs: doctype_keep_history_with_can_be_deleted_rejected (fails today) and doctype_keep_history_with_can_be_deleted_false_accepted (passes — guards against an over-broad fix).
packages/rs-drive-abci/.../batch/tests/document/deletion.rs: test_document_delete_on_document_type_that_keeps_history_is_rejected (fails today), with fixture tests/supporting_files/contract/note/note-contract-keep-history-and-can-be-deleted.json.
Context
An SDK user can build and deploy a contract whose schema declares its documents deletable, then find that deletes for that type fail with an internal error rather than a clean, actionable rejection. The contradiction is invisible until runtime and offers no feedback at the point where it could be fixed (contract creation). Catching it early turns a confusing internal-error failure into an immediate validation error naming the conflicting flags.
Your Environment
Version used: branch v3.1-dev; reproduced at PlatformVersion::latest() (protocol version 12, try_from_schema v2). Drive-layer guard present since at least the InvalidDeletionOfDocumentThatKeepsHistory test (PR test(drive): improve document module test coverage #3333).
Environment name and version (e.g. Chrome 39, node.js 5.4): node.js 22.22; @dashevo/evo-sdk 4.0.0-rc.2
Operating System and version (desktop, server, or mobile): Linux (testnet)
Link to your project: testnet contract 5CBPiadGmx3Zsjc26g5onopcx7pdxHPbrRAUD2T2yAbC (document type note)
Expected Behavior
A document type that sets both
documentsKeepHistory: trueandcanBeDeleted: trueis self-contradictory: rs-drive unconditionally refuses to delete a document whose type keeps history, socanBeDeleted: trueadvertises a capability the storage layer will always reject.The contradiction should be caught at the earliest possible point:
documentsKeepHistory: trueandcanBeDeleted: true, so the bad contract can never be deployed. (Mirrors the existing cross-flag ruleContestedUniqueIndexOnMutableDocumentTypeError.)In both cases an SDK user should get an immediate, legible error instead of the delete failing as an internal error.
Current Behavior
Nothing catches the contradiction up front, and the delete fails as an internal error rather than a clean rejection:
DocumentType::try_from_schemaparsesdocumentsKeepHistory: true+canBeDeleted: truewith no error. There is no cross-flag validation for this pair. (Live example: testnet contract5CBPiadGmx3Zsjc26g5onopcx7pdxHPbrRAUD2T2yAbC, document typenote, has all ofdocumentsMutable,documentsKeepHistory, andcanBeDeletedset totrue.)documents_keep_history(). It only checksdocuments_can_be_deleted()(document_delete_transition_action/advanced_structure_v0/mod.rs), so the delete passes broadcast/structure validation.DriveError, not a consensus error.force_delete_document_for_contract_operations_v0returnsDriveError::InvalidDeletionOfDocumentThatKeepsHistorywhendocuments_keep_history()is true. In the rs-drive-abci processing path this surfaces asExecutionResult::InternalError— the transition is classified as neither valid nor invalid (valid_count == 0,invalid_paid_count == 0).An internal error means "the node failed to process this", not "this transition is invalid". This is the wrong classification for what is really an invalid transition, and it offers no clean consensus accept/reject for a client to act on.
Observed processing-result classification for the doomed delete (from the reproduction test below):
Possible Solution
Add guards at both upper layers:
DocumentType::try_from_schema: rejectdocuments_keep_history && documents_can_be_deletedin the flag-parsing region, next to the existingContestedUniqueIndexOnMutableDocumentTypeErrorcross-flag check. (This is a consensus/validation change and cannot retroactively fix already-deployed contracts.)documents_keep_history()check beside the existingdocuments_can_be_deleted()check indocument_delete_transition_action/advanced_structure_v0/mod.rs, returning a consensus error so a delete against a keep-history type becomes a normal invalid (paid) transition instead of an internal error. This fixes the classification even for contracts that already exist on-chain.Together: (1) prevents new contradictory contracts; (2) makes any already-deployed contradictory contract fail fast and legibly as an invalid transition.
Steps to Reproduce (for bugs)
documentsKeepHistory: trueandcanBeDeleted: true— e.g. testnet contract5CBPiadGmx3Zsjc26g5onopcx7pdxHPbrRAUD2T2yAbC, document typenote. Contract creation succeeds (it should be rejected).InvalidDeletionOfDocumentThatKeepsHistory, surfaced asExecutionResult::InternalError—valid_count == 0andinvalid_paid_count == 0. The transition is neither committed nor cleanly rejected as invalid.Reproduced end-to-end against testnet via
@dashevo/evo-sdk(sdk.documents.createthensdk.documents.deleteagainst the contract above; the delete returns theInvalidDeletionOfDocumentThatKeepsHistoryerror), and in-process by failing tests that pin both layers:packages/rs-dpp/.../try_from_schema/v2/mod.rs:doctype_keep_history_with_can_be_deleted_rejected(fails today) anddoctype_keep_history_with_can_be_deleted_false_accepted(passes — guards against an over-broad fix).packages/rs-drive-abci/.../batch/tests/document/deletion.rs:test_document_delete_on_document_type_that_keeps_history_is_rejected(fails today), with fixturetests/supporting_files/contract/note/note-contract-keep-history-and-can-be-deleted.json.Context
An SDK user can build and deploy a contract whose schema declares its documents deletable, then find that deletes for that type fail with an internal error rather than a clean, actionable rejection. The contradiction is invisible until runtime and offers no feedback at the point where it could be fixed (contract creation). Catching it early turns a confusing internal-error failure into an immediate validation error naming the conflicting flags.
Your Environment
v3.1-dev; reproduced atPlatformVersion::latest()(protocol version 12,try_from_schemav2). Drive-layer guard present since at least theInvalidDeletionOfDocumentThatKeepsHistorytest (PR test(drive): improve document module test coverage #3333).@dashevo/evo-sdk4.0.0-rc.25CBPiadGmx3Zsjc26g5onopcx7pdxHPbrRAUD2T2yAbC(document typenote)