Drop custom PS logic for guessing fees etc. from SelectCoins (#2371)
* drop most of custom PS logic from SelectCoins and inject it into regular flow (i.e. SelectCoinsMinConf) * different priority for different denoms * move CompareByPriority higher * update comment Co-Authored-By: UdjinM6 <udjinm6@gmail.com>
This commit is contained in:
parent
02442673d2
commit
23f169c44a
@ -86,8 +86,10 @@ std::string COutput::ToString() const
|
|||||||
|
|
||||||
int COutput::Priority() const
|
int COutput::Priority() const
|
||||||
{
|
{
|
||||||
for (const auto& d : CPrivateSend::GetStandardDenominations())
|
for (const auto& d : CPrivateSend::GetStandardDenominations()) {
|
||||||
if(tx->tx->vout[i].nValue == d) return 10000;
|
// large denoms have lower value
|
||||||
|
if(tx->tx->vout[i].nValue == d) return (float)COIN / d * 10000;
|
||||||
|
}
|
||||||
if(tx->tx->vout[i].nValue < 1*COIN) return 20000;
|
if(tx->tx->vout[i].nValue < 1*COIN) return 20000;
|
||||||
|
|
||||||
//nondenom return largest first
|
//nondenom return largest first
|
||||||
@ -2687,6 +2689,15 @@ static void ApproximateBestSubset(std::vector<std::pair<CAmount, std::pair<const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct CompareByPriority
|
||||||
|
{
|
||||||
|
bool operator()(const COutput& t1,
|
||||||
|
const COutput& t2) const
|
||||||
|
{
|
||||||
|
return t1.Priority() > t2.Priority();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// move denoms down
|
// move denoms down
|
||||||
bool less_then_denom (const COutput& out1, const COutput& out2)
|
bool less_then_denom (const COutput& out1, const COutput& out2)
|
||||||
{
|
{
|
||||||
@ -2704,7 +2715,7 @@ bool less_then_denom (const COutput& out1, const COutput& out2)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMine, const int nConfTheirs, const uint64_t nMaxAncestors, std::vector<COutput> vCoins,
|
bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMine, const int nConfTheirs, const uint64_t nMaxAncestors, std::vector<COutput> vCoins,
|
||||||
std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, bool fUseInstantSend) const
|
std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, AvailableCoinsType nCoinType, bool fUseInstantSend) const
|
||||||
{
|
{
|
||||||
setCoinsRet.clear();
|
setCoinsRet.clear();
|
||||||
nValueRet = 0;
|
nValueRet = 0;
|
||||||
@ -2720,11 +2731,24 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMin
|
|||||||
|
|
||||||
random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
|
random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
|
||||||
|
|
||||||
// move denoms down on the list
|
int tryDenomStart = 0;
|
||||||
std::sort(vCoins.begin(), vCoins.end(), less_then_denom);
|
CAmount nMinChange = MIN_CHANGE;
|
||||||
|
|
||||||
|
if (nCoinType == ONLY_DENOMINATED) {
|
||||||
|
// larger denoms first
|
||||||
|
std::sort(vCoins.rbegin(), vCoins.rend(), CompareByPriority());
|
||||||
|
// we actually want denoms only, so let's skip "non-denom only" step
|
||||||
|
tryDenomStart = 1;
|
||||||
|
// no change is allowed
|
||||||
|
nMinChange = 0;
|
||||||
|
} else {
|
||||||
|
// move denoms down on the list
|
||||||
|
// try not to use denominated coins when not needed, save denoms for privatesend
|
||||||
|
std::sort(vCoins.begin(), vCoins.end(), less_then_denom);
|
||||||
|
}
|
||||||
|
|
||||||
// try to find nondenom first to prevent unneeded spending of mixed coins
|
// try to find nondenom first to prevent unneeded spending of mixed coins
|
||||||
for (unsigned int tryDenom = 0; tryDenom < 2; tryDenom++)
|
for (unsigned int tryDenom = tryDenomStart; tryDenom < 2; tryDenom++)
|
||||||
{
|
{
|
||||||
LogPrint("selectcoins", "tryDenom: %d\n", tryDenom);
|
LogPrint("selectcoins", "tryDenom: %d\n", tryDenom);
|
||||||
vValue.clear();
|
vValue.clear();
|
||||||
@ -2747,6 +2771,13 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMin
|
|||||||
CAmount n = pcoin->tx->vout[i].nValue;
|
CAmount n = pcoin->tx->vout[i].nValue;
|
||||||
if (tryDenom == 0 && CPrivateSend::IsDenominatedAmount(n)) continue; // we don't want denom values on first run
|
if (tryDenom == 0 && CPrivateSend::IsDenominatedAmount(n)) continue; // we don't want denom values on first run
|
||||||
|
|
||||||
|
if (nCoinType == ONLY_DENOMINATED) {
|
||||||
|
// Make sure it's actually anonymized
|
||||||
|
COutPoint outpoint = COutPoint(pcoin->GetHash(), i);
|
||||||
|
int nRounds = GetRealOutpointPrivateSendRounds(outpoint);
|
||||||
|
if (nRounds < privateSendClient.nPrivateSendRounds) continue;
|
||||||
|
}
|
||||||
|
|
||||||
std::pair<CAmount, std::pair<const CWalletTx*,unsigned int> > coin = std::make_pair(n, std::make_pair(pcoin, i));
|
std::pair<CAmount, std::pair<const CWalletTx*,unsigned int> > coin = std::make_pair(n, std::make_pair(pcoin, i));
|
||||||
|
|
||||||
if (n == nTargetValue)
|
if (n == nTargetValue)
|
||||||
@ -2755,7 +2786,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMin
|
|||||||
nValueRet += coin.first;
|
nValueRet += coin.first;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (n < nTargetValue + MIN_CHANGE)
|
else if (n < nTargetValue + nMinChange)
|
||||||
{
|
{
|
||||||
vValue.push_back(coin);
|
vValue.push_back(coin);
|
||||||
nTotalLower += n;
|
nTotalLower += n;
|
||||||
@ -2789,7 +2820,9 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMin
|
|||||||
}
|
}
|
||||||
setCoinsRet.insert(coinLowestLarger.second);
|
setCoinsRet.insert(coinLowestLarger.second);
|
||||||
nValueRet += coinLowestLarger.first;
|
nValueRet += coinLowestLarger.first;
|
||||||
return true;
|
// There is no change in PS, so we know the fee beforehand,
|
||||||
|
// can see if we exceeded the max fee and thus fail quickly.
|
||||||
|
return nCoinType == ONLY_DENOMINATED ? (nValueRet - nTargetValue <= maxTxFee) : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// nTotalLower > nTargetValue
|
// nTotalLower > nTargetValue
|
||||||
@ -2804,13 +2837,13 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMin
|
|||||||
CAmount nBest;
|
CAmount nBest;
|
||||||
|
|
||||||
ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest, fUseInstantSend);
|
ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest, fUseInstantSend);
|
||||||
if (nBest != nTargetValue && nTotalLower >= nTargetValue + MIN_CHANGE)
|
if (nBest != nTargetValue && nTotalLower >= nTargetValue + nMinChange)
|
||||||
ApproximateBestSubset(vValue, nTotalLower, nTargetValue + MIN_CHANGE, vfBest, nBest, fUseInstantSend);
|
ApproximateBestSubset(vValue, nTotalLower, nTargetValue + nMinChange, vfBest, nBest, fUseInstantSend);
|
||||||
|
|
||||||
// If we have a bigger coin and (either the stochastic approximation didn't find a good solution,
|
// If we have a bigger coin and (either the stochastic approximation didn't find a good solution,
|
||||||
// or the next bigger coin is closer), return the bigger coin
|
// or the next bigger coin is closer), return the bigger coin
|
||||||
if (coinLowestLarger.second.first &&
|
if (coinLowestLarger.second.first &&
|
||||||
((nBest != nTargetValue && nBest < nTargetValue + MIN_CHANGE) || coinLowestLarger.first <= nBest))
|
((nBest != nTargetValue && nBest < nTargetValue + nMinChange) || coinLowestLarger.first <= nBest))
|
||||||
{
|
{
|
||||||
setCoinsRet.insert(coinLowestLarger.second);
|
setCoinsRet.insert(coinLowestLarger.second);
|
||||||
nValueRet += coinLowestLarger.first;
|
nValueRet += coinLowestLarger.first;
|
||||||
@ -2829,7 +2862,9 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMin
|
|||||||
LogPrint("selectcoins", "%s - total %s\n", s, FormatMoney(nBest));
|
LogPrint("selectcoins", "%s - total %s\n", s, FormatMoney(nBest));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
// There is no change in PS, so we know the fee beforehand,
|
||||||
|
// can see if we exceeded the max fee and thus fail quickly.
|
||||||
|
return nCoinType == ONLY_DENOMINATED ? (nValueRet - nTargetValue <= maxTxFee) : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl, AvailableCoinsType nCoinType, bool fUseInstantSend) const
|
bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl, AvailableCoinsType nCoinType, bool fUseInstantSend) const
|
||||||
@ -2859,28 +2894,6 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
|
|||||||
return (nValueRet >= nTargetValue);
|
return (nValueRet >= nTargetValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
//if we're doing only denominated, we need to round up to the nearest smallest denomination
|
|
||||||
if(nCoinType == ONLY_DENOMINATED) {
|
|
||||||
std::vector<CAmount> vecPrivateSendDenominations = CPrivateSend::GetStandardDenominations();
|
|
||||||
CAmount nSmallestDenom = vecPrivateSendDenominations.back();
|
|
||||||
// Make outputs by looping through denominations, from large to small
|
|
||||||
for (const auto& nDenom : vecPrivateSendDenominations)
|
|
||||||
{
|
|
||||||
for (const auto& out : vCoins)
|
|
||||||
{
|
|
||||||
//make sure it's the denom we're looking for, round the amount up to smallest denom
|
|
||||||
if(out.tx->tx->vout[out.i].nValue == nDenom && nValueRet + nDenom < nTargetValue + nSmallestDenom) {
|
|
||||||
COutPoint outpoint = COutPoint(out.tx->GetHash(),out.i);
|
|
||||||
int nRounds = GetCappedOutpointPrivateSendRounds(outpoint);
|
|
||||||
// make sure it's actually anonymized
|
|
||||||
if(nRounds < privateSendClient.nPrivateSendRounds) continue;
|
|
||||||
nValueRet += nDenom;
|
|
||||||
setCoinsRet.insert(std::make_pair(out.tx, out.i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (nValueRet >= nTargetValue);
|
|
||||||
}
|
|
||||||
// calculate value from preset inputs and store them
|
// calculate value from preset inputs and store them
|
||||||
std::set<std::pair<const CWalletTx*, uint32_t> > setPresetCoins;
|
std::set<std::pair<const CWalletTx*, uint32_t> > setPresetCoins;
|
||||||
CAmount nValueFromPresetInputs = 0;
|
CAmount nValueFromPresetInputs = 0;
|
||||||
@ -2897,6 +2910,12 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
|
|||||||
// Clearly invalid input, fail
|
// Clearly invalid input, fail
|
||||||
if (pcoin->tx->vout.size() <= outpoint.n)
|
if (pcoin->tx->vout.size() <= outpoint.n)
|
||||||
return false;
|
return false;
|
||||||
|
if (nCoinType == ONLY_DENOMINATED) {
|
||||||
|
// Make sure to include anonymized preset inputs only,
|
||||||
|
// even if some non-anonymized inputs were manually selected via CoinControl
|
||||||
|
int nRounds = GetRealOutpointPrivateSendRounds(outpoint);
|
||||||
|
if (nRounds < privateSendClient.nPrivateSendRounds) continue;
|
||||||
|
}
|
||||||
nValueFromPresetInputs += pcoin->tx->vout[outpoint.n].nValue;
|
nValueFromPresetInputs += pcoin->tx->vout[outpoint.n].nValue;
|
||||||
setPresetCoins.insert(std::make_pair(pcoin, outpoint.n));
|
setPresetCoins.insert(std::make_pair(pcoin, outpoint.n));
|
||||||
} else
|
} else
|
||||||
@ -2916,13 +2935,13 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
|
|||||||
bool fRejectLongChains = GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS);
|
bool fRejectLongChains = GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS);
|
||||||
|
|
||||||
bool res = nTargetValue <= nValueFromPresetInputs ||
|
bool res = nTargetValue <= nValueFromPresetInputs ||
|
||||||
SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 6, 0, vCoins, setCoinsRet, nValueRet, fUseInstantSend) ||
|
SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 6, 0, vCoins, setCoinsRet, nValueRet, nCoinType, fUseInstantSend) ||
|
||||||
SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 1, 0, vCoins, setCoinsRet, nValueRet, fUseInstantSend) ||
|
SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 1, 0, vCoins, setCoinsRet, nValueRet, nCoinType, fUseInstantSend) ||
|
||||||
(bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, 2, vCoins, setCoinsRet, nValueRet, fUseInstantSend)) ||
|
(bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, 2, vCoins, setCoinsRet, nValueRet, nCoinType, fUseInstantSend)) ||
|
||||||
(bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, std::min((size_t)4, nMaxChainLength/3), vCoins, setCoinsRet, nValueRet, fUseInstantSend)) ||
|
(bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, std::min((size_t)4, nMaxChainLength/3), vCoins, setCoinsRet, nValueRet, nCoinType, fUseInstantSend)) ||
|
||||||
(bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength/2, vCoins, setCoinsRet, nValueRet, fUseInstantSend)) ||
|
(bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength/2, vCoins, setCoinsRet, nValueRet, nCoinType, fUseInstantSend)) ||
|
||||||
(bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength, vCoins, setCoinsRet, nValueRet, fUseInstantSend)) ||
|
(bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength, vCoins, setCoinsRet, nValueRet, nCoinType, fUseInstantSend)) ||
|
||||||
(bSpendZeroConfChange && !fRejectLongChains && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, std::numeric_limits<uint64_t>::max(), vCoins, setCoinsRet, nValueRet, fUseInstantSend));
|
(bSpendZeroConfChange && !fRejectLongChains && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, std::numeric_limits<uint64_t>::max(), vCoins, setCoinsRet, nValueRet, nCoinType, fUseInstantSend));
|
||||||
|
|
||||||
// because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset
|
// because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset
|
||||||
setCoinsRet.insert(setPresetCoins.begin(), setPresetCoins.end());
|
setCoinsRet.insert(setPresetCoins.begin(), setPresetCoins.end());
|
||||||
@ -2933,15 +2952,6 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CompareByPriority
|
|
||||||
{
|
|
||||||
bool operator()(const COutput& t1,
|
|
||||||
const COutput& t2) const
|
|
||||||
{
|
|
||||||
return t1.Priority() > t2.Priority();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool overrideEstimatedFeeRate, const CFeeRate& specificFeeRate, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, bool keepReserveKey, const CTxDestination& destChange)
|
bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool overrideEstimatedFeeRate, const CFeeRate& specificFeeRate, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, bool keepReserveKey, const CTxDestination& destChange)
|
||||||
{
|
{
|
||||||
std::vector<CRecipient> vecSend;
|
std::vector<CRecipient> vecSend;
|
||||||
|
@ -803,7 +803,7 @@ public:
|
|||||||
* completion the coin set and corresponding actual target value is
|
* completion the coin set and corresponding actual target value is
|
||||||
* assembled
|
* assembled
|
||||||
*/
|
*/
|
||||||
bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, uint64_t nMaxAncestors, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, bool fUseInstantSend = false) const;
|
bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, uint64_t nMaxAncestors, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, AvailableCoinsType nCoinType=ALL_COINS, bool fUseInstantSend = false) const;
|
||||||
|
|
||||||
// Coin selection
|
// Coin selection
|
||||||
bool SelectPSInOutPairsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector< std::pair<CTxDSIn, CTxOut> >& vecPSInOutPairsRet);
|
bool SelectPSInOutPairsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector< std::pair<CTxDSIn, CTxOut> >& vecPSInOutPairsRet);
|
||||||
|
Loading…
Reference in New Issue
Block a user