Repository navigation
fix: keep short rotation quarters as selected #8074
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
c963c7b
7445e79
3826c2a
2b42fce
f757aec
5fe5c0b
4befd4e
7dc6bb1
7be06e3
a9ea3df
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| Consensus changes | ||
| ----------------- | ||
|
|
||
| - A rotating LLMQ (DIP0024) cycle that can't fill a quarter, because too few eligible masternodes are left, now | ||
| keeps the members it actually selected: the quarter stays short or empty when it is rebuilt from the cycle's | ||
| quorum snapshot. Previously, rebuilding a stored short quarter padded it by wrapping around the candidate list, | ||
| adding members that were never selected and possibly repeating members of the quorum's other quarters. With too | ||
| few enabled masternodes, or when the selection walk made no progress, the builder instead returned empty | ||
| quarters without storing a snapshot, and later cycles stopped loading their older quarters at the missing | ||
| snapshot. Cycles whose quarters all fill are selected, stored and rebuilt exactly as before. Quorum sizes, | ||
| minimum sizes and thresholds are unchanged: the existing `minSize`, DKG and commitment rules still decide | ||
| whether a quorum with short quarters forms. | ||
| - There is no activation: the new rules apply to every cycle. Mainnet history replays unchanged under them. The | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| testnet cycles whose selection differs (base blocks at h=838368, h=901152-903168 and h=1366560-1367136) keep | ||
| the old rules. Short or empty quarters only occur when very few masternodes are eligible. Older and upgraded | ||
|
Comment on lines
+13
to
+15
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Suggestion: Match historical compatibility claims to the exact replay evidence The unconditional statement that mainnet history replays unchanged exceeds the validation reported in the PR. Those replays used an additional per-index proTxHash exclusion and a different snapshot-mode policy, whereas this head retains the HasMN/AddMN callback at utils.cpp:411–418. Historical property conflicts can make those exclusion rules produce different selections. The exhaustive walk tests prove equivalence for matching inputs, and the synthetic exception test proves dispatch, but neither establishes identical preceding inputs throughout mainnet/testnet history. Successful block verification with the variant also does not compare member lists for quorums that never committed. Record an exact-head comparison against the base, including historical member lists and snapshot bytes, or qualify this release-note statement and the equivalent claim in commit f757aec to describe the variant-build evidence and its limits. source: |
||
| nodes can then derive different quorum members, either in that cycle or when its quarters are reused in later | ||
| cycles, and reject each other's commitments, so nodes have to upgrade before such a cycle occurs. | ||
| - Devnets and regtest chains that already had a cycle with a short or empty quarter are not supported across | ||
| this upgrade and have to be started over. Their stored snapshots, or missing snapshots, can give upgraded nodes | ||
| different members than nodes that reindex or sync from scratch, and those can reject historical commitments | ||
| whose members change, so reindexing alone is not a guaranteed recovery. | ||
|
|
||
| Notes for SPV and other clients that rebuild rotating quorums from `qrinfo` | ||
| ------------------------------------------------------------------------------- | ||
|
|
||
| The serialized `CQuorumSnapshot` and `qrinfo` formats don't change, but `mnSkipListMode` gains a value, | ||
| `MODE_SHORT_QUARTERS` (4). Snapshots in `MODE_NO_SKIPPING` (0) and `MODE_SKIPPING_ENTRIES` (1) keep their | ||
| meaning and are decoded as before. Nodes store `MODE_SHORT_QUARTERS` only for cycles with a short or empty | ||
| quarter, so clients must decode it before such a cycle occurs: | ||
|
|
||
| - Candidate list: as before, `activeQuorumMembers` refers to the work block's valid masternodes with a | ||
| confirmed registration (non-null `confirmedHash`), sorted by score. The candidates are the unmarked ones | ||
| followed by the marked ones, each part in that order. | ||
| - Walk: a step counter starts at 0 and counts every candidate visited in the cycle, across all quorum indices | ||
| in order. The candidate at step `t` is `list[t % list.size()]`. For each quorum index, a visited candidate is | ||
| skipped if `t` is a skip step and added otherwise. An index's quarter ends when it has `quarterSize` members | ||
| or after `list.size()` consecutive skips; the next index continues at the next step. An empty candidate list | ||
| gives empty quarters and an empty skip list. | ||
| - Skip steps: `mnSkipList` holds the steps at which a candidate was skipped. The first entry is the absolute | ||
| step of the first skip; each later entry is the positive difference from the previous skip step. A snapshot | ||
| is malformed if an entry is negative (or a later entry is zero), if a skip step is never reached by the walk, | ||
| or if a quarter would contain the same position twice. | ||
|
|
||
| For cycles they compute successfully, outside predictions, nodes now store a snapshot even when no masternodes | ||
| are eligible. The exempt testnet cycles keep the old storage behaviour. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,7 +32,8 @@ enum class SnapshotSkipMode : int { | |
| MODE_NO_SKIPPING = 0, | ||
| MODE_SKIPPING_ENTRIES = 1, | ||
| MODE_NO_SKIPPING_ENTRIES = 2, | ||
| MODE_ALL_SKIPPED = 3 | ||
| MODE_ALL_SKIPPED = 3, | ||
| MODE_SHORT_QUARTERS = 4, // Some quarter is short or empty; the list holds the walk steps at which a candidate was skipped | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Suggestion: Track mode-4 support in the owning SPV repository The new snapshot mode requires a coordinated consumer update. In the available rust-dashcore source at ee50584d23c6169b0e6663f9fda0c16fa1325043, dash/src/network/message_qrinfo.rs defines only modes 0–3, and MNSkipListMode::consensus_decode rejects 4 with "Invalid MnSkipListMode". A qrinfo response containing a short-quarter snapshot therefore fails decoding in that consumer. The release note correctly documents the compatibility requirement, and the implementation belongs in rust-dashcore rather than a Core fallback. Link a tracking issue or follow-up PR covering mode decoding, reconstruction, and shared test vectors before rollout on affected networks; the supplied PR evidence contains no such link. source: fresh:general |
||
| }; | ||
| template<> struct is_serializable_enum<SnapshotSkipMode> : std::true_type {}; | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Script executed:
Repository: dashpay/dash
Length of output: 8483
Script executed:
Repository: dashpay/dash
Length of output: 42149
Script executed:
Repository: dashpay/dash
Length of output: 41422
Script executed:
Repository: dashpay/dash
Length of output: 37850
Qualify the full-quarter compatibility guarantee.
A previously padded quarter can change the used-member set for later selections. Those selections can differ even when their new quarters fill. Qualify the guarantee to require identical prior-quarter inputs.