88mod bitcoind_rpc;
99mod block_sync_init;
1010
11- use crate :: chain:: bitcoind_rpc:: { BitcoindRpcClient , BoundedHeaderCache , ChainListener } ;
11+ use crate :: chain:: bitcoind_rpc:: {
12+ BitcoindRpcClient , BoundedHeaderCache , ChainListener , FeeRateEstimationMode ,
13+ } ;
1214use crate :: chain:: block_sync_init:: synchronize_listeners;
1315use crate :: config:: {
1416 Config , EsploraSyncConfig , BDK_CLIENT_CONCURRENCY , BDK_CLIENT_STOP_GAP ,
@@ -18,13 +20,14 @@ use crate::config::{
1820} ;
1921use crate :: fee_estimator:: {
2022 apply_post_estimation_adjustments, get_all_conf_targets, get_num_block_defaults_for_target,
21- OnchainFeeEstimator ,
23+ ConfirmationTarget , OnchainFeeEstimator ,
2224} ;
2325use crate :: io:: utils:: write_node_metrics;
2426use crate :: logger:: { log_bytes, log_error, log_info, log_trace, FilesystemLogger , Logger } ;
2527use crate :: types:: { Broadcaster , ChainMonitor , ChannelManager , DynStore , Sweeper , Wallet } ;
2628use crate :: { Error , NodeMetrics } ;
2729
30+ use lightning:: chain:: chaininterface:: ConfirmationTarget as LdkConfirmationTarget ;
2831use lightning:: chain:: { Confirm , Filter , Listen } ;
2932use lightning:: util:: ser:: Writeable ;
3033
@@ -348,6 +351,13 @@ impl ChainSource {
348351 chain_polling_interval
349352 . set_missed_tick_behavior ( tokio:: time:: MissedTickBehavior :: Skip ) ;
350353
354+ let mut fee_rate_update_interval =
355+ tokio:: time:: interval ( Duration :: from_secs ( CHAIN_POLLING_INTERVAL_SECS ) ) ;
356+ // When starting up, we just blocked on updating, so skip the first tick.
357+ fee_rate_update_interval. reset ( ) ;
358+ fee_rate_update_interval
359+ . set_missed_tick_behavior ( tokio:: time:: MissedTickBehavior :: Skip ) ;
360+
351361 // Start the polling loop.
352362 loop {
353363 tokio:: select! {
@@ -382,6 +392,9 @@ impl ChainSource {
382392 } ) ;
383393 }
384394 }
395+ _ = fee_rate_update_interval. tick( ) => {
396+ let _ = self . update_fee_rate_estimates( ) . await ;
397+ }
385398 }
386399 }
387400 } ,
@@ -704,7 +717,108 @@ impl ChainSource {
704717
705718 Ok ( ( ) )
706719 } ,
707- Self :: BitcoindRpc { .. } => todo ! ( ) ,
720+ Self :: BitcoindRpc {
721+ bitcoind_rpc_client,
722+ fee_estimator,
723+ kv_store,
724+ logger,
725+ node_metrics,
726+ ..
727+ } => {
728+ macro_rules! get_fee_rate_update {
729+ ( $estimation_fut: expr) => { {
730+ tokio:: time:: timeout(
731+ Duration :: from_secs( FEE_RATE_CACHE_UPDATE_TIMEOUT_SECS ) ,
732+ $estimation_fut,
733+ )
734+ . await
735+ . map_err( |e| {
736+ log_error!( logger, "Updating fee rate estimates timed out: {}" , e) ;
737+ Error :: FeerateEstimationUpdateTimeout
738+ } ) ?
739+ . map_err( |e| {
740+ log_error!( logger, "Failed to retrieve fee rate estimates: {}" , e) ;
741+ Error :: FeerateEstimationUpdateFailed
742+ } ) ?
743+ } } ;
744+ }
745+ let confirmation_targets = get_all_conf_targets ( ) ;
746+
747+ let mut new_fee_rate_cache = HashMap :: with_capacity ( 10 ) ;
748+ let now = Instant :: now ( ) ;
749+ for target in confirmation_targets {
750+ let fee_rate = match target {
751+ ConfirmationTarget :: Lightning (
752+ LdkConfirmationTarget :: MinAllowedAnchorChannelRemoteFee ,
753+ ) => {
754+ let estimation_fut = bitcoind_rpc_client. get_mempool_minimum_fee_rate ( ) ;
755+ get_fee_rate_update ! ( estimation_fut)
756+ } ,
757+ ConfirmationTarget :: Lightning (
758+ LdkConfirmationTarget :: MaximumFeeEstimate ,
759+ ) => {
760+ let num_blocks = get_num_block_defaults_for_target ( target) ;
761+ let estimation_mode = FeeRateEstimationMode :: Conservative ;
762+ let estimation_fut = bitcoind_rpc_client
763+ . get_fee_estimate_for_target ( num_blocks, estimation_mode) ;
764+ get_fee_rate_update ! ( estimation_fut)
765+ } ,
766+ ConfirmationTarget :: Lightning (
767+ LdkConfirmationTarget :: UrgentOnChainSweep ,
768+ ) => {
769+ let num_blocks = get_num_block_defaults_for_target ( target) ;
770+ let estimation_mode = FeeRateEstimationMode :: Conservative ;
771+ let estimation_fut = bitcoind_rpc_client
772+ . get_fee_estimate_for_target ( num_blocks, estimation_mode) ;
773+ get_fee_rate_update ! ( estimation_fut)
774+ } ,
775+ _ => {
776+ // Otherwise, we default to economical block-target estimate.
777+ let num_blocks = get_num_block_defaults_for_target ( target) ;
778+ let estimation_mode = FeeRateEstimationMode :: Economical ;
779+ let estimation_fut = bitcoind_rpc_client
780+ . get_fee_estimate_for_target ( num_blocks, estimation_mode) ;
781+ get_fee_rate_update ! ( estimation_fut)
782+ } ,
783+ } ;
784+
785+ // LDK 0.0.118 introduced changes to the `ConfirmationTarget` semantics that
786+ // require some post-estimation adjustments to the fee rates, which we do here.
787+ let adjusted_fee_rate = apply_post_estimation_adjustments ( target, fee_rate) ;
788+
789+ new_fee_rate_cache. insert ( target, adjusted_fee_rate) ;
790+
791+ log_trace ! (
792+ logger,
793+ "Fee rate estimation updated for {:?}: {} sats/kwu" ,
794+ target,
795+ adjusted_fee_rate. to_sat_per_kwu( ) ,
796+ ) ;
797+ }
798+
799+ if fee_estimator. set_fee_rate_cache ( new_fee_rate_cache) {
800+ // We only log if the values changed, as it might be very spammy otherwise.
801+ log_info ! (
802+ logger,
803+ "Fee rate cache update finished in {}ms." ,
804+ now. elapsed( ) . as_millis( )
805+ ) ;
806+ }
807+
808+ let unix_time_secs_opt =
809+ SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) . ok ( ) . map ( |d| d. as_secs ( ) ) ;
810+ {
811+ let mut locked_node_metrics = node_metrics. write ( ) . unwrap ( ) ;
812+ locked_node_metrics. latest_fee_rate_cache_update_timestamp = unix_time_secs_opt;
813+ write_node_metrics (
814+ & * locked_node_metrics,
815+ Arc :: clone ( & kv_store) ,
816+ Arc :: clone ( & logger) ,
817+ ) ?;
818+ }
819+
820+ Ok ( ( ) )
821+ } ,
708822 }
709823 }
710824
0 commit comments