Skip to content

Commit

Permalink
Use wallet UTXOs whenever possible to avoid looping through all walle…
Browse files Browse the repository at this point in the history
…t txes (#3156)

* Use setWalletUTXO whenever possible to avoid looping through all wallet txes

* Apply review suggestion - GetSpendableTXs()
  • Loading branch information
UdjinM6 authored and codablock committed Oct 17, 2019
1 parent 21d33dd commit 3c6b5f9
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 41 deletions.
76 changes: 35 additions & 41 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2446,14 +2446,33 @@ void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman
*/


std::unordered_set<const CWalletTx*, WalletTxHasher> CWallet::GetSpendableTXs() const
{
AssertLockHeld(cs_wallet);

std::unordered_set<const CWalletTx*, WalletTxHasher> ret;
for (auto it = setWalletUTXO.begin(); it != setWalletUTXO.end(); ) {
const auto& outpoint = *it;
const auto jt = mapWallet.find(outpoint.hash);
if (jt != mapWallet.end()) {
ret.emplace(&jt->second);
}

// setWalletUTXO is sorted by COutPoint, which means that all UTXOs for the same TX are neighbors
// skip entries until we encounter a new TX
while (it != setWalletUTXO.end() && it->hash == outpoint.hash) {
++it;
}
}
return ret;
}

CAmount CWallet::GetBalance() const
{
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
for (auto pcoin : GetSpendableTXs()) {
if (pcoin->IsTrusted())
nTotal += pcoin->GetAvailableCredit();
}
Expand Down Expand Up @@ -2492,15 +2511,8 @@ CAmount CWallet::GetAnonymizedBalance() const

LOCK2(cs_main, cs_wallet);

std::set<uint256> setWalletTxesCounted;
for (const auto& outpoint : setWalletUTXO) {

if (!setWalletTxesCounted.emplace(outpoint.hash).second) continue;

const auto it = mapWallet.find(outpoint.hash);
if (it == mapWallet.end() || !it->second.IsTrusted()) continue;

nTotal += it->second.GetAnonymizedCredit();
for (auto pcoin : GetSpendableTXs()) {
nTotal += pcoin->GetAnonymizedCredit();
}

return nTotal;
Expand Down Expand Up @@ -2560,14 +2572,8 @@ CAmount CWallet::GetDenominatedBalance(bool unconfirmed) const

LOCK2(cs_main, cs_wallet);

std::set<uint256> setWalletTxesCounted;
for (const auto& outpoint : setWalletUTXO) {
if (!setWalletTxesCounted.emplace(outpoint.hash).second) continue;

const auto it = mapWallet.find(outpoint.hash);
if (it == mapWallet.end()) continue;

nTotal += it->second.GetDenominatedCredit(unconfirmed);
for (auto pcoin : GetSpendableTXs()) {
nTotal += pcoin->GetDenominatedCredit(unconfirmed);
}

return nTotal;
Expand All @@ -2578,9 +2584,7 @@ CAmount CWallet::GetUnconfirmedBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
for (auto pcoin : GetSpendableTXs()) {
if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && !pcoin->IsLockedByInstantSend() && pcoin->InMempool())
nTotal += pcoin->GetAvailableCredit();
}
Expand All @@ -2593,9 +2597,7 @@ CAmount CWallet::GetImmatureBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
for (auto pcoin : GetSpendableTXs()) {
nTotal += pcoin->GetImmatureCredit();
}
}
Expand All @@ -2607,9 +2609,7 @@ CAmount CWallet::GetWatchOnlyBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
for (auto pcoin : GetSpendableTXs()) {
if (pcoin->IsTrusted())
nTotal += pcoin->GetAvailableWatchOnlyCredit();
}
Expand All @@ -2623,9 +2623,7 @@ CAmount CWallet::GetUnconfirmedWatchOnlyBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
for (auto pcoin : GetSpendableTXs()) {
if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && !pcoin->IsLockedByInstantSend() && pcoin->InMempool())
nTotal += pcoin->GetAvailableWatchOnlyCredit();
}
Expand All @@ -2638,9 +2636,7 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
for (auto pcoin : GetSpendableTXs()) {
nTotal += pcoin->GetImmatureWatchOnlyCredit();
}
}
Expand Down Expand Up @@ -2714,10 +2710,8 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const

CAmount nTotal = 0;

for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const uint256& wtxid = it->first;
const CWalletTx* pcoin = &(*it).second;
for (auto pcoin : GetSpendableTXs()) {
const uint256& wtxid = pcoin->GetHash();

if (!CheckFinalTx(*pcoin))
continue;
Expand Down Expand Up @@ -2760,10 +2754,10 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const
if (pcoin->tx->vout[i].nValue < nMinimumAmount || pcoin->tx->vout[i].nValue > nMaximumAmount)
continue;

if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs && !coinControl->IsSelected(COutPoint((*it).first, i)))
if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs && !coinControl->IsSelected(COutPoint(wtxid, i)))
continue;

if (IsLockedCoin((*it).first, i) && nCoinType != ONLY_1000)
if (IsLockedCoin(wtxid, i) && nCoinType != ONLY_1000)
continue;

if (IsSpent(wtxid, i))
Expand Down
12 changes: 12 additions & 0 deletions src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "amount.h"
#include "base58.h"
#include "policy/feerate.h"
#include "saltedhasher.h"
#include "streams.h"
#include "tinyformat.h"
#include "ui_interface.h"
Expand Down Expand Up @@ -518,6 +519,14 @@ class CWalletTx : public CMerkleTx
std::set<uint256> GetConflicts() const;
};

struct WalletTxHasher
{
StaticSaltedHasher h;
size_t operator()(const CWalletTx* a) const
{
return h(a->GetHash());
}
};

class CInputCoin {
public:
Expand Down Expand Up @@ -775,6 +784,9 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
// the next block comes in
uint256 hashPrevBestCoinbase;

// A helper function which loops through wallet UTXOs
std::unordered_set<const CWalletTx*, WalletTxHasher> GetSpendableTXs() const;

public:
/*
* Main wallet lock.
Expand Down

0 comments on commit 3c6b5f9

Please sign in to comment.