Skip to content

Conversation

@kwvg
Copy link
Collaborator

@kwvg kwvg commented Dec 15, 2025

Additional Information

Breaking Changes

Work in progress.

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)

@github-actions
Copy link

github-actions bot commented Dec 15, 2025

✅ No Merge Conflicts Detected

This PR currently has no conflicts with other open PRs.

@kwvg kwvg force-pushed the active_p5 branch 2 times, most recently from 3ebc918 to 869f847 Compare December 15, 2025 13:06
@github-actions
Copy link

This pull request has conflicts, please rebase.

PastaPastaPasta added a commit that referenced this pull request Dec 23, 2025
8e44990 chore!: enforce ban for re-propagation of stale `QFCOMMIT`s (Kittywhiskers Van Gogh)

Pull request description:

  ## Additional Information

  Spun off from [dash#7066](#7066) due to breaking change, enforces policy introduced in [dash#5145](#5145).

  ## Breaking changes

  Broadcasting stale `QFCOMMIT`s will result in the offending node getting banned.

  ## Checklist

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

ACKs for top commit:
  PastaPastaPasta:
    utACK 8e44990; since this is protocol version guarded; not a breaking change.
  UdjinM6:
    utACK 8e44990

Tree-SHA512: 659e43fba896ac3046dfc7aa197ab0a2207e1648488fdcd545902a90d4efa4f25d74f4a92b99eb2e68cf96b30a78a99114d9487c1abf0b8954dc7a585131d88b
PastaPastaPasta added a commit that referenced this pull request Jan 8, 2026
…ontext` (3/n, DKG session isolation, `ActiveContext` consolidation)

de4d0ea chore: update lint circular dependencies allowlist (Kittywhiskers Van Gogh)
a93f8ae refactor: keep base DKG handler lightweight, follow IWYU (Kittywhiskers Van Gogh)
70e6372 refactor: `InitNewQuorum()` is the only place where real `curSession`s are created (Kittywhiskers Van Gogh)
d115e0e refactor: consolidate masternode mode logic to `src/active/` (Kittywhiskers Van Gogh)
19b2ee5 refactor: merge `ActiveNotificationInterface` into `ActiveContext` (Kittywhiskers Van Gogh)
f0468e6 refactor: merge `CActiveMasternodeInfo` into `CActiveMasternodeManager` (Kittywhiskers Van Gogh)
e9f8294 refactor: move `CActiveMasternodeManager` to `ActiveContext` (Kittywhiskers Van Gogh)
004b3b7 refactor: drop `CActiveMasternodeManager` from chainstate init (Kittywhiskers Van Gogh)
01c0b94 refactor: separate active session routines into dedicated class (Kittywhiskers Van Gogh)
bb90306 move-only: move DKG session participant logic to `llmq/active` (Kittywhiskers Van Gogh)
b59baac refactor: separate active session handler routines into dedicated class (Kittywhiskers Van Gogh)
1bdf836 move-only: move DKG session handler participant logic to `llmq/active` (Kittywhiskers Van Gogh)
831dbfe refactor: move DKG session handler init out of ctor (Kittywhiskers Van Gogh)
394c66b refactor: use `unique_ptr` in DKG session handler map (Kittywhiskers Van Gogh)

Pull request description:

  ## Additional Information

  * Depends on #7063

  * Dependency for #7066

  * As `ActiveNotificationInterface` exclusively interacts with `ActiveContext` members, we can squash them together like `ObserverContext`.

  ## Breaking Changes

  None expected.

  ## Checklist:

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

ACKs for top commit:
  PastaPastaPasta:
    utACK de4d0ea
  UdjinM6:
    utACK de4d0ea

Tree-SHA512: 79d92003b672cd9309fe241610544ebd32caecd2984a60e31673e11a922d1e4e3cc4a189b2345ce71e9a9793d4364a07ac5f5b49d40bcf0aa0d3b379b8a6d8a5
@github-actions
Copy link

github-actions bot commented Jan 8, 2026

This pull request has conflicts, please rebase.

@kwvg
Copy link
Collaborator Author

kwvg commented Jan 9, 2026

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Jan 9, 2026

✅ Actions performed

Review triggered.

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
Copy link

coderabbitai bot commented Jan 9, 2026

Walkthrough

This PR refactors LLMQ (Long-Living Masternode Quorum) infrastructure across multiple components. Key changes include: replacing std::set containers with Uint256HashSet and std::unordered_set for performance optimization; restructuring CDKGDebugManager to use dependency injection (dmnman, qsnapman, chainman) instead of default construction; introducing a ReceiveMessagePreamble template method to centralize message handling logic for Contribution, Complaint, and Justification message types; consolidating CQuorumManager mutexes (cs_map_quorums and cs_scan_quorums into m_cs_maps); converting CDKGDebugStatus from a class to a struct with simplified interfaces; adding thread-safe lazy initialization for qwatch connection seed; and updating RPC parameter parsing from ParseInt64V/ParseInt32V to direct UniValue.getInt<>() calls. The changes span protocol handling, quorum management, RPC interfaces, and data structure containers.

Sequence Diagram(s)

sequenceDiagram
    participant Client as CDKGSession
    participant Preamble as ReceiveMessagePreamble<br/>(Template)
    participant Container as Message Container<br/>(Phase Map)
    participant Debug as CDKGLogger
    participant Processor as Per-Type Handler<br/>(VerifyAndJustify, etc.)

    Client->>Preamble: ReceiveMessagePreamble<CDKGContribution>(msg, phase)
    Preamble->>Container: Select container by phase
    Preamble->>Container: Insert message into phase map
    Preamble->>Debug: Update debug status
    Preamble->>Preamble: Check membership & accumulate hashes
    Preamble-->>Client: Return ReceiveMessageState (member, hash, inv, should_process)
    
    alt should_process == true
        Client->>Processor: Call VerifyAndJustify or equivalent
        Processor-->>Client: Process result
    else should_process == false
        Note over Client: Skip full processing
    end
    
    Note over Preamble: Relay logic executes before<br/>full verification regardless
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main refactoring work: extracting CActiveMasternodeManager from LLMQContext as part 4 of a series, which is directly reflected in the changeset.
Description check ✅ Passed The description is related to the changeset as it mentions the dependency on PR 7065, marks the PR as work in progress, and references breaking changes consistent with the comprehensive refactoring across multiple files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/llmq/signing.cpp (1)

182-189: Harden writeTime deserialization to avoid crashes on corrupted/unexpected DB data (keep happy-path behavior unchanged).

db->ReadDataStream(k2, writeTimeDs) succeeding doesn’t guarantee the stream contains at least 4 bytes (or is in the expected format). writeTimeDs >> writeTime; without a size/exception guard can crash cleanup/removal on DB corruption.

Proposed fix (minimal, behavior-preserving for valid entries)
     if (deleteTimeKey) {
         CDataStream writeTimeDs(SER_DISK, CLIENT_VERSION);
         if (db->ReadDataStream(k2, writeTimeDs)) {
-            uint32_t writeTime;
-            writeTimeDs >> writeTime;
-            auto k5 = std::make_tuple(std::string("rs_t"), (uint32_t) htobe32_internal(writeTime), recSig.getLlmqType(), recSig.getId());
-            batch.Erase(k5);
+            // Defensive: DB value may be corrupted or from an unexpected legacy format
+            if (writeTimeDs.size() >= sizeof(uint32_t)) {
+                try {
+                    uint32_t writeTime;
+                    writeTimeDs >> writeTime;
+                    auto k5 = std::make_tuple(std::string("rs_t"), (uint32_t)htobe32_internal(writeTime), recSig.getLlmqType(), recSig.getId());
+                    batch.Erase(k5);
+                } catch (const std::exception&) {
+                    // ignore; leave rs_t cleanup to CleanupOldRecoveredSigs()
+                }
+            }
         }
     }
src/llmq/dkgsession.cpp (1)

1-1: Fix clang-format issues before merging.

The CI pipeline reports clang-format differences. Run clang-format-diff.py to fix formatting in this file.

🤖 Fix all issues with AI agents
In @src/llmq/utils.h:
- Around line 65-67: The header declares std::unordered_set in the public API
(CalcDeterministicWatchConnections) but does not include <unordered_set>; add an
explicit #include <unordered_set> to the top of the header (next to the other
standard includes) so the declaration does not rely on transitive includes and
consumers can compile independently.
🧹 Nitpick comments (4)
src/llmq/ehf_signals.h (1)

8-13: Include addition is fine; consider dropping <set> if it’s now unused in this header.

src/llmq/utils.cpp (1)

761-768: Thread-safe lazy initialization for qwatch connection seed is functionally correct but could be improved.

The current pattern checks the atomic flag outside the lock but doesn't re-check inside. Multiple threads could sequentially generate seeds. While this is acceptable for random seed generation (any random value is valid), a cleaner double-checked locking pattern would be:

if (!qwatchConnectionSeedGenerated) {
    LOCK(qwatchConnectionSeedCs);
    if (!qwatchConnectionSeedGenerated) {  // Re-check after acquiring lock
        qwatchConnectionSeed = GetRandHash();
        qwatchConnectionSeedGenerated = true;
    }
}

This is a minor improvement and the current code is functionally correct for its purpose. Based on learnings, this refinement could be deferred to a follow-up.

src/llmq/dkgsession.cpp (2)

620-636: Consider adding a defensive default case inside the switch.

The switch statement covers all current MsgPhase values, and the assert(false) after the lambda provides a runtime check. However, for improved maintainability and compiler diagnostics, consider either:

  1. Adding default: assert(false); inside the switch, or
  2. Using std::unreachable() (C++23) or compiler-specific __builtin_unreachable() to help the compiler with control flow analysis

This would allow compilers to warn if a new enum value is added but not handled.

♻️ Optional improvement
     auto& member_set = [&]() -> Uint256HashSet& {
         switch (phase) {
         case MsgPhase::Contribution:
             inv_type = MSG_QUORUM_CONTRIB;
             msg_name = "contribution";
             return member->contributions;
         case MsgPhase::Complaint:
             inv_type = MSG_QUORUM_COMPLAINT;
             msg_name = "complaint";
             return member->complaints;
         case MsgPhase::Justification:
             inv_type = MSG_QUORUM_JUSTIFICATION;
             msg_name = "justification";
             return member->justifications;
+        default:
+            assert(false);
         }
-        assert(false);
     }();

640-671: Logic flow is correct but comment could be clearer.

The two size checks serve different purposes:

  1. Line 640: size >= 2 - Rejects the 3rd+ message entirely (before emplacing)
  2. Line 665: size > 1 - After emplacing, if size is now >1, marks member as bad but still relays

This correctly allows up to 2 messages to be relayed while marking the sender as bad after the 2nd. The comment on line 641 mentions "justifications" but this template handles all three message types. Consider updating the comment to be generic.

📝 Minor comment fix
     if (member_set.size() >= 2) {
-        // only relay up to 2 justifications, that's enough to let the other members know about his bad behavior
+        // only relay up to 2 messages per member, that's enough to let the other members know about their bad behavior
         return std::nullopt;
     }
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7482956 and 2262e22.

📒 Files selected for processing (32)
  • src/active/context.cpp
  • src/active/dkgsession.cpp
  • src/active/dkgsession.h
  • src/active/dkgsessionhandler.cpp
  • src/llmq/core_write.cpp
  • src/llmq/debug.cpp
  • src/llmq/debug.h
  • src/llmq/dkgsession.cpp
  • src/llmq/dkgsession.h
  • src/llmq/dkgsessionhandler.h
  • src/llmq/ehf_signals.h
  • src/llmq/observer/context.cpp
  • src/llmq/observer/quorums.cpp
  • src/llmq/observer/quorums.h
  • src/llmq/quorums.cpp
  • src/llmq/quorums.h
  • src/llmq/quorumsman.cpp
  • src/llmq/quorumsman.h
  • src/llmq/signing.cpp
  • src/llmq/utils.cpp
  • src/llmq/utils.h
  • src/net.cpp
  • src/net.h
  • src/rpc/client.cpp
  • src/rpc/evo.cpp
  • src/rpc/governance.cpp
  • src/rpc/masternode.cpp
  • src/rpc/quorums.cpp
  • src/rpc/util.cpp
  • src/rpc/util.h
  • src/test/rpc_tests.cpp
  • test/functional/feature_llmq_dkgerrors.py
💤 Files with no reviewable changes (2)
  • src/rpc/util.cpp
  • src/rpc/util.h
🧰 Additional context used
📓 Path-based instructions (7)
src/**/*.{cpp,h,hpp,cc}

📄 CodeRabbit inference engine (CLAUDE.md)

Dash Core implementation must be written in C++20, requiring at least Clang 16 or GCC 11.1

Files:

  • src/llmq/dkgsessionhandler.h
  • src/rpc/masternode.cpp
  • src/net.cpp
  • src/rpc/evo.cpp
  • src/active/dkgsession.h
  • src/llmq/quorums.cpp
  • src/llmq/observer/quorums.cpp
  • src/net.h
  • src/llmq/quorumsman.cpp
  • src/rpc/client.cpp
  • src/llmq/observer/quorums.h
  • src/llmq/signing.cpp
  • src/llmq/quorumsman.h
  • src/llmq/dkgsession.h
  • src/rpc/governance.cpp
  • src/llmq/dkgsession.cpp
  • src/llmq/quorums.h
  • src/active/dkgsession.cpp
  • src/llmq/observer/context.cpp
  • src/llmq/utils.cpp
  • src/llmq/utils.h
  • src/active/context.cpp
  • src/test/rpc_tests.cpp
  • src/llmq/ehf_signals.h
  • src/rpc/quorums.cpp
  • src/llmq/debug.h
  • src/llmq/debug.cpp
  • src/active/dkgsessionhandler.cpp
  • src/llmq/core_write.cpp
src/{masternode,evo,llmq,governance,coinjoin}/**/*.{cpp,h}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Dash-specific database implementations: CFlatDB for persistent storage (MasternodeMetaStore, GovernanceStore, SporkStore, NetFulfilledRequestStore) and CDBWrapper extensions for Evolution/DKG/InstantSend/Quorum/RecoveredSigs data

Files:

  • src/llmq/dkgsessionhandler.h
  • src/llmq/quorums.cpp
  • src/llmq/observer/quorums.cpp
  • src/llmq/quorumsman.cpp
  • src/llmq/observer/quorums.h
  • src/llmq/signing.cpp
  • src/llmq/quorumsman.h
  • src/llmq/dkgsession.h
  • src/llmq/dkgsession.cpp
  • src/llmq/quorums.h
  • src/llmq/observer/context.cpp
  • src/llmq/utils.cpp
  • src/llmq/utils.h
  • src/llmq/ehf_signals.h
  • src/llmq/debug.h
  • src/llmq/debug.cpp
  • src/llmq/core_write.cpp
src/{masternode,llmq}/**/*.{cpp,h}

📄 CodeRabbit inference engine (CLAUDE.md)

BLS integration must be used for cryptographic foundation of advanced masternode features

Files:

  • src/llmq/dkgsessionhandler.h
  • src/llmq/quorums.cpp
  • src/llmq/observer/quorums.cpp
  • src/llmq/quorumsman.cpp
  • src/llmq/observer/quorums.h
  • src/llmq/signing.cpp
  • src/llmq/quorumsman.h
  • src/llmq/dkgsession.h
  • src/llmq/dkgsession.cpp
  • src/llmq/quorums.h
  • src/llmq/observer/context.cpp
  • src/llmq/utils.cpp
  • src/llmq/utils.h
  • src/llmq/ehf_signals.h
  • src/llmq/debug.h
  • src/llmq/debug.cpp
  • src/llmq/core_write.cpp
src/llmq/**/*.{cpp,h}

📄 CodeRabbit inference engine (CLAUDE.md)

src/llmq/**/*.{cpp,h}: LLMQ quorums must support multiple configurations (50/60, 400/60, 400/85) for different services (ChainLocks, InstantSend, governance voting)
InstantSend implementation must provide distributed key generation for secure transaction locking with quorum consensus
ChainLocks implementation must prevent reorganizations and provide block finality through 51% attack prevention

Files:

  • src/llmq/dkgsessionhandler.h
  • src/llmq/quorums.cpp
  • src/llmq/observer/quorums.cpp
  • src/llmq/quorumsman.cpp
  • src/llmq/observer/quorums.h
  • src/llmq/signing.cpp
  • src/llmq/quorumsman.h
  • src/llmq/dkgsession.h
  • src/llmq/dkgsession.cpp
  • src/llmq/quorums.h
  • src/llmq/observer/context.cpp
  • src/llmq/utils.cpp
  • src/llmq/utils.h
  • src/llmq/ehf_signals.h
  • src/llmq/debug.h
  • src/llmq/debug.cpp
  • src/llmq/core_write.cpp
src/{masternode,llmq,evo,coinjoin,governance}/**/*.{cpp,h}

📄 CodeRabbit inference engine (CLAUDE.md)

Use unordered_lru_cache for efficient caching with LRU eviction in Dash-specific data structures

Files:

  • src/llmq/dkgsessionhandler.h
  • src/llmq/quorums.cpp
  • src/llmq/observer/quorums.cpp
  • src/llmq/quorumsman.cpp
  • src/llmq/observer/quorums.h
  • src/llmq/signing.cpp
  • src/llmq/quorumsman.h
  • src/llmq/dkgsession.h
  • src/llmq/dkgsession.cpp
  • src/llmq/quorums.h
  • src/llmq/observer/context.cpp
  • src/llmq/utils.cpp
  • src/llmq/utils.h
  • src/llmq/ehf_signals.h
  • src/llmq/debug.h
  • src/llmq/debug.cpp
  • src/llmq/core_write.cpp
test/functional/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Functional tests in test/functional/ must be written in Python (minimum version specified in .python-version) and depend on dashd and dash-node

Files:

  • test/functional/feature_llmq_dkgerrors.py
src/{test,wallet/test}/**/*.{cpp,h}

📄 CodeRabbit inference engine (CLAUDE.md)

Unit tests in src/test/ and src/wallet/test/ must use Boost::Test framework

Files:

  • src/test/rpc_tests.cpp
🧠 Learnings (31)
📓 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: 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: 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/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.
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/chainlock/signing.cpp:15-250
Timestamp: 2025-07-23T09:28:32.783Z
Learning: In refactoring PRs like #6761, kwvg prefers to defer code formatting fixes to separate follow-up PRs when formatting is not the primary objective, to maintain focus on the structural changes and avoid scope creep.
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/llmq/**/*.{cpp,h} : LLMQ quorums must support multiple configurations (50/60, 400/60, 400/85) for different services (ChainLocks, InstantSend, governance voting)
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/llmq/**/*.{cpp,h} : InstantSend implementation must provide distributed key generation for secure transaction locking with quorum consensus
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.
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/llmq/**/*.{cpp,h} : ChainLocks implementation must prevent reorganizations and provide block finality through 51% attack prevention
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/evo/evodb/**/*.{cpp,h} : Evolution Database (CEvoDb) must handle masternode snapshots, quorum state, governance objects with efficient differential updates for masternode lists
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.
📚 Learning: 2025-12-22T15:42:48.595Z
Learnt from: kwvg
Repo: dashpay/dash PR: 7068
File: src/qt/guiutil_font.h:68-77
Timestamp: 2025-12-22T15:42:48.595Z
Learning: In C++/Qt codebases, use fail-fast asserts in setters to enforce invariants (e.g., ensuring internal maps contain necessary keys). Prefer assert() for programmer errors that should be caught in development and debugging, rather than defensive runtime checks with fallbacks. This helps catch invariant violations early during development. Apply to header and source files where invariant-driven state mutations occur, especially in setters like SetWeightBold/SetWeightNormal that assume established relationships or preconditions.

Applied to files:

  • src/llmq/dkgsessionhandler.h
  • src/active/dkgsession.h
  • src/net.h
  • src/llmq/observer/quorums.h
  • src/llmq/quorumsman.h
  • src/llmq/dkgsession.h
  • src/llmq/quorums.h
  • src/llmq/utils.h
  • src/llmq/ehf_signals.h
  • src/llmq/debug.h
📚 Learning: 2025-10-03T11:29:36.358Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6838
File: src/governance/signing.cpp:84-85
Timestamp: 2025-10-03T11:29:36.358Z
Learning: After bitcoin#25153 (included in dash#6775), UniValue uses the templated getInt<T>() API instead of the legacy get_int() and get_int64() methods. For example, use jproposal["start_epoch"].getInt<int64_t>() to retrieve int64_t values from UniValue objects.

Applied to files:

  • src/rpc/masternode.cpp
  • src/rpc/evo.cpp
  • src/rpc/governance.cpp
📚 Learning: 2025-08-08T07:01:47.332Z
Learnt from: knst
Repo: dashpay/dash PR: 6805
File: src/wallet/rpc/wallet.cpp:357-357
Timestamp: 2025-08-08T07:01:47.332Z
Learning: In src/wallet/rpc/wallet.cpp, the upgradetohd RPC now returns a UniValue string message (RPCResult::Type::STR) instead of a boolean, including guidance about mnemonic backup and null-character passphrase handling; functional tests have been updated to assert returned strings in several cases.

Applied to files:

  • src/rpc/evo.cpp
  • src/rpc/client.cpp
  • src/test/rpc_tests.cpp
  • src/rpc/quorums.cpp
📚 Learning: 2025-11-24T16:41:22.457Z
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/evo/evodb/**/*.{cpp,h} : Evolution Database (CEvoDb) must handle masternode snapshots, quorum state, governance objects with efficient differential updates for masternode lists

Applied to files:

  • src/rpc/evo.cpp
  • src/llmq/observer/quorums.cpp
  • src/llmq/quorumsman.cpp
  • src/llmq/dkgsession.h
📚 Learning: 2025-12-02T12:59:28.247Z
Learnt from: UdjinM6
Repo: dashpay/dash PR: 7026
File: src/rpc/evo.cpp:1713-1799
Timestamp: 2025-12-02T12:59:28.247Z
Learning: In the Dash codebase, CChain::operator[] has built-in safe bounds checking. Accessing chainman.ActiveChain()[height] is safe even if height exceeds the current chain height, as the operator will handle bounds checking internally. There is no need to manually check chain height before using the [] operator on CChain.

Applied to files:

  • src/rpc/evo.cpp
  • src/rpc/quorums.cpp
📚 Learning: 2025-11-24T16:41:22.457Z
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/llmq/**/*.{cpp,h} : LLMQ quorums must support multiple configurations (50/60, 400/60, 400/85) for different services (ChainLocks, InstantSend, governance voting)

Applied to files:

  • src/llmq/quorums.cpp
  • src/llmq/observer/quorums.cpp
  • src/net.h
  • src/llmq/quorumsman.cpp
  • src/llmq/observer/quorums.h
  • src/llmq/quorumsman.h
  • src/llmq/dkgsession.h
  • src/llmq/dkgsession.cpp
  • src/llmq/quorums.h
  • src/llmq/utils.cpp
  • src/llmq/utils.h
  • src/rpc/quorums.cpp
  • src/llmq/debug.h
📚 Learning: 2025-11-24T16:41:22.457Z
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/llmq/**/*.{cpp,h} : InstantSend implementation must provide distributed key generation for secure transaction locking with quorum consensus

Applied to files:

  • src/llmq/quorums.cpp
  • src/llmq/observer/quorums.cpp
  • src/net.h
  • src/llmq/quorumsman.cpp
  • src/llmq/quorumsman.h
  • src/llmq/dkgsession.h
  • src/llmq/dkgsession.cpp
  • src/llmq/utils.cpp
  • src/llmq/utils.h
  • src/llmq/ehf_signals.h
  • src/rpc/quorums.cpp
  • src/llmq/debug.h
📚 Learning: 2025-11-24T16:41:22.457Z
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/{masternode,llmq}/**/*.{cpp,h} : BLS integration must be used for cryptographic foundation of advanced masternode features

Applied to files:

  • src/net.h
  • src/llmq/quorumsman.h
  • src/llmq/dkgsession.h
  • src/llmq/ehf_signals.h
📚 Learning: 2025-11-24T16:41:22.457Z
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/{validation,txmempool}/**/*.{cpp,h} : Block validation and mempool handling must use extensions to Bitcoin Core mechanisms for special transaction validation and enhanced transaction relay

Applied to files:

  • src/net.h
📚 Learning: 2025-11-24T16:41:22.457Z
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/{validation,consensus,net_processing}/**/*.{cpp,h} : ValidationInterface callbacks must be used for event-driven architecture to coordinate subsystems during block/transaction processing

Applied to files:

  • src/net.h
📚 Learning: 2025-11-24T16:41:22.457Z
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/coinjoin/**/*.{cpp,h} : CoinJoin implementation must use masternode-coordinated mixing sessions with uniform denomination outputs

Applied to files:

  • src/net.h
  • src/llmq/dkgsession.h
  • src/active/dkgsession.cpp
📚 Learning: 2025-11-24T16:41:22.457Z
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/llmq/**/*.{cpp,h} : ChainLocks implementation must prevent reorganizations and provide block finality through 51% attack prevention

Applied to files:

  • src/net.h
  • src/llmq/quorumsman.cpp
  • src/llmq/quorumsman.h
  • src/llmq/dkgsession.h
  • src/llmq/dkgsession.cpp
  • src/llmq/utils.cpp
  • src/llmq/utils.h
  • src/llmq/debug.h
📚 Learning: 2025-10-21T11:09:34.688Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6849
File: src/governance/governance.cpp:1339-1343
Timestamp: 2025-10-21T11:09:34.688Z
Learning: In the Dash Core codebase, `CacheMap` (defined in src/cachemap.h) is internally thread-safe and uses its own `mutable CCriticalSection cs` to protect access to its members. Methods like `GetSize()`, `Insert()`, `Get()`, `HasKey()`, etc., can be called without holding external locks.

Applied to files:

  • src/net.h
  • src/llmq/quorumsman.cpp
  • src/llmq/quorumsman.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/net.h
  • src/llmq/quorumsman.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.

Applied to files:

  • src/net.h
📚 Learning: 2025-09-09T21:36:58.969Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6837
File: src/stats/rawsender.cpp:223-232
Timestamp: 2025-09-09T21:36:58.969Z
Learning: In RawSender class (src/stats/rawsender.cpp), socket operations are properly synchronized using the cs_net mutex. The m_sock and m_server members are GUARDED_BY(cs_net), and methods like Connect(), SendDirectly(), and ReconnectThread() use appropriate locking with cs_net to prevent race conditions on socket access.

Applied to files:

  • src/net.h
📚 Learning: 2025-09-09T21:36:31.504Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6837
File: src/stats/rawsender.cpp:0-0
Timestamp: 2025-09-09T21:36:31.504Z
Learning: In RawSender class (src/stats/rawsender.cpp), m_sock access is protected by the cs_net mutex. This mutex coordinates between the TCP send path in SendDirectly() and the reconnection operations in Connect()/Reconnect() methods, ensuring proper synchronization of socket state.

Applied to files:

  • src/net.h
📚 Learning: 2025-11-24T16:41:22.457Z
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/{masternode,evo}/**/*.{cpp,h} : Masternode lists must use immutable data structures (Immer library) for thread safety

Applied to files:

  • src/net.h
  • src/llmq/dkgsession.h
📚 Learning: 2025-09-09T21:36:31.504Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6837
File: src/stats/rawsender.cpp:0-0
Timestamp: 2025-09-09T21:36:31.504Z
Learning: In RawSender class (src/stats/rawsender.cpp), m_sock access requires synchronization using the cs_net mutex. The race condition exists between SendDirectly() (callable from any thread) and Connect() (called by ReconnectThread), where both read and write m_sock concurrently. The cs_net mutex properly coordinates these network operations.

Applied to files:

  • src/net.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/quorumsman.cpp
  • src/llmq/quorumsman.h
  • src/llmq/dkgsession.cpp
  • src/llmq/observer/context.cpp
  • src/llmq/utils.cpp
  • src/active/context.cpp
  • src/rpc/quorums.cpp
  • src/llmq/debug.h
📚 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/quorumsman.cpp
  • src/llmq/observer/context.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_dkgerrors.py
  • src/rpc/quorums.cpp
📚 Learning: 2025-11-24T16:41:22.457Z
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/{masternode,llmq,evo,coinjoin,governance}/**/*.{cpp,h} : Use unordered_lru_cache for efficient caching with LRU eviction in Dash-specific data structures

Applied to files:

  • src/llmq/quorumsman.h
  • src/llmq/dkgsession.h
  • src/llmq/utils.h
📚 Learning: 2025-11-13T20:02:55.480Z
Learnt from: UdjinM6
Repo: dashpay/dash PR: 6969
File: src/evo/deterministicmns.h:441-479
Timestamp: 2025-11-13T20:02:55.480Z
Learning: In `src/evo/deterministicmns.h`, the `internalId` field in `CDeterministicMN` and the `mnInternalIdMap` in `CDeterministicMNList` are non-deterministic and used only for internal bookkeeping and efficient lookups. Different nodes can assign different internalIds to the same masternode depending on their sync history. Methods like `IsEqual()` intentionally ignore internalId mappings and only compare consensus-critical deterministic fields (proTxHash, collateral, state, etc.).

Applied to files:

  • src/llmq/dkgsession.h
  • src/llmq/utils.cpp
  • src/llmq/utils.h
  • src/llmq/debug.h
📚 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.cpp
  • src/llmq/utils.h
  • src/rpc/quorums.cpp
📚 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/active/context.cpp
📚 Learning: 2025-10-03T11:20:37.475Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6838
File: src/active/context.cpp:29-33
Timestamp: 2025-10-03T11:20:37.475Z
Learning: In Dash codebase, NodeContext (src/node/context.h) serves only as a container with trivial c/d-tors; member lifetime is explicitly managed via reset() calls in the shutdown sequence (src/init.cpp), not by declaration order. For example, active_ctx.reset() is called before DashChainstateSetupClose handles llmq_ctx teardown, ensuring proper destruction order regardless of declaration order in the struct.

Applied to files:

  • src/active/context.cpp
📚 Learning: 2025-01-14T09:06:19.717Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6532
File: src/test/fuzz/netaddress.cpp:83-84
Timestamp: 2025-01-14T09:06:19.717Z
Learning: In fuzzer harness tests, CServiceHash can be used with both default constructor (CServiceHash()) and parameterized constructor (CServiceHash(salt_k0, salt_k1)) to test different variants. The usage pattern CServiceHash()(service) and CServiceHash(0, 0)(service) is valid and intentional in such tests.

Applied to files:

  • src/llmq/ehf_signals.h
📚 Learning: 2025-11-04T18:24:27.241Z
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.

Applied to files:

  • src/rpc/quorums.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/rpc/quorums.cpp
🧬 Code graph analysis (14)
src/rpc/evo.cpp (1)
src/evo/providertx.h (1)
  • nReason (258-300)
src/net.h (1)
src/net.cpp (2)
  • AddPendingProbeConnections (4458-4462)
  • AddPendingProbeConnections (4458-4458)
test/functional/feature_llmq_dkgerrors.py (1)
test/functional/test_framework/test_framework.py (2)
  • get_node (1223-1228)
  • mine_quorum (2108-2196)
src/llmq/observer/quorums.h (1)
src/llmq/quorumsman.cpp (2)
  • CleanupOldQuorumData (362-366)
  • CleanupOldQuorumData (362-362)
src/llmq/quorumsman.h (1)
src/llmq/quorumsman.cpp (10)
  • ScanQuorums (193-197)
  • ScanQuorums (193-193)
  • ScanQuorums (199-307)
  • ScanQuorums (199-201)
  • CleanupOldQuorumData (362-366)
  • CleanupOldQuorumData (362-362)
  • GetQuorum (368-389)
  • GetQuorum (368-368)
  • GetQuorum (391-407)
  • GetQuorum (391-391)
src/llmq/dkgsession.h (2)
src/llmq/dkgsession.cpp (5)
  • ReceiveMessagePreamble (612-675)
  • ReceiveMessagePreamble (612-612)
  • ReceiveMessagePreamble (677-677)
  • ReceiveMessagePreamble (678-678)
  • ReceiveMessagePreamble (679-679)
src/active/dkgsessionhandler.cpp (1)
  • logger (336-336)
src/rpc/governance.cpp (4)
src/qt/rpcconsole.cpp (2)
  • request (421-475)
  • request (421-421)
src/rpc/request.cpp (1)
  • request (31-31)
src/rpc/server.cpp (1)
  • request (552-552)
src/governance/vote.h (1)
  • nTime (69-69)
src/llmq/dkgsession.cpp (2)
src/llmq/debug.h (1)
  • phase (60-60)
src/llmq/commitment.h (1)
  • quorumIndex (56-56)
src/llmq/quorums.h (1)
src/llmq/quorums.cpp (2)
  • DataCleanupHelper (29-74)
  • DataCleanupHelper (29-29)
src/active/dkgsession.cpp (1)
src/active/dkgsessionhandler.cpp (1)
  • logger (336-336)
src/llmq/utils.h (2)
src/llmq/utils.cpp (2)
  • CalcDeterministicWatchConnections (757-777)
  • CalcDeterministicWatchConnections (757-759)
src/llmq/params.h (1)
  • LLMQType (14-125)
src/test/rpc_tests.cpp (5)
src/rpc/quorums.cpp (1)
  • result (475-475)
src/rpc/mining.cpp (1)
  • result (872-872)
src/rpc/blockchain.cpp (3)
  • result (139-139)
  • result (277-277)
  • result (564-564)
src/bitcoin-cli.cpp (4)
  • result (329-329)
  • result (340-340)
  • result (474-474)
  • result (715-715)
src/rpc/node.cpp (7)
  • result (429-429)
  • result (503-503)
  • result (590-590)
  • result (678-678)
  • result (743-743)
  • result (1015-1015)
  • result (1094-1094)
src/llmq/debug.h (2)
src/llmq/debug.cpp (4)
  • CDKGDebugManager (110-116)
  • CDKGDebugManager (118-118)
  • GetSessionCount (120-123)
  • GetSessionCount (120-120)
src/llmq/core_write.cpp (14)
  • GetJsonHelp (20-78)
  • GetJsonHelp (20-20)
  • GetJsonHelp (81-95)
  • GetJsonHelp (81-81)
  • GetJsonHelp (97-114)
  • GetJsonHelp (97-97)
  • GetJsonHelp (134-142)
  • GetJsonHelp (134-134)
  • GetJsonHelp (153-178)
  • GetJsonHelp (153-153)
  • GetJsonHelp (222-234)
  • GetJsonHelp (222-222)
  • GetJsonHelp (255-266)
  • GetJsonHelp (255-255)
src/llmq/debug.cpp (1)
src/llmq/debug.h (1)
  • CDKGDebugManager (91-124)
🪛 Cppcheck (2.19.0)
src/llmq/core_write.cpp

[error] 80-80: Uninitialized variable

(legacyUninitvar)

🪛 GitHub Actions: Clang Diff Format Check
src/llmq/dkgsession.h

[error] 1-1: Clang format differences detected. Run clang-format-diff.py to fix formatting in this file.

src/llmq/dkgsession.cpp

[error] 1-1: Clang format differences detected. Run clang-format-diff.py to fix formatting in this file.

src/rpc/quorums.cpp

[error] 1-1: Clang format differences detected. Run clang-format-diff.py to fix formatting in this file.

src/llmq/debug.h

[error] 1-1: Clang format differences detected. Run clang-format-diff.py to fix formatting in this file.

src/active/dkgsessionhandler.cpp

[error] 1-1: Clang format differences detected. Run clang-format-diff.py to fix formatting in this file.

🔇 Additional comments (59)
src/rpc/client.cpp (2)

258-258: LGTM: Clear documentation of index offset.

The comment accurately explains that compound RPC parameter indices are offset by one to account for the subcommand occupying position 0 in the parameter array.


259-313: All parameter indices in the RPC conversion entries are correct and match the actual RPC method signatures. No changes needed.

src/rpc/governance.cpp (4)

179-180: LGTM - Consistent use of getInt() API.

The migration from ParseInt32V/ParseInt64V to getInt<int>() and getInt<int64_t>() aligns with the UniValue templated API introduced in bitcoin#25153 (dash#6775). Based on learnings.


228-228: LGTM - Type consistency verified.

The collateralIndex is correctly parsed as int and subsequently cast to uint32_t on line 232, matching the existing pattern.


281-281: LGTM - Proper handling of optional parameter.

The ternary correctly handles the empty params case with a default of 10, and the negative check on line 282 provides appropriate validation.


364-365: LGTM - Consistent with gobject_prepare parsing.

The nRevision and nTime parsing matches the pattern used in gobject_prepare (lines 179-180), maintaining consistency across related RPC handlers.

src/rpc/evo.cpp (4)

716-716: LGTM - Proper negative value validation before cast.

The pattern of parsing as int, validating collateralIndex < 0, then casting to uint32_t on line 721 is correct and safe.


1269-1274: LGTM - Proper bounds validation for reason code.

The nReason is correctly validated against both lower bound (< 0) and upper bound (CProUpRevTx::REASON_LAST) before casting to uint16_t. This matches the uint16_t nReason field in CProUpRevTx as shown in the relevant code snippets from src/evo/providertx.h.


1455-1455: LGTM - Consistent height parsing with validation.

The height is properly validated on line 1456 against chain bounds before use.


1488-1488: LGTM - Consistent pattern with wallet list variant.

This matches the same parsing and validation pattern used on lines 1455-1458 for the wallet case, maintaining consistency within the function.

src/net.h (3)

36-38: LGTM - Required includes for type migration.

The saltedhasher.h include provides the Uint256HashSet type definition needed for the container type changes below.


1469-1469: LGTM - Consistent container type migration.

The parameter type change from std::set<uint256> to Uint256HashSet aligns with the member variable change on line 1786 and the implementation in net.cpp that uses range insert.


1786-1786: LGTM - Performance optimization for pending probes.

Changing from std::set<uint256> to Uint256HashSet provides O(1) average-case lookup/insert complexity instead of O(log n). Since probe connections don't require ordering, an unordered set is appropriate here. This aligns with the broader PR migration pattern across DKG and quorum-related components.

src/active/context.cpp (1)

38-41: DI construction for CDKGDebugManager looks consistent with the refactor.

No concerns with the new constructor wiring; it also keeps dkgdbgman initialized before qdkgsman/handlers that may use it.

src/llmq/ehf_signals.h (1)

32-37: Uint256HashSet for ids looks appropriate for the described “filter” usage.

Assuming callers don’t require ordered iteration, this is a good perf-oriented refactor.

src/test/rpc_tests.cpp (1)

604-616: Test expectation update to getInt<int>() is aligned with typed RPC conversion.

src/net.cpp (1)

4458-4462: Self-aliasing risk is theoretical but extremely unlikely; iterator invalidation concern is incorrect.

The function is called only once in the codebase (src/llmq/utils.cpp:873) with a locally-constructed Uint256HashSet probeConnections, making self-aliasing with masternodePendingProbes impossible in practice.

More importantly, the iterator invalidation risk described is not present: the code iterates over the source range (proTxHashes) while inserting into the destination (masternodePendingProbes). Rehashing of the destination set does not invalidate iterators to the source, so there is no UB here. Iterator invalidation would only occur if you iterated over the same unordered_set being rehashed during insertion.

The proposed hardening with reserve() and the self-aliasing check are defensive in the wrong direction—if self-aliasing did occur, you would still need to copy the source before inserting to avoid modifying the container mid-iteration. Given the single, fixed call site with a local variable, this mitigation adds complexity without addressing a realistic threat.

src/llmq/quorums.h (1)

38-38: LGTM! Performance optimization with hash-based container.

The migration from std::set<uint256> to Uint256HashSet is well-suited for the skip list use case, providing O(1) membership checks instead of O(log n). The implementation in src/llmq/quorums.cpp confirms this is used exclusively for lookups without requiring ordering.

src/rpc/masternode.cpp (1)

385-385: LGTM! Type-safe parameter extraction.

The migration to getInt<int64_t>() provides type-safe extraction with proper null-check handling via the ternary operator. This aligns with the modern UniValue API introduced in bitcoin#25153.

src/llmq/observer/quorums.cpp (1)

337-363: LGTM! Consistent container migration for performance.

The migration to Uint256HashSet for both dbKeysToSkip and quorum_keys is appropriate. The containers are used exclusively for membership tracking and merging, where hash-based operations provide O(1) performance vs O(log n) for ordered sets. The merge() operation is fully supported in C++17+ for std::unordered_set.

src/llmq/observer/context.cpp (1)

22-22: LGTM! Dependency injection for improved testability.

The change from default construction to parameterized construction CDKGDebugManager(dmnman, qsnapman, chainman) makes dependencies explicit and improves testability. The required references are already available from the constructor parameter list.

src/llmq/observer/quorums.h (1)

62-62: LGTM! Interface updated for container migration.

The pure virtual method signature correctly updated to match the Uint256HashSet migration. The implementation in src/llmq/quorumsman.cpp:361 confirms the interface change is consistently applied across all implementations.

test/functional/feature_llmq_dkgerrors.py (1)

40-40: LGTM! Numeric argument type alignment.

The conversion from string literals to integer literals for quorum command numeric arguments is consistent across all test cases and aligns with the RPC parameter parsing refactor (switching from ParseInt32V/ParseInt64V to direct .getInt<>() calls).

Also applies to: 45-46, 51-51, 59-60, 65-67, 72-73, 78-79

src/llmq/dkgsessionhandler.h (1)

70-70: LGTM! Performance optimization via hash-based container.

Replacing std::set<uint256> with Uint256HashSet provides O(1) lookup instead of O(log n) for message deduplication, which is appropriate since message ordering is not required for tracking seen messages.

src/llmq/quorums.cpp (1)

29-29: LGTM! Container type migration for DataCleanupHelper.

The parameter type change to Uint256HashSet is compatible with the existing usage at line 50 (skip_list.find(...)) and aligns with the broader performance optimization effort.

src/llmq/quorumsman.cpp (2)

85-85: LGTM! Mutex consolidation simplifies quorum cache locking.

The consolidation of cs_map_quorums and cs_scan_quorums into a single m_cs_maps mutex simplifies the locking logic and ensures consistent protection for both mapQuorumsCache and scanQuorumsCache.

Note: This consolidation may increase lock contention if map and scan operations were previously parallelizable, but it eliminates potential lock-ordering issues and reduces complexity.

Also applies to: 109-109, 233-233, 296-296, 402-402, 533-533


362-362: LGTM! Parameter type change aligns with container migration.

The signature change to accept const Uint256HashSet& instead of const std::set<uint256>& is consistent with the broader performance optimization effort across LLMQ code.

src/active/dkgsession.h (1)

46-46: LGTM! Consistent parameter type migration.

The SendJustification parameter type change from const std::set<uint256>& to const Uint256HashSet& aligns with the broader container migration for performance optimization. All call-sites have been properly updated to pass Uint256HashSet, as confirmed by the implementation at src/active/dkgsession.cpp:307-336 where the justifyFor variable is correctly declared as Uint256HashSet and passed to the method.

src/active/dkgsession.cpp (3)

46-47: LGTM: Logger initialization moved after membership check.

The logger is now created after the AreWeMember() check and threshold assertion, avoiding unnecessary construction when the early return paths are taken.


307-307: LGTM: Container type update to Uint256HashSet.

The change from std::set<uint256> to Uint256HashSet improves lookup performance for member justification tracking. The usage with emplace() and count() remains semantically equivalent.


340-341: LGTM: SendJustification signature updated consistently.

The parameter type change to const Uint256HashSet& aligns with the caller in VerifyAndJustify and the header declaration.

src/active/dkgsessionhandler.cpp (2)

253-260: LGTM: Container type changes for batch signature verification.

The function signature and internal containers are updated from ordered to unordered sets. This is appropriate since ordering is not required for tracking bad nodes or message hashes, and hash-based containers provide better average-case lookup performance.


266-266: LGTM: messageHashesSet uses Uint256HashSet.

Consistent with the PR-wide migration to hash-based containers for uint256 collections.

src/llmq/dkgsession.h (4)

9-9: LGTM: Added protocol.h include.

Required for CInv type used in the new ReceiveMessageState struct.


218-224: LGTM: CDKGMember container types updated to Uint256HashSet.

All member tracking containers (contributions, complaints, justifications, prematureCommitments, badMemberVotes, complaintsFromOthers) now use hash-based sets. This aligns with the coding guidelines for using efficient containers in LLMQ data structures.


284-296: LGTM: Internal helper types for message reception.

The MsgPhase enum and ReceiveMessageState struct support the new ReceiveMessagePreamble template, centralizing common message handling logic and reducing code duplication across ReceiveMessage overloads.


417-420: LGTM: ReceiveMessagePreamble template declaration.

The template with EXCLUSIVE_LOCKS_REQUIRED(invCs) annotation correctly documents the locking requirements for the centralized message preamble processing.

src/llmq/core_write.cpp (1)

80-81: LGTM: GetJsonHelp moved to CDKGDebugManager.

The function scope change from CDKGDebugStatus to CDKGDebugManager aligns with the refactor consolidating debug status reporting. The added inner_optional parameter provides flexibility for optional inner field documentation.

Note: The Cppcheck "uninitialized variable" warning at line 80 appears to be a false positive—this is a static method that returns a fully constructed RPCResult object.

src/llmq/utils.cpp (2)

757-770: LGTM: Return type and container updated to unordered_set.

The function returns connection indices where ordering is not required, making std::unordered_set<size_t> appropriate.


845-845: LGTM: probeConnections uses Uint256HashSet.

Consistent with PR-wide container type migration.

src/rpc/quorums.cpp (5)

72-72: LGTM: Direct UniValue parameter parsing.

Using request.params[0].getInt<int>() instead of ParseInt32V() is cleaner and leverages UniValue's built-in type conversion with proper error handling.


277-277: LGTM: llmqType parsing updated consistently.

The pattern static_cast<Consensus::LLMQType>(request.params[0].getInt<int>()) is used consistently across all RPC methods that accept llmqType.


300-300: LGTM: Updated to CDKGDebugManager::GetJsonHelp.

Reflects the API consolidation where JSON help generation moved to the debug manager.


349-358: LGTM: Debug status JSON generation refactored.

The refactor from constructing CDKGDebugStatus separately to using debugman->ToJson(detailLevel) simplifies the code and centralizes the JSON generation logic in the debug manager.


1006-1006: LGTM: Using GetSessionCount() accessor.

The new accessor method properly encapsulates the session count retrieval with appropriate locking.

src/llmq/debug.h (4)

48-48: LGTM: complaintsFromMembers uses std::unordered_set.

The container change from std::set<uint16_t> to std::unordered_set<uint16_t> is appropriate since member indices don't require ordering for complaint tracking.


86-89: LGTM: CDKGDebugStatus simplified to struct.

Changing from class to struct with only data members is appropriate since all methods were moved to CDKGDebugManager. The simpler data structure clearly conveys its role as a plain data container.


93-106: LGTM: CDKGDebugManager constructor with dependency injection.

The refactor introduces proper dependency injection, storing references to CDeterministicMNManager, CQuorumSnapshotManager, and ChainstateManager. This aligns with the broader refactoring goal of extracting components from LLMQContext and follows the project's initialization patterns seen in other files.


119-123: LGTM: New accessor methods with proper lock annotations.

  • GetSessionCount() provides encapsulated access to session count
  • GetJsonHelp() is appropriately static since it doesn't depend on instance state
  • ToJson() has the correct EXCLUSIVE_LOCKS_REQUIRED(!cs_lockStatus) annotation indicating it acquires the lock internally

The API is clean and well-documented.

src/llmq/quorumsman.h (3)

87-91: Mutex consolidation looks good.

Consolidating cs_map_quorums and cs_scan_quorums into a single m_cs_maps mutex simplifies the locking strategy. Looking at the relevant snippets from quorumsman.cpp, the ScanQuorums method accesses both caches within the same logical operation (lines 231-262 and 296-302), so having a single mutex is appropriate and reduces the risk of lock ordering issues.


161-161: Signature change to Uint256HashSet aligns with guidelines.

Switching from std::set<uint256> to Uint256HashSet provides O(1) lookup complexity, which is appropriate for membership checks during cleanup operations. As per coding guidelines, this follows the preference for unordered containers in Dash-specific data structures.


15-15: Include addition is necessary.

The saltedhasher.h include is required for Uint256HashSet type used in the CleanupOldQuorumData signature.

src/llmq/dkgsession.cpp (3)

206-221: Clean extraction of common logic to preamble.

The refactoring properly delegates pre-processing (hash computation, relay decision, status updates) to ReceiveMessagePreamble, and the contribution-specific logic (vvec storage, decryption, verification) remains in ReceiveMessage. The timer t2 is correctly placed to measure only the contribution-specific processing.


361-361: Good performance improvement.

Switching from std::set<size_t> to std::unordered_set<size_t> improves the duplicate detection check from O(log n) to O(1), which is appropriate for this DoS protection code path.


677-679: Explicit instantiations are complete.

The three explicit template instantiations correctly cover all message types that use ReceiveMessagePreamble. CDKGPrematureCommitment intentionally has different handling and doesn't use this template.

src/llmq/debug.cpp (4)

110-116: Dependency injection improves design.

The new constructor that accepts CDeterministicMNManager&, CQuorumSnapshotManager&, and const ChainstateManager& improves testability and makes dependencies explicit. This aligns with the broader refactoring goals of the PR.


120-123: Simple and thread-safe accessor.

The GetSessionCount() method correctly uses WITH_LOCK to access localStatus.sessions.size() under the mutex.


135-146: Session iteration correctly uses internal state and injected dependencies.

The loop properly iterates over localStatus.sessions and passes the stored member references (m_dmnman, m_qsnapman, m_chainman) to CDKGDebugSessionStatus::ToJson. This ensures consistent behavior regardless of where ToJson is called from.


125-150: Lock ordering is consistent and safe. The ToJson method acquires cs_lockStatus, then calls CDKGDebugSessionStatus::ToJson which uses WITH_LOCK to acquire cs_main. This establishes a consistent one-way lock order (cs_lockStatus → cs_main) with no reverse dependency. Public methods are properly annotated with EXCLUSIVE_LOCKS_REQUIRED(!cs_lockStatus), preventing misuse. No deadlock risk exists.

Comment on lines +65 to +67
std::unordered_set<size_t> CalcDeterministicWatchConnections(Consensus::LLMQType llmqType,
gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex,
size_t memberCount, size_t connectionCount);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's check if the file exists and read its content around lines 65-67
head -n 80 src/llmq/utils.h | tail -n 30

Repository: dashpay/dash

Length of output: 1616


🏁 Script executed:

# Check the full include section at the top of the file
head -n 20 src/llmq/utils.h

Repository: dashpay/dash

Length of output: 527


🏁 Script executed:

# Find all call sites of CalcDeterministicWatchConnections
rg -n 'CalcDeterministicWatchConnections\s*\(' --type=cpp

Repository: dashpay/dash

Length of output: 606


🏁 Script executed:

# Check the call site at src/llmq/utils.cpp:805
sed -n '800,815p' src/llmq/utils.cpp

Repository: dashpay/dash

Length of output: 916


🏁 Script executed:

# Check the call site at src/active/quorums.cpp:60
sed -n '55,75p' src/active/quorums.cpp

Repository: dashpay/dash

Length of output: 2055


Add explicit #include <unordered_set> to src/llmq/utils.h.

The function declaration at lines 65–67 returns std::unordered_set<size_t>, but the header lacks an explicit include for it. Call sites (src/llmq/utils.cpp:805 and src/active/quorums.cpp:60) iterate through the result to index into arrays, so they don't depend on ordering. However, relying on transitive includes for a type used in the public API is fragile; add the include directly.

Proposed fix
 #include <gsl/pointers.h>

+#include <unordered_set>
 #include <set>
 #include <vector>

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @src/llmq/utils.h around lines 65 - 67, The header declares
std::unordered_set in the public API (CalcDeterministicWatchConnections) but
does not include <unordered_set>; add an explicit #include <unordered_set> to
the top of the header (next to the other standard includes) so the declaration
does not rely on transitive includes and consumers can compile independently.

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.

1 participant