Skip to content

Commit

Permalink
Add more variance to coin selection in PS mixing (#2261)
Browse files Browse the repository at this point in the history
* Lean towards "from high to low" branch but still mix via "from low to high" one someties

* Try to mix non-duplicate txids only

* Lean towards edges but still mix starting from the middle sometimes

If failed when started from the middle try mixing from the edges right away.

Note: liqudity providers always start from 0

* map -> set

* Refactor nRoundStart calculations
  • Loading branch information
UdjinM6 authored Sep 5, 2018
1 parent cb37c39 commit ad31dbb
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 17 deletions.
50 changes: 35 additions & 15 deletions src/privatesend-client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1036,7 +1036,7 @@ bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymize
CAmount nMaxAmount = nBalanceNeedsAnonymized;

// Try to match their denominations if possible, select exact number of denominations
if(!pwalletMain->SelectCoinsByDenominations(dsq.nDenom, nMinAmount, nMaxAmount, vecTxDSInTmp, vCoinsTmp, nValueInTmp, 0, privateSendClient.nPrivateSendRounds)) {
if(!pwalletMain->SelectCoinsByDenominations(dsq.nDenom, nMinAmount, nMaxAmount, vecTxDSInTmp, vCoinsTmp, nValueInTmp, 0, privateSendClient.nPrivateSendRounds, true)) {
LogPrintf("CPrivateSendClientSession::JoinExistingQueue -- Couldn't match %d denominations %d (%s)\n", vecBits.front(), dsq.nDenom, CPrivateSend::GetDenominationsToString(dsq.nDenom));
continue;
}
Expand Down Expand Up @@ -1180,25 +1180,45 @@ bool CPrivateSendClientSession::SubmitDenominate(CConnman& connman)
std::string strError;
std::vector<CTxDSIn> vecTxDSInRet;
std::vector<CTxOut> vecTxOutRet;
// lean towards "highest" branch but still mix via "lowest" one someties
bool fMixLowest = privateSendClient.nLiquidityProvider || (GetRandInt(4) == 0);
// lean towards edges but still mix starting from the middle someties
// Note: liqudity providers always start from 0
bool fScanFromTheMiddle = (privateSendClient.nLiquidityProvider == 0) && (GetRandInt(4) == 0);

int nRoundStart{0};
if (fScanFromTheMiddle) {
nRoundStart = privateSendClient.nPrivateSendRounds / 2;
} else if (!fMixLowest) {
nRoundStart = privateSendClient.nPrivateSendRounds;
}

// Submit transaction to the pool if we get here
if (privateSendClient.nLiquidityProvider) {
// Try to use only inputs with the same number of rounds starting from the lowest number of rounds possible
for(int i = 0; i< privateSendClient.nPrivateSendRounds; i++) {
if(PrepareDenominate(i, i + 1, strError, vecTxDSInRet, vecTxOutRet)) {
LogPrintf("CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for %d rounds, success\n", i);
return SendDenominate(vecTxDSInRet, vecTxOutRet, connman);
if (fMixLowest) {
// Try to use only inputs with the same number of rounds, from low to high
while (true) {
for(int i = nRoundStart; i < privateSendClient.nPrivateSendRounds; i++) {
if(PrepareDenominate(i, i + 1, strError, vecTxDSInRet, vecTxOutRet)) {
LogPrintf("CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for %d rounds, success\n", i);
return SendDenominate(vecTxDSInRet, vecTxOutRet, connman);
}
LogPrint("privatesend", "CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for %d rounds, error: %s\n", i, strError);
}
LogPrint("privatesend", "CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for %d rounds, error: %s\n", i, strError);
if (nRoundStart == 0) break;
nRoundStart = 0;
}
} else {
// Try to use only inputs with the same number of rounds starting from the highest number of rounds possible
for(int i = privateSendClient.nPrivateSendRounds; i > 0; i--) {
if(PrepareDenominate(i - 1, i, strError, vecTxDSInRet, vecTxOutRet)) {
LogPrintf("CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for %d rounds, success\n", i);
return SendDenominate(vecTxDSInRet, vecTxOutRet, connman);
// Try to use only inputs with the same number of rounds, from high to low
while (true) {
for(int i = nRoundStart; i > 0; i--) {
if(PrepareDenominate(i - 1, i, strError, vecTxDSInRet, vecTxOutRet)) {
LogPrintf("CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for %d rounds, success\n", i);
return SendDenominate(vecTxDSInRet, vecTxOutRet, connman);
}
LogPrint("privatesend", "CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for %d rounds, error: %s\n", i, strError);
}
LogPrint("privatesend", "CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for %d rounds, error: %s\n", i, strError);
if (nRoundStart == privateSendClient.nPrivateSendRounds) break;
nRoundStart = privateSendClient.nPrivateSendRounds;
}
}

Expand Down Expand Up @@ -1251,7 +1271,7 @@ bool CPrivateSendClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds
return false;
}
std::vector<CAmount> vecStandardDenoms = CPrivateSend::GetStandardDenominations();
bool fSelected = pwalletMain->SelectCoinsByDenominations(nSessionDenom, vecStandardDenoms[vecBits.front()], CPrivateSend::GetMaxPoolAmount(), vecTxDSIn, vCoins, nValueIn, nMinRounds, nMaxRounds);
bool fSelected = pwalletMain->SelectCoinsByDenominations(nSessionDenom, vecStandardDenoms[vecBits.front()], CPrivateSend::GetMaxPoolAmount(), vecTxDSIn, vCoins, nValueIn, nMinRounds, nMaxRounds, true);
if (nMinRounds >= 0 && !fSelected) {
strErrorRet = "Can't select current denominated inputs";
return false;
Expand Down
9 changes: 8 additions & 1 deletion src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3007,8 +3007,10 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool ov
return true;
}

bool CWallet::SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector<CTxDSIn>& vecTxDSInRet, std::vector<COutput>& vCoinsRet, CAmount& nValueRet, int nPrivateSendRoundsMin, int nPrivateSendRoundsMax)
bool CWallet::SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector<CTxDSIn>& vecTxDSInRet, std::vector<COutput>& vCoinsRet, CAmount& nValueRet, int nPrivateSendRoundsMin, int nPrivateSendRoundsMax, bool fNoDuplicateTxIds)
{
std::set<uint256> setRecentTxIds;

vecTxDSInRet.clear();
vCoinsRet.clear();
nValueRet = 0;
Expand Down Expand Up @@ -3037,6 +3039,7 @@ bool CWallet::SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount
{
// masternode-like input should not be selected by AvailableCoins now anyway
//if(out.tx->vout[out.i].nValue == 1000*COIN) continue;
if(fNoDuplicateTxIds && setRecentTxIds.find(out.tx->GetHash()) != setRecentTxIds.end()) continue;
if(nValueRet + out.tx->tx->vout[out.i].nValue <= nValueMax){

CTxIn txin = CTxIn(out.tx->GetHash(), out.i);
Expand All @@ -3051,11 +3054,15 @@ bool CWallet::SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount
vecTxDSInRet.push_back(CTxDSIn(txin, out.tx->tx->vout[out.i].scriptPubKey));
vCoinsRet.push_back(out);
nDenomResult |= 1 << nBit;
setRecentTxIds.emplace(out.tx->GetHash());
LogPrint("privatesend", "CWallet::SelectCoinsByDenominations -- hash %s nValue %d\n", out.tx->GetHash().ToString(), out.tx->tx->vout[out.i].nValue);
}
}
}
}

LogPrintf("CWallet::SelectCoinsByDenominations -- setRecentTxIds.size() %d\n", setRecentTxIds.size());

return nValueRet >= nValueMin && nDenom == nDenomResult;
}

Expand Down
2 changes: 1 addition & 1 deletion src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -806,7 +806,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
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;

// Coin selection
bool SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector<CTxDSIn>& vecTxDSInRet, std::vector<COutput>& vCoinsRet, CAmount& nValueRet, int nPrivateSendRoundsMin, int nPrivateSendRoundsMax);
bool SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector<CTxDSIn>& vecTxDSInRet, std::vector<COutput>& vCoinsRet, CAmount& nValueRet, int nPrivateSendRoundsMin, int nPrivateSendRoundsMax, bool fNoDuplicateTxIds);
bool GetCollateralTxDSIn(CTxDSIn& txdsinRet, CAmount& nValueRet) const;
bool SelectCoinsDark(CAmount nValueMin, CAmount nValueMax, std::vector<CTxIn>& vecTxInRet, CAmount& nValueRet, int nPrivateSendRoundsMin, int nPrivateSendRoundsMax) const;

Expand Down

0 comments on commit ad31dbb

Please sign in to comment.