|
13 | 13 | from test_framework.test_framework import BitcoinTestFramework |
14 | 14 | from test_framework.util import ( |
15 | 15 | assert_equal, |
| 16 | + assert_greater_than, |
| 17 | + assert_greater_than_or_equal, |
16 | 18 | assert_raises_rpc_error, |
| 19 | + get_fee, |
17 | 20 | ) |
18 | 21 | from test_framework.wallet import MiniWallet |
19 | 22 | from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE |
@@ -74,6 +77,9 @@ def run_test(self): |
74 | 77 | self.log.info("Running test full replace by fee...") |
75 | 78 | self.test_fullrbf() |
76 | 79 |
|
| 80 | + self.log.info("Running test incremental relay feerates...") |
| 81 | + self.test_incremental_relay_feerates() |
| 82 | + |
77 | 83 | self.log.info("Passed") |
78 | 84 |
|
79 | 85 | def make_utxo(self, node, amount, *, confirmed=True, scriptPubKey=None): |
@@ -583,6 +589,38 @@ def test_replacement_relay_fee(self): |
583 | 589 | tx.vout[0].nValue -= 1 |
584 | 590 | assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx.serialize().hex()) |
585 | 591 |
|
| 592 | + def test_incremental_relay_feerates(self): |
| 593 | + self.log.info("Test that incremental relay fee is applied correctly in RBF for various settings...") |
| 594 | + node = self.nodes[0] |
| 595 | + for incremental_setting in (0, 5, 10, 50, 100, 234, 1000, 5000, 21000): |
| 596 | + incremental_setting_decimal = incremental_setting / Decimal(COIN) |
| 597 | + self.log.info(f"-> Test -incrementalrelayfee={incremental_setting_decimal:.8f}sat/kvB...") |
| 598 | + self.restart_node(0, extra_args=[f"-incrementalrelayfee={incremental_setting_decimal:.8f}", "-persistmempool=0"]) |
| 599 | + |
| 600 | + # When incremental relay feerate is higher than min relay feerate, min relay feerate is automatically increased. |
| 601 | + min_relay_feerate = node.getmempoolinfo()["minrelaytxfee"] |
| 602 | + assert_greater_than_or_equal(min_relay_feerate, incremental_setting_decimal) |
| 603 | + |
| 604 | + low_feerate = min_relay_feerate * 2 |
| 605 | + confirmed_utxo = self.wallet.get_utxo(confirmed_only=True) |
| 606 | + replacee_tx = self.wallet.create_self_transfer(utxo_to_spend=confirmed_utxo, fee_rate=low_feerate, target_vsize=5000) |
| 607 | + node.sendrawtransaction(replacee_tx['hex']) |
| 608 | + |
| 609 | + replacement_placeholder_tx = self.wallet.create_self_transfer(utxo_to_spend=confirmed_utxo) |
| 610 | + replacement_expected_size = replacement_placeholder_tx['tx'].get_vsize() |
| 611 | + replacement_required_fee = get_fee(replacement_expected_size, incremental_setting_decimal) + replacee_tx['fee'] |
| 612 | + |
| 613 | + # Should always be required to pay additional fees |
| 614 | + if incremental_setting > 0: |
| 615 | + assert_greater_than(replacement_required_fee, replacee_tx['fee']) |
| 616 | + |
| 617 | + # 1 satoshi shy of the required fee |
| 618 | + failed_replacement_tx = self.wallet.create_self_transfer(utxo_to_spend=confirmed_utxo, fee=replacement_required_fee - Decimal("0.00000001")) |
| 619 | + assert_raises_rpc_error(-26, "insufficient fee", node.sendrawtransaction, failed_replacement_tx['hex']) |
| 620 | + |
| 621 | + replacement_tx = self.wallet.create_self_transfer(utxo_to_spend=confirmed_utxo, fee=replacement_required_fee) |
| 622 | + node.sendrawtransaction(replacement_tx['hex']) |
| 623 | + |
586 | 624 | def test_fullrbf(self): |
587 | 625 | # BIP125 signaling is not respected |
588 | 626 |
|
|
0 commit comments