-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat: share vecMasternodesUsed
across all wallets, improve its handling
#6875
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
✅ No Merge Conflicts DetectedThis PR currently has no conflicts with other open PRs. |
WalkthroughReplaces in-memory vecMasternodesUsed in CCoinJoinClientManager with CMasternodeMetaMan-based tracking keyed by masternode proTxHash. CCoinJoinClientManager::AddUsedMasternode signature changed to accept a uint256 proTxHash and callers were updated. Client exclusion, random selection, queue-joining, and logging now use proTxHash and delegate removal/counting to m_mn_metaman. CMasternodeMetaMan adds m_used_masternodes (deque) and m_used_masternodes_set plus thread-safe APIs (AddUsedMasternode, RemoveUsedMasternodes, GetUsedMasternodesCount, IsUsedMasternode), updates serialization to "CMasternodeMetaMan-Version-5", and persists/clears the new data. Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Warning Review ran into problems🔥 ProblemsGit: Failed to clone repository. Please run the 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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
-
src/coinjoin/client.cpp
(5 hunks) -
src/coinjoin/client.h
(1 hunks) -
src/masternode/meta.cpp
(2 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/coinjoin/client.h
src/masternode/meta.h
src/coinjoin/client.cpp
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
🧬 Code graph analysis (4)
src/coinjoin/client.h (2)
src/coinjoin/client.cpp (2)
AddUsedMasternode
(1024-1027)AddUsedMasternode
(1024-1024)src/masternode/meta.cpp (2)
AddUsedMasternode
(156-160)AddUsedMasternode
(156-156)
src/masternode/meta.h (2)
src/coinjoin/client.cpp (2)
AddUsedMasternode
(1024-1027)AddUsedMasternode
(1024-1024)src/masternode/meta.cpp (8)
AddUsedMasternode
(156-160)AddUsedMasternode
(156-156)RemoveUsedMasternodes
(162-170)RemoveUsedMasternodes
(162-162)GetUsedMasternodesCount
(172-176)GetUsedMasternodesCount
(172-172)GetUsedMasternodesSet
(178-182)GetUsedMasternodesSet
(178-178)
src/coinjoin/client.cpp (1)
src/masternode/meta.cpp (2)
AddUsedMasternode
(156-160)AddUsedMasternode
(156-156)
src/masternode/meta.cpp (1)
src/coinjoin/client.cpp (2)
AddUsedMasternode
(1024-1027)AddUsedMasternode
(1024-1024)
🪛 GitHub Actions: Clang Diff Format Check
src/coinjoin/client.cpp
[error] 1021-1021: Clang format differences detected. Differences shown between 'before formatting' and 'after formatting'. Command: git diff -U0 origin/develop --
[error] 1021-1027: Clang-format-diff reported formatting changes that need to be applied. Run the suggested formatting diff or execute the formatting tool to fix.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Build container / Build container
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM de30f58
src/masternode/meta.h
Outdated
// keep track of dsq count to prevent masternodes from gaming coinjoin queue | ||
std::atomic<int64_t> nDsqCount{0}; | ||
// keep track of the used Masternodes for CoinJoin | ||
std::vector<uint256> m_used_masternodes GUARDED_BY(cs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It really seems like bad design to use a vector here; The eviction policy isn't super clear as to the current behavior; but it seems an LRU cache or a std::set together with a std::list would better accomplish our goals here.
Granted this isn't like it's really in a hot loop; but it's still wasteful, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Claude made this - 9eadb70, seems reasonable :)
Improves performance by implementing a dual data structure approach for tracking used masternodes in CoinJoin sessions: - Use std::deque<uint256> for maintaining FIFO insertion order - Use std::unordered_set<uint256> for O(1) lookup performance - Replace GetUsedMasternodesSet() with IsUsedMasternode() to avoid expensive set construction on every masternode selection Performance improvements at 1800 used masternodes: - Masternode selection: 2.5ms → 0.1ms (25x faster) - Batch removal: 100µs → 27µs (4x faster) The optimization becomes increasingly important at scale (>1000 MNs) and in multi-wallet scenarios with concurrent CoinJoin sessions. Key design decisions: - Deque provides O(1) front removal (vs O(n) for vector) - Unordered_set provides O(1) lookup (vs O(n log n) set construction) - Only deque is serialized; set is rebuilt on load (no version bump) - Both structures stay synchronized through all operations - Automatic duplicate prevention in AddUsedMasternode() Memory cost: ~130 KB for 1800 entries (negligible) Code complexity: Minimal, well-encapsulated This builds on PR dashpay#6875 which moved masternode tracking from per-wallet to shared global storage. That PR solved the multi-wallet coordination problem; this patch addresses the performance bottleneck at scale.
Improves performance by implementing a dual data structure approach for tracking used masternodes in CoinJoin sessions: - Use std::deque<uint256> for maintaining FIFO insertion order - Use std::unordered_set<uint256> for O(1) lookup performance - Replace GetUsedMasternodesSet() with IsUsedMasternode() to avoid expensive set construction on every masternode selection Performance improvements at 1800 used masternodes: - Masternode selection: 2.5ms → 0.1ms (25x faster) - Batch removal: 100µs → 27µs (4x faster) The optimization becomes increasingly important at scale (>1000 MNs) and in multi-wallet scenarios with concurrent CoinJoin sessions. Key design decisions: - Deque provides O(1) front removal (vs O(n) for vector) - Unordered_set provides O(1) lookup (vs O(n log n) set construction) - Only deque is serialized; set is rebuilt on load (no version bump) - Both structures stay synchronized through all operations - Automatic duplicate prevention in AddUsedMasternode() Memory cost: ~130 KB for 1800 entries (negligible) Code complexity: Minimal, well-encapsulated This builds on PR dashpay#6875 which moved masternode tracking from per-wallet to shared global storage. That PR solved the multi-wallet coordination problem; this patch addresses the performance bottleneck at scale.
9eadb70
to
7ad1724
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
-
src/coinjoin/client.cpp
(5 hunks) -
src/masternode/meta.cpp
(2 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/coinjoin/client.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
🧬 Code graph analysis (3)
src/masternode/meta.cpp (1)
src/coinjoin/client.cpp (2)
AddUsedMasternode
(1024-1027)AddUsedMasternode
(1024-1024)
src/coinjoin/client.cpp (1)
src/masternode/meta.cpp (2)
AddUsedMasternode
(156-163)AddUsedMasternode
(156-156)
src/masternode/meta.h (2)
src/coinjoin/client.cpp (2)
AddUsedMasternode
(1024-1027)AddUsedMasternode
(1024-1024)src/masternode/meta.cpp (8)
AddUsedMasternode
(156-163)AddUsedMasternode
(156-156)RemoveUsedMasternodes
(165-175)RemoveUsedMasternodes
(165-165)GetUsedMasternodesCount
(177-181)GetUsedMasternodesCount
(177-177)IsUsedMasternode
(183-187)IsUsedMasternode
(183-183)
🪛 GitHub Actions: Clang Diff Format Check
src/coinjoin/client.cpp
[error] 1021-1021: Clang format differences detected. Run the clang-format-diff.py step or clang-format to fix formatting in src/coinjoin/client.cpp. Command that produced issue: git diff -U0 origin/develop --
⏰ 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: linux64_nowallet-build / Build source
- GitHub Check: mac-build / Build source
- GitHub Check: arm-linux-build / Build source
- GitHub Check: linux64_tsan-build / Build source
- GitHub Check: win64-build / Build source
- GitHub Check: linux64_sqlite-build / Build source
- GitHub Check: linux64-build / Build source
- GitHub Check: linux64_ubsan-build / Build source
- GitHub Check: linux64_fuzz-build / Build source
🔇 Additional comments (12)
src/masternode/meta.h (5)
135-138
: LGTM: Dual data structure is appropriate for FIFO eviction.The combination of
std::deque
for FIFO ordering andUint256HashSet
for O(1) lookups is a reasonable design. While the past review suggested an LRU cache, that would be inappropriate here since the eviction policy is FIFO (oldest entries removed first), not LRU. The implementation inmeta.cpp
correctly maintains synchronization between these two structures.
149-151
: LGTM: Serialization approach is sound.Converting the deque to a vector for serialization is correct, and the unordered_set is appropriately omitted since it can be reconstructed during deserialization.
166-177
: LGTM: Deserialization correctly reconstructs both structures.The deserialization properly rebuilds both
m_used_masternodes
(deque) andm_used_masternodes_set
from the serialized vector, maintaining consistency.
185-186
: LGTM: Clear() maintains structure consistency.Both data structures are properly cleared, maintaining synchronization.
269-273
: LGTM: Public API provides proper encapsulation.The new methods provide clean, encapsulated access to the used masternodes tracking functionality.
src/masternode/meta.cpp (4)
11-11
: LGTM: Serialization version correctly bumped.The version increment from 4 to 5 is appropriate given the addition of the new
m_used_masternodes
field to the serialized data.
156-163
: LGTM: Duplicate prevention is correctly implemented.The method correctly prevents duplicates by checking the set insertion result before appending to the deque, and thread safety is ensured via the lock.
165-175
: LGTM: FIFO removal correctly maintains structure synchronization.The method properly removes the oldest entries (FIFO) and keeps both the set and deque in sync by removing from both structures.
177-187
: LGTM: Accessor methods are correctly implemented.Both
GetUsedMasternodesCount()
andIsUsedMasternode()
properly leverage the appropriate data structure (deque for size, set for lookup) with correct thread safety.src/coinjoin/client.cpp (3)
1024-1026
: LGTM: Signature change aligns with proTxHash migration.The method now correctly accepts
proTxHash
instead ofCOutPoint
and properly delegates to the centralized tracking inCMasternodeMetaMan
.
1034-1059
: LGTM: Efficient O(1) lookup with centralized tracking.The changes correctly leverage
IsUsedMasternode()
for O(1) lookups via the unordered_set, and the migration from outpoint-based to proTxHash-based identification is complete and consistent.
1111-1111
: LGTM: Consistent proTxHash-based tracking across all call sites.Both
JoinExistingQueue
andStartNewQueue
correctly useproTxHash
for masternode tracking, ensuring consistency across the codebase.Also applies to: 1165-1165
"""
Was this actually benched? Or a guess by claude? |
It's a guess: estimationsPerformance MetricsBefore (Vector):
After (Hybrid):
Improvement:
but it also created a benchmark performance_test.cpp
and I'm getting numbers like this
(NOTE: |
This pull request has conflicts, please rebase. |
Improves performance by implementing a dual data structure approach for tracking used masternodes in CoinJoin sessions: - Use std::deque<uint256> for maintaining FIFO insertion order - Use std::unordered_set<uint256> for O(1) lookup performance - Replace GetUsedMasternodesSet() with IsUsedMasternode() to avoid expensive set construction on every masternode selection Performance improvements at 1800 used masternodes: - Masternode selection: 2.5ms → 0.1ms (25x faster) - Batch removal: 100µs → 27µs (4x faster) The optimization becomes increasingly important at scale (>1000 MNs) and in multi-wallet scenarios with concurrent CoinJoin sessions. Key design decisions: - Deque provides O(1) front removal (vs O(n) for vector) - Unordered_set provides O(1) lookup (vs O(n log n) set construction) - Only deque is serialized; set is rebuilt on load (no version bump) - Both structures stay synchronized through all operations - Automatic duplicate prevention in AddUsedMasternode() Memory cost: ~130 KB for 1800 entries (negligible) Code complexity: Minimal, well-encapsulated This builds on PR dashpay#6875 which moved masternode tracking from per-wallet to shared global storage. That PR solved the multi-wallet coordination problem; this patch addresses the performance bottleneck at scale.
7ad1724
to
3b0b595
Compare
Rebased after #6868 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/coinjoin/client.cpp (1)
1033-1038
: Clamp “not excluded” count to avoid size_t underflow.If used > enabled (possible across wallets/persistence), current subtraction underflows.
Apply:
- size_t nCountNotExcluded{nCountEnabled - m_mn_metaman.GetUsedMasternodesCount()}; + const size_t used = m_mn_metaman.GetUsedMasternodesCount(); + const size_t nCountNotExcluded = (used >= nCountEnabled) ? 0 : (nCountEnabled - used);
🧹 Nitpick comments (4)
src/masternode/meta.h (2)
135-139
: Add explicit invariant/capacity to prevent unbounded growth.Deque+unordered_set is fine, but this structure can grow indefinitely across restarts. Consider:
- Enforcing a hard cap (e.g., 2× valid MNs) and evicting from front on insert beyond cap.
- Or, use unordered_lru_cache<uint256, bool, StaticSaltedHasher> to get built‑in LRU eviction and O(1) membership, per project practice.
As per coding guidelines
166-178
: Deserialization rebuilds both containers correctly.Assigning deque and rebuilding the set is correct and keeps O(1) checks. Consider asserting sizes match in debug to catch divergence.
src/coinjoin/client.cpp (1)
1111-1112
: Confirm intent: marking MN as “used” before connection/eligibility checks.You add to “used” prior to winner/connection/dsq checks. This prevents reattempts across wallets, but can also exclude nodes never actually mixed. Confirm this is desired; otherwise, add conditionally after successful queue join/start.
Also applies to: 1165-1166
src/masternode/meta.cpp (1)
165-175
: FIFO removal keeps structures in sync.Implementation is correct. Optionally assert sizes remain equal in debug.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
-
src/coinjoin/client.cpp
(5 hunks) -
src/coinjoin/client.h
(1 hunks) -
src/masternode/meta.cpp
(2 hunks) -
src/masternode/meta.h
(5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/coinjoin/client.h
🧰 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/coinjoin/client.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/masternode/meta.h
src/masternode/meta.cpp
🧬 Code graph analysis (3)
src/coinjoin/client.cpp (1)
src/masternode/meta.cpp (2)
AddUsedMasternode
(156-163)AddUsedMasternode
(156-156)
src/masternode/meta.h (2)
src/masternode/meta.cpp (8)
AddUsedMasternode
(156-163)AddUsedMasternode
(156-156)RemoveUsedMasternodes
(165-175)RemoveUsedMasternodes
(165-165)GetUsedMasternodesCount
(177-181)GetUsedMasternodesCount
(177-177)IsUsedMasternode
(183-187)IsUsedMasternode
(183-183)src/coinjoin/client.cpp (2)
AddUsedMasternode
(1024-1027)AddUsedMasternode
(1024-1024)
src/masternode/meta.cpp (2)
src/coinjoin/client.cpp (2)
AddUsedMasternode
(1024-1027)AddUsedMasternode
(1024-1024)src/masternode/meta.h (2)
cs
(55-80)cs
(57-57)
🪛 GitHub Actions: Clang Diff Format Check
src/coinjoin/client.cpp
[error] 1021-1021: Clang-format differences detected for the file. The diff shows formatting changes between before/after formatting. Command: 'git diff -U0 origin/develop --
⏰ 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_tsan-build / Build source
- GitHub Check: linux64_nowallet-build / Build source
- GitHub Check: arm-linux-build / Build source
- GitHub Check: win64-build / Build source
- GitHub Check: linux64_ubsan-build / Build source
- GitHub Check: linux64_sqlite-build / Build source
- GitHub Check: linux64_fuzz-build / Build source
- GitHub Check: linux64-build / Build source
🔇 Additional comments (12)
src/masternode/meta.h (4)
17-17
: Header include looks good.Adding is appropriate for the new FIFO container.
149-152
: Serialization order/version OK; consider forward-compat note.Converting deque→vector for wire is fine. Since version bumped to 5 in meta.cpp, older caches (v4) will be ignored. If that’s intentional, fine; otherwise, add backward handling to accept v4 (and default m_used_masternodes to empty).
185-187
: Clear() now clears new state as well.Good coverage.
269-274
: API surface is clear and thread-safe.Annotations indicate “do not hold cs” externally; methods lock internally. Consistent with usage in meta.cpp.
src/coinjoin/client.cpp (3)
1051-1059
: LGTM: O(1) membership check instead of copying set.Direct IsUsedMasternode lookup avoids building a temporary set. Good.
1024-1027
: Forwarder to metaman is clean.
994-1000
: Run clang-format on src/coinjoin/client.cpp
CI is reporting formatting mismatches butclang-format
isn’t available here; please install/run clang-format locally on this file and commit the updated formatting.src/masternode/meta.cpp (5)
11-11
: Version bump to V5.Matches new serialized field. Ensure release notes mention dropping V4 cache on mismatch.
156-163
: Duplicate-safe insert with O(1) membership.Good use of set+deque to avoid duplicates and keep order for eviction.
177-181
: Count via deque size OK.
183-187
: O(1) lookup via set OK.
189-194
: ToString locks internally; adds used count.Good observability improvement.
// If we've used 90% of the Masternode list then drop the oldest first ~30% | ||
int nThreshold_high = nMnCountEnabled * 0.9; | ||
int nThreshold_low = nThreshold_high * 0.7; | ||
WalletCJLogPrint(m_wallet, "Checking vecMasternodesUsed: size: %d, threshold: %d\n", (int)vecMasternodesUsed.size(), nThreshold_high); | ||
size_t nUsedMasternodes{m_mn_metaman.GetUsedMasternodesCount()}; | ||
|
||
if ((int)vecMasternodesUsed.size() > nThreshold_high) { | ||
vecMasternodesUsed.erase(vecMasternodesUsed.begin(), vecMasternodesUsed.begin() + vecMasternodesUsed.size() - nThreshold_low); | ||
WalletCJLogPrint(m_wallet, " vecMasternodesUsed: new size: %d, threshold: %d\n", (int)vecMasternodesUsed.size(), nThreshold_high); | ||
WalletCJLogPrint(m_wallet, "Checking nUsedMasternodes: %d, threshold: %d\n", (int)nUsedMasternodes, nThreshold_high); | ||
|
||
if ((int)nUsedMasternodes > nThreshold_high) { | ||
size_t nToRemove{nUsedMasternodes - nThreshold_low}; | ||
m_mn_metaman.RemoveUsedMasternodes(nToRemove); | ||
WalletCJLogPrint(m_wallet, " new nUsedMasternodes: %d, threshold: %d\n", | ||
(int)m_mn_metaman.GetUsedMasternodesCount(), nThreshold_high); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid FP math and signed/unsigned mixing in thresholds; compute in size_t.
Use integer math and keep types consistent to prevent truncation and potential wraparounds.
Apply:
- int nThreshold_high = nMnCountEnabled * 0.9;
- int nThreshold_low = nThreshold_high * 0.7;
- size_t nUsedMasternodes{m_mn_metaman.GetUsedMasternodesCount()};
- WalletCJLogPrint(m_wallet, "Checking nUsedMasternodes: %d, threshold: %d\n", (int)nUsedMasternodes, nThreshold_high);
- if ((int)nUsedMasternodes > nThreshold_high) {
- size_t nToRemove{nUsedMasternodes - nThreshold_low};
+ const size_t nThreshold_high = (static_cast<size_t>(nMnCountEnabled) * 9) / 10;
+ const size_t nThreshold_low = (nThreshold_high * 7) / 10;
+ const size_t nUsedMasternodes = m_mn_metaman.GetUsedMasternodesCount();
+ WalletCJLogPrint(m_wallet, "Checking nUsedMasternodes: %d, threshold: %d\n",
+ static_cast<int>(nUsedMasternodes), static_cast<int>(nThreshold_high));
+ if (nUsedMasternodes > nThreshold_high) {
+ const size_t nToRemove = nUsedMasternodes - nThreshold_low;
m_mn_metaman.RemoveUsedMasternodes(nToRemove);
WalletCJLogPrint(m_wallet, " new nUsedMasternodes: %d, threshold: %d\n",
- (int)m_mn_metaman.GetUsedMasternodesCount(), nThreshold_high);
+ static_cast<int>(m_mn_metaman.GetUsedMasternodesCount()),
+ static_cast<int>(nThreshold_high));
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
// If we've used 90% of the Masternode list then drop the oldest first ~30% | |
int nThreshold_high = nMnCountEnabled * 0.9; | |
int nThreshold_low = nThreshold_high * 0.7; | |
WalletCJLogPrint(m_wallet, "Checking vecMasternodesUsed: size: %d, threshold: %d\n", (int)vecMasternodesUsed.size(), nThreshold_high); | |
size_t nUsedMasternodes{m_mn_metaman.GetUsedMasternodesCount()}; | |
if ((int)vecMasternodesUsed.size() > nThreshold_high) { | |
vecMasternodesUsed.erase(vecMasternodesUsed.begin(), vecMasternodesUsed.begin() + vecMasternodesUsed.size() - nThreshold_low); | |
WalletCJLogPrint(m_wallet, " vecMasternodesUsed: new size: %d, threshold: %d\n", (int)vecMasternodesUsed.size(), nThreshold_high); | |
WalletCJLogPrint(m_wallet, "Checking nUsedMasternodes: %d, threshold: %d\n", (int)nUsedMasternodes, nThreshold_high); | |
if ((int)nUsedMasternodes > nThreshold_high) { | |
size_t nToRemove{nUsedMasternodes - nThreshold_low}; | |
m_mn_metaman.RemoveUsedMasternodes(nToRemove); | |
WalletCJLogPrint(m_wallet, " new nUsedMasternodes: %d, threshold: %d\n", | |
(int)m_mn_metaman.GetUsedMasternodesCount(), nThreshold_high); | |
} | |
// If we've used 90% of the Masternode list then drop the oldest first ~30% | |
const size_t nThreshold_high = (static_cast<size_t>(nMnCountEnabled) * 9) / 10; | |
const size_t nThreshold_low = (nThreshold_high * 7) / 10; | |
const size_t nUsedMasternodes = m_mn_metaman.GetUsedMasternodesCount(); | |
WalletCJLogPrint(m_wallet, "Checking nUsedMasternodes: %d, threshold: %d\n", | |
static_cast<int>(nUsedMasternodes), static_cast<int>(nThreshold_high)); | |
if (nUsedMasternodes > nThreshold_high) { | |
const size_t nToRemove = nUsedMasternodes - nThreshold_low; | |
m_mn_metaman.RemoveUsedMasternodes(nToRemove); | |
WalletCJLogPrint(m_wallet, " new nUsedMasternodes: %d, threshold: %d\n", | |
static_cast<int>(m_mn_metaman.GetUsedMasternodesCount()), | |
static_cast<int>(nThreshold_high)); | |
} |
🤖 Prompt for AI Agents
In src/coinjoin/client.cpp around lines 989-1001, the thresholds use
floating-point literals and mix signed/unsigned types causing truncation and
wrap risks; compute thresholds using integer math and size_t throughout. Change
nThreshold_high and nThreshold_low to size_t and compute them with integer
operations, e.g. nThreshold_high = (nMnCountEnabled * 9) / 10 and nThreshold_low
= (nMnCountEnabled * 7) / 10 (or derive low from high with
multiplication/division using size_t), then compare and compute nToRemove using
size_t so there is no signed/unsigned or FP mixing.
3b0b595
to
a797abe
Compare
There was a problem hiding this 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.cpp (1)
183-187
: Consider using C++20contains()
for idiomatic code.The logic is correct. For C++20 codebases,
contains()
is more idiomatic thanfind() != end()
.Apply this diff for a minor readability improvement:
bool CMasternodeMetaMan::IsUsedMasternode(const uint256& proTxHash) const { LOCK(cs); - return m_used_masternodes_set.find(proTxHash) != m_used_masternodes_set.end(); + return m_used_masternodes_set.contains(proTxHash); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/masternode/meta.cpp
(2 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,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
🔇 Additional comments (5)
src/masternode/meta.cpp (5)
11-11
: LGTM! Serialization version correctly bumped.The version increment from 4 to 5 is appropriate given the addition of persistent
m_used_masternodes
data structures.
156-163
: LGTM! Duplicate prevention and consistency maintained.The method correctly prevents duplicates by checking
insert().second
before adding to the deque, ensuring both data structures remain consistent.
165-175
: LGTM! FIFO removal correctly implemented.The method safely removes the oldest entries while maintaining consistency between the set and deque. Edge cases (empty deque, excessive count) are properly handled.
177-181
: LGTM! Thread-safe getter.
189-194
: LGTM! Improved observability.The addition of used masternodes count to the string output enhances debugging and monitoring capabilities.
Issue being fixed or feature implemented
vecMasternodesUsed
has a few issues:StartNewQueue()
and fail to start mixing because of thatWhat was done?
MasternodeMetaStore
and renamed it tom_used_masternodes
std::vector<uint256>
(usingproTxHash
now)m_used_masternodes
is no longer accessed via multiple threads (because it's not cleared inResetPool()
) but I made it thread-safe anyway just in case (using existingRecursiveMutex cs
)How Has This Been Tested?
Mixing in multiple wallets at once
Breaking Changes
n/a
Checklist: