From 0a8a1272bccc31e190aea5210f73de50abf63805 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Tue, 14 Aug 2018 20:06:54 +0300 Subject: [PATCH 1/5] Lean towards "from high to low" branch but still mix via "from low to high" one someties --- src/privatesend-client.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/privatesend-client.cpp b/src/privatesend-client.cpp index e123f8c6733f..ce04bbdd45c4 100644 --- a/src/privatesend-client.cpp +++ b/src/privatesend-client.cpp @@ -1180,9 +1180,11 @@ bool CPrivateSendClientSession::SubmitDenominate(CConnman& connman) std::string strError; std::vector vecTxDSInRet; std::vector vecTxOutRet; + // lean towards "highest" branch but still mix via "lowest" one someties + bool fMixLowest = GetRandInt(4) == 0; // Submit transaction to the pool if we get here - if (privateSendClient.nLiquidityProvider) { + if (privateSendClient.nLiquidityProvider || fMixLowest) { // 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)) { From 1dc7e9ab0d49a64c45320eabe096b0cf25e30e95 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Tue, 4 Sep 2018 00:08:37 +0300 Subject: [PATCH 2/5] 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 --- src/privatesend-client.cpp | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src/privatesend-client.cpp b/src/privatesend-client.cpp index ce04bbdd45c4..6e7a57daba95 100644 --- a/src/privatesend-client.cpp +++ b/src/privatesend-client.cpp @@ -1182,25 +1182,38 @@ bool CPrivateSendClientSession::SubmitDenominate(CConnman& connman) std::vector vecTxOutRet; // lean towards "highest" branch but still mix via "lowest" one someties bool fMixLowest = GetRandInt(4) == 0; + // lean towards edges but still mix starting from the middle someties + // Note: liqudity providers always start from 0 + int nRoundStart = GetRandInt(4) == 0 + ? (privateSendClient.nLiquidityProvider ? 0 : (privateSendClient.nPrivateSendRounds / 2)) + : (fMixLowest ? 0 : privateSendClient.nPrivateSendRounds); // Submit transaction to the pool if we get here if (privateSendClient.nLiquidityProvider || fMixLowest) { - // 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); + // 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; } } From 8025de847e2bb2fb9b5d1b2c01188a5535331436 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Thu, 30 Aug 2018 04:26:25 +0300 Subject: [PATCH 3/5] Try to mix non-duplicate txids only --- src/privatesend-client.cpp | 4 ++-- src/wallet/wallet.cpp | 9 ++++++++- src/wallet/wallet.h | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/privatesend-client.cpp b/src/privatesend-client.cpp index 6e7a57daba95..50bc7f628d7f 100644 --- a/src/privatesend-client.cpp +++ b/src/privatesend-client.cpp @@ -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; } @@ -1266,7 +1266,7 @@ bool CPrivateSendClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds return false; } std::vector 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; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index e4bf343a6dab..d43d12206883 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -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& vecTxDSInRet, std::vector& vCoinsRet, CAmount& nValueRet, int nPrivateSendRoundsMin, int nPrivateSendRoundsMax) +bool CWallet::SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector& vecTxDSInRet, std::vector& vCoinsRet, CAmount& nValueRet, int nPrivateSendRoundsMin, int nPrivateSendRoundsMax, bool fNoDuplicateTxIds) { + std::map mapRecentTxIds; + vecTxDSInRet.clear(); vCoinsRet.clear(); nValueRet = 0; @@ -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 && mapRecentTxIds.find(out.tx->GetHash()) != mapRecentTxIds.end()) continue; if(nValueRet + out.tx->tx->vout[out.i].nValue <= nValueMax){ CTxIn txin = CTxIn(out.tx->GetHash(), out.i); @@ -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; + mapRecentTxIds.emplace(out.tx->GetHash(), 0); + LogPrint("privatesend", "CWallet::SelectCoinsByDenominations -- hash %s nValue %d\n", out.tx->GetHash().ToString(), out.tx->tx->vout[out.i].nValue); } } } } + LogPrintf("CWallet::SelectCoinsByDenominations -- mapRecentTxIds.size() %d\n", mapRecentTxIds.size()); + return nValueRet >= nValueMin && nDenom == nDenomResult; } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 27dd22ef1859..8fff1dbf5020 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -806,7 +806,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, uint64_t nMaxAncestors, std::vector vCoins, std::set >& setCoinsRet, CAmount& nValueRet, bool fUseInstantSend = false) const; // Coin selection - bool SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector& vecTxDSInRet, std::vector& vCoinsRet, CAmount& nValueRet, int nPrivateSendRoundsMin, int nPrivateSendRoundsMax); + bool SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector& vecTxDSInRet, std::vector& vCoinsRet, CAmount& nValueRet, int nPrivateSendRoundsMin, int nPrivateSendRoundsMax, bool fNoDuplicateTxIds); bool GetCollateralTxDSIn(CTxDSIn& txdsinRet, CAmount& nValueRet) const; bool SelectCoinsDark(CAmount nValueMin, CAmount nValueMax, std::vector& vecTxInRet, CAmount& nValueRet, int nPrivateSendRoundsMin, int nPrivateSendRoundsMax) const; From 6eb1cc5c11b2b066956d20407d0f8c44ed73ac50 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Wed, 5 Sep 2018 14:35:24 +0300 Subject: [PATCH 4/5] map -> set --- src/wallet/wallet.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index d43d12206883..5eac1b238dab 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3009,7 +3009,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool ov bool CWallet::SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector& vecTxDSInRet, std::vector& vCoinsRet, CAmount& nValueRet, int nPrivateSendRoundsMin, int nPrivateSendRoundsMax, bool fNoDuplicateTxIds) { - std::map mapRecentTxIds; + std::set setRecentTxIds; vecTxDSInRet.clear(); vCoinsRet.clear(); @@ -3039,7 +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 && mapRecentTxIds.find(out.tx->GetHash()) != mapRecentTxIds.end()) 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); @@ -3054,14 +3054,14 @@ 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; - mapRecentTxIds.emplace(out.tx->GetHash(), 0); + 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 -- mapRecentTxIds.size() %d\n", mapRecentTxIds.size()); + LogPrintf("CWallet::SelectCoinsByDenominations -- setRecentTxIds.size() %d\n", setRecentTxIds.size()); return nValueRet >= nValueMin && nDenom == nDenomResult; } From e0b0f4e1d9a67dc467734c0adadbfa795534934e Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Wed, 5 Sep 2018 14:57:02 +0300 Subject: [PATCH 5/5] Refactor nRoundStart calculations --- src/privatesend-client.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/privatesend-client.cpp b/src/privatesend-client.cpp index 50bc7f628d7f..01ce35f0cabf 100644 --- a/src/privatesend-client.cpp +++ b/src/privatesend-client.cpp @@ -1181,15 +1181,20 @@ bool CPrivateSendClientSession::SubmitDenominate(CConnman& connman) std::vector vecTxDSInRet; std::vector vecTxOutRet; // lean towards "highest" branch but still mix via "lowest" one someties - bool fMixLowest = GetRandInt(4) == 0; + 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 - int nRoundStart = GetRandInt(4) == 0 - ? (privateSendClient.nLiquidityProvider ? 0 : (privateSendClient.nPrivateSendRounds / 2)) - : (fMixLowest ? 0 : privateSendClient.nPrivateSendRounds); + 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 || fMixLowest) { + 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++) {