Skip to content

Commit 286a35e

Browse files
committed
[Refactoring] Make CWallet::FundTransaction atomic
>>> Inspired by bitcoin#11864 (+bitcoin#10784) Since CreateTransaction still needs cs_main we need to obtain both locks in FundTransaction, to preserve locking order. After introducing the chain interface (bitcoin#14437) we can change the LOCK2(cs_main, cs_wallet) to just LOCK(cs_wallet)
1 parent e288fd6 commit 286a35e

File tree

1 file changed

+15
-11
lines changed

1 file changed

+15
-11
lines changed

src/wallet/wallet.cpp

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2854,8 +2854,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool ov
28542854

28552855
// Turn the txout set into a CRecipient vector
28562856
for (const CTxOut& txOut : tx.vout) {
2857-
CRecipient recipient = {txOut.scriptPubKey, txOut.nValue, false};
2858-
vecSend.push_back(recipient);
2857+
vecSend.emplace_back(txOut.scriptPubKey, txOut.nValue, false);
28592858
}
28602859

28612860
CCoinControl coinControl;
@@ -2865,26 +2864,31 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool ov
28652864
coinControl.fOverrideFeeRate = overrideEstimatedFeeRate;
28662865
coinControl.nFeeRate = specificFeeRate;
28672866

2868-
for (const CTxIn& txin : tx.vin)
2867+
for (const CTxIn& txin : tx.vin) {
28692868
coinControl.Select(txin.prevout);
2869+
}
2870+
2871+
// Acquire the locks to prevent races to the new locked unspents between the
2872+
// CreateTransaction call and LockCoin calls (when lockUnspents is true).
2873+
LOCK2(cs_main, cs_wallet);
28702874

28712875
CReserveKey reservekey(this);
28722876
CTransactionRef wtx;
28732877
if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosInOut, strFailReason, &coinControl, ALL_COINS, false))
28742878
return false;
28752879

2876-
if (nChangePosInOut != -1)
2880+
if (nChangePosInOut != -1) {
28772881
tx.vout.insert(tx.vout.begin() + nChangePosInOut, wtx->vout[nChangePosInOut]);
2882+
// We don't have the normal Create/Commit cycle, and don't want to risk
2883+
// reusing change, so just remove the key from the keypool here.
2884+
reservekey.KeepKey();
2885+
}
28782886

2879-
// Add new txins (keeping original txin scriptSig/order)
2887+
// Add new txins while keeping original txin scriptSig/order.
28802888
for (const CTxIn& txin : wtx->vin) {
28812889
if (!coinControl.IsSelected(txin.prevout)) {
2882-
tx.vin.push_back(txin);
2883-
2884-
if (lockUnspents) {
2885-
LOCK(cs_wallet);
2886-
LockCoin(txin.prevout);
2887-
}
2890+
tx.vin.emplace_back(txin);
2891+
if (lockUnspents) LockCoin(txin.prevout);
28882892
}
28892893
}
28902894

0 commit comments

Comments
 (0)