55// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
66// accordance with one or both of these licenses.
77
8+ use std:: collections:: HashMap ;
89use std:: net:: SocketAddr ;
910use std:: sync:: { Arc , Mutex , RwLock } ;
10- use std:: time:: Duration ;
11+ use std:: time:: { Duration , Instant , SystemTime , UNIX_EPOCH } ;
1112
1213use bip157:: { BlockHash , Builder , Client , Event , Info , Requester , TrustedPeer , Warning } ;
1314use bitcoin:: { Script , Transaction , Txid } ;
@@ -16,7 +17,10 @@ use lightning::util::ser::Writeable;
1617use tokio:: sync:: mpsc;
1718
1819use crate :: config:: { CbfSyncConfig , Config } ;
19- use crate :: fee_estimator:: OnchainFeeEstimator ;
20+ use crate :: fee_estimator:: {
21+ apply_post_estimation_adjustments, get_all_conf_targets, OnchainFeeEstimator ,
22+ } ;
23+ use crate :: io:: utils:: write_node_metrics;
2024use crate :: logger:: { log_bytes, log_debug, log_error, log_info, log_trace, LdkLogger , Logger } ;
2125use crate :: runtime:: Runtime ;
2226use crate :: types:: { ChainMonitor , ChannelManager , DynStore , Sweeper , Wallet } ;
@@ -226,8 +230,69 @@ impl CbfChainSource {
226230 }
227231
228232 /// Estimate fee rates from recent block data.
233+ // NOTE: This is a single-block fee estimation. A multi-block lookback with
234+ // per-target percentile selection is added later.
229235 pub ( crate ) async fn update_fee_rate_estimates ( & self ) -> Result < ( ) , Error > {
230- log_error ! ( self . logger, "Fee rate estimation via CBF is not yet implemented." ) ;
236+ let requester = self . requester ( ) ?;
237+
238+ let tip_hash = match * self . latest_tip . lock ( ) . unwrap ( ) {
239+ Some ( hash) => hash,
240+ None => {
241+ log_debug ! ( self . logger, "No tip available yet for fee rate estimation, skipping." ) ;
242+ return Ok ( ( ) ) ;
243+ } ,
244+ } ;
245+
246+ let now = Instant :: now ( ) ;
247+
248+ let base_fee_rate = tokio:: time:: timeout (
249+ Duration :: from_secs (
250+ self . sync_config . timeouts_config . fee_rate_cache_update_timeout_secs ,
251+ ) ,
252+ requester. average_fee_rate ( tip_hash) ,
253+ )
254+ . await
255+ . map_err ( |e| {
256+ log_error ! ( self . logger, "Updating fee rate estimates timed out: {}" , e) ;
257+ Error :: FeerateEstimationUpdateTimeout
258+ } ) ?
259+ . map_err ( |e| {
260+ log_error ! ( self . logger, "Failed to retrieve fee rate estimate: {:?}" , e) ;
261+ Error :: FeerateEstimationUpdateFailed
262+ } ) ?;
263+
264+ let confirmation_targets = get_all_conf_targets ( ) ;
265+ let mut new_fee_rate_cache = HashMap :: with_capacity ( confirmation_targets. len ( ) ) ;
266+
267+ for target in confirmation_targets {
268+ let adjusted_fee_rate = apply_post_estimation_adjustments ( target, base_fee_rate) ;
269+ new_fee_rate_cache. insert ( target, adjusted_fee_rate) ;
270+
271+ log_trace ! (
272+ self . logger,
273+ "Fee rate estimation updated for {:?}: {} sats/kwu" ,
274+ target,
275+ adjusted_fee_rate. to_sat_per_kwu( ) ,
276+ ) ;
277+ }
278+
279+ self . fee_estimator . set_fee_rate_cache ( new_fee_rate_cache) ;
280+
281+ log_debug ! (
282+ self . logger,
283+ "Fee rate cache update finished in {}ms." ,
284+ now. elapsed( ) . as_millis( )
285+ ) ;
286+
287+ update_node_metrics_timestamp (
288+ & self . node_metrics ,
289+ & * self . kv_store ,
290+ & * self . logger ,
291+ |m, t| {
292+ m. latest_fee_rate_cache_update_timestamp = t;
293+ } ,
294+ ) ?;
295+
231296 Ok ( ( ) )
232297 }
233298
@@ -293,3 +358,15 @@ impl CbfChainSource {
293358 log_error ! ( self . logger, "CBF register_output is not yet implemented." ) ;
294359 }
295360}
361+
362+ /// Record the current timestamp in a `NodeMetrics` field and persist the metrics.
363+ fn update_node_metrics_timestamp (
364+ node_metrics : & RwLock < NodeMetrics > , kv_store : & DynStore , logger : & Logger ,
365+ setter : impl FnOnce ( & mut NodeMetrics , Option < u64 > ) ,
366+ ) -> Result < ( ) , Error > {
367+ let unix_time_secs_opt = SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) . ok ( ) . map ( |d| d. as_secs ( ) ) ;
368+ let mut locked = node_metrics. write ( ) . unwrap ( ) ;
369+ setter ( & mut locked, unix_time_secs_opt) ;
370+ write_node_metrics ( & * locked, kv_store, logger) ?;
371+ Ok ( ( ) )
372+ }
0 commit comments