wallet: shuffle coins before grouping, where warranted

Issue brought up in https://github.com/bitcoin/bitcoin/pull/12257\#discussion_r204554549
This commit is contained in:
Karl-Johan Alm 2018-07-31 01:50:43 +09:00 committed by Karl-Johan Alm
parent f66e1c793e
commit 18f690ec2f
No known key found for this signature in database
GPG key ID: 57AF762DB3353322

View file

@ -35,6 +35,8 @@
#include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/replace.hpp>
static const size_t OUTPUT_GROUP_MAX_ENTRIES = 10;
static CCriticalSection cs_wallets; static CCriticalSection cs_wallets;
static std::vector<std::shared_ptr<CWallet>> vpwallets GUARDED_BY(cs_wallets); static std::vector<std::shared_ptr<CWallet>> vpwallets GUARDED_BY(cs_wallets);
@ -2525,6 +2527,12 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
// form groups from remaining coins; note that preset coins will not // form groups from remaining coins; note that preset coins will not
// automatically have their associated (same address) coins included // automatically have their associated (same address) coins included
if (coin_control.m_avoid_partial_spends && vCoins.size() > OUTPUT_GROUP_MAX_ENTRIES) {
// Cases where we have 11+ outputs all pointing to the same destination may result in
// privacy leaks as they will potentially be deterministically sorted. We solve that by
// explicitly shuffling the outputs before processing
std::shuffle(vCoins.begin(), vCoins.end(), FastRandomContext());
}
std::vector<OutputGroup> groups = GroupOutputs(vCoins, !coin_control.m_avoid_partial_spends); std::vector<OutputGroup> groups = GroupOutputs(vCoins, !coin_control.m_avoid_partial_spends);
size_t max_ancestors = (size_t)std::max<int64_t>(1, gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT)); 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
// Limit output groups to no more than 10 entries, to protect // Limit output groups to no more than 10 entries, to protect
// against inadvertently creating a too-large transaction // against inadvertently creating a too-large transaction
// when using -avoidpartialspends // when using -avoidpartialspends
if (gmap[dst].m_outputs.size() >= 10) { if (gmap[dst].m_outputs.size() >= OUTPUT_GROUP_MAX_ENTRIES) {
groups.push_back(gmap[dst]); groups.push_back(gmap[dst]);
gmap.erase(dst); gmap.erase(dst);
} }