Skip to content

Commit 18f690e

Browse files
committed
wallet: shuffle coins before grouping, where warranted
Issue brought up in https://github.com/bitcoin/bitcoin/pull/12257\#discussion_r204554549
1 parent f66e1c7 commit 18f690e

File tree

1 file changed

+9
-1
lines changed

1 file changed

+9
-1
lines changed

src/wallet/wallet.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535

3636
#include <boost/algorithm/string/replace.hpp>
3737

38+
static const size_t OUTPUT_GROUP_MAX_ENTRIES = 10;
39+
3840
static CCriticalSection cs_wallets;
3941
static std::vector<std::shared_ptr<CWallet>> vpwallets GUARDED_BY(cs_wallets);
4042

@@ -2525,6 +2527,12 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
25252527

25262528
// form groups from remaining coins; note that preset coins will not
25272529
// automatically have their associated (same address) coins included
2530+
if (coin_control.m_avoid_partial_spends && vCoins.size() > OUTPUT_GROUP_MAX_ENTRIES) {
2531+
// Cases where we have 11+ outputs all pointing to the same destination may result in
2532+
// privacy leaks as they will potentially be deterministically sorted. We solve that by
2533+
// explicitly shuffling the outputs before processing
2534+
std::shuffle(vCoins.begin(), vCoins.end(), FastRandomContext());
2535+
}
25282536
std::vector<OutputGroup> groups = GroupOutputs(vCoins, !coin_control.m_avoid_partial_spends);
25292537

25302538
size_t max_ancestors = (size_t)std::max<int64_t>(1, gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT));
@@ -4444,7 +4452,7 @@ std::vector<OutputGroup> CWallet::GroupOutputs(const std::vector<COutput>& outpu
44444452
// Limit output groups to no more than 10 entries, to protect
44454453
// against inadvertently creating a too-large transaction
44464454
// when using -avoidpartialspends
4447-
if (gmap[dst].m_outputs.size() >= 10) {
4455+
if (gmap[dst].m_outputs.size() >= OUTPUT_GROUP_MAX_ENTRIES) {
44484456
groups.push_back(gmap[dst]);
44494457
gmap.erase(dst);
44504458
}

0 commit comments

Comments
 (0)