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);
|
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;
|
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");
|
LogPrint("privatesend", "CPrivateSendClientSession::CreateDenominated -- SelectCoinsGroupedByAddresses can't find any inputs!\n");
|
||||||
return false;
|
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);
|
LOCK2(cs_main, cs_wallet);
|
||||||
|
|
||||||
isminefilter filter = ISMINE_SPENDABLE;
|
isminefilter filter = ISMINE_SPENDABLE;
|
||||||
|
|
||||||
// try to use cache for already confirmed anonymizable inputs
|
// try to use cache for already confirmed anonymizable inputs, no cache should be used when the limit is specified
|
||||||
if(fAnonymizable && fSkipUnconfirmed) {
|
if(nMaxOupointsPerAddress != -1 && fAnonymizable && fSkipUnconfirmed) {
|
||||||
if(fSkipDenominated && fAnonymizableTallyCachedNonDenom) {
|
if(fSkipDenominated && fAnonymizableTallyCachedNonDenom) {
|
||||||
vecTallyRet = vecAnonymizableTallyCachedNonDenom;
|
vecTallyRet = vecAnonymizableTallyCachedNonDenom;
|
||||||
LogPrint("selectcoins", "SelectCoinsGroupedByAddresses - using cache for non-denom inputs %d\n", vecTallyRet.size());
|
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);
|
isminefilter mine = ::IsMine(*this, txdest);
|
||||||
if(!(mine & filter)) continue;
|
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(IsSpent(outpoint.hash, i) || IsLockedCoin(outpoint.hash, i)) continue;
|
||||||
|
|
||||||
if(fSkipDenominated && CPrivateSend::IsDenominatedAmount(wtx.tx->vout[i].nValue)) 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;
|
if(GetCappedOutpointPrivateSendRounds(COutPoint(outpoint.hash, i)) >= privateSendClient.nPrivateSendRounds) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
CompactTallyItem& item = mapTally[txdest];
|
if (itTallyItem == mapTally.end()) {
|
||||||
item.txdest = txdest;
|
itTallyItem = mapTally.emplace(txdest, CompactTallyItem()).first;
|
||||||
item.nAmount += wtx.tx->vout[i].nValue;
|
itTallyItem->second.txdest = txdest;
|
||||||
item.vecOutPoints.emplace_back(outpoint.hash, i);
|
}
|
||||||
|
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
|
// order by amounts per address, from smallest to largest
|
||||||
std::sort(vecTallyRet.rbegin(), vecTallyRet.rend(), CompareByAmount());
|
std::sort(vecTallyRet.rbegin(), vecTallyRet.rend(), CompareByAmount());
|
||||||
|
|
||||||
// cache already confirmed anonymizable entries for later use
|
// cache already confirmed anonymizable entries for later use, no cache should be saved when the limit is specified
|
||||||
if(fAnonymizable && fSkipUnconfirmed) {
|
if(nMaxOupointsPerAddress != -1 && fAnonymizable && fSkipUnconfirmed) {
|
||||||
if(fSkipDenominated) {
|
if(fSkipDenominated) {
|
||||||
vecAnonymizableTallyCachedNonDenom = vecTallyRet;
|
vecAnonymizableTallyCachedNonDenom = vecTallyRet;
|
||||||
fAnonymizableTallyCachedNonDenom = true;
|
fAnonymizableTallyCachedNonDenom = true;
|
||||||
|
@ -810,7 +810,7 @@ public:
|
|||||||
bool GetCollateralTxDSIn(CTxDSIn& txdsinRet, CAmount& nValueRet) const;
|
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 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
|
/// 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 = "");
|
bool GetMasternodeOutpointAndKeys(COutPoint& outpointRet, CPubKey& pubKeyRet, CKey& keyRet, const std::string& strTxHash = "", const std::string& strOutputIndex = "");
|
||||||
|
Loading…
Reference in New Issue
Block a user