Skip to content

fix(platform)!: a preallocated agreement source must fit a tree key (PV14) - #5123

Merged
QuantumExplorer merged 1 commit into
v4.2-devfrom
claude/preallocated-agreement-source-fits-key
Sep 28, 2026
Merged

QuantumExplorer merged 1 commit into
v4.2-devfrom
claude/preallocated-agreement-source-fits-key

Conversation

@QuantumExplorer

@QuantumExplorer QuantumExplorer commented Sep 28, 2026 •

Copy link
Copy Markdown
Member

Basic explanation

What this does: A refersTo reference can declare a propertyAgreement, for example "a like must carry the same hashtag as the post it likes". A preallocated index on the like type makes Platform create the like's index trees as soon as the post is created, keyed by the post's hashtag. An index key holds at most 255 bytes. If the post's hashtag could be longer than that, those trees could not be made, and creating a post failed with an internal error. The contract still registered, so a post type could end up where no tagged post could ever be created.

From protocol version 14 such a contract, or a contract update that adds such an index, is refused at registration with a clear error. Drive also stops failing on a contract of that shape that already exists: it sizes the cost estimate from the like's hashtag, and it creates no trees for a post value that no like could ever carry.

This was split out of #5102, which keeps the other half: agreement pairs compare values instead of index keys.

Example:

Before After
A contract whose agreement source post.hashtag is a string of up to 280 characters, bound to a like's preallocated byHashtagPost registers, then no post carrying a hashtag can be created: InternalError("fee: overflow error: referenced document field is too big for being an index") refused at registration (create or update) with ReferencedDocumentPropertyAgreementInvalidError (40126), naming the index
The same contract, applied before this check existed post creates fail as above posts are created; one whose hashtag is wider than a like's gets no byHashtagPost trees
The same contract with post.hashtag at maxLength 63 (252 bytes) registers, posts and likes are created unchanged

Value: A contract author who binds a preallocated index to a property that is too wide finds out when registering, instead of after the post type has stopped working for good.

Risks: Consensus change at protocol version 14, which is not on mainnet or testnet. Replaying devnet history that contains such contracts gives different results: a contract that registered with a too-wide preallocated agreement source is refused, and the preallocation estimate for an agreement-keyed level changes (it feeds the balance pre-check). The drive-abci module edited in place is listed at older protocol versions too; the section below says why the edit cannot run there.

Issue being fixed or feature implemented

A preallocated index keyed by an agreement source wider than any tree key (from #4509). Take post.hashtag with maxLength 280 and no index, and an indexOnly like whose preallocated byHashtagPost index is keyed through propertyAgreement { hashtag: hashtag }, with like.hashtag at maxLength 63. The contract registers. Creating a post then preallocates the like trees:

  • The cost estimate (validate_fees_of_event runs the insert with apply = false) sized the hashtag level from the referenced property's midway size, 2 × (minLength + maxLength) bytes for a string, 562 here, and returned FeeError::Overflow above 255. Every post carrying a hashtag failed, however short.
  • The insert itself encoded the post's actual value as a key, which fails above 255 bytes.

Contract registration (data_contract_reference_validation v0) never looked at the size. A contract update adding like to a live contract with post did the same to an existing type.

What was done?

  • data_contract_reference_validation v0 refuses, with 40126, an agreement pair through which a preallocated index of the declaring type is keyed (found with the same Index::preallocation_bindings the insert uses) when the referenced property's saturating_max_byte_size is above MAX_INDEX_SIZE. This runs on contract create and update. Agreements that key no preallocated index are not bounded: their values are never tree keys.
  • Drive preallocation (add_preallocated_index_tree_operations, reached only from add_document_for_contract_operations 1, which only DRIVE_DOCUMENT_METHOD_VERSIONS_V4, protocol version 14, selects):
    • The estimate for an agreement-keyed level is sized from the referring index property, exactly as an entry insert sizes the same level, instead of from the referenced property. Estimation without a document sizes the key the same way.
    • With a document in hand, a referenced value whose key would be wider than the referring property's max_byte_size is not preallocated, as an absent or null value already is: no referring document could ever agree with it.
    • The binding helper takes the referring DocumentTypeRef instead of its name and index structure, which also drops a second lookup of the type by name.
  • PV14 note 55 in packages/rs-platform-version/src/version/v14.rs.
  • The book (contract-keywords/refers-to.md, contract-keywords/index-only.md) states the new registration rule and the skipped preallocation.

Before and after, for the preallocated fixture with post.hashtag up to 280 characters:

DataContractCreate (or a DataContractUpdate adding `like` to a contract holding `post`)
  before: SuccessfulExecution, then every post create carrying a hashtag:
          InternalError("fee: overflow error: referenced document field is too big for being an index")
  after:  PaidConsensusError ReferencedDocumentPropertyAgreementInvalidError (40126):
          "the preallocated index byHashtagPost keys its trees by the referenced property's value,
           and a tree key holds at most 255 bytes, but the referenced property can hold values of
           up to 1120 bytes"

the same contract applied before this check existed
  before: post create InternalError, as above
  after:  posts are created; one whose hashtag is wider than a like's gets no byHashtagPost trees

With post.hashtag at maxLength 63 (252 bytes) the contract registers and posts and likes are created, before and after.

In-place changes to shipped generations

  • data_contract_reference_validation 0 (drive-abci) is listed by every DRIVE_ABCI_VALIDATION_VERSIONS_* table, including V9 at protocol version 13, but it is called only from contract create and update state validation 1, which only DRIVE_ABCI_VALIDATION_VERSIONS_V10 (protocol version 14) selects. Protocol versions 1 to 13 run state validation 0, which never calls it, so the new check cannot run there. preallocated itself only parses from meta-schema v3, also protocol version 14. The existing in-place comments of this module make the same argument, and the new check carries one.
  • The Drive preallocation code is not a shipped generation: add_preallocated_index_tree_operations_for_referring_types is called only from add_document_for_contract_operations 1, which only DRIVE_DOCUMENT_METHOD_VERSIONS_V4 (DRIVE_VERSION_V9, protocol version 14) selects.

How Has This Been Tested?

The code and tests come unchanged from #5102. Two batch tests moved into their own file, and two contract-create tests moved a few tests down in the same module, so that this pull request and #5102 do not touch the same lines. All test names start with should_:

  • drive-abci, batch/tests/document/preallocated_agreement_source.rs (full ABCI pipeline):
    • should_create_posts_and_likes_when_the_agreement_source_fits_a_tree_key: maxLength 63, including a 63-emoji hashtag.
    • should_create_posts_under_an_agreement_source_wider_than_a_tree_key: a too-wide contract applied directly, as one registered before this check would be; a 70-emoji post and a short-hashtag post with its like are created.
  • drive-abci, contract create: should_reject_an_agreement_keying_a_preallocated_index_by_a_property_wider_than_a_tree_key, should_register_an_agreement_keying_a_preallocated_index_by_a_property_that_fits_a_tree_key. Contract update: should_reject_contract_update_keying_a_preallocated_index_by_a_property_wider_than_a_tree_key.
  • drive: should_skip_preallocation_for_a_bound_value_wider_than_the_referring_property (the estimate and the insert of a 280-byte-hashtag post succeed, the estimate upper-bounds the applied storage fee, no byHashtagPost trees, byPost still preallocated, a short hashtag still preallocated), and should_size_an_agreement_bound_layer_as_the_referring_property (the estimated layer is 128 bytes, from like.hashtag).

None of these tests depends on #5102's value comparison: every agreement they exercise holds under the old key comparison too.

For this split no cargo build or test was run locally, because the build machine is short on disk, so this pull request relies on CI. Checked locally: git diff --check, rustfmt --edition 2021 --check on every touched Rust file, the three JSON fixtures parse, and a trial merge of this branch with the trimmed #5102 is clean and gives back #5102's original code.

Breaking Changes

Consensus change at protocol version 14 (unreleased), PV14 note 55. At protocol version 14 a contract create or update is refused with ReferencedDocumentPropertyAgreementInvalidError (40126) when a preallocated index is keyed through an agreement whose referenced property can hold more than 255 bytes, and the preallocation estimate for an agreement-keyed level is sized from the referring property. Protocol versions 1 to 13 are unchanged.

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

PR Hygiene · 29ccb40

  • Bots — coderabbitai not yet · thepastaclaw not yet — /skip-bots proceeds without the ones not yet reported
  • Self-review — post /self-reviewed once the bots are done
  • Within your 5 open PRs
  • Build running
  • Approvals — you own every area touched; none needed

When every box is checked the PR Hygiene check passes and this can merge.

Summary by CodeRabbit

  • Bug Fixes
    • Preallocated indexes now skip creating trees when a referenced value exceeds the referring property’s supported size. Other eligible index trees can still be created.
    • Contract creation and updates now reject property agreements that use unknown or oversized values as preallocated index keys, with a validation error.
  • Documentation
    • Clarified the 255-byte limit for preallocated index keys and the existing restriction on combining preallocation with time ranges.

…PV14)

A preallocated index keyed through a refersTo propertyAgreement writes
the referenced document's value as a tree key when that document is
created. When the referenced property could hold more than 255 bytes,
the contract registered, and then every create of a referenced document
carrying the value failed with an internal error (the estimate sized
the layer from the referenced property's midway size).

Contract create and update state validation 1 now refuse such a pair,
paid, with ReferencedDocumentPropertyAgreementInvalidError (40126).
Drive sizes the preallocated layer from the referring index property,
as an entry insert does, and preallocates nothing for a referenced
value wider than the referring property can hold, so a contract of
that shape applied before the check still takes documents.

PV14 note 55. Split out of #5102, which keeps the value comparison of
agreement pairs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added this to the v4.2.0 milestone Sep 28, 2026
@github-actions

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-09-28T11:57:43.663Z

@github-actions github-actions Bot added the waiting-bots Waiting for the review bots to report on this head label Sep 28, 2026
@coderabbitai

coderabbitai Bot commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: Repository: dashpay/platform/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 76d24c2f-9c58-4e1e-b08a-75f98d278968

📥 Commits

Reviewing files that changed from the base of the PR and between 7799497 and 29ccb40.

📒 Files selected for processing (14)
  • book/src/contract-keywords/index-only.md
  • book/src/contract-keywords/refers-to.md
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/preallocated_agreement_source.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_common/data_contract_reference_validation/v0/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/mod.rs
  • packages/rs-drive-abci/tests/supporting_files/contract/reference-validation/reference-validation-contract-agreement-preallocated-fits.json
  • packages/rs-drive-abci/tests/supporting_files/contract/reference-validation/reference-validation-contract-agreement-preallocated-too-wide-update-v1.json
  • packages/rs-drive-abci/tests/supporting_files/contract/reference-validation/reference-validation-contract-agreement-preallocated-too-wide.json
  • packages/rs-drive/src/drive/contract/insert/insert_contract/v0/tests/preallocated_index_e2e_tests.rs
  • packages/rs-drive/src/drive/document/insert/add_preallocated_index_tree_operations/mod.rs
  • packages/rs-drive/src/drive/document/insert/add_preallocated_index_tree_operations/tests.rs
  • packages/rs-platform-version/src/version/v14.rs
 _______________________________________________________________________________________________________
< Make it easy to reuse. If it's easy to reuse, people will. Create an environment that supports reuse. >
 -------------------------------------------------------------------------------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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.

QuantumExplorer added a commit that referenced this pull request Sep 28, 2026


This pull request now only makes propertyAgreement pairs compare values
instead of index keys. The registration rule that a preallocated
index's agreement source fits a tree key, and the Drive preallocation
changes that go with it, move unchanged to #5123 with their tests and
fixtures.

The PV14 note is renumbered from 53, which #5099 took on v4.2-dev, to
56 (54 is claimed by an open pull request, 55 by #5123), and now covers
only the comparison.

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

thepastaclaw commented Sep 28, 2026 •

Copy link
Copy Markdown
Collaborator

🕓 Queued for automated review — 3rd in line, estimated start in ~25 min (commit 29ccb40)
Estimated review time once started: ~50 min (two-phase automated review; median of recent runs).

  • Request priority review — click to move this review to the front of the queue.

@QuantumExplorer QuantumExplorer left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Approved

@QuantumExplorer
QuantumExplorer merged commit 812d630 into v4.2-dev Sep 28, 2026
20 of 23 checks passed
@QuantumExplorer
QuantumExplorer deleted the claude/preallocated-agreement-source-fits-key branch September 28, 2026 12:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

waiting-bots Waiting for the review bots to report on this head

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants