Skip to content

feat(rpc): expose upcoming DKG participation#7404

Open
thepastaclaw wants to merge 2 commits into
dashpay:developfrom
thepastaclaw:rpc-dkg-scheduled-participation
Open

feat(rpc): expose upcoming DKG participation#7404
thepastaclaw wants to merge 2 commits into
dashpay:developfrom
thepastaclaw:rpc-dkg-scheduled-participation

Conversation

@thepastaclaw

@thepastaclaw thepastaclaw commented Jul 3, 2026

Copy link
Copy Markdown

feat(rpc): expose upcoming DKG participation

Issue being fixed or feature implemented

Dashmate currently uses quorum dkginfo/quorum dkgstatus to avoid unsafe
restart/reindex operations around DKG windows, but Core only exposes global DKG
timing. That forces Dashmate to treat "a DKG is soon" as "this node might be
needed", which blocks harmless recovery operations for masternodes that are not
actually selected for the upcoming DKG.

This PR extends quorum dkginfo so tooling can ask whether a specific
proTxHash is selected for an upcoming, already-determinable DKG.

What was done?

  • Added an optional quorum dkginfo proTxHash parameter, defaulting to the
    local active masternode when available.
  • Added an upcoming_dkgs result array with quorum type, planned quorum height,
    blocks until start, known/unknown status, and per-proTxHash membership
    fields when prediction is possible. The RPC reports only upcoming sessions
    whose work block is already mined.
  • Added utility helpers that compute future v20 quorum members from already-known
    DKG work blocks for both non-rotated and rotated quorum types.
  • For rotated quorums, prediction uses the cycle base work block and historical
    quarter-rotation snapshots, without storing a snapshot for the future cycle
    base block.
  • Shared the post-v20 work-block hash modifier helper with normal quorum
    selection, so prediction does not duplicate modifier logic.
  • Snapshot the chain tip/work-block lookup consistently for the prediction path.
  • Return structured unknown reasons instead of guessing for cases that cannot be
    predicted safely, including unavailable work blocks, unavailable rotated
    snapshots, and pre-v20 quorum selection.
  • Extended feature_llmq_rotation.py to verify:
    • pre-v20 responses are explicitly unknown;
    • empty proTxHash defaults to the local masternode;
    • predicted non-rotated member counts are exposed;
    • predicted rotated llmq_test_dip0024 members match the quorum that is later
      mined.
  • Extended feature_llmq_evo.py to verify platform quorum prediction uses only
    EvoNodes and matches the later mined llmq_test_platform quorum members.

How Has This Been Tested?

  • git diff --check
  • python3 -m py_compile test/functional/feature_llmq_rotation.py test/functional/feature_llmq_evo.py
  • python3 -m flake8 test/functional/feature_llmq_rotation.py test/functional/feature_llmq_evo.py 2>&1 | rg 'E127' || true
  • ./autogen.sh
  • ./configure --with-gui=no --disable-bench --disable-fuzz-binary --disable-tests
  • make -j4 src/dashd
  • test/functional/feature_llmq_rotation.py
  • test/functional/feature_llmq_evo.py
  • Local pre-PR code review gate against this worktree:
    • result: ship with fixes
    • fixed the reported lookahead_blocks overflow edge case before later removing
      the custom lookahead parameter
    • rebuilt and reran feature_llmq_rotation.py after the fix

Breaking Changes

None expected. Existing active_dkgs and next_dkg fields are preserved; the
new upcoming_dkgs field is additive.

Checklist

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have made corresponding changes to the documentation
  • I have assigned this pull request to a milestone
    (for repository code-owners and collaborators only)

@thepastaclaw

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 3, 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.

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown

✅ No Merge Conflicts Detected

This PR currently has no conflicts with other open PRs.

@coderabbitai

coderabbitai Bot commented Jul 3, 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

Walkthrough

This PR adds work-block-based quorum member prediction helpers in llmq::utils for rotated and non-rotated quorums. quorum dkginfo now accepts optional proTxHash input and returns richer upcoming_dkgs metadata, including known/reason status, membership details, and work-block identifiers. Functional tests were extended to cover platform quorum prediction and rotated quorum prediction behavior.

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

Sequence Diagram(s)

sequenceDiagram
  participant RPC as quorum dkginfo
  participant Utils as llmq::utils
  participant Chain as CBlockIndex
  participant MNList as CDeterministicMNList
  RPC->>Utils: request upcoming quorum prediction
  Utils->>Chain: inspect tip, work block, and deployment state
  Utils->>MNList: compute predicted members
  Utils-->>RPC: return upcoming_dkgs metadata
Loading

Suggested reviewers: PastaPastaPasta, kwvg

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title clearly summarizes the main change: exposing upcoming DKG participation via RPC.
Description check ✅ Passed The description matches the changeset, covering the new RPC fields, quorum helpers, and functional tests.
✨ 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.

@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: 1

🧹 Nitpick comments (1)
src/llmq/utils.cpp (1)

582-585: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Extract the shared V20 modifier logic. The V20 branch here duplicates GetHashModifier; sharing it would keep the prediction path from drifting if the selection rules change.

🤖 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 `@src/llmq/utils.cpp` around lines 582 - 585, The V20 prediction path in
GetV20HashModifier duplicates the same modifier-selection logic used by
GetHashModifier, so extract that shared logic into a common helper and have both
paths call it. Keep the helper responsible for selecting the correct quorum base
block hash / modifier source based on the deployment state, then reuse it from
the V20 branch and the existing modifier calculation to prevent drift if the
selection rules change.
🤖 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 `@test/functional/feature_llmq_rotation.py`:
- Around line 265-266: The `assert_raises_rpc_error` call in
`feature_llmq_rotation.py` has a continuation line that is over-indented,
triggering flake8 E127. Update the indentation in the
`assert_raises_rpc_error(...)` invocation so the wrapped arguments align
consistently with the opening parenthesis, keeping the formatting around
`active_mn.get_node(self).quorum` and its following arguments compliant.

---

Nitpick comments:
In `@src/llmq/utils.cpp`:
- Around line 582-585: The V20 prediction path in GetV20HashModifier duplicates
the same modifier-selection logic used by GetHashModifier, so extract that
shared logic into a common helper and have both paths call it. Keep the helper
responsible for selecting the correct quorum base block hash / modifier source
based on the deployment state, then reuse it from the V20 branch and the
existing modifier calculation to prevent drift if the selection rules change.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: bc1011c1-247c-4fe7-9019-f3ac675e4b51

📥 Commits

Reviewing files that changed from the base of the PR and between 4af395d and a49287a.

📒 Files selected for processing (4)
  • src/llmq/utils.cpp
  • src/llmq/utils.h
  • src/rpc/quorums.cpp
  • test/functional/feature_llmq_rotation.py

Comment thread test/functional/feature_llmq_rotation.py Outdated
@thepastaclaw thepastaclaw force-pushed the rpc-dkg-scheduled-participation branch from a49287a to 0b83dc4 Compare July 3, 2026 16:32
@thepastaclaw

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 3, 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.

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

🧹 Nitpick comments (1)
test/functional/feature_llmq_evo.py (1)

89-100: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Hardcoded DKG interval/lookahead values couple test to RPC internals.

dkg_interval = 24 (Line 89) and the lookahead of 8 passed to quorum("dkginfo", ...) (Line 100) mirror llmq_params.dkgInterval and llmq::WORK_DIFF_DEPTH in src/rpc/quorums.cpp. If either constant changes for llmq_test_platform, this test will silently miscompute expected_quorum_height/blocks_to_mine and become flaky rather than failing clearly. Consider omitting the lookahead_blocks param to rely on the RPC's own default (WORK_DIFF_DEPTH), and/or sourcing dkg_interval from self.nodes[0].quorum("list", ...) params or an existing test helper if one exists.

🤖 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 `@test/functional/feature_llmq_evo.py` around lines 89 - 100, The test
currently hardcodes the DKG interval and lookahead, which ties feature_llmq_evo
to rpc/quorums.cpp internals and can silently drift if llmq_test_platform
settings change. Update the setup around getblockcount/expected_quorum_height to
derive dkg_interval from the quorum config (for example via
self.nodes[0].quorum("list", ... ) or an existing helper) instead of using 24.
Also remove the explicit 8 passed to quorum("dkginfo", ...) so the RPC default
lookahead is used, or centralize that value through the same shared source.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@test/functional/feature_llmq_evo.py`:
- Around line 89-100: The test currently hardcodes the DKG interval and
lookahead, which ties feature_llmq_evo to rpc/quorums.cpp internals and can
silently drift if llmq_test_platform settings change. Update the setup around
getblockcount/expected_quorum_height to derive dkg_interval from the quorum
config (for example via self.nodes[0].quorum("list", ... ) or an existing
helper) instead of using 24. Also remove the explicit 8 passed to
quorum("dkginfo", ...) so the RPC default lookahead is used, or centralize that
value through the same shared source.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d067e03f-d086-4f92-998a-6619ea22f00f

📥 Commits

Reviewing files that changed from the base of the PR and between a49287a and 0b83dc4.

📒 Files selected for processing (5)
  • src/llmq/utils.cpp
  • src/llmq/utils.h
  • src/rpc/quorums.cpp
  • test/functional/feature_llmq_evo.py
  • test/functional/feature_llmq_rotation.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/llmq/utils.h
  • src/rpc/quorums.cpp

@thepastaclaw

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 3, 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 rpc-dkg-scheduled-participation branch from b3e4105 to aa15b30 Compare July 3, 2026 17:09
@thepastaclaw

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 3, 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

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 3, 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 marked this pull request as ready for review July 4, 2026 14:33
@dashpay dashpay deleted a comment from thepastaclaw Jul 4, 2026
@dashpay dashpay deleted a comment from coderabbitai Bot Jul 4, 2026
@thepastaclaw

thepastaclaw commented Jul 4, 2026

Copy link
Copy Markdown
Author

✅ Review complete (commit 12b3ddb)

@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 (1)
src/rpc/quorums.cpp (1)

1058-1117: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use rotation_enabled consistently here. GetEnabledQuorumTypes() only says the quorum type is active; the current-cycle rotation state can still differ, so workHeight and the member-selection branch should follow rotation_enabled instead of llmq_params.useRotation.

🤖 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 `@src/rpc/quorums.cpp` around lines 1058 - 1117, Use rotation_enabled
consistently in this quorum-upcoming calculation path. In the logic inside the
loop over GetEnabledQuorumTypes, compute workHeight and choose the
member-selection branch based on rotation_enabled rather than
llmq_params.useRotation, so the current-cycle rotation state matches the same
condition already used to set quorums_num. Update the related workHeight
calculation and the if/else that calls ComputeRotatedQuorumMembersFromWorkBlock
versus ComputeNonRotatedQuorumMembersFromWorkBlock accordingly.
🧹 Nitpick comments (2)
src/rpc/quorums.cpp (1)

1035-1036: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Raw dereference of pindexTip->nHeight.

pindexTip is taken from chainman.ActiveChain().Tip() and immediately dereferenced. If the active chain tip is ever null (e.g., extremely early startup edge case), this is a null-pointer dereference. The prior implementation reportedly derived height via a chain accessor rather than dereferencing the tip directly. Low real-world likelihood since the RPC framework guards on active/observer context being available, but a defensive guard is cheap.

🤖 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 `@src/rpc/quorums.cpp` around lines 1035 - 1036, The `GetQuorumInfo` path is
dereferencing `pindexTip->nHeight` immediately after fetching
`chainman.ActiveChain().Tip()`, so add a defensive null check before using the
tip. Update the logic around `pindexTip`/`nTipHeight` to handle a null
active-chain tip safely, preferably by using an accessor-based height lookup or
by returning an appropriate early error when `Tip()` is absent.
test/functional/feature_llmq_rotation.py (1)

275-334: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate hardcoded 8 (work-diff depth) across multiple test sections.

The value mirroring llmq::WORK_DIFF_DEPTH is hardcoded independently at Lines 111, 284, 310-311, and 328-329. Consider hoisting it into a single local/class constant (e.g., self.work_diff_depth = 8 set once in run_test) to avoid drift if the depth changes.

🤖 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 `@test/functional/feature_llmq_rotation.py` around lines 275 - 334, The test is
duplicating the work-diff depth value in multiple assertions and calculations,
which risks drift if the depth changes. Hoist the shared `8` used for the
`llmq::WORK_DIFF_DEPTH`-based timing into a single constant or `run_test`-level
field, then reuse it throughout `feature_llmq_rotation.py` in the `dkginfo`
checks. Update the calculations for `blocks_to_mine`, `workBlockHeight`, and
related expected heights to reference that shared symbol instead of repeating
the literal. Use a clear identifier like `work_diff_depth` so the values in the
`dkginfo` test stay consistent.
🤖 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 `@src/rpc/quorums.cpp`:
- Around line 1058-1117: Use rotation_enabled consistently in this
quorum-upcoming calculation path. In the logic inside the loop over
GetEnabledQuorumTypes, compute workHeight and choose the member-selection branch
based on rotation_enabled rather than llmq_params.useRotation, so the
current-cycle rotation state matches the same condition already used to set
quorums_num. Update the related workHeight calculation and the if/else that
calls ComputeRotatedQuorumMembersFromWorkBlock versus
ComputeNonRotatedQuorumMembersFromWorkBlock accordingly.

---

Nitpick comments:
In `@src/rpc/quorums.cpp`:
- Around line 1035-1036: The `GetQuorumInfo` path is dereferencing
`pindexTip->nHeight` immediately after fetching `chainman.ActiveChain().Tip()`,
so add a defensive null check before using the tip. Update the logic around
`pindexTip`/`nTipHeight` to handle a null active-chain tip safely, preferably by
using an accessor-based height lookup or by returning an appropriate early error
when `Tip()` is absent.

In `@test/functional/feature_llmq_rotation.py`:
- Around line 275-334: The test is duplicating the work-diff depth value in
multiple assertions and calculations, which risks drift if the depth changes.
Hoist the shared `8` used for the `llmq::WORK_DIFF_DEPTH`-based timing into a
single constant or `run_test`-level field, then reuse it throughout
`feature_llmq_rotation.py` in the `dkginfo` checks. Update the calculations for
`blocks_to_mine`, `workBlockHeight`, and related expected heights to reference
that shared symbol instead of repeating the literal. Use a clear identifier like
`work_diff_depth` so the values in the `dkginfo` test stay consistent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 07160cc2-1cd5-4d7b-b27f-a64e7308fd91

📥 Commits

Reviewing files that changed from the base of the PR and between aa15b30 and f455571.

📒 Files selected for processing (3)
  • src/rpc/quorums.cpp
  • test/functional/feature_llmq_evo.py
  • test/functional/feature_llmq_rotation.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/functional/feature_llmq_evo.py

@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

The PR is generally sound and its refactor preserves the real quorum-formation path, but there is one in-scope correctness bug in the RPC filter: rotated cycles share one work block, yet the filter uses per-quorumHeight distance, dropping every quorumIndex>=1 entry the moment the tip enters the work-diff window — silently defeating the RPC's stated purpose for later rotated slots. Two lower-severity notes: the prediction path evaluates DEPLOYMENT_V19/EvoOnly against the work block rather than the future quorum base block (dormant today), and the commit stack contains a same-PR add/undo of the lookahead_blocks RPC parameter that should be folded before merge.

🔴 1 blocking | 🟡 2 suggestion(s)

Source: reviewers: opus (general), claude-sonnet-5 (general), gpt-5.5 (general), opus (dash-core-commit-history), claude-sonnet-5 (dash-core-commit-history), gpt-5.5 (dash-core-commit-history); verifier: opus; specialists: dash-core-commit-history.

🤖 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 `src/rpc/quorums.cpp`:
- [BLOCKING] src/rpc/quorums.cpp:1070-1072: Rotated quorumIndex >= 1 entries are dropped even when their work block is mined
  The eligibility filter `quorumHeight - nTipHeight > llmq::WORK_DIFF_DEPTH` gates on the individual quorum's start height, but for rotated quorums every quorumIndex in a cycle shares the same work block at `cycleBaseHeight - WORK_DIFF_DEPTH`. As soon as that work block is mined, `ComputeRotatedQuorumMembersFromWorkBlock` can predict all indices 0..signingActiveQuorumCount-1 at once, yet this filter rejects indices 1..N-1 because their `blocksUntilStart` is `WORK_DIFF_DEPTH + quorumIndex`, exceeding the threshold. Concrete case: with `dkgInterval=24`, `WORK_DIFF_DEPTH=8`, `signingActiveQuorumCount=4` and tip at `cycleBase-8`, only quorumIndex=0 is reported; quorumIndex=1,2,3 (blocksUntilStart=9,10,11) are silently dropped even though they would all succeed the subsequent `workHeight > nTipHeight` check. This defeats the RPC's stated purpose (dashmate restart-window planning): a masternode whose only upcoming slot is a later quorumIndex will see no entry and may restart into an active DKG. The RPC docstring — 'sessions starting within the work-diff depth' — also conflates the two conditions, which are only equivalent for non-rotated quorums. Gate the pre-filter on the work block rather than on quorumHeight for rotated types; the existing `workHeight`/tip check already handles the truly-unavailable case, so the redundant guard can be tightened or dropped. Extend `feature_llmq_rotation.py` to compare prediction against at least one non-zero quorumIndex against the mined rotated quorum.

In `src/llmq/utils.cpp`:
- [SUGGESTION] src/llmq/utils.cpp:607-617: Deployment gates evaluated against the work block, not the future quorum base
  In the real path, `ComputeQuorumMembers` and `ComputeQuorumMembersByQuarterRotation` evaluate `DEPLOYMENT_V19` (for `EvoOnly` and `skipRemovedMNs`) against the quorum's own base block. The prediction path evaluates the same gates against `pWorkBlockIndex`, which is `WORK_DIFF_DEPTH` blocks earlier: `ComputeNonRotatedQuorumMembersFromWorkBlock` uses `pWorkBlockIndex` directly for `EvoOnly`, and `ComputeRotatedQuorumMembersFromWorkBlock` passes `pDeploymentIndex=pWorkBlockIndex` into `BuildNewQuorumQuarterMembers`, where `skipRemovedMNs` is derived. If a future deployment gating member selection activates within that 8-block window, prediction will diverge from the actual mined quorum's membership. In practice this is dormant — V19 is long since active on all real networks before V20 (which itself gates prediction). Either document the constraint explicitly or bail out of prediction when the relevant deployment isn't yet active at the projected quorum base height.

In `<commit:f455571aea>`:
- [SUGGESTION] <commit:f455571aea>:1: Squash the transient `lookahead_blocks` add-then-remove into the introducing commit
  Commit `0b83dc4895` introduces a `lookahead_blocks` optional RPC arg (RPCArg entry, `lookaheadBlocks` local, negative-value validation, and a functional-test `assert_raises_rpc_error` for the negative case). Commit `f455571aea` deletes every trace of it and replaces the threshold with `llmq::WORK_DIFF_DEPTH`. Because Dash Core merges the stack as-is (no squash on merge), this leaves permanent `git log`/`git blame` churn for an RPC parameter that never shipped, and adds a needless bisect step where the RPC surface changes shape mid-stack. Interactive-rebase the `f455571aea` hunks into `0b83dc4895` so the final history introduces the RPC in its final, parameter-less form. Two feature commits (`expose upcoming DKG participation`, `predict rotated DKG participation`) are the clean landing shape.

Comment thread src/rpc/quorums.cpp Outdated
Comment on lines +1070 to +1072
if (quorumHeight <= nTipHeight || quorumHeight - nTipHeight > llmq::WORK_DIFF_DEPTH) {
continue;
}

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: Rotated quorumIndex >= 1 entries are dropped even when their work block is mined

The eligibility filter quorumHeight - nTipHeight > llmq::WORK_DIFF_DEPTH gates on the individual quorum's start height, but for rotated quorums every quorumIndex in a cycle shares the same work block at cycleBaseHeight - WORK_DIFF_DEPTH. As soon as that work block is mined, ComputeRotatedQuorumMembersFromWorkBlock can predict all indices 0..signingActiveQuorumCount-1 at once, yet this filter rejects indices 1..N-1 because their blocksUntilStart is WORK_DIFF_DEPTH + quorumIndex, exceeding the threshold. Concrete case: with dkgInterval=24, WORK_DIFF_DEPTH=8, signingActiveQuorumCount=4 and tip at cycleBase-8, only quorumIndex=0 is reported; quorumIndex=1,2,3 (blocksUntilStart=9,10,11) are silently dropped even though they would all succeed the subsequent workHeight > nTipHeight check. This defeats the RPC's stated purpose (dashmate restart-window planning): a masternode whose only upcoming slot is a later quorumIndex will see no entry and may restart into an active DKG. The RPC docstring — 'sessions starting within the work-diff depth' — also conflates the two conditions, which are only equivalent for non-rotated quorums. Gate the pre-filter on the work block rather than on quorumHeight for rotated types; the existing workHeight/tip check already handles the truly-unavailable case, so the redundant guard can be tightened or dropped. Extend feature_llmq_rotation.py to compare prediction against at least one non-zero quorumIndex against the mined rotated quorum.

Suggested change
if (quorumHeight <= nTipHeight || quorumHeight - nTipHeight > llmq::WORK_DIFF_DEPTH) {
continue;
}
const int cycleBaseHeight{quorumHeight - quorumIndex};
const int workHeight{(llmq_params.useRotation ? cycleBaseHeight : quorumHeight) - llmq::WORK_DIFF_DEPTH};
if (quorumHeight <= nTipHeight || workHeight > nTipHeight) {
continue;
}

source: ['claude', 'codex']

Comment thread src/llmq/utils.cpp
@thepastaclaw

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 4, 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.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 94eb4ad9f8

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/rpc/quorums.cpp Outdated
if (quorumHeight <= nTipHeight) {
quorumHeight += llmq_params.dkgInterval;
}
if (quorumHeight <= nTipHeight || quorumHeight - nTipHeight > llmq::WORK_DIFF_DEPTH) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Include rotated DKGs when their work block exists

For rotated quorums this filters by quorumHeight - nTipHeight, but their work block is cycleBaseHeight - WORK_DIFF_DEPTH, independent of quorumIndex. On mainnet llmq_60_75 has 32 rotated indexes while WORK_DIFF_DEPTH is 8, so at cycleBaseHeight - 8 the work block for all 32 upcoming DKGs is already mined, yet this RPC only reports index 0 and later only indexes within 8 blocks of starting. That makes upcoming_dkgs incomplete for determinable rotated DKG participation; the availability check should be based on the computed workHeight <= nTipHeight instead.

Useful? React with 👍 / 👎.

Comment thread src/llmq/utils.cpp Outdated
}

bool EvoOnly = (chainparams.GetConsensus().llmqTypePlatform == llmqType) &&
DeploymentActiveAfter(pWorkBlockIndex.get(), chainparams.GetConsensus(), Consensus::DEPLOYMENT_V19);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use the quorum height for V19 platform filtering

When predicting platform quorums in the V19 activation window, this checks Evo-only selection against the work block, but the normal path in ComputeQuorumMembers checks DeploymentActiveAfter(pQuorumBaseBlockIndex, ..., V19). If V19 activates during the 8-block gap between the work block and the upcoming quorum height, dkginfo will rank regular masternodes too and can report a membership set that differs from the quorum that is actually mined.

Useful? React with 👍 / 👎.

Comment thread src/llmq/utils.cpp Outdated
Comment on lines +679 to +680
auto newQuarterMembers = BuildNewQuorumQuarterMembers(llmq_params, util_params, allMns, previousQuarters,
modifier, pWorkBlockIndex, cycleBaseHeight,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Match rotated V19 skip rules to the cycle base

For rotated predictions this passes the work block as the deployment index used by BuildNewQuorumQuarterMembers to decide skipRemovedMNs, while the production path passes the cycle base block. During the first cycle where V19 is active at the future cycle base but not at cycleBase - WORK_DIFF_DEPTH, removed previous-quarter MNs are retained in the prediction even though the mined quorum skips them, so upcoming_dkgs can report the wrong rotated membership.

Useful? React with 👍 / 👎.

@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

The latest delta (94eb4ad) correctly aligns the rotated/non-rotated dispatch with DIP-0024 activation state by using tip-evaluated rotation_enabled in place of the static useRotation flag and adds a CHECK_NONFATAL guard on the active tip. However, prior-1's blocking bug in the eligibility pre-filter at src/rpc/quorums.cpp:1070 was not addressed and continues to silently drop every rotated quorumIndex >= 1 slot for quorumIndex blocks after the shared cycle work block is mined — defeating the RPC's stated purpose for later rotated slots. Two lower-severity carried-forward items (deployment gates evaluated against the work block instead of the future quorum base, and pre-merge commit-stack hygiene) also remain.

Blocking: 1 | Suggestions: 3 | Nitpicks: 0

Carried-forward prior findings still valid at 94eb4ad9: prior-1 blocker in src/rpc/quorums.cpp, prior-2 deployment-gate suggestion in src/llmq/utils.cpp, and prior-3 commit-history suggestion for f455571a.
New finding in the latest delta: commit-history suggestion to fold 94eb4ad9f8 into the commits it patches.

Source: reviewers: opus (general), claude-sonnet-5 (general), gpt-5.5 (general), opus (dash-core-commit-history), claude-sonnet-5 (dash-core-commit-history), gpt-5.5 (dash-core-commit-history); verifier: opus; specialists: dash-core-commit-history.

Note: GitHub does not allow me to submit REQUEST_CHANGES on my own PR, so this is posted as a COMMENT while preserving the verified blocking finding.

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 `src/rpc/quorums.cpp`:
- [BLOCKING] src/rpc/quorums.cpp:1066: Rotated quorumIndex >= 1 entries are dropped even when the shared cycle work block is mined
  STILL VALID — carried forward from the prior review at f455571a; the 94eb4ad9 delta only renamed `useRotation` to `rotation_enabled` on lines 1083/1100 and did not touch this pre-filter.

  For rotated quorums the whole cycle shares a single work block at `cycleBaseHeight - WORK_DIFF_DEPTH`, so as soon as that shared work block is mined `ComputeRotatedQuorumMembersFromWorkBlock` can predict every `quorumIndex` in `0..signingActiveQuorumCount - 1`. But this filter gates on per-quorum distance `quorumHeight - nTipHeight > WORK_DIFF_DEPTH` where `quorumHeight = cycleBaseHeight + quorumIndex`, so later indexes are rejected for `quorumIndex` additional blocks.

  Concrete case (`dkgInterval=24`, `WORK_DIFF_DEPTH=8`, `signingActiveQuorumCount=4`, tip=16 — the cycle=24 work block at height 16 has just been mined):
  - `quorumIndex=0`: `blocksUntilStart=8` → passes → reported.
  - `quorumIndex=1`: `blocksUntilStart=9` → dropped (even though the shared work block is mined).
  - `quorumIndex=2,3`: dropped for even more blocks.

  This silently defeats the RPC's stated purpose (dashmate restart-window planning): a masternode whose only upcoming slot is a later `quorumIndex` sees no entry at all in `upcoming_dkgs` for that cycle and can be restarted straight into an already-determinable DKG window. `feature_llmq_rotation.py`'s new assertions only check `quorumIndex == 0` and therefore do not exercise the miss — extending the test to cover `quorumIndex >= 1` immediately after the cycle work block is mined would reproduce it.

  Fix: filter by the height that actually governs work-block availability (`cycleBaseHeight` for rotated, `quorumHeight` otherwise). See suggestion.

  Suggested patch:
                  const int cycleBaseHeight{quorumHeight - quorumIndex};
                  const int workHeight{(rotation_enabled ? cycleBaseHeight : quorumHeight) - llmq::WORK_DIFF_DEPTH};
                  if (quorumHeight <= nTipHeight || workHeight > nTipHeight) {
                      continue;
                  }

In `src/llmq/utils.cpp`:
- [SUGGESTION] src/llmq/utils.cpp:607: Deployment gates evaluated against the work block, not the future quorum base
  STILL VALID but currently dormant — carried forward from the prior review. In the real (non-predictive) path, `ComputeQuorumMembers` derives `EvoOnly` from `DeploymentActiveAfter` against the quorum's own base block. Here, `ComputeNonRotatedQuorumMembersFromWorkBlock` evaluates the V20 gate and the DEPLOYMENT_V19 `EvoOnly` flag against `pWorkBlockIndex`, and `ComputeRotatedQuorumMembersFromWorkBlock` passes `pDeploymentIndex=pWorkBlockIndex` into `BuildNewQuorumQuarterMembers` where `skipRemovedMNs` is derived — both `WORK_DIFF_DEPTH` blocks earlier than the true future quorum/cycle base height.

  Currently dormant because (1) V19 activates before V20 in Dash's deployment order, so any block past V20 is also past V19, and (2) the RPC bails out with `known=false` when V20 is not active at the work block. But if a future deployment gating member selection activates inside the WORK_DIFF_DEPTH window, the prediction will diverge from the actual mined quorum. Not required for this PR; worth a comment or aligning the check with the real path for correctness clarity.

In `<commit:f455571aea>`:
- [SUGGESTION] <commit:f455571aea>:1: Squash the transient `lookahead_blocks` add-then-remove into the introducing commit
  STILL VALID — carried forward. Commit 0b83dc4895 introduces the `lookahead_blocks` RPC parameter (RPCArg, validation for negative values, RPC help, functional-test coverage), and commit f455571aea two commits later removes every trace of it and replaces the threshold with `llmq::WORK_DIFF_DEPTH`. Because dashpay/dash preserves PR commit history at merge time, this leaves permanent `git log`/`git blame` churn for a public RPC parameter that never shipped. Fold f455571aea's reversion back into 0b83dc4895 via interactive rebase so the introducing commit reflects the final parameter-less shape directly.

In `<commit:94eb4ad9f8>`:
- [SUGGESTION] <commit:94eb4ad9f8>:1: Fold the `rotation_enabled` / `CHECK_NONFATAL` fixup into the commits it patches
  Commit 94eb4ad9f8 is a 3-line corrective follow-up to code introduced earlier in the same unmerged PR: it swaps `llmq_params.useRotation` for the tip-evaluated `rotation_enabled` on lines 1083/1100 (rotation-selection branches introduced by aa15b305f3 and 0b83dc4895) and hardens the tip lookup added by 0b83dc4895 with `CHECK_NONFATAL`. As permanent Dash Core history, this is the canonical 'commit A introduces logic, commit B in the same PR fixes a bug in it before it ever ships' pattern the project's no-squash-merge convention is most sensitive to: `git bisect` between aa15b305f3 and 94eb4ad9f8 lands on a state where rotated prediction ignores DIP-0024 activation state. Squash the `rotation_enabled` change into aa15b305f3 (and 0b83dc4895 for the non-rotated site) and the `CHECK_NONFATAL` change into 0b83dc4895 so each commit in the merged stack is individually correct.

@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

The blocking bug from the prior review (prior-1: rotated quorumIndex>=1 dropped by the availability filter) is fixed at head 783ca1d by computing workHeight from cycleBaseHeight when rotation is enabled, and functional coverage was extended to assert both rotated indices per cycle. Remaining items are all carried forward suggestions: one dormant code-logic concern in src/llmq/utils.cpp (deployment gates evaluated against the work block, not the future quorum base) and three commit-history hygiene items — the transient lookahead_blocks add/remove, the rotation_enabled/CHECK_NONFATAL fixup, and now this new same-PR fix commit itself patching aa15b30.

🟡 4 suggestion(s)

Prior finding reconciliation:

  • prior-1: FIXED — Verified in src/rpc/quorums.cpp at lines 1066-1076: workHeight is derived from cycleBaseHeight when rotation_enabled, and the pre-filter now uses that shared value, so rotated indices >= 1 are reported once the shared cycle work block is mined. Functional coverage extended for both rotated indices.
  • prior-2: STILL VALID — src/llmq/utils.cpp lines 607-613 and 647-681 still evaluate DEPLOYMENT_V19/V20 and derive skipRemovedMNs from pWorkBlockIndex rather than the future quorum/cycle base block. Untouched by the latest delta. Currently dormant but retained as a low-confidence suggestion.
  • prior-3: STILL VALID — Commit stack still contains 0b83dc4 introducing the lookahead_blocks RPCArg and f455571 two commits later removing every trace of it. Add-then-remove pair for a public RPC parameter that never ships.
  • prior-4: STILL VALID — 94eb4ad remains a standalone corrective commit patching aa15b30/0b83dc4895 (rotation_enabled dispatch + CHECK_NONFATAL). The latest push added a further same-PR fixup (783ca1d) on the same code path, compounding the hygiene concern; captured as an additional finding.

Source: reviewers: opus (general), claude-sonnet-5 (general), gpt-5.5 (general), opus (dash-core-commit-history), claude-sonnet-5 (dash-core-commit-history), gpt-5.5 (dash-core-commit-history); verifier: opus; specialists: dash-core-commit-history.

🤖 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 `src/llmq/utils.cpp`:
- [SUGGESTION] src/llmq/utils.cpp:607: Deployment gates evaluated against the work block, not the future quorum base
  Carried forward from the prior review — dormant but unresolved. ComputeNonRotatedQuorumMembersFromWorkBlock evaluates both the DEPLOYMENT_V20 gate and the EvoOnly (DEPLOYMENT_V19) flag against pWorkBlockIndex; ComputeRotatedQuorumMembersFromWorkBlock similarly threads pWorkBlockIndex through BuildNewQuorumQuarterMembers where skipRemovedMNs is derived. The canonical production selection path evaluates DEPLOYMENT_V19 against the future quorum/cycle base block instead, which is WORK_DIFF_DEPTH blocks later. Currently harmless because V19 activates before V20 in Dash's deployment order and the RPC already bails with known=false when V20 is not active at the work block, but this leaves the prediction algorithm subtly divergent from the real member-selection algorithm if a future deployment gates member selection and activates inside the WORK_DIFF_DEPTH window. Worth aligning with the canonical path or documenting the deliberate divergence.

In `<commit:f455571aea>`:
- [SUGGESTION] <commit:f455571aea>:1: Squash the transient lookahead_blocks add-then-remove into the introducing commit
  Commit 0b83dc4895 introduces the lookahead_blocks RPCArg, its help text, negative-value validation, and functional-test coverage; commit f455571aea removes every trace of that parameter two commits later, replacing the threshold with llmq::WORK_DIFF_DEPTH. Since dashpay/dash preserves PR commit history at merge time, the add-then-remove pair for a public RPC surface that never shipped becomes permanent noise in git log and git blame. Fold f455571aea back into 0b83dc4895 via interactive rebase so the introducing commit lands with the final parameter-less shape.

In `<commit:94eb4ad9f8>`:
- [SUGGESTION] <commit:94eb4ad9f8>:1: Fold the rotation_enabled / CHECK_NONFATAL fixup into the commits it patches
  94eb4ad9f8 is a 3-line corrective follow-up to logic introduced earlier in the same unmerged PR: it replaces static useRotation checks with tip-evaluated rotation_enabled and adds CHECK_NONFATAL around the active tip lookup. Landed as a standalone commit, this leaves the merged stack with an intermediate state where rotated dkginfo prediction ignores DIP-0024 activation state — a bisect hazard on LLMQ/DKG behavior. Squash the rotation_enabled hunk into aa15b305f3 and the CHECK_NONFATAL hunk into 0b83dc4895 so each commit in the final stack is individually correct.

In `<commit:783ca1d1ef>`:
- [SUGGESTION] <commit:783ca1d1ef>:1: Fold the rotated-index work-block fix into the commit that introduced the bug
  This new top commit fixes the rotated pre-filter by gating on the shared cycle-base work block and extends feature_llmq_rotation.py to cover both rotated indices — the right final behavior. However, the bug it fixes was introduced earlier in the same unmerged PR by aa15b305f3 ('rpc: predict rotated DKG participation'). Since the PR merges without squashing, a git bisect landing between aa15b305f3 and 783ca1d1ef would find rotated quorumIndex>=1 prediction silently broken. This is the same pattern already flagged for 94eb4ad9f8 and f455571aea — the fixup chain on this file now compounds. Squash 783ca1d1ef into aa15b305f3 (and fold its test extension into whichever commit first added rotated coverage) so each commit is individually correct.

@thepastaclaw

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 4, 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

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 6, 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.

@thephez thephez added the RPC Some notable changes to RPC params/behaviour/descriptions label Jul 6, 2026
@thepastaclaw

Copy link
Copy Markdown
Author

Manual follow-up on current head f26c8bead8.

I found one additional issue that is separate from the already-posted exact-SHA review:

  • src/rpc/quorums.cpp:1063-1122: rotation_enabled is computed from IsQuorumRotationEnabled(llmq_params, pindexTip), which describes the tip's current DKG cycle, but the new upcoming_dkgs path predicts the next DKG cycle once its work block is known. Around DIP0024 activation, a rotation-capable quorum type can already be enabled at the tip while the current cycle is still non-rotated and the upcoming cycle is the first rotated one. In that window, this code sets quorums_num = 1, computes the non-rotated work height, enters the non-rotated branch for a useRotation=true quorum, and ComputeNonRotatedQuorumMembersFromWorkBlock() returns {} because it explicitly rejects rotation params. The RPC then still emits known: true with memberCount: 0, which is worse than returning known: false and can hide the upcoming rotated quorum indices entirely.

The steady-state tests pass because they cover pre-v20/no-prediction and post-activation rotation, but not the activation-boundary window where the type is enabled and the next cycle's rotation state differs from pindexTip's current-cycle state. I think this should be fixed before merge by deriving the rotation decision for the predicted cycle, or by returning known=false when the future cycle's rotation state cannot be safely determined. At minimum, avoid reporting an empty helper result as a known quorum membership set.

@thepastaclaw

Copy link
Copy Markdown
Author

Pushed fixes for the review items in 999b0ca34e:\n\n- 9c02c020ed: derives upcoming-cycle rotation from the predicted cycle's DIP0024 state instead of the tip's current cycle, and propagates std::optional from prediction helpers so unavailable predictions return known=false rather than known=true/memberCount=0.\n- 999b0ca34e: cleans up the V19 deployment checks after threading the deployment-tip context through the helpers.\n\nLocal checks run before push:\n- git diff --check f26c8bead8562bb85adcefd772fcd8ba18f39461..HEAD\n- git clang-format --diff f26c8bead8562bb85adcefd772fcd8ba18f39461 -- src/rpc/quorums.cpp src/llmq/utils.cpp src/llmq/utils.h\n\nNo configured build directory in this worktree, so compile/functional coverage is left to PR CI now running.

@thepastaclaw

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 6, 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

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 6, 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.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 999b0ca34e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/rpc/quorums.cpp Outdated

@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

Source: reviewers = claude general opus; codex general gpt-5.5 (retry after unavailable gpt-5.5[high] alias); claude dash-core-commit-history opus; codex dash-core-commit-history gpt-5.5 (retry); verifier = claude opus (full retry); specialists = dash-core-commit-history.

Cumulative review at 999b0ca. The prior f26c8be deployment-gating finding is FIXED: the prediction helpers now take a deployment-tip context, refuse prediction when future V19 state is not knowable from the tip, and thread that context into BuildNewQuorumQuarterMembers; the RPC also predicts upcoming DIP0024 rotation state instead of using the tip's current cycle. No carried-forward prior findings remain, and the latest delta has no new runtime correctness issues. One new commit-history hygiene suggestion remains for the two review-fix commits added after f26c8be.

1 suggestion

Prior finding reconciliation:

  • prior-1: FIXED - Fixed at 999b0ca. ComputeNonRotatedQuorumMembersFromWorkBlock (src/llmq/utils.cpp:592-628) now accepts pDeploymentTipIndex, returns std::nullopt for platform LLMQ types when V19 is not active at tip, and derives EvoOnly = is_platform_llmq && v19_active_at_tip. ComputeRotatedQuorumMembersFromWorkBlock (src/llmq/utils.cpp:631-718) also accepts pDeploymentTipIndex, refuses to predict at lines 669-671 when !v19_active_at_tip && !TESTNET (matching the OR structure of skipRemovedMNs), and threads pDeploymentTipIndex into BuildNewQuorumQuarterMembers at lines 700-702. BuildNewQuorumQuarterMembers was refactored to accept an explicit pDeploymentIndex and cycleBaseHeight so skipRemovedMNs is evaluated against the caller-supplied context (tip for prediction, base index for canonical via the wrapper). The RPC dispatch at src/rpc/quorums.cpp:1079-1088 handles the analogous DIP0024 rotation prediction, reporting known=false when the future rotation state cannot be determined. The monotonic-deployment reasoning is sound: V19-active-at-tip implies V19-active-at-future-base; V19-inactive-at-tip means the future-base state is unknown. Commit 999b0ca correctly drops the redundant work-block V19 check because the work block is an ancestor of the tip, so V19-active-at-work is implied by V19-active-at-tip.

Carried-forward prior findings:

  • None.

New findings in the latest delta:

  • [SUGGESTION] commit:9c02c020:1: Fold the review-fix commits 9c02c02 and 999b0ca into the commits that introduced the affected code
    The last two commits in this stack patch behavior introduced earlier in the same PR that has never left this branch. 9c02c02 fixes (a) quorum_dkginfo routing the upcoming cycle through the wrong helper by calling IsQuorumRotationEnabled(pindexTip) (a call site added in 9ce1c4d and extended in f26c8be), and (b) ComputeNon/RotatedQuorumMembersFromWorkBlock gating DEPLOYMENT_V19 on the work block instead of the future quorum/cycle base (helpers introduced in 9ce1c4d/f26c8bea). 999b0ca then removes the !v19_active_at_work && !v19_active_at_tip redundancy and hoists is_platform_llmq — both against code the same PR just introduced two commits earlier. The 9c02c02 commit message itself is structured as "First review item... Second review item", the classic address-review-feedback pattern. Dash merges PR commits without squashing, so leaving these as separate commits permanently records intermediate versions of the prediction helpers that return known-wrong membership predictions around DIP0024 / V19 activation — a bisect hazard for anyone later chasing a DKG-prediction bug, with git blame on the helpers pointing at 999b0ca for a one-liner. Rebase the 9c02c02 hunks into 9ce1c4d (V19-gating signature/threading) and f26c8be (rotation-route fix), and fold 999b0ca into that cleanup, preserving any useful rationale in the final commit messages.
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 `<commit:9c02c020>`:
- [SUGGESTION] <commit:9c02c020>:1: Fold the review-fix commits 9c02c020 and 999b0ca3 into the commits that introduced the affected code
  The last two commits in this stack patch behavior introduced earlier in the same PR that has never left this branch. 9c02c020ed fixes (a) `quorum_dkginfo` routing the upcoming cycle through the wrong helper by calling `IsQuorumRotationEnabled(pindexTip)` (a call site added in 9ce1c4def6 and extended in f26c8bead8), and (b) `ComputeNon/RotatedQuorumMembersFromWorkBlock` gating `DEPLOYMENT_V19` on the work block instead of the future quorum/cycle base (helpers introduced in 9ce1c4de/f26c8bea). 999b0ca34e then removes the `!v19_active_at_work && !v19_active_at_tip` redundancy and hoists `is_platform_llmq` — both against code the same PR just introduced two commits earlier. The 9c02c020 commit message itself is structured as "First review item... Second review item", the classic address-review-feedback pattern. Dash merges PR commits without squashing, so leaving these as separate commits permanently records intermediate versions of the prediction helpers that return known-wrong membership predictions around DIP0024 / V19 activation — a bisect hazard for anyone later chasing a DKG-prediction bug, with `git blame` on the helpers pointing at 999b0ca3 for a one-liner. Rebase the 9c02c020 hunks into 9ce1c4def6 (V19-gating signature/threading) and f26c8bead8 (rotation-route fix), and fold 999b0ca34e into that cleanup, preserving any useful rationale in the final commit messages.

Add optional proTxHash support to quorum dkginfo and report upcoming DKG sessions whose work block is already available.

Use the already-mined work block to predict non-rotated v20 quorum membership, while reporting unknown membership when the future quorum base's deployment state cannot be determined from the current tip. This keeps the RPC from returning known membership based on a V19 state that may change before the future base block.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@thepastaclaw thepastaclaw force-pushed the rpc-dkg-scheduled-participation branch from 999b0ca to 9315b27 Compare July 7, 2026 01:27
@thepastaclaw

Copy link
Copy Markdown
Author

Rewrote the PR branch to address the commit-history feedback from the 999b0ca review.

  • Folded the V19/deployment-tip prediction fixes into 62e8beeff4 (rpc: expose upcoming DKG participation).
  • Folded the upcoming-cycle DIP0024 route fix plus the redundant V19-check cleanup into 9315b2778b (rpc: predict rotated DKG participation).
  • The resulting tree is identical to reviewed head 999b0ca34e; only the commit stack changed.

Local validation: git diff --check upstream/develop..HEAD, python3 -m py_compile test/functional/feature_llmq_rotation.py test/functional/feature_llmq_evo.py, and git diff --exit-code 999b0ca34e..HEAD all pass.

@thepastaclaw

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 7, 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.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9315b2778b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/rpc/quorums.cpp

@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

Incremental delta from 999b0ca3 to 9315b277 is empty, so this push rewrites history without changing the final tree. The carried-forward prior finding is FIXED: the stack is now two coherent commits on upstream/develop (62e8beeff4 rpc: expose upcoming DKG participation and 9315b2778b rpc: predict rotated DKG participation), with the previous review-fix commits folded away. No new in-scope findings were identified in the cumulative review.

Prior finding reconciliation:

  • prior-1: FIXED — The prior commit-history suggestion asked to fold review-fix commits 9c02c020 and 999b0ca3 into the commits that introduced the affected code. The current head no longer contains those commits as separate history, and the final tree is unchanged from 999b0ca3.

Carried-forward prior findings: none.

New findings in latest delta: none.

Source: reviewers = claude general opus (failed: quota exhausted, resets Jul 10 8am America/Chicago); codex general gpt-5.5; claude dash-core-commit-history opus (failed: quota exhausted, resets Jul 10 8am America/Chicago); codex dash-core-commit-history gpt-5.5; verifier = codex gpt-5.5; specialists = dash-core-commit-history.

Note: GitHub does not allow me to submit an approval on my own PR, so this is posted as a COMMENT while preserving the clean verified result.

@thepastaclaw thepastaclaw force-pushed the rpc-dkg-scheduled-participation branch from 9315b27 to 598a810 Compare July 7, 2026 02:03
@thepastaclaw

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 7, 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.

Extend quorum dkginfo upcoming membership prediction to rotated LLMQs by reusing the known cycle work block, historical quarter snapshots, and an explicit deployment-tip context.

Predict the upcoming cycle's DIP0024 state rather than the tip's current cycle state, and return known=false when future deployment state or rotated snapshots are not yet available. The same deployment-tip context is threaded through the rotated helper so V19-dependent skipRemovedMNs behavior matches the future cycle base without claiming certainty before the tip proves it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@thepastaclaw thepastaclaw force-pushed the rpc-dkg-scheduled-participation branch from 598a810 to 12b3ddb Compare July 7, 2026 02:10
@thepastaclaw

Copy link
Copy Markdown
Author

Pushed 12b3ddb46b with the latest review follow-ups folded into rpc: predict rotated DKG participation:

  • Re-check upcoming quorum type enablement against the predicted cycle base predecessor before emitting upcoming_dkgs, so legacy types that are disabled by the future base are skipped.
  • Derive DIP0024 rotation state from cycleBaseHeight - 1 when that block is already known, instead of letting tip-level activation mark remaining current-cycle indexes as rotated.
  • Skip quorumIndex > 0 entries when the predicted cycle is known non-rotated.

Resolved the two Codex review threads. Local checks: git diff --check, targeted git clang-format --diff 9315b2778bce29653a89d98834151c0582babc8d -- src/rpc/quorums.cpp, and python3 -m py_compile test/functional/feature_llmq_evo.py test/functional/feature_llmq_rotation.py.

@thepastaclaw

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 7, 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

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 7, 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.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 12b3ddb46b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/rpc/quorums.cpp
predicted_members = llmq::utils::ComputeRotatedQuorumMembersFromWorkBlock(
llmq_params.type,
{*CHECK_NONFATAL(node.dmnman), *CHECK_NONFATAL(llmq_ctx.qsnapman), chainman, pindexTip},
pWorkBlockIndex, quorumHeight, pindexTip);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use the cycle base for rotated V19 decisions

Fresh evidence is that this call still passes the current tip even for remaining indexes of an already-started rotated cycle. In regtest/custom activation windows where V20 is active and V19 activates after cycleBaseHeight but before a later quorum index starts, production built the cycle with BuildNewQuorumQuarterMembers(..., pCycleQuorumBaseBlockIndex) and skipRemovedMNs == false, while this prediction uses pindexTip and flips it to true, so upcoming_dkgs can report a different rotated membership set for the rest of that cycle.

Useful? React with 👍 / 👎.

@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

Incremental delta from 9315b277 to 598a8106 adds the disabled-quorum-type guard in src/rpc/quorums.cpp. The prior exact-SHA review at 9315b277 found no issues, and the cumulative recheck at 598a8106 remains clean: no carried-forward prior findings and no new in-scope findings in the latest delta.

Prior finding reconciliation:

  • prior review at 9315b277: STILL CLEAN - it had no findings, and the current-head recheck did not uncover any issue that should have been carried forward.

Carried-forward prior findings: none.

New findings in latest delta: none.

Source: reviewers = claude general opus (failed: quota exhausted, resets Jul 10 8am America/Chicago); codex general gpt-5.5; claude dash-core-commit-history opus (failed: quota exhausted, resets Jul 10 8am America/Chicago); codex dash-core-commit-history gpt-5.5; verifier = codex gpt-5.5; specialists = dash-core-commit-history.

Note: GitHub does not allow me to submit an approval on my own PR, so this is posted as a COMMENT while preserving the clean verified result.

@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

Source: reviewers = claude general opus (failed: quota exhausted, resets Jul 10 8am America/Chicago); codex general gpt-5.5; claude dash-core-commit-history opus (failed: quota exhausted, resets Jul 10 8am America/Chicago); codex dash-core-commit-history gpt-5.5; verifier = codex gpt-5.5 (recovery after opus quota exhaustion and an initial codex verifier run produced no final JSON); specialists = dash-core-commit-history.

Prior review at 9315b27 had no findings and remains reconciled as clean for carried-forward issues. The current cumulative review finds one new in-scope issue in src/rpc/quorums.cpp: upcoming_dkgs seeds candidates from quorum types enabled at the current tip, which can omit a determinable future DKG type before the later quorum-base enablement guard is reached.

Prior finding reconciliation:

  • prior review at 9315b277: STILL CLEAN - it had no findings, and the current cumulative recheck found no carried-forward prior issues.

Carried-forward prior findings: none.

New findings in latest delta:

  • blocking: src/rpc/quorums.cpp:1084 seeds upcoming_dkgs from quorum types enabled at the current tip, so a future quorum type whose quorum-base predecessor is already determinable can be omitted before the new future-base guard runs.

🔴 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 `src/rpc/quorums.cpp`:
- [BLOCKING] src/rpc/quorums.cpp:1084: Do not seed upcoming DKGs from tip-enabled quorum types only
  `upcoming_dkgs` iterates `llmq::GetEnabledQuorumTypes(chainman, pindexTip)`, so quorum types that are disabled at the RPC tip are skipped before the later upcoming-quorum-base checks can run. Canonical DKG validation checks enablement against the quorum base predecessor, and buried deployments such as DIP0024/DIP0020 can be determinable by height before they are active at the current tip. In that window, the work block for the first post-activation DKG can already be known, but this RPC will omit the session entirely instead of returning an unknown or known upcoming entry. Iterate the configured LLMQ params as the initial universe, then filter with the upcoming quorum-base predecessor logic.

Note: GitHub does not allow me to submit REQUEST_CHANGES on my own PR, so this is posted as a COMMENT while preserving the verified blocking finding.

Comment thread src/rpc/quorums.cpp

if (!proTxHash.IsNull()) {
UniValue upcoming(UniValue::VARR);
for (const auto& type : llmq::GetEnabledQuorumTypes(chainman, pindexTip)) {

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: Do not seed upcoming DKGs from tip-enabled quorum types only

upcoming_dkgs iterates llmq::GetEnabledQuorumTypes(chainman, pindexTip), so quorum types that are disabled at the RPC tip are skipped before the later upcoming-quorum-base checks can run. Canonical DKG validation checks enablement against the quorum base predecessor, and buried deployments such as DIP0024/DIP0020 can be determinable by height before they are active at the current tip. In that window, the work block for the first post-activation DKG can already be known, but this RPC will omit the session entirely instead of returning an unknown or known upcoming entry. Iterate the configured LLMQ params as the initial universe, then filter with the upcoming quorum-base predecessor logic.

source: ['codex-general']

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

RPC Some notable changes to RPC params/behaviour/descriptions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants