Add more variance to coin selection in PS mixing#2261
Conversation
|
concept ACK, I think the selection could be a little bit better than this in such a way that any input could be selected (rather than highest, middlest(¯\(ツ)/¯), lowest). But with this in conjunction with 8fe3811, this should be a major improvement, while not decreasing speed much. The only situation I am worried about here is the mixing of a single input, but even that should be fine with 8fe3811 |
PastaPastaPasta
left a comment
There was a problem hiding this comment.
See inline: Spacing after if and for
Looks like these files as a whole need a redo, I might do that after this gets merged
There was a problem hiding this comment.
I'm following the surrounding code format here intentionally (to improve readability).
There was a problem hiding this comment.
Agree on that, if a general code cleanup is needed for the touched code, that's better in a separate PR. If a small code cleanup is enough, e.g. in just the line that is being touched, then in the same commit is ok IMHO.
… high" one someties
If failed when started from the middle try mixing from the edges right away. Note: liqudity providers always start from 0
|
Rebased and force-pushed. Re all the formatting comments: new line has such for readability reasons and I didn't fix code style in others (old ones) because of the "do not mix functionality and refactoring in one PR" principle https://github.com/dashpay/dash/blob/master/CONTRIBUTING.md#pull-request-philosophy |
There was a problem hiding this comment.
Can you convert this into if/else statements? Hard to read and using if/else would make this easier.
There was a problem hiding this comment.
Not exactly if/else but should be simpler to read now imo.
There was a problem hiding this comment.
What about this?
diff --git a/src/privatesend-client.cpp b/src/privatesend-client.cpp
index bf1d60f2f..ac0f74fe1 100644
--- a/src/privatesend-client.cpp
+++ b/src/privatesend-client.cpp
@@ -1185,9 +1185,13 @@ bool CPrivateSendClientSession::SubmitDenominate(CConnman& connman)
// 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 = fScanFromTheMiddle
- ? privateSendClient.nPrivateSendRounds / 2
- : (fMixLowest ? 0 : privateSendClient.nPrivateSendRounds);
+
+ int nRoundStart = privateSendClient.nPrivateSendRounds;
+ if (fScanFromTheMiddle) {
+ nRoundStart = privateSendClient.nPrivateSendRounds / 2;
+ } else if (fMixLowest) {
+ nRoundStart = 0;
+ }
// Submit transaction to the pool if we get here
if (privateSendClient.nLiquidityProvider || fMixLowest) {I find this much more clear, as it's immediately visible that there are 3 possible cases. With the nested ternary operators, it's very hard to see this.
| 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::map<uint256, uint8_t> mapRecentTxIds; |
There was a problem hiding this comment.
ooops, initial idea was to count them and then maybe sort etc. but then I figured out that I just need unique ones and... forgot about the map thing completely 🙈 Good catch 👍
There was a problem hiding this comment.
Agree on that, if a general code cleanup is needed for the touched code, that's better in a separate PR. If a small code cleanup is enough, e.g. in just the line that is being touched, then in the same commit is ok IMHO.
| { | ||
| // 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; |
There was a problem hiding this comment.
But will not this lead to the situation that most mixing transactions will contain only 1 input from each participant?
There was a problem hiding this comment.
No, it shouldn't. Even if it does that's fine for privacy.
There was a problem hiding this comment.
Yes, it's very fine for privacy. But mixing time will increase significantly. And mixing will cost much more.
There was a problem hiding this comment.
This sounds like a valid concern. I'll have a look.
There was a problem hiding this comment.
Fees would go up, but I see no situation where a participant would only be able to submit one denom, maybe the first mix when they are all fresh out of create denoms
There was a problem hiding this comment.
@PastaPastaPasta not only after create denoms.
What we have: in most cases (nRoundStart = privateSendClient.nPrivateSendRounds) mixing function will select inputs with highest round originating only from different Txs.
After "create denoms" the participant will be able to provide from 1 to several inputs (depending on amount he is trying to mix - can be several "create denoms" Txs).
And after every mixing round where participant will be able to provide more than 1 input, on the next round in most cases he will not be able to provide more than 1 input because all inputs with highest round will be from the same Tx.
The number of inputs in this situation will always tends to one.
|
I like the concept but what is the motivation behind randomly choosing to scan from
Wouldn't this approach make certain I think it might be better and more simple if we sometimes choose a random input instead of scanning. SelectCoinsByDenominations used by PrepareDenominate seems to choose a random input between nPrivateSendRoundsMin and nPrivateSendRoundsMax. My idea would look something like this: (totally untested) |
|
@Antti-Kaikkonen lowest to highest, vice versa or from the middle to whatever edge - all of them are not about denominations but about number of rounds, so no, there should be no preferences for specific denoms I think. Motivation for slightly randomising it for rounds is basically to make it harder to guess what's going on, otherwise you know it's highest to lowest all the time, so maybe someone could use this as a heuristic or smth. Also, pls see an extension of this idea in #2275 (avoiding single input mix) and an alternative solution in #2278 (mixing rounds with most inputs first). |
|
@UdjinM6 yeah rounds is what I mean and not denominations. I think it might be better to sometimes simply pick a random input rather than changing the scan direction because it will randomly choose from a larger set of inputs. |
|
@Antti-Kaikkonen Probably. That was one of the ideas I had before #2278 tbh ;) but then I realized that picking random rounds have to be balanced with the speed of mixing somehow and picking rounds with the most inputs improves mixing speed while also achieving some kind of shuffling/randomization as a free bonus, see PR description there. |
This should make it harder to analyse mixing sessions. See individual commits, should be self-explanatory. Client side only, requires no protobump.
Note: this includes #2259 , will rebase after #2259 is merged.@PastaPastaPasta @Antti-Kaikkonen