Skip to content

fix: dangling point to cj client#7259

Open
knst wants to merge 6 commits intodashpay:developfrom
knst:fix-cj-dangling-ptr
Open

fix: dangling point to cj client#7259
knst wants to merge 6 commits intodashpay:developfrom
knst:fix-cj-dangling-ptr

Conversation

@knst
Copy link
Copy Markdown
Collaborator

@knst knst commented Mar 29, 2026

Depends on #7248

Issue being fixed or feature implemented

Hold lock during flush operations to prevent TOCTOU race condition.

getClient() releases cs_wallet_manager_map before returning the raw pointer. If another thread calls removeWallet() concurrently, the unique_ptr is destroyed while flushWallet() still holds a reference, leading to use-after-free. This is inconsistent with removeWallet() which safely erases under the lock.

Discovered here #7248 (comment)

What was done?

Use doWithClient(name, [](){...}) instead of getClient(name)->...

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 24 milestone Mar 29, 2026
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 29, 2026

✅ No Merge Conflicts Detected

This PR currently has no conflicts with other open PRs.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: acb27a0efa

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +145 to +148
LOCK(cs_wallet_manager_map);
auto it = m_wallet_manager_map.find(name);
if (it == m_wallet_manager_map.end()) return false;
func(*it->second);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Do not invoke client callbacks while holding manager mutex

doForClient() now keeps cs_wallet_manager_map locked while running arbitrary callbacks, and several new callbacks call client.resetPool() (for example coinjoin reset in src/rpc/coinjoin.cpp and flushWallet() in this file), which takes wallet locks via CCoinJoinClientSession::ResetPool(). At the same time, wallet code can take the opposite order (cs_wallet then CoinJoin manager lock) through CWallet::NewKeyPoolCallback() calling WithClient() in src/wallet/wallet.cpp, creating a lock-order inversion that can deadlock under concurrent RPC/UI keypool operations and CoinJoin reset/flush paths.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

not, the whole point of PR is doing it under cs_wallet_manager_map mutex, otherwhise wallet maybe destroyed

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 29, 2026

Walkthrough

This PR refactors the CoinJoin subsystem's client access pattern from direct pointer return to callback-based invocation. It renames CoinJoin client methods to lowerCamelCase (StartMixingstartMixing, etc.), changes getJsonInfo from mutating an external UniValue parameter to returning a new UniValue, moves coinjoin/walletman.cpp from the node to wallet library archive, and replaces the GetClient() / getClient() API with WithClient() / doForClient() methods that accept callbacks executed under lock. All call sites in Qt, RPC, wallet initialization, and tests are updated to invoke client operations within the new callback pattern.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • UdjinM6
  • PastaPastaPasta
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title concisely identifies the main change—fixing a dangling pointer to the CoinJoin client—which matches the core issue addressed in the PR regarding TOCTOU race conditions and use-after-free vulnerability.
Description check ✅ Passed The description is directly related to the changeset, explaining the TOCTOU race condition issue, the solution (replacing getClient() with doWithClient()), and testing performed.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@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: 3

Caution

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

⚠️ Outside diff range comments (1)
src/Makefile.am (1)

656-660: ⚠️ Potential issue | 🔴 Critical

The library split still leaves a no-wallet link hole.

The new #ifdef ENABLE_WALLET in src/init.cpp removes the direct CJWalletManager::make() call, but src/net_processing.cpp is still built into libbitcoin_node.a and still uses CJWalletManager through PeerManager plus the hasQueue() / processMessage() call sites. With coinjoin/walletman.cpp moved only into libbitcoin_wallet.a, a --disable-wallet build no longer has an implementation owner for that surface. Either keep coinjoin/walletman.cpp in libbitcoin_node.a for now, or finish moving the remaining CJWalletManager references behind wallet-only code first.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Makefile.am` around lines 656 - 660, The build splits wallet sources into
libbitcoin_wallet.a but leaves references to CJWalletManager in code still built
into libbitcoin_node.a (notably net_processing.cpp via PeerManager and the
hasQueue()/processMessage() call sites), causing unresolved links when
--disable-wallet is used; either move coinjoin/walletman.cpp back into the node
archive or gate all usages of CJWalletManager (and any calls to
PeerManager::hasQueue()/processMessage() that forward to it) behind the same
ENABLE_WALLET conditional as used in init.cpp so that net_processing.cpp no
longer references CJWalletManager when wallets are disabled; update the
Makefile.am entry for libbitcoin_node_a_SOURCES or wrap the
CJWalletManager-using code paths in net_processing.cpp/PeerManager with `#ifdef`
ENABLE_WALLET to restore a consistent implementation owner.
🧹 Nitpick comments (7)
src/coinjoin/walletman.h (1)

51-53: Document the callback as non-reentrant.

func runs while the wallet-manager lock is held. A short note that callbacks must not call back into CJWalletManager would make that deadlock boundary explicit for future call sites.

📝 Suggested doc tweak
-    //! Execute func under the wallet manager lock for the client identified by name.
+    //! Execute func under the wallet manager lock for the client identified by name.
+    //! The callback must not re-enter CJWalletManager methods.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/coinjoin/walletman.h` around lines 51 - 53, The comment for doForClient
should explicitly document that the callback func is non-reentrant: add a short
sentence to the function comment (for doForClient) stating that func is invoked
while the wallet-manager lock is held and must not call back into
CJWalletManager or invoke any methods that may acquire the same wallet-manager
lock (to avoid deadlocks); reference CCoinJoinClientManager as the callback
parameter type and make the non-reentrancy constraint explicit so future callers
know not to call CJWalletManager methods from within func.
src/qt/overviewpage.cpp (2)

599-607: Potential incorrect state if client unavailable.

When withCoinJoin() fails to find the client, notMixing remains false (its initialization), which means the code path after line 607 treats this as if mixing is active. This could display incorrect UI state.

Consider initializing notMixing to true as a safer default:

♻️ Suggested safer default
-    bool notMixing{false};
+    bool notMixing{true};  // Default to not mixing if client unavailable
     walletModel->withCoinJoin([&](auto& client) {
         notMixing = !client.isMixing();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/qt/overviewpage.cpp` around lines 599 - 607, The current logic leaves
notMixing=false when withCoinJoin() can't find a client, causing the UI to
incorrectly show "mixing" active; change the default to true (bool
notMixing{true};) so absence of a client is treated as not mixing, and keep the
existing update inside walletModel->withCoinJoin(...) that sets notMixing =
!client.isMixing(), while preserving the cached-blocks check
(client.getCachedBlocks(), client.setCachedBlocks(...),
updateCoinJoinProgress()) so state stays correct when a client is present.

581-585: Unchecked return value could mask client availability issues.

The withCoinJoin() return value is ignored. If the client is not found, tooFast remains false and the UI update proceeds. While this is likely benign (the UI updates when it shouldn't skip), consider whether silent failure is the desired behavior across all these call sites, or if a missing client should be logged/handled differently.

This pattern is repeated throughout this file (lines 599-607, 665-666, 690-697, 714-715, 734, 745-755, 794).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/qt/overviewpage.cpp` around lines 581 - 585, withCoinJoin's boolean
return value is ignored so a missing client can be silently skipped; change the
call sites (e.g. the block using walletModel->withCoinJoin, the tooFast
assignment that references client.getCachedBlocks()) to capture the return value
and handle the false case explicitly: if withCoinJoin(...) returns false, log a
warning (or otherwise handle client-unavailable) and avoid treating tooFast as
valid, otherwise run the lambda to set tooFast using nBestHeight,
client.getCachedBlocks(), GetTime() and nLastDSProgressBlockTime; apply the same
pattern to all repeated sites in this file.
src/coinjoin/server.cpp (2)

193-193: Inconsistent synchronization strategy: TryAddQueue vs AddQueue.

ProcessDSQUEUE uses the non-blocking TryAddQueue() which silently fails if the lock is contended, while CreateNewSession (line 728) and CheckForCompleteQueue (line 520) use the blocking AddQueue().

This inconsistency means:

  • Incoming DSQ messages from peers may be silently dropped under load
  • Server-initiated queues (session creation) always succeed

This appears intentional (peer messages are less critical to drop vs server-initiated actions), but the behavioral difference should be documented.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/coinjoin/server.cpp` at line 193, ProcessDSQUEUE currently uses the
non-blocking m_queueman.TryAddQueue(dsq) while CreateNewSession and
CheckForCompleteQueue use the blocking AddQueue(), causing peer DSQ messages to
be silently dropped under contention; update the codebase to either (a) unify
behavior by replacing TryAddQueue with AddQueue in ProcessDSQUEUE or (b)
explicitly document the intended difference—add a clear comment at the
ProcessDSQUEUE call site referencing TryAddQueue, explaining that peer DSQ drops
are intentional and why, and update any developer docs; ensure you reference the
methods TryAddQueue, AddQueue and the functions ProcessDSQUEUE,
CreateNewSession, CheckForCompleteQueue so reviewers can locate and verify the
change.

90-97: Silent return on lock contention may drop legitimate requests.

When TryHasQueueFromMasternode() returns std::nullopt due to lock contention, the DSACCEPT message is silently dropped without any response to the peer. This differs from the previous blocking behavior where the message would always be processed.

While this prevents potential deadlocks, peers may experience intermittent failures to join mixing sessions under load. Consider logging when this occurs for debugging purposes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/coinjoin/server.cpp` around lines 90 - 97, When TryHasQueueFromMasternode
(called on m_queueman with m_mn_activeman.GetOutPoint()) returns std::nullopt in
the DSACCEPT handling, do not silently return: add a LogPrint(BCLog::COINJOIN,
...) that records the lock-contention case including the masternode outpoint and
peer info for debugging, and reply to the peer so the request is not dropped
(e.g. call PushStatus(peer, STATUS_REJECTED, ERR_BUSY) or another appropriate
temporary-failure code) so callers get a clear transient-failure response
instead of no response.
src/coinjoin/coinjoin.h (1)

352-376: Fix formatting to pass CI pipeline.

The pipeline reports clang-format differences on lines 360-364. The [[nodiscard]] attribute declarations for TryHasQueueFromMasternode and TryCheckDuplicate need formatting adjustments.

🔧 Suggested formatting fix
-    //! TRY_LOCK variant: returns nullopt if lock can't be acquired; true if any queue entry has this
-    //! outpoint (any readiness).
-    [[nodiscard]] std::optional<bool> TryHasQueueFromMasternode(const COutPoint& outpoint) const EXCLUSIVE_LOCKS_REQUIRED(!cs_vecqueue);
-    //! TRY_LOCK combined duplicate check: returns nullopt if lock can't be acquired; true if dsq is
-    //! an exact duplicate or the masternode is sending too many dsqs with the same readiness.
-    [[nodiscard]] std::optional<bool> TryCheckDuplicate(const CCoinJoinQueue& dsq) const EXCLUSIVE_LOCKS_REQUIRED(!cs_vecqueue);
+    //! TRY_LOCK variant: returns nullopt if lock can't be acquired; true if any queue entry has this
+    //! outpoint (any readiness).
+    [[nodiscard]] std::optional<bool> TryHasQueueFromMasternode(const COutPoint& outpoint) const
+        EXCLUSIVE_LOCKS_REQUIRED(!cs_vecqueue);
+    //! TRY_LOCK combined duplicate check: returns nullopt if lock can't be acquired; true if dsq is
+    //! an exact duplicate or the masternode is sending too many dsqs with the same readiness.
+    [[nodiscard]] std::optional<bool> TryCheckDuplicate(const CCoinJoinQueue& dsq) const
+        EXCLUSIVE_LOCKS_REQUIRED(!cs_vecqueue);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/coinjoin/coinjoin.h` around lines 352 - 376, Reformat the two function
declarations so clang-format is happy: put the [[nodiscard]] attribute directly
adjacent to the function declaration rather than on its own line and ensure
spacing matches the surrounding declarations; specifically update the
declarations for TryHasQueueFromMasternode and TryCheckDuplicate so the
[[nodiscard]] attribute precedes the function signature on the same line and
keep the EXCLUSIVE_LOCKS_REQUIRED(!cs_vecqueue) annotation and ending semicolon
intact.
src/coinjoin/client.cpp (1)

140-152: Fix formatting to pass CI pipeline.

The pipeline reports clang-format differences on lines 137-155. The method signatures for startMixing, stopMixing, and isMixing need formatting adjustments.

🔧 Suggested formatting fix
-bool CCoinJoinClientManager::startMixing() {
+bool CCoinJoinClientManager::startMixing()
+{
     bool expected{false};
     return fMixing.compare_exchange_strong(expected, true);
 }

-void CCoinJoinClientManager::stopMixing() {
+void CCoinJoinClientManager::stopMixing()
+{
     fMixing = false;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/coinjoin/client.cpp` around lines 140 - 152, Reformat the three methods
to match project clang-format style: place the opening brace on the same line as
the function signature, use consistent spacing for initializers (e.g., bool
expected = false or bool expected{false} per project style), and ensure
return/statements and braces follow the same indentation and spacing
conventions; update CCoinJoinClientManager::startMixing,
CCoinJoinClientManager::stopMixing, and CCoinJoinClientManager::isMixing
accordingly so clang-format no longer reports differences.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/coinjoin/server.cpp`:
- Line 904: Clang-format flagged inconsistent spacing on the obj.pushKV line;
reformat the line that calls obj.pushKV("queue_size", m_queueman.GetQueueSize())
so spacing and alignment match project clang-format rules (run clang-format or
your editor's format command), ensuring the call to obj.pushKV and the
m_queueman.GetQueueSize() argument use the same spacing style as surrounding
pushKV calls.
- Around line 159-165: Run clang-format on the affected file and fix the
formatting of the LogPrint line in the block where you call
m_queueman.TryCheckDuplicate(dsq); specifically reflow/wrap the long LogPrint
invocation (the line referencing BCLog::COINJOIN, the format string "DSQUEUE --
Peer %d is sending WAY too many dsq messages for a masternode with collateral
%s\n", and the arguments from and dsq.masternodeOutpoint.ToStringShort()) so it
matches the project's clang-format style (proper indentation and line breaks)
and then commit the formatted change.

In `@src/rpc/coinjoin.cpp`:
- Around line 281-286: The coinjoin salt generation path (coinjoinsalt_generate)
currently calls node.coinjoin_loader->WithClient(...) and silently proceeds if
WithClient returns false, skipping the mixing check; update the call to assert
the client lookup succeeded using CHECK_NONFATAL so the RPC fails early when the
client isn't found (i.e., wrap the WithClient invocation result in
CHECK_NONFATAL and preserve the existing mixing check that throws JSONRPCError
if client.isMixing()), referencing coinjoin_loader->WithClient,
coinjoinsalt_generate, CHECK_NONFATAL, and client.isMixing to locate and fix the
code.

---

Outside diff comments:
In `@src/Makefile.am`:
- Around line 656-660: The build splits wallet sources into libbitcoin_wallet.a
but leaves references to CJWalletManager in code still built into
libbitcoin_node.a (notably net_processing.cpp via PeerManager and the
hasQueue()/processMessage() call sites), causing unresolved links when
--disable-wallet is used; either move coinjoin/walletman.cpp back into the node
archive or gate all usages of CJWalletManager (and any calls to
PeerManager::hasQueue()/processMessage() that forward to it) behind the same
ENABLE_WALLET conditional as used in init.cpp so that net_processing.cpp no
longer references CJWalletManager when wallets are disabled; update the
Makefile.am entry for libbitcoin_node_a_SOURCES or wrap the
CJWalletManager-using code paths in net_processing.cpp/PeerManager with `#ifdef`
ENABLE_WALLET to restore a consistent implementation owner.

---

Nitpick comments:
In `@src/coinjoin/client.cpp`:
- Around line 140-152: Reformat the three methods to match project clang-format
style: place the opening brace on the same line as the function signature, use
consistent spacing for initializers (e.g., bool expected = false or bool
expected{false} per project style), and ensure return/statements and braces
follow the same indentation and spacing conventions; update
CCoinJoinClientManager::startMixing, CCoinJoinClientManager::stopMixing, and
CCoinJoinClientManager::isMixing accordingly so clang-format no longer reports
differences.

In `@src/coinjoin/coinjoin.h`:
- Around line 352-376: Reformat the two function declarations so clang-format is
happy: put the [[nodiscard]] attribute directly adjacent to the function
declaration rather than on its own line and ensure spacing matches the
surrounding declarations; specifically update the declarations for
TryHasQueueFromMasternode and TryCheckDuplicate so the [[nodiscard]] attribute
precedes the function signature on the same line and keep the
EXCLUSIVE_LOCKS_REQUIRED(!cs_vecqueue) annotation and ending semicolon intact.

In `@src/coinjoin/server.cpp`:
- Line 193: ProcessDSQUEUE currently uses the non-blocking
m_queueman.TryAddQueue(dsq) while CreateNewSession and CheckForCompleteQueue use
the blocking AddQueue(), causing peer DSQ messages to be silently dropped under
contention; update the codebase to either (a) unify behavior by replacing
TryAddQueue with AddQueue in ProcessDSQUEUE or (b) explicitly document the
intended difference—add a clear comment at the ProcessDSQUEUE call site
referencing TryAddQueue, explaining that peer DSQ drops are intentional and why,
and update any developer docs; ensure you reference the methods TryAddQueue,
AddQueue and the functions ProcessDSQUEUE, CreateNewSession,
CheckForCompleteQueue so reviewers can locate and verify the change.
- Around line 90-97: When TryHasQueueFromMasternode (called on m_queueman with
m_mn_activeman.GetOutPoint()) returns std::nullopt in the DSACCEPT handling, do
not silently return: add a LogPrint(BCLog::COINJOIN, ...) that records the
lock-contention case including the masternode outpoint and peer info for
debugging, and reply to the peer so the request is not dropped (e.g. call
PushStatus(peer, STATUS_REJECTED, ERR_BUSY) or another appropriate
temporary-failure code) so callers get a clear transient-failure response
instead of no response.

In `@src/coinjoin/walletman.h`:
- Around line 51-53: The comment for doForClient should explicitly document that
the callback func is non-reentrant: add a short sentence to the function comment
(for doForClient) stating that func is invoked while the wallet-manager lock is
held and must not call back into CJWalletManager or invoke any methods that may
acquire the same wallet-manager lock (to avoid deadlocks); reference
CCoinJoinClientManager as the callback parameter type and make the
non-reentrancy constraint explicit so future callers know not to call
CJWalletManager methods from within func.

In `@src/qt/overviewpage.cpp`:
- Around line 599-607: The current logic leaves notMixing=false when
withCoinJoin() can't find a client, causing the UI to incorrectly show "mixing"
active; change the default to true (bool notMixing{true};) so absence of a
client is treated as not mixing, and keep the existing update inside
walletModel->withCoinJoin(...) that sets notMixing = !client.isMixing(), while
preserving the cached-blocks check (client.getCachedBlocks(),
client.setCachedBlocks(...), updateCoinJoinProgress()) so state stays correct
when a client is present.
- Around line 581-585: withCoinJoin's boolean return value is ignored so a
missing client can be silently skipped; change the call sites (e.g. the block
using walletModel->withCoinJoin, the tooFast assignment that references
client.getCachedBlocks()) to capture the return value and handle the false case
explicitly: if withCoinJoin(...) returns false, log a warning (or otherwise
handle client-unavailable) and avoid treating tooFast as valid, otherwise run
the lambda to set tooFast using nBestHeight, client.getCachedBlocks(), GetTime()
and nLastDSProgressBlockTime; apply the same pattern to all repeated sites in
this file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 252bc396-6bb7-4302-80d6-7814b1bb0bef

📥 Commits

Reviewing files that changed from the base of the PR and between d1eab6c and acb27a0.

📒 Files selected for processing (25)
  • contrib/auto_gdb/simple_class_obj.py
  • src/Makefile.am
  • src/Makefile.test.include
  • src/coinjoin/client.cpp
  • src/coinjoin/client.h
  • src/coinjoin/coinjoin.cpp
  • src/coinjoin/coinjoin.h
  • src/coinjoin/interfaces.cpp
  • src/coinjoin/server.cpp
  • src/coinjoin/server.h
  • src/coinjoin/walletman.cpp
  • src/coinjoin/walletman.h
  • src/init.cpp
  • src/interfaces/coinjoin.h
  • src/qt/bitcoingui.cpp
  • src/qt/optionsdialog.cpp
  • src/qt/overviewpage.cpp
  • src/qt/walletmodel.cpp
  • src/qt/walletmodel.h
  • src/rpc/coinjoin.cpp
  • src/test/coinjoin_basemanager_tests.cpp
  • src/test/coinjoin_queue_tests.cpp
  • src/wallet/init.cpp
  • src/wallet/test/coinjoin_tests.cpp
  • src/wallet/wallet.cpp
💤 Files with no reviewable changes (2)
  • src/Makefile.test.include
  • src/test/coinjoin_basemanager_tests.cpp

Comment on lines +159 to +165
const auto isDup = m_queueman.TryCheckDuplicate(dsq);
if (!isDup.has_value()) return;
if (*isDup) {
LogPrint(BCLog::COINJOIN, "DSQUEUE -- Peer %d is sending WAY too many dsq messages for a masternode with collateral %s\n", from, dsq.masternodeOutpoint.ToStringShort());
return;
}
} // cs_vecqueue
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Pipeline failure: Clang-format issue.

The CI pipeline reports a formatting difference on these lines. Please run clang-format to fix the indentation/wrapping of the LogPrint statement.

🧰 Tools
🪛 GitHub Actions: Clang Diff Format Check

[error] 159-161: Clang-format-diff.py reported formatting differences (LogPrint wrapped/indented). This step failed due to detected diff; exit code 1.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/coinjoin/server.cpp` around lines 159 - 165, Run clang-format on the
affected file and fix the formatting of the LogPrint line in the block where you
call m_queueman.TryCheckDuplicate(dsq); specifically reflow/wrap the long
LogPrint invocation (the line referencing BCLog::COINJOIN, the format string
"DSQUEUE -- Peer %d is sending WAY too many dsq messages for a masternode with
collateral %s\n", and the arguments from and
dsq.masternodeOutpoint.ToStringShort()) so it matches the project's clang-format
style (proper indentation and line breaks) and then commit the formatted change.

obj.clear();
obj.setObject();
obj.pushKV("queue_size", GetQueueSize());
obj.pushKV("queue_size", m_queueman.GetQueueSize());
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Pipeline failure: Clang-format issue.

The CI pipeline reports a formatting difference on this line (spacing/alignment of pushKV). Please run clang-format to fix.

🧰 Tools
🪛 GitHub Actions: Clang Diff Format Check

[error] 901-904: Clang-format-diff.py reported formatting differences (obj.pushKV queue_size spacing alignment). This step failed due to detected diff; exit code 1.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/coinjoin/server.cpp` at line 904, Clang-format flagged inconsistent
spacing on the obj.pushKV line; reformat the line that calls
obj.pushKV("queue_size", m_queueman.GetQueueSize()) so spacing and alignment
match project clang-format rules (run clang-format or your editor's format
command), ensuring the call to obj.pushKV and the m_queueman.GetQueueSize()
argument use the same spacing style as surrounding pushKV calls.

@knst knst force-pushed the fix-cj-dangling-ptr branch from acb27a0 to b017394 Compare March 30, 2026 09:09
@thepastaclaw
Copy link
Copy Markdown

thepastaclaw commented Mar 30, 2026

Review Gate

Commit: b79f5a51

  • Debounce: 1853m ago (need 30m)

  • CI checks: build failure: linux64_multiprocess-build / Build source, linux64_tsan-build / Build source, linux64_sqlite-build / Build source

  • CodeRabbit review: comment found

  • Off-peak hours: peak window (5am-11am PT) — currently 08:09 AM PT Tuesday

  • Run review now (check to override)

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b017394a9c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +211 to 213
if (fAutoStart) {
mgr.startMixing();
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Skip CoinJoin autostart when wallet is locked

InitCoinJoinSettings() now calls mgr.startMixing() unconditionally when -coinjoinautostart=1, but this function no longer has any wallet-lock check. For encrypted wallets that start locked, this sets isMixing() to true even though DoAutomaticDenominating() exits early on lock, so the client reports a running mix session that cannot proceed; this also blocks operations like coinjoinsalt_generate/coinjoinsalt_set that reject while mixing is active. The previous logic explicitly stopped mixing for locked wallets, so this is a behavioral regression for locked-at-startup nodes.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/coinjoin/client.cpp`:
- Around line 140-152: Reformat the three CCoinJoinClientManager methods
(CCoinJoinClientManager::startMixing, ::stopMixing, and ::isMixing) to match
project clang-format style: place the opening brace on the same line as the
function signature, ensure spacing around return types and parameters is
consistent, and keep single-line bodies compact (e.g., return fMixing; or
fMixing = false; as appropriate); run clang-format or apply the repo's style so
these method definitions and use of the atomic fMixing variable conform to CI
formatting rules.

In `@src/coinjoin/interfaces.cpp`:
- Around line 44-50: The lambda passed to manager().doForClient in AddWallet()
is mis-indented and fails clang-format; reformat the call so the lambda's
opening bracket and body align with the call (ensure the capture/signature and
body are indented consistently), e.g. place the lambda on the next line with its
body indented and the closing "});" aligned with the start of the
manager().doForClient call; target the AddWallet function and the
manager().doForClient(..., [&](CCoinJoinClientManager& mgr) { ... }) lambda for
the fix.

In `@src/coinjoin/walletman.cpp`:
- Around line 39-79: The function declarations with EXCLUSIVE_LOCKS_REQUIRED
annotations (doForClient, processMessage, getMixingMasternodes, addWallet,
removeWallet, flushWallet, UpdatedBlockTip, DoMaintenance, and ProcessDSQueue)
fail clang-format; reflow each declaration so the EXCLUSIVE_LOCKS_REQUIRED
attribute is placed on its own trailing line (not inline with parameters) per
project style — keep the return type, function name and parameter list together,
then place the EXCLUSIVE_LOCKS_REQUIRED(...) on the next line for each of the
listed symbols to satisfy formatting checks.

In `@src/wallet/init.cpp`:
- Around line 204-213: The default for -enablecoinjoin in
WalletInit::InitCoinJoinSettings is currently true
(gArgs.GetBoolArg("-enablecoinjoin", true)) which contradicts the documented
default of 0; change the fallback value to false (or to whatever project-wide
DEFAULT_COINJOIN_ENABLED constant you use) in the GetBoolArg call and keep
CCoinJoinClientOptions::SetEnabled(...) as is — alternatively, update the help
text to reflect that coinjoin is enabled by default; see
WalletInit::InitCoinJoinSettings, CCoinJoinClientOptions::SetEnabled, and
gArgs.GetBoolArg("-enablecoinjoin", ...) to make the fix.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c6feb52a-bb86-4e9a-88f9-6dc0853dd1b8

📥 Commits

Reviewing files that changed from the base of the PR and between acb27a0 and b017394.

📒 Files selected for processing (18)
  • src/Makefile.am
  • src/coinjoin/client.cpp
  • src/coinjoin/client.h
  • src/coinjoin/interfaces.cpp
  • src/coinjoin/walletman.cpp
  • src/coinjoin/walletman.h
  • src/init.cpp
  • src/interfaces/coinjoin.h
  • src/qt/bitcoingui.cpp
  • src/qt/optionsdialog.cpp
  • src/qt/overviewpage.cpp
  • src/qt/walletmodel.cpp
  • src/qt/walletmodel.h
  • src/rpc/coinjoin.cpp
  • src/wallet/init.cpp
  • src/wallet/test/coinjoin_tests.cpp
  • src/wallet/wallet.cpp
  • src/walletinitinterface.h
✅ Files skipped from review due to trivial changes (4)
  • src/Makefile.am
  • src/wallet/wallet.cpp
  • src/init.cpp
  • src/interfaces/coinjoin.h
🚧 Files skipped from review as they are similar to previous changes (7)
  • src/qt/optionsdialog.cpp
  • src/wallet/test/coinjoin_tests.cpp
  • src/qt/bitcoingui.cpp
  • src/coinjoin/walletman.h
  • src/qt/walletmodel.cpp
  • src/qt/overviewpage.cpp
  • src/rpc/coinjoin.cpp

Comment on lines 39 to 79

public:
bool hasQueue(const uint256& hash) const override;
CCoinJoinClientManager* getClient(const std::string& name) override;
bool doForClient(const std::string& name, const std::function<void(CCoinJoinClientManager&)>& func) override EXCLUSIVE_LOCKS_REQUIRED(!cs_wallet_manager_map);
MessageProcessingResult processMessage(CNode& peer, CChainState& chainstate, CConnman& connman, CTxMemPool& mempool,
std::string_view msg_type, CDataStream& vRecv) override;
std::string_view msg_type, CDataStream& vRecv) override EXCLUSIVE_LOCKS_REQUIRED(!cs_ProcessDSQueue, !cs_wallet_manager_map);
std::optional<CCoinJoinQueue> getQueueFromHash(const uint256& hash) const override;
std::optional<int> getQueueSize() const override;
std::vector<CDeterministicMNCPtr> getMixingMasternodes() override;
void addWallet(const std::shared_ptr<wallet::CWallet>& wallet) override;
void removeWallet(const std::string& name) override;
void flushWallet(const std::string& name) override;
std::vector<CDeterministicMNCPtr> getMixingMasternodes() override EXCLUSIVE_LOCKS_REQUIRED(!cs_wallet_manager_map);
void addWallet(const std::shared_ptr<wallet::CWallet>& wallet) override EXCLUSIVE_LOCKS_REQUIRED(!cs_wallet_manager_map);
void removeWallet(const std::string& name) override EXCLUSIVE_LOCKS_REQUIRED(!cs_wallet_manager_map);
void flushWallet(const std::string& name) override EXCLUSIVE_LOCKS_REQUIRED(!cs_wallet_manager_map);

protected:
// CValidationInterface
void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) override;
void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) override EXCLUSIVE_LOCKS_REQUIRED(!cs_wallet_manager_map);

private:
const bool m_relay_txes;
ChainstateManager& m_chainman;
CDeterministicMNManager& m_dmnman;
CMasternodeMetaMan& m_mn_metaman;
CTxMemPool& m_mempool;
const CMasternodeSync& m_mn_sync;
const llmq::CInstantSendManager& m_isman;

// m_queueman is declared before the wallet map so that it is destroyed
// after all CCoinJoinClientManager instances (which hold a raw pointer to it).
// Null when relay_txes is false (no queue processing).
const std::unique_ptr<CoinJoinQueueManager> m_queueman;

mutable Mutex cs_ProcessDSQueue;

mutable Mutex cs_wallet_manager_map;
std::map<const std::string, std::unique_ptr<CCoinJoinClientManager>> m_wallet_manager_map GUARDED_BY(cs_wallet_manager_map);

void DoMaintenance(CConnman& connman) EXCLUSIVE_LOCKS_REQUIRED(!cs_wallet_manager_map);

[[nodiscard]] MessageProcessingResult ProcessDSQueue(NodeId from, CConnman& connman, std::string_view msg_type,
CDataStream& vRecv) EXCLUSIVE_LOCKS_REQUIRED(!cs_ProcessDSQueue, !cs_wallet_manager_map);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix formatting to pass CI checks.

The CI pipeline reports clang-format errors for the function declarations with EXCLUSIVE_LOCKS_REQUIRED annotations. These need to be reflowed onto multiple lines per the project's formatting rules.

🧰 Tools
🪛 GitHub Actions: Clang Diff Format Check

[error] 39-79: Clang-format would reflow function declarations/override lines with EXCLUSIVE_LOCKS_REQUIRED onto multiple lines.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/coinjoin/walletman.cpp` around lines 39 - 79, The function declarations
with EXCLUSIVE_LOCKS_REQUIRED annotations (doForClient, processMessage,
getMixingMasternodes, addWallet, removeWallet, flushWallet, UpdatedBlockTip,
DoMaintenance, and ProcessDSQueue) fail clang-format; reflow each declaration so
the EXCLUSIVE_LOCKS_REQUIRED attribute is placed on its own trailing line (not
inline with parameters) per project style — keep the return type, function name
and parameter list together, then place the EXCLUSIVE_LOCKS_REQUIRED(...) on the
next line for each of the listed symbols to satisfy formatting checks.

@knst knst force-pushed the fix-cj-dangling-ptr branch from b017394 to 5c2f753 Compare March 30, 2026 10:29
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5c2f753b78

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

// Dash Specific WalletInitInterface
virtual void AutoLockMasternodeCollaterals(interfaces::WalletLoader& wallet_loader) const = 0;
virtual void InitCoinJoinSettings(interfaces::CoinJoin::Loader& coinjoin_loader, interfaces::WalletLoader& wallet_loader) const = 0;
virtual void InitCoinJoinSettings(CCoinJoinClientManager& mgr) const = 0;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve no-wallet InitCoinJoinSettings override compatibility

Changing WalletInitInterface::InitCoinJoinSettings to take CCoinJoinClientManager& here leaves the non-wallet implementation out of sync: DummyWalletInit still declares InitCoinJoinSettings(interfaces::CoinJoin::Loader&, interfaces::WalletLoader&) in src/dummywallet.cpp. In --disable-wallet builds that signature no longer overrides the pure virtual method, so the dummy wallet target fails to compile (or remains abstract).

Useful? React with 👍 / 👎.

@knst knst force-pushed the fix-cj-dangling-ptr branch from 5c2f753 to 92d0f34 Compare March 30, 2026 12:56
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 92d0f348f8

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +43 to +45
if (!wallet->IsLocked()) {
g_wallet_init_interface.InitCoinJoinSettings(mgr);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Initialize CoinJoin settings for locked wallets too

CoinJoinLoaderImpl::AddWallet now calls InitCoinJoinSettings only when !wallet->IsLocked(), but CoinJoinLoaderImpl sets CCoinJoinClientOptions::SetEnabled(false) in its constructor and this is the only place settings are re-initialized. For encrypted wallets that start locked, CoinJoin stays globally disabled forever (even after later unlock), so coinjoin start/status/stop/reset fail in ValidateCoinJoinArguments() with the internal-disabled error. This is a functional regression for the default locked-at-startup wallet flow.

Useful? React with 👍 / 👎.

knst added 5 commits April 13, 2026 14:58
    /usr/bin/ld: libbitcoin_node.a(libbitcoin_node_a-walletman.o): in function `CJWalletManagerImpl::UpdatedBlockTip(CBlockIndex const*, CBlockIndex const*, bool)::{lambda(CCoinJoinClientManager&)#1}::operator()(CCoinJoinClientManager&) const':
    DASH/src/coinjoin/walletman.cpp:132:(.text+0x51c): undefined reference to `CCoinJoinClientManager::UpdatedBlockTip(CBlockIndex const*)'
@knst knst force-pushed the fix-cj-dangling-ptr branch from 92d0f34 to af2d8ed Compare April 13, 2026 08:15
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/coinjoin/interfaces.cpp (1)

42-48: ⚠️ Potential issue | 🟡 Minor

Align the -enablecoinjoin fallback with the advertised default.

src/wallet/init.cpp still documents -enablecoinjoin as defaulting to 0, but this path enables CoinJoin when the flag is omitted. Please make this fallback consistent with the help text, and keep src/rpc/coinjoin.cpp’s ValidateCoinJoinArguments() on the same shared default as well.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/coinjoin/interfaces.cpp` around lines 42 - 48, The code currently enables
CoinJoin by default via gArgs.GetBoolArg("-enablecoinjoin", true) in
CCoinJoinClientOptions::SetEnabled which conflicts with the help text in
src/wallet/init.cpp and the shared default used by ValidateCoinJoinArguments();
change the fallback to false (use gArgs.GetBoolArg("-enablecoinjoin", false)) so
the absent flag defaults to disabled, and ensure ValidateCoinJoinArguments() and
any other consumers reference the same shared default/constant rather than
hardcoding true/false so the behavior and help text remain consistent (update
any shared default variable or call site to use the unified default).
🧹 Nitpick comments (1)
src/interfaces/coinjoin.h (1)

50-52: Document the callback lifetime contract explicitly.

Please spell out that the Client& passed to WithClient(...) is only valid for the duration of func and must not be stored. That is the safety property replacing the old raw-pointer API.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/interfaces/coinjoin.h` around lines 50 - 52, The comment for
WithClient(...) must explicitly state the lifetime contract: update the
docstring for virtual bool WithClient(const std::string& name,
std::function<void(Client&)> func) to clearly say the Client& passed into func
is only valid for the duration of the callback invocation and must not be
stored, copied, or used after func returns (this is the safety guarantee
replacing the old raw-pointer API); mention that callers should perform any
needed work inside func or copy safe data out, and that implementations must
ensure the reference becomes invalid immediately after func returns.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/coinjoin/walletman.cpp`:
- Around line 318-320: The non-wallet factory branch in
src/coinjoin/walletman.cpp currently does assert(false) and then falls off the
end of a non-void function in release builds; update the non-wallet path (the
factory function in walletman.cpp that constructs/returns a wallet object when
wallet support is disabled) to return an explicit safe default (e.g., return
nullptr) after the assert(false) so the function has a defined return value in
non-debug builds; ensure the returned value matches the function's return type
(use nullptr for pointer returns or an appropriate sentinel value) and keep the
assert for debug-time diagnostics.

---

Duplicate comments:
In `@src/coinjoin/interfaces.cpp`:
- Around line 42-48: The code currently enables CoinJoin by default via
gArgs.GetBoolArg("-enablecoinjoin", true) in CCoinJoinClientOptions::SetEnabled
which conflicts with the help text in src/wallet/init.cpp and the shared default
used by ValidateCoinJoinArguments(); change the fallback to false (use
gArgs.GetBoolArg("-enablecoinjoin", false)) so the absent flag defaults to
disabled, and ensure ValidateCoinJoinArguments() and any other consumers
reference the same shared default/constant rather than hardcoding true/false so
the behavior and help text remain consistent (update any shared default variable
or call site to use the unified default).

---

Nitpick comments:
In `@src/interfaces/coinjoin.h`:
- Around line 50-52: The comment for WithClient(...) must explicitly state the
lifetime contract: update the docstring for virtual bool WithClient(const
std::string& name, std::function<void(Client&)> func) to clearly say the Client&
passed into func is only valid for the duration of the callback invocation and
must not be stored, copied, or used after func returns (this is the safety
guarantee replacing the old raw-pointer API); mention that callers should
perform any needed work inside func or copy safe data out, and that
implementations must ensure the reference becomes invalid immediately after func
returns.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 2911219b-5305-430e-b53b-aaba4ec97f6c

📥 Commits

Reviewing files that changed from the base of the PR and between b017394 and b79f5a5.

📒 Files selected for processing (19)
  • src/Makefile.am
  • src/coinjoin/client.cpp
  • src/coinjoin/client.h
  • src/coinjoin/interfaces.cpp
  • src/coinjoin/walletman.cpp
  • src/coinjoin/walletman.h
  • src/dummywallet.cpp
  • src/init.cpp
  • src/interfaces/coinjoin.h
  • src/qt/bitcoingui.cpp
  • src/qt/optionsdialog.cpp
  • src/qt/overviewpage.cpp
  • src/qt/walletmodel.cpp
  • src/qt/walletmodel.h
  • src/rpc/coinjoin.cpp
  • src/wallet/init.cpp
  • src/wallet/test/coinjoin_tests.cpp
  • src/wallet/wallet.cpp
  • src/walletinitinterface.h
✅ Files skipped from review due to trivial changes (3)
  • src/Makefile.am
  • src/qt/optionsdialog.cpp
  • src/init.cpp
🚧 Files skipped from review as they are similar to previous changes (7)
  • src/qt/bitcoingui.cpp
  • src/coinjoin/walletman.h
  • src/qt/walletmodel.cpp
  • src/walletinitinterface.h
  • src/qt/walletmodel.h
  • src/qt/overviewpage.cpp
  • src/coinjoin/client.cpp

Comment on lines 318 to +320
#else
// Cannot be constructed if wallet support isn't built
return nullptr;
assert(false);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
nl -ba src/coinjoin/walletman.cpp | sed -n '311,322p'

Repository: dashpay/dash

Length of output: 98


🏁 Script executed:

sed -n '311,322p' src/coinjoin/walletman.cpp

Repository: dashpay/dash

Length of output: 729


Return after assert(false) in the non-wallet factory path.

In release builds, assert(false) compiles out, so this branch falls off the end of a non-void function. This breaks -nowallet builds and is undefined behavior.

🔧 Minimal fix
 `#else`
     // Cannot be constructed if wallet support isn't built
     assert(false);
+    return nullptr;
 `#endif` // ENABLE_WALLET
 }
📝 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.

Suggested change
#else
// Cannot be constructed if wallet support isn't built
return nullptr;
assert(false);
`#else`
// Cannot be constructed if wallet support isn't built
assert(false);
return nullptr;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/coinjoin/walletman.cpp` around lines 318 - 320, The non-wallet factory
branch in src/coinjoin/walletman.cpp currently does assert(false) and then falls
off the end of a non-void function in release builds; update the non-wallet path
(the factory function in walletman.cpp that constructs/returns a wallet object
when wallet support is disabled) to return an explicit safe default (e.g.,
return nullptr) after the assert(false) so the function has a defined return
value in non-debug builds; ensure the returned value matches the function's
return type (use nullptr for pointer returns or an appropriate sentinel value)
and keep the assert for debug-time diagnostics.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b79f5a512e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

if (std::unique_ptr<interfaces::CoinJoin::Client> coinjoin_client = coinjoin_available() ? coinjoin_loader().GetClient(GetName()) : nullptr) {
coinjoin_client->stopMixing();
if (coinjoin_available()) {
coinjoin_loader().WithClient(GetName(), [](auto& client) { client.stopMixing(); });
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Break cs_KeyStore/manager lock cycle in NewKeyPoolCallback

LegacyScriptPubKeyMan::NewKeyPool() invokes m_storage.NewKeyPoolCallback() while holding cs_KeyStore (see src/wallet/scriptpubkeyman.cpp around lines 1428-1439), and this callback now calls coinjoin_loader().WithClient(...), which acquires cs_wallet_manager_map. At the same time, coinjoin reset/flushWallet execute resetPool() under cs_wallet_manager_map, and resetPool() calls keyHolderStorage.ReturnAll() which reaches ReserveDestination::ReturnDestination() and takes cs_KeyStore (via src/coinjoin/client.cpp and src/wallet/scriptpubkeyman.cpp). This introduces a lock-order inversion (cs_KeyStore -> cs_wallet_manager_map vs cs_wallet_manager_map -> cs_KeyStore) that can deadlock during concurrent keypool refresh and CoinJoin reset/flush operations.

Useful? React with 👍 / 👎.

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.

2 participants