@@ -1515,6 +1515,19 @@ struct AsyncReceiveOffer {
15151515 offer_paths_request_attempts: u8,
15161516}
15171517
1518+ impl AsyncReceiveOffer {
1519+ /// Removes the offer from our cache if it's expired.
1520+ #[cfg(async_payments)]
1521+ fn check_expire_offer(&mut self, duration_since_epoch: Duration) {
1522+ if let Some(ref mut offer) = self.offer {
1523+ if offer.is_expired_no_std(duration_since_epoch) {
1524+ self.offer.take();
1525+ self.offer_paths_request_attempts = 0;
1526+ }
1527+ }
1528+ }
1529+ }
1530+
15181531impl_writeable_tlv_based!(AsyncReceiveOffer, {
15191532 (0, offer, option),
15201533 (2, offer_paths_request_attempts, (static_value, 0)),
@@ -2429,6 +2442,8 @@ where
24292442//
24302443// `pending_async_payments_messages`
24312444//
2445+ // `async_receive_offer_cache`
2446+ //
24322447// `total_consistency_lock`
24332448// |
24342449// |__`forward_htlcs`
@@ -4849,6 +4864,60 @@ where
48494864 )
48504865 }
48514866
4867+ #[cfg(async_payments)]
4868+ fn check_refresh_async_receive_offer(&self) {
4869+ if self.default_configuration.paths_to_static_invoice_server.is_empty() { return }
4870+
4871+ let expanded_key = &self.inbound_payment_key;
4872+ let entropy = &*self.entropy_source;
4873+ let duration_since_epoch = self.duration_since_epoch();
4874+
4875+ {
4876+ let mut offer_cache = self.async_receive_offer_cache.lock().unwrap();
4877+ offer_cache.check_expire_offer(duration_since_epoch);
4878+
4879+ if let Some(ref offer) = offer_cache.offer {
4880+ // If we have more than three hours before our offer expires, don't bother requesting new
4881+ // paths.
4882+ const PATHS_EXPIRY_BUFFER: Duration = Duration::from_secs(60 * 60 * 3);
4883+ let offer_expiry = offer.absolute_expiry().unwrap_or(Duration::MAX);
4884+ if offer_expiry > duration_since_epoch.saturating_add(PATHS_EXPIRY_BUFFER) {
4885+ return
4886+ }
4887+ }
4888+
4889+ const MAX_ATTEMPTS: u8 = 3;
4890+ if offer_cache.offer_paths_request_attempts > MAX_ATTEMPTS { return }
4891+ }
4892+
4893+ let reply_paths = {
4894+ // We expect the static invoice server to respond quickly to our request for offer paths, but
4895+ // add some buffer for no-std users that rely on block timestamps.
4896+ const REPLY_PATH_RELATIVE_EXPIRY: Duration = Duration::from_secs(2 * 60 * 60);
4897+ let nonce = Nonce::from_entropy_source(entropy);
4898+ let context = MessageContext::AsyncPayments(AsyncPaymentsContext::OfferPaths {
4899+ nonce,
4900+ hmac: signer::hmac_for_offer_paths_context(nonce, expanded_key),
4901+ path_absolute_expiry: duration_since_epoch.saturating_add(REPLY_PATH_RELATIVE_EXPIRY),
4902+ });
4903+ match self.create_blinded_paths(context) {
4904+ Ok(paths) => paths,
4905+ Err(()) => {
4906+ log_error!(self.logger, "Failed to create blinded paths when requesting async receive offer paths");
4907+ return
4908+ }
4909+ }
4910+ };
4911+
4912+
4913+ self.async_receive_offer_cache.lock().unwrap().offer_paths_request_attempts += 1;
4914+ let message = AsyncPaymentsMessage::OfferPathsRequest(OfferPathsRequest {});
4915+ queue_onion_message_with_reply_paths(
4916+ message, &self.default_configuration.paths_to_static_invoice_server[..], reply_paths,
4917+ &mut self.pending_async_payments_messages.lock().unwrap()
4918+ );
4919+ }
4920+
48524921 #[cfg(async_payments)]
48534922 fn initiate_async_payment(
48544923 &self, invoice: &StaticInvoice, payment_id: PaymentId
@@ -6798,6 +6867,9 @@ where
67986867 duration_since_epoch, &self.pending_events
67996868 );
68006869
6870+ #[cfg(async_payments)]
6871+ self.check_refresh_async_receive_offer();
6872+
68016873 // Technically we don't need to do this here, but if we have holding cell entries in a
68026874 // channel that need freeing, it's better to do that here and block a background task
68036875 // than block the message queueing pipeline.
@@ -12082,6 +12154,9 @@ where
1208212154 return NotifyOption::SkipPersistHandleEvents;
1208312155 //TODO: Also re-broadcast announcement_signatures
1208412156 });
12157+
12158+ #[cfg(async_payments)]
12159+ self.check_refresh_async_receive_offer();
1208512160 res
1208612161 }
1208712162
0 commit comments