Skip to content

Commit

Permalink
adds CWallet::AvailableCoins performance improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
pedro-at-decenomy committed Sep 24, 2024
1 parent 63f8523 commit a0ad6a3
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 38 deletions.
127 changes: 90 additions & 37 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -588,9 +588,10 @@ ScriptPubKeyMan* CWallet::GetScriptPubKeyMan() const
* Outpoint is spent if any non-conflicted transaction
* spends it:
*/
bool CWallet::IsSpent(const uint256& hash, unsigned int n) const
bool CWallet::IsSpent(const uint256& hash, unsigned int n, int& nSpendDepth) const
{
const COutPoint outpoint(hash, n);
nSpendDepth = 0;
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
range = mapTxSpends.equal_range(outpoint);
for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
Expand All @@ -601,8 +602,10 @@ bool CWallet::IsSpent(const uint256& hash, unsigned int n) const
const int nDepth = mit->second.GetDepthAndMempool(fConflicted);
// not in mempool txes can spend coins only if not coinstakes
const bool fConflictedCoinstake = fConflicted && mit->second.IsCoinStake();
if (nDepth > 0 || (nDepth == 0 && !mit->second.isAbandoned() && !fConflictedCoinstake) )
if (nDepth > 0 || (nDepth == 0 && !mit->second.isAbandoned() && !fConflictedCoinstake)) {
nSpendDepth = nDepth;
return true; // Spent
}
}
}
return false;
Expand Down Expand Up @@ -823,6 +826,9 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
// Inserts only if not already there, returns tx inserted or tx found
auto ret = mapWallet.insert(std::make_pair(hash, wtxIn));
CWalletTx& wtx = (*ret.first).second;
if(ret.second) { // if it is a newly inserted transaction
setWallet.insert(hash);
}
wtx.BindWallet(this);
bool fInsertedNew = ret.second;
if (fInsertedNew) {
Expand Down Expand Up @@ -886,6 +892,7 @@ bool CWallet::LoadToWallet(const CWalletTx& wtxIn)
{
const uint256& hash = wtxIn.GetHash();
mapWallet[hash] = wtxIn;
setWallet.insert(hash);
CWalletTx& wtx = mapWallet[hash];
wtx.BindWallet(this);
wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
Expand Down Expand Up @@ -1088,8 +1095,10 @@ void CWallet::EraseFromWallet(const uint256& hash)
return;
{
LOCK(cs_wallet);
if (mapWallet.erase(hash))
if (mapWallet.erase(hash)) {
setWallet.erase(hash);
CWalletDB(strWalletFile).EraseTx(hash);
}
LogPrintf("%s: Erased wtx %s from wallet\n", __func__, hash.GetHex());
}
return;
Expand Down Expand Up @@ -1624,8 +1633,12 @@ CAmount CWallet::loopTxsBalance(std::function<void(const uint256&, const CWallet
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
for (const auto& it : mapWallet) {
method(it.first, it.second, nTotal);

for (const auto& it : setWallet) {
auto it2 = mapWallet.find(it);
if(it2 != mapWallet.end()) {
method(it, it2->second, nTotal);
}
}
}
return nTotal;
Expand All @@ -1650,18 +1663,28 @@ CAmount CWallet::GetAvailableBalance(isminefilter& filter, bool useCache, int mi

CAmount CWallet::GetStakingBalance() const
{
return std::max(CAmount(0), loopTxsBalance(
[](const uint256& id, const CWalletTx& pcoin, CAmount& nTotal) {
if (pcoin.IsTrusted() &&
pcoin.GetDepthInMainChain()
>=
(Params().GetConsensus().NetworkUpgradeActive(chainActive.Height(), Consensus::UPGRADE_STAKE_MIN_DEPTH_V2) ?
Params().GetConsensus().nStakeMinDepthV2 : Params().GetConsensus().nStakeMinDepth)
) {
nTotal += pcoin.GetAvailableCredit(); // available coins
nTotal -= pcoin.GetLockedCredit(); // minus locked coins, if any
}
}));
const auto& nHeight = chainActive.Height();
const auto& params = Params();
const auto& consensus = params.GetConsensus();
const auto& nStakeMinDepth =
consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_STAKE_MIN_DEPTH_V2) ?
consensus.nStakeMinDepthV2 :
consensus.nStakeMinDepth;

return
std::max(
CAmount(0),
loopTxsBalance(
[nStakeMinDepth](const uint256& id, const CWalletTx& pcoin, CAmount& nTotal)
{
if (pcoin.IsTrusted() && pcoin.GetDepthInMainChain() >= nStakeMinDepth)
{
nTotal += pcoin.GetAvailableCredit(); // available coins
nTotal -= pcoin.GetLockedCredit(); // minus locked coins, if any
}
}
)
);
}

CAmount CWallet::GetLockedCoins() const
Expand Down Expand Up @@ -1865,50 +1888,71 @@ bool CWallet::AvailableCoins(std::vector<COutput>* pCoins, // --> populates
if (pCoins) pCoins->clear();
const bool fCoinsSelected = (coinControl != nullptr) && coinControl->HasSelected();

{
LOCK2(cs_main, cs_wallet);
for (auto it = mapWallet.begin(); it != mapWallet.end(); ++it) {
const uint256& wtxid = it->first;
const CWalletTx* pcoin = &(*it).second;
const auto nMaxReorgDepth = GetArg("-maxreorg", DEFAULT_MAX_REORG_DEPTH);
const auto& params = Params();
const auto& consensus = params.GetConsensus();
const auto nHeight = chainActive.Height();
const auto nStakeMinDepth =
consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_STAKE_MIN_DEPTH_V2) ?
consensus.nStakeMinDepthV2 :
consensus.nStakeMinDepth;

LOCK2(cs_main, cs_wallet);

std::vector<uint256> vErase;

for (auto it = setWallet.begin(); it != setWallet.end(); ++it) {

const uint256& wtxid = *it;

auto it2 = mapWallet.find(wtxid);
if(it2 != mapWallet.end()) {
const CWalletTx* pcoin = &(*it2).second;

// Check if the tx is selectable
int nDepth;
if (!CheckTXAvailability(pcoin, fOnlyConfirmed, nDepth))
continue;

// Check min depth requirement for stake inputs
if (nCoinType == STAKEABLE_COINS &&
nDepth
<
(Params().GetConsensus().NetworkUpgradeActive(chainActive.Height(), Consensus::UPGRADE_STAKE_MIN_DEPTH_V2) ?
Params().GetConsensus().nStakeMinDepthV2 : Params().GetConsensus().nStakeMinDepth)) continue;

for (unsigned int i = 0; i < pcoin->vout.size(); i++) {
if (nCoinType == STAKEABLE_COINS && nDepth < nStakeMinDepth) continue;

// Check for only 10k utxo
if (nCoinType == ONLY_10000 && !CMasternode::CheckMasternodeCollateral(pcoin->vout[i].nValue)) continue;
int nMine = 0;
int nMineSpent = 0;

// Check if the utxo was spent.
if (IsSpent(wtxid, i)) continue;
for (unsigned int i = 0; i < pcoin->vout.size(); i++) {

int nSpendDepth;
bool spent = IsSpent(wtxid, i, nSpendDepth);
isminetype mine = IsMine(pcoin->vout[i]);

// Check If not mine
if (mine == ISMINE_NO) continue;

nMine++;

// Check if the utxo was spent.
if (spent) {
if(nSpendDepth > nMaxReorgDepth) nMineSpent++;
continue;
}

// Check for only 10k utxo
if (nCoinType == ONLY_10000 && !CMasternode::CheckMasternodeCollateral(pcoin->vout[i].nValue)) continue;

// Check if watch only utxo are allowed
if (mine == ISMINE_WATCH_ONLY && coinControl && !coinControl->fAllowWatchOnly) continue;

// Skip locked utxo
if (IsLockedCoin((*it).first, i) && nCoinType != ONLY_10000) continue;
if (IsLockedCoin(wtxid, i) && nCoinType != ONLY_10000) continue;

// Skip configured masternode collaterals
if (masternodeConfig.contains(COutPoint((*it).first, i)) && nCoinType != ONLY_10000) continue;
if (masternodeConfig.contains(COutPoint(wtxid, i)) && nCoinType != ONLY_10000) continue;

// Check if we should include zero value utxo
if (pcoin->vout[i].nValue <= 0) continue;

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

bool solvable = IsSolvable(*this, pcoin->vout[i].scriptPubKey);
Expand All @@ -1920,9 +1964,18 @@ bool CWallet::AvailableCoins(std::vector<COutput>* pCoins, // --> populates
if (!pCoins) return true;
pCoins->emplace_back(COutput(pcoin, i, nDepth, spendable, solvable));
}

if(nDepth > 0 && nMine > 0 && nMine == nMineSpent) {
vErase.push_back(wtxid);
}
}
return (pCoins && pCoins->size() > 0);
}

for (auto it = vErase.begin(); it != vErase.end(); ++it) {
setWallet.erase(*it);
}

return (pCoins && pCoins->size() > 0);
}

std::map<CTxDestination , std::vector<COutput> > CWallet::AvailableCoinsByAddress(bool fConfirmed, CAmount maxCoinValue)
Expand Down
9 changes: 8 additions & 1 deletion src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <vector>

#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>

extern CWallet* pwalletMain;

Expand Down Expand Up @@ -336,6 +337,8 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
void setMultiSendDisabled();

boost::unordered_map<uint256, CWalletTx, uint256CheapHasher> mapWallet;
mutable boost::unordered_set<uint256, uint256CheapHasher> setWallet;

std::list<CAccountingEntry> laccentries;

typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair;
Expand Down Expand Up @@ -378,7 +381,11 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
/// Extract txin information and keys from output
bool GetVinAndKeysFromOutput(COutput out, CTxIn& txinRet, CPubKey& pubKeyRet, CKey& keyRet);

bool IsSpent(const uint256& hash, unsigned int n) const;
bool IsSpent(const uint256& hash, unsigned int n, int& nSpendDepth) const;
bool IsSpent(const uint256& hash, unsigned int n) const {
int nSpendDepth;
return IsSpent(hash, n, nSpendDepth);
};

bool IsLockedCoin(const uint256& hash, unsigned int n) const;
void LockCoin(const COutPoint& output);
Expand Down

0 comments on commit a0ad6a3

Please sign in to comment.