-
Notifications
You must be signed in to change notification settings - Fork 1.2k
fix(wallet): exclude unconfirmable outputs from CoinJoin accounting #7634
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?
Changes from all commits
f44af84
72ad8cb
1255064
6b8b0b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| Wallet changes | ||
| -------------- | ||
|
|
||
| - CoinJoin denomination counts, average mixing rounds and the normalized | ||
| anonymized balance no longer include outputs of transactions that cannot | ||
| confirm as they stand: conflicted ones, and ones that were abandoned, never | ||
| broadcast, or rejected from the mempool. Previously such outputs inflated | ||
| these figures, which could make the wallet create fewer denominations than | ||
| intended and report mixing progress that did not match the coins it could | ||
| actually use. (#7634) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -162,7 +162,7 @@ std::vector<CompactTallyItem> CWallet::SelectCoinsGroupedByAddresses(bool fSkipD | |
|
|
||
| if (wtx.IsCoinBase() && GetTxBlocksToMaturity(wtx) > 0) continue; | ||
| if (fSkipUnconfirmed && !CachedTxIsTrusted(*this, wtx)) continue; | ||
| if (GetTxDepthInMainChain(wtx) < 0) continue; | ||
| if (!IsWalletUTXOSpendable(wtx)) continue; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 Blocking: Invalidate cached tallies when a transaction leaves the mempool
source: ['codex'] There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Resolved in this update — Invalidate cached tallies when a transaction leaves the mempool no longer present. Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread. |
||
|
|
||
| for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) { | ||
| CTxDestination txdest; | ||
|
|
@@ -253,7 +253,7 @@ int CWallet::CountInputsWithAmount(CAmount nInputAmount) const | |
| const auto it{mapWallet.find(outpoint.hash)}; | ||
| if (it == mapWallet.end()) continue; | ||
| if (it->second.tx->vout[outpoint.n].nValue != nInputAmount) continue; | ||
| if (GetTxDepthInMainChain(it->second) < 0) continue; | ||
| if (!IsWalletUTXOSpendable(it->second)) continue; | ||
|
|
||
| nTotal++; | ||
| } | ||
|
|
@@ -542,6 +542,9 @@ float CWallet::GetAverageAnonymizedRounds() const | |
|
|
||
| LOCK(cs_wallet); | ||
| for (const auto& outpoint : setWalletUTXO) { | ||
| const auto it{mapWallet.find(outpoint.hash)}; | ||
| if (it == mapWallet.end()) continue; | ||
| if (!IsWalletUTXOSpendable(it->second)) continue; | ||
| if (!IsDenominated(outpoint)) continue; | ||
|
|
||
| nTotal += GetCappedOutpointCoinJoinRounds(outpoint); | ||
|
|
@@ -568,7 +571,7 @@ CAmount CWallet::GetNormalizedAnonymizedBalance() const | |
|
|
||
| CAmount nValue = it->second.tx->vout[outpoint.n].nValue; | ||
| if (!CoinJoin::IsDenominatedAmount(nValue)) continue; | ||
| if (GetTxDepthInMainChain(it->second) < 0) continue; | ||
| if (!IsWalletUTXOSpendable(it->second)) continue; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Filtering only the normalized/rounds paths leaves the primary CoinJoin balances unchanged: Useful? React with 👍 / 👎. |
||
|
|
||
| int nRounds = GetCappedOutpointCoinJoinRounds(outpoint); | ||
| nTotal += nValue * nRounds / CCoinJoinClientOptions::GetRounds(); | ||
|
|
@@ -581,8 +584,8 @@ CAmount CachedTxGetAnonymizedCredit(const CWallet& wallet, const CWalletTx& wtx, | |
| { | ||
| AssertLockHeld(wallet.cs_wallet); | ||
|
|
||
| // Exclude coinbase and conflicted txes | ||
| if (wtx.IsCoinBase() || wallet.GetTxDepthInMainChain(wtx) < 0) return 0; | ||
| // Exclude coinbase transactions, and any that cannot confirm as they stand | ||
| if (wtx.IsCoinBase() || !wallet.IsWalletUTXOSpendable(wtx)) return 0; | ||
|
|
||
| CAmount nCredit = 0; | ||
| uint256 hashTx = wtx.GetHash(); | ||
|
|
@@ -620,9 +623,9 @@ CoinJoinCredits CachedTxGetAvailableCoinJoinCredits(const CWallet& wallet, const | |
| // Must wait until coinbase is safely deep enough in the chain before valuing it | ||
| if (wtx.IsCoinBase() && wallet.GetTxBlocksToMaturity(wtx) > 0) return ret; | ||
|
|
||
| int nDepth = wallet.GetTxDepthInMainChain(wtx); | ||
| if (nDepth < 0) return ret; | ||
| if (!wallet.IsWalletUTXOSpendable(wtx)) return ret; | ||
|
|
||
| const int nDepth{wallet.GetTxDepthInMainChain(wtx)}; | ||
| ret.is_unconfirmed = CachedTxIsTrusted(wallet, wtx) && nDepth == 0; | ||
|
|
||
| if (wtx.m_amounts[CWalletTx::ANON_CREDIT].m_cached[ISMINE_SPENDABLE]) { | ||
|
|
||
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.
When a trusted wallet transaction is in the mempool, the default
GetAnonymizableBalance()path can cache it before reaching this check on later calls. For non-conflict mempool removals,transactionRemovedFromMempool()only callsRefreshMempoolStatus()and does not clearfAnonymizableTallyCachedorfAnonymizableTallyCachedNonDenom, so after eviction/expiry this function returns the cached tally at lines 137–147 without evaluating the new liveness condition. Automatic CoinJoin accounting can therefore continue using the unconfirmable outputs until an unrelated cache reset; invalidate these caches on the in-mempool-to-inactive transition or avoid caching zero-depth entries.Useful? React with 👍 / 👎.