Skip to content

feat(rs-sdk): own the masternode voting-key facts - #4340

Merged
QuantumExplorer merged 1 commit into
v4.2-devfrom
feat/rs-sdk-masternode-vote-helper
Aug 8, 2026
Merged

feat(rs-sdk): own the masternode voting-key facts#4340
QuantumExplorer merged 1 commit into
v4.2-devfrom
feat/rs-sdk-masternode-vote-helper

Conversation

@QuantumExplorer

@QuantumExplorer QuantumExplorer commented Aug 8, 2026

Copy link
Copy Markdown
Member

Follow-up to #4333, which fixed a masternode voting bug — and in doing so put a pile of Platform domain knowledge in the FFI shim.

The problem

Casting a contested-resource vote needs three things that are properties of Platform, not of any binding:

  1. which key a voter identity holds,
  2. how to recognise that Platform rejected that key, and
  3. what the rejection actually meant.

All three live in rs-sdk-ffi. So Swift and Kotlin callers get them — they route through the FFI — while a Rust caller of PutVote does not, and has to rediscover them.

That is not hypothetical. get_voting_identity_id derives the voter identity from voter_pro_tx_hash.as_bytes() verbatim, and until #4333 nothing said which orientation that had to be. A caller holding wire/Txid bytes addresses an identity that has never existed and gets "no voter identity" back. That cost real debugging time, and the FFI's .reverse() only protects callers who go through the FFI.

What this adds

platform::transition::masternode_vote_keys:

voter_identity_id takes a typed ProTxHash, not bytes
voter_identity_voting_key builds the key Platform holds, so no fetch is needed to broadcast
select_voting_key picks the usable key off a fetched identity by its own data
is_voting_key_failure gates diagnosis on the typed consensus error
diagnose_voting_key_failure returns a typed VotingKeyProblem

Two choices worth calling out:

The type is the guard, not the doc. voter_identity_id takes ProTxHash because the derivation is orientation-sensitive and Txid bytes for the same transaction are its exact reverse. A doc comment already proved insufficient — this bug happened once with the contract undocumented, and documenting it (#4333) helps only readers. The type helps everyone.

diagnose_voting_key_failure returns a fact, not a sentence. VotingKeyProblem is an enum; bindings phrase it for their users. Formatting messages in the SDK would make every caller inherit English strings they cannot localise.

Signing stays with the caller. Producing a Signer from a raw key is a binding concern, and pulling simple-signer into the public SDK to do it here would be the wrong trade — so this covers the key facts, not a full cast_vote.

Testing

10 tests, all in-process:

  • the fabricated key matches what create_voter_identity_v0 assigns (id 0, VOTING, ECDSA_HASH160, enabled)
  • the identity id is orientation-sensitive — reversing the ProTxHash changes it, which is the property that made votes fail
  • selection is by data not position (a voting key at id 4 behind another key at id 0 is still found), and rejects a disabled key, a different address, a wrong purpose, and a wrong key type — each isolated so no predicate is dead weight
  • the three key failures are diagnosable; a signature failure that is not about the key's existence or state, and a broadcast error with no consensus cause, are not

Scope

No behaviour change on its own — this is the API. Moving rs-sdk-ffi onto it is a separate PR so this can be reviewed as the surface it is, and so #4333 (already several rounds in) is not reopened.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added public utilities for resolving masternode voting identities and keys.
    • Added support for selecting enabled, matching voting keys.
    • Added diagnostics for missing identities, unavailable keys, and relevant voting failures.
    • Added comprehensive validation for voting-key construction, selection, and failure detection.

Casting a contested-resource vote needs three things that are properties of
Platform, not of any binding: which key a voter identity holds, how to
recognise that Platform rejected that key, and what the rejection meant.
All three lived in `rs-sdk-ffi`, so Swift and Kotlin callers got them by
routing through the FFI while Rust callers of `PutVote` did not — and had
to rediscover them, including the byte-order rule that makes a vote address
an identity that has never existed.

Adds `platform::transition::masternode_vote_keys`:

  * `voter_identity_id` takes a typed `ProTxHash` rather than bytes. The
    derivation is orientation-sensitive and `Txid` bytes for the same
    transaction are its exact reverse, so passing the wrong one silently
    yields a nonexistent identity. The type is the guard; a doc comment was
    not enough to stop it happening once already.
  * `voter_identity_voting_key` builds the key Platform holds, so a caller
    can broadcast without first fetching the identity.
  * `select_voting_key` picks the usable key off a fetched identity by its
    own data, not by position — position cannot tell a live key from one a
    rotation disabled.
  * `is_voting_key_failure` gates diagnosis on the typed consensus error.
    Without it, diagnosing every failure lets an absent voter identity
    masquerade as the cause of a closed poll or a transport error.
  * `diagnose_voting_key_failure` returns a typed `VotingKeyProblem` rather
    than a formatted string: rs-sdk reports the fact, bindings phrase it.

Signing stays with the caller. Producing a `Signer` from a raw key is a
binding concern, and pulling `simple-signer` into the public SDK to do it
here would be the wrong trade.

No behaviour change on its own — `rs-sdk-ffi` moves onto these separately,
so this can be reviewed as the API it is.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions github-actions Bot added this to the v4.2.0 milestone Aug 8, 2026
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The Rust SDK adds a public transition module with utilities for voter identity derivation, voting-key construction and selection, consensus failure classification, and asynchronous diagnosis. Tests cover byte ordering, key attributes, disabled or mismatched keys, and supported failures.

Changes

Voting key utilities

Layer / File(s) Summary
Identity and voting-key contracts
packages/rs-sdk/src/platform/transition.rs, packages/rs-sdk/src/platform/transition/masternode_vote_keys.rs
The SDK exports masternode_vote_keys. The module derives voter identity identifiers, constructs expected voting keys, defines VotingKeyProblem, and selects enabled matching keys.
Failure classification and diagnosis
packages/rs-sdk/src/platform/transition/masternode_vote_keys.rs
The module recognizes supported consensus signature failures and asynchronously diagnoses missing identities or unusable voting keys.
Voting-key utility validation
packages/rs-sdk/src/platform/transition/masternode_vote_keys.rs
Tests verify key construction, byte orientation, key selection, and failure classification.

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

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant diagnose_voting_key_failure
  participant Sdk
  participant Platform
  Caller->>diagnose_voting_key_failure: provide ProTxHash and voting address
  diagnose_voting_key_failure->>Sdk: fetch voter identity
  Sdk->>Platform: request identity by derived Identifier
  Platform-->>Sdk: return identity or fetch error
  Sdk-->>diagnose_voting_key_failure: return identity result
  diagnose_voting_key_failure->>diagnose_voting_key_failure: select_voting_key
  diagnose_voting_key_failure-->>Caller: return VotingKeyProblem or None
Loading

Possibly related PRs

  • dashpay/platform#4333: Adds overlapping voter-identity and voting-key construction, selection, and diagnostic helpers.

Suggested reviewers: lklimek, shumkov

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the rs-sdk feature that centralizes masternode voting-key facts.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/rs-sdk-masternode-vote-helper

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

@thepastaclaw

Copy link
Copy Markdown
Collaborator

🕓 Ready for review — 1 ahead in queue (commit e1465ed)
Queue position: 2/2

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/rs-sdk/src/platform/transition/masternode_vote_keys.rs (1)

254-256: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the dead reversal block.

bytes and reversed do not affect the assertions. asymmetric already tests orientation behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/rs-sdk/src/platform/transition/masternode_vote_keys.rs` around lines
254 - 256, Remove the unused bytes and reversed initialization/reversal block
from the affected test, leaving the existing assertions and asymmetric
orientation coverage unchanged.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/rs-sdk/src/platform/transition/masternode_vote_keys.rs`:
- Around line 254-256: Remove the unused bytes and reversed
initialization/reversal block from the affected test, leaving the existing
assertions and asymmetric orientation coverage unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 468d71ef-eea9-422f-bdb5-20ebc2b115b5

📥 Commits

Reviewing files that changed from the base of the PR and between bce107b and e1465ed.

📒 Files selected for processing (2)
  • packages/rs-sdk/src/platform/transition.rs
  • packages/rs-sdk/src/platform/transition/masternode_vote_keys.rs

@QuantumExplorer
QuantumExplorer merged commit f446428 into v4.2-dev Aug 8, 2026
14 checks passed
@QuantumExplorer
QuantumExplorer deleted the feat/rs-sdk-masternode-vote-helper branch August 8, 2026 10:16
@codecov

codecov Bot commented Aug 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.62%. Comparing base (8f98180) to head (e1465ed).
⚠️ Report is 5 commits behind head on v4.2-dev.

Additional details and impacted files
@@             Coverage Diff              @@
##           v4.2-dev    #4340      +/-   ##
============================================
- Coverage     87.62%   87.62%   -0.01%     
============================================
  Files          2704     2704              
  Lines        345206   345211       +5     
============================================
  Hits         302474   302474              
- Misses        42732    42737       +5     
Components Coverage Δ
dpp 88.86% <ø> (ø)
drive 86.25% <ø> (ø)
drive-abci 89.66% <ø> (ø)
sdk ∅ <ø> (∅)
dapi-client ∅ <ø> (∅)
platform-version ∅ <ø> (∅)
platform-value 92.88% <ø> (ø)
platform-wallet ∅ <ø> (∅)
drive-proof-verifier 48.02% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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