Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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.GetAnonymizedBalance();
ret.m_anonymized += balance_anonymized.m_anonymized;
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;
}
}
}
}
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