Skip to content

Commit

Permalink
Merge bitcoin#20573: wallet, bugfix: allow send with string fee_rate …
Browse files Browse the repository at this point in the history
…amounts

6fa72ce test: add coverage for passing fee rate as a string (Jon Atack)
ce207d6 wallet, bugfix: allow send to take string fee rate values (Jon Atack)

Pull request description:

  RPC send currently only accepts fee rates as numbers, which is a user-facing bug. It should accept fee rates as an amount, e.g. a string or a number, as documented in its help and like sendtoaddress, sendmany, fundrawtransaction, walletcreatefundedpsbt, and bumpfee. Provide a fix and regression test coverage.

ACKs for top commit:
  MarcoFalke:
    review ACK 6fa72ce
  achow101:
    Code review ACK 6fa72ce
  promag:
    Code review ACK 6fa72ce.

Tree-SHA512: 735f9269cb1b81953764b5283449c0b154bd62de034225be5bcedc515c84faf767fe8fe0741008679fe412922c847b00d116cb11aab775236b779c847ba87167
  • Loading branch information
MarcoFalke committed Dec 10, 2020
2 parents 22f13c1 + 6fa72ce commit 38176dc
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/wallet/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4089,7 +4089,7 @@ static RPCHelpMan send()
UniValueType(), // outputs (ARR or OBJ, checked later)
UniValue::VNUM, // conf_target
UniValue::VSTR, // estimate_mode
UniValue::VNUM, // fee_rate
UniValueType(), // fee_rate, will be checked by AmountFromValue() in SetFeeEstimateMode()
UniValue::VOBJ, // options
}, true
);
Expand Down
4 changes: 2 additions & 2 deletions test/functional/rpc_fundrawtransaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -717,10 +717,10 @@ def test_option_feerate(self):

result = node.fundrawtransaction(rawtx) # uses self.min_relay_tx_fee (set by settxfee)
btc_kvb_to_sat_vb = 100000 # (1e5)
result1 = node.fundrawtransaction(rawtx, {"fee_rate": 2 * btc_kvb_to_sat_vb * self.min_relay_tx_fee})
result1 = node.fundrawtransaction(rawtx, {"fee_rate": str(2 * btc_kvb_to_sat_vb * self.min_relay_tx_fee)})
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})
result4 = node.fundrawtransaction(rawtx, {"feeRate": str(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})
Expand Down
4 changes: 2 additions & 2 deletions test/functional/rpc_psbt.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,11 +190,11 @@ def run_test(self):
self.log.info("Test walletcreatefundedpsbt fee rate of 10000 sat/vB and 0.1 BTC/kvB produces a total fee at or slightly below -maxtxfee (~0.05290000)")
res1 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"fee_rate": 10000, "add_inputs": True})
assert_approx(res1["fee"], 0.055, 0.005)
res2 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"feeRate": 0.1, "add_inputs": True})
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})
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)
Expand Down
29 changes: 27 additions & 2 deletions test/functional/wallet_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,8 @@ def run_test(self):
fee_rate_btc_kvb = fee_rate_sat_vb * 1e3 / 1e8
explicit_fee_rate_btc_kvb = Decimal(fee_rate_btc_kvb) / 1000

txid = self.nodes[2].sendmany(amounts={address: 10}, fee_rate=fee_rate_sat_vb)
# Test passing fee_rate as a string
txid = self.nodes[2].sendmany(amounts={address: 10}, fee_rate=str(fee_rate_sat_vb))
self.nodes[2].generate(1)
self.sync_all(self.nodes[0:3])
balance = self.nodes[2].getbalance()
Expand All @@ -244,6 +245,17 @@ def run_test(self):
node_0_bal += Decimal('10')
assert_equal(self.nodes[0].getbalance(), node_0_bal)

# Test passing fee_rate as an integer
amount = Decimal("0.0001")
txid = self.nodes[2].sendmany(amounts={address: amount}, fee_rate=fee_rate_sat_vb)
self.nodes[2].generate(1)
self.sync_all(self.nodes[0:3])
balance = self.nodes[2].getbalance()
node_2_bal = self.check_fee_amount(balance, node_2_bal - amount, explicit_fee_rate_btc_kvb, self.get_vsize(self.nodes[2].gettransaction(txid)['hex']))
assert_equal(balance, node_2_bal)
node_0_bal += amount
assert_equal(self.nodes[0].getbalance(), node_0_bal)

for key in ["totalFee", "feeRate"]:
assert_raises_rpc_error(-8, "Unknown named parameter key", self.nodes[2].sendtoaddress, address=address, amount=1, fee_rate=1, key=1)

Expand Down Expand Up @@ -405,7 +417,7 @@ def run_test(self):
amount = 3
fee_rate_sat_vb = 2
fee_rate_btc_kvb = fee_rate_sat_vb * 1e3 / 1e8

# Test passing fee_rate as an integer
txid = self.nodes[2].sendtoaddress(address=address, amount=amount, fee_rate=fee_rate_sat_vb)
tx_size = self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])
self.nodes[0].generate(1)
Expand All @@ -414,6 +426,19 @@ def run_test(self):
fee = prebalance - postbalance - Decimal(amount)
assert_fee_amount(fee, tx_size, Decimal(fee_rate_btc_kvb))

prebalance = self.nodes[2].getbalance()
amount = Decimal("0.001")
fee_rate_sat_vb = 1.23
fee_rate_btc_kvb = fee_rate_sat_vb * 1e3 / 1e8
# Test passing fee_rate as a string
txid = self.nodes[2].sendtoaddress(address=address, amount=amount, fee_rate=str(fee_rate_sat_vb))
tx_size = self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])
self.nodes[0].generate(1)
self.sync_all(self.nodes[0:3])
postbalance = self.nodes[2].getbalance()
fee = prebalance - postbalance - amount
assert_fee_amount(fee, tx_size, Decimal(fee_rate_btc_kvb))

for key in ["totalFee", "feeRate"]:
assert_raises_rpc_error(-8, "Unknown named parameter key", self.nodes[2].sendtoaddress, address=address, amount=1, fee_rate=1, key=1)

Expand Down
2 changes: 1 addition & 1 deletion test/functional/wallet_bumpfee.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def test_simple_bumpfee_succeeds(self, mode, rbf_node, peer_node, dest_address):
self.sync_mempools((rbf_node, peer_node))
assert rbfid in rbf_node.getrawmempool() and rbfid in peer_node.getrawmempool()
if mode == "fee_rate":
bumped_psbt = rbf_node.psbtbumpfee(rbfid, {"fee_rate": NORMAL})
bumped_psbt = rbf_node.psbtbumpfee(rbfid, {"fee_rate": str(NORMAL)})
bumped_tx = rbf_node.bumpfee(rbfid, {"fee_rate": NORMAL})
else:
bumped_psbt = rbf_node.psbtbumpfee(rbfid)
Expand Down
4 changes: 2 additions & 2 deletions test/functional/wallet_send.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,8 @@ def run_test(self):
assert res["complete"]

self.log.info("Test setting explicit fee rate")
res1 = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, arg_fee_rate=1, add_to_wallet=False)
res2 = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, fee_rate=1, add_to_wallet=False)
res1 = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, arg_fee_rate="1", add_to_wallet=False)
res2 = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, fee_rate="1", add_to_wallet=False)
assert_equal(self.nodes[1].decodepsbt(res1["psbt"])["fee"], self.nodes[1].decodepsbt(res2["psbt"])["fee"])

res = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, fee_rate=7, add_to_wallet=False)
Expand Down

0 comments on commit 38176dc

Please sign in to comment.