Skip to content

Commit ad31dbb

Browse files
authored
Add more variance to coin selection in PS mixing (#2261)
* 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
1 parent cb37c39 commit ad31dbb

File tree

3 files changed

+44
-17
lines changed

3 files changed

+44
-17
lines changed

src/privatesend-client.cpp

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,7 +1036,7 @@ bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymize
10361036
CAmount nMaxAmount = nBalanceNeedsAnonymized;
10371037

10381038
// Try to match their denominations if possible, select exact number of denominations
1039-
if(!pwalletMain->SelectCoinsByDenominations(dsq.nDenom, nMinAmount, nMaxAmount, vecTxDSInTmp, vCoinsTmp, nValueInTmp, 0, privateSendClient.nPrivateSendRounds)) {
1039+
if(!pwalletMain->SelectCoinsByDenominations(dsq.nDenom, nMinAmount, nMaxAmount, vecTxDSInTmp, vCoinsTmp, nValueInTmp, 0, privateSendClient.nPrivateSendRounds, true)) {
10401040
LogPrintf("CPrivateSendClientSession::JoinExistingQueue -- Couldn't match %d denominations %d (%s)\n", vecBits.front(), dsq.nDenom, CPrivateSend::GetDenominationsToString(dsq.nDenom));
10411041
continue;
10421042
}
@@ -1180,25 +1180,45 @@ bool CPrivateSendClientSession::SubmitDenominate(CConnman& connman)
11801180
std::string strError;
11811181
std::vector<CTxDSIn> vecTxDSInRet;
11821182
std::vector<CTxOut> vecTxOutRet;
1183+
// lean towards "highest" branch but still mix via "lowest" one someties
1184+
bool fMixLowest = privateSendClient.nLiquidityProvider || (GetRandInt(4) == 0);
1185+
// lean towards edges but still mix starting from the middle someties
1186+
// Note: liqudity providers always start from 0
1187+
bool fScanFromTheMiddle = (privateSendClient.nLiquidityProvider == 0) && (GetRandInt(4) == 0);
1188+
1189+
int nRoundStart{0};
1190+
if (fScanFromTheMiddle) {
1191+
nRoundStart = privateSendClient.nPrivateSendRounds / 2;
1192+
} else if (!fMixLowest) {
1193+
nRoundStart = privateSendClient.nPrivateSendRounds;
1194+
}
11831195

11841196
// Submit transaction to the pool if we get here
1185-
if (privateSendClient.nLiquidityProvider) {
1186-
// Try to use only inputs with the same number of rounds starting from the lowest number of rounds possible
1187-
for(int i = 0; i< privateSendClient.nPrivateSendRounds; i++) {
1188-
if(PrepareDenominate(i, i + 1, strError, vecTxDSInRet, vecTxOutRet)) {
1189-
LogPrintf("CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for %d rounds, success\n", i);
1190-
return SendDenominate(vecTxDSInRet, vecTxOutRet, connman);
1197+
if (fMixLowest) {
1198+
// Try to use only inputs with the same number of rounds, from low to high
1199+
while (true) {
1200+
for(int i = nRoundStart; i < privateSendClient.nPrivateSendRounds; i++) {
1201+
if(PrepareDenominate(i, i + 1, strError, vecTxDSInRet, vecTxOutRet)) {
1202+
LogPrintf("CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for %d rounds, success\n", i);
1203+
return SendDenominate(vecTxDSInRet, vecTxOutRet, connman);
1204+
}
1205+
LogPrint("privatesend", "CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for %d rounds, error: %s\n", i, strError);
11911206
}
1192-
LogPrint("privatesend", "CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for %d rounds, error: %s\n", i, strError);
1207+
if (nRoundStart == 0) break;
1208+
nRoundStart = 0;
11931209
}
11941210
} else {
1195-
// Try to use only inputs with the same number of rounds starting from the highest number of rounds possible
1196-
for(int i = privateSendClient.nPrivateSendRounds; i > 0; i--) {
1197-
if(PrepareDenominate(i - 1, i, strError, vecTxDSInRet, vecTxOutRet)) {
1198-
LogPrintf("CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for %d rounds, success\n", i);
1199-
return SendDenominate(vecTxDSInRet, vecTxOutRet, connman);
1211+
// Try to use only inputs with the same number of rounds, from high to low
1212+
while (true) {
1213+
for(int i = nRoundStart; i > 0; i--) {
1214+
if(PrepareDenominate(i - 1, i, strError, vecTxDSInRet, vecTxOutRet)) {
1215+
LogPrintf("CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for %d rounds, success\n", i);
1216+
return SendDenominate(vecTxDSInRet, vecTxOutRet, connman);
1217+
}
1218+
LogPrint("privatesend", "CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for %d rounds, error: %s\n", i, strError);
12001219
}
1201-
LogPrint("privatesend", "CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for %d rounds, error: %s\n", i, strError);
1220+
if (nRoundStart == privateSendClient.nPrivateSendRounds) break;
1221+
nRoundStart = privateSendClient.nPrivateSendRounds;
12021222
}
12031223
}
12041224

@@ -1251,7 +1271,7 @@ bool CPrivateSendClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds
12511271
return false;
12521272
}
12531273
std::vector<CAmount> vecStandardDenoms = CPrivateSend::GetStandardDenominations();
1254-
bool fSelected = pwalletMain->SelectCoinsByDenominations(nSessionDenom, vecStandardDenoms[vecBits.front()], CPrivateSend::GetMaxPoolAmount(), vecTxDSIn, vCoins, nValueIn, nMinRounds, nMaxRounds);
1274+
bool fSelected = pwalletMain->SelectCoinsByDenominations(nSessionDenom, vecStandardDenoms[vecBits.front()], CPrivateSend::GetMaxPoolAmount(), vecTxDSIn, vCoins, nValueIn, nMinRounds, nMaxRounds, true);
12551275
if (nMinRounds >= 0 && !fSelected) {
12561276
strErrorRet = "Can't select current denominated inputs";
12571277
return false;

src/wallet/wallet.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3007,8 +3007,10 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool ov
30073007
return true;
30083008
}
30093009

3010-
bool CWallet::SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector<CTxDSIn>& vecTxDSInRet, std::vector<COutput>& vCoinsRet, CAmount& nValueRet, int nPrivateSendRoundsMin, int nPrivateSendRoundsMax)
3010+
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)
30113011
{
3012+
std::set<uint256> setRecentTxIds;
3013+
30123014
vecTxDSInRet.clear();
30133015
vCoinsRet.clear();
30143016
nValueRet = 0;
@@ -3037,6 +3039,7 @@ bool CWallet::SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount
30373039
{
30383040
// masternode-like input should not be selected by AvailableCoins now anyway
30393041
//if(out.tx->vout[out.i].nValue == 1000*COIN) continue;
3042+
if(fNoDuplicateTxIds && setRecentTxIds.find(out.tx->GetHash()) != setRecentTxIds.end()) continue;
30403043
if(nValueRet + out.tx->tx->vout[out.i].nValue <= nValueMax){
30413044

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

3064+
LogPrintf("CWallet::SelectCoinsByDenominations -- setRecentTxIds.size() %d\n", setRecentTxIds.size());
3065+
30593066
return nValueRet >= nValueMin && nDenom == nDenomResult;
30603067
}
30613068

src/wallet/wallet.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
806806
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;
807807

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

0 commit comments

Comments
 (0)