Fix CreateDenominated failure for addresses with huge amount of inputs (#2486)
* Allow specifing max number of outpoints to be returned per address in SelectCoinsGroupedByAddresses Fixes CreateDenominated failure for addresses with huge amount of inputs * Apply suggested fixes
This commit is contained in:
parent
0123517b48
commit
9d4df466b9
@ -1444,8 +1444,12 @@ bool CPrivateSendClientSession::CreateDenominated(CConnman& connman)
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
// NOTE: We do not allow txes larger than 100kB, so we have to limit number of inputs here.
|
||||
// We still want to consume a lot of inputs to avoid creating only smaller denoms though.
|
||||
// Knowing that each CTxIn is at least 148b big, 400 inputs should take 400 x ~148b = ~60kB.
|
||||
// This still leaves more than enough room for another data of typical CreateDenominated tx.
|
||||
std::vector<CompactTallyItem> vecTally;
|
||||
if (!pwalletMain->SelectCoinsGroupedByAddresses(vecTally)) {
|
||||
if (!pwalletMain->SelectCoinsGroupedByAddresses(vecTally, true, true, true, 400)) {
|
||||
LogPrint("privatesend", "CPrivateSendClientSession::CreateDenominated -- SelectCoinsGroupedByAddresses can't find any inputs!\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -3069,14 +3069,14 @@ struct CompareByAmount
|
||||
}
|
||||
};
|
||||
|
||||
bool CWallet::SelectCoinsGroupedByAddresses(std::vector<CompactTallyItem>& vecTallyRet, bool fSkipDenominated, bool fAnonymizable, bool fSkipUnconfirmed) const
|
||||
bool CWallet::SelectCoinsGroupedByAddresses(std::vector<CompactTallyItem>& vecTallyRet, bool fSkipDenominated, bool fAnonymizable, bool fSkipUnconfirmed, int nMaxOupointsPerAddress) const
|
||||
{
|
||||
LOCK2(cs_main, cs_wallet);
|
||||
|
||||
isminefilter filter = ISMINE_SPENDABLE;
|
||||
|
||||
// try to use cache for already confirmed anonymizable inputs
|
||||
if(fAnonymizable && fSkipUnconfirmed) {
|
||||
// try to use cache for already confirmed anonymizable inputs, no cache should be used when the limit is specified
|
||||
if(nMaxOupointsPerAddress != -1 && fAnonymizable && fSkipUnconfirmed) {
|
||||
if(fSkipDenominated && fAnonymizableTallyCachedNonDenom) {
|
||||
vecTallyRet = vecAnonymizableTallyCachedNonDenom;
|
||||
LogPrint("selectcoins", "SelectCoinsGroupedByAddresses - using cache for non-denom inputs %d\n", vecTallyRet.size());
|
||||
@ -3114,6 +3114,9 @@ bool CWallet::SelectCoinsGroupedByAddresses(std::vector<CompactTallyItem>& vecTa
|
||||
isminefilter mine = ::IsMine(*this, txdest);
|
||||
if(!(mine & filter)) continue;
|
||||
|
||||
auto itTallyItem = mapTally.find(txdest);
|
||||
if (nMaxOupointsPerAddress != -1 && itTallyItem != mapTally.end() && itTallyItem->second.vecOutPoints.size() >= nMaxOupointsPerAddress) continue;
|
||||
|
||||
if(IsSpent(outpoint.hash, i) || IsLockedCoin(outpoint.hash, i)) continue;
|
||||
|
||||
if(fSkipDenominated && CPrivateSend::IsDenominatedAmount(wtx.tx->vout[i].nValue)) continue;
|
||||
@ -3129,10 +3132,12 @@ bool CWallet::SelectCoinsGroupedByAddresses(std::vector<CompactTallyItem>& vecTa
|
||||
if(GetCappedOutpointPrivateSendRounds(COutPoint(outpoint.hash, i)) >= privateSendClient.nPrivateSendRounds) continue;
|
||||
}
|
||||
|
||||
CompactTallyItem& item = mapTally[txdest];
|
||||
item.txdest = txdest;
|
||||
item.nAmount += wtx.tx->vout[i].nValue;
|
||||
item.vecOutPoints.emplace_back(outpoint.hash, i);
|
||||
if (itTallyItem == mapTally.end()) {
|
||||
itTallyItem = mapTally.emplace(txdest, CompactTallyItem()).first;
|
||||
itTallyItem->second.txdest = txdest;
|
||||
}
|
||||
itTallyItem->second.nAmount += wtx.tx->vout[i].nValue;
|
||||
itTallyItem->second.vecOutPoints.emplace_back(outpoint.hash, i);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3146,8 +3151,8 @@ bool CWallet::SelectCoinsGroupedByAddresses(std::vector<CompactTallyItem>& vecTa
|
||||
// order by amounts per address, from smallest to largest
|
||||
std::sort(vecTallyRet.rbegin(), vecTallyRet.rend(), CompareByAmount());
|
||||
|
||||
// cache already confirmed anonymizable entries for later use
|
||||
if(fAnonymizable && fSkipUnconfirmed) {
|
||||
// cache already confirmed anonymizable entries for later use, no cache should be saved when the limit is specified
|
||||
if(nMaxOupointsPerAddress != -1 && fAnonymizable && fSkipUnconfirmed) {
|
||||
if(fSkipDenominated) {
|
||||
vecAnonymizableTallyCachedNonDenom = vecTallyRet;
|
||||
fAnonymizableTallyCachedNonDenom = true;
|
||||
|
@ -810,7 +810,7 @@ public:
|
||||
bool GetCollateralTxDSIn(CTxDSIn& txdsinRet, CAmount& nValueRet) const;
|
||||
bool SelectPrivateCoins(CAmount nValueMin, CAmount nValueMax, std::vector<CTxIn>& vecTxInRet, CAmount& nValueRet, int nPrivateSendRoundsMin, int nPrivateSendRoundsMax) const;
|
||||
|
||||
bool SelectCoinsGroupedByAddresses(std::vector<CompactTallyItem>& vecTallyRet, bool fSkipDenominated = true, bool fAnonymizable = true, bool fSkipUnconfirmed = true) const;
|
||||
bool SelectCoinsGroupedByAddresses(std::vector<CompactTallyItem>& vecTallyRet, bool fSkipDenominated = true, bool fAnonymizable = true, bool fSkipUnconfirmed = true, int nMaxOupointsPerAddress = -1) const;
|
||||
|
||||
/// Get 1000DASH output and keys which can be used for the Masternode
|
||||
bool GetMasternodeOutpointAndKeys(COutPoint& outpointRet, CPubKey& pubKeyRet, CKey& keyRet, const std::string& strTxHash = "", const std::string& strOutputIndex = "");
|
||||
|
Loading…
Reference in New Issue
Block a user