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