Skip to content

fix: address review feedback for CoinJoin promotion/demotion (PR #7052)#44

Merged
PastaPastaPasta merged 6 commits intoPastaPastaPasta:feat/coinjoin-promotionfrom
thepastaclaw:fix/7052-review-feedback
Mar 17, 2026
Merged

fix: address review feedback for CoinJoin promotion/demotion (PR #7052)#44
PastaPastaPasta merged 6 commits intoPastaPastaPasta:feat/coinjoin-promotionfrom
thepastaclaw:fix/7052-review-feedback

Conversation

@thepastaclaw
Copy link
Copy Markdown

Address review feedback from PR dashpay#7052 code review.

Changes

fix: enforce standard mixer minimum on full-session finalization

The full-session finalization path in CheckPool was creating the final transaction without verifying the minimum standard mixer count. This could allow a session with only promotion/demotion entries (which don't provide privacy) to finalize. Adds the same GetStandardEntriesCount() check that the timeout path already uses.

fix: acquire cs_main for V24 activation checks in server

Two locations access ActiveChain().Tip() without holding cs_main, creating a race with tip updates/reorgs. Wraps both in LOCK(::cs_main).

fix: add bounds checking for outpoint.n in coinjoin client

Adds outpoint.n < wtx.tx->vout.size() bounds check before accessing wallet transaction outputs, preventing potential out-of-bounds access from corrupted outpoints.

fix: add IsLockedCoin/IsSpent check in SelectFullyMixedForPromotion

SelectFullyMixedForPromotion() was iterating setWalletUTXO without checking IsLockedCoin() or IsSpent(), enabling double-reservation of coins.

refactor: use ValidatePromotionEntry/ValidateDemotionEntry in IsValidInOuts

Replaces inline promotion/demotion validation in IsValidInOuts() with calls to the dedicated CoinJoin::ValidatePromotionEntry() and CoinJoin::ValidateDemotionEntry() functions. These were already declared, implemented, and tested but never called from production code.

refactor: rename m_vecPromotionInputs to m_vecRebalanceInputs

The member stores inputs for both promotion AND demotion operations, so m_vecPromotionInputs was misleading. Renamed to m_vecRebalanceInputs to better reflect its dual purpose.

thepastaclaw and others added 6 commits March 17, 2026 13:11
Add IsSpent/IsLockedCoin filtering to both CountCoinsByDenomination()
and SelectFullyMixedForPromotion() to prevent concurrent CoinJoin
sessions from selecting the same UTXOs. This matches the existing
filtering pattern used in the denomination selector.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add bounds check for outpoint.n before accessing wtx.tx->vout in
JoinExistingQueue and StartNewQueue promotion paths. This prevents
potential out-of-bounds access if wallet state changes between
UTXO selection and input construction.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wrap m_chainman.ActiveChain().Tip() accesses in LOCK(::cs_main)
in ProcessDSVIN and AddEntry to prevent race conditions during
V24 activation state checks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The full-session finalization path in CheckPool was creating the final
transaction without verifying the minimum standard mixer count. This
could allow a session with only promotion/demotion entries (which don't
provide privacy) to finalize. Add the same GetStandardEntriesCount()
check that the timeout path already uses.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…InOuts

Replace the inline promotion/demotion validation in IsValidInOuts()
with calls to the dedicated CoinJoin::ValidatePromotionEntry() and
CoinJoin::ValidateDemotionEntry() functions. These functions were
already declared, implemented, and tested but never called from
production code. This ensures the tested code IS the production code.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The member stores inputs for both promotion AND demotion operations,
so the name m_vecPromotionInputs was misleading. Rename to
m_vecRebalanceInputs to better reflect its dual purpose.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 17, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 497b6253-7fc8-4ca8-93bf-b6def14438ca

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

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
Copy Markdown

✅ No Merge Conflicts Detected

This PR currently has no conflicts with other open PRs.

@PastaPastaPasta PastaPastaPasta marked this pull request as ready for review March 17, 2026 19:43
@PastaPastaPasta PastaPastaPasta merged commit 332186c into PastaPastaPasta:feat/coinjoin-promotion Mar 17, 2026
31 checks passed
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: cc50997142

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (fConsumeCollateralRet) *fConsumeCollateralRet = true;
return false;
}
nExpectedInputDenom = CoinJoin::GetLargerAdjacentDenom(nSessionDenom);
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 Reject demotion at the largest session denomination

This path now sets nExpectedInputDenom from GetLargerAdjacentDenom(nSessionDenom) without checking for 0, so a demotion-shaped entry (1 input, 10 outputs) in a session already at the largest denom can pass structure/output validation and then accept a non-denominated input (AmountToDenomination == 0) if values balance. Before this commit, the explicit nLargerAdjacentDenom == 0 guard rejected this case, so this is a regression that allows an invalid demotion mode and weakens the mixing rules for largest-denom sessions.

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