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
@@ -347,6 +350,13 @@ impl ChainSource {
347350 chain_polling_interval
348351 . set_missed_tick_behavior ( tokio:: time:: MissedTickBehavior :: Skip ) ;
349352
353+ let mut fee_rate_update_interval =
354+ tokio:: time:: interval ( Duration :: from_secs ( CHAIN_POLLING_INTERVAL_SECS ) ) ;
355+ // When starting up, we just blocked on updating, so skip the first tick.
356+ fee_rate_update_interval. reset ( ) ;
357+ fee_rate_update_interval
358+ . set_missed_tick_behavior ( tokio:: time:: MissedTickBehavior :: Skip ) ;
359+
350360 // Start the polling loop.
351361 loop {
352362 tokio:: select! {
@@ -381,6 +391,9 @@ impl ChainSource {
381391 } ) ;
382392 }
383393 }
394+ _ = fee_rate_update_interval. tick( ) => {
395+ let _ = self . update_fee_rate_estimates( ) . await ;
396+ }
384397 }
385398 }
386399 } ,
@@ -703,7 +716,108 @@ impl ChainSource {
703716
704717 Ok ( ( ) )
705718 } ,
706- Self :: BitcoindRpc { .. } => todo ! ( ) ,
719+ Self :: BitcoindRpc {
720+ bitcoind_rpc_client,
721+ fee_estimator,
722+ kv_store,
723+ logger,
724+ node_metrics,
725+ ..
726+ } => {
727+ macro_rules! get_fee_rate_update {
728+ ( $estimation_fut: expr) => { {
729+ tokio:: time:: timeout(
730+ Duration :: from_secs( FEE_RATE_CACHE_UPDATE_TIMEOUT_SECS ) ,
731+ $estimation_fut,
732+ )
733+ . await
734+ . map_err( |e| {
735+ log_error!( logger, "Updating fee rate estimates timed out: {}" , e) ;
736+ Error :: FeerateEstimationUpdateTimeout
737+ } ) ?
738+ . map_err( |e| {
739+ log_error!( logger, "Failed to retrieve fee rate estimates: {}" , e) ;
740+ Error :: FeerateEstimationUpdateFailed
741+ } ) ?
742+ } } ;
743+ }
744+ let confirmation_targets = get_all_conf_targets ( ) ;
745+
746+ let mut new_fee_rate_cache = HashMap :: with_capacity ( 10 ) ;
747+ let now = Instant :: now ( ) ;
748+ for target in confirmation_targets {
749+ let fee_rate = match target {
750+ ConfirmationTarget :: Lightning (
751+ LdkConfirmationTarget :: MinAllowedAnchorChannelRemoteFee ,
752+ ) => {
753+ let estimation_fut = bitcoind_rpc_client. get_mempool_minimum_fee_rate ( ) ;
754+ get_fee_rate_update ! ( estimation_fut)
755+ } ,
756+ ConfirmationTarget :: Lightning (
757+ LdkConfirmationTarget :: MaximumFeeEstimate ,
758+ ) => {
759+ let num_blocks = get_num_block_defaults_for_target ( target) ;
760+ let estimation_mode = FeeRateEstimationMode :: Conservative ;
761+ let estimation_fut = bitcoind_rpc_client
762+ . get_fee_estimate_for_target ( num_blocks, estimation_mode) ;
763+ get_fee_rate_update ! ( estimation_fut)
764+ } ,
765+ ConfirmationTarget :: Lightning (
766+ LdkConfirmationTarget :: UrgentOnChainSweep ,
767+ ) => {
768+ let num_blocks = get_num_block_defaults_for_target ( target) ;
769+ let estimation_mode = FeeRateEstimationMode :: Conservative ;
770+ let estimation_fut = bitcoind_rpc_client
771+ . get_fee_estimate_for_target ( num_blocks, estimation_mode) ;
772+ get_fee_rate_update ! ( estimation_fut)
773+ } ,
774+ _ => {
775+ // Otherwise, we default to economical block-target estimate.
776+ let num_blocks = get_num_block_defaults_for_target ( target) ;
777+ let estimation_mode = FeeRateEstimationMode :: Economical ;
778+ let estimation_fut = bitcoind_rpc_client
779+ . get_fee_estimate_for_target ( num_blocks, estimation_mode) ;
780+ get_fee_rate_update ! ( estimation_fut)
781+ } ,
782+ } ;
783+
784+ // LDK 0.0.118 introduced changes to the `ConfirmationTarget` semantics that
785+ // require some post-estimation adjustments to the fee rates, which we do here.
786+ let adjusted_fee_rate = apply_post_estimation_adjustments ( target, fee_rate) ;
787+
788+ new_fee_rate_cache. insert ( target, adjusted_fee_rate) ;
789+
790+ log_trace ! (
791+ logger,
792+ "Fee rate estimation updated for {:?}: {} sats/kwu" ,
793+ target,
794+ adjusted_fee_rate. to_sat_per_kwu( ) ,
795+ ) ;
796+ }
797+
798+ if fee_estimator. set_fee_rate_cache ( new_fee_rate_cache) {
799+ // We only log if the values changed, as it might be very spammy otherwise.
800+ log_info ! (
801+ logger,
802+ "Fee rate cache update finished in {}ms." ,
803+ now. elapsed( ) . as_millis( )
804+ ) ;
805+ }
806+
807+ let unix_time_secs_opt =
808+ SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) . ok ( ) . map ( |d| d. as_secs ( ) ) ;
809+ {
810+ let mut locked_node_metrics = node_metrics. write ( ) . unwrap ( ) ;
811+ locked_node_metrics. latest_fee_rate_cache_update_timestamp = unix_time_secs_opt;
812+ write_node_metrics (
813+ & * locked_node_metrics,
814+ Arc :: clone ( & kv_store) ,
815+ Arc :: clone ( & logger) ,
816+ ) ?;
817+ }
818+
819+ Ok ( ( ) )
820+ } ,
707821 }
708822 }
709823
0 commit comments