Skip to content

fix(drive): prove decision proposal creates as plain documents, found by a new strategy test - #5696

Merged
QuantumExplorer merged 3 commits into
v5.1-devfrom
claude/decision-proposals-strategy-test
Oct 31, 2026
Merged

QuantumExplorer merged 3 commits into
v5.1-devfrom
claude/decision-proposals-strategy-test

Conversation

@QuantumExplorer

@QuantumExplorer QuantumExplorer commented Oct 31, 2026 •

Copy link
Copy Markdown
Member

Basic explanation

What this does: It runs decision proposals (protocol version 15, #5684) in a simulated chain next to a DPNS name contest, for four weeks of blocks. The run found two problems, both fixed here.

What the test found:

  • The proof of a proposal create looked in the wrong place. Drive's prover and the client's proof verifier treat any create that states a fund as a contested document, and look for it in the contest area. A proposal states its 0.5 Dash fund but is stored as a normal document. So a client that creates a proposal and waits for the result would be told the proposal does not exist.
  • Drive's own description of its tree was too strict. A document type that keeps history stores each version with its owner's storage flags. The description allowed versions with no flags only, so the structure check failed on any chain holding such documents. Proposals keep their history, and are the first test chain to write them.

Before and after, for a client creating a proposal and waiting for the result:

before: the node proves the create at the contest path, the client looks there too
        -> "document not found" (the proposal was created, the client cannot see it)
after:  both look where the proposal is stored
        -> the proposal, proven

Value:

Risks:

  • Consensus impact: none. Proofs are not part of consensus, and the only creates whose proof changes belong to the decision proposals contract, which exists from protocol version 15 only (unreleased). The structure description is used by tests and the structure viewer only.
  • Strategy files: OperationType::YesNoVote is appended last, so saved strategies (for example Dash Evo Tool's) still decode. A client matching OperationType exhaustively needs one more arm.

Issue being fixed or feature implemented

The strategy test on the test list of #5679 that #5684 left out: many proposals and votes on end dates shared with DPNS contests. Writing it found the two bugs above.

What was done?

Proof of a proposal create (rs-drive)

SingleDocumentDriveQueryContestedStatus::of_document_transition decides where a transition's document is stored: contested for a create stating a fund, except a decision proposal (dpp::decision_proposal::is_decision_proposal). prove_state_transition v0 and verify_state_transition_was_executed_with_proof v0 both call it, in place of two identical inline checks.

Structure description (rs-drive)

contracts.contract.documents.document_type.primary_key.document.revision allows EpochOwned flags as well as none, like the document node above it. grovedb-structure.json is regenerated (5 lines).

Yes/no votes in strategies (strategy-tests, drive-abci strategy runner)

OperationType::YesNoVote(YesNoVoteOp { vote_poll_id, end_date, vote_choices_with_weights }). Each hit picks a random masternode and a weighted answer, and skips a vote that would be refused or could not be checked:

  • the same answer the masternode already gave, or one past its 5 votes on the poll (read from Drive);
  • a second answer by the same masternode in the same block (the strategy checks every vote's proof against the state the block leaves, which holds only the last answer);
  • any vote once the block time reaches the end date (the poll closes at the start of that block).

The contested-vote branch and this one share the masternode vote signing (signed_masternode_vote). The weighted pick is shared too (choose_weighted), and draws from the random generator exactly as before, so existing strategy outcomes do not move.

The test

run_chain_with_decision_proposals_closing_beside_a_dpns_contest, at protocol version 15:

  1. Two identities preorder and then register the same DPNS name, opening a contest.
  2. In the next block, four identities open eight proposals, two each:
Proposal passPercent minimumTurnoutPercent End date Answers
Contest day, simple majority 50 0 the contest's mostly yes
Contest day, four fifths 80 0 the contest's mostly yes
Contest day, half the network 50 50 the contest's mostly yes
Shortest run 50 10 1 week mostly no
Three weeks, simple majority 50 0 3 weeks mostly no
Three weeks, seven tenths 70 10 3 weeks mostly yes
Two weeks and a half day 60 0 2 weeks + 12 h even
Longest run 66 25 4 weeks mostly yes
  1. Thirty daily blocks follow: masternodes answer every open proposal (1 to 3 votes per proposal per block) and vote on the contest.

It checks:

  • every create succeeds; each poll opens with its rule (read back with DecisionProposalVotePoll::from_proposal, the function consensus uses) and holds exactly 0.5 Dash;
  • the contest's end date lists the contest and the three proposals ending with it;
  • every vote succeeds, and its proof verifies;
  • polls close in end date order, at most maximum_vote_polls_to_process per block, the contest included. A poll closes in the first daily block at or after its end date that has room, and every block it waits through closes the maximum, none of them due later than it. Here the four polls due on the contest's end date take two blocks, and "Two weeks and a half day" waits one block behind them;
  • the contest is won by the favoured contender;
  • each result's minimum is the turnout share of the network, rounded up, and passed follows from the rule (yes strictly above the percent of yes plus no, and yes plus no reaching the minimum), matching YesNoVotePoll::passes;
  • at least one proposal passed, one failed on the answers and one fell short of its turnout;
  • each poll's fund is gone (the rest went to processing), the end date index is empty, and all eight proposals remain.

How Has This Been Tested?

  • The new strategy test fails without each fix: first on the create's proof, then on the structure check. It passes with both (about 5 s).
  • All 9 voting strategy tests pass (cargo test -p drive-abci --test strategy_tests test_cases::voting_tests), strategy-tests unit tests pass.
  • rs-drive: the new unit test of of_document_transition (a contested create, a plain create, a proposal), the verify/prove/single document tests (520 passed), and the structure tests with the regenerated JSON (11 passed).
  • drive-abci library tests for decision proposals and contested resources (49 passed).
  • cargo clippy -p drive -p strategy-tests -p drive-abci --tests is clean; cargo fmt --all.

In-place changes to shipped generations

Generation Change Why it cannot change consensus
prove_state_transition v0 A decision proposal create is proved as a plain document Proofs are not part of consensus. Only creates of the decision proposals contract change, and that contract exists from protocol version 15 only.
verify_state_transition_was_executed_with_proof v0 The same, on the client side Client-side; same reason.

Breaking Changes

None to the protocol. strategy_tests::operations::OperationType gains a variant (appended last, so serialized strategies still decode).

Checklist:

  • I have performed a self-review of my own code
  • My Rust, FFI, WASM, Swift or Kotlin changes follow the coding conventions
  • 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
  • If I added or changed a system contract's document schemas, I checked the contract 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 · a66e85c

  • Bots — thepastaclaw not yet — /skip-bots proceeds without the ones not yet reported
  • Self-review — post /self-reviewed
  • Build running
  • Approvals — you own every area touched; none needed

When every merge requirement is met, the PR Hygiene check passes. Reviewer limits do not block merging; other required GitHub checks and protections still apply.

Summary by CodeRabbit

  • Bug Fixes
    • Contested status is now handled consistently across document transitions, including decision proposals.
  • Documentation
    • Clarified document revision storage flags and refund behavior when a revision is deleted.
  • Tests
    • Expanded voting coverage for contests and decision proposals, including vote acceptance, poll outcomes, fund usage, and processing order.

QuantumExplorer and others added 3 commits October 31, 2026 05:45
…ored

The prover and the client verifier both looked for a create's document in
the contest area whenever the create stated a fund. A decision proposal
(protocol version 15) states the decision proposal fund, but it opens a
yes/no poll and is stored as any document is, so the proof of a proposal
create looked in the wrong place and a client waiting for the result could
not find the proposal it had just created.

`SingleDocumentDriveQueryContestedStatus::of_document_transition` now
decides where a transition's document is stored, for both: contested for a
create stating a fund, except a decision proposal. Only creates of the
decision proposals contract change, and that contract exists from protocol
version 15 only.

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

A document of a type keeping history stores each revision with the
document's storage flags, the owner's when the owner paid. The structure
description allowed a revision no flags only, so the conformance check of a
chain holding such documents failed. Decision proposals keep their history
and are the first strategy fixture to write them.

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

A strategy test at protocol version 15: four identities open eight
proposals in one block, three ending on the end date of a DPNS contest
opened the block before, the others one to four weeks out. Masternodes
answer every proposal and vote on the contest for four weeks of daily
blocks, the strategy verifying the proof of every create and vote.

It checks that each proposal opens its poll with exactly the decision
proposal fund, filed under its end date beside the contest; that due polls
close in end date order, at most `maximum_vote_polls_to_process` a block,
the contest's included (so the proposal due half a day after the contest
waits a block); that each result follows from the poll's rule and tallies,
with polls passing, failing on the answers and failing short of turnout;
that the rest of each fund is spent and the end date index emptied; and
that the proposals stay.

Strategies gain `OperationType::YesNoVote`, appended last so saved
strategies still decode. It answers a yes/no poll with weighted answers,
skipping an answer the masternode already gave, one past its allowance, a
second answer in the same block (the proof is checked against the state the
block leaves) and any vote once the poll is due. The masternode vote
signing the contested votes used is shared with it.

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

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 (1 node)

  • contracts.contract.documents.document_type.primary_key.document.revision

Compared eaa7602a8e with a66e85c422. Updated at 2026-10-31T02:46:51.337Z

@github-actions github-actions Bot added this to the v5.1.0 milestone Oct 31, 2026
@coderabbitai

coderabbitai Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between eaa7602 and a66e85c.

Files selected for processing: 8
  • packages/rs-drive-abci/tests/strategy_tests/strategy.rs
  • packages/rs-drive-abci/tests/strategy_tests/test_cases/voting_tests.rs
  • packages/rs-drive/grovedb-structure.json
  • packages/rs-drive/src/drive/document/structure.rs
  • packages/rs-drive/src/prove/prove_state_transition/v0/mod.rs
  • packages/rs-drive/src/query/single_document_drive_query.rs
  • packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs
  • packages/strategy-tests/src/operations.rs

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Walkthrough

The change adds weighted yes/no/abstain operations to strategy tests, exercises DPNS contests and decision-proposal polls across their lifecycle, and centralizes document-transition contested-status classification for proof generation and verification. Document revision flag metadata is updated to describe epoch-owned and absent flags.

Changes: Decision proposal voting and proof handling

Layer / File(s) Summary
Weighted vote operations
packages/strategy-tests/src/operations.rs
Adds a weighted yes/no/abstain operation and serialization support. The existing weighted-choice method now uses a shared helper.
Document contested-status classification
packages/rs-drive/src/query/single_document_drive_query.rs, packages/rs-drive/src/prove/prove_state_transition/v0/mod.rs, packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs, packages/rs-drive/src/drive/document/structure.rs, packages/rs-drive/grovedb-structure.json
Adds a shared classifier that excludes decision proposals from contested creates. Proof generation and verification use it. Revision flag metadata describes epoch-owned and absent flags.
Strategy vote generation
packages/rs-drive-abci/tests/strategy_tests/strategy.rs
Generates eligible yes/no votes before poll end dates. Resource and yes/no votes use a shared helper to construct masternode vote transitions.
Proposal poll setup and indexing
packages/rs-drive-abci/tests/strategy_tests/test_cases/voting_tests.rs
Adds a chain test that creates DPNS contenders and decision proposals, then checks poll dates, funding, and end-date index entries.
Proposal voting and resolution checks
packages/rs-drive-abci/tests/strategy_tests/test_cases/voting_tests.rs
Runs daily contest and proposal voting. Checks outcomes, closing order and capacity, and final index and document state.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related issues

Suggested reviewers: lklimek, pastapastapasta, shumkov

Merge Risk: Minimal · up to a66e8

Decision proposal creates are now classified as plain documents when their proof is located, and the shared classifier keeps proof generation and verification consistent. The other changes are a documentation-level structure update and new strategy tests. I see no concrete merge-blocking risk.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 62.50% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documenta… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title names the two main fixes: proof handling for decision proposal creates and a new strategy test that surfaced them. The changeset matches this. Its files change the proof and verification log…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Title check

Explanation

The title names the two main fixes: proof handling for decision proposal creates and a new strategy test that surfaced them. The changeset matches this. Its files change the proof and verification logic so decision proposal creates are treated as plain documents, add a strategy test that runs decision proposals alongside a DPNS contest, and fix the grovedb structure description for document revisions. The title is specific and omits the structure fix, which is expected for a title.

Full details: Docstring Coverage

Explanation

Docstring coverage is 62.50% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 8 functions across 7 files. (1 skipped: 1 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches
Generate docstrings
  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • 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

@github-actions

github-actions Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Waiting for bot review — thepastaclaw not yet. Wait for the missing reviews, or a writer can post /skip-bots to proceed without them; blocking findings still need addressing.
Full checklist in the description.

@github-actions github-actions Bot added the waiting-bots Waiting for the review bots to report on this head label Oct 31, 2026
@thepastaclaw

Copy link
Copy Markdown
Collaborator

🕓 Review not started yet because the new head is waiting for the 30-minute push debounce.

  • Request normal review — click when the PR is ready for review.
  • Request priority review — click to move this review to the front of the queue.

Commit a66e85c. Normal review starts when eligible; priority review starts as soon as a slot is available.

@QuantumExplorer
QuantumExplorer merged commit 40677dc into v5.1-dev Oct 31, 2026
26 of 27 checks passed
@QuantumExplorer
QuantumExplorer deleted the claude/decision-proposals-strategy-test branch October 31, 2026 02:59
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