Skip to content

docs: add Decentralized Masternode Shares DIP - #187

Open
PastaPastaPasta wants to merge 12 commits into
dashpay:masterfrom
PastaPastaPasta:dip-pasta-shared-masternode-collateral
Open

docs: add Decentralized Masternode Shares DIP#187
PastaPastaPasta wants to merge 12 commits into
dashpay:masterfrom
PastaPastaPasta:dip-pasta-shared-masternode-collateral

Conversation

@PastaPastaPasta

@PastaPastaPasta PastaPastaPasta commented Jul 4, 2026

Copy link
Copy Markdown
Member

Decentralized Masternode Shares (pre-DIP)

Adds dip-pasta-shared-masternode-collateral.md (alias naming per BIP2 conventions, pending DIP number assignment): a specification for trustless shared masternode ownership — 2 to 8 participants fund one masternode's collateral atomically in a single registration transaction, consensus splits the owner reward by recorded contribution, and the collateral can only move through a consensus-enforced dissolution transaction that pays each participant's principal to a refund script fixed at registration.

Relationship to DIP-0026 / #184

This is a strict superset of multi-party payouts: DIP-0026 gives a protocol-enforced recurring reward split but leaves the registrar in control of the payout list and the collateral spendable by whoever holds it — its Security Considerations explicitly defer immutable payout rights to a future protocol mechanism. This DIP is that mechanism. It extends the provider transaction payload version 3 (extended addresses) from #184; a version 3 payload with an empty share list behaves exactly as DIP-0026 specifies. The two deploy together in v24 (EHF).

Key design points

  • Consensus covenant, not multisig / pre-signed refunds — without SegWit/Taproot, co-signer txid malleability makes pre-signed refund chains unsafe; ownership lives in the provider payload and spends are enforced in consensus (same trust model as DIP-0003).
  • Tagged collateral script (04445348437551, exact match) — creation is valid only inside a shared registration, spending only via ProDisTx; the DIP states the anyone-can-spend-on-non-enforcing-chains trade-off explicitly.
  • Monotone dissolution validity — minimum-based output rules with a non-increasing required penalty: a dissolution valid at height h is valid at every later height, which also makes offline "standby dissolutions" (owner-key-loss insurance) safe to sign years ahead.
  • Bounded loss under key compromise — unilateral dissolutions carry a fixed consensus fee ceiling (MAX_DIS_FEE, 0.01 DASH) and a bonus ceiling at the configured earlyPenalty, so a stolen share owner key can cost its holder at most the consented early-exit penalty plus a small constant; every other duff must reach the immutable refund script.
  • Immutable share owner keys, refund scripts, amounts, and penalty terms; only the reward script is participant-updatable. Rationale for each immutability choice (including why key rotation is deliberately absent) is in the Rationale section.
  • Exit is always possible: unilateral dissolution (early-period penalty, redistributed pro-rata to remaining participants) or unanimous dissolution (penalty-free). Regular masternodes only in this version; Evo requires a Platform-side credit-distribution spec first.

A reference implementation exists at dashpay/dash#7437 and is kept in sync with this text.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation
    • Added a complete draft specification for trustless shared masternode ownership among 2–8 participants.
    • Documented shared registration, proportional reward distribution, owner-approved updates, dissolution and refund rules, validation requirements, deployment guidance, and security and privacy considerations.
    • Added specifications for shared masternode registration, reward updates, and dissolution transactions.
  • Chores
    • Expanded the accepted terminology list with technical vocabulary related to shared collateral, signatures, transaction processing, and privacy.

Pre-DIP (alias dip-pasta-shared-masternode-collateral per BIP2 naming) specifying trustless shared masternode collateral: 2-8 participants fund one masternode atomically, consensus splits owner rewards by contribution, and a covenant-enforced dissolution transaction (ProDisTx) is the only way collateral can move. Builds on DIP-0003 and extends DIP-0026 provider transaction version 4.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8a01bc2b-6978-47f1-9f56-3fea0d7fe31a

📥 Commits

Reviewing files that changed from the base of the PR and between c19da1d and 79ed4ab.

📒 Files selected for processing (2)
  • dip-pasta-shared-masternode-collateral.md
  • project-words.txt
💤 Files with no reviewable changes (1)
  • project-words.txt
🚧 Files skipped from review as they are similar to previous changes (1)
  • dip-pasta-shared-masternode-collateral.md

Included review availability: Your plan includes up to 3 reviews per rolling hour; 2 remain after this review.


📝 Walkthrough

Walkthrough

This PR adds a DIP for trustless shared masternode ownership by 2–8 participants. It defines registration, rewards, dissolution, lifecycle updates, consensus enforcement, activation, tests, security considerations, and supporting vocabulary updates.

Changes

Shared Masternode Collateral DIP

Layer / File(s) Summary
Shared registration contract
dip-pasta-shared-masternode-collateral.md
Defines shared registration data, collateral templates, share fields, consent signatures, serialization, and validity rules.
Dissolution and share updates
dip-pasta-shared-masternode-collateral.md
Defines ProDisTx, ProUpShareTx, and ProUpSharedRegTx, including dissolution penalties, reward updates, registrar updates, and deterministic list state.
Reward distribution
dip-pasta-shared-masternode-collateral.md
Defines ordered, weighted reward allocation with floor, remainder, fallback, and zero-output rules.
Collateral enforcement and activation
dip-pasta-shared-masternode-collateral.md
Defines template validation, forbidden destinations, mempool and block rules, filtering, same-block processing, and DEPLOYMENT_V24 activation.
Bounds, validation, and considerations
dip-pasta-shared-masternode-collateral.md
Adds rationale, limits, tests, security considerations, privacy considerations, and licensing information.
Spell-checker vocabulary
project-words.txt
Adds terms used by the DIP and retains the existing Wray entry.

Estimated code review effort: 4 (Complex) | ~60 minutes

Merge Risk: ⚪ Minimal · up to 79ed4

This documentation-only change introduces no actionable merge-blocking risk; it is merge-ready after normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant ShareOwners
  participant Registration
  participant DeterministicList
  participant ConsensusValidation
  participant RewardConstruction
  ShareOwners->>Registration: submit shared registration and consent signatures
  Registration->>DeterministicList: create shared masternode state
  ShareOwners->>DeterministicList: submit lifecycle update or dissolution transaction
  DeterministicList->>ConsensusValidation: validate template, signatures, and state
  ConsensusValidation->>RewardConstruction: apply share-table reward rules
  RewardConstruction-->>ShareOwners: construct proportional reward outputs
Loading
🚥 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 documentation change and the shared masternode DIP added by the pull request.
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 unit tests (beta)
  • Create PR with unit tests

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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.

Inline comments:
In `@dip-pasta-shared-masternode-collateral.md`:
- Around line 286-291: The monotonicity note in the ProDisTx/requiredPenalty
description is too strong for the zero-penalty case; rewrite the sentence so
validity is defined by paying at least requiredPenalty, and say a unilateral
ProDisTx is invalid whenever it pays less than requiredPenalty rather than only
“until the early period ends.” Update the surrounding explanation in the section
that discusses requiredPenalty, earlyPenalty, and ProDisTx validity to preserve
the monotonicity claim without excluding earlyPenalty = 0.
- Around line 292-307: The ProDisTx validity rules in the actor/output section
currently allow the actor refund output to be optional whenever it is non-zero,
which can let a valid dissolution omit the actor’s remaining principal. Update
the wording around the `actorIndex`, `shares[a].refundScript`, and
`requiredPenalty` rules to make the actor output mandatory whenever
`shares[a].amount - P > 0`, and only omit it in the genuinely zero-value case;
keep the rest of the output-order and no-extra-outputs constraints unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5f33eb94-07ee-4903-8e91-242fb4c1f4e8

📥 Commits

Reviewing files that changed from the base of the PR and between a4d46dd and 29810a3.

📒 Files selected for processing (2)
  • dip-pasta-shared-masternode-collateral.md
  • project-words.txt

Comment thread dip-pasta-shared-masternode-collateral.md Outdated
Comment thread dip-pasta-shared-masternode-collateral.md
@ndrezza

ndrezza commented Jul 9, 2026

Copy link
Copy Markdown

<3

- Commit the signature count into SharedDisHash so the unilateral/unanimous
  mode cannot be malleated by dropping or adding signatures after signing.
- Remove the non-normative replace-by-higher-fee relay suggestion; Dash relay
  has no replacement mechanism, so the first ProDisTx for a collateral wins.
- Remove operatorReward from the ProUpSharedRegTx payload: the operator reward
  is fixed at registration, matching the DIP-0003 ProUpRegTx model.
- Specify that a validated ProDisTx removes its masternode in the
  collateral-spend phase of list construction, after the block's other
  provider transactions apply, so a same-masternode update and dissolution are
  valid together in one block in either order.
- Rewrite the filtering section: the registration matches on every share
  refund script, reward script and owner key; the lifecycle transactions are
  matched by proTxHash (plus ProUpShareTx's new reward script), consistent
  with the DIP-0003 treatment of ProUpRegTx and ProUpRevTx, since they do not
  carry the share table and stateless filters perform no list lookup.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@hilawe

hilawe commented Jul 11, 2026

Copy link
Copy Markdown

Following up on my #186 closing comment. This is the Platform-side half I said
would come forward once it was ready. Background is in that thread (the June 28
request-for-comments post and the July 6 comparison with this draft). What follows draws on
a private prototype. Where something is a suggestion rather than a prototype result, I say
so.

What ran

I implemented most of this draft on a fork based on merged DIP-0026 (8c9f166a3):
registration, share updates, rewards, and dissolution. ProUpSharedRegTx and parts of the
destination rules stayed out of scope. The functional tests pass on regtest.

On the tested paths, the draft behaves as specified:

  • A two-participant shared masternode registers with the template collateral.
  • A normal transaction cannot spend the template output.
  • The node earns its share-weighted owner rewards in the coinbase.
  • A unilateral dissolution during the early period refunds the passive participant in
    full, to their immutable refund script, with the penalty math exact to the duff.

On that tested path, nothing is ever pre-signed against a transaction id, so the failure
mode the Motivation describes does not arise there.

Notes on the draft text from implementing it

These are the places where building it required decisions the text does not currently pin
down. I can expand any of them into separate comments or suggestions.

  • The template-creation and template-spend checks need to cover the coinbase and the
    same-block create-then-spend path, not only ordinary mempool inputs. I hit both in
    testing.
  • The penalty and reward split multiplies two duff-scale values (an amount times a share
    over the collateral). That overflows a 64-bit intermediate. The text could require wide
    multiplication explicitly.
  • Low-S form on the joinSig and dissolution signatures is worth pinning in the text so
    implementations agree.
  • The new transaction types need to join the contextual allowed-type list at the v24 gate.
    I hit this with ProDisTx and ProUpShareTx. Worth a line in the deployment section.
  • Proof-of-service interacts with shared nodes (the ban and revive path). The text is
    silent on whether a shared node revives the same way. Better to state it than leave
    implementations to guess.
  • The version-4 ProRegTx wire format would benefit from an explicit field-order statement.
    I had to infer it.
  • Exposing the share table in the protx info output makes a shared node inspectable
    without fetching its registration transaction. I implemented this and would suggest
    speccing that surface.
  • I also have a functional test with per-rule negative vectors for ProDisTx: each malformed
    dissolution is refused on its own consensus rule (redirecting a non-actor refund,
    underpaying a non-actor, wrong output count, wrong actor script, corrupted signature).
    Happy to contribute it in whatever form fits.

The Platform-side companion

This is the half I promised when closing the RFC. Everything here ran on a local Platform
devnet, so these are devnet results, not testnet or mainnet ones.

One property carries the whole design. A single asset-lock transaction can hold one credit
output per recipient, and Platform accepts identity top-ups against any credit-output index
of that one transaction. So a pool can turn a node reward into per-member Platform credits
directly, in one step. No pooled intermediary identity exists at any point, which means
there is no window where an operator holds the members' funds.

On top of that, a small document contract (pool, share, membership request, reward accrual,
vote preference, settlement) ran the member lifecycle end to end:

  • Members join and leave by matched handover, strictly within the Platform-accounted group
    behind one Layer 1 (L1) slot. The L1 share table never changes, and recorded capital
    never unwinds on chain.
  • Rewards distribute per epoch.
  • On dissolution, the returned principal goes to the recorded members, with no operator
    cut.
  • A member exits to L1 through a credit withdrawal signed by their own key.

Two design notes for anyone building this layer:

  • Record the member's share (in basis points, at distribution time) inside each accrual
    document, under a uniqueness rule per pool, member, and epoch. That makes every past
    distribution checkable from the ledger alone, even after membership changes. Without it,
    deleted share records leave no trace, and old epochs stop being verifiable. One caution
    from experience is that the uniqueness key also needs a distribution-kind field, because
    a reward and a principal return can land at the same height.
  • Governance is the honest trust remainder. A member-weighted tally over recorded
    preferences ran, and anyone can recompute it. But the node has one voting key, so casting
    the tally is enforced socially. Two mitigations would need no consensus change, and
    neither is built yet. The first is a published cast receipt, where the operator publishes
    the tally state and the resulting vote, so any deviation is visible and attributable. The
    second is a threshold arrangement on the voting key, for when a pool outgrows social
    enforcement.

Asks

  • Tell me which of the notes above you want as separate issue comments or PR suggestions,
    and I will write them up individually.
  • Say the word if the ProDisTx negative-test vectors would help the reference
    implementation, and I will share them.
  • Say whether the Platform-side companion belongs in this PR's discussion or in a
    dedicated issue. I have the write-up ready either way.

hilawe added a commit to hilawe/dash-tegara-mn-pooling that referenced this pull request Jul 15, 2026
…-signer

The honesty section now says plainly that dashpay/dips#187 is an open,
unmerged proposal (as of July 2026) whose consensus changes would wait on a
future hard fork even after a merge, and that the Layer 1 half of this design
moves with it. The what-is-here section credits dash-rawkey-signer, the
standalone wallet-free signing library the seed-loss recovery path runs on.
Dash Core folded the unreleased ProTx version 4 (MultiPayout) into
version 3 (extended addresses) since both are introduced by the same
deployment, so the shared-collateral fields now extend the version 3
payload; update every version reference accordingly.

The reference implementation also dropped support for registering and
dissolving a shared masternode within one block: a ProDisTx is now
validated against the previous block's masternode list in blocks exactly
as in the mempool, which removes the need for a second block-context
validation path. Update the enforcement rules and test vectors to match.
A standby dissolution simply becomes valid one block after registration.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
dip-pasta-shared-masternode-collateral.md (2)

172-176: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Apply the canonical low-S rule to shared registration update signatures too.

ProUpShareTx and ProUpSharedRegTx are signature-bearing payloads introduced by this DIP, but lines 172-174 only list joinSigs and ProDisTx. Since these updates are consensus-critical and affect txid stability, reword this as applying to every signature introduced by the DIP, including ProUpShareTx.payloadSig and ProUpSharedRegTx.sigs, or document an explicit exception.

Suggested wording
-All signatures introduced by this DIP (`joinSigs` and ProDisTx signatures) are
+All signatures introduced by this DIP, including `joinSigs`, ProDisTx,
+ProUpShareTx, and ProUpSharedRegTx signatures, are
🤖 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 `@dip-pasta-shared-masternode-collateral.md` around lines 172 - 176, Update the
low-S signature rule statement to cover every signature introduced by the DIP,
explicitly including ProUpShareTx.payloadSig and ProUpSharedRegTx.sigs alongside
joinSigs and ProDisTx signatures; do not leave these consensus-critical update
signatures as an implicit exception.

204-207: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Make the payee-reuse predicate explicit.

Line 204 mentions P2PK even though share scripts are described as P2PKH/P2SH and the test cases omit P2PK. Define P2PK as invalid/rejected, and define P2PKH/P2SH reuse as exact destination comparison: match P2PKH CKeyIDs as HASH160(pubkey) and match P2SH CScriptIDs to the script hash. Without that predicate, implementations can disagree on registration validity.

🤖 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 `@dip-pasta-shared-masternode-collateral.md` around lines 204 - 207, Clarify
the payee-reuse rule in the collateral specification: explicitly reject any P2PK
refundScript or rewardScript, and define P2PKH/P2SH reuse as exact destination
comparisons, matching P2PKH CKeyIDs against HASH160(pubkey) and P2SH CScriptIDs
against the script hash. Update the relevant rule and test cases to use this
predicate consistently.
🧹 Nitpick comments (2)
dip-pasta-shared-masternode-collateral.md (2)

631-645: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Add a wire-format compatibility vector for non-shared version 3 ProRegTx.

Lines 112-115 append shared fields to every version-3 payload while claiming sharesCount = 0 remains DIP-0026-compatible. Add an exact serialization and deserialization test covering payouts, empty shares and joinSigs, and zeroed penalty fields. This protects ordinary version-3 registrations from wire-format regressions.

🤖 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 `@dip-pasta-shared-masternode-collateral.md` around lines 631 - 645, Add a
wire-format compatibility test for a non-shared version-3 ProRegTx covering
exact serialization and deserialization with populated payouts, empty shares and
joinSigs, and zeroed penalty fields; preserve the expected DIP-0026-compatible
encoding when sharesCount is zero.

675-677: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Test both same-block update and dissolution orders.

Lines 472-475 allow ProUpShareTx or ProUpSharedRegTx and ProDisTx in either transaction order. Add test vectors for both (update, dissolution) and (dissolution, update) in one block. This verifies that block validation and mempool validation apply the same state transition.

🤖 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 `@dip-pasta-shared-masternode-collateral.md` around lines 675 - 677, Expand the
reorg test vectors to cover both transaction orders within a single block:
ProUpShareTx or ProUpSharedRegTx followed by ProDisTx, and ProDisTx followed by
the update transaction. Verify each ordering through both block validation and
mempool validation, preserving the deterministic masternode snapshots before and
after shared-state changes.
🤖 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.

Outside diff comments:
In `@dip-pasta-shared-masternode-collateral.md`:
- Around line 172-176: Update the low-S signature rule statement to cover every
signature introduced by the DIP, explicitly including ProUpShareTx.payloadSig
and ProUpSharedRegTx.sigs alongside joinSigs and ProDisTx signatures; do not
leave these consensus-critical update signatures as an implicit exception.
- Around line 204-207: Clarify the payee-reuse rule in the collateral
specification: explicitly reject any P2PK refundScript or rewardScript, and
define P2PKH/P2SH reuse as exact destination comparisons, matching P2PKH CKeyIDs
against HASH160(pubkey) and P2SH CScriptIDs against the script hash. Update the
relevant rule and test cases to use this predicate consistently.

---

Nitpick comments:
In `@dip-pasta-shared-masternode-collateral.md`:
- Around line 631-645: Add a wire-format compatibility test for a non-shared
version-3 ProRegTx covering exact serialization and deserialization with
populated payouts, empty shares and joinSigs, and zeroed penalty fields;
preserve the expected DIP-0026-compatible encoding when sharesCount is zero.
- Around line 675-677: Expand the reorg test vectors to cover both transaction
orders within a single block: ProUpShareTx or ProUpSharedRegTx followed by
ProDisTx, and ProDisTx followed by the update transaction. Verify each ordering
through both block validation and mempool validation, preserving the
deterministic masternode snapshots before and after shared-state changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 5f26b49d-0a44-42b9-837c-9533c2c872c7

📥 Commits

Reviewing files that changed from the base of the PR and between e7eba87 and b360f4c.

📒 Files selected for processing (1)
  • dip-pasta-shared-masternode-collateral.md

BIP68 gives input sequence numbers consensus meaning on version 2 and
later transactions, so a sequence rewrite between consent signing and
funding-input signing could impose a months-long relative timelock on a
fully consented registration without invalidating any consent signature.
Hash the sequences into SharedRegConsentHash, matching what
SharedDisHash already does.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@thephez thephez left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@coderabbitai @PastaPastaPasta please see feedback

Comment thread dip-pasta-shared-masternode-collateral.md Outdated
Comment thread dip-pasta-shared-masternode-collateral.md Outdated
Comment thread dip-pasta-shared-masternode-collateral.md
Comment thread dip-pasta-shared-masternode-collateral.md
Comment thread dip-pasta-shared-masternode-collateral.md Outdated
Comment thread dip-pasta-shared-masternode-collateral.md Outdated
Comment thread dip-pasta-shared-masternode-collateral.md Outdated
Comment thread dip-pasta-shared-masternode-collateral.md Outdated
Comment thread dip-pasta-shared-masternode-collateral.md Outdated
Comment thread project-words.txt Outdated

@thephez thephez left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Few more items to consider

Comment thread dip-pasta-shared-masternode-collateral.md
deployment, the reference implementation folded version 4 into version 3, and
this DIP follows that layout. A version 3 ProRegTx with a non-zero
`sharesCount` is a **shared registration**. A version 3 ProRegTx with
This DIP extends the unreleased version 3 (extended addresses) ProRegTx payload,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

"unreleased" is going to be stale as soon as the next version of Core is out. Is it necessary to state it's unreleased here?

Comment on lines 110 to 113

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same as above - is it necessary to state version 3 has not been released? Wouldn't it be enough to say this dip and dip 26 deploy together?

Comment on lines +642 to +645
Version 3 (extended addresses, which carries DIP-0026's payouts) has not shipped,
so using the same version avoids an additional payload version solely for field
layering, at the cost of a wire-format change to an unreleased payload. The two
DIPs deploy together in v24.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same as above - is it necessary to state version 3 has not been released? Wouldn't it be enough to say this dip and dip 26 deploy together?

Also, this point is already explained further up in the DIP. Probably should only cover it once in the doc.

Comment thread dip-pasta-shared-masternode-collateral.md
PastaPastaPasta and others added 7 commits August 17, 2026 11:01
The minimum-based output rules left two unbounded paths by which value could leave the actor's share: the transaction fee and voluntary penalty overpayment. A single stolen share owner key could sign a unilateral ProDisTx that pays the victim's entire share to miners as fee, or as bonus concentrated on a colluding participant, contradicting the guarantee that owner-key compromise can never cost principal. Cap the fee at a fixed constant (MAX_DIS_FEE, 0.01 DASH) in both modes and cap the unilateral bonus sum at the configured earlyPenalty. Both ceilings are height-independent, so monotone validity is preserved and early-period standbys paying the full penalty stay valid forever. Worst-case loss under key compromise is now earlyPenalty + MAX_DIS_FEE.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The two digests were defined in prose, leaving byte-level choices open that would fork independent implementations: whether the domain tags are hashed as bare bytes or as length-prefixed strings, whether the shares field includes the sharesCount byte, and what 'netInfo and Platform fields' covers for a type-0 payload. Pin all three, note why collateralOutpoint is deliberately absent, and state the signed-hash convention for ProUpShareTx and ProUpSharedRegTx (signature fields omitted entirely, per DIP-0003 practice), including why sigCount is uncommitted for type 12 but committed for ProDisTx.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The requirement that a sharesCount = 0 payload carry no join signatures and zeroed penalty fields was only a descriptive parenthetical; no listed validation rule rejected a non-shared payload with stray non-zero values, so implementations could disagree on block validity. State the rule normatively and add it to the test list. Also rewords the section to stop describing version 3 as unreleased, which would go stale on release (review feedback).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Registration rule 10 and ProUpShareTx both prevent a share script from paying the voting key, but the collision has a third entry point the spec did not cover: keeping the scripts fixed and moving the voting key onto an existing payee via ProUpSharedRegTx. The reference implementation already rejects this; state the rule so independent implementations agree.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The spec fixed same-block semantics only for ProDisTx, leaving two block-validity-observable orderings to implementer inference: whether an update may follow its masternode's registration in the same block (yes, updates validate against the evolving in-block list) and whether a registration may reuse an owner key freed by a same-block dissolution (no, removal takes effect in the collateral-spend phase).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The dissolution digest commits nLockTime and the input sequence but consensus does not restrict them, and BIP68 applies to version-3 transactions, so a co-signer's wallet could embed a lock the other signers fail to notice. Keep time locks available to participants who want them, scope the monotone-validity claim to final transactions, and require wallets to verify the lock fields before signing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review feedback: statements that version 3 is unreleased go stale the moment it ships. The deploy-together requirement stands on its own.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@PastaPastaPasta

Copy link
Copy Markdown
Member Author

Pushed 7 commits addressing an internal adversarial review plus the outstanding review feedback:

Security fix165b6c3 closes a real gap: the minimum-based dissolution output rules left the fee and voluntary penalty overpayment unbounded, so one stolen share owner key could sign a unilateral ProDisTx paying the victim's entire share to miners (as fee) or to a colluding participant (as "bonus"), contradicting the never-principal-theft guarantee. Unilateral dissolutions now carry two height-independent ceilings — fee <= MAX_DIS_FEE (0.01 DASH, both modes) and sum(bonus) <= earlyPenalty — bounding worst-case loss under key compromise at earlyPenalty + MAX_DIS_FEE. Monotone validity is preserved (the bonus ceiling is the configured earlyPenalty, not the height-dependent required penalty).

Interoperability pins (each of these was a place an independent implementation could diverge from the reference implementation and fork):

  • 4a5e8ba — byte-exact digest conventions: domain tags are compactSize-length-prefixed strings, shares includes the count byte, and the ProUpShareTx/ProUpSharedRegTx signed hash omits the signature fields entirely (DIP-0003 convention).
  • 6999fba — a non-shared v3 payload with non-zero joinSigs/earlyPeriodBlocks/earlyPenalty is now normatively invalid.
  • 7762415 — the payee-reuse rule now also covers a ProUpSharedRegTx moving the voting key onto an existing share payee (the reference implementation already rejects this).
  • 46c4142 — same-block ordering pinned for updates: register+update in one block is valid; reusing an owner key freed by a same-block dissolution is not.

Guidance and wording:

  • 82a2c31 — time locks on dissolutions stay permitted; wallets must verify nLockTime/sequence before signing (BIP68 applies to version-3 transactions).
  • 6999fba/79ed4ab — dropped the "unreleased version 3" framing that would go stale on release (thephez review).

Test Cases updated to cover each new rule. The PR description's stale "version 4" reference is also fixed. The reference implementation (dashpay/dash#7437) is being updated to match the new ceilings.


🤖 Posted autonomously by Claude on behalf of pasta.

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.

4 participants