From b4e607b4e1f762e9e6ec55774476aefea304f7bd Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Tue, 20 Aug 2019 22:56:13 -0700 Subject: [PATCH] Select smallest coins for contracts --- src/wallet.cpp | 43 ++++++++++++++++++++++++++++++++++++------- src/wallet.h | 4 ++-- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/wallet.cpp b/src/wallet.cpp index a8d07af43f..da4936655c 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1341,7 +1341,19 @@ int64_t CWallet::GetNewMint() const return nTotal; } -bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, unsigned int nSpendTime, int nConfMine, int nConfTheirs, vector vCoins, set >& setCoinsRet, int64_t& nValueRet) const +// This comparator is needed since std::sort alone cannot sort COutput +struct smallestcoincomp +{ + bool operator() (const COutput a, const COutput b) + { + const CWalletTx* acoin = a.tx; + const CWalletTx* bcoin = b.tx; + + return (acoin->vout[a.i].nValue < bcoin->vout[b.i].nValue); + } +}; + +bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, unsigned int nSpendTime, int nConfMine, int nConfTheirs, vector vCoins, set >& setCoinsRet, int64_t& nValueRet, bool contract) const { setCoinsRet.clear(); nValueRet = 0; @@ -1353,7 +1365,12 @@ bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, unsigned int nSpendTime, vector > > vValue; int64_t nTotalLower = 0; - random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt); + // For contracts lets sort instead of random shuffle so we use lowest coin inputs first and not affect larger coin inputs that could be staking when possible + if (contract) + sort(vCoins.begin(), vCoins.end(), smallestcoincomp()); + + else + random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt); for (auto output : vCoins) { @@ -1447,7 +1464,7 @@ bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, unsigned int nSpendTime, return true; } -bool CWallet::SelectCoins(int64_t nTargetValue, unsigned int nSpendTime, set >& setCoinsRet, int64_t& nValueRet, const CCoinControl* coinControl) const +bool CWallet::SelectCoins(int64_t nTargetValue, unsigned int nSpendTime, set >& setCoinsRet, int64_t& nValueRet, const CCoinControl* coinControl, bool contract) const { vector vCoins; AvailableCoins(vCoins, true, coinControl, false); @@ -1463,9 +1480,9 @@ bool CWallet::SelectCoins(int64_t nTargetValue, unsigned int nSpendTime, set= nTargetValue); } - return (SelectCoinsMinConf(nTargetValue, nSpendTime, 1, 10, vCoins, setCoinsRet, nValueRet) || - SelectCoinsMinConf(nTargetValue, nSpendTime, 1, 1, vCoins, setCoinsRet, nValueRet) || - SelectCoinsMinConf(nTargetValue, nSpendTime, 0, 1, vCoins, setCoinsRet, nValueRet)); + return (SelectCoinsMinConf(nTargetValue, nSpendTime, 1, 10, vCoins, setCoinsRet, nValueRet, contract) || + SelectCoinsMinConf(nTargetValue, nSpendTime, 1, 1, vCoins, setCoinsRet, nValueRet, contract) || + SelectCoinsMinConf(nTargetValue, nSpendTime, 0, 1, vCoins, setCoinsRet, nValueRet, contract)); } // Select some coins without random shuffle or best subset approximation @@ -1551,12 +1568,24 @@ bool CWallet::CreateTransaction(const vector >& vecSend, for (auto const& s : vecSend) wtxNew.vout.push_back(CTxOut(s.second, s.first)); + + // Determine if transaction is a contract + bool contract = false; + + if (!wtxNew.hashBoinc.empty() && !coinControl) + { + string contracttype = ExtractXML(wtxNew.hashBoinc, "", ""); + + if (contracttype == "beacon" || contracttype == "vote" || contracttype == "poll" || contracttype == "project") + contract = true; + } + int64_t nValueIn = 0; // If provided coin set is empty, choose coins to use. if (!setCoins.size()) { - if (!SelectCoins(nTotalValue, wtxNew.nTime, setCoins, nValueIn, coinControl)) + if (!SelectCoins(nTotalValue, wtxNew.nTime, setCoins, nValueIn, coinControl, contract)) return false; } else diff --git a/src/wallet.h b/src/wallet.h index 129810270c..08f4fbfff0 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -78,7 +78,7 @@ class CKeyPool class CWallet : public CCryptoKeyStore { private: - bool SelectCoins(int64_t nTargetValue, unsigned int nSpendTime, std::set >& setCoinsRet, int64_t& nValueRet, const CCoinControl *coinControl=NULL) const; + bool SelectCoins(int64_t nTargetValue, unsigned int nSpendTime, std::set >& setCoinsRet, int64_t& nValueRet, const CCoinControl *coinControl=NULL, bool contract = false) const; CWalletDB *pwalletdbEncryption; @@ -144,7 +144,7 @@ class CWallet : public CCryptoKeyStore void AvailableCoinsForStaking(std::vector& vCoins, unsigned int nSpendTime) const; bool SelectCoinsForStaking(int64_t nTargetValue, unsigned int nSpendTime, std::set >& setCoinsRet, int64_t& nValueRet) const; void AvailableCoins(std::vector& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl=NULL, bool fIncludeStakingCoins=false) const; - bool SelectCoinsMinConf(int64_t nTargetValue, unsigned int nSpendTime, int nConfMine, int nConfTheirs, std::vector vCoins, std::set >& setCoinsRet, int64_t& nValueRet) const; + bool SelectCoinsMinConf(int64_t nTargetValue, unsigned int nSpendTime, int nConfMine, int nConfTheirs, std::vector vCoins, std::set >& setCoinsRet, int64_t& nValueRet, bool contract = false) const; // keystore implementation // Generate a new key