Skip to content

Conversation

@knst
Copy link
Collaborator

@knst knst commented Oct 15, 2025

Issue being fixed or feature implemented

Current implementation:

  1. every access to CMasternodeMetaInfo is done by accessing GetMetaInfo under mutex CMasternodeMetaMan::cs
  2. GetMetaInfo returns shared_ptr to object
  3. every read or write of GetMetaInfo is protected by atomic, second mutex CMasternodeMetaInfo::cs; access to object is done indirectly by one more memory hop (because shared_ptr)

It is not efficient, because GetMetaInfo is spread all over code base and not a single case need shared_ptr here; all accesses are brief and short (single read or single write; except RPC where all structure is serialized).

What was done?

This PR is follow-up for PR #6868 with further improvements and simplification of code.

Instead returning shared_ptr with CMasternodeMetaInfo directly access to members of CMasternodeMetaMan under its mutex; all mutexes, atomic and shared_ptr itself are removed from CMasternodeMetaInfo accesses.

It simplified implementation significantly, removed big amount of thread-safety annotations.
Performance is probably improved, but improvement is unmeasurable, because CMasternodeMetaInfo and CMasternodeMetaMan has not been spotted as hot spot in profiler neither hot spot in lock contentions logs.

Also this PR removes duplicated code between coinjoin/client and coinjoin/server by creating a helper in CMasternodeMetaMan

How Has This Been Tested?

Run unit & functional tests

Breaking Changes

N/A

Checklist:

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

@knst knst added this to the 23 milestone Oct 15, 2025
@knst knst changed the title refactor: drop mutex and atomic from CMasternodeMetaInfo, keep object instead shared_ptr refactor: drop mutex and atomic from CMasternodeMetaInfo, access to object directly without shared_ptr Oct 15, 2025
@coderabbitai
Copy link

coderabbitai bot commented Oct 15, 2025

Walkthrough

Refactors masternode metadata to value-based CMasternodeMetaInfo with expanded CMasternodeMetaMan manager-level APIs. Call sites that previously accessed per-entry pointers (GetMetaInfo(...)->...) now call CMasternodeMetaMan methods (e.g., IsMixingThresholdExceeded, AllowMixing/DisallowMixing, IsValidForMixingTxes, Set/GetLastOutboundAttempt/Success, OutboundFailedTooManyTimes, AddGovernanceVote, Set/Reset/GetPlatformBan). DSQ/mixing guards, outbound tracking, governance vote handling, platform-ban forwarding, and related logging were updated across coinjoin, evo, llmq, governance, net, net_processing, rpc, and masternode meta modules. New constants and serialization changes added in the meta implementation.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Peer as Peer
    participant CJServer as CoinJoin Server
    participant MNMeta as CMasternodeMetaMan

    Note right of Peer: DSACCEPT / DSQUEUE request

    Peer->>CJServer: Send DSQ request (proTxHash, mnCount)
    CJServer->>MNMeta: IsMixingThresholdExceeded(proTxHash, mnCount)?
    alt exceeded == true
        MNMeta-->>CJServer: true
        CJServer->>Peer: Reject (ERR_RECENT) / concise log
    else exceeded == false
        MNMeta-->>CJServer: false
        CJServer->>MNMeta: AllowMixing(proTxHash)
        CJServer->>CJServer: Initialize queue/session and proceed
        CJServer->>Peer: Continue DSQ handling
    end
Loading
sequenceDiagram
    autonumber
    participant Node as NetProcessing
    participant MNMeta as CMasternodeMetaMan
    participant Prop as BanPropagator

    Note right of Node: Platform ban detected/received

    Node->>MNMeta: SetPlatformBan(inv_hash, ban_msg)
    MNMeta-->>Node: applied? (bool)
    alt applied == true
        Node->>Prop: Enqueue ban for forwarding
        Prop->>Network: Forward ban to peers
    else applied == false
        Node->>Logs: Already known / no-op
    end
Loading
sequenceDiagram
    autonumber
    participant Auth as CMNAuth
    participant MNMeta as CMasternodeMetaMan

    Note right of Auth: Outbound success update

    Auth->>MNMeta: SetLastOutboundSuccess(proRegTxHash, timestamp)
    MNMeta-->>Auth: (void)
    Auth->>Logs: Updated last outbound success timestamp
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Files/areas needing extra attention:

  • src/masternode/meta.h/.cpp — large data-model, serialization, API surface, and locking/ownership changes.
  • src/coinjoin/client.cpp and src/coinjoin/server.cpp — DSQ/mixing guard replacements and logging changes.
  • src/net.cpp and src/net_processing.cpp — outbound tracking and platform-ban propagation changes.
  • src/evo/deterministicmns.cpp and src/evo/mnauth.cpp — platform-ban reset and outbound timestamp updates.
  • src/governance/object.cpp — removal of early-exit on AddGovernanceVote failure.
  • src/llmq/* and src/rpc/evo.cpp — updated meta access patterns and probing logic.
  • Concurrency and EXCLUSIVE_LOCKS_REQUIRED annotations for the new manager-level APIs.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.79% 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 clearly and specifically describes the main refactoring: removing mutexes and atomics from CMasternodeMetaInfo and switching from shared_ptr to direct object access.
Description check ✅ Passed The description is directly related to the changeset, detailing the inefficiency of the current implementation, the specific refactoring performed, and the context of being a follow-up to PR #6868.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 16915ff and 572bafd.

📒 Files selected for processing (4)
  • src/coinjoin/client.cpp (2 hunks)
  • src/coinjoin/server.cpp (2 hunks)
  • src/masternode/meta.cpp (4 hunks)
  • src/masternode/meta.h (7 hunks)
🧰 Additional context used
🧠 Learnings (13)
📓 Common learnings
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.
Learnt from: kwvg
Repo: dashpay/dash PR: 6543
File: src/wallet/receive.cpp:240-251
Timestamp: 2025-02-06T14:34:30.466Z
Learning: Pull request #6543 is focused on move-only changes and refactoring, specifically backporting from Bitcoin. Behavior changes should be proposed in separate PRs.
Learnt from: kwvg
Repo: dashpay/dash PR: 6761
File: src/chainlock/signing.cpp:247-250
Timestamp: 2025-07-29T14:32:48.369Z
Learning: In PR #6761, kwvg acknowledged a null pointer check issue in ChainLockSigner::Cleanup() method but deferred it to follow-up, consistent with the pattern of avoiding scope creep in refactoring PRs.
Learnt from: kwvg
Repo: dashpay/dash PR: 6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.
📚 Learning: 2025-07-09T15:02:26.899Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6729
File: src/evo/deterministicmns.cpp:1313-1316
Timestamp: 2025-07-09T15:02:26.899Z
Learning: In Dash's masternode transaction validation, `IsVersionChangeValid()` is only called by transaction types that update existing masternode entries (like `ProUpServTx`, `ProUpRegTx`, `ProUpRevTx`), not by `ProRegTx` which creates new entries. This means validation logic in `IsVersionChangeValid()` only applies to the subset of transaction types that actually call it, not all masternode transaction types.

Applied to files:

  • src/coinjoin/server.cpp
  • src/coinjoin/client.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/meta.cpp
  • src/masternode/meta.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/meta.cpp
  • src/masternode/meta.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/masternode/meta.cpp
  • src/masternode/meta.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/masternode/meta.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/masternode/meta.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/masternode/meta.cpp
📚 Learning: 2025-06-06T11:53:09.094Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6665
File: src/evo/providertx.h:82-82
Timestamp: 2025-06-06T11:53:09.094Z
Learning: In ProTx serialization code (SERIALIZE_METHODS), version checks should use hardcoded maximum flags (/*is_basic_scheme_active=*/true, /*is_extended_addr=*/true) rather than deployment-based flags. This is because serialization code should be able to deserialize any structurally valid ProTx up to the maximum version the code knows how to handle, regardless of current consensus validity. Validation code, not serialization code, is responsible for checking whether a ProTx version is consensus-valid based on deployment status.

Applied to files:

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

Applied to files:

  • src/masternode/meta.h
🧬 Code graph analysis (2)
src/masternode/meta.cpp (1)
src/masternode/meta.h (9)
  • m_last_dsq (34-34)
  • m_mixing_tx_count (35-35)
  • outboundAttemptCount (40-40)
  • lastOutboundAttempt (41-41)
  • lastOutboundSuccess (42-42)
  • m_platform_ban (45-85)
  • m_platform_ban_updated (47-47)
  • SetLastOutboundSuccess (71-71)
  • SetPlatformBan (73-84)
src/masternode/meta.h (1)
src/masternode/meta.cpp (42)
  • ToJson (38-54)
  • ToJson (38-38)
  • AddGovernanceVote (56-62)
  • AddGovernanceVote (56-56)
  • AddGovernanceVote (130-134)
  • AddGovernanceVote (130-130)
  • RemoveGovernanceObject (64-68)
  • RemoveGovernanceObject (64-64)
  • RemoveGovernanceObject (136-142)
  • RemoveGovernanceObject (136-136)
  • SetLastOutboundAttempt (151-155)
  • SetLastOutboundAttempt (151-151)
  • SetLastOutboundSuccess (157-161)
  • SetLastOutboundSuccess (157-157)
  • SetPlatformBan (197-208)
  • SetPlatformBan (197-197)
  • GetMetaInfo (83-91)
  • GetMetaInfo (83-83)
  • GetMetaInfoOrDefault (70-75)
  • GetMetaInfoOrDefault (70-70)
  • GetInfo (77-81)
  • GetInfo (77-77)
  • IsMixingThresholdExceeded (93-108)
  • IsMixingThresholdExceeded (93-93)
  • AllowMixing (110-116)
  • AllowMixing (110-110)
  • DisallowMixing (118-122)
  • DisallowMixing (118-118)
  • IsValidForMixingTxes (124-128)
  • IsValidForMixingTxes (124-124)
  • GetAndClearDirtyGovernanceObjectHashes (144-149)
  • GetAndClearDirtyGovernanceObjectHashes (144-144)
  • GetLastOutboundAttempt (163-167)
  • GetLastOutboundAttempt (163-163)
  • GetLastOutboundSuccess (169-173)
  • GetLastOutboundSuccess (169-169)
  • OutboundFailedTooManyTimes (175-179)
  • OutboundFailedTooManyTimes (175-175)
  • IsPlatformBanned (181-185)
  • IsPlatformBanned (181-181)
  • ResetPlatformBan (187-195)
  • ResetPlatformBan (187-187)
⏰ 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). (9)
  • GitHub Check: check_merge
  • GitHub Check: predict_conflicts
  • GitHub Check: Lint / Run linters
  • GitHub Check: x86_64-apple-darwin / Build depends
  • 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_multiprocess / Build depends
  • GitHub Check: arm-linux-gnueabihf / Build depends
  • GitHub Check: x86_64-pc-linux-gnu / Build depends
🔇 Additional comments (6)
src/coinjoin/server.cpp (2)

102-111: LGTM! Cleaner DSQ threshold check.

The centralized IsMixingThresholdExceeded check replaces the previous per-node LastDsq/Threshold calculations, making the logic more maintainable and consistent across the codebase.


196-200: LGTM! Consistent threshold enforcement.

The same IsMixingThresholdExceeded pattern is correctly applied here for DSQUEUE non-ready path, ensuring consistent DSQ rate limiting across different code paths.

src/coinjoin/client.cpp (2)

127-132: LGTM! Client-side DSQ threshold check.

The client correctly uses IsMixingThresholdExceeded to filter out masternodes that have been used too recently for mixing, consistent with the server-side implementation.


1177-1183: LGTM! Appropriate pre-queue validation.

The check prevents selecting masternodes that are over their DSQ threshold before attempting to start a new queue, with clear logging of why the masternode is skipped.

src/masternode/meta.h (2)

203-204: Good use of thread-safety annotations.

The private helpers correctly use EXCLUSIVE_LOCKS_REQUIRED(cs) to document that they must be called with the lock held. This helps catch potential threading issues at compile time.


216-243: Public API annotations look correct.

All public methods that access the metadata store are properly annotated with EXCLUSIVE_LOCKS_REQUIRED(!cs) and internally acquire the lock. This ensures thread-safe access to the value-based CMasternodeMetaInfo entries.

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.

@github-actions
Copy link

github-actions bot commented Oct 15, 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.

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

Caution

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

⚠️ Outside diff range comments (1)
src/net_processing.cpp (1)

3480-3485: Still need the mixing meta lock

IsValidForMixingTxes assumes CMasternodeMetaMan::cs is held; the previous code performed the meta check inside the manager’s critical section. We call it here without locking, so the method’s internal AssertLockHeld will trip (or worse, we race). Acquire WITH_LOCK(mn_metaman.GetCs(), return mn_metaman.IsValidForMixingTxes(...)) (or similar helper) before invoking the new API.

🧹 Nitpick comments (5)
src/masternode/meta.h (4)

56-61: Serialization format change: confirm backward compatibility and handle duplicates

You now serialize a vector of CMasternnodeMetaInfo by value. Ensure this matches prior on-disk format for the same SERIALIZATION_VERSION_STRING. Also, if the vector contains duplicate m_protx_hash entries, later ones are silently ignored by emplace.

Consider using insert_or_assign to make last-wins explicit.

Apply this small change to make behavior explicit:

-        for (auto& mm : tmpMetaInfo) {
-            metaInfos.emplace(mm.m_protx_hash, CMasternodeMetaInfo{std::move(mm)});
-        }
+        for (auto& mm : tmpMetaInfo) {
+            metaInfos.insert_or_assign(mm.m_protx_hash, std::move(mm));
+        }

71-73: Add thread-safety annotation to outbound setters

SetLastOutboundAttempt/Success mutate shared state. For consistency with the new locking model, add the same EXCLUSIVE_LOCKS_REQUIRED(!cs) (or appropriate annotation) used on other mutators.


39-41: Consider guarding against attempt counter overflow

outboundAttemptCount is int and is unbounded; in pathological cases it could overflow. Either use a wider unsigned type or saturate at a reasonable max in SetLastOutboundAttempt.

Example:

-    void SetLastOutboundAttempt(int64_t t) { lastOutboundAttempt = t; ++outboundAttemptCount; }
+    void SetLastOutboundAttempt(int64_t t) {
+        lastOutboundAttempt = t;
+        if (outboundAttemptCount < std::numeric_limits<int>::max()) ++outboundAttemptCount;
+    }

92-106: Serialize/Unserialize: minor efficiency/readability nits

  • Reserve tmpMetaInfo to avoid reallocations (metaInfos.size()).
  • Use insert_or_assign during Unserialize as suggested above.
-        std::vector<CMasternodeMetaInfo> tmpMetaInfo;
-        for (const auto& p : metaInfos) {
-            tmpMetaInfo.emplace_back(p.second);
-        }
+        std::vector<CMasternnodeMetaInfo> tmpMetaInfo;
+        tmpMetaInfo.reserve(metaInfos.size());
+        for (const auto& [_, mi] : metaInfos) {
+            tmpMetaInfo.emplace_back(mi);
+        }

Also applies to: 114-125

src/governance/object.cpp (1)

151-152: Behavioral change: dropped failure handling from AddGovernanceVote

Previously, failure from AddGovernanceVote aborted processing. The new API is void; processing now proceeds unconditionally. Confirm this is intentional and that rate/duplicate checks are fully covered earlier (fileVotes/rate checks).

If you still need a guard, consider having AddGovernanceVote return a bool (no-op vs. insert) and log on false.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f170aed and b57740d.

📒 Files selected for processing (12)
  • src/coinjoin/client.cpp (2 hunks)
  • src/coinjoin/server.cpp (2 hunks)
  • src/evo/deterministicmns.cpp (1 hunks)
  • src/evo/mnauth.cpp (1 hunks)
  • src/governance/object.cpp (1 hunks)
  • src/llmq/dkgsession.cpp (1 hunks)
  • src/llmq/utils.cpp (1 hunks)
  • src/masternode/meta.cpp (4 hunks)
  • src/masternode/meta.h (5 hunks)
  • src/net.cpp (4 hunks)
  • src/net_processing.cpp (2 hunks)
  • src/rpc/evo.cpp (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • src/llmq/dkgsession.cpp
  • src/llmq/utils.cpp
  • src/net_processing.cpp
  • src/net.cpp
  • src/governance/object.cpp
  • src/coinjoin/server.cpp
  • src/coinjoin/client.cpp
  • src/rpc/evo.cpp
  • src/evo/deterministicmns.cpp
  • src/evo/mnauth.cpp
  • src/masternode/meta.h
  • src/masternode/meta.cpp
src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • src/evo/deterministicmns.cpp
  • src/evo/mnauth.cpp
  • src/masternode/meta.h
  • src/masternode/meta.cpp
🔇 Additional comments (13)
src/llmq/utils.cpp (1)

915-916: Good API migration

Switched to mn_metaman.GetLastOutboundSuccess(...) keeps logic unchanged and centralizes access.

src/rpc/evo.cpp (1)

1382-1383: Avoids shared_ptr/meta indirection

Using GetInfo(...).ToJson() is simpler and matches value-based storage. Minor perf note: this copies the meta before JSON, which is fine here.

src/llmq/dkgsession.cpp (1)

495-502: Correctly moved to manager-level checks

OutboundFailedTooManyTimes/IsPlatformBanned calls on m_mn_metaman are consistent with the refactor and preserve behavior.

src/coinjoin/server.cpp (2)

81-91: Centralized DSQ gating via IsDsqOver

Good consolidation; logs and ERR_RECENT behavior preserved.


173-179: Consistent DSQ abuse prevention

Using IsDsqOver(...) with GetValidMNsCount() matches the new API and intent to avoid domination.

src/masternode/meta.h (1)

200-206: Public API surface looks coherent

The value-returning GetInfo and centralized IsDsqOver/readers align with the new locking model and reduce unsafe exposure.

Optionally, verify no old pointer-style usages remain:

src/coinjoin/client.cpp (2)

119-124: Centralized DSQ rate-limit — looks good; confirm locking

Using m_mn_metaman.IsDsqOver(...) simplifies and unifies the guard. Please confirm these new manager-level APIs perform internal locking of CMasternodeMetaMan::cs (since CMasternodeMetaInfo dropped its own mutex/atomic) so call sites don’t need to hold the lock explicitly.


1166-1169: Unified check in StartNewQueue — good; verify count semantics

The IsDsqOver(dmn->proTxHash, nMnCount) gate is consistent with ProcessMessage. Please double-check IsDsqOver expects non-weighted MN count (GetValidMNsCount), not weighted, to avoid threshold drift.

src/net.cpp (5)

3445-3449: Swap to GetLastOutboundAttempt — verify time units and locking

nANow is seconds (GetTimestd::chrono::seconds().count()). Please confirm GetLastOutboundAttempt returns the same unit and that internal locking of CMasternodeMetaMan::cs is handled inside the method.


3469-3471: SetLastOutboundSuccess on existing outbound — ensure backoff reset

The success mark here is appropriate. Confirm it also clears/decays failure/backoff state for this MN so future attempts aren’t unnecessarily delayed.


3476-3482: Second use of GetLastOutboundAttempt — same unit/lock check

Same ask as above: confirm return unit matches nANow and that manager-level methods encapsulate required locking.


3527-3528: SetLastOutboundAttempt before dialing — semantics check

Marking the attempt pre-connection is fine for backoff. Please verify failure paths always advance failure counters (or similar) so OutboundFailedTooManyTimes reflects this attempt if connect fails immediately.


3541-3543: OutboundFailedTooManyTimes usage — confirm increment path

Ensure the code path that led here increments the failure count used by OutboundFailedTooManyTimes() within CMasternodeMetaMan, and that concurrency with list updates is internally synchronized.

Comment on lines 671 to 682
if (m_mn_metaman.ResetPlatformBan(opt_proTx->proTxHash, nHeight)) {
LogPrint(BCLog::LLMQ, "%s -- MN %s is failed to Platform revived at height %d\n", __func__,
opt_proTx->proTxHash.ToString(), nHeight);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Clarify the log message for platform ban revival.

The log message "is failed to Platform revived" is grammatically incorrect and confusing. Since this block now executes when the revival succeeds (not when it fails, as in the previous implementation), consider revising the message to something clearer like:

LogPrint(BCLog::LLMQ, "%s -- MN %s platform ban revived at height %d\n", __func__,
         opt_proTx->proTxHash.ToString(), nHeight);
🤖 Prompt for AI Agents
In src/evo/deterministicmns.cpp around lines 671-674, the LogPrint message is
grammatically incorrect and misleading ("is failed to Platform revived") and
should reflect that ResetPlatformBan succeeded; update the log string to a
clear, concise message such as "MN %s platform ban revived at height %d"
(preserve __func__ and the proTxHash.ToString() and nHeight parameters) so the
log accurately represents a successful revival.

Comment on lines 105 to 108
if (!peer.IsInboundConn()) {
mn_metaman.GetMetaInfo(mnauth.proRegTxHash)->SetLastOutboundSuccess(GetTime<std::chrono::seconds>().count());
mn_metaman.SetLastOutboundSuccess(mnauth.proRegTxHash, GetTime<std::chrono::seconds>().count());
if (peer.m_masternode_probe_connection) {
LogPrint(BCLog::NET_NETCONN, "CMNAuth::ProcessMessage -- Masternode probe successful for %s, disconnecting. peer=%d\n",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Guard SetLastOutboundSuccess with mn meta lock

SetLastOutboundSuccess requires the manager mutex to be held (the old code locked via GetMetaInfo). We’re now calling it bare, which violates the contract and will assert. Wrap the call in the manager’s lock (e.g. WITH_LOCK(mn_metaman.GetCs(), mn_metaman.SetLastOutboundSuccess(...));).

🤖 Prompt for AI Agents
In src/evo/mnauth.cpp around lines 105 to 108, SetLastOutboundSuccess is called
without holding mn_metaman's mutex which violates the manager's locking contract
and will assert; wrap the call with the manager lock, e.g. use
WITH_LOCK(mn_metaman.GetCs(),
mn_metaman.SetLastOutboundSuccess(mnauth.proRegTxHash,
GetTime<std::chrono::seconds>().count())); and keep the rest of the logic
unchanged so the call is protected by the manager's mutex.

Comment on lines 3607 to 3608
// At this point, the outgoing message serialization version can't change.
const auto meta_info = m_mn_metaman.GetMetaInfo(ban_msg.m_protx_hash);
if (meta_info->SetPlatformBan(true, ban_msg.m_requested_height)) {
LogPrintf("PLATFORMBAN -- forward message to other nodes\n");
m_mn_metaman.RememberPlatformBan(hash, std::move(ban_msg));
if (m_mn_metaman.SetPlatformBan(hash, std::move(ban_msg))) {
LogPrintf("PLATFORMBAN -- hash: %s forward message to other nodes\n", hash.ToString());
ret.m_inventory.emplace_back(MSG_PLATFORM_BAN, hash);
}
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

Missing ban propagation after failed SetPlatformBan

SetPlatformBan now returns false when the entry was already present. Previously we always forwarded by calling RememberPlatformBan regardless. Dropping the relay in this branch breaks propagation of matching quorum signatures (peers stop seeing refreshed bans). Keep forwarding when the manager reports “already had it”—only skip if the call throws/invalidates.

🤖 Prompt for AI Agents
In src/net_processing.cpp around lines 3607 to 3611, the current logic only
forwards the platform-ban message when m_mn_metaman.SetPlatformBan returns true;
change it so that a false return that indicates “already present” still results
in forwarding the ban inventory (i.e., still emplace MSG_PLATFORM_BAN) so
matching quorum signature refreshes propagate — only avoid forwarding if
SetPlatformBan signals an error/invalidation (exception or explicit invalid
status); in practice, treat a normal false (already-existed) the same as true
for relay, and only suppress relay on thrown/invalid cases.

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 (1)
src/masternode/meta.h (1)

54-54: Copy constructor may be expensive for large governance maps.

The defaulted copy constructor will perform a deep copy of mapGovernanceObjectsVotedOn, which could be expensive if a masternode has voted on many governance objects. Since CMasternodeMetaInfo is now returned by value from GetInfo(), this copy cost will be incurred on every call.

Consider whether the call sites need a full copy, or if they could work with const references where appropriate. If copies are necessary, document the performance implications or consider optimizing the storage structure if governance maps become large.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b57740d and 6834d68.

📒 Files selected for processing (1)
  • src/masternode/meta.h (5 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • src/masternode/meta.h
src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • src/masternode/meta.h
🔇 Additional comments (6)
src/masternode/meta.h (6)

98-106: LGTM!

The serialization correctly creates a vector from the value-based map entries. The use of p.second at line 103 properly extracts the CMasternodeMetaInfo value from the map.


109-124: LGTM!

The unserialization correctly reconstructs the map using mm.m_protx_hash as the key and move semantics for the value. This aligns well with the value-based storage model.


188-190: LGTM!

The private helpers correctly return references (GetMetaInfo) and const references (GetMetaInfoOrDefault) while requiring the lock to be held by the caller. This is an efficient pattern for internal use within the class.


199-199: LGTM!

Returning CMasternodeMetaInfo by value ensures thread safety by providing a copy to the caller, eliminating the need for the caller to hold the lock after the method returns. This is the correct approach for the public API.


205-227: LGTM!

The public API methods are consistently annotated with EXCLUSIVE_LOCKS_REQUIRED(!cs), indicating they acquire the lock internally. This provides a clean, thread-safe interface for callers who don't need to manage locking manually.


72-83: Verify platform ban idempotency at the same height.

The logic at lines 77-78 prevents unsetting a ban at the same height, but allows setting a ban multiple times at the same height (when is_banned == true). This might allow duplicate processing of the same ban message.

Verify whether callers deduplicate ban messages before calling SetPlatformBan, or if this method should enforce stricter idempotency:

@knst knst force-pushed the fix-drop-meta-cs branch from 6834d68 to cdc9825 Compare October 15, 2025 19:28
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

♻️ Duplicate comments (1)
src/masternode/meta.cpp (1)

93-108: Critical logic error in IsDsqOver already flagged in past review.

This issue was previously identified: Line 97 checks if (it != metaInfos.end()) (meaning "found"), but then returns false and does not use the iterator. Subsequently, line 101 attempts to access it->second, which is undefined behavior when the iterator is at end() (not found).

The condition must be inverted to check for "not found" before returning false.

Apply this diff to fix the logic error:

 bool CMasternodeMetaMan::IsDsqOver(const uint256& protx_hash, int mn_count) const
 {
     LOCK(cs);
     auto it = metaInfos.find(protx_hash);
-    if (it != metaInfos.end()) {
-        LogPrint(BCLog::COINJOIN, "DSQUEUE -- node %s is logged\n", protx_hash.ToString());
+    if (it == metaInfos.end()) {
+        LogPrint(BCLog::COINJOIN, "DSQUEUE -- node %s not found in metaInfos\n", protx_hash.ToString());
         return false;
     }
     const auto& meta_info = it->second;
     int64_t last_dsq = meta_info.m_last_dsq;
     int64_t threshold = last_dsq + mn_count / 5;
     
     LogPrint(BCLog::COINJOIN, "DSQUEUE -- mn: %s last_dsq: %d  dsq_threshold: %d  nDsqCount: %d\n",
              protx_hash.ToString(), last_dsq, threshold, nDsqCount);
     return last_dsq != 0 && threshold > nDsqCount;
 }
🧹 Nitpick comments (1)
src/masternode/meta.cpp (1)

16-18: Minor: Consider renaming the default instance for clarity.

The variable name default_meta_info_meta_info contains redundant repetition. Consider simplifying to default_meta_info or default_metainfo.

Apply this diff to improve naming:

 namespace {
-static const CMasternodeMetaInfo default_meta_info_meta_info{};
+static const CMasternodeMetaInfo default_meta_info{};
 } // anonymous namespace

Then update line 73:

-    if (it == metaInfos.end()) return default_meta_info_meta_info;
+    if (it == metaInfos.end()) return default_meta_info;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6834d68 and cdc9825.

📒 Files selected for processing (2)
  • src/masternode/meta.cpp (4 hunks)
  • src/masternode/meta.h (5 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • src/masternode/meta.cpp
  • src/masternode/meta.h
src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • src/masternode/meta.cpp
  • src/masternode/meta.h
🔇 Additional comments (13)
src/masternode/meta.cpp (4)

110-118: Verify atomic increment ordering is correct.

nDsqCount++ (line 112) increments the atomic counter before acquiring the lock. While nDsqCount is atomic and this is safe for the increment itself, confirm that reading nDsqCount.load() on line 116 after incrementing but potentially from a different thread's perspective won't cause any DSQ sequencing issues.

The current pattern appears intentional—incrementing the global counter first, then recording that value under lock—but please verify this ordering satisfies the DSQ queue semantics across concurrent AllowMixing calls.


126-130: Confirm mixing transaction threshold semantics.

Line 129 uses m_mixing_tx_count <= MASTERNODE_MAX_MIXING_TXES, allowing up to 5 mixing transactions inclusive. Ensure this matches the intended policy (i.e., 5 is the maximum allowed, not 4).


189-197: LGTM: ResetPlatformBan correctly handles missing entries.

Returning false when the masternode entry does not exist (line 194) is appropriate—you cannot reset a ban on a nonexistent entry.


199-210: LGTM: SetPlatformBan creates entry if needed and caches ban message.

The method correctly uses GetMetaInfo (which creates an entry if absent), attempts the ban update, and on success caches the ban message. The move semantics for ban_msg are efficient.

src/masternode/meta.h (9)

29-46: LGTM: Public member variables align with value-based refactor.

Exposing CMasternodeMetaInfo fields publicly is appropriate given the refactor removes per-entry locking and centralizes synchronization at the manager level (CMasternodeMetaMan::cs).


56-61: LGTM: Serialization includes all necessary fields.

All members—including m_protx_hash, DSQ/mixing state, governance votes, outbound tracking, and platform ban state—are serialized. This preserves state across restarts.


69-70: LGTM: Outbound attempt/success setters correctly update counters.

SetLastOutboundAttempt increments the attempt counter, while SetLastOutboundSuccess resets it. This logic supports the "too many failed attempts" check.


72-83: Verify platform ban state transition semantics.

The SetPlatformBan logic rejects older heights (line 74-76) and rejects unbanning at the same height as a ban (line 77-79). Confirm this aligns with the intended platform ban state machine—specifically, that unbanning at the same height as banning should indeed fail.

If the semantics are correct, consider adding a brief comment explaining why same-height unbans are rejected, as this is subtle.


92-92: LGTM: Value-based map storage aligns with refactor objectives.

Switching from std::map<uint256, std::shared_ptr<CMasternodeMetaInfo>> to std::map<uint256, CMasternodeMetaInfo> removes pointer indirection and simplifies memory management, as intended by this refactor.


102-103: LGTM: Serialization correctly copies value-based entries.

Iterating metaInfos and emplacing p.second into the temporary vector is correct for the value-based map.


122-122: LGTM: Unserialization efficiently moves entries into map.

Using CMasternodeMetaInfo{std::move(mm)} avoids copying the unserialized object. The key mm.m_protx_hash is extracted before the move, which is correct.


188-189: LGTM: Private accessor lock annotations match implementations.

The EXCLUSIVE_LOCKS_REQUIRED(cs) annotations correctly document that callers must hold cs when invoking these private helpers.


199-227: LGTM: Public API lock annotations correctly specify external requirements.

All public methods use EXCLUSIVE_LOCKS_REQUIRED(!cs), documenting that callers must not hold the lock (the methods acquire it internally). This prevents deadlocks and centralizes locking at the manager level.

@github-actions
Copy link

This pull request has conflicts, please rebase.

@github-actions
Copy link

github-actions bot commented Nov 4, 2025

This pull request has conflicts, please rebase.

@knst knst force-pushed the fix-drop-meta-cs branch from a657aff to fe3966d Compare November 4, 2025 19:24
knst and others added 2 commits November 11, 2025 03:13
Co-Authored-By: UdjinM6 <UdjinM6@users.noreply.github.com>
Co-Authored-By: UdjinM6 <UdjinM6@users.noreply.github.com>
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

♻️ Duplicate comments (1)
src/masternode/meta.cpp (1)

93-108: Correct the misleading log message.

The iterator check on line 97 is now correct (checks for end()), but the log message on line 98 still says "node %s is logged" when the node is not found. This was flagged in previous reviews as needing correction.

Apply this diff to clarify the message:

     if (it == metaInfos.end()) {
-        LogPrint(BCLog::COINJOIN, "DSQUEUE -- node %s is logged\n", protx_hash.ToString());
+        LogPrint(BCLog::COINJOIN, "DSQUEUE -- node %s not found in metaInfos\n", protx_hash.ToString());
         return false;
     }
🧹 Nitpick comments (1)
src/masternode/meta.h (1)

55-55: Explicitly default the move constructor.

Line 55 defaults only the copy constructor. For a value-based type, explicitly defaulting the move constructor improves clarity and ensures optimal move semantics.

Apply this diff:

 CMasternodeMetaInfo(const CMasternodeMetaInfo& ref) = default;
+CMasternodeMetaInfo(CMasternodeMetaInfo&& ref) = default;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fe3966d and 982b68e.

📒 Files selected for processing (3)
  • src/evo/deterministicmns.cpp (1 hunks)
  • src/masternode/meta.cpp (4 hunks)
  • src/masternode/meta.h (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/evo/deterministicmns.cpp
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • src/masternode/meta.h
  • src/masternode/meta.cpp
src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • src/masternode/meta.h
  • src/masternode/meta.cpp
🧠 Learnings (7)
📓 Common learnings
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.
Learnt from: kwvg
Repo: dashpay/dash PR: 6543
File: src/wallet/receive.cpp:240-251
Timestamp: 2025-02-06T14:34:30.466Z
Learning: Pull request #6543 is focused on move-only changes and refactoring, specifically backporting from Bitcoin. Behavior changes should be proposed in separate PRs.
Learnt from: kwvg
Repo: dashpay/dash PR: 6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.
Learnt from: kwvg
Repo: dashpay/dash PR: 6761
File: src/chainlock/signing.cpp:247-250
Timestamp: 2025-07-29T14:32:48.369Z
Learning: In PR #6761, kwvg acknowledged a null pointer check issue in ChainLockSigner::Cleanup() method but deferred it to follow-up, consistent with the pattern of avoiding scope creep in refactoring PRs.
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp} : Masternode lists must use immutable data structures (Immer library) for thread safety
📚 Learning: 2025-07-20T18:42:49.794Z
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp} : Masternode lists must use immutable data structures (Immer library) for thread safety

Applied to files:

  • src/masternode/meta.h
  • src/masternode/meta.cpp
📚 Learning: 2025-06-06T11:53:09.094Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6665
File: src/evo/providertx.h:82-82
Timestamp: 2025-06-06T11:53:09.094Z
Learning: In ProTx serialization code (SERIALIZE_METHODS), version checks should use hardcoded maximum flags (/*is_basic_scheme_active=*/true, /*is_extended_addr=*/true) rather than deployment-based flags. This is because serialization code should be able to deserialize any structurally valid ProTx up to the maximum version the code knows how to handle, regardless of current consensus validity. Validation code, not serialization code, is responsible for checking whether a ProTx version is consensus-valid based on deployment status.

Applied to files:

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

Applied to files:

  • src/masternode/meta.h
📚 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/meta.cpp
📚 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/meta.cpp
📚 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/masternode/meta.cpp
🧬 Code graph analysis (2)
src/masternode/meta.h (1)
src/masternode/meta.cpp (42)
  • ToJson (38-54)
  • ToJson (38-38)
  • AddGovernanceVote (56-62)
  • AddGovernanceVote (56-56)
  • AddGovernanceVote (130-134)
  • AddGovernanceVote (130-130)
  • RemoveGovernanceObject (64-68)
  • RemoveGovernanceObject (64-64)
  • RemoveGovernanceObject (136-142)
  • RemoveGovernanceObject (136-136)
  • SetLastOutboundAttempt (151-155)
  • SetLastOutboundAttempt (151-151)
  • SetLastOutboundSuccess (157-161)
  • SetLastOutboundSuccess (157-157)
  • SetPlatformBan (197-208)
  • SetPlatformBan (197-197)
  • GetMetaInfo (83-91)
  • GetMetaInfo (83-83)
  • GetMetaInfoOrDefault (70-75)
  • GetMetaInfoOrDefault (70-70)
  • GetInfo (77-81)
  • GetInfo (77-77)
  • IsDsqOver (93-108)
  • IsDsqOver (93-93)
  • AllowMixing (110-116)
  • AllowMixing (110-110)
  • DisallowMixing (118-122)
  • DisallowMixing (118-118)
  • IsValidForMixingTxes (124-128)
  • IsValidForMixingTxes (124-124)
  • GetAndClearDirtyGovernanceObjectHashes (144-149)
  • GetAndClearDirtyGovernanceObjectHashes (144-144)
  • GetLastOutboundAttempt (163-167)
  • GetLastOutboundAttempt (163-163)
  • GetLastOutboundSuccess (169-173)
  • GetLastOutboundSuccess (169-169)
  • OutboundFailedTooManyTimes (175-179)
  • OutboundFailedTooManyTimes (175-175)
  • IsPlatformBanned (181-185)
  • IsPlatformBanned (181-181)
  • ResetPlatformBan (187-195)
  • ResetPlatformBan (187-187)
src/masternode/meta.cpp (1)
src/masternode/meta.h (10)
  • m_last_dsq (34-34)
  • m_mixing_tx_count (35-35)
  • outboundAttemptCount (40-40)
  • lastOutboundAttempt (41-41)
  • lastOutboundSuccess (42-42)
  • m_platform_ban (45-85)
  • m_platform_ban_updated (47-47)
  • nDsqCount (95-95)
  • SetLastOutboundSuccess (71-71)
  • SetPlatformBan (73-84)
⏰ 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). (6)
  • GitHub Check: x86_64-apple-darwin / Build depends
  • GitHub Check: x86_64-w64-mingw32 / Build depends
  • GitHub Check: x86_64-pc-linux-gnu / Build depends
  • GitHub Check: arm-linux-gnueabihf / Build depends
  • GitHub Check: x86_64-pc-linux-gnu_multiprocess / Build depends
  • GitHub Check: x86_64-pc-linux-gnu_nowallet / Build depends
🔇 Additional comments (6)
src/masternode/meta.h (2)

30-85: Value-based design correctly removes internal locking.

The refactoring to expose fields directly and rely on external locking at the manager level is sound. All access patterns are now guarded by CMasternodeMetaMan::cs, eliminating the overhead of per-entry atomics and mutexes.


203-204: Private accessor methods correctly require caller to hold lock.

GetMetaInfo and GetMetaInfoOrDefault are annotated with EXCLUSIVE_LOCKS_REQUIRED(cs), ensuring they're only called from within locked contexts. This aligns with the value-based refactoring goal.

src/masternode/meta.cpp (4)

13-18: Constants and default instance are well-placed.

Using constexpr for the thresholds and an anonymous-namespace default instance for CMasternodeMetaInfo is clean and efficient.


70-81: GetMetaInfoOrDefault and GetInfo correctly handle missing entries.

GetMetaInfoOrDefault returns a const reference to a default instance when the entry is not found, avoiding unnecessary allocations. GetInfo returns a copy for safe cross-lock-boundary access.


110-122: AllowMixing and DisallowMixing correctly update metadata.

Both methods properly acquire the lock and update the relevant fields. The pre-increment of nDsqCount in line 114 is clean.


151-208: Outbound and platform ban methods are well-structured.

All methods correctly acquire cs, delegate to per-entry methods or access fields directly, and return the appropriate values. The platform ban logic in SetPlatformBan properly integrates with the LRU cache.

@knst knst requested a review from UdjinM6 November 11, 2025 19:55
UdjinM6
UdjinM6 previously approved these changes Nov 13, 2025
Copy link

@UdjinM6 UdjinM6 left a comment

Choose a reason for hiding this comment

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

utACK 16915ff

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 (1)
src/masternode/meta.h (1)

31-32: Keep the stored proTx hash immutable.

m_protx_hash is the identity that ties a meta entry to the metaInfos map key. Making it mutable invites accidental reassignments (now that the field is public), leaving the stored value out of sync with the key and breaking lookups. Please keep this member const (as it effectively was before) and initialize it in the constructors; if copy assignment ever becomes necessary we can provide a custom implementation.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 982b68e and 0386115.

📒 Files selected for processing (1)
  • src/masternode/meta.h (7 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • src/masternode/meta.h
src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • src/masternode/meta.h
🧠 Learnings (4)
📓 Common learnings
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.
Learnt from: kwvg
Repo: dashpay/dash PR: 6543
File: src/wallet/receive.cpp:240-251
Timestamp: 2025-02-06T14:34:30.466Z
Learning: Pull request #6543 is focused on move-only changes and refactoring, specifically backporting from Bitcoin. Behavior changes should be proposed in separate PRs.
Learnt from: kwvg
Repo: dashpay/dash PR: 6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.
Learnt from: kwvg
Repo: dashpay/dash PR: 6761
File: src/chainlock/signing.cpp:247-250
Timestamp: 2025-07-29T14:32:48.369Z
Learning: In PR #6761, kwvg acknowledged a null pointer check issue in ChainLockSigner::Cleanup() method but deferred it to follow-up, consistent with the pattern of avoiding scope creep in refactoring PRs.
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp} : Masternode lists must use immutable data structures (Immer library) for thread safety
📚 Learning: 2025-07-20T18:42:49.794Z
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp} : Masternode lists must use immutable data structures (Immer library) for thread safety

Applied to files:

  • src/masternode/meta.h
📚 Learning: 2025-06-06T11:53:09.094Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6665
File: src/evo/providertx.h:82-82
Timestamp: 2025-06-06T11:53:09.094Z
Learning: In ProTx serialization code (SERIALIZE_METHODS), version checks should use hardcoded maximum flags (/*is_basic_scheme_active=*/true, /*is_extended_addr=*/true) rather than deployment-based flags. This is because serialization code should be able to deserialize any structurally valid ProTx up to the maximum version the code knows how to handle, regardless of current consensus validity. Validation code, not serialization code, is responsible for checking whether a ProTx version is consensus-valid based on deployment status.

Applied to files:

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

Applied to files:

  • src/masternode/meta.h
🧬 Code graph analysis (1)
src/masternode/meta.h (1)
src/masternode/meta.cpp (42)
  • ToJson (38-54)
  • ToJson (38-38)
  • AddGovernanceVote (56-62)
  • AddGovernanceVote (56-56)
  • AddGovernanceVote (130-134)
  • AddGovernanceVote (130-130)
  • RemoveGovernanceObject (64-68)
  • RemoveGovernanceObject (64-64)
  • RemoveGovernanceObject (136-142)
  • RemoveGovernanceObject (136-136)
  • SetLastOutboundAttempt (151-155)
  • SetLastOutboundAttempt (151-151)
  • SetLastOutboundSuccess (157-161)
  • SetLastOutboundSuccess (157-157)
  • SetPlatformBan (197-208)
  • SetPlatformBan (197-197)
  • GetMetaInfo (83-91)
  • GetMetaInfo (83-83)
  • GetMetaInfoOrDefault (70-75)
  • GetMetaInfoOrDefault (70-70)
  • GetInfo (77-81)
  • GetInfo (77-77)
  • IsDsqOver (93-108)
  • IsDsqOver (93-93)
  • AllowMixing (110-116)
  • AllowMixing (110-110)
  • DisallowMixing (118-122)
  • DisallowMixing (118-118)
  • IsValidForMixingTxes (124-128)
  • IsValidForMixingTxes (124-124)
  • GetAndClearDirtyGovernanceObjectHashes (144-149)
  • GetAndClearDirtyGovernanceObjectHashes (144-144)
  • GetLastOutboundAttempt (163-167)
  • GetLastOutboundAttempt (163-163)
  • GetLastOutboundSuccess (169-173)
  • GetLastOutboundSuccess (169-169)
  • OutboundFailedTooManyTimes (175-179)
  • OutboundFailedTooManyTimes (175-175)
  • IsPlatformBanned (181-185)
  • IsPlatformBanned (181-181)
  • ResetPlatformBan (187-195)
  • ResetPlatformBan (187-187)
⏰ 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_ubsan-build / Build source
  • GitHub Check: linux64_tsan-build / Build source
  • GitHub Check: mac-build / Build source
  • GitHub Check: arm-linux-build / Build source
  • GitHub Check: linux64_nowallet-build / Build source
  • GitHub Check: win64-build / Build source
  • GitHub Check: Lint / Run linters

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 (2)
src/masternode/meta.h (2)

129-131: Clarify move semantics by capturing the key before move.

While the current code is safe (C++17 guarantees left-to-right evaluation and uint256 is likely trivially copyable), accessing mm.m_protx_hash in the same expression as std::move(mm) is potentially confusing.

Consider this refactor for improved clarity:

 for (auto& mm : tmpMetaInfo) {
-    metaInfos.emplace(mm.m_protx_hash, CMasternodeMetaInfo{std::move(mm)});
+    const uint256 protx_hash = mm.m_protx_hash;
+    metaInfos.emplace(protx_hash, std::move(mm));
 }

106-109: Consider reserving vector capacity for serialization.

Pre-allocating space for the temporary vector would avoid potential reallocations during the copy loop.

 std::vector<CMasternodeMetaInfo> tmpMetaInfo;
+tmpMetaInfo.reserve(metaInfos.size());
 for (const auto& p : metaInfos) {
     tmpMetaInfo.emplace_back(p.second);
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0386115 and 16915ff.

📒 Files selected for processing (1)
  • src/masternode/meta.h (7 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • src/masternode/meta.h
src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • src/masternode/meta.h
🧠 Learnings (4)
📓 Common learnings
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.
Learnt from: kwvg
Repo: dashpay/dash PR: 6543
File: src/wallet/receive.cpp:240-251
Timestamp: 2025-02-06T14:34:30.466Z
Learning: Pull request #6543 is focused on move-only changes and refactoring, specifically backporting from Bitcoin. Behavior changes should be proposed in separate PRs.
Learnt from: kwvg
Repo: dashpay/dash PR: 6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.
Learnt from: kwvg
Repo: dashpay/dash PR: 6761
File: src/chainlock/signing.cpp:247-250
Timestamp: 2025-07-29T14:32:48.369Z
Learning: In PR #6761, kwvg acknowledged a null pointer check issue in ChainLockSigner::Cleanup() method but deferred it to follow-up, consistent with the pattern of avoiding scope creep in refactoring PRs.
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp} : Masternode lists must use immutable data structures (Immer library) for thread safety
📚 Learning: 2025-07-20T18:42:49.794Z
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp} : Masternode lists must use immutable data structures (Immer library) for thread safety

Applied to files:

  • src/masternode/meta.h
📚 Learning: 2025-06-06T11:53:09.094Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6665
File: src/evo/providertx.h:82-82
Timestamp: 2025-06-06T11:53:09.094Z
Learning: In ProTx serialization code (SERIALIZE_METHODS), version checks should use hardcoded maximum flags (/*is_basic_scheme_active=*/true, /*is_extended_addr=*/true) rather than deployment-based flags. This is because serialization code should be able to deserialize any structurally valid ProTx up to the maximum version the code knows how to handle, regardless of current consensus validity. Validation code, not serialization code, is responsible for checking whether a ProTx version is consensus-valid based on deployment status.

Applied to files:

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

Applied to files:

  • src/masternode/meta.h
🧬 Code graph analysis (1)
src/masternode/meta.h (1)
src/masternode/meta.cpp (42)
  • ToJson (38-54)
  • ToJson (38-38)
  • AddGovernanceVote (56-62)
  • AddGovernanceVote (56-56)
  • AddGovernanceVote (130-134)
  • AddGovernanceVote (130-130)
  • RemoveGovernanceObject (64-68)
  • RemoveGovernanceObject (64-64)
  • RemoveGovernanceObject (136-142)
  • RemoveGovernanceObject (136-136)
  • SetLastOutboundAttempt (151-155)
  • SetLastOutboundAttempt (151-151)
  • SetLastOutboundSuccess (157-161)
  • SetLastOutboundSuccess (157-157)
  • SetPlatformBan (197-208)
  • SetPlatformBan (197-197)
  • GetMetaInfo (83-91)
  • GetMetaInfo (83-83)
  • GetMetaInfoOrDefault (70-75)
  • GetMetaInfoOrDefault (70-70)
  • GetInfo (77-81)
  • GetInfo (77-77)
  • IsDsqOver (93-108)
  • IsDsqOver (93-93)
  • AllowMixing (110-116)
  • AllowMixing (110-110)
  • DisallowMixing (118-122)
  • DisallowMixing (118-118)
  • IsValidForMixingTxes (124-128)
  • IsValidForMixingTxes (124-124)
  • GetAndClearDirtyGovernanceObjectHashes (144-149)
  • GetAndClearDirtyGovernanceObjectHashes (144-144)
  • GetLastOutboundAttempt (163-167)
  • GetLastOutboundAttempt (163-163)
  • GetLastOutboundSuccess (169-173)
  • GetLastOutboundSuccess (169-169)
  • OutboundFailedTooManyTimes (175-179)
  • OutboundFailedTooManyTimes (175-175)
  • IsPlatformBanned (181-185)
  • IsPlatformBanned (181-181)
  • ResetPlatformBan (187-195)
  • ResetPlatformBan (187-187)
⏰ 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_multiprocess-build / Build source
  • GitHub Check: mac-build / Build source
  • GitHub Check: linux64_sqlite-build / Build source
  • GitHub Check: linux64_fuzz-build / Build source
  • GitHub Check: linux64-build / Build source
  • GitHub Check: linux64_ubsan-build / Build source
  • GitHub Check: linux64_tsan-build / Build source
  • GitHub Check: arm-linux-build / Build source
  • GitHub Check: linux64_nowallet-build / Build source
  • GitHub Check: win64-build / Build source
🔇 Additional comments (2)
src/masternode/meta.h (2)

28-85: LGTM! Clean refactor to value-based semantics.

The transition from mutex-guarded, pointer-backed entries to a public value structure is well-executed. All fields are appropriately public since access is controlled by CMasternodeMetaMan::cs. The SetPlatformBan logic correctly prevents stale or redundant updates.


203-241: LGTM! Well-structured manager API with proper locking.

The expanded public API follows a clean pattern:

  • Private helpers (GetMetaInfo, GetMetaInfoOrDefault) require cs held
  • Public methods acquire cs and delegate to private helpers
  • Locking annotations are consistent and correct

The move from per-object to manager-level locking simplifies the design and is well-suited to the brief access patterns across the codebase.

// MN's threshold is calculated as the last dsq count this specific masternode was used in a mixing
// session plus a margin of 20% of masternode count. In other words we expect at least 20% of unique
// masternodes before we ever see a masternode that we know already mixed someone's funds earlier.
bool IsDsqOver(const uint256& protx_hash, int mn_count) const EXCLUSIVE_LOCKS_REQUIRED(!cs);
Copy link
Member

Choose a reason for hiding this comment

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

IsDsqOver as name doesn't make a lot of sense to me. Should it be, DidMasternodeMixRecently or CanMasternodeMix or something like that @coderabbitai, please propose some better names if you have better ideas than those.

Copy link

Choose a reason for hiding this comment

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

@PastaPastaPasta, I agree that IsDsqOver could be clearer. Here are some naming alternatives based on the method's behavior (returns true when a masternode has been used too recently for mixing and should be skipped):

Option 1: HasMasternodeExceededMixingThreshold

  • Most explicit about both what's being checked and the threshold concept
  • Clear boolean semantics: true = exceeded, false = hasn't exceeded
  • Longer but unambiguous

Option 2: IsMasternodeRecentlyUsedForMixing

  • More natural language, immediately understandable
  • Shorter while still being clear
  • "Recently" captures the time-based threshold aspect

Option 3: ShouldSkipMasternodeForMixing

  • Action-oriented name that matches how it's used in the code
  • Very clear intent: true = skip it, false = use it
  • Aligns well with usage patterns in the codebase

Option 4: WasMasternodeUsedTooRecently (slight variation)

  • Past tense emphasizes the check is about historical usage
  • "Too recently" incorporates the threshold notion
  • Natural phrasing

My recommendation would be Option 2 (IsMasternodeRecentlyUsedForMixing) or Option 3 (ShouldSkipMasternodeForMixing), as they strike the best balance between clarity and conciseness. Option 3 might be slightly better since it directly expresses the decision outcome rather than requiring the caller to interpret what "recently used" means for their use case.

What do you think?


🧠 Learnings used
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.).

Learnt from: kwvg
Repo: dashpay/dash PR: 6665
File: src/evo/providertx.h:82-82
Timestamp: 2025-06-06T11:53:09.094Z
Learning: In ProTx serialization code (SERIALIZE_METHODS), version checks should use hardcoded maximum flags (/*is_basic_scheme_active=*/true, /*is_extended_addr=*/true) rather than deployment-based flags. This is because serialization code should be able to deserialize any structurally valid ProTx up to the maximum version the code knows how to handle, regardless of current consensus validity. Validation code, not serialization code, is responsible for checking whether a ProTx version is consensus-valid based on deployment status.

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.

Learnt from: kwvg
Repo: dashpay/dash PR: 6543
File: src/wallet/receive.cpp:240-251
Timestamp: 2025-02-06T14:34:30.466Z
Learning: Pull request #6543 is focused on move-only changes and refactoring, specifically backporting from Bitcoin. Behavior changes should be proposed in separate PRs.

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

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

Copy link
Member

Choose a reason for hiding this comment

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

@knst pls apply something like this; otherwise, I'm happy with it

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I used IsMixingThresholdExceeded because it's a member of CMasternodeMetaMan and it has an argument protx_hash so it's already tell that it is masternode's related method (along all other members that has protx_hash as an argument)

exception = CGovernanceException(msg, GOVERNANCE_EXCEPTION_PERMANENT_ERROR);
return false;
}
mn_metaman.AddGovernanceVote(dmn->proTxHash, vote.GetParentHash());
Copy link
Member

Choose a reason for hiding this comment

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

can this no longer fail?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

See 969b841

LOCK(cs);
// Insert a zero value, or not. Then increment the value regardless. This
// ensures the value is in the map.
const auto& pair = mapGovernanceObjectsVotedOn.emplace(nGovernanceObjectHash, 0);
Copy link
Member

Choose a reason for hiding this comment

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

does mapGovernanceObjectsVotedOnnot need to be guarded?

Comment on lines -38 to +42
private:
mutable Mutex cs;

uint256 proTxHash GUARDED_BY(cs);
public:
uint256 m_protx_hash;

//the dsq count from the last dsq broadcast of this node
std::atomic<int64_t> nLastDsq{0};
std::atomic<int> nMixingTxCount{0};
//! the dsq count from the last dsq broadcast of this node
int64_t m_last_dsq{0};
int m_mixing_tx_count{0};

// KEEP TRACK OF GOVERNANCE ITEMS EACH MASTERNODE HAS VOTE UPON FOR RECALCULATION
std::map<uint256, int> mapGovernanceObjectsVotedOn GUARDED_BY(cs);
std::map<uint256, int> mapGovernanceObjectsVotedOn;

std::atomic<int> outboundAttemptCount{0};
std::atomic<int64_t> lastOutboundAttempt{0};
std::atomic<int64_t> lastOutboundSuccess{0};
int outboundAttemptCount{0};
int64_t lastOutboundAttempt{0};
int64_t lastOutboundSuccess{0};
Copy link
Member

Choose a reason for hiding this comment

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

please explain how these are thread safe

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

They are protected by cs murex of manager, check PR description

@knst knst requested a review from PastaPastaPasta November 19, 2025 21:41
Copy link

@UdjinM6 UdjinM6 left a comment

Choose a reason for hiding this comment

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

utACK 572bafd

@PastaPastaPasta PastaPastaPasta merged commit c9faf42 into dashpay:develop Nov 21, 2025
50 of 61 checks passed
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.

3 participants