Skip to content

Conversation

@knst
Copy link
Collaborator

@knst knst commented Nov 25, 2025

Issue being fixed or feature implemented

Separation of consensus & chain code and network & node in Dash Core is blocked by tight connection of network and consensus code; in components such as llmq::CSigningManager, llmq::CSigSharesManager, coinjoin::client, coinjoin::server, governance/, llmq::CInstantSendManager, etc.
It blocks backport's of bitcoin related to 'kernel' project.

What was done?

This PR addresses a dependency of CGovernanceManager on PeerManager

It is a split from proof-of-concept PR #6934

Prior work: #6959 #6992

How Has This Been Tested?

Run unit & functional tests.
Run a linter test/lint/lint-circular-dependencies.py

Overall conception is tested in #6934 as potentially successful to finish separation of network & consensus code.

Breaking Changes

N/A

Checklist:

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

@knst knst added this to the 23.1 milestone Nov 25, 2025
@knst knst changed the title refactor: separate network and consensus logic 3/N [governance] refactor: separate network and consensus logic 3/N [governance] Nov 25, 2025
@github-actions
Copy link

github-actions bot commented Nov 25, 2025

⚠️ Potential Merge Conflicts Detected

This PR has potential conflicts with the following open PRs:

Please coordinate with the authors of these PRs to avoid merge conflicts.

@coderabbitai
Copy link

coderabbitai bot commented Nov 25, 2025

Walkthrough

The PR refactors governance networking into a NetGovernance NetHandler and centralizes handler scheduling via PeerManager::ScheduleHandlers. CGovernanceManager's network-facing API is simplified: ProcessMessage is replaced by ProcessObject and several new data-accessors (FetchRelayInventory, FetchGovernanceObjectVotes, GetMNManager, ProcessVote, etc.) are added with updated locking annotations. NetHandler gains Schedule and ProcessMessage now accepts a CConnman& parameter. CMasternodeSync governance tick/maintenance code is removed. LoadChainstate signatures drop governance/txindex/network-id parameters. Test expectations for circular dependencies are updated.

Sequence Diagram(s)

sequenceDiagram
    participant Scheduler
    participant PeerManager
    participant NetGovernance
    participant CGovernanceManager
    participant Connman

    Note over Scheduler,PeerManager: New handler registration flow
    Scheduler->>PeerManager: ScheduleHandlers()
    activate PeerManager
    PeerManager->>NetGovernance: Schedule(scheduler, connman)
    deactivate PeerManager

    Note over Scheduler,NetGovernance: Periodic tick + message handling
    Scheduler->>NetGovernance: ProcessTick(connman)
    activate NetGovernance
    alt Need votes/objects
        NetGovernance->>NetGovernance: RequestGovernanceObjectVotes(...)
        NetGovernance->>Connman: send requests
    else Sync progress / housekeeping
        NetGovernance->>CGovernanceManager: FetchRelayInventory / FetchGovernanceObjectVotes
    end
    deactivate NetGovernance

    Note over PeerManager,NetGovernance: Inbound message processing
    PeerManager->>NetGovernance: ProcessMessage(peer, connman, msg_type, vRecv)
    activate NetGovernance
    alt MNGOVERNANCEOBJECT
        NetGovernance->>CGovernanceManager: ProcessObject(peer, hash, govobj)
    else MNGOVERNANCEOBJECTVOTE
        NetGovernance->>CGovernanceManager: ProcessVote(peer, vote, exception, connman)
    end
    NetGovernance->>PeerManager: PeerPostProcessMessage(result)
    deactivate NetGovernance
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Areas needing extra attention:
    • src/governance/net_governance.{cpp,h} — new scheduling/tick, request throttling, and message handling logic
    • src/governance/governance.{h,cpp} — API surface, signature changes, locking annotations, and ProcessObject semantics
    • src/net_processing.{h,cpp} — NetHandler/PeerManager interface changes (Schedule, ProcessMessage signature, PeerPostProcessMessage, PeerGetRequestedObjectCount)
    • Cross-cutting: all NetHandler implementations (e.g., instantsend) for updated ProcessMessage signature
    • Init/chainstate impacts: src/init.cpp, src/node/chainstate.{h,cpp} and tests referencing LoadChainstate
    • Thread-safety annotations and EXCLUSIVE_LOCKS_REQUIRED correctness

Possibly related PRs

Suggested reviewers

  • kwvg
  • UdjinM6
  • PastaPastaPasta

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.33% 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 title accurately describes the primary change: refactoring to separate network and consensus logic specifically for governance, clearly identifying it as part 3 of a larger series.
Description check ✅ Passed The description is directly related to the changeset, explaining the motivation (CGovernanceManager dependency on PeerManager), what was done (the refactoring), testing approach, and context within a larger separation effort.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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

🧹 Nitpick comments (9)
src/net_processing.cpp (1)

662-662: Clarify PeerPostProcessMessage semantics for Node-scoped side effects

PeerPostProcessMessage always calls PostProcessMessage(std::move(ret), -1), so any m_error/m_to_erase in MessageProcessingResult will not be attributed to a real peer (both Misbehaving and EraseObjectRequest effectively no-op for node -1).

If NetHandlers are expected to:

  • Drive misbehavior scoring or
  • Erase per-peer object requests

via MessageProcessingResult, they will currently not get those behaviors when going through PeerPostProcessMessage. In that case, either:

  • Thread the actual NodeId through PeerPostProcessMessage, or
  • Document that handlers must call PeerMisbehaving / PeerEraseObjectRequest directly and only use PeerPostProcessMessage for node-agnostic actions (m_transactions, m_inventory, m_dsq).

Please confirm which contract you intend and adjust either the API or callers accordingly.

Also applies to: 3587-3604, 6579-6582

src/governance/net_governance.cpp (7)

20-20: Unnecessary forward declaration.

CConnman is already declared in net.h which is included on line 12. This forward declaration is redundant.

-class CConnman;
-
 void NetGovernance::Schedule(CScheduler& scheduler, CConnman& connman)

131-131: Minor typo: "to early" → "too early".

-            // to early to ask the same node
+            // too early to ask the same node

161-162: Minor style: prefer static const over const static.

Both are valid C++, but static const is the more conventional ordering.

-    const static int64_t nSyncStart = TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now());
-    const static std::string strAllow = strprintf("allow-sync-%lld", nSyncStart);
+    static const int64_t nSyncStart = TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now());
+    static const std::string strAllow = strprintf("allow-sync-%lld", nSyncStart);

310-310: Minor typo: "to early" → "too early".

-            continue; // to early for this node
+            continue; // too early for this node

379-382: Redundant IsBlockchainSynced() check.

This check is redundant because line 348 already returns early if !m_node_sync.IsBlockchainSynced(). Consider removing for clarity.

-        if (!m_node_sync.IsBlockchainSynced()) {
-            LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECT -- masternode list not synced\n");
-            return;
-        }

409-412: Redundant IsBlockchainSynced() check.

Same as above - this is already guarded by the check on line 348.

-        if (!m_node_sync.IsBlockchainSynced()) {
-            LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- masternode list not synced\n");
-            return;
-        }

440-441: Existing TODO comment about relay issue.

This TODO indicates a known issue with immediate inventory relay. Consider tracking this in an issue if not already done.

Would you like me to help document this issue or investigate why immediate sending doesn't work here?

src/governance/governance.h (1)

389-389: Minor: extra blank line.

     bool ProcessVote(CNode* pfrom, const CGovernanceVote& vote, CGovernanceException& exception, CConnman& connman)
         EXCLUSIVE_LOCKS_REQUIRED(!cs_store);

-
 private:
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7d69b5a and dc1d437.

📒 Files selected for processing (17)
  • src/Makefile.am (2 hunks)
  • src/governance/governance.cpp (9 hunks)
  • src/governance/governance.h (1 hunks)
  • src/governance/net_governance.cpp (1 hunks)
  • src/governance/net_governance.h (1 hunks)
  • src/init.cpp (3 hunks)
  • src/instantsend/net_instantsend.cpp (1 hunks)
  • src/instantsend/net_instantsend.h (1 hunks)
  • src/masternode/sync.cpp (1 hunks)
  • src/masternode/sync.h (2 hunks)
  • src/net_processing.cpp (5 hunks)
  • src/net_processing.h (3 hunks)
  • src/node/chainstate.cpp (0 hunks)
  • src/node/chainstate.h (0 hunks)
  • src/test/util/setup_common.cpp (0 hunks)
  • src/validation.h (0 hunks)
  • test/lint/lint-circular-dependencies.py (2 hunks)
💤 Files with no reviewable changes (4)
  • src/test/util/setup_common.cpp
  • src/validation.h
  • src/node/chainstate.h
  • src/node/chainstate.cpp
🧰 Additional context used
📓 Path-based instructions (6)
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/masternode/sync.cpp
  • src/governance/net_governance.h
  • src/instantsend/net_instantsend.cpp
  • src/governance/governance.cpp
  • src/masternode/sync.h
  • src/net_processing.h
  • src/instantsend/net_instantsend.h
  • src/init.cpp
  • src/net_processing.cpp
  • src/governance/net_governance.cpp
  • src/governance/governance.h
src/{masternode,evo}/**/*.{cpp,h}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • src/masternode/sync.cpp
  • src/masternode/sync.h
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/masternode/sync.cpp
  • src/governance/net_governance.h
  • src/governance/governance.cpp
  • src/masternode/sync.h
  • src/governance/net_governance.cpp
  • src/governance/governance.h
src/{masternode,llmq}/**/*.{cpp,h}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • src/masternode/sync.cpp
  • src/masternode/sync.h
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/masternode/sync.cpp
  • src/governance/net_governance.h
  • src/governance/governance.cpp
  • src/masternode/sync.h
  • src/governance/net_governance.cpp
  • src/governance/governance.h
src/governance/**/*.{cpp,h}

📄 CodeRabbit inference engine (CLAUDE.md)

Governance implementation must support governance objects (proposals, triggers, superblock management) and on-chain voting with tallying

Files:

  • src/governance/net_governance.h
  • src/governance/governance.cpp
  • src/governance/net_governance.cpp
  • src/governance/governance.h
🧠 Learnings (21)
📓 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: 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: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: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/governance/**/*.{cpp,h} : Governance implementation must support governance objects (proposals, triggers, superblock management) and on-chain voting with tallying
📚 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/governance/**/*.{cpp,h} : Governance implementation must support governance objects (proposals, triggers, superblock management) and on-chain voting with tallying

Applied to files:

  • src/Makefile.am
  • src/masternode/sync.cpp
  • src/governance/net_governance.h
  • src/governance/governance.cpp
  • src/masternode/sync.h
  • src/init.cpp
  • src/governance/net_governance.cpp
  • src/governance/governance.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/Makefile.am
  • src/governance/governance.cpp
  • src/masternode/sync.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/Makefile.am
  • src/governance/governance.cpp
  • src/net_processing.h
  • src/governance/governance.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/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/masternode/sync.cpp
  • src/governance/governance.cpp
  • src/masternode/sync.h
  • src/init.cpp
  • src/governance/governance.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/instantsend/net_instantsend.cpp
📚 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/instantsend/net_instantsend.cpp
📚 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/instantsend/net_instantsend.cpp
  • src/governance/governance.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/instantsend/net_instantsend.cpp
📚 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/instantsend/net_instantsend.cpp
📚 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 access operations (m_sock and m_server) should be protected by the cs_net mutex, not avoiding synchronization entirely. While lock overhead concerns are valid in general, socket operations require proper synchronization via cs_net.

Applied to files:

  • src/instantsend/net_instantsend.cpp
📚 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 PR #6849, `cmapVoteToObject` was intentionally moved from `GovernanceStore` to `CGovernanceManager` as a memory-only variable and is NOT guarded by `cs_store`. It relies on `CacheMap`'s internal thread-safety instead.

Applied to files:

  • src/governance/governance.cpp
  • src/governance/governance.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/governance/governance.cpp
  • src/masternode/sync.h
  • src/init.cpp
📚 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:

  • src/governance/governance.cpp
  • src/init.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/coinjoin/**/*.{cpp,h} : CoinJoin implementation must use masternode-coordinated mixing sessions with uniform denomination outputs

Applied to files:

  • src/masternode/sync.h
📚 Learning: 2025-11-04T18:23:28.175Z
Learnt from: UdjinM6
Repo: dashpay/dash PR: 6933
File: src/governance/classes.cpp:147-154
Timestamp: 2025-11-04T18:23:28.175Z
Learning: In src/governance/classes.cpp, CSuperblock::GetPaymentsLimit intentionally uses synthetic difficulty constants (nBits = 1 for mainnet, powLimit for networks with min difficulty) and simple height-based V20 activation checks instead of actual chain block data. This is by design because superblocks themselves are "synthetic" governance payment blocks, not regular mined blocks.

Applied to files:

  • src/masternode/sync.h
  • src/governance/governance.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,llmq,governance,coinjoin}/**/*.{cpp,h} : Use Dash-specific database implementations: CFlatDB for persistent storage (MasternodeMetaStore, GovernanceStore, SporkStore, NetFulfilledRequestStore) and CDBWrapper extensions for Evolution/DKG/InstantSend/Quorum/RecoveredSigs data

Applied to files:

  • src/masternode/sync.h
  • src/init.cpp
  • src/governance/governance.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/node/chainstate.{cpp,h} : Chainstate initialization must be separated into dedicated src/node/chainstate.* files

Applied to files:

  • src/init.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/**/*.{cpp,h} : Special transactions use payload serialization routines defined in src/evo/specialtx.h and must include appropriate special transaction types (ProRegTx, ProUpServTx, ProUpRegTx, ProUpRevTx)

Applied to files:

  • src/init.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} : InstantSend implementation must provide distributed key generation for secure transaction locking with quorum consensus

Applied to files:

  • src/init.cpp
📚 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/governance/governance.h
🧬 Code graph analysis (7)
src/governance/net_governance.h (3)
src/governance/governance.cpp (2)
  • CGovernanceManager (66-79)
  • CGovernanceManager (81-85)
src/net_processing.h (3)
  • NetHandler (71-87)
  • NetHandler (75-78)
  • PeerManagerInternal (58-69)
src/governance/net_governance.cpp (10)
  • Schedule (22-54)
  • Schedule (22-22)
  • ProcessMessage (345-449)
  • ProcessMessage (345-345)
  • SendGovernanceSyncRequest (56-61)
  • SendGovernanceSyncRequest (56-56)
  • RequestGovernanceObjectVotes (63-152)
  • RequestGovernanceObjectVotes (63-63)
  • ProcessTick (154-343)
  • ProcessTick (154-154)
src/instantsend/net_instantsend.cpp (1)
src/net_processing.cpp (12)
  • ProcessMessage (3681-5471)
  • ProcessMessage (3681-3686)
  • pfrom (618-618)
  • pfrom (639-640)
  • pfrom (753-755)
  • pfrom (764-764)
  • pfrom (772-772)
  • pfrom (775-775)
  • pfrom (777-777)
  • pfrom (779-779)
  • pfrom (875-875)
  • pfrom (1057-1057)
src/governance/governance.cpp (2)
src/governance/governance.h (1)
  • nCachedBlockHeight (261-261)
src/net.h (1)
  • FullyConnectedOnly (1296-1296)
src/net_processing.h (1)
src/net_processing.cpp (26)
  • PeerGetRequestedObjectCount (6574-6577)
  • PeerGetRequestedObjectCount (6574-6574)
  • nodeid (628-628)
  • nodeid (631-631)
  • nodeid (644-644)
  • nodeid (656-656)
  • nodeid (661-661)
  • nodeid (679-679)
  • nodeid (681-681)
  • nodeid (719-720)
  • nodeid (730-730)
  • nodeid (862-862)
  • nodeid (864-864)
  • nodeid (1040-1040)
  • nodeid (1075-1075)
  • PeerPostProcessMessage (6579-6582)
  • PeerPostProcessMessage (6579-6579)
  • ret (662-662)
  • ret (685-685)
  • scheduler (624-624)
  • scheduler (652-652)
  • scheduler (694-694)
  • ProcessMessage (3681-5471)
  • ProcessMessage (3681-3686)
  • ScheduleHandlers (1701-1706)
  • ScheduleHandlers (1701-1701)
src/instantsend/net_instantsend.h (2)
src/net_processing.cpp (12)
  • ProcessMessage (3681-5471)
  • ProcessMessage (3681-3686)
  • pfrom (618-618)
  • pfrom (639-640)
  • pfrom (753-755)
  • pfrom (764-764)
  • pfrom (772-772)
  • pfrom (775-775)
  • pfrom (777-777)
  • pfrom (779-779)
  • pfrom (875-875)
  • pfrom (1057-1057)
src/instantsend/net_instantsend.cpp (2)
  • ProcessMessage (17-65)
  • ProcessMessage (17-17)
src/init.cpp (3)
src/interfaces/node.h (2)
  • node (42-44)
  • node (404-404)
src/rpc/blockchain.h (1)
  • node (33-36)
src/init.h (1)
  • node (23-25)
src/governance/net_governance.cpp (3)
src/util/time.h (1)
  • TicksSinceEpoch (86-89)
src/net.h (1)
  • FullyConnectedOnly (1296-1296)
src/masternode/sync.cpp (2)
  • ProcessMessage (99-112)
  • ProcessMessage (99-99)
⏰ 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). (7)
  • GitHub Check: linux64_tsan-build / Build source
  • GitHub Check: x86_64-w64-mingw32 / Build depends
  • GitHub Check: Lint / Run linters
  • GitHub Check: x86_64-pc-linux-gnu_nowallet / Build depends
  • GitHub Check: x86_64-apple-darwin / Build depends
  • GitHub Check: x86_64-pc-linux-gnu / Build depends
  • GitHub Check: arm-linux-gnueabihf / Build depends
🔇 Additional comments (29)
src/Makefile.am (1)

222-223: Net governance unit correctly wired into build system

Adding governance/net_governance.h to BITCOIN_CORE_H and governance/net_governance.cpp to libbitcoin_node_a_SOURCES is consistent with how other governance components are exposed and linked; no issues from a build/ordering perspective.

Also applies to: 511-511

src/instantsend/net_instantsend.h (1)

34-38: NetInstantSend interface aligned with NetHandler and Stop/Interrupt contract

Updating ProcessMessage to accept CConnman& and adding an Interrupt() override that forwards to workInterrupt() cleanly integrates NetInstantSend with the new NetHandler interface and the existing Stop() assertion that expects Interrupt() to be called first. No functional regressions apparent.

src/instantsend/net_instantsend.cpp (1)

17-17: ProcessMessage signature update is consistent and behavior‑preserving

The implementation now takes CConnman& (unnamed) to match the updated NetHandler interface and net_processing call sites, while leaving the message handling logic unchanged. This maintains existing InstantSend behavior.

src/net_processing.cpp (3)

1701-1706: Handler scheduling loop is straightforward and thread-safe

ScheduleHandlers just iterates m_handlers and forwards scheduler and m_connman; there are no new locking or lifecycle hazards here given handlers are already managed via Start/Stop/Interrupt.


5462-5463: Ensure NetHandler::ProcessMessage’s contract matches ignoring its return value

handler->ProcessMessage(pfrom, m_connman, msg_type, vRecv); is now called for each m_handlers entry, and its return value (if any) is ignored, unlike the built-in handlers above which still funnel their MessageProcessingResult through PostProcessMessage.

Please verify that:

  • NetHandler::ProcessMessage has been changed to void (handlers do their own post-processing via Peer* APIs), or
  • If it still returns a MessageProcessingResult, that all relevant logic was migrated into the handlers and no behavior previously driven by the result is now lost.

If the latter, consider restoring a PostProcessMessage call on the result to keep the behavior consistent.


652-652: Scheduling API surface is cohesive with existing handler lifecycle

Adding ScheduleHandlers(CScheduler&) alongside StartHandlers/StopHandlers/InterruptHandlers maintains a clear responsibility split: construction, lifecycle, and periodic scheduling are all delegated through PeerManagerImpl. The current design keeps handler ownership and scheduling concerns centralized.

Also applies to: 1670-1699

src/masternode/sync.cpp (1)

7-8: Includes updated to match used types

Adding <chain.h> and <net.h> is appropriate here given this implementation uses CBlockIndex, CConnman, and CNode. This tightens dependencies without changing behavior.

src/init.cpp (2)

2229-2229: LGTM! NetGovernance handler correctly wired.

The handler is properly constructed with required dependencies and added after loading the governance cache. This follows the same pattern as NetInstantSend on line 2198.

Note: The NetGovernance::ProcessMessage and NetGovernance::Schedule implementations already check m_gov_manager.IsValid() internally (per src/governance/net_governance.cpp lines 23 and 344), so the handler can be safely added regardless of is_governance_enabled.


2301-2301: Centralized scheduling via ScheduleHandlers is a clean refactor.

This replaces governance-specific scheduling with a generalized mechanism that iterates over all registered NetHandler instances and calls their Schedule method. This improves separation of concerns.

src/net_processing.h (3)

67-68: Appropriate extension of PeerManagerInternal interface.

These methods expose necessary peer-level operations to NetHandler implementations:

  • PeerGetRequestedObjectCount: Allows handlers to check request queue size to prevent setAskFor overflow (used in RequestGovernanceObjectVotes)
  • PeerPostProcessMessage: Enables handlers to trigger post-processing for misbehavior tracking

Both are properly implemented in PeerManagerImpl per the relevant snippets.


83-84: NetHandler interface extended with scheduling and message processing hooks.

Adding CConnman& parameter to both methods is necessary for handlers to send network messages. The default empty implementations allow handlers to opt-in to only the functionality they need.


174-174: ScheduleHandlers provides centralized scheduling orchestration.

This completes the PeerManager interface to support the new handler scheduling pattern used in init.cpp.

src/governance/net_governance.h (1)

1-39: Well-structured new NetGovernance handler class.

The design cleanly separates governance networking concerns:

  • Proper inheritance from NetHandler with final specifier
  • Constructor dependency injection pattern matches the codebase style
  • References (not pointers) for required dependencies ensure non-null invariants
  • Private helpers encapsulate implementation details

Minor observation: The include guard uses BITCOIN_GOVERNANCE_NET_GOVERNANCE_H which follows the existing convention in the codebase.

test/lint/lint-circular-dependencies.py (2)

42-43: Circular dependency expectations correctly updated.

The paths now route through governance/governance directly instead of via masternode/active/context, reflecting the architectural change where governance networking is decoupled from the active masternode context.


53-53: The new circular dependency is a necessary consequence of the design, not unintended.

The cycle exists because CMasternodeSync has a CConnman& member variable (sync.h line 52) and calls methods on it in the implementation, requiring sync.cpp to include the full net.h definition. Conversely, multiple functions in CConnman take CMasternodeSync& parameters and appear to require the full definition, necessitating the include in net.cpp. This tight coupling is the minimal expected dependency given the architectural choice to embed CConnman& in CMasternodeSync. No refactoring is needed unless the underlying architecture changes.

src/masternode/sync.h (2)

22-28: Sync state constants properly exposed.

Moving these constants to the header allows NetGovernance and other components to reference sync states and timing values without duplicating magic numbers. The values are well-documented with comments.


67-73: New accessors enable external governance sync management.

These additions expose the minimum necessary internal state:

  • BumpAttempt(): Allows NetGovernance to track peer attempts
  • GetLastBump(): Enables timeout checking in external scheduling
  • IsReachedBestHeader(): Required for sync state decisions

This is a good pattern - exposing controlled accessors rather than making members public or passing the entire object.

src/governance/net_governance.cpp (3)

22-54: LGTM!

The scheduling logic correctly gates governance-specific tasks behind IsValid() and uses appropriate timing for test vs. production environments.


94-96: Static local state requires careful consideration.

Using static locals for cs_recently and mapAskedRecently means this state persists across all NetGovernance instances and is shared globally. While this appears intentional (to track recently-asked peers across sync sessions), ensure this is the desired behavior, especially if multiple NetGovernance instances could exist.


140-147: Verify loop termination when no nodes can be asked.

The i-- on line 146 compensates when fAsked is false, but since lines 141-145 unconditionally pop from the vectors regardless of fAsked, the loop will eventually terminate when vectors empty (line 116 breaks). This logic appears correct but is subtle.

src/governance/governance.cpp (8)

27-27: LGTM!

Include change from validation.h to validationinterface.h aligns with the PR's goal of separating concerns. The file uses GetMainSignals() from validationinterface.h for notifications.


183-231: LGTM with optional efficiency note.

The new ProcessObject method correctly consolidates governance object processing. The lock annotations properly require cs_main to be held by the caller (as shown in net_governance.cpp line 393 with WITH_LOCK(::cs_main, ...)).

For a future optimization, consider taking CGovernanceObject by rvalue reference since it's ultimately moved into storage, but this is fine for a refactoring PR.


449-455: LGTM!

Clean swap-and-return pattern for fetching relay inventory with proper locking.


599-599: LGTM!

Adding explicit LOCK(cs_store) at function start correctly implements the lock requirement for accessing mapObjects.


652-652: LGTM!

Same as above - proper lock acquisition for SyncObjects.


960-960: LGTM!

GetMNManager() correctly uses Assert to ensure m_dmnman is valid before dereferencing.


962-991: LGTM!

The updated FetchGovernanceObjectVotes returns a structured pair of vectors, providing a cleaner API than modifying parameters in-place.


1174-1198: LGTM!

The orphan vote cleanup logic is correctly inlined, and the NodesSnapshot pattern with FullyConnectedOnly matches usage in ProcessTick() (see net_governance.cpp line 179).

src/governance/governance.h (1)

367-388: LGTM! Clear API section for NetGovernance integration.

The new public methods are well-organized under a clear comment and have proper lock annotations. The API surface exposed to NetGovernance is appropriately scoped:

  • FetchRelayInventory() - relay coordination
  • CheckAndRemove() - cleanup operations
  • RequestOrphanObjects() - orphan management
  • FetchGovernanceObjectVotes() - vote request preparation
  • ProcessObject() / ProcessVote() - object/vote processing
  • SyncObjects() / SyncSingleObjVotes() - sync responses
  • AcceptMessage() - request tracking
  • GetMNManager() - MN list access

Comment on lines +17 to +18
/** Default for -syncmempool */
static const bool DEFAULT_SYNC_MEMPOOL = true;
Copy link

@coderabbitai coderabbitai bot Nov 25, 2025

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

DEFAULT_SYNC_MEMPOOL constant placement.

This constant is now defined in the masternode/sync header. Verify this is the intended location, as it appears to be a general node configuration option rather than masternode-specific.


🏁 Script executed:

#!/bin/bash
# Check where DEFAULT_SYNC_MEMPOOL was previously defined and where it's used
rg -n "DEFAULT_SYNC_MEMPOOL" --type cpp --type h

Length of output: 383


I'll verify whether this location is appropriate by checking the pattern for similar configuration constants.

Actually, let me correct that - I need to search the actual codebase:


🏁 Script executed:

#!/bin/bash
# Check pattern of DEFAULT_* constants and their locations
echo "=== Finding DEFAULT_* constants ==="
rg -n "static const.*DEFAULT_" --type cpp --type h | head -20

echo ""
echo "=== Checking what init.cpp includes for constants ==="
rg -n "^#include" src/init.cpp | head -20

echo ""
echo "=== Checking where other mempool constants are defined ==="
rg -n "mempool" --type h src/ | grep -i "const\|define" | head -15

Length of output: 4544


🏁 Script executed:

This will be run on the codebase to check patterns.

Length of output: 42


🏁 Script executed:

#!/bin/bash
# Check pattern of DEFAULT_* constants and their locations
echo "=== Finding DEFAULT_* constants ==="
rg -n "static const.*DEFAULT_" --type cpp --type h | head -20

echo ""
echo "=== Checking what init.cpp includes ==="
head -50 src/init.cpp | rg "^#include"

echo ""
echo "=== Check other DEFAULT_ constants in masternode/sync.h and nearby files ==="
rg -n "DEFAULT_" src/masternode/ --type cpp --type h | head -15

Length of output: 2768


Let me check if this constant was recently added or moved to this location.


🏁 Script executed:

#!/bin/bash
# Check if validation.h is included by masternode/sync.h or other related files
echo "=== Checking masternode/sync.h includes ==="
head -30 src/masternode/sync.h

echo ""
echo "=== Check validation.h for mempool-related constants ==="
rg -n "DEFAULT_.*MEMPOOL|DEFAULT_.*SYNC" src/validation.h

echo ""
echo "=== Look for any other instances of DEFAULT_SYNC in codebase ==="
rg -n "DEFAULT_SYNC" --type cpp --type h

Length of output: 1813


Move DEFAULT_SYNC_MEMPOOL to src/validation.h with other mempool-related defaults.

The constant is placed in src/masternode/sync.h but should follow the established pattern: similar mempool constants like DEFAULT_MEMPOOL_EXPIRY and DEFAULT_PERSIST_MEMPOOL are defined in src/validation.h. The -syncmempool option is a general node configuration (used in src/init.cpp) and governance (src/governance/net_governance.cpp), not masternode-specific functionality. This placement should be moved to maintain proper separation of concerns and code organization.

🤖 Prompt for AI Agents
In src/masternode/sync.h around lines 17-18, the DEFAULT_SYNC_MEMPOOL constant
belongs in src/validation.h with the other mempool defaults; remove the static
const bool DEFAULT_SYNC_MEMPOOL = true; from sync.h, add the same definition
into src/validation.h next to DEFAULT_MEMPOOL_EXPIRY/DEFAULT_PERSIST_MEMPOOL,
and ensure any files that previously relied on including sync.h for this symbol
(e.g., src/init.cpp, src/governance/net_governance.cpp) include src/validation.h
instead; rebuild to verify no missing symbol or include errors.

Copy link
Collaborator Author

@knst knst Nov 25, 2025

Choose a reason for hiding this comment

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

That's correct; the file masternode/sync.h which have CMasternodeSync is incorrectly named and incorrectly placed. It has nothing to do with "masternode".

It should be called NodeSyncing or NodeSyncStatus or something similar and be located in node/sync.h.

DEFAULT_SYNC_MEMPOOL is correctly located now. it has nothing to do with "validation" in validation.h

Renaming it is out-of-scope of this PR; could be done someday later

Copy link

Choose a reason for hiding this comment

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

@knst, thank you for the clarification! You're absolutely right that DEFAULT_SYNC_MEMPOOL belongs with the synchronization logic conceptually, not with validation. I understand now that while the file naming and location could be improved (as a future refactoring to node/sync.h with a class rename), the constant is correctly co-located with the sync functionality it relates to.

I appreciate you explaining the architectural reasoning—this helps me better understand the separation between sync-related configuration and validation-related configuration.

 (\__/)
 (='.'=)  *noted for future reviews*
 (")_(")

✏️ Learnings added
Learnt from: knst
Repo: dashpay/dash PR: 7008
File: src/masternode/sync.h:17-18
Timestamp: 2025-11-25T10:53:37.501Z
Learning: In Dash Core, `DEFAULT_SYNC_MEMPOOL` belongs with node synchronization logic (currently in src/masternode/sync.h) rather than with validation logic in src/validation.h, even though other mempool-related constants are in validation.h. The constant is conceptually tied to sync functionality, not validation.

Learnt from: knst
Repo: dashpay/dash PR: 7008
File: src/masternode/sync.h:17-18
Timestamp: 2025-11-25T10:53:37.501Z
Learning: The file src/masternode/sync.h containing `CMasternodeSync` is misnamed and misplaced—it has nothing to do with "masternode" functionality. It should eventually be renamed to `NodeSyncing` or `NodeSyncStatus` and moved to src/node/sync.h as a future refactoring.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
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: 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

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: 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: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/governance/**/*.{cpp,h} : Governance implementation must support governance objects (proposals, triggers, superblock management) and on-chain voting with tallying

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

void PeerRelayInvFiltered(const CInv& inv, const CTransaction& relatedTx) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
void PeerRelayInvFiltered(const CInv& inv, const uint256& relatedTxHash) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
void PeerAskPeersForTransaction(const uint256& txid) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
size_t PeerGetRequestedObjectCount(NodeId nodeid) const override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
Copy link

@coderabbitai coderabbitai bot Nov 25, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix missing cs_main lock in PeerGetRequestedObjectCount wrapper

GetRequestedObjectCount asserts cs_main and reads m_node_states (GUARDED_BY(cs_main)), but PeerGetRequestedObjectCount calls it without taking cs_main, which will:

  • Trip AssertLockHeld(cs_main) in debug builds.
  • Cause a data race on m_node_states in release builds.

Wrap the call in a cs_main lock (and keep the !m_peer_mutex precondition to preserve lock order), e.g.:

 size_t PeerManagerImpl::PeerGetRequestedObjectCount(NodeId nodeid) const
 {
-    return GetRequestedObjectCount(nodeid);
+    WITH_LOCK(cs_main, return GetRequestedObjectCount(nodeid));
 }

This aligns the wrapper with the callee’s locking contract.

Also applies to: 1650-1658, 6574-6577

🤖 Prompt for AI Agents
In src/net_processing.cpp around line 661 (and similarly at 1650-1658 and
6574-6577), the PeerGetRequestedObjectCount wrapper calls
GetRequestedObjectCount without holding cs_main even though
GetRequestedObjectCount asserts cs_main and reads m_node_states
(GUARDED_BY(cs_main)); update each wrapper to acquire cs_main while preserving
the existing !m_peer_mutex precondition/lock ordering, call
GetRequestedObjectCount while cs_main is held, then release cs_main before
returning so the wrapper satisfies the callee’s locking contract and avoids
assert/data-race.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

cs_main is hold correctly, see:

        WITH_LOCK(::cs_main, m_peer_manager->PeerEraseObjectRequest(peer.GetId(), CInv{MSG_GOVERNANCE_OBJECT, nHash}));

Annotation exists also:

    void PeerEraseObjectRequest(const NodeId nodeid, const CInv& inv) override EXCLUSIVE_LOCKS_REQUIRED(::cs_main);

Copy link

Choose a reason for hiding this comment

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

@knst Thanks for the clarification — agreed on PeerEraseObjectRequest: it’s annotated EXCLUSIVE_LOCKS_REQUIRED(::cs_main) and the call site holds cs_main.

The concern I raised is specifically about PeerGetRequestedObjectCount. Its interface is only EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex), but it calls GetRequestedObjectCount(), which asserts cs_main and reads m_node_states (GUARDED_BY(cs_main)). Since callers of PeerGetRequestedObjectCount are not required to hold cs_main, this can trip the AssertLockHeld(cs_main) in debug or race in release.

Minimal, safe fix (preserves the existing precondition and lock ordering):

diff --git a/src/net_processing.cpp b/src/net_processing.cpp
@@
 size_t PeerManagerImpl::PeerGetRequestedObjectCount(NodeId nodeid) const
 {
-    return GetRequestedObjectCount(nodeid);
+    // Wrapper does not require cs_main; the callee asserts cs_main.
+    // Take cs_main here to satisfy the callee’s locking contract while keeping
+    // the !m_peer_mutex precondition and lock order intact.
+    WITH_LOCK(::cs_main, return GetRequestedObjectCount(nodeid));
 }

If you prefer the alternative of making cs_main an explicit requirement for the wrapper, we can also tighten the annotation in the interface to EXCLUSIVE_LOCKS_REQUIRED(::cs_main, !m_peer_mutex) and adjust call sites accordingly. Let me know which direction you’d like; I can update the patch.


🧠 Learnings used
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 access operations (m_sock and m_server) should be protected by the cs_net mutex, not avoiding synchronization entirely. While lock overhead concerns are valid in general, socket operations require proper synchronization via cs_net.

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().

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

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 (4)
src/governance/net_governance.cpp (3)

20-20: Redundant forward declaration.

CConnman is already included transitively through the headers. This forward declaration is unnecessary.

-class CConnman;
-
 void NetGovernance::Schedule(CScheduler& scheduler, CConnman& connman)

131-132: Typo: "to early" should be "too early".

-            // to early to ask the same node
+            // too early to ask the same node
             if (mapAskedRecently[nHashGovobj].count(pnode->addr)) continue;

154-171: Static local variables limit testability.

The static variables (nTick, nSyncStart, strAllow, nTimeLastProcess) persist across calls and would be shared if multiple NetGovernance instances existed. This limits unit test isolation.

Consider promoting these to member variables in a follow-up PR to improve testability, though this is acceptable for a refactoring PR focused on code movement.

src/governance/governance.cpp (1)

183-231: Consider adding lock assertion for clarity.

The method is declared with EXCLUSIVE_LOCKS_REQUIRED(::cs_main, ...) and is correctly called with cs_main held in NetGovernance::ProcessMessage. However, adding an explicit assertion at the method entry would make the requirement self-documenting and catch misuse earlier (before the assertion in AddGovernanceObjectInternal).

 bool CGovernanceManager::ProcessObject(const CNode& peer, const uint256& nHash, CGovernanceObject govobj)
 {
+    AssertLockHeld(::cs_main);
     std::string strHash = nHash.ToString();

     LOCK(cs_store);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dc1d437 and 094a3f6.

📒 Files selected for processing (4)
  • src/governance/governance.cpp (9 hunks)
  • src/governance/governance.h (1 hunks)
  • src/governance/net_governance.cpp (1 hunks)
  • src/governance/net_governance.h (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
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/governance/net_governance.cpp
  • src/governance/net_governance.h
  • src/governance/governance.cpp
  • src/governance/governance.h
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/governance/net_governance.cpp
  • src/governance/net_governance.h
  • src/governance/governance.cpp
  • src/governance/governance.h
src/governance/**/*.{cpp,h}

📄 CodeRabbit inference engine (CLAUDE.md)

Governance implementation must support governance objects (proposals, triggers, superblock management) and on-chain voting with tallying

Files:

  • src/governance/net_governance.cpp
  • src/governance/net_governance.h
  • src/governance/governance.cpp
  • src/governance/governance.h
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/governance/net_governance.cpp
  • src/governance/net_governance.h
  • src/governance/governance.cpp
  • src/governance/governance.h
🧠 Learnings (12)
📓 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: 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: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: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/governance/**/*.{cpp,h} : Governance implementation must support governance objects (proposals, triggers, superblock management) and on-chain voting with tallying
📚 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/governance/**/*.{cpp,h} : Governance implementation must support governance objects (proposals, triggers, superblock management) and on-chain voting with tallying

Applied to files:

  • src/governance/net_governance.cpp
  • src/governance/net_governance.h
  • src/governance/governance.cpp
  • src/governance/governance.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/governance/net_governance.cpp
  • src/governance/governance.cpp
  • src/governance/governance.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/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/governance/governance.cpp
  • src/governance/governance.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/governance/governance.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/{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/governance/governance.cpp
📚 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:

  • src/governance/governance.cpp
📚 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 PR #6849, `cmapVoteToObject` was intentionally moved from `GovernanceStore` to `CGovernanceManager` as a memory-only variable and is NOT guarded by `cs_store`. It relies on `CacheMap`'s internal thread-safety instead.

Applied to files:

  • src/governance/governance.cpp
  • src/governance/governance.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/governance/governance.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,llmq,governance,coinjoin}/**/*.{cpp,h} : Use Dash-specific database implementations: CFlatDB for persistent storage (MasternodeMetaStore, GovernanceStore, SporkStore, NetFulfilledRequestStore) and CDBWrapper extensions for Evolution/DKG/InstantSend/Quorum/RecoveredSigs data

Applied to files:

  • src/governance/governance.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/governance/governance.h
📚 Learning: 2025-11-04T18:23:28.175Z
Learnt from: UdjinM6
Repo: dashpay/dash PR: 6933
File: src/governance/classes.cpp:147-154
Timestamp: 2025-11-04T18:23:28.175Z
Learning: In src/governance/classes.cpp, CSuperblock::GetPaymentsLimit intentionally uses synthetic difficulty constants (nBits = 1 for mainnet, powLimit for networks with min difficulty) and simple height-based V20 activation checks instead of actual chain block data. This is by design because superblocks themselves are "synthetic" governance payment blocks, not regular mined blocks.

Applied to files:

  • src/governance/governance.h
🧬 Code graph analysis (3)
src/governance/net_governance.h (4)
src/governance/governance.cpp (2)
  • CGovernanceManager (66-79)
  • CGovernanceManager (81-85)
src/masternode/sync.cpp (4)
  • CMasternodeSync (14-20)
  • CMasternodeSync (22-22)
  • ProcessMessage (99-112)
  • ProcessMessage (99-99)
src/net_processing.h (3)
  • NetHandler (71-87)
  • NetHandler (75-78)
  • PeerManagerInternal (58-69)
src/governance/net_governance.cpp (10)
  • Schedule (22-54)
  • Schedule (22-22)
  • ProcessMessage (345-449)
  • ProcessMessage (345-345)
  • SendGovernanceSyncRequest (56-61)
  • SendGovernanceSyncRequest (56-56)
  • RequestGovernanceObjectVotes (63-152)
  • RequestGovernanceObjectVotes (63-63)
  • ProcessTick (154-343)
  • ProcessTick (154-154)
src/governance/governance.cpp (2)
src/governance/governance.h (1)
  • nCachedBlockHeight (261-261)
src/coinjoin/client.h (1)
  • nCachedBlockHeight (264-264)
src/governance/governance.h (2)
src/governance/governance.cpp (10)
  • FetchRelayInventory (449-455)
  • FetchRelayInventory (449-449)
  • AcceptMessage (993-1005)
  • AcceptMessage (993-993)
  • ProcessObject (183-231)
  • ProcessObject (183-183)
  • GetMNManager (960-960)
  • GetMNManager (960-960)
  • ProcessVote (800-858)
  • ProcessVote (800-800)
src/governance/object.cpp (2)
  • ProcessVote (58-159)
  • ProcessVote (58-59)
⏰ 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). (7)
  • GitHub Check: linux64_tsan-build / Build source
  • GitHub Check: x86_64-apple-darwin / Build depends
  • GitHub Check: Lint / Run linters
  • GitHub Check: x86_64-w64-mingw32 / Build depends
  • GitHub Check: x86_64-pc-linux-gnu_nowallet / Build depends
  • GitHub Check: x86_64-pc-linux-gnu / Build depends
  • GitHub Check: arm-linux-gnueabihf / Build depends
🔇 Additional comments (6)
src/governance/net_governance.h (1)

14-37: Clean NetHandler implementation for governance networking.

The NetGovernance class properly derives from NetHandler and follows the established pattern for network handlers. The dependency injection via constructor references is appropriate, and the interface is well-defined.

src/governance/net_governance.cpp (2)

22-54: Well-structured scheduling with appropriate guards.

The scheduling logic properly:

  • Checks ShutdownRequested() before processing ticks
  • Conditionally schedules housekeeping only when governance is valid
  • Uses different timing for test vs. production networks

345-448: Governance message handling properly migrated.

The ProcessMessage method correctly handles all three governance message types with appropriate validation and peer misbehavior scoring. The ProcessObject call at line 393 properly acquires cs_main via WITH_LOCK as required by the method's lock annotations.

src/governance/governance.cpp (2)

449-455: Efficient swap-based inventory transfer.

Using swap to transfer the relay inventory avoids unnecessary copying while atomically clearing the source vector under the lock.


1174-1188: Good addition of orphan vote cleanup.

The orphan vote cleanup properly removes expired entries before requesting objects, preventing accumulation of stale data. The iterator handling correctly saves the current position before advancing.

src/governance/governance.h (1)

367-388: Well-organized public API expansion for NetGovernance.

The new public methods are properly grouped with a clarifying comment and have consistent lock annotations that match their implementations. The separation of governance networking concerns into NetGovernance while exposing necessary accessors maintains good encapsulation.

knst added 16 commits November 25, 2025 21:35
It is used to show this warning:

    Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index.

New message is shown in this situation now; behavior is changed by forcing disabling governance:

    Warning: You are starting with governance validation disabled.
…uestOrphanObjects

It helps to manage amount of public methods of CGovernanceManager
…relevant code to NetGovernance

Please note that circular dependency masternode/sync -> net -> masternode/sync existed for a long time,
it's not newly introduced
@knst knst force-pushed the refactor-peermanager-handlers-gov branch from 094a3f6 to a5ef0da Compare November 25, 2025 14:35
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: 2

🧹 Nitpick comments (3)
src/governance/governance.cpp (1)

183-231: Clarify locking expectations for ProcessObject (cs_main precondition).

ProcessObject assumes ::cs_main is held by the caller (as done in NetGovernance::ProcessMessage via WITH_LOCK(::cs_main, ...)) but only locks cs_store locally. This works with current call sites and keeps AddGovernanceObjectInternal’s lock assertions satisfied, but nothing in this method enforces the cs_main precondition.

To future‑proof against accidental misuse, consider adding an AssertLockHeld(::cs_main); at the top of ProcessObject and documenting that it must be called with cs_main held. Behavior stays identical, but incorrect future call sites will fail fast in debug builds.

src/instantsend/net_instantsend.cpp (1)

17-65: ProcessMessage signature alignment looks good.

Updating NetInstantSend::ProcessMessage to take CConnman& matches the new NetHandler interface and PeerManager dispatch. The unused parameter is fine; if compiler warnings become noisy, you can mark it [[maybe_unused]] or name it and (void)connman;, but that’s optional.

src/governance/governance.h (1)

389-390: Minor: Extra blank line.

There's an extra blank line before the private: section that could be removed for consistency.

     bool ProcessVote(CNode* pfrom, const CGovernanceVote& vote, CGovernanceException& exception, CConnman& connman)
         EXCLUSIVE_LOCKS_REQUIRED(!cs_store);

-
 private:
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 094a3f6 and a5ef0da.

📒 Files selected for processing (17)
  • src/Makefile.am (2 hunks)
  • src/governance/governance.cpp (9 hunks)
  • src/governance/governance.h (1 hunks)
  • src/governance/net_governance.cpp (1 hunks)
  • src/governance/net_governance.h (1 hunks)
  • src/init.cpp (3 hunks)
  • src/instantsend/net_instantsend.cpp (1 hunks)
  • src/instantsend/net_instantsend.h (1 hunks)
  • src/masternode/sync.cpp (1 hunks)
  • src/masternode/sync.h (2 hunks)
  • src/net_processing.cpp (5 hunks)
  • src/net_processing.h (3 hunks)
  • src/node/chainstate.cpp (0 hunks)
  • src/node/chainstate.h (0 hunks)
  • src/test/util/setup_common.cpp (0 hunks)
  • src/validation.h (0 hunks)
  • test/lint/lint-circular-dependencies.py (2 hunks)
💤 Files with no reviewable changes (4)
  • src/node/chainstate.cpp
  • src/node/chainstate.h
  • src/test/util/setup_common.cpp
  • src/validation.h
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/instantsend/net_instantsend.h
  • src/Makefile.am
  • src/masternode/sync.cpp
🧰 Additional context used
📓 Path-based instructions (6)
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/net_processing.h
  • src/instantsend/net_instantsend.cpp
  • src/governance/net_governance.h
  • src/governance/net_governance.cpp
  • src/init.cpp
  • src/governance/governance.cpp
  • src/governance/governance.h
  • src/masternode/sync.h
  • src/net_processing.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/governance/net_governance.h
  • src/governance/net_governance.cpp
  • src/governance/governance.cpp
  • src/governance/governance.h
  • src/masternode/sync.h
src/governance/**/*.{cpp,h}

📄 CodeRabbit inference engine (CLAUDE.md)

Governance implementation must support governance objects (proposals, triggers, superblock management) and on-chain voting with tallying

Files:

  • src/governance/net_governance.h
  • src/governance/net_governance.cpp
  • src/governance/governance.cpp
  • src/governance/governance.h
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/governance/net_governance.h
  • src/governance/net_governance.cpp
  • src/governance/governance.cpp
  • src/governance/governance.h
  • src/masternode/sync.h
src/{masternode,evo}/**/*.{cpp,h}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • src/masternode/sync.h
src/{masternode,llmq}/**/*.{cpp,h}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • src/masternode/sync.h
🧠 Learnings (30)
📓 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: 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: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: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/governance/**/*.{cpp,h} : Governance implementation must support governance objects (proposals, triggers, superblock management) and on-chain voting with tallying
📚 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_processing.h
  • src/governance/net_governance.cpp
  • src/governance/governance.cpp
  • src/governance/governance.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/instantsend/net_instantsend.cpp
📚 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/instantsend/net_instantsend.cpp
📚 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/instantsend/net_instantsend.cpp
  • src/governance/governance.h
  • src/net_processing.cpp
📚 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/instantsend/net_instantsend.cpp
📚 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/instantsend/net_instantsend.cpp
📚 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 access operations (m_sock and m_server) should be protected by the cs_net mutex, not avoiding synchronization entirely. While lock overhead concerns are valid in general, socket operations require proper synchronization via cs_net.

Applied to files:

  • src/instantsend/net_instantsend.cpp
  • src/net_processing.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/governance/**/*.{cpp,h} : Governance implementation must support governance objects (proposals, triggers, superblock management) and on-chain voting with tallying

Applied to files:

  • src/governance/net_governance.h
  • src/governance/net_governance.cpp
  • src/init.cpp
  • src/governance/governance.cpp
  • src/governance/governance.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/node/chainstate.{cpp,h} : Chainstate initialization must be separated into dedicated src/node/chainstate.* files

Applied to files:

  • src/init.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/init.cpp
  • src/governance/governance.cpp
  • src/governance/governance.h
  • src/masternode/sync.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,llmq,governance,coinjoin}/**/*.{cpp,h} : Use Dash-specific database implementations: CFlatDB for persistent storage (MasternodeMetaStore, GovernanceStore, SporkStore, NetFulfilledRequestStore) and CDBWrapper extensions for Evolution/DKG/InstantSend/Quorum/RecoveredSigs data

Applied to files:

  • src/init.cpp
  • src/governance/governance.h
  • src/masternode/sync.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/evo/**/*.{cpp,h} : Special transactions use payload serialization routines defined in src/evo/specialtx.h and must include appropriate special transaction types (ProRegTx, ProUpServTx, ProUpRegTx, ProUpRevTx)

Applied to files:

  • src/init.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}/**/*.{cpp,h} : BLS integration must be used for cryptographic foundation of advanced masternode features

Applied to files:

  • src/init.cpp
  • src/governance/governance.cpp
  • src/masternode/sync.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/init.cpp
📚 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:

  • src/init.cpp
  • src/governance/governance.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/{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/governance/governance.cpp
  • src/masternode/sync.h
📚 Learning: 2025-11-25T10:53:37.523Z
Learnt from: knst
Repo: dashpay/dash PR: 7008
File: src/masternode/sync.h:17-18
Timestamp: 2025-11-25T10:53:37.523Z
Learning: The file src/masternode/sync.h containing `CMasternodeSync` is misnamed and misplaced—it has nothing to do with "masternode" functionality. It should eventually be renamed to `NodeSyncing` or `NodeSyncStatus` and moved to src/node/sync.h as a future refactoring.

Applied to files:

  • src/governance/governance.cpp
  • src/masternode/sync.h
📚 Learning: 2025-11-25T10:53:37.523Z
Learnt from: knst
Repo: dashpay/dash PR: 7008
File: src/masternode/sync.h:17-18
Timestamp: 2025-11-25T10:53:37.523Z
Learning: In Dash Core, `DEFAULT_SYNC_MEMPOOL` belongs with node synchronization logic (currently in src/masternode/sync.h) rather than with validation logic in src/validation.h, even though other mempool-related constants are in validation.h. The constant is conceptually tied to sync functionality, not validation.

Applied to files:

  • src/governance/governance.cpp
  • src/masternode/sync.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 PR #6849, `cmapVoteToObject` was intentionally moved from `GovernanceStore` to `CGovernanceManager` as a memory-only variable and is NOT guarded by `cs_store`. It relies on `CacheMap`'s internal thread-safety instead.

Applied to files:

  • src/governance/governance.cpp
  • src/governance/governance.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/governance/governance.h
📚 Learning: 2025-11-04T18:23:28.175Z
Learnt from: UdjinM6
Repo: dashpay/dash PR: 6933
File: src/governance/classes.cpp:147-154
Timestamp: 2025-11-04T18:23:28.175Z
Learning: In src/governance/classes.cpp, CSuperblock::GetPaymentsLimit intentionally uses synthetic difficulty constants (nBits = 1 for mainnet, powLimit for networks with min difficulty) and simple height-based V20 activation checks instead of actual chain block data. This is by design because superblocks themselves are "synthetic" governance payment blocks, not regular mined blocks.

Applied to files:

  • src/governance/governance.h
  • src/masternode/sync.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/masternode/sync.h
  • src/net_processing.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:

  • src/masternode/sync.h
  • src/net_processing.cpp
📚 Learning: 2025-10-05T20:38:28.457Z
Learnt from: knst
Repo: dashpay/dash PR: 6871
File: contrib/guix/libexec/build.sh:358-360
Timestamp: 2025-10-05T20:38:28.457Z
Learning: In the Dash repository, when backporting code from Bitcoin Core, typos and minor issues in comments should be kept as-is to reduce merge conflicts in future backports, even if they remain unfixed in Bitcoin Core's master branch.

Applied to files:

  • src/masternode/sync.h
📚 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/masternode/sync.h
  • src/net_processing.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/masternode/sync.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/masternode/sync.h
📚 Learning: 2025-08-19T14:57:31.801Z
Learnt from: knst
Repo: dashpay/dash PR: 6692
File: src/llmq/blockprocessor.cpp:217-224
Timestamp: 2025-08-19T14:57:31.801Z
Learning: In PR #6692, knst acknowledged a null pointer dereference issue in ProcessBlock() method where LookupBlockIndex may return nullptr but is passed to gsl::not_null, and created follow-up PR #6789 to address it, consistent with avoiding scope creep in performance-focused PRs.

Applied to files:

  • src/net_processing.cpp
📚 Learning: 2025-07-29T14:33:01.040Z
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.

Applied to files:

  • src/net_processing.cpp
🧬 Code graph analysis (7)
src/net_processing.h (1)
src/net_processing.cpp (36)
  • PeerGetRequestedObjectCount (6574-6577)
  • PeerGetRequestedObjectCount (6574-6574)
  • nodeid (628-628)
  • nodeid (631-631)
  • nodeid (644-644)
  • nodeid (656-656)
  • nodeid (661-661)
  • nodeid (679-679)
  • nodeid (681-681)
  • nodeid (719-720)
  • nodeid (730-730)
  • nodeid (862-862)
  • nodeid (864-864)
  • nodeid (1040-1040)
  • nodeid (1075-1075)
  • PeerPostProcessMessage (6579-6582)
  • PeerPostProcessMessage (6579-6579)
  • ret (662-662)
  • ret (685-685)
  • scheduler (624-624)
  • scheduler (652-652)
  • scheduler (694-694)
  • ProcessMessage (3681-5471)
  • ProcessMessage (3681-3686)
  • pfrom (618-618)
  • pfrom (639-640)
  • pfrom (753-755)
  • pfrom (764-764)
  • pfrom (772-772)
  • pfrom (775-775)
  • pfrom (777-777)
  • pfrom (779-779)
  • pfrom (875-875)
  • pfrom (1057-1057)
  • ScheduleHandlers (1701-1706)
  • ScheduleHandlers (1701-1701)
src/instantsend/net_instantsend.cpp (1)
src/net_processing.cpp (12)
  • ProcessMessage (3681-5471)
  • ProcessMessage (3681-3686)
  • pfrom (618-618)
  • pfrom (639-640)
  • pfrom (753-755)
  • pfrom (764-764)
  • pfrom (772-772)
  • pfrom (775-775)
  • pfrom (777-777)
  • pfrom (779-779)
  • pfrom (875-875)
  • pfrom (1057-1057)
src/governance/net_governance.h (2)
src/net_processing.h (3)
  • NetHandler (71-87)
  • NetHandler (75-78)
  • PeerManagerInternal (58-69)
src/governance/net_governance.cpp (10)
  • Schedule (22-54)
  • Schedule (22-22)
  • ProcessMessage (345-449)
  • ProcessMessage (345-345)
  • SendGovernanceSyncRequest (56-61)
  • SendGovernanceSyncRequest (56-56)
  • RequestGovernanceObjectVotes (63-152)
  • RequestGovernanceObjectVotes (63-63)
  • ProcessTick (154-343)
  • ProcessTick (154-154)
src/governance/net_governance.cpp (1)
src/net.h (1)
  • FullyConnectedOnly (1296-1296)
src/init.cpp (5)
src/net_processing.cpp (10)
  • node (616-616)
  • node (617-617)
  • node (642-642)
  • node (757-757)
  • node (792-792)
  • node (892-896)
  • node (907-907)
  • node (918-918)
  • node (929-929)
  • node (937-937)
src/interfaces/node.h (2)
  • node (42-44)
  • node (404-404)
src/kernel/coinstats.h (1)
  • node (19-21)
src/rpc/blockchain.h (1)
  • node (33-36)
src/init.h (1)
  • node (23-25)
src/governance/governance.cpp (1)
src/governance/governance.h (1)
  • nCachedBlockHeight (261-261)
src/masternode/sync.h (1)
src/masternode/sync.cpp (6)
  • BumpAssetLastTime (43-48)
  • BumpAssetLastTime (43-43)
  • GetAssetName (50-59)
  • GetAssetName (50-50)
  • GetSyncStatus (89-97)
  • GetSyncStatus (89-89)
🔇 Additional comments (15)
src/net_processing.h (1)

58-69: Handler and peer APIs are consistent with the new scheduling/message flow.

The additions to PeerManagerInternal (PeerGetRequestedObjectCount, PeerPostProcessMessage), NetHandler (Schedule, ProcessMessage with CConnman&), and PeerManager::ScheduleHandlers match the pattern implemented in PeerManagerImpl and used by NetGovernance/NetInstantSend. The abstractions keep network plumbing inside PeerManager while letting individual handlers own their scheduling and message handling.

Also applies to: 71-87, 155-175

src/governance/net_governance.h (1)

14-37: NetGovernance handler design matches the refactoring goal.

NetGovernance encapsulates governance P2P logic behind the generic NetHandler interface and is wired via constructor injection into the existing managers, which is exactly what’s needed to decouple governance consensus state from PeerManager. The Schedule / ProcessMessage overrides match the base class and the implementation in net_governance.cpp.

src/init.cpp (2)

88-92: NetGovernance attachment and gating look correct.

NetGovernance is always added as an extra handler, but is_governance_enabled is still respected by only loading the governance cache when enabled, and the handler’s implementation guards work on m_gov_manager.IsValid() / sync state. That keeps the wiring simple in init.cpp while avoiding governance network activity (and DB usage) when validation is disabled.

Also applies to: 1690-1691, 2212-2229


2292-2302: Scheduler integration via ScheduleHandlers is a clean generalization.

Calling node.peerman->ScheduleHandlers(*node.scheduler); after registering all handlers (InstantSend, NetGovernance, etc.) centralizes their periodic work (governance cleanup, orphan requests, relay batching, etc.) behind the NetHandler abstraction instead of hard-coding per-subsystem schedule blocks in init.cpp. The order relative to LLQM/masternode scheduling and the shutdown sequence is consistent with existing patterns.

test/lint/lint-circular-dependencies.py (1)

41-53: Updated circular-dependency expectations are consistent with the new handler wiring.

The added cycles capturing core_io → evo/mnhftx → llmq/signing → net_processing → governance/* → core_io and masternode/sync → net → masternode/sync reflect the new NetGovernance/handler paths and sync wiring without changing the linter logic. The whitelist stays aligned with the current architecture.

src/masternode/sync.h (1)

17-18: Sync constants and CMasternodeSync accessors are consistent with current design.

Defining DEFAULT_SYNC_MEMPOOL alongside other sync-related constants and exposing BumpAttempt(), GetLastBump(), and IsReachedBestHeader() mirrors the existing implementation in sync.cpp and keeps node-sync status queryable without changing behavior. Placement of the constant here matches the intended association with node synchronization rather than validation.

Also applies to: 65-74

src/governance/governance.cpp (1)

449-455: LGTM on new relay/vote fetch helpers and orphan‑vote cleanup.

  • FetchRelayInventory() correctly batches and drains m_relay_invs under cs_relay, called within scheduler-driven relay path in NetGovernance.
  • FetchGovernanceObjectVotes() safely co-operates with external NetGovernance code by cleaning expired mapAskedRecently entries using the advance-then-erase pattern while holding cs_store, and honoring nPeersPerHashMax before processing objects.
  • RequestOrphanObjects()'s pruning loop over cmmapOrphanVotes.GetItemList() correctly removes expired orphan votes using the advance-then-erase pattern to avoid iterator invalidation before requesting.

These changes improve separation between network handler code and governance state while maintaining scheduler-driven, network-decoupled voting architecture, without altering consensus behavior.

src/governance/net_governance.cpp (4)

22-54: Scheduler setup looks good; consider lifetime assumptions of captured references

The three scheduled tasks mirror the expected 1s tick plus slower housekeeping and relay pacing, and the IsValid() gate on the heavier governance maintenance/relay work makes sense.

One thing to double‑check: this and &connman are captured by reference in lambdas that may outlive NetGovernance if shutdown/teardown ordering ever changes. If Schedule is called once at init and NetGovernance/CConnman both live until scheduler shutdown, this is fine; if not, you may want a stop hook or a weak/indirection pattern.


56-61: Governance sync request wiring is straightforward

SendGovernanceSyncRequest’s construction of MNGOVERNANCESYNC with an empty Bloom filter and a zero hash matches the expectations in ProcessMessage and keeps the wire encoding simple. No issues here.


63-152: Vote request throttling and per‑hash/per‑peer limits look consistent

The logic in RequestGovernanceObjectVotes (per‑hash peer caps, projected vote count limit per peer, MAX_INV_SZ guard, and static mapAskedRecently with a mutex) is coherent and appears to preserve the intended behavior of avoiding bandwidth explosions while still stressing non‑main networks more heavily.

Assuming FetchGovernanceObjectVotes is responsible for aging out mapAskedRecently entries based on nNow and nTimeout, this design should remain bounded over long uptimes. If that assumption changed in the refactor, it’s worth confirming to avoid unbounded growth of mapAskedRecently.


345-449: ProcessMessage refactor preserves structure; minor duplication only

The three branches for MNGOVERNANCESYNC, MNGOVERNANCEOBJECT, and MNGOVERNANCEOBJECTVOTE look like a direct lift from the old governance message handler, with the right hand‑offs to CGovernanceManager and PeerManager and appropriate sync gating and misbehavior scoring.

There is some duplicated IsBlockchainSynced() checking (top of function plus inside the object/vote branches), but that’s harmless and may even be desirable given the concurrency between sync and net threads. No changes needed here.

src/net_processing.cpp (3)

652-652: NetHandler scheduling hook looks sound

ScheduleHandlers cleanly iterates m_handlers and delegates to handler->Schedule(scheduler, m_connman), matching the new interface and keeping scheduling centralized in PeerManagerImpl. No locking is needed as long as m_handlers is configured only during init/shutdown, which matches existing AddExtraHandler/RemoveHandlers usage.

Also applies to: 1701-1706


661-661: Locking contract for PeerGetRequestedObjectCount now matches internal state access

Requiring both !m_peer_mutex and ::cs_main on PeerGetRequestedObjectCount aligns the wrapper with GetRequestedObjectCount and the m_node_states (GUARDED_BY(cs_main)) access. The wrapper’s implementation is a straight passthrough, which is correct given the updated precondition; callers just need to ensure they now hold cs_main when using the peer-facing variant.

Also applies to: 1650-1659, 6574-6577


5461-5463: Passing CConnman& into NetHandlers is appropriate

Updating the NetHandler dispatch to handler->ProcessMessage(pfrom, m_connman, msg_type, vRecv); matches the expanded handler API and keeps all P2P sends/connection operations going through the shared CConnman instance. This is consistent with the refactoring goal of separating network orchestration from handler logic.

src/governance/governance.h (1)

367-388: Well-structured API boundary for the network/consensus separation.

The new "Used by NetGovernance" section clearly delineates the methods needed by the new NetGovernance handler. Lock annotations are consistently applied:

  • cs_relay for relay inventory operations
  • cs_store for governance object/vote storage operations
  • cs_main appropriately added to ProcessObject for chain-state access

The design correctly exposes data-fetching methods (FetchRelayInventory, FetchGovernanceObjectVotes) and processing entry points (ProcessObject, ProcessVote) that allow NetGovernance to handle network messaging while CGovernanceManager focuses on consensus logic.

GetMNManager() (line 385) returning a reference without lock annotations is correct since m_dmnman is a const member initialized at construction.

Comment on lines +246 to +257
if (gArgs.GetBoolArg("-syncmempool", DEFAULT_SYNC_MEMPOOL)) {
// Now that the blockchain is synced request the mempool from the connected outbound nodes if possible
for (auto pNodeTmp : snap.Nodes()) {
bool fRequestedEarlier = m_netfulfilledman.HasFulfilledRequest(pNodeTmp->addr,
"mempool-sync");
if (!pNodeTmp->IsInboundConn() && !fRequestedEarlier && !pNodeTmp->IsBlockRelayOnly()) {
m_netfulfilledman.AddFulfilledRequest(pNodeTmp->addr, "mempool-sync");
connman.PushMessage(pNodeTmp, msgMaker.Make(NetMsgType::MEMPOOL));
LogPrint(BCLog::MNSYNC, /* Continued */
"Sync Tick -- nTick %d asset_id %d -- syncing mempool from peer=%d\n", nTick,
asset_id, pNodeTmp->GetId());
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

BUG: MEMPOOL sync uses CNetMsgMaker from the wrong peer

In the mempool sync block you send MEMPOOL to pNodeTmp using a CNetMsgMaker constructed from pnode->GetCommonVersion():

CNetMsgMaker msgMaker(pnode->GetCommonVersion());
// ...
for (auto pNodeTmp : snap.Nodes()) {
    // ...
    connman.PushMessage(pNodeTmp, msgMaker.Make(NetMsgType::MEMPOOL));
}

CNetMsgMaker bakes in the per‑peer protocol version; reusing a maker built for one peer when sending to another is incorrect and can lead to mismatched serialization if peers negotiate different versions.

You should construct the message maker using pNodeTmp’s negotiated version instead:

-                        for (auto pNodeTmp : snap.Nodes()) {
+                        for (auto pNodeTmp : snap.Nodes()) {
                             bool fRequestedEarlier = m_netfulfilledman.HasFulfilledRequest(pNodeTmp->addr,
                                                                                            "mempool-sync");
                             if (!pNodeTmp->IsInboundConn() && !fRequestedEarlier && !pNodeTmp->IsBlockRelayOnly()) {
                                 m_netfulfilledman.AddFulfilledRequest(pNodeTmp->addr, "mempool-sync");
-                                connman.PushMessage(pNodeTmp, msgMaker.Make(NetMsgType::MEMPOOL));
+                                CNetMsgMaker mempoolMsgMaker(pNodeTmp->GetCommonVersion());
+                                connman.PushMessage(pNodeTmp, mempoolMsgMaker.Make(NetMsgType::MEMPOOL));
                                 LogPrint(BCLog::MNSYNC, /* Continued */
                                          "Sync Tick -- nTick %d asset_id %d -- syncing mempool from peer=%d\n", nTick,
                                          asset_id, pNodeTmp->GetId());
                             }
                         }

This keeps behavior aligned with the rest of the codebase, where messages are always serialized with the destination peer’s own common version.

🤖 Prompt for AI Agents
In src/governance/net_governance.cpp around lines 246-257, the MEMPOOL message
is being created with a CNetMsgMaker built from the wrong peer (pnode) which
bakes in an incorrect protocol version; fix it by constructing the CNetMsgMaker
with the destination peer's negotiated version (pNodeTmp->GetCommonVersion())
when sending inside the loop (i.e. create a msgMaker per pNodeTmp or call
CNetMsgMaker(pNodeTmp->GetCommonVersion()) before connman.PushMessage), so each
MEMPOOL message is serialized using the target peer's common version.

void PeerRelayInvFiltered(const CInv& inv, const uint256& relatedTxHash) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
void PeerAskPeersForTransaction(const uint256& txid) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
size_t PeerGetRequestedObjectCount(NodeId nodeid) const override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, ::cs_main);
void PeerPostProcessMessage(MessageProcessingResult&& ret) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

PeerPostProcessMessage drops peer context, disabling misbehavior and request cleanup

PeerPostProcessMessage currently forwards to:

void PeerManagerImpl::PeerPostProcessMessage(MessageProcessingResult&& ret)
{
    PostProcessMessage(std::move(ret), -1);
}

PostProcessMessage uses the node argument to:

  • Attribute m_error to a specific peer via Misbehaving(node, ...).
  • Call EraseObjectRequest(node, ...) under cs_main.

Passing -1 means any m_error or m_to_erase set by callers of PeerPostProcessMessage will be silently ignored: Misbehaving(-1, ...) and EraseObjectRequest(-1, ...) won’t find a peer/state entry. Only m_transactions, m_inventory, and m_dsq are effective.

If NetHandlers are expected to use PeerPostProcessMessage with a real per-peer MessageProcessingResult (which the name strongly suggests), this will undercut DoS accounting and object-request bookkeeping for those subsystems.

Consider tightening this by threading the actual NodeId through the interface, e.g.:

-void PeerPostProcessMessage(MessageProcessingResult&& ret) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
+void PeerPostProcessMessage(MessageProcessingResult&& ret, NodeId node) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);

and

-void PeerManagerImpl::PeerPostProcessMessage(MessageProcessingResult&& ret)
-{
-    PostProcessMessage(std::move(ret), -1);
-}
+void PeerManagerImpl::PeerPostProcessMessage(MessageProcessingResult&& ret, NodeId node)
+{
+    PostProcessMessage(std::move(ret), node);
+}

with corresponding updates to PeerManagerInternal and NetGovernance (or other) call sites so they pass pfrom.GetId() when there is a peer context, and only use -1 explicitly in the rare cases where there truly is none.

Also applies to: 3587-3604, 6579-6582

🤖 Prompt for AI Agents
In src/net_processing.cpp around line 662 (and similarly at 3587-3604 and
6579-6582), PeerPostProcessMessage currently calls PostProcessMessage with -1
which drops peer context and prevents Misbehaving(...) and
EraseObjectRequest(...) from attributing errors/cleanup to the correct peer;
change the PeerPostProcessMessage signature to accept a NodeId (or int node) and
forward that node to PostProcessMessage instead of -1, update the
PeerManagerInternal and NetGovernance (and any other callers) to pass
pfrom.GetId() when a peer exists (or -1 only when there truly is no peer), and
update the override/declaration sites accordingly so m_error and m_to_erase are
handled against the correct peer state under cs_main.

@knst
Copy link
Collaborator Author

knst commented Nov 25, 2025

it conflicts with #6992 but conflicts are pretty trivial. Whatever which one will get merged first; 2nd will be rebased on the top.

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