@@ -14,19 +14,32 @@ 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 } ;
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 ;
2024
2125#[ allow( unused_imports) ]
2226use crate :: prelude:: * ;
2327
2428use crate :: chain:: BestBlock ;
29+ use crate :: ln:: channel_state:: ChannelDetails ;
30+ use crate :: ln:: channelmanager:: { CLTV_FAR_FAR_AWAY , MAX_SHORT_LIVED_RELATIVE_EXPIRY } ;
2531use crate :: ln:: inbound_payment;
32+ use crate :: offers:: nonce:: Nonce ;
2633use crate :: onion_message:: async_payments:: AsyncPaymentsMessage ;
2734use crate :: onion_message:: messenger:: { MessageRouter , MessageSendInstructions } ;
2835use crate :: onion_message:: offers:: OffersMessage ;
36+ use crate :: routing:: router:: Router ;
37+ use crate :: sign:: EntropySource ;
2938use crate :: sync:: { Mutex , RwLock } ;
39+ use bitcoin:: block:: Header ;
40+ use bitcoin:: constants:: ChainHash ;
41+ use bitcoin:: secp256k1:: { self , PublicKey , Secp256k1 } ;
42+ use lightning_invoice:: PaymentSecret ;
3043
3144#[ cfg( feature = "dnssec" ) ]
3245use crate :: onion_message:: dns_resolution:: { DNSResolverMessage , OMNameResolver } ;
@@ -142,3 +155,129 @@ where
142155 }
143156 }
144157}
158+
159+ impl < MR : Deref > OffersMessageFlow < MR >
160+ where
161+ MR :: Target : MessageRouter ,
162+ {
163+ /// Creates a collection of blinded paths by delegating to [`MessageRouter`] based on
164+ /// the path's intended lifetime.
165+ ///
166+ /// Whether or not the path is compact depends on whether the path is short-lived or long-lived,
167+ /// respectively, based on the given `absolute_expiry` as seconds since the Unix epoch. See
168+ /// [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`].
169+ fn create_blinded_paths_using_absolute_expiry (
170+ & self , context : OffersContext , absolute_expiry : Option < Duration > ,
171+ peers : Vec < MessageForwardNode > ,
172+ ) -> Result < Vec < BlindedMessagePath > , ( ) > {
173+ let now = self . duration_since_epoch ( ) ;
174+ let max_short_lived_absolute_expiry = now. saturating_add ( MAX_SHORT_LIVED_RELATIVE_EXPIRY ) ;
175+
176+ if absolute_expiry. unwrap_or ( Duration :: MAX ) <= max_short_lived_absolute_expiry {
177+ self . create_compact_blinded_paths ( peers, context)
178+ } else {
179+ self . create_blinded_paths ( peers, MessageContext :: Offers ( context) )
180+ }
181+ }
182+
183+ /// Creates a collection of blinded paths by delegating to
184+ /// [`MessageRouter::create_blinded_paths`].
185+ ///
186+ /// Errors if the `MessageRouter` errors.
187+ fn create_blinded_paths (
188+ & self , peers : Vec < MessageForwardNode > , context : MessageContext ,
189+ ) -> Result < Vec < BlindedMessagePath > , ( ) > {
190+ let recipient = self . get_our_node_id ( ) ;
191+ let secp_ctx = & self . secp_ctx ;
192+
193+ let peers = peers. into_iter ( ) . map ( |node| node. node_id ) . collect ( ) ;
194+
195+ self . message_router
196+ . create_blinded_paths ( recipient, context, peers, secp_ctx)
197+ . and_then ( |paths| ( !paths. is_empty ( ) ) . then ( || paths) . ok_or ( ( ) ) )
198+ }
199+
200+ /// Creates a collection of blinded paths by delegating to
201+ /// [`MessageRouter::create_compact_blinded_paths`].
202+ ///
203+ /// Errors if the `MessageRouter` errors.
204+ fn create_compact_blinded_paths (
205+ & self , peers : Vec < MessageForwardNode > , context : OffersContext ,
206+ ) -> Result < Vec < BlindedMessagePath > , ( ) > {
207+ let recipient = self . get_our_node_id ( ) ;
208+ let secp_ctx = & self . secp_ctx ;
209+
210+ self . message_router
211+ . create_compact_blinded_paths (
212+ recipient,
213+ MessageContext :: Offers ( context) ,
214+ peers,
215+ secp_ctx,
216+ )
217+ . and_then ( |paths| ( !paths. is_empty ( ) ) . then ( || paths) . ok_or ( ( ) ) )
218+ }
219+
220+ /// Creates multi-hop blinded payment paths for the given `amount_msats` by delegating to
221+ /// [`Router::create_blinded_payment_paths`].
222+ fn create_blinded_payment_paths < ES : Deref , R : Deref > (
223+ & self , router : & R , entropy_source : ES , usable_channels : Vec < ChannelDetails > ,
224+ amount_msats : Option < u64 > , payment_secret : PaymentSecret , payment_context : PaymentContext ,
225+ relative_expiry_seconds : u32 ,
226+ ) -> Result < Vec < BlindedPaymentPath > , ( ) >
227+ where
228+ ES :: Target : EntropySource ,
229+ R :: Target : Router ,
230+ {
231+ let expanded_key = & self . inbound_payment_key ;
232+ let entropy = & * entropy_source;
233+ let secp_ctx = & self . secp_ctx ;
234+
235+ let payee_node_id = self . get_our_node_id ( ) ;
236+
237+ // Assume shorter than usual block times to avoid spuriously failing payments too early.
238+ const SECONDS_PER_BLOCK : u32 = 9 * 60 ;
239+ let relative_expiry_blocks = relative_expiry_seconds / SECONDS_PER_BLOCK ;
240+ let max_cltv_expiry = core:: cmp:: max ( relative_expiry_blocks, CLTV_FAR_FAR_AWAY )
241+ . saturating_add ( LATENCY_GRACE_PERIOD_BLOCKS )
242+ . saturating_add ( self . best_block . read ( ) . unwrap ( ) . height ) ;
243+
244+ let payee_tlvs = UnauthenticatedReceiveTlvs {
245+ payment_secret,
246+ payment_constraints : PaymentConstraints { max_cltv_expiry, htlc_minimum_msat : 1 } ,
247+ payment_context,
248+ } ;
249+ let nonce = Nonce :: from_entropy_source ( entropy) ;
250+ let payee_tlvs = payee_tlvs. authenticate ( nonce, expanded_key) ;
251+
252+ router. create_blinded_payment_paths (
253+ payee_node_id,
254+ usable_channels,
255+ payee_tlvs,
256+ amount_msats,
257+ secp_ctx,
258+ )
259+ }
260+
261+ #[ cfg( all( test, async_payments) ) ]
262+ /// Creates multi-hop blinded payment paths for the given `amount_msats` by delegating to
263+ /// [`Router::create_blinded_payment_paths`].
264+ pub ( crate ) fn test_create_blinded_payment_paths < ES : Deref , R : Deref > (
265+ & self , router : & R , entropy_source : ES , usable_channels : Vec < ChannelDetails > ,
266+ amount_msats : Option < u64 > , payment_secret : PaymentSecret , payment_context : PaymentContext ,
267+ relative_expiry_seconds : u32 ,
268+ ) -> Result < Vec < BlindedPaymentPath > , ( ) >
269+ where
270+ ES :: Target : EntropySource ,
271+ R :: Target : Router ,
272+ {
273+ self . create_blinded_payment_paths (
274+ router,
275+ entropy_source,
276+ usable_channels,
277+ amount_msats,
278+ payment_secret,
279+ payment_context,
280+ relative_expiry_seconds,
281+ )
282+ }
283+ }
0 commit comments