Skip to content

Commit

Permalink
tests: Test for assertion when feerate is rounded down
Browse files Browse the repository at this point in the history
When calculating a txs absolute fee, if the fee is rounded down to the
nearest satoshi, it is possible for the coin selection algorithms to
undercalculate the fee needed. This can lead to an assertion error in
some situations. One such scenario is added to
rpc_fundrawtransaction.py.

Github-Pull: bitcoin#22949
Rebased-From: ce2cc44
  • Loading branch information
achow101 authored and fanquake committed Nov 22, 2021
1 parent 83ea81b commit 5f952c6
Showing 1 changed file with 28 additions and 0 deletions.
28 changes: 28 additions & 0 deletions test/functional/rpc_fundrawtransaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ def run_test(self):
self.test_transaction_too_large()
self.test_include_unsafe()
self.test_22670()
self.test_feerate_rounding()

def test_change_position(self):
"""Ensure setting changePosition in fundraw with an exact match is handled properly."""
Expand Down Expand Up @@ -1026,6 +1027,33 @@ def do_fund_send(target):
do_fund_send(upper_bound)

self.restart_node(0)
self.connect_nodes(0, 1)
self.connect_nodes(0, 2)
self.connect_nodes(0, 3)

def test_feerate_rounding(self):
self.log.info("Test that rounding of GetFee does not result in an assertion")

self.nodes[1].createwallet("roundtest")
w = self.nodes[1].get_wallet_rpc("roundtest")

addr = w.getnewaddress(address_type="bech32")
self.nodes[0].sendtoaddress(addr, 1)
self.nodes[0].generate(1)
self.sync_all()

# A P2WPKH input costs 68 vbytes; With a single P2WPKH output, the rest of the tx is 42 vbytes for a total of 110 vbytes.
# At a feerate of 1.85 sat/vb, the input will need a fee of 125.8 sats and the rest 77.7 sats
# The entire tx fee should be 203.5 sats.
# Coin selection rounds the fee individually instead of at the end (due to how CFeeRate::GetFee works).
# If rounding down (which is the incorrect behavior), then the calculated fee will be 125 + 77 = 202.
# If rounding up, then the calculated fee will be 126 + 78 = 204.
# In the former case, the calculated needed fee is higher than the actual fee being paid, so an assertion is reached
# To test this does not happen, we subtract 202 sats from the input value. If working correctly, this should
# fail with insufficient funds rather than bitcoind asserting.
rawtx = w.createrawtransaction(inputs=[], outputs=[{self.nodes[0].getnewaddress(address_type="bech32"): 1 - 0.00000202}])
assert_raises_rpc_error(-4, "Insufficient funds", w.fundrawtransaction, rawtx, {"fee_rate": 1.85})


if __name__ == '__main__':
RawTransactionsTest().main()

0 comments on commit 5f952c6

Please sign in to comment.