Skip to content

docs: add decentralized masternode shares draft DIP#185

Draft
thepastaclaw wants to merge 12 commits into
dashpay:masterfrom
thepastaclaw:docs/dip-decentralized-mn-shares
Draft

docs: add decentralized masternode shares draft DIP#185
thepastaclaw wants to merge 12 commits into
dashpay:masterfrom
thepastaclaw:docs/dip-decentralized-mn-shares

Conversation

@thepastaclaw

@thepastaclaw thepastaclaw commented Jun 20, 2026

Copy link
Copy Markdown

Summary

Adds a draft, unnumbered DIP for Decentralized Masternode Shares.

The draft builds on DIP-0003, DIP-0023, DIP-0026 v4, and DIP-0028 to specify shared-collateral masternode registration, per-share reward distribution, participant-authorized updates, and constrained dissolution.

Also adds:

  • README discoverability for the draft DIP using the TBD placeholder until editor assignment.
  • Proposed DIP-0002 special transaction type registry rows for:
    • 10ProDisTx
    • 11ProUpShareTx
    • 12ProUpSharedRegTx
  • cspell vocabulary needed by the new draft and touched README text.

Dependency / review note

This PR is intentionally draft-blocked on #184, which updates DIP-0026 to the v4 provider-payload semantics this draft references. The shared-masternode branch has been reviewed against that DIP-0026 v4 base; once #184 lands, this PR should become repository-consistent without bundling the DIP-0026 changes here.

Open design feedback to resolve before ready-for-review: whether shared-collateral semantics should remain a separate provider payload version (SharedCollateral = 5, as currently drafted) or be folded into a single version that supports both shared and non-shared masternodes via an explicit flag or share-count discriminator.

Notes for editors/reviewers

  • The DIP intentionally remains DIP: TBD and uses the alias filename dip-decentralized-masternode-shares.md; authors must not self-assign DIP numbers.
  • Transaction type values 10, 11, and 12 are registered here as proposed values for this draft. If any value is consumed before merge, this DIP must be updated to the next free values before merge.
  • Deployment parameters, including the final DIP-0023 deployment name and SHARED_MIN_SHARE_DUFFS, remain explicitly open before activation.
  • This is spec/docs only. No Dash Core implementation is included in this PR.

Validation

  • git diff --check
  • npx cspell --no-progress README.md dip-decentralized-masternode-shares.md dip-0002/special-transactions.md
  • npx markdownlint-cli2 README.md dip-decentralized-masternode-shares.md dip-0002/special-transactions.md --config .markdownlint.json
  • Mandatory pre-PR code-review gate against the intended DIP-0026 v4 base (fix/dip26-review-followup...docs/dip-decentralized-mn-shares): ship

@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8659bf03-f290-4864-bb90-0b676f5fc1b2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

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

@thepastaclaw

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@thepastaclaw

thepastaclaw commented Jun 20, 2026

Copy link
Copy Markdown
Author

✅ Review complete (commit b64a580)

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Code Review

Two convergent blocking findings on the v5 shared-masternode draft: the registration-consent sharesWithoutJoinSigs serialization is consensus-ambiguous, and the ProUpShareTx / ProUpSharedRegTx authorization digests sign nLockTime without binding input sequences (asymmetric with the registration and dissolution digests that already commit to sequences). One additional blocking issue: the draft claims DIP-0026 occupies provider payload version 4, but DIP-0026 in this repo currently specifies version 2, leaving the version ladder for SharedCollateral = 5 undefined. Two nitpicks on a wording inconsistency for the ProUpShareTx key-reuse rule and a logically inconsistent reorg test case.

🔴 3 blocking | 💬 2 nitpick(s)

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `dip-decentralized-masternode-shares.md`:
- [BLOCKING] dip-decentralized-masternode-shares.md:514-516: `sharesWithoutJoinSigs` serialization is ambiguous and consensus-critical
  The text says `sharesWithoutJoinSigs` is the concatenation of every CollateralShare with the `joinSig` field `omitted (treated as a zero-length byte string)`. Two reasonable readings produce different byte sequences and therefore different SharedRegConsentHash values:

  1. The `joinSig` field is omitted entirely — no bytes at all in the concatenation.
  2. The `joinSig` field is serialized as a zero-length compact-size bytestring — i.e., the single byte `0x00` (compact-size length 0, followed by no payload bytes), preserving the field's framing.

  `CollateralShare` (line 339) defines `joinSig` as `vector<unsigned char>  (compact-size length-prefixed, ...)`, which makes interpretation (2) the natural literal reading of `serialize(share)` with an empty vector — yet the word `omitted` suggests (1). Because every participant signs this digest and consensus recomputes it to verify `joinSig`, divergent implementations would either reject otherwise-valid v5 registrations or, once one implementation is patched, cause a chain split. The DIP must pin one encoding normatively and ideally show pseudocode (e.g., `serialize(share) with joinSig replaced by compact_size(0)` vs. `serialize(share) skipping the joinSig field entirely`).
- [BLOCKING] dip-decentralized-masternode-shares.md:573-636: ProUpShareTx and ProUpSharedRegTx digests sign nLockTime without binding input sequences
  The registration digest (line 468) commits to `sequencesHash`, and the dissolution digest (line 775) explicitly commits to `tx.vin[0].nSequence`; in both cases the DIP states the reason is to stop a coordinator/fee-payer from changing finality, RBF, or `nLockTime` semantics after participants sign (lines 500–504, 783–787). The ProUpShareTx digest (lines 573–580) and the ProUpSharedRegTx digest (lines 628–636) commit only to `inputsHash`, `tx.nLockTime`, and `tx.nVersion`/`tx.nType`; they bind no input `nSequence`.

  Because `nLockTime` is only enforced when at least one input has a non-final sequence, a party that controls or replaces the funding input signatures (which need not be SIGHASH_ALL/AC-payable in a way that commits to sequences) can flip an input to a final sequence after the participant signs, effectively neutralising the signed `nLockTime` (e.g., causing a future-dated reward-script update or shared-registrar update to take effect immediately). The risk is particularly acute for ProUpSharedRegTx, where every participant signs but a separate broadcaster/fee-payer typically supplies the funding inputs.

  Mirror the registration/dissolution model by adding `sequencesHash` (or an enumerated commitment to each input's `nSequence`) to both update digests, or — if the omission is deliberate because these updates do not bind finality — add a normative one-line note explaining why and remove `nLockTime` from these digests so implementers do not believe the spec enforces something it does not.
- [BLOCKING] dip-decentralized-masternode-shares.md:111-116: Provider payload versioning conflicts with the referenced DIP-0026
  This draft normatively claims `DIP-0026 introduces provider transaction payload version 4 (MultiPayout)` and then allocates `SharedCollateral = 5` for v5. The DIP-0026 document checked into this repository (`dip-0026.md` line 46) says it introduces `version 2` of ProRegTx/ProUpRegTx with `payoutShares`/`payoutSharesSize`, and makes no claim about versions 3 or 4. As a result, implementers reading only the merged DIPs cannot determine whether DIP-0026 is v2 or v4, what occupies version 3, or whether `SharedCollateral` should actually be version 3 (next free after DIP-0026) rather than version 5.

  The provider payload version is a consensus selector, so this is the kind of registry mismatch the review guidance flags as blocking. Either amend DIP-0026 in this repo to match (renumber its payload to v4 and reserve v3 / specify what it is), or change this DIP's version allocation to be consistent with DIP-0026 as merged. The 'Open Issues' section does not currently cover this dependency, so add it there or in 'Relationship to DIP-0026' with the resolution path.

Comment thread dip-decentralized-masternode-shares.md Outdated
Comment on lines +514 to +516
* `sharesWithoutJoinSigs` is the concatenation of every `CollateralShare`
in share order with the `joinSig` field omitted (treated as a zero-length
byte string) so that signatures are not self-referential.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🔴 Blocking: sharesWithoutJoinSigs serialization is ambiguous and consensus-critical

The text says sharesWithoutJoinSigs is the concatenation of every CollateralShare with the joinSig field omitted (treated as a zero-length byte string). Two reasonable readings produce different byte sequences and therefore different SharedRegConsentHash values:

  1. The joinSig field is omitted entirely — no bytes at all in the concatenation.
  2. The joinSig field is serialized as a zero-length compact-size bytestring — i.e., the single byte 0x00 (compact-size length 0, followed by no payload bytes), preserving the field's framing.

CollateralShare (line 339) defines joinSig as vector<unsigned char> (compact-size length-prefixed, ...), which makes interpretation (2) the natural literal reading of serialize(share) with an empty vector — yet the word omitted suggests (1). Because every participant signs this digest and consensus recomputes it to verify joinSig, divergent implementations would either reject otherwise-valid v5 registrations or, once one implementation is patched, cause a chain split. The DIP must pin one encoding normatively and ideally show pseudocode (e.g., serialize(share) with joinSig replaced by compact_size(0) vs. serialize(share) skipping the joinSig field entirely).

source: ['claude']

Comment on lines +573 to +636
```text
SHA256d("DashSharedMNUpShare" ||
chainGenesisHash ||
LE16(tx.nVersion) || LE16(tx.nType) || LE32(tx.nLockTime) ||
inputsHash ||
LE16(payload.nVersion) ||
proTxHash || LE16(shareIndex) || newRewardScript)
```

`chainGenesisHash` is the 32-byte genesis block hash of the network
validating the transaction. `payload.nVersion` is the ProUpShareTx payload
version (currently `1`).

A valid `ProUpShareTx` replaces `shares[shareIndex].rewardScript` in the
deterministic masternode state. It does not revive a PoSe-banned masternode
and does not affect any other field.

#### ProUpSharedRegTx (type 12)

A `ProUpSharedRegTx` updates fields that affect all participants. In this
DIP the mutable shared-registrar fields are `pubKeyOperator`, `keyIDVoting`,
and `nOperatorReward`.

```text
CProUpSharedRegTx {
nVersion : uint16_t // MUST be 1 (payload version of this new special tx type)
proTxHash : uint256
pubKeyOperator : CBLSPublicKey // basic scheme
keyIDVoting : CKeyID
nOperatorReward : uint16_t
inputsHash : uint256
vchSigs : vector<vector<unsigned char>> // exactly shares.size() entries, in share order
}
```

As with `ProUpShareTx`, this `nVersion` is the independent payload version
of the new `TRANSACTION_PROVIDER_UPDATE_SHARED_REGISTRAR` special
transaction and is unrelated to `ProTxVersion::SharedCollateral = 5`.

Validation:

1. The masternode identified by `proTxHash` MUST exist and MUST be a v5
masternode.
2. `pubKeyOperator` MUST be a valid basic-scheme BLS public key and MUST
NOT collide with the operator key of any other registered masternode.
3. `keyIDVoting` MUST NOT equal any `shares[i].ownerKey`.
4. No current `refundScript` and no current effective `rewardScript` may be a
P2PKH script paying to `keyIDVoting`. For this check, an empty
`rewardScript` is interpreted as the corresponding `refundScript`.
5. `nOperatorReward <= 10000`.
6. `inputsHash` MUST equal `CalcTxInputsHash(tx)`.
7. `vchSigs.size()` MUST equal `shares.size()`.
8. For each `i` in `[0, shares.size())`, `vchSigs[i]` MUST be a valid
ECDSA compact signature by `shares[i].ownerKey` over:

```text
SHA256d("DashSharedMNUpSharedReg" ||
chainGenesisHash ||
LE16(tx.nVersion) || LE16(tx.nType) || LE32(tx.nLockTime) ||
inputsHash ||
LE16(payload.nVersion) ||
proTxHash || pubKeyOperatorSerialized ||
keyIDVoting || LE16(nOperatorReward))
```

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🔴 Blocking: ProUpShareTx and ProUpSharedRegTx digests sign nLockTime without binding input sequences

The registration digest (line 468) commits to sequencesHash, and the dissolution digest (line 775) explicitly commits to tx.vin[0].nSequence; in both cases the DIP states the reason is to stop a coordinator/fee-payer from changing finality, RBF, or nLockTime semantics after participants sign (lines 500–504, 783–787). The ProUpShareTx digest (lines 573–580) and the ProUpSharedRegTx digest (lines 628–636) commit only to inputsHash, tx.nLockTime, and tx.nVersion/tx.nType; they bind no input nSequence.

Because nLockTime is only enforced when at least one input has a non-final sequence, a party that controls or replaces the funding input signatures (which need not be SIGHASH_ALL/AC-payable in a way that commits to sequences) can flip an input to a final sequence after the participant signs, effectively neutralising the signed nLockTime (e.g., causing a future-dated reward-script update or shared-registrar update to take effect immediately). The risk is particularly acute for ProUpSharedRegTx, where every participant signs but a separate broadcaster/fee-payer typically supplies the funding inputs.

Mirror the registration/dissolution model by adding sequencesHash (or an enumerated commitment to each input's nSequence) to both update digests, or — if the omission is deliberate because these updates do not bind finality — add a normative one-line note explaining why and remove nLockTime from these digests so implementers do not believe the spec enforces something it does not.

source: ['claude', 'codex']

Comment on lines +111 to +116
DIP-0026 introduces provider transaction payload version `4` (`MultiPayout`).
Under DIP-0026 v4, the registrar owner remains the sole signer for ProRegTx
and ProUpRegTx, and may freely rewrite the payout list at any time.

This DIP does not modify DIP-0026 v4 semantics. Shared masternodes use a new
provider transaction payload version, `5` (`SharedCollateral`), with the

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🔴 Blocking: Provider payload versioning conflicts with the referenced DIP-0026

This draft normatively claims DIP-0026 introduces provider transaction payload version 4 (MultiPayout) and then allocates SharedCollateral = 5 for v5. The DIP-0026 document checked into this repository (dip-0026.md line 46) says it introduces version 2 of ProRegTx/ProUpRegTx with payoutShares/payoutSharesSize, and makes no claim about versions 3 or 4. As a result, implementers reading only the merged DIPs cannot determine whether DIP-0026 is v2 or v4, what occupies version 3, or whether SharedCollateral should actually be version 3 (next free after DIP-0026) rather than version 5.

The provider payload version is a consensus selector, so this is the kind of registry mismatch the review guidance flags as blocking. Either amend DIP-0026 in this repo to match (renumber its payload to v4 and reserve v3 / specify what it is), or change this DIP's version allocation to be consistent with DIP-0026 as merged. The 'Open Issues' section does not currently cover this dependency, so add it there or in 'Relationship to DIP-0026' with the resolution path.

source: ['codex']

Comment thread dip-decentralized-masternode-shares.md Outdated
Comment on lines +566 to +568
4. `newRewardScript` MUST satisfy the same key-reuse restrictions as
registration: it MUST NOT be a P2PKH paying to any
`shares[i].ownerKey` and MUST NOT pay to `keyIDVoting`.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

💬 Nitpick: ProUpShareTx key-reuse rule wording is inconsistent with registration rule 8

Registration rule 8 (lines 373–377) restricts refundScript/rewardScript from being a P2PKH script paying to the listed key IDs. ProUpShareTx rule 4 reads it MUST NOT be a P2PKH paying to any shares[i].ownerKey and MUST NOT pay to keyIDVoting. The second clause drops the P2PKH qualifier, so it can be read either as more restrictive (any script form paying to keyIDVoting, which is not well-defined for non-P2PKH templates) or as a wording slip. Aligning the wording with registration rule 8 removes the ambiguity for the consensus check.

Suggested change
4. `newRewardScript` MUST satisfy the same key-reuse restrictions as
registration: it MUST NOT be a P2PKH paying to any
`shares[i].ownerKey` and MUST NOT pay to `keyIDVoting`.
4. `newRewardScript` MUST satisfy the same key-reuse restrictions as
registration: it MUST NOT be a P2PKH paying to any
`shares[i].ownerKey` and MUST NOT be a P2PKH paying to `keyIDVoting`.

source: ['claude']

Comment on lines +1443 to +1444
4. A reorg that replays a `ProUpSharedRegTx` followed by a `ProDisTx`
in a different order produces the same final state.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

💬 Nitpick: Reorg test case 4 description is logically inconsistent

Test case 4 says A reorg that replays a ProUpSharedRegTx followed by a ProDisTx in a different order produces the same final state. Read literally, the two orders are [ProUpSharedRegTx, ProDisTx] and [ProDisTx, ProUpSharedRegTx]. Under this spec a valid ProDisTx removes the masternode entry, so the subsequent ProUpSharedRegTx against the same proTxHash would be invalid (the masternode no longer exists). The two orders cannot both produce the same successful final state. Reword so the test target is unambiguous (e.g., independent updates on disjoint masternodes interleaved across a reorg, or that disconnect-then-reconnect reproduces the original deterministic state regardless of intra-block ordering).

source: ['claude']

@thepastaclaw

Copy link
Copy Markdown
Author

@coderabbitai review

Comment thread dip-decentralized-masternode-shares.md Outdated
independent `nVersion` field that starts at `1` (see each payload
definition).

Provider payload version `5` is reserved for shared-collateral semantics.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think that this is a poor decision. It seems to be that we should be able to have a specific individual version to serve both shared and non-shared masternodes. Either we have a flag which indicates shared, or we detect it based on length of the owners or something where only 1 shows it's not shared.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Acknowledged. I removed the paragraph that tried to reserve v5/future versioning as a generic-mode decision. I left the current draft using separate SharedCollateral = 5, but called out in the PR description that this is open design feedback to resolve before ready-for-review: separate provider payload version vs one version with an explicit shared flag or share-count discriminator. I did not silently redesign that part without a concrete direction.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I am saying this IS the design decision. I do not wish 1 version to mean semantically shared and another to mean not. Instead a flag or something else such as length of scripts should say that

Comment thread dip-decentralized-masternode-shares.md Outdated
| `TRANSACTION_PROVIDER_UPDATE_SHARE` | 11 | `ProUpShareTx` payload (this DIP). |
| `TRANSACTION_PROVIDER_UPDATE_SHARED_REGISTRAR` | 12 | `ProUpSharedRegTx` payload (this DIP). |

The numeric assignments `10`, `11`, and `12` are tentative. Before this DIP

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Don't have hedging paragraphs like this. For stuff similar to this keep it in the PR description not in the dip.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done — moved the dependency/merge-blocking prose out of the DIP and into the PR description. The DIP now states the DIP-0026 v4 relationship directly without the PR-status hedging.

thepastaclaw and others added 11 commits June 20, 2026 07:40
Introduces a draft DIP describing shared-collateral masternodes with
2-8 participants, ProTxVersion 5 (SharedCollateral), per-participant
consent for registration and shared-registrar updates, consensus
enforcement of a dissolution covenant on the shared collateral output,
and a new CProDisTx (TRANSACTION_PROVIDER_DISSOLVE) with strict
output/penalty rules. Filed under the alias name per DIP editor policy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Replace 1051200 (~2 yr at 60 s) early-period ceiling with 420480
  (~2 yr at nominal 2.5 min/block) and document wall-clock conversion.
* Narrow the shared collateral covenant: consensus protects only
  active or same-block-pending v5 collateral outpoints, not every
  output whose scriptPubKey matches the template, so unrelated UTXOs
  with the same script are not retroactively locked.
* Fix DistributeByWeight remainder distribution to skip zero-weight
  indices and require sum_w > 0, and add helper tests.
* Allow the actor's dissolution output to be omitted when its value
  would be zero (e.g. when the fee consumes the full pre-fee
  remainder); reject stray zero-value actor outputs; specify output
  matching by walking the share table.
* Special-case unanimous dissolution so DistributeByWeight is not
  invoked with an all-zero weight vector; bonus is set to zero
  directly.
* Update test cases and penalty-bounds rationale.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Address compatibility/versioning review on the draft Shared Masternode
DIP:

* Bind SharedRegConsentHash and SharedDisHash to chainGenesisHash so
  consensus digests are network-scoped; signers MUST verify chain
  context before signing. Rewrite the cross-chain replay security
  consideration accordingly: proTxHash alone is not sufficient.
* Clarify that ProTxVersion::SharedCollateral = 5 is the v5 ProRegTx
  payload version and the shared-MN state tag; the new ProDisTx,
  ProUpShareTx, and ProUpSharedRegTx payloads carry their own
  independent nVersion starting at 1. Reserve future provider payload
  versions (6+) for single-owner ProRegTx changes; v5 is not a
  generic mode flag.
* Clean up ProUpRegTx/ProUpServTx wording: ProUpRegTx is invalid
  against a v5 masternode; ProUpServTx remains operator-authorized for
  service/operator-payout fields only and MUST NOT touch owner or
  shared-collateral fields.
* Spell out the SML/filter trust boundary: SML hashes MUST NOT include
  v5-only fields, full nodes validate v5 data from reconstructed state,
  filter matches exist for client discovery only and are not consensus
  commitments. A future DIP-0004 extension would be required for SPV
  commitments. Mirrors the non-commitment direction taken for DIP-0026
  payout metadata.
* Mark the DIP explicitly non-final for activation until concrete
  SHARED_COLLATERAL_SCRIPT bytes are assigned and inserted, and
  strengthen the open issue requiring re-check of the tentative
  10/11/12 special transaction type numbers against the authoritative
  DIP-0002 / Dash Core allocations before merge or activation, with
  mandatory renumbering on conflict.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…re-vector diffs

Address consensus review blockers ahead of activation-final:

* Deterministic MN state diffs: remove the MAY-compact alternative and
  require a single canonical encoding - full replacement of the share
  vector on any share-field change.
* Same-block ProRegTx + ProDisTx: forbid dissolution in the same block
  as the v5 registration. The protected set is split into an active
  set (allows ProDisTx) and a same-block pending set (rejects every
  spend, including ProDisTx). Update covenant rules, rationale,
  implementation notes, and test cases accordingly.
* Activation language: tighten draft-status wording so the DIP is
  reviewable but explicitly not activation-final until script bytes
  and DIP-0023 deployment parameters are assigned. No specific Dash
  Core release version is claimed.
@thepastaclaw thepastaclaw force-pushed the docs/dip-decentralized-mn-shares branch from 1550555 to c14a4cd Compare June 20, 2026 12:41
@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@thepastaclaw thepastaclaw force-pushed the docs/dip-decentralized-mn-shares branch from c14a4cd to b64a580 Compare June 20, 2026 12:43

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Code Review

Draft DIP for decentralized masternode shares (ProTx v5 + ProDisTx/ProUpShareTx/ProUpSharedRegTx) is tight on the covenant model, digests, penalty bounds, same-block dissolution, and reorg replay. One blocking spec ambiguity remains: the covenant uses the undefined term "active v5 masternode" which could let PoSe-banned masternode collateral escape mempool/block-level rejection if implementations interpret "active" as the valid (non-banned) subset rather than the registered set.

🔴 1 blocking

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `dip-decentralized-masternode-shares.md`:
- [BLOCKING] dip-decentralized-masternode-shares.md:957-961: Define "active v5 masternode" to include PoSe-banned registrations
  The active-set definition keys the mempool and block-level covenant rejection on "every collateral outpoint recorded against an active v5 masternode in the deterministic masternode list", but "active" is not defined. DIP-0003 distinguishes the registered set from the valid (non-PoSe-banned) subset, and an implementer reasonably reading "active" as "valid" would exclude PoSe-banned v5 masternodes from the active set. Mempool rule 1 (line 985) and block-connection rule 2 (line 994-1000) then would not reject an ordinary spend of a PoSe-banned v5 masternode's shared collateral, even though the later list-removal rule 4 (line 1009-1016) says any v5 masternode must only be removed by ProDisTx. That mismatch means a PoSe-banned masternode could be removed via collateral spend on one implementation and rejected on another — a consensus split. Same ambiguity affects the parallel summary at lines 264-269 and references to "active v5 masternode" at lines 1455, 1458, 1476. Specify that the protected active set is every registered v5 masternode in the deterministic list, including PoSe-banned ones, then propagate the wording consistently.

GitHub does not allow PastaClaw to request changes on their own PR, so this is posted as a COMMENT review while preserving the blocking finding.

Inline posting also hit GitHub HTTP 422, so I posted the same verified finding as a top-level review body.

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