@@ -90,7 +90,6 @@ def run_test(self):
90
90
self .test_op_return ()
91
91
self .test_watchonly ()
92
92
self .test_all_watched_funds ()
93
- self .test_feerate_with_conf_target_and_estimate_mode ()
94
93
self .test_option_feerate ()
95
94
self .test_address_reuse ()
96
95
self .test_option_subtract_fee_from_outputs ()
@@ -708,74 +707,89 @@ def test_all_watched_funds(self):
708
707
wwatch .unloadwallet ()
709
708
710
709
def test_option_feerate (self ):
711
- self .log .info ("Test fundrawtxn feeRate option" )
712
-
713
- # Make sure there is exactly one input so coin selection can't skew the result.
714
- assert_equal (len (self .nodes [3 ].listunspent (1 )), 1 )
715
-
716
- inputs = []
717
- outputs = {self .nodes [3 ].getnewaddress () : 1 }
718
- rawtx = self .nodes [3 ].createrawtransaction (inputs , outputs )
719
- result = self .nodes [3 ].fundrawtransaction (rawtx ) # uses self.min_relay_tx_fee (set by settxfee)
720
- result2 = self .nodes [3 ].fundrawtransaction (rawtx , {"feeRate" : 2 * self .min_relay_tx_fee })
721
- result3 = self .nodes [3 ].fundrawtransaction (rawtx , {"feeRate" : 10 * self .min_relay_tx_fee })
722
- assert_raises_rpc_error (- 4 , "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)" , self .nodes [3 ].fundrawtransaction , rawtx , {"feeRate" : 1 })
723
- result_fee_rate = result ['fee' ] * 1000 / count_bytes (result ['hex' ])
724
- assert_fee_amount (result2 ['fee' ], count_bytes (result2 ['hex' ]), 2 * result_fee_rate )
725
- assert_fee_amount (result3 ['fee' ], count_bytes (result3 ['hex' ]), 10 * result_fee_rate )
726
-
727
- def test_feerate_with_conf_target_and_estimate_mode (self ):
728
- self .log .info ("Test fundrawtxn passing an explicit fee rate using conf_target and estimate_mode" )
710
+ self .log .info ("Test fundrawtxn with explicit fee rates (fee_rate sat/vB and feeRate BTC/kvB)" )
729
711
node = self .nodes [3 ]
730
712
# Make sure there is exactly one input so coin selection can't skew the result.
731
- assert_equal (len (node .listunspent (1 )), 1 )
713
+ assert_equal (len (self . nodes [ 3 ] .listunspent (1 )), 1 )
732
714
inputs = []
733
715
outputs = {node .getnewaddress () : 1 }
734
716
rawtx = node .createrawtransaction (inputs , outputs )
735
717
736
- for unit , fee_rate in {"btc/kb" : 0.1 , "sat/b" : 10000 }.items ():
737
- self .log .info ("Test fundrawtxn with conf_target {} estimate_mode {} produces expected fee" .format (fee_rate , unit ))
738
- # With no arguments passed, expect fee of 141 sats/b.
739
- assert_approx (node .fundrawtransaction (rawtx )["fee" ], vexp = 0.00000141 , vspan = 0.00000001 )
740
- # Expect fee to be 10,000x higher when explicit fee 10,000x greater is specified.
741
- result = node .fundrawtransaction (rawtx , {"conf_target" : fee_rate , "estimate_mode" : unit })
742
- assert_approx (result ["fee" ], vexp = 0.0141 , vspan = 0.0001 )
718
+ result = node .fundrawtransaction (rawtx ) # uses self.min_relay_tx_fee (set by settxfee)
719
+ btc_kvb_to_sat_vb = 100000 # (1e5)
720
+ result1 = node .fundrawtransaction (rawtx , {"fee_rate" : 2 * btc_kvb_to_sat_vb * self .min_relay_tx_fee })
721
+ result2 = node .fundrawtransaction (rawtx , {"feeRate" : 2 * self .min_relay_tx_fee })
722
+ result3 = node .fundrawtransaction (rawtx , {"fee_rate" : 10 * btc_kvb_to_sat_vb * self .min_relay_tx_fee })
723
+ result4 = node .fundrawtransaction (rawtx , {"feeRate" : 10 * self .min_relay_tx_fee })
724
+ result_fee_rate = result ['fee' ] * 1000 / count_bytes (result ['hex' ])
725
+ assert_fee_amount (result1 ['fee' ], count_bytes (result2 ['hex' ]), 2 * result_fee_rate )
726
+ assert_fee_amount (result2 ['fee' ], count_bytes (result2 ['hex' ]), 2 * result_fee_rate )
727
+ assert_fee_amount (result3 ['fee' ], count_bytes (result3 ['hex' ]), 10 * result_fee_rate )
728
+ assert_fee_amount (result4 ['fee' ], count_bytes (result3 ['hex' ]), 10 * result_fee_rate )
743
729
744
- for field , fee_rate in { "conf_target" : 0.1 , "estimate_mode" : "sat/b" }. items ():
745
- self . log . info ( "Test fundrawtxn raises RPC error if both feeRate and {} are passed" . format ( field ) )
746
- assert_raises_rpc_error (
747
- - 8 , "Cannot specify both {} and feeRate" . format ( field ),
748
- lambda : node . fundrawtransaction ( rawtx , { "feeRate" : 0.1 , field : fee_rate }) )
730
+ # With no arguments passed, expect fee of 141 satoshis.
731
+ assert_approx ( node . fundrawtransaction ( rawtx )[ "fee" ], vexp = 0.00000141 , vspan = 0.00000001 )
732
+ # Expect fee to be 10,000x higher when an explicit fee rate 10,000x greater is specified.
733
+ result = node . fundrawtransaction ( rawtx , { "fee_rate" : 10000 })
734
+ assert_approx ( result [ "fee" ], vexp = 0.0141 , vspan = 0.0001 )
749
735
750
736
self .log .info ("Test fundrawtxn with invalid estimate_mode settings" )
751
737
for k , v in {"number" : 42 , "object" : {"foo" : "bar" }}.items ():
752
738
assert_raises_rpc_error (- 3 , "Expected type string for estimate_mode, got {}" .format (k ),
753
- lambda : self . nodes [ 1 ]. fundrawtransaction ( rawtx , {"estimate_mode" : v , "conf_target" : 0.1 }) )
754
- for mode in ["foo" , Decimal ("3.141592" )]:
739
+ node . fundrawtransaction , rawtx , {"estimate_mode" : v , "conf_target" : 0.1 , "add_inputs" : True } )
740
+ for mode in ["" , " foo" , Decimal ("3.141592" )]:
755
741
assert_raises_rpc_error (- 8 , "Invalid estimate_mode parameter" ,
756
- lambda : self . nodes [ 1 ]. fundrawtransaction ( rawtx , {"estimate_mode" : mode , "conf_target" : 0.1 }) )
742
+ node . fundrawtransaction , rawtx , {"estimate_mode" : mode , "conf_target" : 0.1 , "add_inputs" : True } )
757
743
758
744
self .log .info ("Test fundrawtxn with invalid conf_target settings" )
759
- for mode in ["unset" , "economical" , "conservative" , "btc/kb" , "sat/b" ]:
745
+ for mode in ["unset" , "economical" , "conservative" ]:
760
746
self .log .debug ("{}" .format (mode ))
761
747
for k , v in {"string" : "" , "object" : {"foo" : "bar" }}.items ():
762
748
assert_raises_rpc_error (- 3 , "Expected type number for conf_target, got {}" .format (k ),
763
- lambda : self .nodes [1 ].fundrawtransaction (rawtx , {"estimate_mode" : mode , "conf_target" : v }))
764
- if mode in ["btc/kb" , "sat/b" ]:
765
- assert_raises_rpc_error (- 3 , "Amount out of range" ,
766
- lambda : self .nodes [1 ].fundrawtransaction (rawtx , {"estimate_mode" : mode , "conf_target" : - 1 }))
767
- assert_raises_rpc_error (- 4 , "Fee rate (0.00000000 BTC/kB) is lower than the minimum fee rate setting (0.00001000 BTC/kB)" ,
768
- lambda : self .nodes [1 ].fundrawtransaction (rawtx , {"estimate_mode" : mode , "conf_target" : 0 }))
769
- else :
770
- for n in [- 1 , 0 , 1009 ]:
771
- assert_raises_rpc_error (- 8 , "Invalid conf_target, must be between 1 and 1008" ,
772
- lambda : self .nodes [1 ].fundrawtransaction (rawtx , {"estimate_mode" : mode , "conf_target" : n }))
773
-
774
- for unit , fee_rate in {"sat/B" : 0.99999999 , "BTC/kB" : 0.00000999 }.items ():
775
- self .log .info ("- raises RPC error 'fee rate too low' if conf_target {} and estimate_mode {} are passed" .format (fee_rate , unit ))
776
- assert_raises_rpc_error (- 4 , "Fee rate (0.00000999 BTC/kB) is lower than the minimum fee rate setting (0.00001000 BTC/kB)" ,
777
- lambda : self .nodes [1 ].fundrawtransaction (rawtx , {"estimate_mode" : unit , "conf_target" : fee_rate , "add_inputs" : True }))
778
-
749
+ node .fundrawtransaction , rawtx , {"estimate_mode" : mode , "conf_target" : v , "add_inputs" : True })
750
+ for n in [- 1 , 0 , 1009 ]:
751
+ assert_raises_rpc_error (- 8 , "Invalid conf_target, must be between 1 and 1008" , # max value of 1008 per src/policy/fees.h
752
+ node .fundrawtransaction , rawtx , {"estimate_mode" : mode , "conf_target" : n , "add_inputs" : True })
753
+
754
+ self .log .info ("Test invalid fee rate settings" )
755
+ assert_raises_rpc_error (- 4 , "Fee rate (0.00000000 BTC/kB) is lower than the minimum fee rate setting (0.00001000 BTC/kB)" ,
756
+ node .fundrawtransaction , rawtx , {"fee_rate" : 0 , "add_inputs" : True })
757
+ assert_raises_rpc_error (- 8 , "Invalid feeRate 0.00000000 BTC/kB (must be greater than 0)" ,
758
+ node .fundrawtransaction , rawtx , {"feeRate" : 0 , "add_inputs" : True })
759
+ for param , value in {("fee_rate" , 100000 ), ("feeRate" , 1.000 )}:
760
+ assert_raises_rpc_error (- 4 , "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)" ,
761
+ node .fundrawtransaction , rawtx , {param : value , "add_inputs" : True })
762
+ assert_raises_rpc_error (- 3 , "Amount out of range" ,
763
+ node .fundrawtransaction , rawtx , {"fee_rate" : - 1 , "add_inputs" : True })
764
+ assert_raises_rpc_error (- 3 , "Amount is not a number or string" ,
765
+ node .fundrawtransaction , rawtx , {"fee_rate" : {"foo" : "bar" }, "add_inputs" : True })
766
+ assert_raises_rpc_error (- 3 , "Invalid amount" ,
767
+ node .fundrawtransaction , rawtx , {"fee_rate" : "" , "add_inputs" : True })
768
+
769
+ # Test setting explicit fee rate just below the minimum.
770
+ self .log .info ("- raises RPC error 'fee rate too low' if fee_rate of 0.99999999 sat/vB is passed" )
771
+ msg = "Fee rate (0.00000999 BTC/kB) is lower than the minimum fee rate setting (0.00001000 BTC/kB)"
772
+ assert_raises_rpc_error (- 4 , msg , node .fundrawtransaction , rawtx , {"fee_rate" : 0.99999999 , "add_inputs" : True })
773
+ # This feeRate test only passes if `coinControl.fOverrideFeeRate = true` in wallet/rpcwallet.cpp::FundTransaction is removed.
774
+ # assert_raises_rpc_error(-4, msg, node.fundrawtransaction, rawtx, {"feeRate": 0.00000999, "add_inputs": True})
775
+
776
+ self .log .info ("- raises RPC error if both feeRate and fee_rate are passed" )
777
+ assert_raises_rpc_error (- 8 , "Cannot specify both fee_rate (sat/vB) and feeRate (BTC/kvB)" ,
778
+ node .fundrawtransaction , rawtx , {"fee_rate" : 0.1 , "feeRate" : 0.1 , "add_inputs" : True })
779
+
780
+ self .log .info ("- raises RPC error if both feeRate and estimate_mode passed" )
781
+ assert_raises_rpc_error (- 8 , "Cannot specify both estimate_mode and feeRate" ,
782
+ node .fundrawtransaction , rawtx , {"estimate_mode" : "economical" , "feeRate" : 0.1 , "add_inputs" : True })
783
+
784
+ for param in ["feeRate" , "fee_rate" ]:
785
+ self .log .info ("- raises RPC error if both {} and conf_target are passed" .format (param ))
786
+ assert_raises_rpc_error (- 8 , "Cannot specify both conf_target and {}. Please provide either a confirmation "
787
+ "target in blocks for automatic fee estimation, or an explicit fee rate." .format (param ),
788
+ node .fundrawtransaction , rawtx , {param : 1 , "conf_target" : 1 , "add_inputs" : True })
789
+
790
+ self .log .info ("- raises RPC error if both fee_rate and estimate_mode are passed" )
791
+ assert_raises_rpc_error (- 8 , "Cannot specify both estimate_mode and fee_rate" ,
792
+ node .fundrawtransaction , rawtx , {"fee_rate" : 1 , "estimate_mode" : "economical" , "add_inputs" : True })
779
793
780
794
def test_address_reuse (self ):
781
795
"""Test no address reuse occurs."""
@@ -803,12 +817,32 @@ def test_option_subtract_fee_from_outputs(self):
803
817
outputs = {self .nodes [2 ].getnewaddress (): 1 }
804
818
rawtx = self .nodes [3 ].createrawtransaction (inputs , outputs )
805
819
820
+ # Test subtract fee from outputs with feeRate (BTC/kvB)
806
821
result = [self .nodes [3 ].fundrawtransaction (rawtx ), # uses self.min_relay_tx_fee (set by settxfee)
807
822
self .nodes [3 ].fundrawtransaction (rawtx , {"subtractFeeFromOutputs" : []}), # empty subtraction list
808
823
self .nodes [3 ].fundrawtransaction (rawtx , {"subtractFeeFromOutputs" : [0 ]}), # uses self.min_relay_tx_fee (set by settxfee)
809
824
self .nodes [3 ].fundrawtransaction (rawtx , {"feeRate" : 2 * self .min_relay_tx_fee }),
810
825
self .nodes [3 ].fundrawtransaction (rawtx , {"feeRate" : 2 * self .min_relay_tx_fee , "subtractFeeFromOutputs" : [0 ]}),]
826
+ dec_tx = [self .nodes [3 ].decoderawtransaction (tx_ ['hex' ]) for tx_ in result ]
827
+ output = [d ['vout' ][1 - r ['changepos' ]]['value' ] for d , r in zip (dec_tx , result )]
828
+ change = [d ['vout' ][r ['changepos' ]]['value' ] for d , r in zip (dec_tx , result )]
829
+
830
+ assert_equal (result [0 ]['fee' ], result [1 ]['fee' ], result [2 ]['fee' ])
831
+ assert_equal (result [3 ]['fee' ], result [4 ]['fee' ])
832
+ assert_equal (change [0 ], change [1 ])
833
+ assert_equal (output [0 ], output [1 ])
834
+ assert_equal (output [0 ], output [2 ] + result [2 ]['fee' ])
835
+ assert_equal (change [0 ] + result [0 ]['fee' ], change [2 ])
836
+ assert_equal (output [3 ], output [4 ] + result [4 ]['fee' ])
837
+ assert_equal (change [3 ] + result [3 ]['fee' ], change [4 ])
811
838
839
+ # Test subtract fee from outputs with fee_rate (sat/vB)
840
+ btc_kvb_to_sat_vb = 100000 # (1e5)
841
+ result = [self .nodes [3 ].fundrawtransaction (rawtx ), # uses self.min_relay_tx_fee (set by settxfee)
842
+ self .nodes [3 ].fundrawtransaction (rawtx , {"subtractFeeFromOutputs" : []}), # empty subtraction list
843
+ self .nodes [3 ].fundrawtransaction (rawtx , {"subtractFeeFromOutputs" : [0 ]}), # uses self.min_relay_tx_fee (set by settxfee)
844
+ self .nodes [3 ].fundrawtransaction (rawtx , {"fee_rate" : 2 * btc_kvb_to_sat_vb * self .min_relay_tx_fee }),
845
+ self .nodes [3 ].fundrawtransaction (rawtx , {"fee_rate" : 2 * btc_kvb_to_sat_vb * self .min_relay_tx_fee , "subtractFeeFromOutputs" : [0 ]}),]
812
846
dec_tx = [self .nodes [3 ].decoderawtransaction (tx_ ['hex' ]) for tx_ in result ]
813
847
output = [d ['vout' ][1 - r ['changepos' ]]['value' ] for d , r in zip (dec_tx , result )]
814
848
change = [d ['vout' ][r ['changepos' ]]['value' ] for d , r in zip (dec_tx , result )]
0 commit comments