Skip to content

fix(rs-sdk): compare fetched vote proof key with vote poll ID #4138

Description

@Claudius-Maginificent

Expected Behavior

Vote::fetch(sdk, VoteQuery::new(voter_id, vote_poll_id)) should return the proved vote for that voter and poll when it exists, or None when it does not.

The proof decoder should validate the returned map key against the requested vote-poll ID.

Current Behavior

FromProof<GetContestedResourceIdentityVotesRequest> for Vote extracts identity_id from the request and compares it with the key returned by ResourceVotesByIdentity:

let id_in_request = Identifier::from_bytes(&v0.identity_id)?;
// ...
let (id, vote) = maybe_votes.into_iter().next()?;

if id != id_in_request {
    return Err(Error::ResponseDecodeError { ... });
}

However, the proved ResourceVotesByIdentity map is keyed by vote-poll ID, not voter identity ID. Drive's proof verification inserts the poll's vote_id as the map key.

Consequently, an existing vote normally fails with a response-decode error equivalent to:

expected vote for identity <voter-id>, got vote for identity <vote-poll-id>

The identifiers are different by design.

Impact

This breaks the public single-vote fetch API whenever a vote exists.

It also affects PutVote::put_to_platform_and_wait_for_response. Its duplicate-transition recovery calls:

Vote::fetch(sdk, VoteQuery::new(voter_pro_tx_hash, vote_poll_id)).await?

Therefore the recovery path can fail while trying to verify that the intended vote already exists.

Clients can work around the bug with ResourceVote::fetch_many and an exact lookup by vote-poll ID, but the public Vote::fetch contract should work directly.

Source Locations

  • Faulty comparison: packages/rs-drive-proof-verifier/src/proof.rs, FromProof<GetContestedResourceIdentityVotesRequest> for Vote
  • Query containing both voter and poll IDs: packages/rs-sdk/src/platform/query.rs, VoteQuery
  • Affected recovery caller: packages/rs-sdk/src/platform/transition/vote.rs
  • Proof map construction: packages/rs-drive/src/verify/voting/verify_identity_votes_given_proof/v0/mod.rs

Suggested Fix

Extract the requested vote-poll ID from the request's start_at value and compare the returned map key with that ID. Keep identity_id only as the voter scope for the query.

Alternatively, preserve the expected poll ID explicitly in the query/request conversion so the proof decoder does not need to infer it from pagination fields.

Suggested Tests

  • Vote::fetch returns an existing vote when the proof map is keyed by the requested poll ID.
  • The returned poll ID must match the requested poll ID.
  • A different returned poll ID is rejected.
  • No vote returns None.
  • PutVote duplicate recovery succeeds when the proved current vote matches the submitted choice.
  • The tests use distinct voter and poll identifiers so comparing the wrong fields cannot pass accidentally.

Context

Discovered while implementing authoritative DPNS vote-state reconciliation in Dash Evo Tool. DET will use the proved ResourceVote::fetch_many API as a temporary workaround.

This is separate from #4137, which concerns classification and retry behavior after a successful broadcast followed by a result-wait failure.

🤖 Co-authored by Claudius the Magnificent AI Agent

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions