Skip to content

feat(dpp): consume and minimumAgeBlocks on any reference judged on the create alone - #5364

Closed
QuantumExplorer wants to merge 1 commit into
claude/wizardly-driscoll-44c981from
claude/consume-on-create-only-references
Closed

QuantumExplorer wants to merge 1 commit into
claude/wizardly-driscoll-44c981from
claude/consume-on-create-only-references

Conversation

@QuantumExplorer

Copy link
Copy Markdown
Member

Basic explanation

A document can point at another document and, when it is created, delete that document (consume) or require it to be old enough (minimumAgeBlocks). Until now that only worked for one kind of pointer: a commit-and-reveal hash. The real requirement was never the hash. It was that the pointer is only checked once, when the document is created, because a later edit would check it again and find the consumed document gone.

A document type whose documents can never be edited (documentsMutable: false) has exactly that property: nothing ever re-checks its pointers. This PR lets such types use consume and minimumAgeBlocks with any findBy, hash or not. It is the first prerequisite for DPNS name tombstones, where a tombstone consumes the name's domain.

Stacked on #5337.

Issue being fixed or feature implemented

consume and minimumAgeBlocks were refused unless the reference's findBy held a hash function. The reason, in DocumentReferenceLookup::is_checked_on_create_only, was that such a reference is judged on the create alone and never again. But a reference declared on a type whose documents are never replaced is judged on the create alone too: a replace is the one write that re-validates a reference (transfers, purchases, price updates, moderator field changes and restores never do, and changeFields may not name a property a reference reads).

What was done?

  • DocumentReferenceLookup::is_checked_on_create_only(documents_mutable): a computed key, or a declaring type whose documents are never replaced.
  • The refusal of minimumAgeBlocks and consume moves from parse_find_by, which has no document type, to validate_reference_lookup_sources (new age_or_consume_error), which runs on every parse once the type is known. Meta-schema v3 now only requires findBy beside either keyword.
  • The rules that follow from "judged on the create alone" follow the new definition:
    • a "$ownerId" findBy source on a transferable or tradeable referring type;
    • creatorRefersTo with a deletableDocument found by findBy;
    • the where and anyOf rule (create_only_leaf_error) and the immutable-property exception, both no-ops on an immutable type.
  • Two callers that meant "has a hash key" now say so (hash_key().is_some()): the string or byte array carrier, which still needs a function, and the repeated-key preimage refusal.
  • Reference validation 0 skips a create-only lookup on a replace by the new definition.
  • Meta-schema v3 descriptions, v14 note 61, the book (refers-to-lookup, documents, refers-to, contract-keywords) and the wasm-dpp2 TypeScript docs updated.

Before and after

A redemption that consumes the writer's voucher, found by its serial without a function:

"redemption": {
  "documentsMutable": false,
  "properties": {
    "voucherSerial": {
      "type": "identifier",
      "position": 0,
      "refersTo": {
        "type": "deletableDocument",
        "documentType": "voucher",
        "findBy": { "serial": "." },
        "where": { "$ownerId": "$ownerId" },
        "minimumAgeBlocks": 1,
        "consume": true
      }
    }
  },
  "required": ["voucherSerial"],
  "additionalProperties": false
}
  • Before: registration refused it ("refersTo minimumAgeBlocks and consume need a findBy function computing the key").
  • After: it registers; creating a redemption in a later block than the voucher deletes the voucher. The same declaration on a type with documentsMutable: true is still refused (10231): "the reference must be judged on the create alone: give findBy a function, or make the document type immutable".

In-place changes to shipped generations

  • Document reference validation 0 (binds_a_changed_property, validate_reference_target_v0): every protocol version selects it. Only lookups reach the changed lines, and only meta-schema v3 (protocol version 14) admits findBy, so nothing changes before 14. A replace never reaches either line for a type whose documents are never replaced (document replace advanced structure refuses it first), so the behaviour at 14 is unchanged too.
  • Meta-schema v3, parser generation 3 and v14 note 61 are edited in place; only protocol version 14, unreleased, selects them.

How Has This Been Tested?

  • dpp:
    • should_parse_age_and_consume_without_a_function_on_a_type_never_replaced;
    • should_refuse_age_and_consume_without_a_function_on_a_type_whose_documents_can_be_replaced (validating and stored-contract parses);
    • should_parse_a_deletable_creator_lookup_without_a_computed_key_on_a_type_never_replaced and its refused twin on a replaceable type;
    • the existing "without findBy" refusals kept.
  • drive-abci, through the full ABCI pipeline (commit_reveal_lookup.rs, a voucher / redemption fixture):
    • should_consume_a_document_a_plain_lookup_finds_on_a_type_never_replaced;
    • should_refuse_a_plain_lookup_redemption_in_the_block_of_its_voucher (40142);
    • should_refuse_redeeming_another_identitys_voucher_through_a_plain_lookup (40127).
  • Commands: cargo test -p dpp --lib, cargo test -p drive-abci --lib -- commit_reveal refers_to reference dpns document moderation, cargo clippy -p dpp -p drive-abci -p dash-sdk --all-targets, cargo check -p wasm-dpp2, cargo fmt --all -- --check.

Breaking Changes

None. Contracts that registered before still register; this only admits declarations that were refused.

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
  • If I added or changed GroveDB structure, I described it in the area's structure.rs, regenerated grovedb-structure.json, and checked the structure viewer link posted on this pull request

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

🤖 Generated with Claude Code

…e create alone

`consume` and `minimumAgeBlocks` needed a findBy function because only a
commit-and-reveal key was judged on the create alone. A reference on a
document type whose documents are never replaced (documentsMutable:
false) is judged on the create alone too: a replace is the one write that
re-validates a reference.

`DocumentReferenceLookup::is_checked_on_create_only(documents_mutable)`
covers both. The age and consume refusal moves from `parse_find_by`,
which has no document type, to `validate_reference_lookup_sources`
(`age_or_consume_error`); meta-schema v3 only requires findBy beside
either keyword. The `$ownerId` source rule, `creatorRefersTo` with a
deletable lookup and the create-only skips in reference validation 0
follow the new definition; the string carrier and the repeated-key
preimage refusal keep testing for a hash key. Docs: meta-schema v3, v14
note 61, the book and the wasm-dpp2 TypeScript docs.

Tests: dpp parses age and consume beside a plain findBy on an immutable
type and refuses them on a mutable one, both parses; creatorRefersTo the
same. drive-abci: a voucher/redemption contract consumes the voucher,
refuses a same-block redemption (40142) and another identity's (40127).

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

coderabbitai Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

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: Repository: dashpay/platform/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 6950b6dd-1032-4d61-a6de-a87f1ea421d8

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
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

📖 Book Preview built successfully.

Download the preview from the workflow artifacts.
To view locally: download the artifact, unzip, and open index.html.

Updated at 2026-10-09T15:23:25.102Z

@thepastaclaw

thepastaclaw commented Oct 9, 2026 •

Copy link
Copy Markdown
Collaborator

🔍 Review in progress — actively reviewing now (commit 467451a) · triage: critical
██████████████████░░ 89% · taking longer than usual · running for 47 min
✅ triage → ⏳ Phase 1 (1/2 lanes) → ✅ Phase 2 → ▫️ verify 2 → ▫️ publish
Estimated from recent reviews of this tier · updated 16:39 UTC · live progress

@QuantumExplorer

Copy link
Copy Markdown
Member Author

Replaced by #5365, which carries the same change based directly on v5.0-dev instead of stacked on #5337.

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