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