Skip to content

feat(rpc): expose upcoming DKG participation#7428

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

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

Conversation

@knst

@knst knst commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

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.

What was done?

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.

How Has This Been Tested?

See updates for functional tests

Breaking Changes

N/A

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

thepastaclaw commented Jul 8, 2026

Copy link
Copy Markdown

✅ Review complete (commit 3035e51)

@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: 5a9b3d4605

ℹ️ 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/llmq/utils.cpp
Comment on lines +622 to +627
auto quorumMembers = ComputeQuorumMembersByQuarterRotation(llmq_params, util_params, pWorkBlockIndex,
cycleBaseHeight, modifier, /*storeSnapshot=*/false);
if (quorumMembers.empty()) {
return std::nullopt;
}
return quorumMembers[quorumIndex];

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 Reject incomplete rotated predictions

When a rotated quorum is predicted and any of the three prior cycle snapshots is unavailable (GetSnapshotForBlock breaks out above), ComputeQuorumMembersByQuarterRotation still returns a non-empty outer vector containing only the quarters it could reconstruct plus the new quarter. This wrapper treats that as known and returns quorumMembers[quorumIndex], so quorum dkginfo can report a reduced memberCount and isMember=false for masternodes that are actually in one of the missing previous quarters (for example while the snapshot DB is incomplete or the required warm-up snapshots are not available). Please return std::nullopt unless the rotated prediction contains a full llmq_params.size members for the requested index.

Useful? React with 👍 / 👎.

@PastaPastaPasta PastaPastaPasta left a comment

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 found one correctness issue in the replacement branch. The simplified rotated prediction path can return known=true using incomplete previous-quarter data when the required rotated quorum snapshots are unavailable, which is unsafe for the Dashmate use case this RPC is meant to support.

I did not run the full functional tests locally; I did run git diff --check and Python compile checks for the touched functional-test files, both clean. CI is still partially pending on GitHub.
~~
Codex posted for me :(

Comment thread src/llmq/utils.cpp
@coderabbitai

coderabbitai Bot commented Jul 8, 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 refactors LLMQ quarter-rotation member selection around explicit work-block, modifier, and cycle-base inputs, adds future quorum prediction, extends quorum dkginfo with proTxHash and upcoming_dkgs, and updates functional validation for prediction and fallback behavior.

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

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant quorum_dkginfo_RPC
  participant ComputeQuorumMembersFromWorkBlock
  participant ComputeQuorumMembersByQuarterRotation
  participant BuildNewQuorumQuarterMembers

  Client->>quorum_dkginfo_RPC: quorum dkginfo(proTxHash)
  quorum_dkginfo_RPC->>quorum_dkginfo_RPC: compute cycle base height and work block
  quorum_dkginfo_RPC->>ComputeQuorumMembersFromWorkBlock: predict members for quorumHeight
  ComputeQuorumMembersFromWorkBlock->>ComputeQuorumMembersByQuarterRotation: select quarter-rotation members
  ComputeQuorumMembersByQuarterRotation->>BuildNewQuorumQuarterMembers: build with modifier and cycleBaseHeight
  BuildNewQuorumQuarterMembers-->>ComputeQuorumMembersByQuarterRotation: return quarter members
  ComputeQuorumMembersByQuarterRotation-->>ComputeQuorumMembersFromWorkBlock: return quorum list
  ComputeQuorumMembersFromWorkBlock-->>quorum_dkginfo_RPC: return optional member list
  quorum_dkginfo_RPC-->>Client: return upcoming_dkgs results
Loading

Suggested reviewers: PastaPastaPasta, thepastaclaw, UdjinM6

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main RPC enhancement: exposing upcoming DKG participation.
Description check ✅ Passed The description matches the change set and explains the new dkginfo behavior and supporting utilities.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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)

457-462: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Guard the implicit m_base_index == cycleBaseHeight coupling.

The function was refactored to take cycleBaseHeight explicitly, but the snapshot path still relies on util_params.m_base_index for both BuildQuorumSnapshot and StoreSnapshotForBlock. This silently assumes m_base_index->nHeight == cycleBaseHeight whenever storeSnapshot is true. It holds today because GetAllQuorumMembers calls replace_index(pCycleQuorumBaseBlockIndex), but a future caller passing a divergent cycleBaseHeight with storeSnapshot=true would persist a snapshot keyed to the wrong block. Consider asserting the invariant.

🛡️ Suggested guard
     if (storeSnapshot) {
+        ASSERT_IF_DEBUG(util_params.m_base_index->nHeight == cycleBaseHeight);
         llmq::CQuorumSnapshot quorumSnapshot{};
         BuildQuorumSnapshot(llmqParams, util_params.m_chainman.GetConsensus(), allMns, MnsUsedAtH, sortedCombinedMnsList,
                             quorumSnapshot, skipList, util_params.m_base_index);
         util_params.m_qsnapman.StoreSnapshotForBlock(llmqParams.type, util_params.m_base_index, quorumSnapshot);
     }
🤖 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 457 - 462, The snapshot branch in the quorum
member flow still assumes util_params.m_base_index matches cycleBaseHeight when
storeSnapshot is true. In the BuildQuorumSnapshot and StoreSnapshotForBlock
path, add an explicit guard/assert around that invariant in GetAllQuorumMembers
so future callers cannot persist a snapshot under the wrong block index; keep
the check close to the existing use of util_params.m_base_index and
cycleBaseHeight.
🤖 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/test_framework/test_framework.py`:
- Around line 2146-2159: The quorum prediction validation in test_framework.py
only asserts that memberIndex is present or not -1, so an incorrect positive
index could still pass. Update the checks in the prediction loop around
quorum_info["members"] and predictions to compare entry["memberIndex"] against
the actual position of proTxHash within quorum_info["members"], while still
keeping the existing isMember and memberCount assertions.

---

Nitpick comments:
In `@src/llmq/utils.cpp`:
- Around line 457-462: The snapshot branch in the quorum member flow still
assumes util_params.m_base_index matches cycleBaseHeight when storeSnapshot is
true. In the BuildQuorumSnapshot and StoreSnapshotForBlock path, add an explicit
guard/assert around that invariant in GetAllQuorumMembers so future callers
cannot persist a snapshot under the wrong block index; keep the check close to
the existing use of util_params.m_base_index and cycleBaseHeight.
🪄 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: 0b14d51e-6d0b-49a4-9f20-9de5347ba22c

📥 Commits

Reviewing files that changed from the base of the PR and between 84b6bf6 and 5a9b3d4.

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

Comment thread test/functional/test_framework/test_framework.py Outdated
@knst knst requested a review from PastaPastaPasta July 8, 2026 17:37

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

Code Review

Source: reviewers: codex/gpt-5.5 general, codex/gpt-5.5 dash-core-commit-history; failed lanes: claude/opus general, claude/opus dash-core-commit-history, claude/opus verifier (quota); verifier: codex/gpt-5.5.

The main correctness issue is confirmed: rotated quorum prediction can return known=true after silently dropping unavailable prior-quarter data, which contradicts the RPC's safety semantics for Dashmate. The added prediction tests also leave the new memberIndex field under-verified by checking only membership, not the returned position in the quorum member order.

1 blocking, 1 suggestion

Blocking

  • src/llmq/utils.cpp:490-500 - Missing rotated snapshots still produce known predictions
    In prediction mode, this loop stops as soon as a previous cycle ancestor or snapshot is unavailable, but it still proceeds with the remaining PreviousQuorumQuarters entries left empty. BuildNewQuorumQuarterMembers then computes a new quarter from that incomplete history, ComputeQuorumMembersFromWorkBlock returns a value, and quorum dkginfo reports known=true. For the Dashmate restart-safety use case, that can falsely report a masternode as not selected when it would have appeared in one of the missing historical quarters; unavailable rotated snapshot data must make the prediction unknown instead of partial.

Suggestion

  • test/functional/test_framework/test_framework.py:2146-2159 - Prediction tests do not verify the returned member index
    The new RPC exposes memberIndex, but the test only checks whether it is -1 consistently with isMember. A regression that returns the wrong positive index for a real member would still pass, even though quorum info exposes members in the same order used for quorum member indexes and consumers may rely on that position.
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`:
- [BLOCKING] src/llmq/utils.cpp:490-500: Missing rotated snapshots still produce known predictions
  In prediction mode, this loop stops as soon as a previous cycle ancestor or snapshot is unavailable, but it still proceeds with the remaining `PreviousQuorumQuarters` entries left empty. `BuildNewQuorumQuarterMembers` then computes a new quarter from that incomplete history, `ComputeQuorumMembersFromWorkBlock` returns a value, and `quorum dkginfo` reports `known=true`. For the Dashmate restart-safety use case, that can falsely report a masternode as not selected when it would have appeared in one of the missing historical quarters; unavailable rotated snapshot data must make the prediction unknown instead of partial.

In `test/functional/test_framework/test_framework.py`:
- [SUGGESTION] test/functional/test_framework/test_framework.py:2146-2159: Prediction tests do not verify the returned member index
  The new RPC exposes `memberIndex`, but the test only checks whether it is `-1` consistently with `isMember`. A regression that returns the wrong positive index for a real member would still pass, even though `quorum info` exposes members in the same order used for quorum member indexes and consumers may rely on that position.

Comment on lines +2146 to +2159
members = set(m["proTxHash"] for m in quorum_info["members"])
work_height = quorum_info["height"] - quorum_info["quorumIndex"] - 8
for proTxHash, entries in predictions.items():
[entry] = [d for d in entries if d["quorumHeight"] == quorum_info["height"]]
assert_equal(entry["proTxHash"], proTxHash)
if not entry["known"]:
# no prediction was possible (e.g. pre-v20); the RPC must tell why
assert "reason" in entry
continue
assert_equal(entry["workBlockHeight"], work_height)
assert_equal(entry["workBlockHash"], self.nodes[0].getblockhash(work_height))
assert_equal(entry["memberCount"], len(members))
assert_equal(entry["isMember"], entry["memberIndex"] != -1)
assert_equal(entry["isMember"], proTxHash in members)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion: Prediction tests do not verify the returned member index

The new RPC exposes memberIndex, but the test only checks whether it is -1 consistently with isMember. A regression that returns the wrong positive index for a real member would still pass, even though quorum info exposes members in the same order used for quorum member indexes and consumers may rely on that position.

Suggested change
members = set(m["proTxHash"] for m in quorum_info["members"])
work_height = quorum_info["height"] - quorum_info["quorumIndex"] - 8
for proTxHash, entries in predictions.items():
[entry] = [d for d in entries if d["quorumHeight"] == quorum_info["height"]]
assert_equal(entry["proTxHash"], proTxHash)
if not entry["known"]:
# no prediction was possible (e.g. pre-v20); the RPC must tell why
assert "reason" in entry
continue
assert_equal(entry["workBlockHeight"], work_height)
assert_equal(entry["workBlockHash"], self.nodes[0].getblockhash(work_height))
assert_equal(entry["memberCount"], len(members))
assert_equal(entry["isMember"], entry["memberIndex"] != -1)
assert_equal(entry["isMember"], proTxHash in members)
member_list = [m["proTxHash"] for m in quorum_info["members"]]
members = set(member_list)
work_height = quorum_info["height"] - quorum_info["quorumIndex"] - 8
for proTxHash, entries in predictions.items():
[entry] = [d for d in entries if d["quorumHeight"] == quorum_info["height"]]
assert_equal(entry["proTxHash"], proTxHash)
if not entry["known"]:
# no prediction was possible (e.g. pre-v20); the RPC must tell why
assert "reason" in entry
continue
assert_equal(entry["workBlockHeight"], work_height)
assert_equal(entry["workBlockHash"], self.nodes[0].getblockhash(work_height))
assert_equal(entry["memberCount"], len(members))
expected_member_index = member_list.index(proTxHash) if proTxHash in members else -1
assert_equal(entry["memberIndex"], expected_member_index)
assert_equal(entry["isMember"], proTxHash in members)

source: ['codex']

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Resolved in e0e1e8fPrediction tests do not verify the returned member index no longer present.

Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.

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

Code Review

Source: reviewers: codex/gpt-5.5 general, codex/gpt-5.5 dash-core-commit-history; failed lanes: claude/opus general, claude/opus dash-core-commit-history; verifier: codex/gpt-5.5

prior-1 is STILL VALID: the current rotated prediction path can still return a known result after missing historical quarter data. prior-2 is FIXED by e0e1e8f, which now checks the exact ordered member index from quorum info. The latest push also introduced a small review-fix commit that should be folded into the feature commit before merge.

🔴 1 blocking | 🟡 1 suggestion(s)

2 finding(s) are included in the review body only; the current diff does not expose stable inline anchors for the carried-forward production issue or the commit-history note.

🤖 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`:
- [BLOCKING] src/llmq/utils.cpp:490-500: Missing rotated snapshots still produce known predictions
  In prediction mode, this loop stops as soon as a previous cycle ancestor or snapshot is unavailable, but it still proceeds with the remaining PreviousQuorumQuarters entries left empty. BuildNewQuorumQuarterMembers then computes from incomplete history, ComputeQuorumMembersFromWorkBlock returns a value, and quorum dkginfo reports known=true. The feature commit explicitly promises structured unknown results for unavailable rotated snapshots, so this can falsely report a masternode as not selected when the missing historical quarter would have included it.

In `<commit:e0e1e8f>`:
- [SUGGESTION] <commit:e0e1e8f>:1: Squash memberIndex test fix into the feature commit
  Commit e0e1e8f6d49 only adjusts the functional test helper added by the preceding feature commit so it verifies memberIndex correctly. This is review-fix history rather than a separate logical change, and Dash PRs are kept cleaner when these small corrections are folded into the commit that introduced the behavior.

@knst

knst commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

prior-1 is STILL VALID: the current rotated prediction path can still return a known result after missing historical quarter data.

Concrete cases when it happens:

first few rotated cycles after DIP0024 activation / before 3 prior rotated snapshots exist
devnet/regtest with DIP0024 active from height 1
node with incomplete/corrupt/rebuilt EvoDB snapshot data

That's not real life scenarios and have nothing to do with PR description. there's no combination of "historical data" and "alive valid masternode"

@knst knst requested a review from thepastaclaw July 8, 2026 18:35
knst and others added 3 commits July 9, 2026 02:03
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.

Co-authored-by: PastaClaw <thepastaclaw@users.noreply.github.com>
…after missing historical quarter data

It never happens in real-life scenarios, only some corner cases such as:
     - first few rotated cycles after DIP0024 activation / before 3 prior rotated snapshots exist
     - devnet/regtest with DIP0024 active from height 1
     - node with incomplete/corrupt/rebuilt EvoDB snapshot data

Though, review agents are concerned about that issue very much, so it should be fixed.
@knst knst force-pushed the rpc-dkg-scheduled-participation-2 branch from 6f3f841 to 2629a3b Compare July 8, 2026 19:04

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

Code Review

Source: reviewers: codex/gpt-5.5 general, codex/gpt-5.5 dash-core-commit-history; failed lanes: claude/opus general, claude/opus dash-core-commit-history, claude/opus verifier (quota); verifier: codex/gpt-5.5.

The prior rotated-snapshot correctness finding is fixed at the current head: prediction mode now returns unknown when required historical rotated quorum data is unavailable. No new code-correctness issue was verified in the latest delta. The remaining verified issue is commit hygiene: both follow-up fix commits correct behavior introduced by the main feature commit and should be folded before merge.

🟡 1 suggestion

Prior Reconciliation

  • prior-1 FIXED: 2629a3b3570 makes prediction mode return no result when a required previous rotated cycle ancestor or snapshot is missing, so quorum dkginfo reports known=false instead of computing from incomplete historical quarters.
  • prior-2 STILL VALID: the memberIndex test correction is still present as a separate follow-up commit, now rewritten as 1f745e1f8db, rather than being folded into the feature commit that introduced the helper.

Carried-Forward Prior Findings

  • <commit:1f745e1> - Squash the memberIndex test fix into a1e59f1b8b0 so the feature lands with the corrected test helper from the start.

New Findings In Latest Delta

  • <commit:2629a3b> - The rotated prediction repair fixes the prior production issue, but it is also a direct review-fix commit for behavior introduced by a1e59f1b8b0; fold it into the feature commit before merge.
🤖 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:1f745e1..2629a3b>`:
- [SUGGESTION] <commit:1f745e1..2629a3b>:1: Squash review-fix commits into the feature commit
  The current stack still has one feature commit followed by two small corrective commits: 1f745e1f8db only fixes the functional test helper added by a1e59f1b8b0, and 2629a3b3570 only fixes the rotated prediction behavior introduced by that same feature. These are not independent logical changes; they are review fixes for the new RPC/LLMQ prediction behavior. Since Dash preserves PR commit history, fold both fix commits into a1e59f1b8b0 so the merged history does not retain a known-bad intermediate implementation.

PastaPastaPasta
PastaPastaPasta previously approved these changes Jul 8, 2026

@PastaPastaPasta PastaPastaPasta left a comment

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.

utACK 2629a3b

@knst knst requested a review from UdjinM6 July 9, 2026 19:34

@kwvg kwvg left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Preferable to use standardised docs for Dash-specific result fields

Comment thread src/rpc/quorums.cpp Outdated
Comment thread src/rpc/quorums.cpp Outdated
Comment thread src/rpc/quorums.cpp Outdated
Comment thread src/rpc/quorums.cpp Outdated
…utput

Co-authored-by: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com>
@knst knst force-pushed the rpc-dkg-scheduled-participation-2 branch from d557a14 to 4534eb8 Compare July 10, 2026 13:16

@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: 53be3436a0

ℹ️ 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

@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

🤖 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 `@src/rpc/quorums.cpp`:
- Around line 1072-1074: Replace the out-of-scope obj.pushKV call in the quorum
result-building logic with ret.pushKV so proTxHash is added to the top-level
response; keep the existing proTxHash null check and subsequent upcoming
construction unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a3f6ea75-9935-49d4-93c5-a64fe33d4c26

📥 Commits

Reviewing files that changed from the base of the PR and between 4534eb8 and 53be343.

📒 Files selected for processing (2)
  • src/rpc/quorums.cpp
  • test/functional/test_framework/test_framework.py
💤 Files with no reviewable changes (1)
  • test/functional/test_framework/test_framework.py

Comment thread src/rpc/quorums.cpp
@knst knst force-pushed the rpc-dkg-scheduled-participation-2 branch from 53be343 to f571843 Compare July 10, 2026 14:10

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

ℹ️ 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 test/functional/test_framework/test_framework.py Outdated

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

Code Review

Carried-forward prior findings: prior-2 (blocking) STILL VALID — verify_upcoming_dkg_predictions still reads entry["proTxHash"] at test_framework.py:2151 after the field moved to the dkginfo top level, so mine_quorum/rotation verification raises KeyError; prior-3, prior-4, prior-5 (suggestions) STILL VALID. New findings in the latest delta: none — the one-line 53be343..f571843 change (obj.pushKV -> ret.pushKV at quorums.cpp:1073) fixes prior-1 (compile break). Additional cumulative current-head findings: none. review_action REQUEST_CHANGES because the KeyError blocker remains.

Source: reviewers — general: opus (ok), gpt-5.6-sol (failed: revoked refresh token); dash-core-commit-history: opus (ok), gpt-5.6-sol (failed: revoked refresh token). Verifier: opus.

🔴 1 blocking | 🟡 3 suggestion(s)

1 additional finding(s) omitted (not in diff).

🤖 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 `test/functional/test_framework/test_framework.py`:
- [BLOCKING] test/functional/test_framework/test_framework.py:2151: verify_upcoming_dkg_predictions reads per-entry proTxHash that only exists at the response top level
  The dkginfo RPC emits proTxHash once at the response top level (src/rpc/quorums.cpp:1073) and never inside each upcoming_dkgs entry. get_upcoming_dkg_predictions (line 2141) keeps only the upcoming_dkgs list and discards the top-level field, but verify_upcoming_dkg_predictions still reads entry["proTxHash"] at line 2151. Now that the compile error is fixed, this raises KeyError when a matching entry is verified. verify_upcoming_dkg_predictions runs inside the shared mine_quorum helper and the rotation flow, so functional tests break. The predictions dict is already keyed by the queried proTxHash, so drop this per-entry assertion or capture and assert against the new top-level field instead.

In `src/rpc/quorums.cpp`:
- [SUGGESTION] src/rpc/quorums.cpp:1006: llmqTypeName is emitted but not documented in the upcoming_dkgs help schema
  Line 1103 emits llmqTypeName for every upcoming entry, but the upcoming_dkgs help block omits it. RPCResult object checking is shallow, so this response/help mismatch is not caught automatically. Re-add llmqTypeName to the help schema or stop emitting it.
- [SUGGESTION] src/rpc/quorums.cpp:1001: Top-level proTxHash documented as required but omitted when null
  GetRpcResult defaults optional to false, so the help advertises top-level proTxHash as always present. But it is emitted only inside if (!proTxHash.IsNull()) at line 1073. In observer/watch-only mode with no explicit argument, node.active_ctx is null and proTxHash stays null, so the field is absent. Mark it optional to match the response shape.

In `<commit:a1e59f1..f571843>`:
- [SUGGESTION] <commit:a1e59f1..f571843>:1: Squash the within-PR fix/refactor/cleanup commits into the feature commit
  Feature commit a1e59f1 is followed by four commits that only correct or polish this unmerged feature: 1f745e1, 2629a3b, 4534eb8, and f5718437. memberIndex/memberCount are introduced, tested, help-refactored, then removed across the stack, and f5718437 also repairs the earlier obj-vs-ret compile break. Fold the four follow-ups into a1e59f1 so permanent Dash develop history contains one coherent feature commit without artificial intermediate states.

Comment thread test/functional/test_framework/test_framework.py Outdated
Comment thread src/rpc/quorums.cpp
Comment thread src/rpc/quorums.cpp Outdated
{
{RPCResult::Type::NUM, "active_dkgs", "Total number of active DKG sessions this node is participating in right now"},
{RPCResult::Type::NUM, "next_dkg", "The number of blocks until the next potential DKG session"},
GetRpcResult("proTxHash"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion: Top-level proTxHash documented as required but omitted when null

GetRpcResult defaults optional to false, so the help advertises top-level proTxHash as always present. But it is emitted only inside if (!proTxHash.IsNull()) at line 1073. In observer/watch-only mode with no explicit argument, node.active_ctx is null and proTxHash stays null, so the field is absent. Mark it optional to match the response shape.

Suggested change
GetRpcResult("proTxHash"),
GetRpcResult("proTxHash", /*optional=*/true),

source: ['claude']

@knst knst force-pushed the rpc-dkg-scheduled-participation-2 branch from f571843 to 618a62d Compare July 10, 2026 14:44
@knst knst force-pushed the rpc-dkg-scheduled-participation-2 branch from 618a62d to d913a48 Compare July 10, 2026 15:04

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

Code Review

Source: reviewers — general: opus, gpt-5.6-sol; dash-core-commit-history: opus, gpt-5.6-sol. Verifier: opus.

Prior Finding Reconciliation: prior-1 (per-entry proTxHash KeyError, blocking) is FIXED — the latest delta deletes the assert_equal(entry["proTxHash"], proTxHash) line at test_framework.py, and proTxHash is now sourced solely from the predictions dict keys. prior-2 (llmqTypeName undocumented) is FIXED — the response emits only llmqType (quorums.cpp:1102) and the help schema documents only llmqType (line 1006); no llmqTypeName remains. prior-3 (top-level proTxHash documented required) is STILL VALID. prior-4 (squash the within-PR commit stack) is STILL VALID. Carried-forward prior findings: prior-3 and prior-4, both re-anchored to current head d913a48. New findings in latest delta: none — the one-line deletion only resolves prior-1. Cumulative current-head review adds one performance suggestion in the rotated-quorum prediction loop. No blocking issues remain; three suggestions total.

🟡 2 suggestion(s)

1 additional finding(s) omitted (not in diff).

1 carried-forward finding(s) already raised on this PR; not re-posting as new inline comments.

🤖 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`:
- [SUGGESTION] src/rpc/quorums.cpp:1125-1129: Compute each rotated cycle only once per LLMQ type
  ComputeQuorumMembersFromWorkBlock is called inside the per-quorumIndex loop, but for rotated types it delegates to ComputeQuorumMembersByQuarterRotation (utils.cpp:624), which reconstructs every quorum in the cycle before returning just quorumMembers[quorumIndex] (utils.cpp:629). For mainnet LLMQ_60_75, signingActiveQuorumCount is 32, so a single dkginfo request rebuilds the same 32-quorum cycle 32 times — repeatedly loading historical snapshots and sorting masternode lists. Since all indices in a cycle share the same work block and cycle base, compute the rotated cycle once per LLMQ type and index into its cached results.

In `<commit:a1e59f1..d913a48>`:
- [SUGGESTION] <commit:a1e59f1..d913a48>:1: Squash the within-PR fix/refactor/cleanup commits into the feature commit
  Feature commit a1e59f1 ("feat(rpc): expose upcoming DKG participation") is followed by four commits that only correct or polish this still-unmerged feature: 1f745e1 (adds memberIndex/memberCount functional assertions), 2629a3b (fixes rotated-prediction handling, framed as review feedback), 4534eb8 (refactors the RPC help), and d913a48 (removes memberIndex/memberCount/per-entry proTxHash/llmqTypeName that earlier commits introduced and drops the corresponding test assertions). Because Dash merges without squashing, permanent develop history would land with artificial intermediate states where fields appear then vanish and tests assert on fields later deleted — noise for git blame/bisect. d913a48 also carries a `feat:` prefix even though its diff is a cleanup/removal. Fold the follow-ups into a1e59f1 so the branch lands as one coherent feature commit; keep any change with durable standalone value as a separate correctly-prefixed commit. (Carried forward from prior review, STILL VALID at current head.)

Comment thread src/rpc/quorums.cpp
Comment on lines +1125 to +1129
const LLMQContext& llmq_ctx = EnsureLLMQContext(node);
const auto predicted_members = llmq::utils::ComputeQuorumMembersFromWorkBlock(
llmq_params.type,
{*CHECK_NONFATAL(node.dmnman), *CHECK_NONFATAL(llmq_ctx.qsnapman), chainman, pindexTip},
pWorkBlockIndex, quorumHeight);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion: Compute each rotated cycle only once per LLMQ type

ComputeQuorumMembersFromWorkBlock is called inside the per-quorumIndex loop, but for rotated types it delegates to ComputeQuorumMembersByQuarterRotation (utils.cpp:624), which reconstructs every quorum in the cycle before returning just quorumMembers[quorumIndex] (utils.cpp:629). For mainnet LLMQ_60_75, signingActiveQuorumCount is 32, so a single dkginfo request rebuilds the same 32-quorum cycle 32 times — repeatedly loading historical snapshots and sorting masternode lists. Since all indices in a cycle share the same work block and cycle base, compute the rotated cycle once per LLMQ type and index into its cached results.

source: ['codex']

@knst knst requested a review from kwvg July 10, 2026 15:41

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

Code Review

Prior Finding Reconciliation: prior-1 (top-level proTxHash documented required at quorums.cpp:1001) is FIXED — the entire delta since d913a48 is exactly GetRpcResult("proTxHash", /*optional=*/true), verified in the current checkout. prior-2 (recompute rotated cycle once per LLMQ type instead of per quorumIndex, quorums.cpp:1125-1129) is STILL VALID — confirmed unchanged: ComputeQuorumMembersFromWorkBlock is still invoked inside the per-quorumIndex loop and calls ComputeQuorumMembersByQuarterRotation (llmq/utils.cpp:470-489, 624-629), which rebuilds the full rotated cycle before returning a single index; the existing non-predicting cache path (GetAllQuorumMembers, utils.cpp:699-708) is not reused for prediction. prior-3 (squash within-PR fix/refactor/cleanup commits) is STILL VALID and now spans a1e59f1..3035e51 (6 commits, verified via git log); commit 2629a3b's own message confirms it is a corner-case fix requested by review agents on the still-unmerged feature. Carried-forward prior findings: prior-2 and prior-3, both re-anchored to current head. New findings in latest delta: none — the one-line change is a correct, targeted fix with no side effects. No blocking issues; two suggestions total.

Source (experiment sonnet-primary-opus-quarter-sample-20260710, cohort sonnet_opus_sample, bucket 0): reviewers codex/general=gpt-5.6-sol(completed); sonnet5/general=claude-sonnet-5(completed); opus/general=claude-opus-4-8(completed); codex/dash-core-commit-history=gpt-5.6-sol(completed); sonnet5/dash-core-commit-history=claude-sonnet-5(completed); opus/dash-core-commit-history=claude-opus-4-8(completed); verifier=verifier-sonnet5-7428-1783846201=claude-sonnet-5; orchestrator=openai/gpt-5.6-sol reasoning=high (orchestration-only, not a reviewer/verifier).

🟡 1 suggestion(s)

1 additional finding(s) omitted (not in diff).

1 carried-forward finding(s) already raised on this PR; not re-posting as new inline comments.

🤖 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:a1e59f1..3035e51>`:
- [SUGGESTION] <commit:a1e59f1..3035e51>:1: Squash the within-PR fix/refactor/cleanup commits into the feature commit
  Feature commit a1e59f1 ('feat(rpc): expose upcoming DKG participation') is followed by five commits that only correct or polish this still-unmerged feature: 1f745e1 (adds memberIndex/memberCount functional assertions), 2629a3b (fixes rotated-prediction handling — its own message says the corner case 'never happens in real-life scenarios' but was fixed because 'review agents are concerned about that issue very much'), 4534eb8 (refactors the RPC help just added), d913a48 (removes memberIndex/memberCount/per-entry proTxHash/llmqTypeName that earlier commits introduced and drops the corresponding test assertions, under a `feat:` prefix despite being a cleanup), and 3035e51 ('fix: add optional for proTxHash') — a one-line correction to the exact same GetRpcResult("proTxHash") entry a1e59f1 introduced. Because Dash merges without squashing, permanent develop history would show fields appearing then vanishing and a help schema being wrong for several commits before correction — pure noise for git blame/bisect. Fold these five commits into a1e59f1 (git rebase -i / --autosquash) so the branch lands as one coherent feature commit; keep any change with durable standalone value as a separate correctly-prefixed commit.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants