diff --git a/src/builder.rs b/src/builder.rs index 2a361396d..ef4295669 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -979,6 +979,7 @@ fn build_with_store_internal( let latest_fee_rate_cache_update_timestamp = Arc::new(RwLock::new(None)); let latest_rgs_snapshot_timestamp = Arc::new(RwLock::new(None)); let latest_node_announcement_broadcast_timestamp = Arc::new(RwLock::new(None)); + let latest_channel_monitor_archival_height = Arc::new(RwLock::new(None)); Ok(Node { runtime, @@ -1010,6 +1011,7 @@ fn build_with_store_internal( latest_fee_rate_cache_update_timestamp, latest_rgs_snapshot_timestamp, latest_node_announcement_broadcast_timestamp, + latest_channel_monitor_archival_height, }) } diff --git a/src/config.rs b/src/config.rs index aaa205f24..37e37bd63 100644 --- a/src/config.rs +++ b/src/config.rs @@ -30,6 +30,9 @@ pub(crate) const DEFAULT_ESPLORA_SERVER_URL: &str = "https://blockstream.info/ap // The timeout after which we abandon retrying failed payments. pub(crate) const LDK_PAYMENT_RETRY_TIMEOUT: Duration = Duration::from_secs(10); +// The interval (in block height) after which we retry archiving fully resolved channel monitors. +pub(crate) const RESOLVED_CHANNEL_MONITOR_ARCHIVAL_INTERVAL: u32 = 6; + // The time in-between peer reconnection attempts. pub(crate) const PEER_RECONNECTION_INTERVAL: Duration = Duration::from_secs(10); diff --git a/src/lib.rs b/src/lib.rs index 9c3c12342..2368e5a5a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -122,7 +122,8 @@ pub use builder::BuildError; pub use builder::NodeBuilder as Builder; use config::{ - NODE_ANN_BCAST_INTERVAL, PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL, + NODE_ANN_BCAST_INTERVAL, PEER_RECONNECTION_INTERVAL, + RESOLVED_CHANNEL_MONITOR_ARCHIVAL_INTERVAL, RGS_SYNC_INTERVAL, WALLET_SYNC_INTERVAL_MINIMUM_SECS, }; use connection::ConnectionManager; @@ -198,6 +199,7 @@ pub struct Node { latest_fee_rate_cache_update_timestamp: Arc>>, latest_rgs_snapshot_timestamp: Arc>>, latest_node_announcement_broadcast_timestamp: Arc>>, + latest_channel_monitor_archival_height: Arc>>, } impl Node { @@ -343,10 +345,13 @@ impl Node { let tx_sync = Arc::clone(&self.tx_sync); let sync_cman = Arc::clone(&self.channel_manager); + let archive_cman = Arc::clone(&self.channel_manager); let sync_cmon = Arc::clone(&self.chain_monitor); + let archive_cmon = Arc::clone(&self.chain_monitor); let sync_sweeper = Arc::clone(&self.output_sweeper); let sync_logger = Arc::clone(&self.logger); let sync_wallet_timestamp = Arc::clone(&self.latest_wallet_sync_timestamp); + let sync_monitor_archival_height = Arc::clone(&self.latest_channel_monitor_archival_height); let mut stop_sync = self.stop_sender.subscribe(); let wallet_sync_interval_secs = self.config.wallet_sync_interval_secs.max(WALLET_SYNC_INTERVAL_MINIMUM_SECS); @@ -376,6 +381,12 @@ impl Node { let unix_time_secs_opt = SystemTime::now().duration_since(UNIX_EPOCH).ok().map(|d| d.as_secs()); *sync_wallet_timestamp.write().unwrap() = unix_time_secs_opt; + + periodically_archive_fully_resolved_monitors( + Arc::clone(&archive_cman), + Arc::clone(&archive_cmon), + Arc::clone(&sync_monitor_archival_height) + ); } Err(e) => { log_error!(sync_logger, "Background sync of Lightning wallet failed: {}", e) @@ -1113,7 +1124,8 @@ impl Node { } } - /// Manually sync the LDK and BDK wallets with the current chain state. + /// Manually sync the LDK and BDK wallets with the current chain state and update the fee rate + /// cache. /// /// **Note:** The wallets are regularly synced in the background, which is configurable via /// [`Config::onchain_wallet_sync_interval_secs`] and [`Config::wallet_sync_interval_secs`]. @@ -1128,7 +1140,10 @@ impl Node { let wallet = Arc::clone(&self.wallet); let tx_sync = Arc::clone(&self.tx_sync); let sync_cman = Arc::clone(&self.channel_manager); + let archive_cman = Arc::clone(&self.channel_manager); let sync_cmon = Arc::clone(&self.chain_monitor); + let archive_cmon = Arc::clone(&self.chain_monitor); + let fee_estimator = Arc::clone(&self.fee_estimator); let sync_sweeper = Arc::clone(&self.output_sweeper); let sync_logger = Arc::clone(&self.logger); let confirmables = vec![ @@ -1136,6 +1151,11 @@ impl Node { &*sync_cmon as &(dyn Confirm + Sync + Send), &*sync_sweeper as &(dyn Confirm + Sync + Send), ]; + let sync_wallet_timestamp = Arc::clone(&self.latest_wallet_sync_timestamp); + let sync_fee_rate_update_timestamp = + Arc::clone(&self.latest_fee_rate_cache_update_timestamp); + let sync_onchain_wallet_timestamp = Arc::clone(&self.latest_onchain_wallet_sync_timestamp); + let sync_monitor_archival_height = Arc::clone(&self.latest_channel_monitor_archival_height); tokio::task::block_in_place(move || { tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap().block_on( @@ -1148,6 +1168,11 @@ impl Node { "Sync of on-chain wallet finished in {}ms.", now.elapsed().as_millis() ); + let unix_time_secs_opt = SystemTime::now() + .duration_since(UNIX_EPOCH) + .ok() + .map(|d| d.as_secs()); + *sync_onchain_wallet_timestamp.write().unwrap() = unix_time_secs_opt; }, Err(e) => { log_error!(sync_logger, "Sync of on-chain wallet failed: {}", e); @@ -1155,6 +1180,26 @@ impl Node { }, }; + let now = Instant::now(); + match fee_estimator.update_fee_estimates().await { + Ok(()) => { + log_info!( + sync_logger, + "Fee rate cache update finished in {}ms.", + now.elapsed().as_millis() + ); + let unix_time_secs_opt = SystemTime::now() + .duration_since(UNIX_EPOCH) + .ok() + .map(|d| d.as_secs()); + *sync_fee_rate_update_timestamp.write().unwrap() = unix_time_secs_opt; + }, + Err(e) => { + log_error!(sync_logger, "Fee rate cache update failed: {}", e,); + return Err(e); + }, + } + let now = Instant::now(); match tx_sync.sync(confirmables).await { Ok(()) => { @@ -1163,6 +1208,18 @@ impl Node { "Sync of Lightning wallet finished in {}ms.", now.elapsed().as_millis() ); + + let unix_time_secs_opt = SystemTime::now() + .duration_since(UNIX_EPOCH) + .ok() + .map(|d| d.as_secs()); + *sync_wallet_timestamp.write().unwrap() = unix_time_secs_opt; + + periodically_archive_fully_resolved_monitors( + archive_cman, + archive_cmon, + sync_monitor_archival_height, + ); Ok(()) }, Err(e) => { @@ -1486,3 +1543,19 @@ pub(crate) fn total_anchor_channels_reserve_sats( * anchor_channels_config.per_channel_reserve_sats }) } + +fn periodically_archive_fully_resolved_monitors( + channel_manager: Arc, chain_monitor: Arc, + latest_channel_monitor_archival_height: Arc>>, +) { + let mut latest_archival_height_lock = latest_channel_monitor_archival_height.write().unwrap(); + let cur_height = channel_manager.current_best_block().height; + let should_archive = latest_archival_height_lock + .as_ref() + .map_or(true, |h| cur_height >= h + RESOLVED_CHANNEL_MONITOR_ARCHIVAL_INTERVAL); + + if should_archive { + chain_monitor.archive_fully_resolved_channel_monitors(); + *latest_archival_height_lock = Some(cur_height); + } +}