From 6491b4da5d49cc1cc2d6fca7eaa4c3768ceebd56 Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Wed, 20 Mar 2019 16:59:03 -0400 Subject: [PATCH] Use upstream Shuffle which doesn't cause DEBUG panic --- src/random.h | 25 +++++++++++++++++++++++++ src/wallet/wallet.cpp | 5 +++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/random.h b/src/random.h index 3d5421eb3e..5b0085f1c8 100644 --- a/src/random.h +++ b/src/random.h @@ -150,4 +150,29 @@ bool Random_SanityCheck(); /** Initialize the RNG. */ void RandomInit(); +/** Shuffle function Poached from upstream: #14624 **/ + +/** More efficient than using std::shuffle on a FastRandomContext. + * + * This is more efficient as std::shuffle will consume entropy in groups of + * 64 bits at the time and throw away most. + * + * This also works around a bug in libstdc++ std::shuffle that may cause + * type::operator=(type&&) to be invoked on itself, which the library's + * debug mode detects and panics on. This is a known issue, see + * https://stackoverflow.com/questions/22915325/avoiding-self-assignment-in-stdshuffle + */ +template +void Shuffle(I first, I last, R&& rng) +{ + while (first != last) { + size_t j = rng.randrange(last - first); + if (j) { + using std::swap; + swap(*first, *(first + j)); + } + ++first; + } +} + #endif // BITCOIN_RANDOM_H diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 41369df814..88b1b6c093 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -38,6 +38,7 @@ #include #include #include +#include static const size_t OUTPUT_GROUP_MAX_ENTRIES = 10; @@ -2551,7 +2552,7 @@ bool CWallet::SelectCoins(const std::vector& vAvailableCoins, const CAm // 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()); + Shuffle(vCoins.begin(), vCoins.end(), FastRandomContext()); } std::vector groups = GroupOutputs(vCoins, !coin_control.m_avoid_partial_spends); @@ -3188,7 +3189,7 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CTransac // Elements: Shuffle here to preserve random ordering for surjection proofs selected_coins = std::vector(setCoins.begin(), setCoins.end()); - std::shuffle(selected_coins.begin(), selected_coins.end(), FastRandomContext()); + Shuffle(selected_coins.begin(), selected_coins.end(), FastRandomContext()); // Dummy fill vin for maximum size estimation //