8
8
mod bitcoind_rpc;
9
9
mod block_sync_init;
10
10
11
- use crate :: chain:: bitcoind_rpc:: { BitcoindRpcClient , BoundedHeaderCache , ChainListener } ;
11
+ use crate :: chain:: bitcoind_rpc:: {
12
+ BitcoindRpcClient , BoundedHeaderCache , ChainListener , FeeRateEstimationMode ,
13
+ } ;
12
14
use crate :: chain:: block_sync_init:: synchronize_listeners;
13
15
use crate :: config:: {
14
16
Config , EsploraSyncConfig , BDK_CLIENT_CONCURRENCY , BDK_CLIENT_STOP_GAP ,
@@ -18,13 +20,14 @@ use crate::config::{
18
20
} ;
19
21
use crate :: fee_estimator:: {
20
22
apply_post_estimation_adjustments, get_all_conf_targets, get_num_block_defaults_for_target,
21
- OnchainFeeEstimator ,
23
+ ConfirmationTarget , OnchainFeeEstimator ,
22
24
} ;
23
25
use crate :: io:: utils:: write_node_metrics;
24
26
use crate :: logger:: { log_bytes, log_error, log_info, log_trace, FilesystemLogger , Logger } ;
25
27
use crate :: types:: { Broadcaster , ChainMonitor , ChannelManager , DynStore , Sweeper , Wallet } ;
26
28
use crate :: { Error , NodeMetrics } ;
27
29
30
+ use lightning:: chain:: chaininterface:: ConfirmationTarget as LdkConfirmationTarget ;
28
31
use lightning:: chain:: { Confirm , Filter , Listen } ;
29
32
use lightning:: util:: ser:: Writeable ;
30
33
@@ -348,6 +351,13 @@ impl ChainSource {
348
351
chain_polling_interval
349
352
. set_missed_tick_behavior ( tokio:: time:: MissedTickBehavior :: Skip ) ;
350
353
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
+
351
361
// Start the polling loop.
352
362
loop {
353
363
tokio:: select! {
@@ -382,6 +392,9 @@ impl ChainSource {
382
392
} ) ;
383
393
}
384
394
}
395
+ _ = fee_rate_update_interval. tick( ) => {
396
+ let _ = self . update_fee_rate_estimates( ) . await ;
397
+ }
385
398
}
386
399
}
387
400
} ,
@@ -704,7 +717,108 @@ impl ChainSource {
704
717
705
718
Ok ( ( ) )
706
719
} ,
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
+ } ,
708
822
}
709
823
}
710
824
0 commit comments