diff --git a/dip-pasta-shared-masternode-collateral.md b/dip-pasta-shared-masternode-collateral.md new file mode 100644 index 00000000..03ff430f --- /dev/null +++ b/dip-pasta-shared-masternode-collateral.md @@ -0,0 +1,745 @@ +
+ DIP: pasta-shared-masternode-collateral + Title: Decentralized Masternode Shares + Author(s): Pasta + Comments-Summary: No comments yet. + Status: Draft + Type: Standard + Created: 2026-07-04 + Requires: 2, 3, 26 + License: MIT License ++ +## Table of Contents + +1. [Abstract](#abstract) +2. [Motivation](#motivation) +3. [Prior Work](#prior-work) +4. [Specification](#specification) + 1. [Terminology](#terminology) + 2. [Provider Transaction Version](#provider-transaction-version) + 3. [Shared Collateral Script](#shared-collateral-script) + 4. [Collateral Share](#collateral-share) + 5. [Registering a Shared Masternode](#registering-a-shared-masternode) + 6. [Dissolving a Shared Masternode (ProDisTx)](#dissolving-a-shared-masternode-prodistx) + 7. [Updating a Share (ProUpShareTx)](#updating-a-share-proupsharetx) + 8. [Updating the Shared Registrar (ProUpSharedRegTx)](#updating-the-shared-registrar-proupsharedregtx) + 9. [Masternode List State](#masternode-list-state) + 10. [Masternode Reward Payments](#masternode-reward-payments) + 11. [Collateral Spend Enforcement](#collateral-spend-enforcement) + 12. [Forbidden Template Destinations](#forbidden-template-destinations) + 13. [Special Transaction Filtering](#special-transaction-filtering) +5. [Deployment and Compatibility](#deployment-and-compatibility) +6. [Rationale](#rationale) +7. [Test Cases](#test-cases) +8. [Security Considerations](#security-considerations) +9. [Privacy Considerations](#privacy-considerations) +10. [Copyright](#copyright) + +## Abstract + +This DIP extends [DIP-0003: Deterministic Masternode Lists](dip-0003.md) and +[DIP-0026: Masternode Multi-Party Payouts](dip-0026.md) to allow 2 to 8 +participants to trustlessly co-own a single masternode. The participants fund +the collateral atomically in one registration transaction, consensus splits the +owner reward across the participants in proportion to their recorded +contributions, and the collateral can leave the masternode only through a +consensus-enforced dissolution that pays each participant's principal to a +refund script recorded at registration. No participant, operator, miner, or +compromised update path can redirect another participant's principal, and no +participant can be prevented from exiting. + +## Motivation + +DIP-0026 provides protocol-enforced recurring reward splitting, but it +explicitly leaves the registrar owner in control of the payout list and does +not protect the collateral UTXO from unilateral spending. Its Security +Considerations section notes that "a share arrangement that requires immutable +payout rights must use additional contractual, wallet, or protocol mechanisms +outside the scope of this DIP." This DIP is that protocol mechanism. + +Without it, shared masternode ownership requires trusting a collateral holder: +whoever controls the collateral key can spend the collateral, destroy the +masternode, and abscond with the other participants' principal. Pre-signed +multi-signature refund transactions cannot fix this on Dash: without SegWit or +Taproot, a co-signer can malleate the funding transaction identifier and +invalidate every pre-signed child. The only robust construction available is a +consensus-enforced covenant: the protocol itself records each participant's +contribution, refund script, reward script, and owner key, and enforces +refunds, rewards, and update consent directly. + +This DIP is therefore a strict superset of DIP-0026: + +* DIP-0026: protocol-enforced recurring reward split; +* this DIP: protocol-enforced funding, reward split, update consent, and + trustless exit. + +## Prior Work + +* [DIP-0002: Special Transactions](dip-0002.md) +* [DIP-0003: Deterministic Masternode Lists](dip-0003.md) +* [DIP-0026: Masternode Multi-Party Payouts](dip-0026.md) + +## Specification + +### Terminology + +| Term | Definition | +| --- | --- | +| Participant | One of the 2 to 8 co-owners of a shared masternode. | +| Share | One participant's recorded collateral contribution and associated scripts and key. | +| Share table | The ordered list of shares recorded at registration. Order is consensus-significant. | +| Refund script | The immutable script a participant's principal is paid to at dissolution. | +| Reward script | The script a participant's portion of owner rewards is paid to. Participant-updatable. | +| Share owner key | The ECDSA key (as a key ID) that authorizes a participant's consensus actions. Immutable. | +| Early period | The first `earlyPeriodBlocks` blocks after registration, during which unilateral exit is penalized. | +| Dissolution | The consensus-enforced spend of shared collateral that refunds all participants and removes the masternode. | +| Actor | The participant designated by `actorIndex` in a dissolution; pays the penalty (if any) and the transaction fee. | +| Unilateral dissolution | A dissolution authorized by exactly one participant. | +| Unanimous dissolution | A dissolution authorized by every participant. | + +### Provider Transaction Version + +This DIP extends the version 4 (`MultiPayout`) ProRegTx payload defined in +DIP-0026, prior to its release in any Dash Core version. A version 4 ProRegTx +with a non-zero `sharesCount` is a **shared registration**. A version 4 +ProRegTx with `sharesCount = 0` behaves exactly as specified in DIP-0026. + +Because version 4 has not been released, the additional fields below change the +serialization of all version 4 ProRegTx payloads (a non-shared payload still +serializes `sharesCount = 0`, an empty share list, and zeroed penalty fields). +This DIP and DIP-0026 must therefore deploy in the same release. + +### Shared Collateral Script + +The collateral output of a shared registration must use exactly the following +7-byte script (the **template**): + +```text +0x04 "DSHC" OP_DROP OP_TRUE +hex: 04445348437551 +``` + +Template matching is always **exact-script** comparison against these 7 bytes, +never prefix matching. + +The template contains no keys and is spendable with an empty `scriptSig` at the +script layer. All protection comes from the following consensus rules, active +from deployment activation: + +* **Creation:** an output whose `scriptPubKey` equals the template is valid + only as the collateral output of a valid shared registration. Any other + creation — in a normal transaction, a coinbase, another special transaction, + or a non-collateral output of the registration itself — is invalid. +* **Spending:** a transaction spending an output whose `scriptPubKey` equals + the template is valid only if it is a valid ProDisTx whose referenced + masternode owns that outpoint. + +A template output mined before activation (necessarily created deliberately, +against a pattern reserved by this published DIP, and nonstandard to relay) +becomes permanently unspendable at activation. This follows the established +reserved-pattern upgrade path and affects only coins whose owner explicitly +opted in. + +### Collateral Share + +Each share has the following structure: + +| Field | Type | Size | Description | +| --- | --- | --- | --- | +| amount | int64_t | 8 | Collateral contribution in duffs. | +| refundScriptSize | compactSize uint | 1-9 | Size of the refund script. | +| refundScript | Script | Variable | Immutable principal refund script (P2PKH/P2SH). | +| rewardScriptSize | compactSize uint | 1-9 | Size of the reward script. | +| rewardScript | Script | Variable | Reward payout script (P2PKH/P2SH). Zero length means "use refundScript". | +| ownerKeyID | CKeyID | 20 | Immutable share owner key ID. | + +For shared registrations, the following fields are appended to the version 4 +ProRegTx payload immediately after the `payouts` field defined in DIP-0026: + +| Field | Type | Size | Description | +| --- | --- | --- | --- | +| sharesCount | uint8_t | 1 | Number of shares. 0 = not shared; otherwise 2 to 8. | +| shares | CollateralShare[] | Variable | The share table, in consensus-significant order. | +| joinSigs | signature[sharesCount] | 65 * sharesCount | One registration consent signature per share, in share order. | +| earlyPeriodBlocks | uint32_t | 4 | Length of the early period in blocks. | +| earlyPenalty | int64_t | 8 | Penalty in duffs for unilateral dissolution during the early period. | + +All signatures introduced by this DIP (`joinSigs` and ProDisTx signatures) are +65-byte compact recoverable ECDSA signatures with **enforced low-S** (the +signature scheme used for owner-key payload signatures in DIP-0003). High-S +signatures are invalid. This, combined with the digest rules below, makes the +affected transaction identifiers non-malleable by third parties. + +### Registering a Shared Masternode + +A shared registration (version 4 ProRegTx, `sharesCount > 0`) is valid only if +all of the following hold, in addition to DIP-0003 rules not explicitly +replaced here: + +1. The deployment (see [Deployment and Compatibility](#deployment-and-compatibility)) + is active. +2. `type` is 0 (Regular masternode). Shared Evo masternodes are out of scope + (see [Rationale](#rationale)). +3. The collateral is internal: `collateralOutpoint.hash` is null and + `collateralOutpoint.n` points at an output of this transaction whose value + equals the required collateral and whose `scriptPubKey` is exactly the + template. +4. The DIP-0026 `payouts` list is empty (owner rewards derive from the share + table) and the legacy `scriptPayout` is absent per version 4. +5. `keyIdOwner` is all zeros. The share owner keys replace it. +6. `sharesCount` is between 2 and 8 inclusive. +7. Every share `amount` is at least 100 DASH, and the amounts sum exactly to + the required collateral. +8. `0 <= earlyPenalty < min(share amounts)`, and `earlyPeriodBlocks` does not + exceed 420480 blocks (approximately two years at 2.5-minute blocks). +9. No two shares have the same `ownerKeyID`; no share `ownerKeyID` equals any + owner key registered by any other masternode (see + [Masternode List State](#masternode-list-state)); duplicate `refundScript`s + within the share table are invalid; duplicate `rewardScript`s are allowed. +10. No `refundScript` or `rewardScript` pays P2PK or P2PKH to any share + `ownerKeyID` in the table or to `keyIdVoting` (extends the DIP-0026 + payee-reuse rules), and none equals the template + (see [Forbidden Template Destinations](#forbidden-template-destinations)). +11. The external-collateral `payloadSig` is empty, and each entry of `joinSigs` + is a valid canonical signature by the corresponding share's `ownerKeyID` + over `SharedRegConsentHash`. + +`SharedRegConsentHash` is the double-SHA256 of the serialization of: + +```text +"DashSharedMNReg" || payload version || +tx version || tx type || tx nLockTime || +inputsHash || outputsHash || +type || mode || netInfo and Platform fields || +keyIdVoting || pubKeyOperator || operatorReward || +shares || earlyPeriodBlocks || earlyPenalty +``` + +where `inputsHash` and `outputsHash` are as defined in DIP-0003, and `shares` +is the serialized share table. Consent therefore binds every participant to the +exact funding inputs, all outputs (including the collateral output and every +change output), the full share table, the penalty terms, and the registrar +configuration. Consent never relies on the sighash modes of funding-input +signatures, because Dash transaction signatures permit `SIGHASH_NONE`, +`SIGHASH_SINGLE`, and `SIGHASH_ANYONECANPAY`. + +Registration is atomic: if any funding input is double-spent or any participant +withholds a `joinSig`, no shared masternode is created and no participant's +funds move. Co-signer transaction-identifier malleability is harmless: nothing +is pre-signed against the registration txid, and the consent digest binds to +prevouts and outputs, which malleation cannot change. + +### Dissolving a Shared Masternode (ProDisTx) + +This DIP introduces a new special transaction type: + +| Name | Special transaction type | +| --- | --- | +| ProDisTx | 10 | + +Payload: + +| Field | Type | Size | Description | +| --- | --- | --- | --- | +| version | uint16_t | 2 | Payload version. Currently 1. | +| proTxHash | uint256 | 32 | The ProRegTx hash of the shared masternode. | +| actorIndex | uint16_t | 2 | Index into the share table of the actor. | +| sigCount | uint8_t | 1 | Number of signatures: exactly 1 (unilateral) or exactly `sharesCount` (unanimous). | +| sigs | signature[sigCount] | 65 * sigCount | Canonical signatures over `SharedDisHash`. | + +There is no mode field: **the signature count defines the mode**. Exactly one +signature — which must be by `shares[actorIndex].ownerKeyID` — is a unilateral +dissolution. Exactly `sharesCount` signatures — one per share, in share order — +is a unanimous dissolution. Any other count, order, or signer set is invalid. +The signature count is committed into `SharedDisHash` (below), so the mode is +bound into every signature: a third party cannot reinterpret a penalty-free +unanimous dissolution as a unilateral one (or vice versa) by dropping or adding +signatures, which would otherwise leave the inputs and outputs unchanged but +alter the transaction identifier. + +A ProDisTx must have exactly one input: the masternode's collateral outpoint, +with an empty `scriptSig`. It must have no outputs other than those required +below. + +`SharedDisHash` is the double-SHA256 of the serialization of: + +```text +"DashSharedMNDissolve" || payload version || +tx version || tx type || tx nLockTime || +all input prevouts || all input sequences || all outputs || +proTxHash || actorIndex || sigCount +``` + +The digest commits to the transaction's actual input and outputs directly; the +payload deliberately carries no `inputsHash`/`outputsHash` copies. It also +commits to `sigCount`, which selects the mode, so the unilateral/unanimous +distinction cannot be malleated after signing. + +#### Required penalty + +```text +early = (spendHeight - registeredHeight) < earlyPeriodBlocks +requiredPenalty = (unanimous or not early) ? 0 : earlyPenalty +``` + +`spendHeight` is the height of the block containing the ProDisTx and +`registeredHeight` is the masternode's registration height. `requiredPenalty` +can only step from `earlyPenalty` to zero as the chain advances, so it is +non-increasing in `spendHeight`. + +#### Output rules + +All output rules are **minimum-based**: paying more penalty than required is +always valid. Because `requiredPenalty` is non-increasing, a ProDisTx that is +valid at height `h` is valid at every height `h' >= h`: no dissolution is +silently invalidated by chain progress. The converse is intentionally not true: +a unilateral ProDisTx paying no penalty is invalid until the early period ends. + +Let `a = actorIndex`, `W` = the sum of non-actor share amounts, and +`P = requiredPenalty`. A ProDisTx is valid only if: + +1. `actorIndex < sharesCount`. +2. There is exactly one output per non-actor share `i`, paying + `shares[i].refundScript`, in share order, plus optionally one final output + paying `shares[a].refundScript` (the actor output). A zero-value actor + output must be omitted. No other outputs are permitted. +3. For each non-actor output, with `bonus[i] = value[i] - shares[i].amount`: + `bonus[i] >= floor(P * shares[i].amount / W)`. +4. The sum of all `bonus[i]` is at least `P`. + +Everything not paid to these outputs is the transaction fee, which by value +conservation can only come from the actor's share; the actor output is +therefore implicitly capped at `shares[a].amount - P`. + +The per-recipient minimum in rule 3 uses a plain floor with no remainder +assignment: floors are element-wise monotone in `P`, whereas any remainder +assignment rule is not, and would break monotone validity. Rule 4 forces the +sub-duff remainder onto some non-actor output. The pro-rata floors also prevent +the actor from concentrating the penalty into a colluding share beyond rounding +dust. Constructors should build outputs with the same sequential-floor, +remainder-to-last convention that DIP-0026 uses for rewards; that construction +always satisfies the minimums. + +When a valid ProDisTx is confirmed, the masternode is removed from the +deterministic masternode list. Confirmed reward-script or registrar updates +never invalidate a pending ProDisTx (its digest references none of those +fields); the only transaction that can displace a pending ProDisTx is a +competing ProDisTx, which conflicts on the collateral input. + +#### Fees and standby dissolutions (non-normative) + +Dash relay supports neither BIP125 replacement nor package relay, so a ProDisTx +must embed a sufficient fee at signing time; child-pays-for-parent on the actor +output can only raise the mining priority of a ProDisTx that already meets the +minimum relay fee. A flat fee of roughly 100000 duffs — about one millionth of +the minimum share — provides large fee-market headroom. Because Dash relay has +no replacement mechanism, the first ProDisTx to reach the mempool for a given +collateral wins; a competing ProDisTx conflicts on the collateral input and is +rejected until the first is mined or dropped. + +Because validity is monotone and share owner keys are immutable, a signed +ProDisTx never goes stale. Wallets should have each participant sign a +**standby dissolution** immediately after registration confirms — unilateral, +paying `earlyPenalty` (valid immediately and forever) or no penalty (valid from +the end of the early period, forever) — and store it with the participant's +refund-key backup, separately from the owner key. If the owner key is later +lost, broadcasting the standby recovers the participant's principal without any +other party's cooperation. A leaked standby is griefing-only: every output is +covenant-fixed, so its holder can trigger the exit (costing the signer the +penalty) but cannot redirect any value. + +### Updating a Share (ProUpShareTx) + +| Name | Special transaction type | +| --- | --- | +| ProUpShareTx | 11 | + +Payload: + +| Field | Type | Size | Description | +| --- | --- | --- | --- | +| version | uint16_t | 2 | Payload version. Currently 1. | +| proTxHash | uint256 | 32 | The ProRegTx hash of the shared masternode. | +| shareIndex | uint16_t | 2 | Index into the share table of the share being updated. | +| rewardScriptSize | compactSize uint | 1-9 | Size of the new reward script. | +| rewardScript | Script | Variable | New reward script (P2PKH/P2SH), or zero length for "use refundScript". | +| inputsHash | uint256 | 32 | Hash of all transaction inputs, as in DIP-0003 update payloads. | +| payloadSig | signature | 65 | Canonical signature by `shares[shareIndex].ownerKeyID` over the payload hash (with this field empty). | + +A ProUpShareTx updates exactly one share's `rewardScript` and nothing else. +Share `amount`, `refundScript`, `ownerKeyID`, the participant count, the +penalty, and the early period are immutable for the life of the masternode. The +new reward script is subject to the same script-type, payee-reuse, and template +restrictions as at registration. A ProUpShareTx referencing a non-shared +masternode is invalid. + +### Updating the Shared Registrar (ProUpSharedRegTx) + +| Name | Special transaction type | +| --- | --- | +| ProUpSharedRegTx | 12 | + +Payload: + +| Field | Type | Size | Description | +| --- | --- | --- | --- | +| version | uint16_t | 2 | Payload version. Currently 1. | +| proTxHash | uint256 | 32 | The ProRegTx hash of the shared masternode. | +| pubKeyOperator | BLSPubKey | 48 | New operator public key. | +| keyIdVoting | CKeyID | 20 | New voting key ID. | +| inputsHash | uint256 | 32 | Hash of all transaction inputs, as in DIP-0003 update payloads. | +| sigCount | uint8_t | 1 | Must equal `sharesCount`. | +| sigs | signature[sigCount] | 65 * sigCount | Canonical signatures over the payload hash (with this field empty), one per share, in share order. | + +A ProUpSharedRegTx updates the whole-masternode registrar fields and requires +one valid signature from **every** current share owner key, in share order. +Operator-key change semantics (service reset) match ProUpRegTx in DIP-0003. A +ProUpSharedRegTx referencing a non-shared masternode is invalid, and a plain +ProUpRegTx referencing a shared masternode is invalid. + +The operator reward is fixed at registration and is not updatable, matching the +DIP-0003 ProUpRegTx model (where `operatorReward` is likewise immutable after +registration); it is therefore not carried in this payload. + +Operator-authorized updates are unchanged: the operator continues to manage +service fields via ProUpServTx (including the operator payout script) and may +revoke via ProUpRevTx. The operator can stop service but cannot spend +collateral, redirect owner rewards, or rewrite ownership. + +### Masternode List State + +Deterministic masternode state for a shared masternode must store the share +table (without `joinSigs`, which are needed only at registration validation), +`earlyPeriodBlocks`, and `earlyPenalty`. State diffs must report the share +table as a single logical field: any change to a mutable share field includes +the full replacement share table. + +Owner-key uniqueness is enforced across the whole masternode list in both +directions: a share `ownerKeyID` must not equal any other masternode's +registered owner key (shared or `keyIdOwner`), and a normal registration must +not reuse any active share owner key. + +Share data is excluded from the simplified masternode list entry hash +(`CSimplifiedMNListEntry`), matching DIP-0026's treatment of payout data. +Extended JSON forms may expose shares for diagnostics; this is not a +light-client commitment. Full nodes validate shared rewards and dissolutions +from deterministic masternode state reconstructed from blocks. + +### Masternode Reward Payments + +Reward payment construction for a shared masternode follows the DIP-0026 +procedure exactly, with the owner payout entries derived from the share table: + +* the entry ordering is the share-table order; +* the entry weight is the share `amount` (instead of basis points), so entry + `i` (except the last) receives `floor(ownerReward * amount[i] / collateral)` + and the last entry receives the remainder; +* the entry destination is the share's `rewardScript` if non-empty, otherwise + its `refundScript`; +* zero-amount outputs are omitted, and operator reward handling is unchanged. + +This reuses DIP-0026's single rounding convention (sequential floor, remainder +to the last entry) rather than introducing a second one. + +### Collateral Spend Enforcement + +Template rules cannot live only inside provider-transaction checks. Consensus +implementations must enforce, at both mempool acceptance and block connection: + +1. **Spend check:** for every transaction, if any input's previous output + script equals the template, the transaction must be a valid ProDisTx + spending that outpoint. This is a constant exact-script comparison per + input; the masternode list is consulted only inside ProDisTx validation. +2. **Creation check:** any transaction output whose script equals the template, + outside the collateral slot of a valid shared registration, is invalid. +3. Block-level validation evaluates ProDisTx against the deterministic + masternode list as of the previous block plus earlier transactions in the + same block (a masternode may be registered and dissolved within one block). +4. Masternode removal for a shared masternode occurs only through a validated + ProDisTx. Collateral-spend removal semantics for normal masternodes are + unchanged (normal collateral never carries the template). +5. A validated ProDisTx removes its masternode in the same collateral-spend + phase of deterministic-list construction as an ordinary collateral spend — + that is, after all of the block's provider transactions (registrations and + updates) have been applied. The dissolution is validated at its position in + the transaction order (so it sees the masternode and any earlier same-block + registration), but the removal itself is deferred to that phase. A shared + masternode update (ProUpShareTx or ProUpSharedRegTx) and a dissolution of the + same masternode may therefore appear together in one block in either order: + the update always applies before the removal takes effect. + +Mempool implementations should additionally evict pending ProUpShareTx and +ProUpSharedRegTx transactions for a masternode when its ProDisTx confirms. + +### Forbidden Template Destinations + +Because template outputs may only be created inside shared registrations, any +consensus-mandated output paying the template would be unconstructable and +could deadlock consensus. Validation must therefore reject the template script +wherever a user-supplied script later becomes a consensus-mandated output: + +* share `refundScript` and `rewardScript` values (registration and + ProUpShareTx) — a template refund script would make every dissolution + invalid, freezing the collateral forever; +* every provider-transaction payout script for every masternode type and + payload version, including DIP-0026 payout entries and the operator payout + script — a template payout would make the coinbase unconstructable when that + masternode is paid; +* governance proposal and trigger payment scripts (validated after + activation) — a template payee would invalidate the superblock carrying it; +* asset-unlock (credit withdrawal) destinations — a template destination would + make the withdrawal transaction invalid. + +### Special Transaction Filtering + +A shared **registration** carries the full share table, so special transaction +filters and bloom filters must match it on every share `refundScript`, +`rewardScript`, and `ownerKeyID`, in the same manner that DIP-0026 requires for +payout scripts. + +The lifecycle transactions do not carry the share table — only the `proTxHash` +identifying the masternode — so, consistent with the DIP-0003 treatment of +ProUpRegTx and ProUpRevTx, they are matched by `proTxHash` (plus the new +`rewardScript` for ProUpShareTx). A light client learns a masternode's share +scripts and owner keys from the registration it matched, then follows that +masternode's lifecycle by its `proTxHash`. Two properties make this sufficient +in practice: the refund and reward payments produced by a ProDisTx are ordinary +transaction outputs, matched by script in the base filter, so a client watching +its refund or reward script sees its funds without any special-transaction +logic; and a BIP37 bloom filter with `BLOOM_UPDATE_ALL` inserts the `proTxHash` +automatically when it matches the registration, so an owner-key watcher receives +subsequent lifecycle transactions without further configuration. + +Requiring stateless filters to match the lifecycle transactions on the share +`ownerKeyID`s is not possible, because those transactions do not contain the +keys and filter construction performs no masternode-list lookup. + +## Deployment and Compatibility + +This DIP deploys with Dash Core's v24 network upgrade (`DEPLOYMENT_V24`, +an Enhanced Hard Fork per [DIP-0023](dip-0023.md)), together with DIP-0026. + +Before activation: + +* Shared registrations, ProDisTx, ProUpShareTx, and ProUpSharedRegTx are + invalid. +* Creating template-scripted outputs is nonstandard but not consensus-invalid. + +After activation: + +* All rules in this DIP apply. +* Template outputs created before activation are permanently unspendable. +* Existing masternodes (legacy and DIP-0026 version 4 non-shared) are + unaffected. Normal masternode collateral-spend semantics are unchanged. + +Shared registration is restricted to Regular masternodes in this version. +Extending shared ownership to Evo masternodes requires a Platform-side +specification for distributing Platform credits according to the share table; +without it, Platform-side rewards would not follow the consensus split and +would reintroduce the trust this DIP removes. + +## Rationale + +### Why a consensus covenant instead of multi-signature scripts + +Dash lacks SegWit and Taproot, so transaction identifiers are malleable by +co-signers and pre-signed refund transactions are unsafe. A P2SH multi-sig +collateral script would additionally freeze funds if signers disappear and +cannot express per-participant refund amounts. Recording ownership in the +provider payload and enforcing spends in consensus — the same trust model as +DIP-0003's deterministic masternode lists — avoids both problems. The price is +that the collateral output is anyone-can-spend at the script layer on any chain +that does not enforce these rules; see +[Security Considerations](#security-considerations). + +### Why the template is pattern-restricted on both creation and spend + +Restricting creation makes the template a trustworthy marker: after activation, +every template output is live shared collateral. Restricting spending by +pattern (rather than by masternode-list lookup) makes the per-input hook a +constant script comparison and closes every path to such an output. Freezing +the (deliberately created, nonstandard) pre-activation outputs follows the +SegWit reserved-pattern precedent and affects only opt-in coins. Exact-script +matching keeps the reserved set to a single 7-byte script. + +### Why share owner keys cannot be rotated + +Rotation authorization would rest on the very key being replaced, so under key +compromise rotation is first-mover-wins: a thief who rotates first locks the +honest participant out of their own share permanently. With immutable keys, +compromise is a standoff in which the honest holder always retains the right to +dissolve, and principal is protected by the immutable refund script in every +scenario. Share owner keys sign only rare deliberate events and should be held +in cold storage; custody migration uses a penalty-free unanimous dissolution +followed by re-registration. Immutability also makes dissolution validity +unconditional: no confirmed transaction can stale a pending ProDisTx's +signatures. + +### Why dissolution outputs are minimum-based + +Exact-amount output rules would make a unilateral ProDisTx signed near the +early-period boundary silently consensus-invalid one block later (the required +penalty changes with height, so the exact amounts change). Minimum-based rules +with a non-increasing required penalty make validity monotone: once valid, +always valid. This property is also what makes standby dissolutions safe to +sign years in advance. + +### Why the penalty is redistributed rather than burned or waived + +Redistribution compensates remaining participants for losing their node and +payment-queue position. Burning would punish the innocent majority to deny a +hypothetical griefer a small bonus. A penalty waiver triggered by sustained +PoSe ban was considered and rejected: the operator controls PoSe status, and in +practice a participant is often the operator, so a waiver lets a participant +deliberately get the node banned and exit penalty-free during the early period, +converting "the leaver compensates the others" into "everyone loses". There is +exactly one penalty and it applies only to unilateral exits during the early +period; free exit afterwards is structural. + +### Why the mode is derived from the signature count + +A ProDisTx with one signature is unilateral; with all `sharesCount` signatures +it is unanimous. An explicit mode byte would be redundant with the signature +count and require a consistency cross-check. Both modes share one output-rule +regime because the minimum-based rules degenerate cleanly to +"each participant receives at least their share" when the required penalty is +zero. + +### Why this extends provider transaction version 4 + +DIP-0026's version 4 has not shipped, so folding shared collateral into the +same version avoids an additional version solely for field layering, at the +cost of a wire-format change to an unreleased payload version. The two DIPs +deploy together in v24. + +### Bounds + +Two to eight participants matches the DIP-0026 payout-entry cap and bounds +coinbase fan-out and masternode state size. The 100 DASH minimum share keeps +shares meaningful and bounds fragmentation. The two-year cap on the early +period prevents unbounded penalty windows. `earlyPenalty < min(share amounts)` +guarantees the actor a positive remainder, so a dissolution can always pay its +own fee. + +## Test Cases + +Implementations should include tests for at least the following: + +1. A valid shared registration with 2 and with 8 participants. +2. Invalid: shared Evo registration; external shared collateral; share sum not + equal to the collateral; share below 100 DASH; `earlyPenalty >= min(share)`; + early period above the cap; non-empty DIP-0026 `payouts` with shares; + non-zero `keyIdOwner`. +3. Invalid: duplicate share owner key within the table or across masternodes + (both directions with normal masternodes); duplicate refund scripts; + refund or reward script paying P2PKH to any share owner key or the voting + key; refund or reward script equal to the template. +4. Invalid: missing or non-canonical (high-S) `joinSig`; consent digest + mismatch after changing any covered field. +5. Invalid: any normal transaction spending a template output; post-activation + template-output creation in a normal transaction, a coinbase, or a + non-collateral output of a shared registration. A near-miss script (template + plus or minus a byte) is unrestricted. A pre-activation template output is + permanently unspendable. +6. Valid: unilateral dissolution during the early period paying `earlyPenalty`; + unilateral dissolution after the early period paying no penalty; a + dissolution signed during the early period confirming after the boundary + (monotonicity); overpaying the penalty; unanimous dissolution paying no + penalty at any height. +7. Invalid: unilateral dissolution paying no penalty inside the early period; + any per-recipient floor violation; bonus sum below the required penalty; + redirected or reordered refund outputs; extra outputs; extra inputs; + non-empty `scriptSig` on the collateral input; wrong actor signature; + signature count other than 1 or `sharesCount`; unanimous signatures out of + share order. +8. Registration and dissolution of the same masternode within one block. +9. A pending dissolution remains valid across confirming ProUpShareTx and + ProUpSharedRegTx transactions; a standby dissolution signed at registration + broadcasts successfully after the early-period boundary. +10. ProUpShareTx updates exactly one reward script with the correct single + signature; invalid for wrong signer, non-shared masternode, or any attempt + to alter immutable fields. ProUpSharedRegTx requires all signatures in + share order; plain ProUpRegTx is invalid for a shared masternode. +11. Reward split across mined blocks: conservation, remainder to the last + entry, zero-output omission, operator reward interaction, reward script + fallback to refund script. +12. Reorg across registration, across the early-period boundary, and across + update-then-dissolution ordering; restart from a deterministic masternode + list snapshot before and after shared state changes. +13. Filter matching for every share refund script, reward script, and owner + key. + +## Security Considerations + +**Non-enforcing chains.** The template is anyone-can-spend at the script layer. +On any chain that does not enforce this DIP — non-upgraded software, a chain +split, a hypothetical future consensus regression — shared collateral outputs +are freely spendable. The protection is the hard fork itself: theft can only +"succeed" on chains that are economically meaningless to the participants. This +trade-off is inherent to consensus covenants on a chain without script-level +covenant support and must be accepted with eyes open. + +**Key separation.** The share owner key is control plane, never a fund +destination. The central guarantee — owner-key compromise cannot steal +principal — holds only because the refund destination is independent of the +owner key: a thief who dissolves as the victim still pays the principal to a +script they cannot spend. This is why refund and reward scripts must not pay to +share owner keys, and why wallets must not derive refund destinations from +owner keys even in forms consensus cannot detect (such as inside P2SH). + +**Key compromise.** A stolen share owner key allows redirecting that share's +future rewards and triggering a penalized unilateral dissolution — never +principal theft. Because keys cannot be rotated, victim and thief hold +identical capabilities; the honest holder always retains the exit right. + +**Key loss.** Principal is never endangered: any other participant's unilateral +dissolution refunds the key-less participant in full, and outside the early +period this costs the rescuer only the transaction fee. A key-less participant +cannot force exit, one lost key permanently disables the unanimous and +whole-masternode update paths, and losing all owner keys freezes the collateral +forever. Standby dissolutions (see above) reduce all of these to "keep your +standby with your refund-key backup". + +**Hostage and griefing dynamics.** A participant who refuses to sign +whole-masternode updates can degrade the node (for example, blocking operator +key replacement), and an honest leaver both pays the early penalty and pays a +pro-rata slice of it to the obstructive participant. This is bounded: the +initially configured operator key keeps working indefinitely, exit after the +early period is penalty-free, and the early penalty is a term every participant +consented to at formation. Wallets must present penalty terms prominently, and +must warn that a zero `earlyPenalty` permits cheap early griefing. + +**Transaction-identifier malleability.** The covenant input's empty-`scriptSig` +rule and the low-S requirement on all payload signatures pin every free byte of +a ProDisTx; inputs, sequences, outputs, and lock time are covered by the signed +digest. Without these rules, third parties could mutate a pending dissolution's +txid, breaking child-pays-for-parent fee bumps. + +**Forbidden destinations.** The list in +[Forbidden Template Destinations](#forbidden-template-destinations) is +consensus-critical: missing any entry creates either permanently frozen +collateral or an unconstructable coinbase (a consensus deadlock) via a crafted +script. + +## Privacy Considerations + +Shared ownership is consensus-visible by construction: + +* the share table — amounts, owner key IDs, refund scripts, reward scripts, and + penalty terms — is public on-chain forever; +* every payout block creates up to 8 owner outputs that persistently cluster + the co-owners' scripts with each other and with the masternode; +* the immutable refund script is an address pre-commitment made years before + the exit that eventually pays it. + +Wallets should use fresh keys and destinations for every formation, never reuse +a refund destination across formations or with other on-chain activity, and may +rotate reward scripts freely. Participants who want unlinkability between their +share and their other funds must break the link before funding (for example, +by mixing the funding inputs); note that refunds return as large, +non-denominated outputs. + +## Copyright + +Copyright (c) 2026 Dash Core Group, Inc. [Licensed under the MIT License](https://opensource.org/licenses/MIT) diff --git a/project-words.txt b/project-words.txt index 85f03cf8..b6312e7d 100644 --- a/project-words.txt +++ b/project-words.txt @@ -10,6 +10,7 @@ CBLS CBLSIES cbitset CBOR +ANYONECANPAY chainwork CHECKDATASIG CHECKDATASIGVERIFY @@ -31,6 +32,7 @@ dptp dpts DSPC DVRF +DSHC ECDH ecdh evonode @@ -55,6 +57,9 @@ Keybase libsecp LLMQ Masternode +malleate +malleated +malleation masternodes mainnet MERKLEBLOCK @@ -70,6 +75,8 @@ preorder Preorder preordered prevout +prevouts +ProUpServTx protx pseudorandomness QDATA @@ -92,6 +99,8 @@ RIPEMD sendheaders SEPA signmessage +sighash +SIGHASH Skiplist Spork subtx @@ -104,6 +113,9 @@ topups tprv tpub unretrievable +unconstructable +unlinkability +trustlessly UTXO varint vvec @@ -162,4 +174,4 @@ Udjin Udjinm Virgile Westrich -Wray \ No newline at end of file +Wray