From fb7b2f4edbd3cc6c5e939b134859450129cb1adf Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Sat, 1 Feb 2025 17:54:28 +0700 Subject: [PATCH 1/8] refactor: remove unused getAnonymizedBalance from interfaces::wallet --- src/interfaces/wallet.h | 3 --- src/wallet/interfaces.cpp | 4 ---- 2 files changed, 7 deletions(-) diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 57a01676a32d..f65564ba1558 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -223,9 +223,6 @@ class Wallet //! Get anonymizable balance. virtual CAmount getAnonymizableBalance(bool fSkipDenominated, bool fSkipUnconfirmed) = 0; - //! Get anonymized balance. - virtual CAmount getAnonymizedBalance() = 0; - //! Get denominated balance. virtual CAmount getDenominatedBalance(bool unconfirmed) = 0; diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index a4fbb369bcc5..9b21285d1ccc 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -412,10 +412,6 @@ class WalletImpl : public Wallet { return m_wallet->GetAnonymizableBalance(fSkipDenominated, fSkipUnconfirmed); } - CAmount getAnonymizedBalance() override - { - return m_wallet->GetBalance().m_anonymized; - } CAmount getDenominatedBalance(bool unconfirmed) override { const auto bal = m_wallet->GetBalance(); From b801c92eff58769686dc0eb7639b04aa0efccc62 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Mon, 6 Jan 2025 01:03:54 +0700 Subject: [PATCH 2/8] perf: faster calculate balance of wallet --- src/wallet/interfaces.cpp | 2 +- src/wallet/receive.cpp | 24 ++++++++++-- src/wallet/transaction.h | 11 +++++- src/wallet/wallet.cpp | 77 ++++++++++++++++++++++++++------------- src/wallet/wallet.h | 3 +- 5 files changed, 83 insertions(+), 34 deletions(-) diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index 9b21285d1ccc..4992c1f9490a 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -432,7 +432,7 @@ class WalletImpl : public Wallet CAmount getAvailableBalance(const CCoinControl& coin_control) override { if (coin_control.IsUsingCoinJoin()) { - return m_wallet->GetBalance(0, coin_control.m_avoid_address_reuse, false, &coin_control).m_anonymized; + return m_wallet->GetBalanceAnonymized(coin_control); } else { return m_wallet->GetAvailableBalance(&coin_control); } diff --git a/src/wallet/receive.cpp b/src/wallet/receive.cpp index 96bcb25ea323..62381c306e28 100644 --- a/src/wallet/receive.cpp +++ b/src/wallet/receive.cpp @@ -313,7 +313,19 @@ bool CWalletTx::IsTrusted() const return pwallet->IsTrusted(*this, trusted_parents); } -CWallet::Balance CWallet::GetBalance(const int min_depth, const bool avoid_reuse, const bool fAddLocked, const CCoinControl* coinControl) const +CAmount CWallet::GetBalanceAnonymized(const CCoinControl& coinControl) const +{ + if (!CCoinJoinClientOptions::IsEnabled()) return 0; + + CAmount anonymized_amount{0}; + LOCK(cs_wallet); + for (auto pcoin : GetSpendableTXs()) { + anonymized_amount += pcoin->GetAnonymizedCredit(coinControl); + } + return anonymized_amount; +} + +CWallet::Balance CWallet::GetBalance(const int min_depth, const bool avoid_reuse, const bool fAddLocked) const { Balance ret; isminefilter reuse_filter = avoid_reuse ? ISMINE_NO : ISMINE_USED; @@ -338,9 +350,13 @@ CWallet::Balance CWallet::GetBalance(const int min_depth, const bool avoid_reuse ret.m_mine_immature += wtx.GetImmatureCredit(); ret.m_watchonly_immature += wtx.GetImmatureWatchOnlyCredit(); if (CCoinJoinClientOptions::IsEnabled()) { - ret.m_anonymized += wtx.GetAnonymizedCredit(coinControl); - ret.m_denominated_trusted += wtx.GetDenominatedCredit(false); - ret.m_denominated_untrusted_pending += wtx.GetDenominatedCredit(true); + ret.m_anonymized += wtx.GetAnonymizedCredit(); + const auto balance_anonymized = wtx.GetDenominatedCredit(); + if (balance_anonymized.is_unconfirmed) { + ret.m_denominated_untrusted_pending += balance_anonymized.m_denom_credit; + } else { + ret.m_denominated_trusted += balance_anonymized.m_denom_credit; + } } } } diff --git a/src/wallet/transaction.h b/src/wallet/transaction.h index 38549aa11f7a..e0952665da4d 100644 --- a/src/wallet/transaction.h +++ b/src/wallet/transaction.h @@ -289,12 +289,19 @@ class CWalletTx CAmount GetImmatureWatchOnlyCredit(const bool fUseCache = true) const; CAmount GetChange() const; + struct BalanceAnonymized + { + CAmount m_denom_credit{0}; + bool is_unconfirmed{false}; + }; + // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The // annotation "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid // having to resolve the issue of member access into incomplete type CWallet. - CAmount GetAnonymizedCredit(const CCoinControl* coinControl = nullptr) const NO_THREAD_SAFETY_ANALYSIS; - CAmount GetDenominatedCredit(bool unconfirmed, bool fUseCache=true) const NO_THREAD_SAFETY_ANALYSIS; + CAmount GetAnonymizedCredit() const NO_THREAD_SAFETY_ANALYSIS; + CAmount GetAnonymizedCredit(const CCoinControl& coinControl) const NO_THREAD_SAFETY_ANALYSIS; + BalanceAnonymized GetDenominatedCredit() const NO_THREAD_SAFETY_ANALYSIS; /** Get the marginal bytes if spending the specified output from this transaction */ int GetSpendSize(unsigned int out, bool use_max_sig = false) const diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index f030eaeb301e..d0fa2c8a6afa 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1993,7 +1993,7 @@ std::set CWalletTx::GetConflicts() const return result; } -CAmount CWalletTx::GetAnonymizedCredit(const CCoinControl* coinControl) const +CAmount CWalletTx::GetAnonymizedCredit(const CCoinControl& coinControl) const { if (!pwallet) return 0; @@ -2004,9 +2004,6 @@ CAmount CWalletTx::GetAnonymizedCredit(const CCoinControl* coinControl) const if (IsCoinBase() || GetDepthInMainChain() < 0) return 0; - if (coinControl == nullptr && m_amounts[ANON_CREDIT].m_cached[ISMINE_SPENDABLE]) - return m_amounts[ANON_CREDIT].m_value[ISMINE_SPENDABLE]; - CAmount nCredit = 0; uint256 hashTx = GetHash(); for (unsigned int i = 0; i < tx->vout.size(); i++) @@ -2014,7 +2011,7 @@ CAmount CWalletTx::GetAnonymizedCredit(const CCoinControl* coinControl) const const CTxOut &txout = tx->vout[i]; const COutPoint outpoint = COutPoint(hashTx, i); - if (coinControl != nullptr && coinControl->HasSelected() && !coinControl->IsSelected(outpoint)) { + if (coinControl.HasSelected() && !coinControl.IsSelected(outpoint)) { continue; } @@ -2027,39 +2024,67 @@ CAmount CWalletTx::GetAnonymizedCredit(const CCoinControl* coinControl) const } } - if (coinControl == nullptr) { - m_amounts[ANON_CREDIT].Set(ISMINE_SPENDABLE, nCredit); + return nCredit; +} + +CAmount CWalletTx::GetAnonymizedCredit() const +{ + if (!pwallet) + return 0; + + AssertLockHeld(pwallet->cs_wallet); + + // Exclude coinbase and conflicted txes + if (IsCoinBase() || GetDepthInMainChain() < 0) + return 0; + + if (m_amounts[ANON_CREDIT].m_cached[ISMINE_SPENDABLE]) + return m_amounts[ANON_CREDIT].m_value[ISMINE_SPENDABLE]; + + CAmount nCredit = 0; + uint256 hashTx = GetHash(); + for (unsigned int i = 0; i < tx->vout.size(); i++) + { + const CTxOut &txout = tx->vout[i]; + const COutPoint outpoint = COutPoint(hashTx, i); + + if (pwallet->IsSpent(hashTx, i) || !CoinJoin::IsDenominatedAmount(txout.nValue)) continue; + + if (pwallet->IsFullyMixed(outpoint)) { + nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); + if (!MoneyRange(nCredit)) + throw std::runtime_error(std::string(__func__) + ": value out of range"); + } } + m_amounts[ANON_CREDIT].Set(ISMINE_SPENDABLE, nCredit); + return nCredit; } -CAmount CWalletTx::GetDenominatedCredit(bool unconfirmed, bool fUseCache) const +CWalletTx::BalanceAnonymized CWalletTx::GetDenominatedCredit() const { + CWalletTx::BalanceAnonymized ret{0, false}; if (pwallet == nullptr) - return 0; + return ret; AssertLockHeld(pwallet->cs_wallet); // Must wait until coinbase is safely deep enough in the chain before valuing it if (IsCoinBase() && GetBlocksToMaturity() > 0) - return 0; + return ret; int nDepth = GetDepthInMainChain(); - if (nDepth < 0) return 0; + if (nDepth < 0) return ret; - bool isUnconfirmed = IsTrusted() && nDepth == 0; - if (unconfirmed != isUnconfirmed) return 0; + ret.is_unconfirmed = IsTrusted() && nDepth == 0; - if (fUseCache) { - if(unconfirmed && m_amounts[DENOM_UCREDIT].m_cached[ISMINE_SPENDABLE]) { - return m_amounts[DENOM_UCREDIT].m_value[ISMINE_SPENDABLE]; - } else if (!unconfirmed && m_amounts[DENOM_CREDIT].m_cached[ISMINE_SPENDABLE]) { - return m_amounts[DENOM_CREDIT].m_value[ISMINE_SPENDABLE]; - } + if(ret.is_unconfirmed && m_amounts[DENOM_UCREDIT].m_cached[ISMINE_SPENDABLE]) { + return {m_amounts[DENOM_UCREDIT].m_value[ISMINE_SPENDABLE], ret.is_unconfirmed}; + } else if (!ret.is_unconfirmed && m_amounts[DENOM_CREDIT].m_cached[ISMINE_SPENDABLE]) { + return {m_amounts[DENOM_CREDIT].m_value[ISMINE_SPENDABLE], ret.is_unconfirmed}; } - CAmount nCredit = 0; uint256 hashTx = GetHash(); for (unsigned int i = 0; i < tx->vout.size(); i++) { @@ -2067,17 +2092,17 @@ CAmount CWalletTx::GetDenominatedCredit(bool unconfirmed, bool fUseCache) const if (pwallet->IsSpent(hashTx, i) || !CoinJoin::IsDenominatedAmount(txout.nValue)) continue; - nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); - if (!MoneyRange(nCredit)) + ret.m_denom_credit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); + if (!MoneyRange(ret.m_denom_credit)) throw std::runtime_error(std::string(__func__) + ": value out of range"); } - if (unconfirmed) { - m_amounts[DENOM_UCREDIT].Set(ISMINE_SPENDABLE, nCredit); + if (ret.is_unconfirmed) { + m_amounts[DENOM_UCREDIT].Set(ISMINE_SPENDABLE, ret.m_denom_credit); } else { - m_amounts[DENOM_CREDIT].Set(ISMINE_SPENDABLE, nCredit); + m_amounts[DENOM_CREDIT].Set(ISMINE_SPENDABLE, ret.m_denom_credit); } - return nCredit; + return ret; } // Rebroadcast transactions from the wallet. We do this on a random timer diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 50b06c635b6d..53fdd0e809df 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -709,7 +709,8 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati CAmount m_denominated_trusted{0}; CAmount m_denominated_untrusted_pending{0}; }; - Balance GetBalance(const int min_depth = 0, const bool avoid_reuse = true, const bool fAddLocked = false, const CCoinControl* coinControl = nullptr) const; + Balance GetBalance(const int min_depth = 0, const bool avoid_reuse = true, const bool fAddLocked = false) const; + CAmount GetBalanceAnonymized(const CCoinControl& coinControl) const; CAmount GetAnonymizableBalance(bool fSkipDenominated = false, bool fSkipUnconfirmed = true) const; float GetAverageAnonymizedRounds() const; From 8e786e875583a16a001c5b37266bcdab19872857 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Mon, 6 Jan 2025 02:34:40 +0700 Subject: [PATCH 3/8] perf: optimize more CWallet::GetBalance for anonymized balance --- src/wallet/receive.cpp | 4 +-- src/wallet/transaction.h | 4 +-- src/wallet/wallet.cpp | 61 ++++++++++++---------------------------- 3 files changed, 22 insertions(+), 47 deletions(-) diff --git a/src/wallet/receive.cpp b/src/wallet/receive.cpp index 62381c306e28..f70a87111698 100644 --- a/src/wallet/receive.cpp +++ b/src/wallet/receive.cpp @@ -350,8 +350,8 @@ CWallet::Balance CWallet::GetBalance(const int min_depth, const bool avoid_reuse ret.m_mine_immature += wtx.GetImmatureCredit(); ret.m_watchonly_immature += wtx.GetImmatureWatchOnlyCredit(); if (CCoinJoinClientOptions::IsEnabled()) { - ret.m_anonymized += wtx.GetAnonymizedCredit(); - const auto balance_anonymized = wtx.GetDenominatedCredit(); + const auto balance_anonymized = wtx.GetAnonymizedBalance(); + ret.m_anonymized += balance_anonymized.m_anonymized; if (balance_anonymized.is_unconfirmed) { ret.m_denominated_untrusted_pending += balance_anonymized.m_denom_credit; } else { diff --git a/src/wallet/transaction.h b/src/wallet/transaction.h index e0952665da4d..e0b36d869f78 100644 --- a/src/wallet/transaction.h +++ b/src/wallet/transaction.h @@ -291,6 +291,7 @@ class CWalletTx struct BalanceAnonymized { + CAmount m_anonymized{0}; CAmount m_denom_credit{0}; bool is_unconfirmed{false}; }; @@ -299,9 +300,8 @@ class CWalletTx // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The // annotation "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid // having to resolve the issue of member access into incomplete type CWallet. - CAmount GetAnonymizedCredit() const NO_THREAD_SAFETY_ANALYSIS; CAmount GetAnonymizedCredit(const CCoinControl& coinControl) const NO_THREAD_SAFETY_ANALYSIS; - BalanceAnonymized GetDenominatedCredit() const NO_THREAD_SAFETY_ANALYSIS; + BalanceAnonymized GetAnonymizedBalance() const NO_THREAD_SAFETY_ANALYSIS; /** Get the marginal bytes if spending the specified output from this transaction */ int GetSpendSize(unsigned int out, bool use_max_sig = false) const diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index d0fa2c8a6afa..b0f08000a9e4 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2027,42 +2027,7 @@ CAmount CWalletTx::GetAnonymizedCredit(const CCoinControl& coinControl) const return nCredit; } -CAmount CWalletTx::GetAnonymizedCredit() const -{ - if (!pwallet) - return 0; - - AssertLockHeld(pwallet->cs_wallet); - - // Exclude coinbase and conflicted txes - if (IsCoinBase() || GetDepthInMainChain() < 0) - return 0; - - if (m_amounts[ANON_CREDIT].m_cached[ISMINE_SPENDABLE]) - return m_amounts[ANON_CREDIT].m_value[ISMINE_SPENDABLE]; - - CAmount nCredit = 0; - uint256 hashTx = GetHash(); - for (unsigned int i = 0; i < tx->vout.size(); i++) - { - const CTxOut &txout = tx->vout[i]; - const COutPoint outpoint = COutPoint(hashTx, i); - - if (pwallet->IsSpent(hashTx, i) || !CoinJoin::IsDenominatedAmount(txout.nValue)) continue; - - if (pwallet->IsFullyMixed(outpoint)) { - nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); - if (!MoneyRange(nCredit)) - throw std::runtime_error(std::string(__func__) + ": value out of range"); - } - } - - m_amounts[ANON_CREDIT].Set(ISMINE_SPENDABLE, nCredit); - - return nCredit; -} - -CWalletTx::BalanceAnonymized CWalletTx::GetDenominatedCredit() const +CWalletTx::BalanceAnonymized CWalletTx::GetAnonymizedBalance() const { CWalletTx::BalanceAnonymized ret{0, false}; if (pwallet == nullptr) @@ -2079,24 +2044,34 @@ CWalletTx::BalanceAnonymized CWalletTx::GetDenominatedCredit() const ret.is_unconfirmed = IsTrusted() && nDepth == 0; - if(ret.is_unconfirmed && m_amounts[DENOM_UCREDIT].m_cached[ISMINE_SPENDABLE]) { - return {m_amounts[DENOM_UCREDIT].m_value[ISMINE_SPENDABLE], ret.is_unconfirmed}; - } else if (!ret.is_unconfirmed && m_amounts[DENOM_CREDIT].m_cached[ISMINE_SPENDABLE]) { - return {m_amounts[DENOM_CREDIT].m_value[ISMINE_SPENDABLE], ret.is_unconfirmed}; + if (m_amounts[ANON_CREDIT].m_cached[ISMINE_SPENDABLE]) { + if (ret.is_unconfirmed && m_amounts[DENOM_UCREDIT].m_cached[ISMINE_SPENDABLE]) { + return {m_amounts[ANON_CREDIT].m_value[ISMINE_SPENDABLE], m_amounts[DENOM_UCREDIT].m_value[ISMINE_SPENDABLE], ret.is_unconfirmed}; + } else if (!ret.is_unconfirmed && m_amounts[DENOM_CREDIT].m_cached[ISMINE_SPENDABLE]) { + return {m_amounts[ANON_CREDIT].m_value[ISMINE_SPENDABLE], m_amounts[DENOM_CREDIT].m_value[ISMINE_SPENDABLE], ret.is_unconfirmed}; + } } uint256 hashTx = GetHash(); - for (unsigned int i = 0; i < tx->vout.size(); i++) - { + for (unsigned int i = 0; i < tx->vout.size(); i++) { const CTxOut &txout = tx->vout[i]; + const COutPoint outpoint = COutPoint(hashTx, i); if (pwallet->IsSpent(hashTx, i) || !CoinJoin::IsDenominatedAmount(txout.nValue)) continue; + const CAmount credit = pwallet->GetCredit(txout, ISMINE_SPENDABLE); + + if (pwallet->IsFullyMixed(outpoint)) { + ret.m_anonymized += credit; + if (!MoneyRange(ret.m_anonymized)) + throw std::runtime_error(std::string(__func__) + ": value out of range"); + } - ret.m_denom_credit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); + ret.m_denom_credit += credit; if (!MoneyRange(ret.m_denom_credit)) throw std::runtime_error(std::string(__func__) + ": value out of range"); } + m_amounts[ANON_CREDIT].Set(ISMINE_SPENDABLE, ret.m_anonymized); if (ret.is_unconfirmed) { m_amounts[DENOM_UCREDIT].Set(ISMINE_SPENDABLE, ret.m_denom_credit); } else { From ffd119bdbf961a68e111cbe9b2acc12032042f65 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Fri, 31 Jan 2025 03:49:34 +0700 Subject: [PATCH 4/8] perf: reduce duplicating requests for CJ balance in Qt app --- src/interfaces/wallet.h | 5 ++--- src/qt/overviewpage.cpp | 7 +++---- src/wallet/interfaces.cpp | 11 ++--------- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index f65564ba1558..d6a0cf413a68 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -223,9 +223,6 @@ class Wallet //! Get anonymizable balance. virtual CAmount getAnonymizableBalance(bool fSkipDenominated, bool fSkipUnconfirmed) = 0; - //! Get denominated balance. - virtual CAmount getDenominatedBalance(bool unconfirmed) = 0; - //! Get normalized anonymized balance. virtual CAmount getNormalizedAnonymizedBalance() = 0; @@ -385,6 +382,8 @@ struct WalletBalances CAmount watch_only_balance = 0; CAmount unconfirmed_watch_only_balance = 0; CAmount immature_watch_only_balance = 0; + CAmount denominated_untrusted_pending = 0; + CAmount denominated_trusted = 0; bool balanceChanged(const WalletBalances& prev) const { diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index ca079d9e89d1..1c430b457c9d 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -423,13 +423,12 @@ void OverviewPage::updateCoinJoinProgress() if (!fShowAdvancedCJUI) return; - CAmount nDenominatedConfirmedBalance; - CAmount nDenominatedUnconfirmedBalance; + const interfaces::WalletBalances balances = walletModel->wallet().getBalances(); + CAmount nDenominatedConfirmedBalance = balances.denominated_trusted; + CAmount nDenominatedUnconfirmedBalance = balances.denominated_untrusted_pending; CAmount nNormalizedAnonymizedBalance; float nAverageAnonymizedRounds; - nDenominatedConfirmedBalance = walletModel->wallet().getDenominatedBalance(false); - nDenominatedUnconfirmedBalance = walletModel->wallet().getDenominatedBalance(true); nNormalizedAnonymizedBalance = walletModel->wallet().getNormalizedAnonymizedBalance(); nAverageAnonymizedRounds = walletModel->wallet().getAverageAnonymizedRounds(); diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index 4992c1f9490a..67a2e5467a5a 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -392,6 +392,8 @@ class WalletImpl : public Wallet result.unconfirmed_watch_only_balance = bal.m_watchonly_untrusted_pending; result.immature_watch_only_balance = bal.m_watchonly_immature; } + result.denominated_untrusted_pending = bal.m_denominated_untrusted_pending; + result.denominated_trusted = bal.m_denominated_trusted; return result; } bool tryGetBalances(WalletBalances& balances, uint256& block_hash) override @@ -412,15 +414,6 @@ class WalletImpl : public Wallet { return m_wallet->GetAnonymizableBalance(fSkipDenominated, fSkipUnconfirmed); } - CAmount getDenominatedBalance(bool unconfirmed) override - { - const auto bal = m_wallet->GetBalance(); - if (unconfirmed) { - return bal.m_denominated_untrusted_pending; - } else { - return bal.m_denominated_trusted; - } - } CAmount getNormalizedAnonymizedBalance() override { return m_wallet->GetNormalizedAnonymizedBalance(); From 0f309a40d4ae9c7416d3c3896caa7ba2e5d34fe7 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Tue, 4 Feb 2025 19:06:37 +0700 Subject: [PATCH 5/8] perf: avoid atomic / static variables inside loop in GetBalance --- src/wallet/receive.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wallet/receive.cpp b/src/wallet/receive.cpp index f70a87111698..3660451c671c 100644 --- a/src/wallet/receive.cpp +++ b/src/wallet/receive.cpp @@ -329,6 +329,7 @@ CWallet::Balance CWallet::GetBalance(const int min_depth, const bool avoid_reuse { Balance ret; isminefilter reuse_filter = avoid_reuse ? ISMINE_NO : ISMINE_USED; + const bool cj_enabled = CCoinJoinClientOptions::IsEnabled(); { LOCK(cs_wallet); std::set trusted_parents; @@ -349,7 +350,7 @@ CWallet::Balance CWallet::GetBalance(const int min_depth, const bool avoid_reuse } ret.m_mine_immature += wtx.GetImmatureCredit(); ret.m_watchonly_immature += wtx.GetImmatureWatchOnlyCredit(); - if (CCoinJoinClientOptions::IsEnabled()) { + if (cj_enabled) { const auto balance_anonymized = wtx.GetAnonymizedBalance(); ret.m_anonymized += balance_anonymized.m_anonymized; if (balance_anonymized.is_unconfirmed) { From 7f3b75feac0bb2ac208d72356e5f24530d4fdb59 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Sun, 2 Feb 2025 14:08:23 +0300 Subject: [PATCH 6/8] refactor: change some names why: - we calculate credits only, so "balance"->"credits" - we calculate unspent credits only, so use word "Available" for func name - "Anonymized" means "fully mixed denominated", so use word "CoinJoin" for struct and func names instead --- src/wallet/transaction.h | 6 +++--- src/wallet/wallet.cpp | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/wallet/transaction.h b/src/wallet/transaction.h index e0b36d869f78..0e0840f4c3bf 100644 --- a/src/wallet/transaction.h +++ b/src/wallet/transaction.h @@ -289,10 +289,10 @@ class CWalletTx CAmount GetImmatureWatchOnlyCredit(const bool fUseCache = true) const; CAmount GetChange() const; - struct BalanceAnonymized + struct CoinJoinCredits { CAmount m_anonymized{0}; - CAmount m_denom_credit{0}; + CAmount m_denominated{0}; bool is_unconfirmed{false}; }; @@ -301,7 +301,7 @@ class CWalletTx // annotation "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid // having to resolve the issue of member access into incomplete type CWallet. CAmount GetAnonymizedCredit(const CCoinControl& coinControl) const NO_THREAD_SAFETY_ANALYSIS; - BalanceAnonymized GetAnonymizedBalance() const NO_THREAD_SAFETY_ANALYSIS; + CoinJoinCredits GetAvailableCoinJoinCredits() const NO_THREAD_SAFETY_ANALYSIS; /** Get the marginal bytes if spending the specified output from this transaction */ int GetSpendSize(unsigned int out, bool use_max_sig = false) const diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index b0f08000a9e4..269a8e0aedf5 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2027,9 +2027,9 @@ CAmount CWalletTx::GetAnonymizedCredit(const CCoinControl& coinControl) const return nCredit; } -CWalletTx::BalanceAnonymized CWalletTx::GetAnonymizedBalance() const +CWalletTx::CoinJoinCredits CWalletTx::GetAvailableCoinJoinCredits() const { - CWalletTx::BalanceAnonymized ret{0, false}; + CWalletTx::CoinJoinCredits ret{0, false}; if (pwallet == nullptr) return ret; @@ -2066,16 +2066,16 @@ CWalletTx::BalanceAnonymized CWalletTx::GetAnonymizedBalance() const throw std::runtime_error(std::string(__func__) + ": value out of range"); } - ret.m_denom_credit += credit; - if (!MoneyRange(ret.m_denom_credit)) + ret.m_denominated += credit; + if (!MoneyRange(ret.m_denominated)) throw std::runtime_error(std::string(__func__) + ": value out of range"); } m_amounts[ANON_CREDIT].Set(ISMINE_SPENDABLE, ret.m_anonymized); if (ret.is_unconfirmed) { - m_amounts[DENOM_UCREDIT].Set(ISMINE_SPENDABLE, ret.m_denom_credit); + m_amounts[DENOM_UCREDIT].Set(ISMINE_SPENDABLE, ret.m_denominated); } else { - m_amounts[DENOM_CREDIT].Set(ISMINE_SPENDABLE, ret.m_denom_credit); + m_amounts[DENOM_CREDIT].Set(ISMINE_SPENDABLE, ret.m_denominated); } return ret; } From df208d47101d55fd5f9118b9fa3f3da0ceeae366 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Mon, 10 Feb 2025 14:52:44 +0700 Subject: [PATCH 7/8] fix: nits fixes by coderabbit recommendations --- src/wallet/transaction.h | 2 ++ src/wallet/wallet.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/wallet/transaction.h b/src/wallet/transaction.h index 0e0840f4c3bf..0847646bed55 100644 --- a/src/wallet/transaction.h +++ b/src/wallet/transaction.h @@ -300,7 +300,9 @@ class CWalletTx // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The // annotation "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid // having to resolve the issue of member access into incomplete type CWallet. + /* Requires cs_wallet lock. */ CAmount GetAnonymizedCredit(const CCoinControl& coinControl) const NO_THREAD_SAFETY_ANALYSIS; + /* Requires cs_wallet lock. */ CoinJoinCredits GetAvailableCoinJoinCredits() const NO_THREAD_SAFETY_ANALYSIS; /** Get the marginal bytes if spending the specified output from this transaction */ diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 269a8e0aedf5..b7d9f05c6138 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2029,7 +2029,7 @@ CAmount CWalletTx::GetAnonymizedCredit(const CCoinControl& coinControl) const CWalletTx::CoinJoinCredits CWalletTx::GetAvailableCoinJoinCredits() const { - CWalletTx::CoinJoinCredits ret{0, false}; + CWalletTx::CoinJoinCredits ret; if (pwallet == nullptr) return ret; From 0363185824b57b9823b07e63543206d9cd2f5515 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Mon, 10 Feb 2025 22:39:58 +0700 Subject: [PATCH 8/8] fix: missing conflicts changes --- src/wallet/receive.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wallet/receive.cpp b/src/wallet/receive.cpp index 3660451c671c..d2631466bd44 100644 --- a/src/wallet/receive.cpp +++ b/src/wallet/receive.cpp @@ -351,12 +351,12 @@ CWallet::Balance CWallet::GetBalance(const int min_depth, const bool avoid_reuse ret.m_mine_immature += wtx.GetImmatureCredit(); ret.m_watchonly_immature += wtx.GetImmatureWatchOnlyCredit(); if (cj_enabled) { - const auto balance_anonymized = wtx.GetAnonymizedBalance(); + const auto balance_anonymized = wtx.GetAvailableCoinJoinCredits(); ret.m_anonymized += balance_anonymized.m_anonymized; if (balance_anonymized.is_unconfirmed) { - ret.m_denominated_untrusted_pending += balance_anonymized.m_denom_credit; + ret.m_denominated_untrusted_pending += balance_anonymized.m_denominated; } else { - ret.m_denominated_trusted += balance_anonymized.m_denom_credit; + ret.m_denominated_trusted += balance_anonymized.m_denominated; } } }