@@ -3006,6 +3006,8 @@ pub struct ChannelManager<
30063006 funding_batch_states: Mutex<BTreeMap<Txid, Vec<(ChannelId, PublicKey, bool)>>>,
30073007
30083008 background_events_processed_since_startup: AtomicBool,
3009+ /// Set when a channel change may have made cached async receive static invoices stale.
3010+ async_receive_static_invoice_refresh_pending: AtomicBool,
30093011
30103012 event_persist_notifier: Notifier,
30113013 needs_persist_flag: AtomicBool,
@@ -3766,6 +3768,7 @@ impl<
37663768 pending_background_events: Mutex::new(Vec::new()),
37673769 total_consistency_lock: RwLock::new(()),
37683770 background_events_processed_since_startup: AtomicBool::new(false),
3771+ async_receive_static_invoice_refresh_pending: AtomicBool::new(false),
37693772 event_persist_notifier: Notifier::new(),
37703773 needs_persist_flag: AtomicBool::new(false),
37713774 funding_batch_states: Mutex::new(BTreeMap::new()),
@@ -4564,6 +4567,8 @@ impl<
45644567 ));
45654568 }
45664569 }
4570+ self.mark_async_receive_static_invoice_refresh_pending();
4571+
45674572 for (err, counterparty_node_id) in shutdown_results.drain(..) {
45684573 let _ = self.handle_error(err, counterparty_node_id);
45694574 }
@@ -4693,6 +4698,7 @@ impl<
46934698 log_error!(logger, "Closing channel: {}", err_internal.err.err);
46944699
46954700 self.finish_close_channel(shutdown_res);
4701+ self.process_pending_async_receive_static_invoice_refresh();
46964702 if let Some((update, node_id_1, node_id_2)) = update_option {
46974703 let mut pending_broadcast_messages =
46984704 self.pending_broadcast_messages.lock().unwrap();
@@ -5916,6 +5922,19 @@ impl<
59165922 );
59175923 }
59185924
5925+ fn mark_async_receive_static_invoice_refresh_pending(&self) {
5926+ self.async_receive_static_invoice_refresh_pending.store(true, Ordering::Release);
5927+ }
5928+
5929+ fn process_pending_async_receive_static_invoice_refresh(&self) {
5930+ // Channel state transitions often happen while a peer's channel lock is held. Defer the
5931+ // actual refresh until after those locks are released, because rebuilding static invoices
5932+ // needs a fresh snapshot of usable channels.
5933+ if self.async_receive_static_invoice_refresh_pending.swap(false, Ordering::AcqRel) {
5934+ self.force_refresh_async_receive_static_invoices();
5935+ }
5936+ }
5937+
59195938 #[cfg(test)]
59205939 pub(crate) fn test_check_refresh_async_receive_offers(&self) {
59215940 self.check_refresh_async_receive_offer_cache(false);
@@ -9141,6 +9160,7 @@ impl<
91419160 .remove_stale_payments(duration_since_epoch, &self.pending_events);
91429161
91439162 self.check_refresh_async_receive_offer_cache(true);
9163+ self.process_pending_async_receive_static_invoice_refresh();
91449164
91459165 if self.check_free_holding_cells() {
91469166 // While we try to ensure we clear holding cells immediately, its possible we miss
@@ -13761,6 +13781,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1376113781 },
1376213782 None,
1376313783 ));
13784+ self.mark_async_receive_static_invoice_refresh_pending();
1376413785 splice_promotion.discarded_funding.into_iter().for_each(|funding_info| {
1376513786 let event = Event::DiscardFunding {
1376613787 channel_id: chan.context.channel_id(),
@@ -16464,6 +16485,7 @@ impl<
1646416485 funding_txo: Some(funding_txo.into_bitcoin_outpoint()),
1646516486 channel_type: funded_channel.funding.get_channel_type().clone(),
1646616487 }, None));
16488+ self.mark_async_receive_static_invoice_refresh_pending();
1646716489 discarded_funding.into_iter().for_each(|funding_info| {
1646816490 let event = Event::DiscardFunding {
1646916491 channel_id: funded_channel.context.channel_id(),
@@ -16884,16 +16906,19 @@ impl<
1688416906
1688516907 #[rustfmt::skip]
1688616908 fn handle_splice_locked(&self, counterparty_node_id: PublicKey, msg: &msgs::SpliceLocked) {
16887- let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || {
16888- let res = self.internal_splice_locked(&counterparty_node_id, msg);
16889- let persist = match &res {
16890- Err(e) if e.closes_channel() => NotifyOption::DoPersist,
16891- Err(_) => NotifyOption::SkipPersistHandleEvents,
16892- Ok(()) => NotifyOption::DoPersist,
16893- };
16894- let _ = self.handle_error(res, counterparty_node_id);
16895- persist
16896- });
16909+ {
16910+ let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || {
16911+ let res = self.internal_splice_locked(&counterparty_node_id, msg);
16912+ let persist = match &res {
16913+ Err(e) if e.closes_channel() => NotifyOption::DoPersist,
16914+ Err(_) => NotifyOption::SkipPersistHandleEvents,
16915+ Ok(()) => NotifyOption::DoPersist,
16916+ };
16917+ let _ = self.handle_error(res, counterparty_node_id);
16918+ persist
16919+ });
16920+ }
16921+ self.process_pending_async_receive_static_invoice_refresh();
1689716922 }
1689816923
1689916924 fn handle_shutdown(&self, counterparty_node_id: PublicKey, msg: &msgs::Shutdown) {
@@ -17028,14 +17053,22 @@ impl<
1702817053 }
1702917054
1703017055 fn handle_channel_update(&self, counterparty_node_id: PublicKey, msg: &msgs::ChannelUpdate) {
17031- PersistenceNotifierGuard::optionally_notify(self, || {
17032- let res = self.internal_channel_update(&counterparty_node_id, msg);
17033- if let Ok(persist) = self.handle_error(res, counterparty_node_id) {
17034- persist
17035- } else {
17036- NotifyOption::DoPersist
17037- }
17038- });
17056+ {
17057+ PersistenceNotifierGuard::optionally_notify(self, || {
17058+ let res = self.internal_channel_update(&counterparty_node_id, msg);
17059+ if let Ok(persist) = self.handle_error(res, counterparty_node_id) {
17060+ if persist == NotifyOption::DoPersist {
17061+ // Static invoices encode the counterparty's forwarding parameters. Refresh
17062+ // them when an update changes those parameters for a local channel.
17063+ self.mark_async_receive_static_invoice_refresh_pending();
17064+ }
17065+ persist
17066+ } else {
17067+ NotifyOption::DoPersist
17068+ }
17069+ });
17070+ }
17071+ self.process_pending_async_receive_static_invoice_refresh();
1703917072 }
1704017073
1704117074 fn handle_channel_reestablish(
@@ -20524,6 +20557,7 @@ impl<
2052420557 pending_background_events: Mutex::new(pending_background_events),
2052520558 total_consistency_lock: RwLock::new(()),
2052620559 background_events_processed_since_startup: AtomicBool::new(false),
20560+ async_receive_static_invoice_refresh_pending: AtomicBool::new(false),
2052720561
2052820562 event_persist_notifier: Notifier::new(),
2052920563 needs_persist_flag: AtomicBool::new(false),
0 commit comments