Skip to content

Commit be177c1

Browse files
committed
bumpfee: Check the correct feerate when replacing outputs
When doing the feerate check for bumped transactions that replace the outputs, we need to consider that the size of the new outputs may be different from the old outputs and calculate the minimum feerate accordingly.
1 parent fc7c21f commit be177c1

File tree

1 file changed

+10
-11
lines changed

1 file changed

+10
-11
lines changed

src/wallet/feebumper.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ static feebumper::Result PreconditionChecks(const CWallet& wallet, const CWallet
6363
}
6464

6565
//! Check if the user provided a valid feeRate
66-
static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wtx, const CFeeRate& newFeerate, const int64_t maxTxSize, CAmount old_fee, std::vector<bilingual_str>& errors)
66+
static feebumper::Result CheckFeeRate(const CWallet& wallet, const CFeeRate& newFeerate, const int64_t maxTxSize, CAmount old_fee, std::vector<bilingual_str>& errors)
6767
{
6868
// check that fee rate is higher than mempool's minimum fee
6969
// (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
@@ -84,15 +84,12 @@ static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wt
8484

8585
CFeeRate incrementalRelayFee = std::max(wallet.chain().relayIncrementalFee(), CFeeRate(WALLET_INCREMENTAL_RELAY_FEE));
8686

87-
// Given old total fee and transaction size, calculate the old feeRate
88-
const int64_t txSize = GetVirtualTransactionSize(*(wtx.tx));
89-
CFeeRate nOldFeeRate(old_fee, txSize);
9087
// Min total fee is old fee + relay fee
91-
CAmount minTotalFee = nOldFeeRate.GetFee(maxTxSize) + incrementalRelayFee.GetFee(maxTxSize);
88+
CAmount minTotalFee = old_fee + incrementalRelayFee.GetFee(maxTxSize);
9289

9390
if (new_total_fee < minTotalFee) {
9491
errors.push_back(strprintf(Untranslated("Insufficient total fee %s, must be at least %s (oldFee %s + incrementalFee %s)"),
95-
FormatMoney(new_total_fee), FormatMoney(minTotalFee), FormatMoney(nOldFeeRate.GetFee(maxTxSize)), FormatMoney(incrementalRelayFee.GetFee(maxTxSize))));
92+
FormatMoney(new_total_fee), FormatMoney(minTotalFee), FormatMoney(old_fee), FormatMoney(incrementalRelayFee.GetFee(maxTxSize))));
9693
return feebumper::Result::INVALID_PARAMETER;
9794
}
9895

@@ -234,7 +231,8 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
234231
// is one). If outputs vector is non-empty, replace original
235232
// outputs with its contents, otherwise use original outputs.
236233
std::vector<CRecipient> recipients;
237-
for (const auto& output : outputs.empty() ? wtx.tx->vout : outputs) {
234+
const auto& txouts = outputs.empty() ? wtx.tx->vout : outputs;
235+
for (const auto& output : txouts) {
238236
if (!OutputIsChange(wallet, output)) {
239237
CRecipient recipient = {output.scriptPubKey, output.nValue, false};
240238
recipients.push_back(recipient);
@@ -249,13 +247,14 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
249247
// The user provided a feeRate argument.
250248
// We calculate this here to avoid compiler warning on the cs_wallet lock
251249
// We need to make a temporary transaction with no input witnesses as the dummy signer expects them to be empty for external inputs
252-
CMutableTransaction mtx{*wtx.tx};
253-
for (auto& txin : mtx.vin) {
250+
CMutableTransaction temp_mtx{*wtx.tx};
251+
for (auto& txin : temp_mtx.vin) {
254252
txin.scriptSig.clear();
255253
txin.scriptWitness.SetNull();
256254
}
257-
const int64_t maxTxSize{CalculateMaximumSignedTxSize(CTransaction(mtx), &wallet, &new_coin_control).vsize};
258-
Result res = CheckFeeRate(wallet, wtx, *new_coin_control.m_feerate, maxTxSize, old_fee, errors);
255+
temp_mtx.vout = txouts;
256+
const int64_t maxTxSize{CalculateMaximumSignedTxSize(CTransaction(temp_mtx), &wallet, &new_coin_control).vsize};
257+
Result res = CheckFeeRate(wallet, *new_coin_control.m_feerate, maxTxSize, old_fee, errors);
259258
if (res != Result::OK) {
260259
return res;
261260
}

0 commit comments

Comments
 (0)