@@ -128,6 +128,14 @@ def make_tx(wallet, utxo, feerate):
128128 fee_rate = Decimal (feerate * 1000 ) / COIN ,
129129 )
130130
131+ def check_fee_estimates_btw_modes (node , expected_conservative , expected_economical ):
132+ fee_est_conservative = node .estimatesmartfee (1 , estimate_mode = "conservative" )['feerate' ]
133+ fee_est_economical = node .estimatesmartfee (1 , estimate_mode = "economical" )['feerate' ]
134+ fee_est_default = node .estimatesmartfee (1 )['feerate' ]
135+ assert_equal (fee_est_conservative , expected_conservative )
136+ assert_equal (fee_est_economical , expected_economical )
137+ assert_equal (fee_est_default , expected_economical )
138+
131139
132140class EstimateFeeTest (BitcoinTestFramework ):
133141 def set_test_params (self ):
@@ -382,6 +390,40 @@ def test_acceptstalefeeestimates_option(self):
382390 self .start_node (0 ,extra_args = ["-acceptstalefeeestimates" ])
383391 assert_equal (self .nodes [0 ].estimatesmartfee (1 )["feerate" ], fee_rate )
384392
393+ def clear_estimates (self ):
394+ self .log .info ("Restarting node with fresh estimation" )
395+ self .stop_node (0 )
396+ fee_dat = self .nodes [0 ].chain_path / "fee_estimates.dat"
397+ os .remove (fee_dat )
398+ self .start_node (0 )
399+ self .connect_nodes (0 , 1 )
400+ self .connect_nodes (0 , 2 )
401+ assert_equal (self .nodes [0 ].estimatesmartfee (1 )["errors" ], ["Insufficient data or no feerate found" ])
402+
403+ def broadcast_and_mine (self , broadcaster , miner , feerate , count ):
404+ """Broadcast and mine some number of transactions with a specified fee rate."""
405+ for _ in range (count ):
406+ self .wallet .send_self_transfer (from_node = broadcaster , fee_rate = feerate )
407+ self .sync_mempools ()
408+ self .generate (miner , 1 )
409+
410+ def test_estimation_modes (self ):
411+ low_feerate = Decimal ("0.001" )
412+ high_feerate = Decimal ("0.005" )
413+ tx_count = 24
414+ # Broadcast and mine high fee transactions for the first 12 blocks.
415+ for _ in range (12 ):
416+ self .broadcast_and_mine (self .nodes [1 ], self .nodes [2 ], high_feerate , tx_count )
417+ check_fee_estimates_btw_modes (self .nodes [0 ], high_feerate , high_feerate )
418+
419+ # We now track 12 blocks; short horizon stats will start decaying.
420+ # Broadcast and mine low fee transactions for the next 4 blocks.
421+ for _ in range (4 ):
422+ self .broadcast_and_mine (self .nodes [1 ], self .nodes [2 ], low_feerate , tx_count )
423+ # conservative mode will consider longer time horizons while economical mode does not
424+ # Check the fee estimates for both modes after mining low fee transactions.
425+ check_fee_estimates_btw_modes (self .nodes [0 ], high_feerate , low_feerate )
426+
385427
386428 def run_test (self ):
387429 self .log .info ("This test is time consuming, please be patient" )
@@ -420,17 +462,15 @@ def run_test(self):
420462 self .log .info ("Test reading old fee_estimates.dat" )
421463 self .test_old_fee_estimate_file ()
422464
423- self .log .info ("Restarting node with fresh estimation" )
424- self .stop_node (0 )
425- fee_dat = os .path .join (self .nodes [0 ].chain_path , "fee_estimates.dat" )
426- os .remove (fee_dat )
427- self .start_node (0 )
428- self .connect_nodes (0 , 1 )
429- self .connect_nodes (0 , 2 )
465+ self .clear_estimates ()
430466
431467 self .log .info ("Testing estimates with RBF." )
432468 self .sanity_check_rbf_estimates (self .confutxo + self .memutxo )
433469
470+ self .clear_estimates ()
471+ self .log .info ("Test estimatesmartfee modes" )
472+ self .test_estimation_modes ()
473+
434474 self .log .info ("Testing that fee estimation is disabled in blocksonly." )
435475 self .restart_node (0 , ["-blocksonly" ])
436476 assert_raises_rpc_error (
0 commit comments