aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Chow <github@achow101.com>2023-03-22 17:49:09 -0400
committerAndrew Chow <github@achow101.com>2023-04-10 09:56:25 -0400
commitbe177c15a40199fac79d8ab96bb4b4d5a9b4fe22 (patch)
tree3388dd4a429eae6959dcfbe0fce2ab13cd1f3eb7
parentfc7c21f664fd24ac17f518d07f04e0a3d9f8681c (diff)
downloadbitcoin-be177c15a40199fac79d8ab96bb4b4d5a9b4fe22.tar.xz
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.
-rw-r--r--src/wallet/feebumper.cpp21
1 files changed, 10 insertions, 11 deletions
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index 37a704bfa4..d127c41c43 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -63,7 +63,7 @@ static feebumper::Result PreconditionChecks(const CWallet& wallet, const CWallet
}
//! Check if the user provided a valid feeRate
-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)
+static feebumper::Result CheckFeeRate(const CWallet& wallet, const CFeeRate& newFeerate, const int64_t maxTxSize, CAmount old_fee, std::vector<bilingual_str>& errors)
{
// check that fee rate is higher than mempool's minimum fee
// (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
CFeeRate incrementalRelayFee = std::max(wallet.chain().relayIncrementalFee(), CFeeRate(WALLET_INCREMENTAL_RELAY_FEE));
- // Given old total fee and transaction size, calculate the old feeRate
- const int64_t txSize = GetVirtualTransactionSize(*(wtx.tx));
- CFeeRate nOldFeeRate(old_fee, txSize);
// Min total fee is old fee + relay fee
- CAmount minTotalFee = nOldFeeRate.GetFee(maxTxSize) + incrementalRelayFee.GetFee(maxTxSize);
+ CAmount minTotalFee = old_fee + incrementalRelayFee.GetFee(maxTxSize);
if (new_total_fee < minTotalFee) {
errors.push_back(strprintf(Untranslated("Insufficient total fee %s, must be at least %s (oldFee %s + incrementalFee %s)"),
- FormatMoney(new_total_fee), FormatMoney(minTotalFee), FormatMoney(nOldFeeRate.GetFee(maxTxSize)), FormatMoney(incrementalRelayFee.GetFee(maxTxSize))));
+ FormatMoney(new_total_fee), FormatMoney(minTotalFee), FormatMoney(old_fee), FormatMoney(incrementalRelayFee.GetFee(maxTxSize))));
return feebumper::Result::INVALID_PARAMETER;
}
@@ -234,7 +231,8 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
// is one). If outputs vector is non-empty, replace original
// outputs with its contents, otherwise use original outputs.
std::vector<CRecipient> recipients;
- for (const auto& output : outputs.empty() ? wtx.tx->vout : outputs) {
+ const auto& txouts = outputs.empty() ? wtx.tx->vout : outputs;
+ for (const auto& output : txouts) {
if (!OutputIsChange(wallet, output)) {
CRecipient recipient = {output.scriptPubKey, output.nValue, false};
recipients.push_back(recipient);
@@ -249,13 +247,14 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
// The user provided a feeRate argument.
// We calculate this here to avoid compiler warning on the cs_wallet lock
// We need to make a temporary transaction with no input witnesses as the dummy signer expects them to be empty for external inputs
- CMutableTransaction mtx{*wtx.tx};
- for (auto& txin : mtx.vin) {
+ CMutableTransaction temp_mtx{*wtx.tx};
+ for (auto& txin : temp_mtx.vin) {
txin.scriptSig.clear();
txin.scriptWitness.SetNull();
}
- const int64_t maxTxSize{CalculateMaximumSignedTxSize(CTransaction(mtx), &wallet, &new_coin_control).vsize};
- Result res = CheckFeeRate(wallet, wtx, *new_coin_control.m_feerate, maxTxSize, old_fee, errors);
+ temp_mtx.vout = txouts;
+ const int64_t maxTxSize{CalculateMaximumSignedTxSize(CTransaction(temp_mtx), &wallet, &new_coin_control).vsize};
+ Result res = CheckFeeRate(wallet, *new_coin_control.m_feerate, maxTxSize, old_fee, errors);
if (res != Result::OK) {
return res;
}