@@ -14,18 +14,28 @@ use core::ops::Deref;
1414use core:: sync:: atomic:: { AtomicUsize , Ordering } ;
1515use core:: time:: Duration ;
1616
17- use bitcoin:: block:: Header ;
18- use bitcoin:: constants:: ChainHash ;
19- use bitcoin:: secp256k1:: { self , PublicKey , Secp256k1 } ;
20-
17+ use crate :: blinded_path:: message:: {
18+ BlindedMessagePath , MessageContext , MessageForwardNode , OffersContext ,
19+ } ;
20+ use crate :: blinded_path:: payment:: {
21+ BlindedPaymentPath , PaymentConstraints , PaymentContext , UnauthenticatedReceiveTlvs ,
22+ } ;
23+ use crate :: chain:: channelmonitor:: LATENCY_GRACE_PERIOD_BLOCKS ;
2124use crate :: chain:: BestBlock ;
25+ use crate :: ln:: channel_state:: ChannelDetails ;
26+ use crate :: ln:: channelmanager:: { CLTV_FAR_FAR_AWAY , MAX_SHORT_LIVED_RELATIVE_EXPIRY } ;
2227use crate :: ln:: inbound_payment;
28+ use crate :: offers:: nonce:: Nonce ;
2329use crate :: onion_message:: async_payments:: AsyncPaymentsMessage ;
2430use crate :: onion_message:: messenger:: { MessageRouter , MessageSendInstructions } ;
2531use crate :: onion_message:: offers:: OffersMessage ;
2632use crate :: routing:: router:: Router ;
2733use crate :: sign:: EntropySource ;
2834use crate :: sync:: { Mutex , RwLock } ;
35+ use bitcoin:: block:: Header ;
36+ use bitcoin:: constants:: ChainHash ;
37+ use bitcoin:: secp256k1:: { self , PublicKey , Secp256k1 } ;
38+ use lightning_invoice:: PaymentSecret ;
2939
3040#[ cfg( feature = "dnssec" ) ]
3141use crate :: onion_message:: dns_resolution:: DNSResolverMessage ;
@@ -150,3 +160,107 @@ where
150160 max_time ! ( self . highest_seen_timestamp) ;
151161 }
152162}
163+
164+ impl < ES : Deref , MR : Deref , R : Deref > OffersMessageFlow < ES , MR , R >
165+ where
166+ ES :: Target : EntropySource ,
167+ MR :: Target : MessageRouter ,
168+ R :: Target : Router ,
169+ {
170+ /// Creates a collection of blinded paths by delegating to [`MessageRouter`] based on
171+ /// the path's intended lifetime.
172+ ///
173+ /// Whether or not the path is compact depends on whether the path is short-lived or long-lived,
174+ /// respectively, based on the given `absolute_expiry` as seconds since the Unix epoch. See
175+ /// [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`].
176+ fn create_blinded_paths_using_absolute_expiry (
177+ & self , context : OffersContext , absolute_expiry : Option < Duration > ,
178+ peers : Vec < MessageForwardNode > ,
179+ ) -> Result < Vec < BlindedMessagePath > , ( ) > {
180+ let now = self . duration_since_epoch ( ) ;
181+ let max_short_lived_absolute_expiry = now. saturating_add ( MAX_SHORT_LIVED_RELATIVE_EXPIRY ) ;
182+
183+ if absolute_expiry. unwrap_or ( Duration :: MAX ) <= max_short_lived_absolute_expiry {
184+ self . create_compact_blinded_paths ( peers, context)
185+ } else {
186+ self . create_blinded_paths ( peers, MessageContext :: Offers ( context) )
187+ }
188+ }
189+
190+ /// Creates a collection of blinded paths by delegating to
191+ /// [`MessageRouter::create_blinded_paths`].
192+ ///
193+ /// Errors if the `MessageRouter` errors.
194+ fn create_blinded_paths (
195+ & self , peers : Vec < MessageForwardNode > , context : MessageContext ,
196+ ) -> Result < Vec < BlindedMessagePath > , ( ) > {
197+ let recipient = self . get_our_node_id ( ) ;
198+ let secp_ctx = & self . secp_ctx ;
199+
200+ let peers = peers. into_iter ( ) . map ( |node| node. node_id ) . collect ( ) ;
201+
202+ self . message_router
203+ . create_blinded_paths ( recipient, context, peers, secp_ctx)
204+ . and_then ( |paths| ( !paths. is_empty ( ) ) . then ( || paths) . ok_or ( ( ) ) )
205+ }
206+
207+ /// Creates a collection of blinded paths by delegating to
208+ /// [`MessageRouter::create_compact_blinded_paths`].
209+ ///
210+ /// Errors if the `MessageRouter` errors.
211+ fn create_compact_blinded_paths (
212+ & self , peers : Vec < MessageForwardNode > , context : OffersContext ,
213+ ) -> Result < Vec < BlindedMessagePath > , ( ) > {
214+ let recipient = self . get_our_node_id ( ) ;
215+ let secp_ctx = & self . secp_ctx ;
216+
217+ let peers = peers;
218+
219+ self . message_router
220+ . create_compact_blinded_paths (
221+ recipient,
222+ MessageContext :: Offers ( context) ,
223+ peers,
224+ secp_ctx,
225+ )
226+ . and_then ( |paths| ( !paths. is_empty ( ) ) . then ( || paths) . ok_or ( ( ) ) )
227+ }
228+
229+ /// Creates multi-hop blinded payment paths for the given `amount_msats` by delegating to
230+ /// [`Router::create_blinded_payment_paths`].
231+ fn create_blinded_payment_paths (
232+ & self , usable_channels : Vec < ChannelDetails > , amount_msats : Option < u64 > ,
233+ payment_secret : PaymentSecret , payment_context : PaymentContext ,
234+ relative_expiry_seconds : u32 ,
235+ ) -> Result < Vec < BlindedPaymentPath > , ( ) > {
236+ let expanded_key = & self . inbound_payment_key ;
237+ let entropy = & * self . entropy_source ;
238+ let secp_ctx = & self . secp_ctx ;
239+
240+ let first_hops = usable_channels;
241+ let payee_node_id = self . get_our_node_id ( ) ;
242+
243+ // Assume shorter than usual block times to avoid spuriously failing payments too early.
244+ const SECONDS_PER_BLOCK : u32 = 9 * 60 ;
245+ let relative_expiry_blocks = relative_expiry_seconds / SECONDS_PER_BLOCK ;
246+ let max_cltv_expiry = core:: cmp:: max ( relative_expiry_blocks, CLTV_FAR_FAR_AWAY )
247+ . saturating_add ( LATENCY_GRACE_PERIOD_BLOCKS )
248+ . saturating_add ( self . best_block . read ( ) . unwrap ( ) . height ) ;
249+
250+ let payee_tlvs = UnauthenticatedReceiveTlvs {
251+ payment_secret,
252+ payment_constraints : PaymentConstraints { max_cltv_expiry, htlc_minimum_msat : 1 } ,
253+ payment_context,
254+ } ;
255+ let nonce = Nonce :: from_entropy_source ( entropy) ;
256+ let payee_tlvs = payee_tlvs. authenticate ( nonce, expanded_key) ;
257+
258+ self . router . create_blinded_payment_paths (
259+ payee_node_id,
260+ first_hops,
261+ payee_tlvs,
262+ amount_msats,
263+ secp_ctx,
264+ )
265+ }
266+ }
0 commit comments