|
7 | 7 | from decimal import Decimal
|
8 | 8 | from test_framework.test_framework import BitcoinTestFramework
|
9 | 9 | from test_framework.util import (
|
| 10 | + assert_approx, |
10 | 11 | assert_equal,
|
11 | 12 | assert_fee_amount,
|
12 | 13 | assert_greater_than,
|
@@ -89,6 +90,7 @@ def run_test(self):
|
89 | 90 | self.test_op_return()
|
90 | 91 | self.test_watchonly()
|
91 | 92 | self.test_all_watched_funds()
|
| 93 | + self.test_feerate_with_conf_target_and_estimate_mode() |
92 | 94 | self.test_option_feerate()
|
93 | 95 | self.test_address_reuse()
|
94 | 96 | self.test_option_subtract_fee_from_outputs()
|
@@ -672,6 +674,59 @@ def test_option_feerate(self):
|
672 | 674 | assert_fee_amount(result2['fee'], count_bytes(result2['hex']), 2 * result_fee_rate)
|
673 | 675 | assert_fee_amount(result3['fee'], count_bytes(result3['hex']), 10 * result_fee_rate)
|
674 | 676 |
|
| 677 | + def test_feerate_with_conf_target_and_estimate_mode(self): |
| 678 | + self.log.info("Test fundrawtxn passing an explicit fee rate using conf_target and estimate_mode") |
| 679 | + node = self.nodes[3] |
| 680 | + # Make sure there is exactly one input so coin selection can't skew the result. |
| 681 | + assert_equal(len(node.listunspent(1)), 1) |
| 682 | + inputs = [] |
| 683 | + outputs = {node.getnewaddress() : 1} |
| 684 | + rawtx = node.createrawtransaction(inputs, outputs) |
| 685 | + |
| 686 | + for unit, fee_rate in {"btc/kb": 0.1, "sat/b": 10000}.items(): |
| 687 | + self.log.info("Test fundrawtxn with conf_target {} estimate_mode {} produces expected fee".format(fee_rate, unit)) |
| 688 | + # With no arguments passed, expect fee of 141 sats/b. |
| 689 | + assert_approx(node.fundrawtransaction(rawtx)["fee"], vexp=0.00000141, vspan=0.00000001) |
| 690 | + # Expect fee to be 10,000x higher when explicit fee 10,000x greater is specified. |
| 691 | + result = node.fundrawtransaction(rawtx, {"conf_target": fee_rate, "estimate_mode": unit}) |
| 692 | + assert_approx(result["fee"], vexp=0.0141, vspan=0.0001) |
| 693 | + |
| 694 | + for field, fee_rate in {"conf_target": 0.1, "estimate_mode": "sat/b"}.items(): |
| 695 | + self.log.info("Test fundrawtxn raises RPC error if both feeRate and {} are passed".format(field)) |
| 696 | + assert_raises_rpc_error( |
| 697 | + -8, "Cannot specify both {} and feeRate".format(field), |
| 698 | + lambda: node.fundrawtransaction(rawtx, {"feeRate": 0.1, field: fee_rate})) |
| 699 | + |
| 700 | + self.log.info("Test fundrawtxn with invalid estimate_mode settings") |
| 701 | + for k, v in {"number": 42, "object": {"foo": "bar"}}.items(): |
| 702 | + assert_raises_rpc_error(-3, "Expected type string for estimate_mode, got {}".format(k), |
| 703 | + lambda: self.nodes[1].fundrawtransaction(rawtx, {"estimate_mode": v, "conf_target": 0.1})) |
| 704 | + for mode in ["foo", Decimal("3.141592")]: |
| 705 | + assert_raises_rpc_error(-8, "Invalid estimate_mode parameter", |
| 706 | + lambda: self.nodes[1].fundrawtransaction(rawtx, {"estimate_mode": mode, "conf_target": 0.1})) |
| 707 | + |
| 708 | + self.log.info("Test fundrawtxn with invalid conf_target settings") |
| 709 | + for mode in ["unset", "economical", "conservative", "btc/kb", "sat/b"]: |
| 710 | + self.log.debug("{}".format(mode)) |
| 711 | + for k, v in {"string": "", "object": {"foo": "bar"}}.items(): |
| 712 | + assert_raises_rpc_error(-3, "Expected type number for conf_target, got {}".format(k), |
| 713 | + lambda: self.nodes[1].fundrawtransaction(rawtx, {"estimate_mode": mode, "conf_target": v})) |
| 714 | + if mode in ["btc/kb", "sat/b"]: |
| 715 | + assert_raises_rpc_error(-3, "Amount out of range", |
| 716 | + lambda: self.nodes[1].fundrawtransaction(rawtx, {"estimate_mode": mode, "conf_target": -1})) |
| 717 | + assert_raises_rpc_error(-4, "Fee rate (0.00000000 BTC/kB) is lower than the minimum fee rate setting (0.00001000 BTC/kB)", |
| 718 | + lambda: self.nodes[1].fundrawtransaction(rawtx, {"estimate_mode": mode, "conf_target": 0})) |
| 719 | + else: |
| 720 | + for n in [-1, 0, 1009]: |
| 721 | + assert_raises_rpc_error(-8, "Invalid conf_target, must be between 1 and 1008", |
| 722 | + lambda: self.nodes[1].fundrawtransaction(rawtx, {"estimate_mode": mode, "conf_target": n})) |
| 723 | + |
| 724 | + for unit, fee_rate in {"sat/B": 0.99999999, "BTC/kB": 0.00000999}.items(): |
| 725 | + self.log.info("- raises RPC error 'fee rate too low' if conf_target {} and estimate_mode {} are passed".format(fee_rate, unit)) |
| 726 | + assert_raises_rpc_error(-4, "Fee rate (0.00000999 BTC/kB) is lower than the minimum fee rate setting (0.00001000 BTC/kB)", |
| 727 | + lambda: self.nodes[1].fundrawtransaction(rawtx, {"estimate_mode": unit, "conf_target": fee_rate, "add_inputs": True})) |
| 728 | + |
| 729 | + |
675 | 730 | def test_address_reuse(self):
|
676 | 731 | """Test no address reuse occurs."""
|
677 | 732 | self.log.info("Test fundrawtxn does not reuse addresses")
|
|
0 commit comments