Skip to content

Conversation

@UdjinM6
Copy link

@UdjinM6 UdjinM6 commented Jan 16, 2026

Issue being fixed or feature implemented

Move all network operations from CGovernanceManager to the appropriate network layer classes (SyncManager and NetGovernance).

What was done?

Refactor only, see individual commits

How Has This Been Tested?

Run tests, sync gov data on mainnet node

Breaking Changes

n/a

Checklist:

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

UdjinM6 and others added 2 commits January 16, 2026 12:11
…thods

Replace SyncObjects() and SyncSingleObjVotes() with pure data accessors:
- GetSyncableObjectInvs(): returns inventory of syncable governance objects
- GetSyncableVoteInvs(): returns inventory of syncable votes for an object

Move network message construction (SYNCSTATUSCOUNT) to NetGovernance,
following the established pattern in NetSigning and NetInstantSend.

This improves separation of concerns:
- CGovernanceManager handles data access only
- NetGovernance handles network protocol operations

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Complete separation of network operations from CGovernanceManager by
moving RequestGovernanceObject functionality to the appropriate network
layer classes.

Changes to CGovernanceManager (data access only):
- Add GetVoteBloomFilter() to build bloom filter for sync requests
- Add GetOrphanVoteObjectHashes() to get object hashes for orphan votes
- Modify ProcessVote() to use output param hashToRequest instead of
  doing network operations internally
- Remove RequestGovernanceObject() and RequestOrphanObjects()

Changes to SyncManager:
- Add SendGovernanceObjectSyncRequest() for vote sync requests
- Update RequestGovernanceObjectVotes() to use new method

Changes to NetGovernance:
- Handle orphan vote requests in ProcessMessage() after ProcessVote
- Move RequestOrphanObjects logic into Schedule() for periodic requests

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@UdjinM6 UdjinM6 added this to the 23.1 milestone Jan 16, 2026
@coderabbitai
Copy link

coderabbitai bot commented Jan 16, 2026

Walkthrough

The changes refactor the governance synchronization API by decoupling network operations from data collection. Four network-performing methods are replaced with pure getter/accessor methods: SyncObjects() and SyncSingleObjVotes() become GetSyncableObjectInvs() and GetSyncableVoteInvs(); RequestGovernanceObject() becomes GetVoteBloomFilter(); and RequestOrphanObjects() becomes GetOrphanVoteObjectHashes(). The ProcessVote() interface is extended with an output parameter hashToRequest to decouple vote processing from relay operations. Call sites in net_governance.cpp are updated to invoke these getters and perform network operations independently. A new helper method SendGovernanceObjectSyncRequest() is added to SyncManager to centralize governance object sync requests.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

The refactoring spans five files with heterogeneous changes to public APIs and their call sites. While the changes follow a consistent decoupling pattern, they require careful verification that all callers are updated correctly and that network operations are properly delegated. The moderate logic density involving bloom filters, orphan tracking, and inventory management, combined with the multiple affected components, necessitates detailed review.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'refactor: move all network operations out of CGovernanceManager' directly and clearly summarizes the main change: decoupling network I/O from the governance manager class.
Description check ✅ Passed The description is related to the changeset, explaining the issue (moving network operations), what was done (refactor), and testing approach, though checklist items are incomplete.

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

✨ Finishing touches
  • 📝 Generate docstrings


📜 Recent review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0bbc3a5 and af1ab7f.

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

📄 CodeRabbit inference engine (CLAUDE.md)

NodeContext must be extended with Dash-specific managers for each subsystem during initialization

Files:

  • src/node/sync_manager.h
  • src/node/sync_manager.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.cpp
  • src/governance/governance.h
  • src/governance/governance.cpp
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/governance.h
  • src/governance/governance.cpp
src/{masternode,llmq,evo,coinjoin,governance}/**/*.{cpp,h}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • src/governance/net_governance.cpp
  • src/governance/governance.h
  • src/governance/governance.cpp
🧠 Learnings (13)
📓 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: 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: 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.
📚 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/node/sync_manager.h
  • src/governance/net_governance.cpp
  • src/node/sync_manager.cpp
  • src/governance/governance.h
  • src/governance/governance.cpp
📚 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/node/sync_manager.h
  • src/node/sync_manager.cpp
  • src/governance/governance.cpp
📚 Learning: 2025-12-22T15:42:48.595Z
Learnt from: kwvg
Repo: dashpay/dash PR: 7068
File: src/qt/guiutil_font.h:68-77
Timestamp: 2025-12-22T15:42:48.595Z
Learning: In C++/Qt codebases, use fail-fast asserts in setters to enforce invariants (e.g., ensuring internal maps contain necessary keys). Prefer assert() for programmer errors that should be caught in development and debugging, rather than defensive runtime checks with fallbacks. This helps catch invariant violations early during development. Apply to header and source files where invariant-driven state mutations occur, especially in setters like SetWeightBold/SetWeightNormal that assume established relationships or preconditions.

Applied to files:

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

Applied to files:

  • src/governance/net_governance.cpp
  • src/governance/governance.cpp
📚 Learning: 2025-12-09T20:40:42.286Z
Learnt from: UdjinM6
Repo: dashpay/dash PR: 7051
File: test/functional/feature_governance_cl.py:159-170
Timestamp: 2025-12-09T20:40:42.286Z
Learning: In feature_governance_cl.py, before running governance cleanup with mockscheduler, the test must wait for the governance module to catch up with the latest block height by checking for the "CGovernanceManager::UpdatedBlockTip -- nCachedBlockHeight" log message. This synchronization ensures that subsequent cleanup operations see the correct block height and produce deterministic results (e.g., "CleanAndRemoveTriggers -- Removing trigger object" instead of "NOT marked for removal").

Applied to files:

  • src/governance/net_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.h
  • 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,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/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-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
📚 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.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/governance/governance.cpp
🧬 Code graph analysis (4)
src/node/sync_manager.h (1)
src/node/sync_manager.cpp (2)
  • SendGovernanceObjectSyncRequest (39-49)
  • SendGovernanceObjectSyncRequest (39-39)
src/node/sync_manager.cpp (1)
src/common/bloom.cpp (1)
  • CBloomFilter (29-45)
src/governance/governance.h (1)
src/governance/governance.cpp (12)
  • GetOrphanVoteObjectHashes (1074-1102)
  • GetOrphanVoteObjectHashes (1074-1074)
  • GetVoteBloomFilter (877-895)
  • GetVoteBloomFilter (877-877)
  • GetSyncableObjectInvs (626-641)
  • GetSyncableObjectInvs (626-626)
  • GetSyncableVoteInvs (593-624)
  • GetSyncableVoteInvs (593-593)
  • AcceptMessage (930-942)
  • AcceptMessage (930-930)
  • ProcessVote (750-807)
  • ProcessVote (750-751)
src/governance/governance.cpp (2)
src/governance/object.cpp (2)
  • ProcessVote (58-159)
  • ProcessVote (58-59)
src/common/bloom.cpp (1)
  • CBloomFilter (29-45)
⏰ 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). (10)
  • GitHub Check: linux64_nowallet-build / Build source
  • GitHub Check: arm-linux-build / Build source
  • GitHub Check: x86_64-w64-mingw32 / Build depends
  • GitHub Check: linux64_fuzz-build / Build source
  • GitHub Check: linux64_ubsan-build / Build source
  • GitHub Check: linux64_sqlite-build / Build source
  • GitHub Check: linux64-build / Build source
  • GitHub Check: linux64_tsan-build / Build source
  • GitHub Check: mac-build / Build source
  • GitHub Check: Lint / Run linters
🔇 Additional comments (15)
src/governance/governance.h (2)

370-381: LGTM! Clean API design for the new getter methods.

The new accessor methods (GetOrphanVoteObjectHashes, GetVoteBloomFilter, GetSyncableObjectInvs, GetSyncableVoteInvs) follow a consistent pattern with:

  • [[nodiscard]] attributes to prevent ignoring return values
  • Proper EXCLUSIVE_LOCKS_REQUIRED(!cs_store) annotations
  • Clear documentation comments describing each method's purpose

This cleanly separates data retrieval from network operations, aligning with the refactoring goals.


388-391: LGTM! Output parameter approach for orphan handling.

The updated ProcessVote signature with hashToRequest output parameter cleanly decouples vote processing from network operations. The documentation clearly explains that hashToRequest is set when the vote references an unknown governance object (orphan case).

src/node/sync_manager.h (1)

31-32: LGTM! Clear method naming convention.

The new SendGovernanceObjectSyncRequest complements the existing SendGovernanceSyncRequest with consistent naming that distinguishes full sync from object-specific sync requests. The fUseFilter parameter allows callers to optionally include a bloom filter of existing votes.

src/node/sync_manager.cpp (2)

39-49: LGTM! Clean implementation of object-specific sync request.

The implementation correctly:

  • Guards against null pnode early (line 41)
  • Conditionally builds the bloom filter based on fUseFilter (line 45)
  • Uses the new GetVoteBloomFilter() accessor from CGovernanceManager
  • Constructs and sends the MNGOVERNANCESYNC message with hash and filter

This properly centralizes the governance object sync request logic in the network layer.


122-122: LGTM! Call site updated correctly.

The call site now uses the new SendGovernanceObjectSyncRequest helper with fUseFilter=true, which will include a bloom filter of existing votes to avoid redundant vote transfers.

src/governance/net_governance.cpp (4)

30-44: LGTM! Orphan object request logic cleanly moved to network layer.

The implementation correctly:

  • Retrieves orphan vote object hashes via the new getter
  • Iterates over fully connected peers to request missing objects
  • Uses an empty bloom filter since we want the object itself, not votes
  • Only sends requests when CanRelay() is true

This properly separates the orphan handling from the governance manager.


80-100: LGTM! Full sync handling properly refactored.

The refactored full sync path:

  • Prevents repeated requests via HasFulfilledRequest/AddFulfilledRequest
  • Uses GetSyncableObjectInvs() to retrieve inventory items
  • Maintains protocol compatibility by sending SYNCSTATUSCOUNT
  • Uses MessageProcessingResult to post inventory for processing

101-114: LGTM! Per-object vote sync refactored correctly.

The vote sync path uses GetSyncableVoteInvs() with the provided bloom filter to retrieve only votes the peer doesn't have, then posts them via MessageProcessingResult.


174-197: LGTM! Orphan vote handling with hashToRequest flow.

The updated vote processing correctly:

  • Captures hashToRequest output from ProcessVote
  • On rejection, checks if hashToRequest is non-zero (indicating orphan)
  • Requests the missing governance object via MNGOVERNANCESYNC with empty filter
  • Continues with existing misbehavior penalty logic
src/governance/governance.cpp (6)

593-624: LGTM! GetSyncableVoteInvs implementation is correct.

The implementation properly:

  • Acquires cs_store lock before accessing mapObjects
  • Returns early for missing or deleted/expired objects
  • Efficiently filters votes using the bloom filter before expensive validity checks
  • Validates votes against the current masternode list
  • Constructs appropriate MSG_GOVERNANCE_OBJECT_VOTE inventory items

626-641: LGTM! GetSyncableObjectInvs implementation.

Clean implementation that reserves vector capacity upfront and filters out deleted/expired objects. Returns MSG_GOVERNANCE_OBJECT inventory items for all syncable objects.


742-743: LGTM! ProcessVoteAndRelay correctly ignores hashToRequest.

The comment clearly explains that hashToRequest is ignored for local votes since there's no peer to request from. The variable is still needed to satisfy the ProcessVote signature.


750-788: LGTM! ProcessVote correctly implements hashToRequest output.

The implementation:

  • Initializes hashToRequest to zero at the start (line 754)
  • Only sets hashToRequest when an orphan vote is successfully inserted (line 783)
  • The conditional cmmapOrphanVotes.Insert() check prevents setting hashToRequest for duplicate orphan votes, avoiding redundant network requests
  • All other exit paths correctly leave hashToRequest as zero

877-895: LGTM! GetVoteBloomFilter implementation.

The bloom filter construction:

  • Uses consensus parameter nGovernanceFilterElements for sizing
  • Applies GOVERNANCE_FILTER_FP_RATE for false positive rate
  • Uses random tweak for hash variation
  • Returns empty filter if object doesn't exist (caller handles gracefully)
  • Efficiently populates filter with existing vote hashes

1074-1102: LGTM! GetOrphanVoteObjectHashes implementation.

The implementation:

  • Acquires cs_store lock for thread safety
  • First cleans up expired orphan votes (prevents memory growth)
  • Then collects unique object hashes from remaining orphan votes
  • Filters to only return hashes of objects not in mapObjects

This properly replaces the old RequestOrphanObjects method with a pure data accessor.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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.

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