mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-14 23:29:56 +02:00
Allow zero-fee fundrawtxn and walletcreatefundedpsbt calls
A check to raise an error on zero-fee txns was mistakenly extended in commit a0d4957 from the bumpfee and send{toaddress, many} RPCs to also include fundrawtransaction and walletcreatefundedpsbt. This commit overrides zero fee rate checking for these two RPCs, not only for the feeRate (BTC/kvB) arg to return to previous behavior, but also for the new fee_rate (sat/vB) arg.
This commit is contained in:
parent
04670ef81e
commit
1b3d700928
@ -219,14 +219,8 @@ static void SetFeeEstimateMode(const CWallet* pwallet, CCoinControl& cc, const U
|
||||
if (!estimate_mode.isNull() && !estimate_mode.get_str().empty()) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and fee_rate");
|
||||
}
|
||||
CFeeRate fee_rate_in_sat_vb{CFeeRate(AmountFromValue(fee_rate), COIN)};
|
||||
if (override_min_fee) {
|
||||
if (fee_rate_in_sat_vb <= CFeeRate(0)) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid fee_rate %s (must be greater than 0)", fee_rate_in_sat_vb.ToString(FeeEstimateMode::SAT_VB)));
|
||||
}
|
||||
cc.fOverrideFeeRate = true;
|
||||
}
|
||||
cc.m_feerate = fee_rate_in_sat_vb;
|
||||
cc.m_feerate = CFeeRate(AmountFromValue(fee_rate), COIN);
|
||||
if (override_min_fee) cc.fOverrideFeeRate = true;
|
||||
// Default RBF to true for explicit fee_rate, if unset.
|
||||
if (cc.m_signal_bip125_rbf == nullopt) cc.m_signal_bip125_rbf = true;
|
||||
return;
|
||||
@ -3150,11 +3144,7 @@ void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& f
|
||||
if (options.exists("estimate_mode")) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and feeRate");
|
||||
}
|
||||
CFeeRate fee_rate(AmountFromValue(options["feeRate"]));
|
||||
if (fee_rate <= CFeeRate(0)) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid feeRate %s (must be greater than 0)", fee_rate.ToString(FeeEstimateMode::BTC_KVB)));
|
||||
}
|
||||
coinControl.m_feerate = fee_rate;
|
||||
coinControl.m_feerate = CFeeRate(AmountFromValue(options["feeRate"]));
|
||||
coinControl.fOverrideFeeRate = true;
|
||||
}
|
||||
|
||||
|
@ -721,11 +721,17 @@ class RawTransactionsTest(BitcoinTestFramework):
|
||||
result2 = node.fundrawtransaction(rawtx, {"feeRate": 2 * self.min_relay_tx_fee})
|
||||
result3 = node.fundrawtransaction(rawtx, {"fee_rate": 10 * btc_kvb_to_sat_vb * self.min_relay_tx_fee})
|
||||
result4 = node.fundrawtransaction(rawtx, {"feeRate": 10 * self.min_relay_tx_fee})
|
||||
# Test that funding non-standard "zero-fee" transactions is valid.
|
||||
result5 = self.nodes[3].fundrawtransaction(rawtx, {"fee_rate": 0})
|
||||
result6 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 0})
|
||||
|
||||
result_fee_rate = result['fee'] * 1000 / count_bytes(result['hex'])
|
||||
assert_fee_amount(result1['fee'], count_bytes(result2['hex']), 2 * result_fee_rate)
|
||||
assert_fee_amount(result2['fee'], count_bytes(result2['hex']), 2 * result_fee_rate)
|
||||
assert_fee_amount(result3['fee'], count_bytes(result3['hex']), 10 * result_fee_rate)
|
||||
assert_fee_amount(result4['fee'], count_bytes(result3['hex']), 10 * result_fee_rate)
|
||||
assert_fee_amount(result5['fee'], count_bytes(result5['hex']), 0)
|
||||
assert_fee_amount(result6['fee'], count_bytes(result6['hex']), 0)
|
||||
|
||||
# With no arguments passed, expect fee of 141 satoshis.
|
||||
assert_approx(node.fundrawtransaction(rawtx)["fee"], vexp=0.00000141, vspan=0.00000001)
|
||||
@ -752,19 +758,15 @@ class RawTransactionsTest(BitcoinTestFramework):
|
||||
node.fundrawtransaction, rawtx, {"estimate_mode": mode, "conf_target": n, "add_inputs": True})
|
||||
|
||||
self.log.info("Test invalid fee rate settings")
|
||||
assert_raises_rpc_error(-8, "Invalid fee_rate 0.000 sat/vB (must be greater than 0)",
|
||||
node.fundrawtransaction, rawtx, {"fee_rate": 0, "add_inputs": True})
|
||||
assert_raises_rpc_error(-8, "Invalid feeRate 0.00000000 BTC/kvB (must be greater than 0)",
|
||||
node.fundrawtransaction, rawtx, {"feeRate": 0, "add_inputs": True})
|
||||
for param, value in {("fee_rate", 100000), ("feeRate", 1.000)}:
|
||||
assert_raises_rpc_error(-4, "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)",
|
||||
node.fundrawtransaction, rawtx, {param: value, "add_inputs": True})
|
||||
assert_raises_rpc_error(-3, "Amount out of range",
|
||||
node.fundrawtransaction, rawtx, {"fee_rate": -1, "add_inputs": True})
|
||||
node.fundrawtransaction, rawtx, {param: -1, "add_inputs": True})
|
||||
assert_raises_rpc_error(-3, "Amount is not a number or string",
|
||||
node.fundrawtransaction, rawtx, {"fee_rate": {"foo": "bar"}, "add_inputs": True})
|
||||
node.fundrawtransaction, rawtx, {param: {"foo": "bar"}, "add_inputs": True})
|
||||
assert_raises_rpc_error(-3, "Invalid amount",
|
||||
node.fundrawtransaction, rawtx, {"fee_rate": "", "add_inputs": True})
|
||||
node.fundrawtransaction, rawtx, {param: "", "add_inputs": True})
|
||||
|
||||
self.log.info("Test min fee rate checks are bypassed with fundrawtxn, e.g. a fee_rate under 1 sat/vB is allowed")
|
||||
node.fundrawtransaction(rawtx, {"fee_rate": 0.99999999, "add_inputs": True})
|
||||
|
@ -192,26 +192,27 @@ class PSBTTest(BitcoinTestFramework):
|
||||
assert_approx(res1["fee"], 0.055, 0.005)
|
||||
res2 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"feeRate": 0.1, "add_inputs": True})
|
||||
assert_approx(res2["fee"], 0.055, 0.005)
|
||||
|
||||
self.log.info("Test min fee rate checks with walletcreatefundedpsbt are bypassed, e.g. a fee_rate under 1 sat/vB is allowed")
|
||||
res3 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"fee_rate": 0.99999999, "add_inputs": True})
|
||||
assert_approx(res3["fee"], 0.00000381, 0.0000001)
|
||||
res4 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"feeRate": 0.00000999, "add_inputs": True})
|
||||
assert_approx(res4["fee"], 0.00000381, 0.0000001)
|
||||
|
||||
self.log.info("Test min fee rate checks with walletcreatefundedpsbt are bypassed and that funding non-standard 'zero-fee' transactions is valid")
|
||||
for param in ["fee_rate", "feeRate"]:
|
||||
assert_equal(self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {param: 0, "add_inputs": True})["fee"], 0)
|
||||
|
||||
self.log.info("Test invalid fee rate settings")
|
||||
assert_raises_rpc_error(-8, "Invalid fee_rate 0.000 sat/vB (must be greater than 0)",
|
||||
self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"fee_rate": 0, "add_inputs": True})
|
||||
assert_raises_rpc_error(-8, "Invalid feeRate 0.00000000 BTC/kvB (must be greater than 0)",
|
||||
self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"feeRate": 0, "add_inputs": True})
|
||||
for param, value in {("fee_rate", 100000), ("feeRate", 1)}:
|
||||
assert_raises_rpc_error(-4, "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)",
|
||||
self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {param: value, "add_inputs": True})
|
||||
assert_raises_rpc_error(-3, "Amount out of range",
|
||||
self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"fee_rate": -1, "add_inputs": True})
|
||||
self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {param: -1, "add_inputs": True})
|
||||
assert_raises_rpc_error(-3, "Amount is not a number or string",
|
||||
self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"fee_rate": {"foo": "bar"}, "add_inputs": True})
|
||||
self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {param: {"foo": "bar"}, "add_inputs": True})
|
||||
assert_raises_rpc_error(-3, "Invalid amount",
|
||||
self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"fee_rate": "", "add_inputs": True})
|
||||
self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {param: "", "add_inputs": True})
|
||||
|
||||
self.log.info("- raises RPC error if both feeRate and fee_rate are passed")
|
||||
assert_raises_rpc_error(-8, "Cannot specify both fee_rate (sat/vB) and feeRate (BTC/kvB)",
|
||||
|
@ -303,10 +303,16 @@ class WalletSendTest(BitcoinTestFramework):
|
||||
self.test_send(from_wallet=w0, to_wallet=w1, amount=1, conf_target=v, estimate_mode=mode,
|
||||
expect_error=(-3, "Expected type number for conf_target, got {}".format(k)))
|
||||
|
||||
# Test setting explicit fee rate just below the minimum.
|
||||
# Test setting explicit fee rate just below the minimum and at zero.
|
||||
self.log.info("Explicit fee rate raises RPC error 'fee rate too low' if fee_rate of 0.99999999 is passed")
|
||||
self.test_send(from_wallet=w0, to_wallet=w1, amount=1, fee_rate=0.99999999,
|
||||
expect_error=(-4, "Fee rate (0.999 sat/vB) is lower than the minimum fee rate setting (1.000 sat/vB)"))
|
||||
self.test_send(from_wallet=w0, to_wallet=w1, amount=1, arg_fee_rate=0.99999999,
|
||||
expect_error=(-4, "Fee rate (0.999 sat/vB) is lower than the minimum fee rate setting (1.000 sat/vB)"))
|
||||
self.test_send(from_wallet=w0, to_wallet=w1, amount=1, fee_rate=0,
|
||||
expect_error=(-4, "Fee rate (0.000 sat/vB) is lower than the minimum fee rate setting (1.000 sat/vB)"))
|
||||
self.test_send(from_wallet=w0, to_wallet=w1, amount=1, arg_fee_rate=0,
|
||||
expect_error=(-4, "Fee rate (0.000 sat/vB) is lower than the minimum fee rate setting (1.000 sat/vB)"))
|
||||
|
||||
# TODO: Return hex if fee rate is below -maxmempool
|
||||
# res = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, conf_target=0.1, estimate_mode="sat/b", add_to_wallet=False)
|
||||
|
Loading…
x
Reference in New Issue
Block a user