Skip to content

Commit 694f4cb

Browse files
committed
Merge #18312: wallet: remove deprecated fee bumping by totalFee
c3857c5 wallet: remove CreateTotalBumpTransaction() (Jon Atack) 4a0b27b wallet: remove totalfee from createBumpTransaction() (Jon Atack) e347cfa rpc: remove deprecated totalFee arg from RPC bumpfee (Jon Atack) bd05f96 test: delete wallet_bumpfee_totalfee_deprecation.py (Jon Atack) a6d1ab8 test: update bumpfee testing from totalFee to fee_rate (Jon Atack) Pull request description: Since 0.19, fee-bumping using `totalFee` was deprecated in #15996 and replaced by `fee_rate` in #16727. This changeset removes it. ACKs for top commit: laanwj: ACK c3857c5 Tree-SHA512: c1bb15d664baf4d2dea06981f36384af02057d125c51fcbc8640b9d5563532187c7b84aa952f7b575255a88ce383ed4d7495bec920a47b05b6fc0d432dce1f00
2 parents 94d3063 + c3857c5 commit 694f4cb

File tree

9 files changed

+43
-262
lines changed

9 files changed

+43
-262
lines changed

src/interfaces/wallet.cpp

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -253,19 +253,12 @@ class WalletImpl : public Wallet
253253
}
254254
bool createBumpTransaction(const uint256& txid,
255255
const CCoinControl& coin_control,
256-
CAmount total_fee,
257256
std::vector<std::string>& errors,
258257
CAmount& old_fee,
259258
CAmount& new_fee,
260259
CMutableTransaction& mtx) override
261260
{
262-
if (total_fee > 0) {
263-
return feebumper::CreateTotalBumpTransaction(m_wallet.get(), txid, coin_control, total_fee, errors, old_fee, new_fee, mtx) ==
264-
feebumper::Result::OK;
265-
} else {
266-
return feebumper::CreateRateBumpTransaction(*m_wallet.get(), txid, coin_control, errors, old_fee, new_fee, mtx) ==
267-
feebumper::Result::OK;
268-
}
261+
return feebumper::CreateRateBumpTransaction(*m_wallet.get(), txid, coin_control, errors, old_fee, new_fee, mtx) == feebumper::Result::OK;
269262
}
270263
bool signBumpTransaction(CMutableTransaction& mtx) override { return feebumper::SignTransaction(*m_wallet.get(), mtx); }
271264
bool commitBumpTransaction(const uint256& txid,

src/interfaces/wallet.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,6 @@ class Wallet
155155
//! Create bump transaction.
156156
virtual bool createBumpTransaction(const uint256& txid,
157157
const CCoinControl& coin_control,
158-
CAmount total_fee,
159158
std::vector<std::string>& errors,
160159
CAmount& old_fee,
161160
CAmount& new_fee,

src/qt/walletmodel.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash)
482482
CAmount old_fee;
483483
CAmount new_fee;
484484
CMutableTransaction mtx;
485-
if (!m_wallet->createBumpTransaction(hash, coin_control, 0 /* totalFee */, errors, old_fee, new_fee, mtx)) {
485+
if (!m_wallet->createBumpTransaction(hash, coin_control, errors, old_fee, new_fee, mtx)) {
486486
QMessageBox::critical(nullptr, tr("Fee bump error"), tr("Increasing transaction fee failed") + "<br />(" +
487487
(errors.size() ? QString::fromStdString(errors[0]) : "") +")");
488488
return false;

src/wallet/feebumper.cpp

Lines changed: 1 addition & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ static feebumper::Result PreconditionChecks(const CWallet& wallet, const CWallet
6060
static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wtx, const CFeeRate& newFeerate, const int64_t maxTxSize, std::vector<std::string>& errors) {
6161
// check that fee rate is higher than mempool's minimum fee
6262
// (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
63-
// This may occur if the user set FeeRate, TotalFee or paytxfee too low, if fallbackfee is too low, or, perhaps,
63+
// This may occur if the user set fee_rate or paytxfee too low, if fallbackfee is too low, or, perhaps,
6464
// in a rare situation where the mempool minimum fee increased significantly since the fee estimation just a
6565
// moment earlier. In this case, we report an error to the user, who may adjust the fee.
6666
CFeeRate minMempoolFeeRate = wallet.chain().mempoolMinFee();
@@ -150,132 +150,6 @@ bool TransactionCanBeBumped(const CWallet& wallet, const uint256& txid)
150150
return res == feebumper::Result::OK;
151151
}
152152

153-
Result CreateTotalBumpTransaction(const CWallet* wallet, const uint256& txid, const CCoinControl& coin_control, CAmount total_fee, std::vector<std::string>& errors,
154-
CAmount& old_fee, CAmount& new_fee, CMutableTransaction& mtx)
155-
{
156-
new_fee = total_fee;
157-
158-
auto locked_chain = wallet->chain().lock();
159-
LOCK(wallet->cs_wallet);
160-
errors.clear();
161-
auto it = wallet->mapWallet.find(txid);
162-
if (it == wallet->mapWallet.end()) {
163-
errors.push_back("Invalid or non-wallet transaction id");
164-
return Result::INVALID_ADDRESS_OR_KEY;
165-
}
166-
const CWalletTx& wtx = it->second;
167-
168-
Result result = PreconditionChecks(*wallet, wtx, errors);
169-
if (result != Result::OK) {
170-
return result;
171-
}
172-
173-
// figure out which output was change
174-
// if there was no change output or multiple change outputs, fail
175-
int nOutput = -1;
176-
for (size_t i = 0; i < wtx.tx->vout.size(); ++i) {
177-
if (wallet->IsChange(wtx.tx->vout[i])) {
178-
if (nOutput != -1) {
179-
errors.push_back("Transaction has multiple change outputs");
180-
return Result::WALLET_ERROR;
181-
}
182-
nOutput = i;
183-
}
184-
}
185-
if (nOutput == -1) {
186-
errors.push_back("Transaction does not have a change output");
187-
return Result::WALLET_ERROR;
188-
}
189-
190-
// Calculate the expected size of the new transaction.
191-
int64_t txSize = GetVirtualTransactionSize(*(wtx.tx));
192-
const int64_t maxNewTxSize = CalculateMaximumSignedTxSize(*wtx.tx, wallet);
193-
if (maxNewTxSize < 0) {
194-
errors.push_back("Transaction contains inputs that cannot be signed");
195-
return Result::INVALID_ADDRESS_OR_KEY;
196-
}
197-
198-
// calculate the old fee and fee-rate
199-
isminefilter filter = wallet->GetLegacyScriptPubKeyMan() && wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) ? ISMINE_WATCH_ONLY : ISMINE_SPENDABLE;
200-
old_fee = wtx.GetDebit(filter) - wtx.tx->GetValueOut();
201-
CFeeRate nOldFeeRate(old_fee, txSize);
202-
// The wallet uses a conservative WALLET_INCREMENTAL_RELAY_FEE value to
203-
// future proof against changes to network wide policy for incremental relay
204-
// fee that our node may not be aware of.
205-
CFeeRate nodeIncrementalRelayFee = wallet->chain().relayIncrementalFee();
206-
CFeeRate walletIncrementalRelayFee = CFeeRate(WALLET_INCREMENTAL_RELAY_FEE);
207-
if (nodeIncrementalRelayFee > walletIncrementalRelayFee) {
208-
walletIncrementalRelayFee = nodeIncrementalRelayFee;
209-
}
210-
211-
CAmount minTotalFee = nOldFeeRate.GetFee(maxNewTxSize) + nodeIncrementalRelayFee.GetFee(maxNewTxSize);
212-
if (total_fee < minTotalFee) {
213-
errors.push_back(strprintf("Insufficient totalFee, must be at least %s (oldFee %s + incrementalFee %s)",
214-
FormatMoney(minTotalFee), FormatMoney(nOldFeeRate.GetFee(maxNewTxSize)), FormatMoney(nodeIncrementalRelayFee.GetFee(maxNewTxSize))));
215-
return Result::INVALID_PARAMETER;
216-
}
217-
CAmount requiredFee = GetRequiredFee(*wallet, maxNewTxSize);
218-
if (total_fee < requiredFee) {
219-
errors.push_back(strprintf("Insufficient totalFee (cannot be less than required fee %s)",
220-
FormatMoney(requiredFee)));
221-
return Result::INVALID_PARAMETER;
222-
}
223-
224-
// Check that in all cases the new fee doesn't violate maxTxFee
225-
const CAmount max_tx_fee = wallet->m_default_max_tx_fee;
226-
if (new_fee > max_tx_fee) {
227-
errors.push_back(strprintf("Specified or calculated fee %s is too high (cannot be higher than -maxtxfee %s)",
228-
FormatMoney(new_fee), FormatMoney(max_tx_fee)));
229-
return Result::WALLET_ERROR;
230-
}
231-
232-
// check that fee rate is higher than mempool's minimum fee
233-
// (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
234-
// This may occur if the user set TotalFee or paytxfee too low, if fallbackfee is too low, or, perhaps,
235-
// in a rare situation where the mempool minimum fee increased significantly since the fee estimation just a
236-
// moment earlier. In this case, we report an error to the user, who may use total_fee to make an adjustment.
237-
CFeeRate minMempoolFeeRate = wallet->chain().mempoolMinFee();
238-
CFeeRate nNewFeeRate = CFeeRate(total_fee, maxNewTxSize);
239-
if (nNewFeeRate.GetFeePerK() < minMempoolFeeRate.GetFeePerK()) {
240-
errors.push_back(strprintf(
241-
"New fee rate (%s) is lower than the minimum fee rate (%s) to get into the mempool -- "
242-
"the totalFee value should be at least %s to add transaction",
243-
FormatMoney(nNewFeeRate.GetFeePerK()),
244-
FormatMoney(minMempoolFeeRate.GetFeePerK()),
245-
FormatMoney(minMempoolFeeRate.GetFee(maxNewTxSize))));
246-
return Result::WALLET_ERROR;
247-
}
248-
249-
// Now modify the output to increase the fee.
250-
// If the output is not large enough to pay the fee, fail.
251-
CAmount nDelta = new_fee - old_fee;
252-
assert(nDelta > 0);
253-
mtx = CMutableTransaction{*wtx.tx};
254-
CTxOut* poutput = &(mtx.vout[nOutput]);
255-
if (poutput->nValue < nDelta) {
256-
errors.push_back("Change output is too small to bump the fee");
257-
return Result::WALLET_ERROR;
258-
}
259-
260-
// If the output would become dust, discard it (converting the dust to fee)
261-
poutput->nValue -= nDelta;
262-
if (poutput->nValue <= GetDustThreshold(*poutput, GetDiscardRate(*wallet))) {
263-
wallet->WalletLogPrintf("Bumping fee and discarding dust output\n");
264-
new_fee += poutput->nValue;
265-
mtx.vout.erase(mtx.vout.begin() + nOutput);
266-
}
267-
268-
// Mark new tx not replaceable, if requested.
269-
if (!coin_control.m_signal_bip125_rbf.get_value_or(wallet->m_signal_rbf)) {
270-
for (auto& input : mtx.vin) {
271-
if (input.nSequence < 0xfffffffe) input.nSequence = 0xfffffffe;
272-
}
273-
}
274-
275-
return Result::OK;
276-
}
277-
278-
279153
Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCoinControl& coin_control, std::vector<std::string>& errors,
280154
CAmount& old_fee, CAmount& new_fee, CMutableTransaction& mtx)
281155
{

src/wallet/feebumper.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,6 @@ enum class Result
2828
//! Return whether transaction can be bumped.
2929
bool TransactionCanBeBumped(const CWallet& wallet, const uint256& txid);
3030

31-
//! Create bumpfee transaction based on total amount.
32-
Result CreateTotalBumpTransaction(const CWallet* wallet,
33-
const uint256& txid,
34-
const CCoinControl& coin_control,
35-
CAmount total_fee,
36-
std::vector<std::string>& errors,
37-
CAmount& old_fee,
38-
CAmount& new_fee,
39-
CMutableTransaction& mtx);
40-
4131
//! Create bumpfee transaction based on feerate estimates.
4232
Result CreateRateBumpTransaction(CWallet& wallet,
4333
const uint256& txid,

src/wallet/rpcwallet.cpp

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3342,24 +3342,19 @@ static UniValue bumpfee(const JSONRPCRequest& request)
33423342
"\nBumps the fee of an opt-in-RBF transaction T, replacing it with a new transaction B.\n"
33433343
"An opt-in RBF transaction with the given txid must be in the wallet.\n"
33443344
"The command will pay the additional fee by reducing change outputs or adding inputs when necessary. It may add a new change output if one does not already exist.\n"
3345-
"If `totalFee` (DEPRECATED) is given, adding inputs is not supported, so there must be a single change output that is big enough or it will fail.\n"
33463345
"All inputs in the original transaction will be included in the replacement transaction.\n"
33473346
"The command will fail if the wallet or mempool contains a transaction that spends one of T's outputs.\n"
33483347
"By default, the new fee will be calculated automatically using estimatesmartfee.\n"
33493348
"The user can specify a confirmation target for estimatesmartfee.\n"
3350-
"Alternatively, the user can specify totalFee (DEPRECATED), or fee_rate (" + CURRENCY_UNIT + " per kB) for the new transaction .\n"
3349+
"Alternatively, the user can specify a fee_rate (" + CURRENCY_UNIT + " per kB) for the new transaction.\n"
33513350
"At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee\n"
33523351
"returned by getnetworkinfo) to enter the node's mempool.\n",
33533352
{
33543353
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The txid to be bumped"},
33553354
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
33563355
{
33573356
{"confTarget", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks)"},
3358-
{"totalFee", RPCArg::Type::NUM, /* default */ "fallback to 'confTarget'", "Total fee (NOT feerate) to pay, in satoshis. (DEPRECATED)\n"
3359-
" In rare cases, the actual fee paid might be slightly higher than the specified\n"
3360-
" totalFee if the tx change output has to be removed because it is too close to\n"
3361-
" the dust threshold."},
3362-
{"fee_rate", RPCArg::Type::NUM, /* default */ "fallback to 'confTarget'", "FeeRate (NOT total fee) to pay, in " + CURRENCY_UNIT + " per kB\n"
3357+
{"fee_rate", RPCArg::Type::NUM, /* default */ "fall back to 'confTarget'", "fee rate (NOT total fee) to pay, in " + CURRENCY_UNIT + " per kB\n"
33633358
" Specify a fee rate instead of relying on the built-in fee estimator.\n"
33643359
"Must be at least 0.0001 " + CURRENCY_UNIT + " per kB higher than the current transaction fee rate.\n"},
33653360
{"replaceable", RPCArg::Type::BOOL, /* default */ "true", "Whether the new transaction should still be\n"
@@ -3400,34 +3395,22 @@ static UniValue bumpfee(const JSONRPCRequest& request)
34003395
CCoinControl coin_control;
34013396
coin_control.fAllowWatchOnly = pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
34023397
// optional parameters
3403-
CAmount totalFee = 0;
34043398
coin_control.m_signal_bip125_rbf = true;
34053399

34063400
if (!request.params[1].isNull()) {
34073401
UniValue options = request.params[1];
34083402
RPCTypeCheckObj(options,
34093403
{
34103404
{"confTarget", UniValueType(UniValue::VNUM)},
3411-
{"totalFee", UniValueType(UniValue::VNUM)},
34123405
{"fee_rate", UniValueType(UniValue::VNUM)},
34133406
{"replaceable", UniValueType(UniValue::VBOOL)},
34143407
{"estimate_mode", UniValueType(UniValue::VSTR)},
34153408
},
34163409
true, true);
3417-
if (options.exists("confTarget") && (options.exists("totalFee") || options.exists("fee_rate"))) {
3418-
throw JSONRPCError(RPC_INVALID_PARAMETER, "confTarget can't be set with totalFee or fee_rate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate.");
3419-
} else if (options.exists("fee_rate") && options.exists("totalFee")) {
3420-
throw JSONRPCError(RPC_INVALID_PARAMETER, "fee_rate can't be set along with totalFee.");
3410+
if (options.exists("confTarget") && options.exists("fee_rate")) {
3411+
throw JSONRPCError(RPC_INVALID_PARAMETER, "confTarget can't be set with fee_rate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate.");
34213412
} else if (options.exists("confTarget")) { // TODO: alias this to conf_target
34223413
coin_control.m_confirm_target = ParseConfirmTarget(options["confTarget"], pwallet->chain().estimateMaxBlocks());
3423-
} else if (options.exists("totalFee")) {
3424-
if (!pwallet->chain().rpcEnableDeprecated("totalFee")) {
3425-
throw JSONRPCError(RPC_INVALID_PARAMETER, "totalFee argument has been deprecated and will be removed in 0.20. Please use -deprecatedrpc=totalFee to continue using this argument until removal.");
3426-
}
3427-
totalFee = options["totalFee"].get_int64();
3428-
if (totalFee <= 0) {
3429-
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid totalFee %s (must be greater than 0)", FormatMoney(totalFee)));
3430-
}
34313414
} else if (options.exists("fee_rate")) {
34323415
CFeeRate fee_rate(AmountFromValue(options["fee_rate"]));
34333416
if (fee_rate <= CFeeRate(0)) {
@@ -3460,13 +3443,8 @@ static UniValue bumpfee(const JSONRPCRequest& request)
34603443
CAmount new_fee;
34613444
CMutableTransaction mtx;
34623445
feebumper::Result res;
3463-
if (totalFee > 0) {
3464-
// Targeting total fee bump. Requires a change output of sufficient size.
3465-
res = feebumper::CreateTotalBumpTransaction(pwallet, hash, coin_control, totalFee, errors, old_fee, new_fee, mtx);
3466-
} else {
3467-
// Targeting feerate bump.
3468-
res = feebumper::CreateRateBumpTransaction(*pwallet, hash, coin_control, errors, old_fee, new_fee, mtx);
3469-
}
3446+
// Targeting feerate bump.
3447+
res = feebumper::CreateRateBumpTransaction(*pwallet, hash, coin_control, errors, old_fee, new_fee, mtx);
34703448
if (res != feebumper::Result::OK) {
34713449
switch(res) {
34723450
case feebumper::Result::INVALID_ADDRESS_OR_KEY:
@@ -4196,7 +4174,7 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
41964174
},
41974175
{"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n"
41984176
" Allows this transaction to be replaced by a transaction with higher fees"},
4199-
{"conf_target", RPCArg::Type::NUM, /* default */ "Fallback to wallet's confirmation target", "Confirmation target (in blocks)"},
4177+
{"conf_target", RPCArg::Type::NUM, /* default */ "fall back to wallet's confirmation target (txconfirmtarget)", "Confirmation target (in blocks)"},
42004178
{"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n"
42014179
" \"UNSET\"\n"
42024180
" \"ECONOMICAL\"\n"

test/functional/test_runner.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,6 @@
182182
'rpc_bind.py --nonloopback',
183183
'mining_basic.py',
184184
'wallet_bumpfee.py',
185-
'wallet_bumpfee_totalfee_deprecation.py',
186185
'wallet_implicitsegwit.py',
187186
'rpc_named_arguments.py',
188187
'wallet_listsinceblock.py',

0 commit comments

Comments
 (0)