77
88mod bitcoind_rpc;
99
10- use crate :: chain:: bitcoind_rpc:: { BitcoindRpcClient , BoundedHeaderCache , ChainListener } ;
10+ use crate :: chain:: bitcoind_rpc:: {
11+ BitcoindRpcClient , BoundedHeaderCache , ChainListener , FeeRateEstimationMode ,
12+ } ;
1113use crate :: config:: {
1214 Config , EsploraSyncConfig , BDK_CLIENT_CONCURRENCY , BDK_CLIENT_STOP_GAP ,
1315 BDK_WALLET_SYNC_TIMEOUT_SECS , FEE_RATE_CACHE_UPDATE_TIMEOUT_SECS , LDK_WALLET_SYNC_TIMEOUT_SECS ,
@@ -16,13 +18,14 @@ use crate::config::{
1618} ;
1719use crate :: fee_estimator:: {
1820 apply_post_estimation_adjustments, get_all_conf_targets, get_num_block_defaults_for_target,
19- OnchainFeeEstimator ,
21+ ConfirmationTarget , OnchainFeeEstimator ,
2022} ;
2123use crate :: io:: utils:: write_node_metrics;
2224use crate :: logger:: { log_bytes, log_error, log_info, log_trace, FilesystemLogger , Logger } ;
2325use crate :: types:: { Broadcaster , ChainMonitor , ChannelManager , DynStore , Sweeper , Wallet } ;
2426use crate :: { Error , NodeMetrics } ;
2527
28+ use lightning:: chain:: chaininterface:: ConfirmationTarget as LdkConfirmationTarget ;
2629use lightning:: chain:: { Confirm , Filter , Listen } ;
2730use lightning:: util:: ser:: Writeable ;
2831
@@ -356,6 +359,13 @@ impl ChainSource {
356359 chain_polling_interval
357360 . set_missed_tick_behavior ( tokio:: time:: MissedTickBehavior :: Skip ) ;
358361
362+ let mut fee_rate_update_interval =
363+ tokio:: time:: interval ( Duration :: from_secs ( CHAIN_POLLING_INTERVAL_SECS ) ) ;
364+ // When starting up, we just blocked on updating, so skip the first tick.
365+ fee_rate_update_interval. reset ( ) ;
366+ fee_rate_update_interval
367+ . set_missed_tick_behavior ( tokio:: time:: MissedTickBehavior :: Skip ) ;
368+
359369 // Start the polling loop.
360370 loop {
361371 tokio:: select! {
@@ -369,6 +379,9 @@ impl ChainSource {
369379 _ = chain_polling_interval. tick( ) => {
370380 let _ = self . poll_and_update_listeners( Arc :: clone( & channel_manager) , Arc :: clone( & chain_monitor) , Arc :: clone( & output_sweeper) ) . await ;
371381 }
382+ _ = fee_rate_update_interval. tick( ) => {
383+ let _ = self . update_fee_rate_estimates( ) . await ;
384+ }
372385 }
373386 }
374387 } ,
@@ -805,7 +818,108 @@ impl ChainSource {
805818
806819 Ok ( ( ) )
807820 } ,
808- Self :: BitcoindRpc { .. } => todo ! ( ) ,
821+ Self :: BitcoindRpc {
822+ bitcoind_rpc_client,
823+ fee_estimator,
824+ kv_store,
825+ logger,
826+ node_metrics,
827+ ..
828+ } => {
829+ macro_rules! get_fee_rate_update {
830+ ( $estimation_fut: expr) => { {
831+ tokio:: time:: timeout(
832+ Duration :: from_secs( FEE_RATE_CACHE_UPDATE_TIMEOUT_SECS ) ,
833+ $estimation_fut,
834+ )
835+ . await
836+ . map_err( |e| {
837+ log_error!( logger, "Updating fee rate estimates timed out: {}" , e) ;
838+ Error :: FeerateEstimationUpdateTimeout
839+ } ) ?
840+ . map_err( |e| {
841+ log_error!( logger, "Failed to retrieve fee rate estimates: {}" , e) ;
842+ Error :: FeerateEstimationUpdateFailed
843+ } ) ?
844+ } } ;
845+ }
846+ let confirmation_targets = get_all_conf_targets ( ) ;
847+
848+ let mut new_fee_rate_cache = HashMap :: with_capacity ( 10 ) ;
849+ let now = Instant :: now ( ) ;
850+ for target in confirmation_targets {
851+ let fee_rate = match target {
852+ ConfirmationTarget :: Lightning (
853+ LdkConfirmationTarget :: MinAllowedAnchorChannelRemoteFee ,
854+ ) => {
855+ let estimation_fut = bitcoind_rpc_client. get_mempool_minimum_fee_rate ( ) ;
856+ get_fee_rate_update ! ( estimation_fut)
857+ } ,
858+ ConfirmationTarget :: Lightning (
859+ LdkConfirmationTarget :: MaximumFeeEstimate ,
860+ ) => {
861+ let num_blocks = get_num_block_defaults_for_target ( target) ;
862+ let estimation_mode = FeeRateEstimationMode :: Conservative ;
863+ let estimation_fut = bitcoind_rpc_client
864+ . get_fee_estimate_for_target ( num_blocks, estimation_mode) ;
865+ get_fee_rate_update ! ( estimation_fut)
866+ } ,
867+ ConfirmationTarget :: Lightning (
868+ LdkConfirmationTarget :: UrgentOnChainSweep ,
869+ ) => {
870+ let num_blocks = get_num_block_defaults_for_target ( target) ;
871+ let estimation_mode = FeeRateEstimationMode :: Conservative ;
872+ let estimation_fut = bitcoind_rpc_client
873+ . get_fee_estimate_for_target ( num_blocks, estimation_mode) ;
874+ get_fee_rate_update ! ( estimation_fut)
875+ } ,
876+ _ => {
877+ // Otherwise, we default to economical block-target estimate.
878+ let num_blocks = get_num_block_defaults_for_target ( target) ;
879+ let estimation_mode = FeeRateEstimationMode :: Economical ;
880+ let estimation_fut = bitcoind_rpc_client
881+ . get_fee_estimate_for_target ( num_blocks, estimation_mode) ;
882+ get_fee_rate_update ! ( estimation_fut)
883+ } ,
884+ } ;
885+
886+ // LDK 0.0.118 introduced changes to the `ConfirmationTarget` semantics that
887+ // require some post-estimation adjustments to the fee rates, which we do here.
888+ let adjusted_fee_rate = apply_post_estimation_adjustments ( target, fee_rate) ;
889+
890+ new_fee_rate_cache. insert ( target, adjusted_fee_rate) ;
891+
892+ log_trace ! (
893+ logger,
894+ "Fee rate estimation updated for {:?}: {} sats/kwu" ,
895+ target,
896+ adjusted_fee_rate. to_sat_per_kwu( ) ,
897+ ) ;
898+ }
899+
900+ if fee_estimator. set_fee_rate_cache ( new_fee_rate_cache) {
901+ // We only log if the values changed, as it might be very spammy otherwise.
902+ log_info ! (
903+ logger,
904+ "Fee rate cache update finished in {}ms." ,
905+ now. elapsed( ) . as_millis( )
906+ ) ;
907+ }
908+
909+ let unix_time_secs_opt =
910+ SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) . ok ( ) . map ( |d| d. as_secs ( ) ) ;
911+ {
912+ let mut locked_node_metrics = node_metrics. write ( ) . unwrap ( ) ;
913+ locked_node_metrics. latest_fee_rate_cache_update_timestamp = unix_time_secs_opt;
914+ write_node_metrics (
915+ & * locked_node_metrics,
916+ Arc :: clone ( & kv_store) ,
917+ Arc :: clone ( & logger) ,
918+ ) ?;
919+ }
920+
921+ Ok ( ( ) )
922+ } ,
809923 }
810924 }
811925
0 commit comments