Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions src/interfaces/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,12 +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;

//! Get normalized anonymized balance.
virtual CAmount getNormalizedAnonymizedBalance() = 0;

Expand Down Expand Up @@ -388,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
{
Expand Down
7 changes: 3 additions & 4 deletions src/qt/overviewpage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
17 changes: 3 additions & 14 deletions src/wallet/interfaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -412,19 +414,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();
if (unconfirmed) {
return bal.m_denominated_untrusted_pending;
} else {
return bal.m_denominated_trusted;
}
}
CAmount getNormalizedAnonymizedBalance() override
{
return m_wallet->GetNormalizedAnonymizedBalance();
Expand All @@ -436,7 +425,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);
}
Expand Down
27 changes: 22 additions & 5 deletions src/wallet/receive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,10 +313,23 @@ 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;
Comment on lines +320 to +325
Copy link
Member

Choose a reason for hiding this comment

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

could probably use accumulate

Suggested change
CAmount anonymized_amount{0};
LOCK(cs_wallet);
for (auto pcoin : GetSpendableTXs()) {
anonymized_amount += pcoin->GetAnonymizedCredit(coinControl);
}
return anonymized_amount;
LOCK(cs_wallet);
return std::accumulate(GetSpendableTXs().begin(), GetSpendableTXs().end(), CAmount{0},
[&](CAmount sum, const auto& pcoin) {
return sum + pcoin->GetAnonymizedCredit(coinControl);
});```

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

should not use std::accumulate() without ranges, I think.

GetSpendableTXs() does caclucation inside, it doesn't just return reference to internal structure.
So, begin() and end() can even belong to 2 different data structures in memory.

}

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;
const bool cj_enabled = CCoinJoinClientOptions::IsEnabled();
{
LOCK(cs_wallet);
std::set<uint256> trusted_parents;
Expand All @@ -337,10 +350,14 @@ 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);
if (cj_enabled) {
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_denominated;
} else {
ret.m_denominated_trusted += balance_anonymized.m_denominated;
}
}
}
}
Expand Down
13 changes: 11 additions & 2 deletions src/wallet/transaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,12 +289,21 @@ class CWalletTx
CAmount GetImmatureWatchOnlyCredit(const bool fUseCache = true) const;
CAmount GetChange() const;

struct CoinJoinCredits
{
CAmount m_anonymized{0};
CAmount m_denominated{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;
/* 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 */
int GetSpendSize(unsigned int out, bool use_max_sig = false) const
Expand Down
58 changes: 29 additions & 29 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1993,7 +1993,7 @@ std::set<uint256> CWalletTx::GetConflicts() const
return result;
}

CAmount CWalletTx::GetAnonymizedCredit(const CCoinControl* coinControl) const
CAmount CWalletTx::GetAnonymizedCredit(const CCoinControl& coinControl) const
{
if (!pwallet)
return 0;
Expand All @@ -2004,17 +2004,14 @@ 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++)
{
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;
}

Expand All @@ -2027,57 +2024,60 @@ CAmount CWalletTx::GetAnonymizedCredit(const CCoinControl* coinControl) const
}
}

if (coinControl == nullptr) {
m_amounts[ANON_CREDIT].Set(ISMINE_SPENDABLE, nCredit);
}

return nCredit;
}

CAmount CWalletTx::GetDenominatedCredit(bool unconfirmed, bool fUseCache) const
CWalletTx::CoinJoinCredits CWalletTx::GetAvailableCoinJoinCredits() const
{
CWalletTx::CoinJoinCredits ret;
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 (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};
}
}

CAmount nCredit = 0;
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);

nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE);
if (!MoneyRange(nCredit))
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_denominated += credit;
if (!MoneyRange(ret.m_denominated))
throw std::runtime_error(std::string(__func__) + ": value out of range");
}

if (unconfirmed) {
m_amounts[DENOM_UCREDIT].Set(ISMINE_SPENDABLE, nCredit);
m_amounts[ANON_CREDIT].Set(ISMINE_SPENDABLE, ret.m_anonymized);
if (ret.is_unconfirmed) {
m_amounts[DENOM_UCREDIT].Set(ISMINE_SPENDABLE, ret.m_denominated);
} else {
m_amounts[DENOM_CREDIT].Set(ISMINE_SPENDABLE, nCredit);
m_amounts[DENOM_CREDIT].Set(ISMINE_SPENDABLE, ret.m_denominated);
}
return nCredit;
return ret;
}

// Rebroadcast transactions from the wallet. We do this on a random timer
Expand Down
3 changes: 2 additions & 1 deletion src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading