Skip to content

fix(platform)!: register the version 14 system contracts without storage flags - #4956

Merged
QuantumExplorer merged 3 commits into
v4.2-devfrom
fix/charter-contested-index-structure
Sep 24, 2026
Merged

QuantumExplorer merged 3 commits into
v4.2-devfrom
fix/charter-contested-index-structure

Conversation

@QuantumExplorer

@QuantumExplorer QuantumExplorer commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

Since #4898 (moderation charters system data contract, 58bfae8) merged, two drive-abci strategy tests fail the GroveDB structure conformance check on v4.2-dev:

cargo test -p drive-abci --test strategy_tests -- run_chain_v13_to_v14_registers_the_app_connect_contract run_chain_reopened_drive_at_epoch_boundary_locks_in_the_same_version_as_a_warm_node

Both panic in packages/rs-drive/src/structure/conformance.rs:146:

GroveDB differs from the structure description:
  - `votes.contested_resource.active_polls.contract` in [0x70, 0x63, 0x70] carries EpochOwned flags, expected one of [None]
  - `votes.contested_resource.active_polls.contract.document_type` in [.., 0xc506e6...f881] carries EpochOwned flags, expected one of [None]
  - `...document_type.storage` and `...document_type.indexes` under 'electedCharter' carry EpochOwned flags, expected one of [None]

CI did not show this at first because nextest stopped at an earlier failure in moderation-charters-contract.

Cause: the upgrade to 14 gave two system contracts storage flags

Genesis stores system contracts without storage flags. The protocol upgrades that add a system contract use insert_contract instead. It gives the contract, and every tree created with it, the contract's storage flags (EpochOwned) whenever the contract is not read only. System contracts are loaded with the default config, which is not read only. None of them can be deleted, since no contract can.

  • Upgrades 6, 9 and 13 registered wallet utils, token history, keyword search and document history this way. On every chain that went through those upgrades, these four carry flags owned by the all-zero system owner.
  • The upgrade to 14 did the same for app-connect and moderation charters. The charter contract is the first of these with a contested index. So its electedCharter trees under votes / contested_resource / active_polls got flags, where the description expects none.

System contracts should not carry flags. Their owner is the all-zero id, which no identity holds, and nothing deletes them, so no refund can ever be paid from those flags. The flags also meant a chain upgraded to 14 stored the two contracts differently from a chain born at 14.

What was done?

  • transition_to_version_14 now registers app-connect and moderation charters through apply_contract with storage_flags: None, the way genesis stores system contracts, instead of insert_contract. A comment says why.
  • New test should_store_the_version_14_system_contracts_as_a_chain_born_at_14_does. It upgrades a chain born at 13 to 14, then compares it with a chain born at 14. The contract elements of both contracts, and of the charter contract under the active polls, carry no flags and are equal on the two chains. Every tree below them is byte-identical (collect_subtree_diffs).
  • The structure description keeps admitting exactly what it admitted before. The contract and document areas now share one CONTRACT_FLAGS note instead of three differently worded copies. The note names who carries the flags: only the four system contracts upgrades 6, 9 and 13 registered. Genesis, state transitions and later upgrades write none. grovedb-structure.json is regenerated; only that note changes.

Earlier commits on this branch made the description accept the flags instead. The last commit takes that back and fixes the upgrade, so please squash.

Before / after

Before, on a chain upgraded from 13 to 14, the charter contract's poll trees carry EpochOwned flags, and the two strategy tests fail with the violations above. The new test fails on the old code:

assertion `left == right` failed: AppConnect is stored without storage flags under [[64]]
  left: Some([2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
 right: None

Those bytes are SingleEpochOwned storage flags: the all-zero owner, epoch 1.

After, both contracts are stored without flags and match a chain born at 14 byte for byte. The strategy tests pass against the unchanged description.

In-place changes to shipped generations

perform_events_on_first_block_of_protocol_change v0 is a shipped generation, and the change is inside it. The edit is in transition_to_version_14, which runs only when previous_protocol_version < 14 && platform_version.protocol_version >= 14. No released binary runs protocol version 14, so no chain built from a release has executed that function. The edit cannot change consensus at any shipped protocol version.

How Has This Been Tested?

  • cargo test -p drive-abci --lib -- version_14 app_connect_registration test_idempotent_transition: 35 passed. That covers the new test, the existing app-connect and moderation charters registration tests, the other transition_to_version_14 tests, the genesis v1 registration tests and the dispatcher rollback-and-retry test. With insert_contract put back, the new test fails as shown above.
  • cargo test -p drive-abci --test strategy_tests -- upgrade_fork_tests: 4 passed (4 #[ignore] upstream), including run_chain_v13_to_v14_registers_the_app_connect_contract and run_chain_reopened_drive_at_epoch_boundary_locks_in_the_same_version_as_a_warm_node, against the unchanged description.
  • cargo test -p drive --lib structure::tests: 11 passed, with grovedb-structure.json regenerated.

Breaking Changes

Consensus at protocol version 14, which is unreleased. The block that activates 14 now stores app-connect and moderation charters without flags. Its app hash therefore differs from what earlier v4.2-dev builds compute for the same upgrade. A devnet that already upgraded from 13 to 14 on such a build cannot be replayed with this one. Chains born at 14 are unaffected, since genesis already stored both contracts without flags.

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 · fb4981d

  • 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 failed
  • Approvals — you own every area touched; none needed

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

…poll trees

insert_contract gives every tree it creates with a contract the contract's
storage flags (EpochOwned with the contract owner when the contract can be
deleted or is not read only), including the contract, document type,
storage and indexes trees under votes/contested_resource/active_polls.
Genesis and the contract create/update transitions store contracts with no
flags, so these trees only carry flags when a protocol upgrade registers a
system contract with a contested index. The moderation charters contract,
registered on the first block of protocol version 14, is the first, and
its electedCharter trees failed the conformance check in the v13 to v14
strategy tests.

The contracts side of the description already admits [EpochOwned, None]
for trees created with a contract; the four poll trees now do too. A new
structure fixture stores a contested contract through insert_contract and
asserts the flags, and grovedb-structure.json is regenerated.

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

coderabbitai Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

Next included review available in 54 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

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

Review profile: CHILL

Plan: Advanced

Run ID: 6a8909f5-44e5-4ae2-98ef-055d52c4b867

📥 Commits

Reviewing files that changed from the base of the PR and between 342b720 and fb4981d.

📒 Files selected for processing (4)
  • packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs
  • packages/rs-drive/grovedb-structure.json
  • packages/rs-drive/src/drive/contract/structure.rs
  • packages/rs-drive/src/drive/document/structure.rs

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 Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

🌳 GroveDB structure

This pull request changes the described GroveDB structure. Open it in the structure viewer: new nodes glow, removed ones stay as ghosts, and the tour walks through each change.

Changed (9 nodes)

  • contracts.contract
  • contracts.contract.contract
  • contracts.contract.documents
  • contracts.contract.documents.document_type
  • contracts.contract.documents.document_type.primary_key
  • contracts.contract.other
  • contracts.contract.other.document_removals
  • contracts.contract.other.document_removals.document_type
  • contracts.contract.other.version

Compared 8825bcd920 with fb4981d403. Updated at 2026-09-24T01:42:43.148Z

@github-actions github-actions Bot added this to the v4.2.0 milestone Sep 24, 2026
@github-actions github-actions Bot added the waiting-bots Waiting for the review bots to report on this head label Sep 24, 2026
@thepastaclaw

thepastaclaw commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

🕓 Queued for automated review — 9th in line, estimated start in ~1.8 h (commit fb4981d)
Estimated review time once started: ~25 min (two-phase automated review; median of recent runs).

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

QuantumExplorer and others added 2 commits September 24, 2026 07:45
A keeps-history contract stored through insert_contract carries the
contract's flags on its `latest` reference and revision items
(add_contract_to_storage writes them with the contract element's flags),
but the description admitted none there: the same miss as the contested
poll trees, latent because no system contract keeps history.

The contract, document and votes descriptions now share one
CONTRACT_FLAGS note, which says who writes the flags: a protocol upgrade
registering a system contract that can be deleted or is not read only.
Genesis and the contract create/update transitions write none. The token
trees insert_contract creates are written without flags and keep their
own descriptions.

The structure fixtures pin both origins: contracts_with_documents and
contested_documents store each contract a second time through
insert_contract and assert the history and poll nodes carry exactly
{None, EpochOwned}. The separate contested fixture and its fresh drive
are folded into contested_documents.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…age flags

Genesis stores system contracts without storage flags, but
transition_to_version_14 registered app-connect and moderation charters
through insert_contract, which gives a contract that is not read only
(every system contract) and every tree created with it EpochOwned flags
owned by the all-zero system owner. Nobody owns that storage and nothing
deletes it, so no refund can ever be paid from those flags, and a chain
upgraded to 14 stored the two contracts differently from a chain born at
14. The charter contract's contested index made it visible: its
electedCharter trees under votes/contested_resource/active_polls failed
the structure conformance check in the v13 to v14 strategy tests.

Both contracts are now registered through apply_contract with no storage
flags, as genesis does. A new test upgrades a chain born at 13 and checks
both contracts, and the charter's trees under the active polls, carry no
flags and are byte-identical to a chain born at 14.

This takes back the description changes of the previous two commits:
the poll trees and the history nodes admit no flags again. The contract
and document areas keep one shared CONTRACT_FLAGS note, now naming the
only contracts that carry flags (the ones upgrades 6, 9 and 13
registered).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@QuantumExplorer QuantumExplorer changed the title fix(drive): structure description admits contract flags on contested poll trees fix(platform)!: register the version 14 system contracts without storage flags Sep 24, 2026

@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 e38b6e3 into v4.2-dev Sep 24, 2026
22 of 24 checks passed
@QuantumExplorer
QuantumExplorer deleted the fix/charter-contested-index-structure branch September 24, 2026 01:51
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