Skip to content

Commit 1697a40

Browse files
committed
wallet: improve bumpfee error/help, add explicit fee rate coverage
1 parent fc57217 commit 1697a40

File tree

2 files changed

+43
-12
lines changed

2 files changed

+43
-12
lines changed

src/wallet/rpcwallet.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3039,7 +3039,7 @@ static RPCHelpMan listunspent()
30393039
};
30403040
}
30413041

3042-
void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& fee_out, int& change_position, UniValue options, CCoinControl& coinControl)
3042+
void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& fee_out, int& change_position, const UniValue& options, CCoinControl& coinControl)
30433043
{
30443044
// Make sure the results are valid at least up to the most recent block
30453045
// the user could have gotten from another RPC command prior to now
@@ -3373,7 +3373,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
33733373
"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"
33743374
"All inputs in the original transaction will be included in the replacement transaction.\n"
33753375
"The command will fail if the wallet or mempool contains a transaction that spends one of T's outputs.\n"
3376-
"By default, the new fee will be calculated automatically using estimatesmartfee.\n"
3376+
"By default, the new fee will be calculated automatically using the estimatesmartfee RPC.\n"
33773377
"The user can specify a confirmation target for estimatesmartfee.\n"
33783378
"Alternatively, the user can specify a fee_rate (" + CURRENCY_UNIT + " per kB) for the new transaction.\n"
33793379
"At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee\n"
@@ -3459,7 +3459,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
34593459

34603460
if (!conf_target.isNull()) {
34613461
if (options.exists("fee_rate")) {
3462-
throw JSONRPCError(RPC_INVALID_PARAMETER, "conf_target can't be set with fee_rate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate.");
3462+
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and fee_rate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate.");
34633463
}
34643464
} else if (options.exists("fee_rate")) {
34653465
CFeeRate fee_rate(AmountFromValue(options["fee_rate"]));
@@ -4115,7 +4115,7 @@ static RPCHelpMan send()
41154115
CMutableTransaction rawTx = ConstructTransaction(options["inputs"], request.params[0], options["locktime"], rbf);
41164116
CCoinControl coin_control;
41174117
// Automatically select coins, unless at least one is manually selected. Can
4118-
// be overriden by options.add_inputs.
4118+
// be overridden by options.add_inputs.
41194119
coin_control.m_add_inputs = rawTx.vin.size() == 0;
41204120
FundTransaction(pwallet, rawTx, fee, change_position, options, coin_control);
41214121

test/functional/wallet_bumpfee.py

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -173,19 +173,50 @@ def test_feerate_args(self, rbf_node, peer_node, dest_address):
173173
self.sync_mempools((rbf_node, peer_node))
174174
assert rbfid in rbf_node.getrawmempool() and rbfid in peer_node.getrawmempool()
175175

176-
assert_raises_rpc_error(-8, "conf_target can't be set with fee_rate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate.", rbf_node.bumpfee, rbfid, {"fee_rate": NORMAL, "confTarget": 1})
177-
178176
assert_raises_rpc_error(-3, "Unexpected key totalFee", rbf_node.bumpfee, rbfid, {"totalFee": NORMAL})
179-
assert_raises_rpc_error(-8, "conf_target can't be set with fee_rate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate.", rbf_node.bumpfee, rbfid, {"fee_rate":0.00001, "confTarget": 1})
180-
181-
# Bumping to just above minrelay should fail to increase total fee enough, at least
182-
assert_raises_rpc_error(-8, "Insufficient total fee", rbf_node.bumpfee, rbfid, {"fee_rate": INSUFFICIENT})
183177

178+
# For each fee mode, bumping to just above minrelay should fail to increase the total fee enough.
179+
for options in [{"fee_rate": INSUFFICIENT}, {"conf_target": INSUFFICIENT, "estimate_mode": BTC_MODE}, {"conf_target": 1, "estimate_mode": SAT_MODE}]:
180+
assert_raises_rpc_error(-8, "Insufficient total fee", rbf_node.bumpfee, rbfid, options)
184181
assert_raises_rpc_error(-3, "Amount out of range", rbf_node.bumpfee, rbfid, {"fee_rate": -1})
185-
186182
assert_raises_rpc_error(-4, "is too high (cannot be higher than", rbf_node.bumpfee, rbfid, {"fee_rate": TOO_HIGH})
187-
self.clear_mempool()
188183

184+
self.log.info("Test explicit fee rate raises RPC error if estimate_mode is passed without a conf_target")
185+
for unit, fee_rate in {"SAT/B": 10, "BTC/KB": NORMAL}.items():
186+
assert_raises_rpc_error(-8, "Selected estimate_mode {} requires a fee rate to be specified in conf_target".format(unit),
187+
rbf_node.bumpfee, rbfid, {"fee_rate": fee_rate, "estimate_mode": unit})
188+
189+
self.log.info("Test explicit fee rate raises RPC error if both fee_rate and conf_target are passed")
190+
error_both = "Cannot specify both conf_target and fee_rate. Please provide either a confirmation " \
191+
"target in blocks for automatic fee estimation, or an explicit fee rate."
192+
assert_raises_rpc_error(-8, error_both, rbf_node.bumpfee, rbfid, {"conf_target": NORMAL, "fee_rate": NORMAL})
193+
194+
self.log.info("Test invalid conf_target settings")
195+
for field in ["confTarget", "conf_target"]:
196+
assert_raises_rpc_error(-8, error_both, rbf_node.bumpfee, rbfid, {field: 1, "fee_rate": NORMAL})
197+
too_high = "is too high (cannot be higher than -maxtxfee"
198+
assert_raises_rpc_error(-4, too_high, lambda: rbf_node.bumpfee(rbfid, {"estimate_mode": BTC_MODE, "conf_target": 2009}))
199+
assert_raises_rpc_error(-4, too_high, lambda: rbf_node.bumpfee(rbfid, {"estimate_mode": SAT_MODE, "conf_target": 2009 * 10000}))
200+
201+
self.log.info("Test invalid estimate_mode settings")
202+
for k, v in {"number": 42, "object": {"foo": "bar"}}.items():
203+
assert_raises_rpc_error(-3, "Expected type string for estimate_mode, got {}".format(k),
204+
lambda: rbf_node.bumpfee(rbfid, {"estimate_mode": v, "fee_rate": NORMAL}))
205+
for mode in ["foo", Decimal("3.141592")]:
206+
assert_raises_rpc_error(-8, "Invalid estimate_mode parameter",
207+
lambda: rbf_node.bumpfee(rbfid, {"estimate_mode": mode, "fee_rate": NORMAL}))
208+
209+
self.log.info("Test invalid fee_rate settings")
210+
for mode in ["unset", "economical", "conservative", BTC_MODE, SAT_MODE]:
211+
self.log.debug("{}".format(mode))
212+
for k, v in {"string": "", "object": {"foo": "bar"}}.items():
213+
assert_raises_rpc_error(-3, "Expected type number for fee_rate, got {}".format(k),
214+
lambda: rbf_node.bumpfee(rbfid, {"estimate_mode": mode, "fee_rate": v}))
215+
assert_raises_rpc_error(-3, "Amount out of range",
216+
lambda: rbf_node.bumpfee(rbfid, {"estimate_mode": mode, "fee_rate": -1}))
217+
assert_raises_rpc_error(-8, "Invalid fee_rate 0.00000000 BTC/kB (must be greater than 0)",
218+
lambda: rbf_node.bumpfee(rbfid, {"estimate_mode": mode, "fee_rate": 0}))
219+
self.clear_mempool()
189220

190221
def test_segwit_bumpfee_succeeds(self, rbf_node, dest_address):
191222
self.log.info('Test that segwit-sourcing bumpfee works')

0 commit comments

Comments
 (0)