Skip to content

Commit c948dc8

Browse files
committed
Merge #12699: [wallet] Shuffle transaction inputs before signing
2fb9c1e shuffle selected coins before transaction finalization (Gregory Sanders) Pull request description: Currently inputs are ordered based on COutPoint ordering, which while doesn't leak additional internal wallet state, likely further fingerprints the wallet as a Core wallet to observers. Note: This slightly changed behavior of `fundrawtransaction` in that the newly-appended inputs will now be shuffled rather than in outpoint-order. This does not break API compatibility. Simple shuffling of the coins being returned will hopefully allow the wallet to blend in a bit more, in lieu of additional data to find what other wallets are doing, or another standard, ala @gmaxwell's suggested of ordering via scriptPubKey. Tree-SHA512: 70689a6eccf9fa7fc6e3d884f2eba4b482446a1e6128beff7a98f446d0c60f7966c5a6c55e9b0b3d73a9b539ce54889a26c7efe78ab7f34af386d5e4f3fa6df2
2 parents ec7dbaa + 2fb9c1e commit c948dc8

File tree

1 file changed

+23
-14
lines changed

1 file changed

+23
-14
lines changed

src/wallet/wallet.cpp

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2890,20 +2890,11 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
28902890
nChangePosInOut = -1;
28912891
}
28922892

2893-
// Fill vin
2893+
// Dummy fill vin for maximum size estimation
28942894
//
2895-
// Note how the sequence number is set to non-maxint so that
2896-
// the nLockTime set above actually works.
2897-
//
2898-
// BIP125 defines opt-in RBF as any nSequence < maxint-1, so
2899-
// we use the highest possible value in that range (maxint-2)
2900-
// to avoid conflicting with other possible uses of nSequence,
2901-
// and in the spirit of "smallest possible change from prior
2902-
// behavior."
2903-
const uint32_t nSequence = coin_control.signalRbf ? MAX_BIP125_RBF_SEQUENCE : (CTxIn::SEQUENCE_FINAL - 1);
2904-
for (const auto& coin : setCoins)
2905-
txNew.vin.push_back(CTxIn(coin.outpoint,CScript(),
2906-
nSequence));
2895+
for (const auto& coin : setCoins) {
2896+
txNew.vin.push_back(CTxIn(coin.outpoint,CScript()));
2897+
}
29072898

29082899
nBytes = CalculateMaximumSignedTxSize(txNew, this);
29092900
if (nBytes < 0) {
@@ -2993,11 +2984,29 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
29932984

29942985
if (nChangePosInOut == -1) reservekey.ReturnKey(); // Return any reserved key if we don't have change
29952986

2987+
// Shuffle selected coins and fill in final vin
2988+
txNew.vin.clear();
2989+
std::vector<CInputCoin> selected_coins(setCoins.begin(), setCoins.end());
2990+
std::shuffle(selected_coins.begin(), selected_coins.end(), FastRandomContext());
2991+
2992+
// Note how the sequence number is set to non-maxint so that
2993+
// the nLockTime set above actually works.
2994+
//
2995+
// BIP125 defines opt-in RBF as any nSequence < maxint-1, so
2996+
// we use the highest possible value in that range (maxint-2)
2997+
// to avoid conflicting with other possible uses of nSequence,
2998+
// and in the spirit of "smallest possible change from prior
2999+
// behavior."
3000+
const uint32_t nSequence = coin_control.signalRbf ? MAX_BIP125_RBF_SEQUENCE : (CTxIn::SEQUENCE_FINAL - 1);
3001+
for (const auto& coin : selected_coins) {
3002+
txNew.vin.push_back(CTxIn(coin.outpoint, CScript(), nSequence));
3003+
}
3004+
29963005
if (sign)
29973006
{
29983007
CTransaction txNewConst(txNew);
29993008
int nIn = 0;
3000-
for (const auto& coin : setCoins)
3009+
for (const auto& coin : selected_coins)
30013010
{
30023011
const CScript& scriptPubKey = coin.txout.scriptPubKey;
30033012
SignatureData sigdata;

0 commit comments

Comments
 (0)