@@ -14,18 +14,28 @@ 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 } ;
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 ;
21
24
use crate :: chain:: BestBlock ;
25
+ use crate :: ln:: channel_state:: ChannelDetails ;
26
+ use crate :: ln:: channelmanager:: { CLTV_FAR_FAR_AWAY , MAX_SHORT_LIVED_RELATIVE_EXPIRY } ;
22
27
use crate :: ln:: inbound_payment;
28
+ use crate :: offers:: nonce:: Nonce ;
23
29
use crate :: onion_message:: async_payments:: AsyncPaymentsMessage ;
24
30
use crate :: onion_message:: messenger:: { MessageRouter , MessageSendInstructions } ;
25
31
use crate :: onion_message:: offers:: OffersMessage ;
26
32
use crate :: routing:: router:: Router ;
27
33
use crate :: sign:: EntropySource ;
28
34
use 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 ;
29
39
30
40
#[ cfg( feature = "dnssec" ) ]
31
41
use crate :: onion_message:: dns_resolution:: DNSResolverMessage ;
@@ -150,3 +160,107 @@ where
150
160
max_time ! ( self . highest_seen_timestamp) ;
151
161
}
152
162
}
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