Skip to content

Conversation

@knst
Copy link
Collaborator

@knst knst commented Nov 13, 2025

Issue being fixed or feature implemented

  • llmq code for signing runs in 2 different modes depending on spork21 value. It complicates implementation signinficantly; while spork21 is active and hardened on mainnet and there's no plans to change a behavior, no reason to keep this implementation. This refactoring is also a blocker for refactor: drop dependency on net_processing for multiple consensus related objects #6934 because separation of network code is over complicated for llmq/signing_share module.

  • Having spork21 increase scope for functional tests; The mechanism of recovered signatures is very different if spork21 is active or not. The functional test feature_llmq_signing indeed runs in 2 modes to ensure that signing mechanism works correctly with and without spork21, but I just have found a bug in a functional test feature_llmq_is_retroactive.py which assumed spork21 is disabled. See commits.

What was done?

  1. drop spork21 as always active and hardened on mainnet
  2. drop unused handlers for p2p messages (QSIGSESANN, QSIGSHARESINV, QGETSIGSHARES) in llmq/signing_shares and related code
  3. fixed feature_llmq_is_retroactive.py with spork21 active
  4. functional tests on CI (especially tsan) are expected to finish ~half-minute faster
35/299 - feature_llmq_signing.py passed, Duration: 136 s <---- removed
38/299 - feature_llmq_signing.py --spork21 passed, Duration: 163 s

How Has This Been Tested?

Run unit & functional tests

Breaking Changes

There's no actually breaking changes; because spork21 is hardened on mainnet and no practical usage of spork21 on devnets or testnet.

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

@knst knst added this to the 23.1 milestone Nov 13, 2025
@github-actions
Copy link

@coderabbitai
Copy link

coderabbitai bot commented Nov 13, 2025

Walkthrough

This pull request removes all references to SPORK_21_QUORUM_ALL_CONNECTED ("all members connected" spork) and eliminates spork manager dependencies from the LLMQ quorum subsystem. Changes include: renaming the spork to deprecated status, removing the IsAllMembersConnectedEnabled() function, deleting the sporkman parameter from CQuorumManager and utility function constructors, simplifying quorum connection logic to always include all members unconditionally, removing spork-based conditionals from signing shares message handling, deleting the GetMasternodeQuorumNodes() network function, and updating all call sites and tests to remove spork-related logic and activations.

Sequence Diagram(s)

sequenceDiagram
    actor Before as Before (with SPORK_21)
    participant QM as CQuorumManager
    participant Utils as utils::GetQuorumConnections
    participant Spork as CSporkManager
    
    Before->>QM: new(..., sporkman)
    QM->>Utils: GetQuorumConnections(..., sporkman)
    Utils->>Spork: Check IsAllMembersConnectedEnabled()
    alt All Connected Enabled
        Spork-->>Utils: true
        Utils-->>QM: Return all members
    else All Connected Disabled
        Spork-->>Utils: false
        Utils-->>QM: Return filtered members
    end
Loading
sequenceDiagram
    actor After as After (SPORK_21 removed)
    participant QM as CQuorumManager
    participant Utils as utils::GetQuorumConnections
    
    After->>QM: new(...) [no sporkman]
    QM->>Utils: GetQuorumConnections(...) [no sporkman]
    Utils-->>QM: Return all members (deterministic)
    
    Note over After,Utils: Unconditional behavior, no spork dependency
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas requiring extra attention:

  • src/llmq/signing_shares.h/cpp: Largest refactoring; removal of CSigSesAnn, CSigSharesInv, CBatchedSigShares classes and significant simplification of message processing paths. Verify that all session-related logic is properly consolidated.
  • src/llmq/utils.cpp: Logic change in GetQuorumConnections where conditional early-return is removed and all members are now always included; ensure deterministic behavior is correct.
  • src/llmq/dkgsession.cpp: Removal of spork-conditional check means connections are now unconditionally marked as bad for unverified members; verify this tightens requirements correctly.
  • Constructor signature changes across CQuorumManager, CSigSharesManager, and utility functions: ensure all instantiation sites are updated consistently across the codebase.
  • Test changes: Verify that removal of SPORK_21 activations doesn't mask or hide existing test failures, and that test expectations properly reflect unconditional behavior.
  • src/net.cpp/h: Verify that removal of GetMasternodeQuorumNodes() doesn't break any calling code paths (check RPC and internal callers).

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.51% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly summarizes the main change: removing spork21 and related code from the LLMQ system. It is concise, specific, and accurately reflects the primary objective of the changeset.
Description check ✅ Passed The PR description clearly explains the rationale for removing spork21, the work performed, and testing approach.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
test/functional/feature_llmq_is_retroactive.py (1)

68-68: Consistent mocktime bumps

Using 10-second bumps at synchronization points looks fine and reduces wall time. Consider using a small helper (e.g., bump_and_sync) if this pattern spreads further, but not required here.

Also applies to: 89-89, 99-99, 104-104, 110-110, 131-131, 136-136

test/functional/test_framework/test_framework.py (2)

1933-1939: Fix bare except in wait_for_instantlock

Use explicit exceptions to satisfy lint and avoid hiding bugs.

-        def check_instantlock():
-            try:
-                self.bump_mocktime(1)
-                return node.getrawtransaction(txid, True)["instantlock"]
-            except:
-                return False
+        def check_instantlock():
+            try:
+                self.bump_mocktime(1)
+                return node.getrawtransaction(txid, True)["instantlock"]
+            except JSONRPCException:
+                return False
+            except KeyError:
+                return False

1943-1951: Fix bare except in wait_for_chainlocked_block

Mirror the explicit handling and keep the 1s step bump.

-        def check_chainlocked_block():
-            try:
-                self.bump_mocktime(1)
-                block = node.getblock(block_hash)
-                return block["confirmations"] > 0 and block["chainlock"]
-            except:
-                return False
+        def check_chainlocked_block():
+            try:
+                self.bump_mocktime(1)
+                block = node.getblock(block_hash)
+                return block["confirmations"] > 0 and block["chainlock"]
+            except JSONRPCException:
+                return False
+            except KeyError:
+                return False
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a39960b and d0e52c3.

📒 Files selected for processing (24)
  • src/llmq/context.cpp (1 hunks)
  • src/llmq/dkgsession.cpp (1 hunks)
  • src/llmq/dkgsessionhandler.cpp (1 hunks)
  • src/llmq/options.cpp (0 hunks)
  • src/llmq/options.h (0 hunks)
  • src/llmq/quorums.cpp (3 hunks)
  • src/llmq/quorums.h (1 hunks)
  • src/llmq/signing_shares.cpp (4 hunks)
  • src/llmq/signing_shares.h (2 hunks)
  • src/llmq/utils.cpp (3 hunks)
  • src/llmq/utils.h (2 hunks)
  • src/masternode/active/context.cpp (1 hunks)
  • src/net.cpp (0 hunks)
  • src/net.h (0 hunks)
  • src/rpc/quorums.cpp (1 hunks)
  • src/spork.cpp (1 hunks)
  • src/spork.h (2 hunks)
  • test/functional/feature_llmq_connections.py (0 hunks)
  • test/functional/feature_llmq_data_recovery.py (0 hunks)
  • test/functional/feature_llmq_is_retroactive.py (7 hunks)
  • test/functional/feature_llmq_signing.py (3 hunks)
  • test/functional/feature_llmq_simplepose.py (0 hunks)
  • test/functional/test_framework/test_framework.py (3 hunks)
  • test/functional/test_runner.py (0 hunks)
💤 Files with no reviewable changes (8)
  • src/llmq/options.cpp
  • src/llmq/options.h
  • src/net.h
  • test/functional/feature_llmq_data_recovery.py
  • test/functional/feature_llmq_connections.py
  • test/functional/test_runner.py
  • test/functional/feature_llmq_simplepose.py
  • src/net.cpp
🧰 Additional context used
📓 Path-based instructions (3)
src/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.{cpp,h,cc,cxx,hpp}: Dash Core C++ codebase must be written in C++20 and require at least Clang 16 or GCC 11.1
Dash uses unordered_lru_cache for efficient caching with LRU eviction

Files:

  • src/llmq/dkgsession.cpp
  • src/llmq/context.cpp
  • src/llmq/utils.h
  • src/llmq/quorums.cpp
  • src/llmq/quorums.h
  • src/llmq/dkgsessionhandler.cpp
  • src/masternode/active/context.cpp
  • src/spork.h
  • src/llmq/utils.cpp
  • src/spork.cpp
  • src/rpc/quorums.cpp
  • src/llmq/signing_shares.cpp
  • src/llmq/signing_shares.h
test/functional/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Functional tests should be written in Python and placed in test/functional/

Files:

  • test/functional/feature_llmq_signing.py
  • test/functional/feature_llmq_is_retroactive.py
  • test/functional/test_framework/test_framework.py
src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

Masternode lists must use immutable data structures (Immer library) for thread safety

Files:

  • src/masternode/active/context.cpp
🧠 Learnings (14)
📓 Common learnings
Learnt from: kwvg
Repo: dashpay/dash PR: 6543
File: src/wallet/receive.cpp:240-251
Timestamp: 2025-02-06T14:34:30.466Z
Learning: Pull request #6543 is focused on move-only changes and refactoring, specifically backporting from Bitcoin. Behavior changes should be proposed in separate PRs.
Learnt from: kwvg
Repo: dashpay/dash PR: 6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.
Learnt from: kwvg
Repo: dashpay/dash PR: 6761
File: src/chainlock/signing.cpp:247-250
Timestamp: 2025-07-29T14:32:48.369Z
Learning: In PR #6761, kwvg acknowledged a null pointer check issue in ChainLockSigner::Cleanup() method but deferred it to follow-up, consistent with the pattern of avoiding scope creep in refactoring PRs.
Learnt from: UdjinM6
Repo: dashpay/dash PR: 6933
File: src/llmq/utils.cpp:284-298
Timestamp: 2025-11-04T18:24:27.241Z
Learning: In consensus-critical code (such as quorum formation, block validation, or deployment activation logic), do not suggest changes to the logic itself even if the implementation appears theoretically incorrect or off-by-one. Consensus rules, once deployed on the Dash network, must be preserved exactly to avoid network forks. Refactoring PRs should maintain perfect behavioral equivalence. Only suggest logic changes if explicitly accompanied by a DIP (Dash Improvement Proposal) or if the maintainer indicates the consensus rule needs to be changed with appropriate activation logic.
Learnt from: kwvg
Repo: dashpay/dash PR: 6761
File: src/wallet/wallet.cpp:0-0
Timestamp: 2025-07-29T14:33:01.040Z
Learning: In refactoring PRs like #6761, kwvg acknowledges code safety improvements (like null pointer checks and unused parameter warnings) but prefers to defer them to follow-up PRs to maintain focus on the primary refactoring objectives, avoiding scope creep.
📚 Learning: 2025-06-06T11:53:09.094Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6665
File: src/evo/providertx.h:82-82
Timestamp: 2025-06-06T11:53:09.094Z
Learning: In ProTx serialization code (SERIALIZE_METHODS), version checks should use hardcoded maximum flags (/*is_basic_scheme_active=*/true, /*is_extended_addr=*/true) rather than deployment-based flags. This is because serialization code should be able to deserialize any structurally valid ProTx up to the maximum version the code knows how to handle, regardless of current consensus validity. Validation code, not serialization code, is responsible for checking whether a ProTx version is consensus-valid based on deployment status.

Applied to files:

  • src/llmq/dkgsession.cpp
📚 Learning: 2025-06-09T16:43:20.996Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.

Applied to files:

  • test/functional/feature_llmq_signing.py
  • src/llmq/utils.h
  • src/llmq/dkgsessionhandler.cpp
  • test/functional/test_framework/test_framework.py
  • src/llmq/utils.cpp
  • src/rpc/quorums.cpp
📚 Learning: 2024-12-29T17:43:41.755Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6504
File: src/llmq/quorums.cpp:224-224
Timestamp: 2024-12-29T17:43:41.755Z
Learning: The `CQuorumManager` is fully initialized by `LLMQContext`, addressing any concerns about the manager’s initialization sequence.

Applied to files:

  • src/llmq/context.cpp
  • src/llmq/quorums.cpp
  • src/llmq/quorums.h
📚 Learning: 2025-10-02T18:29:54.756Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6840
File: src/net_processing.cpp:2882-2886
Timestamp: 2025-10-02T18:29:54.756Z
Learning: Across net_processing.cpp, once LLMQContext (m_llmq_ctx) is asserted non-null, its subcomponents (e.g., isman, qdkgsman, quorum_block_processor) are treated as initialized and used without extra null checks.

Applied to files:

  • src/llmq/context.cpp
  • src/llmq/utils.h
  • src/llmq/quorums.cpp
  • src/llmq/quorums.h
  • src/llmq/dkgsessionhandler.cpp
  • src/llmq/utils.cpp
  • src/rpc/quorums.cpp
  • src/llmq/signing_shares.cpp
  • src/llmq/signing_shares.h
📚 Learning: 2025-01-02T21:50:00.967Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6504
File: src/llmq/context.cpp:42-43
Timestamp: 2025-01-02T21:50:00.967Z
Learning: LLMQContext manages concurrency for the `CInstantSendManager`. Previously, this was handled globally; now it's handled as a class member in `LLMQContext`, but the concurrency control remains consistent.

Applied to files:

  • src/llmq/context.cpp
📚 Learning: 2025-08-19T15:08:00.835Z
Learnt from: knst
Repo: dashpay/dash PR: 6692
File: src/llmq/commitment.cpp:54-60
Timestamp: 2025-08-19T15:08:00.835Z
Learning: In Dash Core, llmq_params.size == 1 is used only for regtest environments, not on public networks, which significantly reduces the risk profile of code paths specific to single-member quorums.

Applied to files:

  • src/llmq/utils.h
  • src/llmq/utils.cpp
  • src/llmq/signing_shares.cpp
📚 Learning: 2025-07-20T18:42:49.794Z
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp} : Masternode lists must use immutable data structures (Immer library) for thread safety

Applied to files:

  • src/llmq/quorums.h
  • src/llmq/signing_shares.cpp
  • src/llmq/signing_shares.h
📚 Learning: 2025-08-19T18:53:02.863Z
Learnt from: knst
Repo: dashpay/dash PR: 6824
File: test/functional/feature_llmq_is_retroactive.py:34-37
Timestamp: 2025-08-19T18:53:02.863Z
Learning: The `check_no_is` method in `test/functional/feature_llmq_is_retroactive.py` uses assertions for validation and doesn't return any value - it either succeeds silently or raises an AssertionError when the InstantLock assertion fails.

Applied to files:

  • test/functional/feature_llmq_is_retroactive.py
📚 Learning: 2025-10-28T08:54:00.392Z
Learnt from: UdjinM6
Repo: dashpay/dash PR: 6926
File: test/functional/feature_governance_cl.py:0-0
Timestamp: 2025-10-28T08:54:00.392Z
Learning: In Dash tests, the scheduler (mockscheduler) operates independently of network state. Isolated nodes should still run scheduler-based cleanup processes like governance cleanup, even if they have different state due to network isolation.

Applied to files:

  • test/functional/feature_llmq_is_retroactive.py
📚 Learning: 2025-10-02T18:29:54.756Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6840
File: src/net_processing.cpp:2882-2886
Timestamp: 2025-10-02T18:29:54.756Z
Learning: In src/net_processing.cpp, if ActiveContext (m_active_ctx) is non-null, its members (including cj_server) are guaranteed to be initialized; call sites can safely dereference m_active_ctx->cj_server without an additional null-check.

Applied to files:

  • src/masternode/active/context.cpp
📚 Learning: 2025-07-29T14:32:48.369Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6761
File: src/chainlock/signing.cpp:247-250
Timestamp: 2025-07-29T14:32:48.369Z
Learning: In PR #6761, kwvg acknowledged a null pointer check issue in ChainLockSigner::Cleanup() method but deferred it to follow-up, consistent with the pattern of avoiding scope creep in refactoring PRs.

Applied to files:

  • src/llmq/signing_shares.cpp
📚 Learning: 2025-07-15T14:53:04.819Z
Learnt from: knst
Repo: dashpay/dash PR: 6691
File: src/test/llmq_params_tests.cpp:148-151
Timestamp: 2025-07-15T14:53:04.819Z
Learning: In the Dash Core LLMQ implementation, signingActiveQuorumCount is never 0 in the actual parameters defined in params.h, making division by zero scenarios unrealistic in the max_cycles() function.

Applied to files:

  • src/llmq/signing_shares.cpp
  • src/llmq/signing_shares.h
📚 Learning: 2025-09-09T21:36:11.833Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6837
File: src/stats/rawsender.cpp:0-0
Timestamp: 2025-09-09T21:36:11.833Z
Learning: In RawSender class (src/stats/rawsender.cpp), cs_net is the appropriate mutex for protecting socket access (m_sock) and network operations, not additional custom locks. The implementation correctly uses cs_net with GUARDED_BY annotations and EXCLUSIVE_LOCKS_REQUIRED to synchronize socket access between SendDirectly() and ReconnectThread().

Applied to files:

  • src/llmq/signing_shares.h
🧬 Code graph analysis (7)
test/functional/feature_llmq_signing.py (6)
test/functional/test_framework/test_framework.py (7)
  • get_node (1219-1224)
  • MasternodeInfo (1145-1461)
  • get_mninfo (2355-2359)
  • wait_until (907-908)
  • connect_nodes (702-742)
  • connect_nodes (1488-1495)
  • bump_mocktime (880-897)
test/functional/test_framework/util.py (2)
  • assert_raises_rpc_error (132-148)
  • assert_equal (69-74)
test/functional/feature_llmq_singlenode.py (2)
  • assert_sigs_nochange (80-81)
  • wait_for_sigs (77-78)
test/functional/test_framework/test_node.py (2)
  • add_p2p_connection (651-708)
  • disconnect_p2ps (778-795)
test/functional/test_framework/p2p.py (2)
  • P2PInterface (492-770)
  • send_message (432-440)
test/functional/test_framework/messages.py (2)
  • msg_qsigshare (2417-2433)
  • uint256_to_string (140-141)
src/llmq/quorums.cpp (1)
src/llmq/utils.cpp (2)
  • EnsureQuorumConnections (833-891)
  • EnsureQuorumConnections (833-837)
test/functional/feature_llmq_is_retroactive.py (1)
test/functional/test_framework/test_framework.py (3)
  • bump_mocktime (880-897)
  • reconnect_isolated_node (784-786)
  • wait_for_mnauth (2393-2401)
src/llmq/dkgsessionhandler.cpp (1)
src/llmq/utils.cpp (2)
  • EnsureQuorumConnections (833-891)
  • EnsureQuorumConnections (833-837)
src/rpc/quorums.cpp (1)
src/llmq/utils.cpp (2)
  • GetQuorumConnections (732-753)
  • GetQuorumConnections (732-735)
src/llmq/signing_shares.cpp (1)
src/spork.h (1)
  • cs (225-340)
src/llmq/signing_shares.h (1)
src/llmq/params.h (1)
  • LLMQType (14-125)
🪛 Flake8 (7.3.0)
test/functional/test_framework/test_framework.py

[error] 1934-1934: do not use bare 'except'

(E722)


[error] 1946-1946: do not use bare 'except'

(E722)

🪛 GitHub Actions: Clang Diff Format Check
src/llmq/context.cpp

[error] 1-1: Clang format differences found in src/llmq/context.cpp. Run the clang-format-diff.py step again or apply formatting changes to fix the diffs.

src/llmq/utils.h

[error] 1-1: Clang format differences found in src/llmq/utils.h. Run the clang-format-diff.py step again or apply formatting changes to fix the diffs.

src/llmq/quorums.cpp

[error] 1-1: Clang format differences found in src/llmq/quorums.cpp. Run the clang-format-diff.py step again or apply formatting changes to fix the diffs.

src/llmq/quorums.h

[error] 1-1: Clang format differences found in src/llmq/quorums.h. Run the clang-format-diff.py step again or apply formatting changes to fix the diffs.

src/spork.h

[error] 1-1: Clang format differences found in src/spork.h. Run the clang-format-diff.py step again or apply formatting changes to fix the diffs.

src/llmq/utils.cpp

[error] 1-1: Clang format differences found in src/llmq/utils.cpp. Run the clang-format-diff.py step again or apply formatting changes to fix the diffs.

src/rpc/quorums.cpp

[error] 1-1: Clang format differences found in src/rpc/quorums.cpp. Run the clang-format-diff.py step again or apply formatting changes to fix the diffs.

src/llmq/signing_shares.h

[error] 1-1: Clang format differences found in src/llmq/signing_shares.h. Run the clang-format-diff.py step again or apply formatting changes to fix the diffs.

🪛 Ruff (0.14.4)
test/functional/test_framework/test_framework.py

1934-1934: Do not use bare except

(E722)


1946-1946: Do not use bare except

(E722)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build container / Build container
🔇 Additional comments (11)
test/functional/feature_llmq_is_retroactive.py (2)

32-34: Deterministic wait is good

Looping sleep + bump_mocktime improves stability and speed. No issues.


163-163: Session-timeout timing bumps

These targeted bumps align with Cleanup()/timeout windows; looks correct.

Also applies to: 173-173, 178-178, 181-181

src/llmq/context.cpp (1)

31-33: qman ctor updated

LLMQContext now constructs CQuorumManager without sporkman; consistent with header change. Re-run clang-format to fix CI.

test/functional/test_framework/test_framework.py (2)

2109-2111: expected_connections default

Using llmq_size - 1 unconditionally (no spork21 branch) is consistent with the PR.


2201-2202: expected_connections for DIP0024

Same here: llmq_size_dip0024 - 1 looks right.

src/rpc/quorums.cpp (1)

366-371: GetQuorumConnections signature update verified—all call sites consistent

The function signature has been successfully updated to remove the sporkman parameter. All three call sites (two in src/rpc/quorums.cpp and one in src/llmq/utils.cpp) are consistent with the new signature and properly pass six parameters in the correct order. The code changes shown in the review snippet are correct.

src/llmq/dkgsessionhandler.cpp (1)

566-567: Verification confirmed: Spork removal complete and correctly implemented

The code changes are correct:

  • EnsureQuorumConnections (lines 566-567) correctly does not take sporkman
  • AddQuorumProbeConnections (line 569) correctly still takes m_sporkman to gate PoSe logic via SPORK_23_QUORUM_POSE (confirmed in src/llmq/options.cpp:34-37)
  • No active spork21 checks remain; only historical comments exist in src/llmq/signing_shares.cpp
src/llmq/quorums.h (1)

270-270: <!-- [scratchpad_start]
[task verify_constructor_change completed]
[observations]

  • Header signature (src/llmq/quorums.h:266-270): correct, no sporkman
  • Implementation signature (src/llmq/quorums.cpp:210-214): correct, no sporkman
  • Call site (src/llmq/context.cpp:30-32): passes 10 args, matches new signature
  • Git history confirms sporkman removal: member variable deleted, parameter removed from signature
  • Formatting appears consistent across header and implementation

[analysis]

  • All three locations (header, implementation, call site) are synchronized
  • Constructor decoupling is complete: sporkman successfully removed
  • No inconsistencies or mismatches found
  • Code formatting aligns with Dash C++ style

[done]
Verification complete. Constructor signature change properly applied across codebase. No issues detected.
[scratchpad_end]

Constructor signature change verified: sporkman parameter successfully removed

Verification confirms all definitions and call sites have been correctly updated:

  • Header declaration (src/llmq/quorums.h:266-270): removed sporkman parameter
  • Implementation (src/llmq/quorums.cpp:210-214): matches header signature
  • Call site (src/llmq/context.cpp:30-32): passes 10 arguments matching the new signature

The sporkman decoupling is complete and consistent across the codebase.

src/llmq/dkgsession.cpp (1)

486-487: Change verified: badConnection unconditionally marks missing peers

The modification correctly removes the spork21 gate from badConnection marking when peers are missing from protoMap (lines 486-487). Recent commit "drop leftover usages of IsAllMembersConnectedEnabled and unused references to spork manager" confirms this is intentional cleanup following spork21 removal.

Test coverage is adequate. Tests exercise partial connectivity scenarios with offline nodes (feature_llmq_simplepose.py) and verify expected complaint counts during phase 3. The mine_quorum helper checks spork23_active and validates expected_complaints, ensuring PoSe behavior remains properly gated by SPORK_23. While badConnection internals aren't directly tested, the behavioral chain—missing peers → badConnection → complaints → PoSe banning—is verified through expected_complaints assertions.

src/spork.cpp (1)

265-265: Ignore this review comment; the hardening is intentional and integral to the PR's scope.

The git history and code comments confirm that hardening ALL sporks on mainnet is not scope creep—it is the refactoring's core goal. The commit series explicitly removes code paths that only execute when spork21 is disabled (e.g., "remove functions related to disabled spork21"). The comment at src/llmq/signing_shares.cpp:114 states: "this message is not expected to be received once spork21 is hardened as active," confirming that activating all sporks is the intended design.

Returning 0 from GetSporkValue() for all sporks ensures the codebase only executes logic that assumes sporks are active, eliminating dead code and runtime overhead. Limiting the change to SPORK_21_DEPRECATED alone would defeat the refactoring's purpose and leave disabled-spork code paths in place.

Likely an incorrect or invalid review comment.

src/llmq/utils.cpp (1)

732-752: Fix outbound quorum connection selection

DeterministicOutboundConnection() returns the proTxHash that is supposed to initiate the link. By comparing the result to dmn->proTxHash we now keep the peers that should wait for inbound traffic and skip the ones we are actually responsible for dialing. As soon as every quorum member runs this build, each pair of nodes waits for the other side to connect, which breaks the full-mesh topology—especially for NATed operators that cannot accept unsolicited inbound sessions. Please restore the comparison against our own proTxHash.

Apply this diff:

-        if (!onlyOutbound || deterministicOutbound == dmn->proTxHash) {
+        if (!onlyOutbound || deterministicOutbound == forMember) {
⛔ Skipped due to learnings
Learnt from: UdjinM6
Repo: dashpay/dash PR: 6933
File: src/llmq/utils.cpp:284-298
Timestamp: 2025-11-04T18:24:27.241Z
Learning: In consensus-critical code (such as quorum formation, block validation, or deployment activation logic), do not suggest changes to the logic itself even if the implementation appears theoretically incorrect or off-by-one. Consensus rules, once deployed on the Dash network, must be preserved exactly to avoid network forks. Refactoring PRs should maintain perfect behavioral equivalence. Only suggest logic changes if explicitly accompanied by a DIP (Dash Improvement Proposal) or if the maintainer indicates the consensus rule needs to be changed with appropriate activation logic.

knst added 12 commits November 13, 2025 20:14
Downside of having spork21:
 - llmq code run in 2 different modes depending it is active or not active. It complicates implementation while we not actually need a case of "inactive"
 - it increase scope of test coverage; functional test to test it takes 2 minutes to run and it increase cost of CI, making CI slower, making local run of functional tests noticeable slower

See previuos commit: functional test feature_llmq_is_retroactive.py actually had been broken for awhile,
but disabled spork21 masked it
…hods from llmq/signing_shares

Careful reviewing implementation is showing that there's no relevant code.

Logic which prepares & creates data to be sent by QGETSIGSHARES is `CollectSigSharesToRequest` in
the loop over nodeState.sessions and it does nothing if spork21 is enabled
…ds from llmq/signing_shares

Careful reviewing implementation is showing that there's no relevant code after removing spork21

Logic which prepares & creates data to be sent by QBSIGSHARES is `CollectSigSharesToSend` in
the loop over nodeState.sessions and it does nothing if spork21 is enabled
{
return EvalSpork(llmqType, sporkman.GetSporkValue(SPORK_21_QUORUM_ALL_CONNECTED));
}
bool IsAllMembersConnectedEnabled(const Consensus::LLMQType llmqType, const CSporkManager& sporkman) { return true; }
Copy link

Choose a reason for hiding this comment

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

c96395b: You can't do that. Mainnet is running with SPORK_21_QUORUM_ALL_CONNECTED: 1 meaning that it's true for small quorums only. For large quorums it's false for a reason - connecting each node of a large quorum is too resource hungry. Also, simply dropping the old quorum connection logic means that nodes that update to this version will try to use "wrong" quorum connection logic (from the point of view of non-updated nodes) and new nodes could be pose-banned or quorum creation could fail, or both.

Copy link

Choose a reason for hiding this comment

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

All you can do here is replace sporkman.GetSporkValue(SPORK_21_QUORUM_ALL_CONNECTED) with 1 and drop const CSporkManager& sporkman from params. And that's pretty much it imo.

Copy link
Collaborator Author

@knst knst Nov 13, 2025

Choose a reason for hiding this comment

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

ah, that's terrible! 😡 I just though I found a short-cut to make 6984 much simpler for signing-shares.
Anyway, nothing to do then.

I miss the fact that EvalSpork actually do something magic

    if (spork_value == 1 && llmqType != Consensus::LLMQType::LLMQ_100_67 && llmqType != Consensus::LLMQType::LLMQ_400_60 && llmqType != Consensus::LLMQType::LLMQ_400_85) {

@knst knst closed this Nov 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants