@@ -16,6 +16,18 @@ use crate::util::ser::{Readable, Writeable, Writer};
1616
1717use core:: convert:: TryFrom ;
1818
19+ #[ derive( Debug ) ]
20+ /// An intermediate node, its outbound channel, and relay parameters.
21+ pub struct ForwardNode {
22+ /// The TLVs for this node's [`BlindedHop`], where the fee parameters contained within are also
23+ /// used for [`BlindedPayInfo`] construction.
24+ pub tlvs : ForwardTlvs ,
25+ /// This node's pubkey.
26+ pub node_id : PublicKey ,
27+ /// The maximum value, in msat, that may be accepted by this node.
28+ pub htlc_maximum_msat : u64 ,
29+ }
30+
1931/// Data to construct a [`BlindedHop`] for forwarding a payment.
2032#[ derive( Debug ) ]
2133pub struct ForwardTlvs {
@@ -150,12 +162,12 @@ impl Readable for BlindedPaymentTlvs {
150162
151163/// Construct blinded payment hops for the given `intermediate_nodes` and payee info.
152164pub ( super ) fn blinded_hops < T : secp256k1:: Signing + secp256k1:: Verification > (
153- secp_ctx : & Secp256k1 < T > , intermediate_nodes : & [ ( PublicKey , ForwardTlvs , u64 ) ] ,
165+ secp_ctx : & Secp256k1 < T > , intermediate_nodes : & [ ForwardNode ] ,
154166 payee_node_id : PublicKey , payee_tlvs : ReceiveTlvs , session_priv : & SecretKey
155167) -> Result < Vec < BlindedHop > , secp256k1:: Error > {
156- let pks = intermediate_nodes. iter ( ) . map ( |( pk , _ , _ ) | pk )
168+ let pks = intermediate_nodes. iter ( ) . map ( |node| & node . node_id )
157169 . chain ( core:: iter:: once ( & payee_node_id) ) ;
158- let tlvs = intermediate_nodes. iter ( ) . map ( |( _ , tlvs , _ ) | BlindedPaymentTlvsRef :: Forward ( tlvs) )
170+ let tlvs = intermediate_nodes. iter ( ) . map ( |node | BlindedPaymentTlvsRef :: Forward ( & node . tlvs ) )
159171 . chain ( core:: iter:: once ( BlindedPaymentTlvsRef :: Receive ( & payee_tlvs) ) ) ;
160172 utils:: construct_blinded_hops ( secp_ctx, pks, tlvs, session_priv)
161173}
@@ -182,13 +194,12 @@ fn amt_to_forward_msat(inbound_amt_msat: u64, payment_relay: &PaymentRelay) -> O
182194}
183195
184196pub ( super ) fn compute_payinfo (
185- intermediate_nodes : & [ ( PublicKey , ForwardTlvs , u64 ) ] , payee_tlvs : & ReceiveTlvs ,
186- payee_htlc_maximum_msat : u64
197+ intermediate_nodes : & [ ForwardNode ] , payee_tlvs : & ReceiveTlvs , payee_htlc_maximum_msat : u64
187198) -> Result < BlindedPayInfo , ( ) > {
188199 let mut curr_base_fee: u64 = 0 ;
189200 let mut curr_prop_mil: u64 = 0 ;
190201 let mut cltv_expiry_delta: u16 = 0 ;
191- for ( _ , tlvs, _ ) in intermediate_nodes. iter ( ) . rev ( ) {
202+ for tlvs in intermediate_nodes. iter ( ) . rev ( ) . map ( |n| & n . tlvs ) {
192203 // In the future, we'll want to take the intersection of all supported features for the
193204 // `BlindedPayInfo`, but there are no features in that context right now.
194205 if tlvs. features . requires_unknown_bits_from ( & BlindedHopFeatures :: empty ( ) ) { return Err ( ( ) ) }
@@ -216,16 +227,16 @@ pub(super) fn compute_payinfo(
216227
217228 let mut htlc_minimum_msat: u64 = 1 ;
218229 let mut htlc_maximum_msat: u64 = 21_000_000 * 100_000_000 * 1_000 ; // Total bitcoin supply
219- for ( _ , tlvs , max_htlc_candidate ) in intermediate_nodes. iter ( ) {
230+ for node in intermediate_nodes. iter ( ) {
220231 // The min htlc for an intermediate node is that node's min minus the fees charged by all of the
221232 // following hops for forwarding that min, since that fee amount will automatically be included
222233 // in the amount that this node receives and contribute towards reaching its min.
223234 htlc_minimum_msat = amt_to_forward_msat (
224- core:: cmp:: max ( tlvs. payment_constraints . htlc_minimum_msat , htlc_minimum_msat) ,
225- & tlvs. payment_relay
235+ core:: cmp:: max ( node . tlvs . payment_constraints . htlc_minimum_msat , htlc_minimum_msat) ,
236+ & node . tlvs . payment_relay
226237 ) . unwrap_or ( 1 ) ; // If underflow occurs, we definitely reached this node's min
227238 htlc_maximum_msat = amt_to_forward_msat (
228- core:: cmp:: min ( * max_htlc_candidate , htlc_maximum_msat) , & tlvs. payment_relay
239+ core:: cmp:: min ( node . htlc_maximum_msat , htlc_maximum_msat) , & node . tlvs . payment_relay
229240 ) . ok_or ( ( ) ) ?; // If underflow occurs, we cannot send to this hop without exceeding their max
230241 }
231242 htlc_minimum_msat = core:: cmp:: max (
@@ -258,7 +269,7 @@ impl_writeable_msg!(PaymentConstraints, {
258269#[ cfg( test) ]
259270mod tests {
260271 use bitcoin:: secp256k1:: PublicKey ;
261- use crate :: blinded_path:: payment:: { ForwardTlvs , ReceiveTlvs , PaymentConstraints , PaymentRelay } ;
272+ use crate :: blinded_path:: payment:: { ForwardNode , ForwardTlvs , ReceiveTlvs , PaymentConstraints , PaymentRelay } ;
262273 use crate :: ln:: PaymentSecret ;
263274 use crate :: ln:: features:: BlindedHopFeatures ;
264275
@@ -267,31 +278,39 @@ mod tests {
267278 // Taken from the spec example for aggregating blinded payment info. See
268279 // https://github.com/lightning/bolts/blob/master/proposals/route-blinding.md#blinded-payments
269280 let dummy_pk = PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ;
270- let intermediate_nodes = vec ! [ ( dummy_pk, ForwardTlvs {
271- short_channel_id: 0 ,
272- payment_relay: PaymentRelay {
273- cltv_expiry_delta: 144 ,
274- fee_proportional_millionths: 500 ,
275- fee_base_msat: 100 ,
276- } ,
277- payment_constraints: PaymentConstraints {
278- max_cltv_expiry: 0 ,
279- htlc_minimum_msat: 100 ,
281+ let intermediate_nodes = vec ! [ ForwardNode {
282+ node_id: dummy_pk,
283+ tlvs: ForwardTlvs {
284+ short_channel_id: 0 ,
285+ payment_relay: PaymentRelay {
286+ cltv_expiry_delta: 144 ,
287+ fee_proportional_millionths: 500 ,
288+ fee_base_msat: 100 ,
289+ } ,
290+ payment_constraints: PaymentConstraints {
291+ max_cltv_expiry: 0 ,
292+ htlc_minimum_msat: 100 ,
293+ } ,
294+ features: BlindedHopFeatures :: empty( ) ,
280295 } ,
281- features: BlindedHopFeatures :: empty( ) ,
282- } , u64 :: max_value( ) ) , ( dummy_pk, ForwardTlvs {
283- short_channel_id: 0 ,
284- payment_relay: PaymentRelay {
285- cltv_expiry_delta: 144 ,
286- fee_proportional_millionths: 500 ,
287- fee_base_msat: 100 ,
296+ htlc_maximum_msat: u64 :: max_value( ) ,
297+ } , ForwardNode {
298+ node_id: dummy_pk,
299+ tlvs: ForwardTlvs {
300+ short_channel_id: 0 ,
301+ payment_relay: PaymentRelay {
302+ cltv_expiry_delta: 144 ,
303+ fee_proportional_millionths: 500 ,
304+ fee_base_msat: 100 ,
305+ } ,
306+ payment_constraints: PaymentConstraints {
307+ max_cltv_expiry: 0 ,
308+ htlc_minimum_msat: 1_000 ,
309+ } ,
310+ features: BlindedHopFeatures :: empty( ) ,
288311 } ,
289- payment_constraints: PaymentConstraints {
290- max_cltv_expiry: 0 ,
291- htlc_minimum_msat: 1_000 ,
292- } ,
293- features: BlindedHopFeatures :: empty( ) ,
294- } , u64 :: max_value( ) ) ] ;
312+ htlc_maximum_msat: u64 :: max_value( ) ,
313+ } ] ;
295314 let recv_tlvs = ReceiveTlvs {
296315 payment_secret : PaymentSecret ( [ 0 ; 32 ] ) ,
297316 payment_constraints : PaymentConstraints {
@@ -330,31 +349,39 @@ mod tests {
330349 // If no hops charge fees, the htlc_minimum_msat should just be the maximum htlc_minimum_msat
331350 // along the path.
332351 let dummy_pk = PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ;
333- let intermediate_nodes = vec ! [ ( dummy_pk, ForwardTlvs {
334- short_channel_id: 0 ,
335- payment_relay: PaymentRelay {
336- cltv_expiry_delta: 0 ,
337- fee_proportional_millionths: 0 ,
338- fee_base_msat: 0 ,
352+ let intermediate_nodes = vec ! [ ForwardNode {
353+ node_id: dummy_pk,
354+ tlvs: ForwardTlvs {
355+ short_channel_id: 0 ,
356+ payment_relay: PaymentRelay {
357+ cltv_expiry_delta: 0 ,
358+ fee_proportional_millionths: 0 ,
359+ fee_base_msat: 0 ,
360+ } ,
361+ payment_constraints: PaymentConstraints {
362+ max_cltv_expiry: 0 ,
363+ htlc_minimum_msat: 1 ,
364+ } ,
365+ features: BlindedHopFeatures :: empty( ) ,
339366 } ,
340- payment_constraints : PaymentConstraints {
341- max_cltv_expiry : 0 ,
342- htlc_minimum_msat : 1 ,
343- } ,
344- features : BlindedHopFeatures :: empty ( ) ,
345- } , u64 :: max_value ( ) ) , ( dummy_pk , ForwardTlvs {
346- short_channel_id : 0 ,
347- payment_relay : PaymentRelay {
348- cltv_expiry_delta : 0 ,
349- fee_proportional_millionths : 0 ,
350- fee_base_msat : 0 ,
351- } ,
352- payment_constraints : PaymentConstraints {
353- max_cltv_expiry : 0 ,
354- htlc_minimum_msat : 2_000 ,
367+ htlc_maximum_msat : u64 :: max_value ( )
368+ } , ForwardNode {
369+ node_id : dummy_pk ,
370+ tlvs : ForwardTlvs {
371+ short_channel_id : 0 ,
372+ payment_relay : PaymentRelay {
373+ cltv_expiry_delta : 0 ,
374+ fee_proportional_millionths : 0 ,
375+ fee_base_msat : 0 ,
376+ } ,
377+ payment_constraints : PaymentConstraints {
378+ max_cltv_expiry : 0 ,
379+ htlc_minimum_msat : 2_000 ,
380+ } ,
381+ features : BlindedHopFeatures :: empty ( ) ,
355382 } ,
356- features : BlindedHopFeatures :: empty ( ) ,
357- } , u64 :: max_value ( ) ) ] ;
383+ htlc_maximum_msat : u64 :: max_value ( )
384+ } ] ;
358385 let recv_tlvs = ReceiveTlvs {
359386 payment_secret : PaymentSecret ( [ 0 ; 32 ] ) ,
360387 payment_constraints : PaymentConstraints {
@@ -372,31 +399,39 @@ mod tests {
372399 // Create a path with varying fees and htlc_mins, and make sure htlc_minimum_msat ends up as the
373400 // max (htlc_min - following_fees) along the path.
374401 let dummy_pk = PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ;
375- let intermediate_nodes = vec ! [ ( dummy_pk, ForwardTlvs {
376- short_channel_id: 0 ,
377- payment_relay: PaymentRelay {
378- cltv_expiry_delta: 0 ,
379- fee_proportional_millionths: 500 ,
380- fee_base_msat: 1_000 ,
381- } ,
382- payment_constraints: PaymentConstraints {
383- max_cltv_expiry: 0 ,
384- htlc_minimum_msat: 5_000 ,
402+ let intermediate_nodes = vec ! [ ForwardNode {
403+ node_id: dummy_pk,
404+ tlvs: ForwardTlvs {
405+ short_channel_id: 0 ,
406+ payment_relay: PaymentRelay {
407+ cltv_expiry_delta: 0 ,
408+ fee_proportional_millionths: 500 ,
409+ fee_base_msat: 1_000 ,
410+ } ,
411+ payment_constraints: PaymentConstraints {
412+ max_cltv_expiry: 0 ,
413+ htlc_minimum_msat: 5_000 ,
414+ } ,
415+ features: BlindedHopFeatures :: empty( ) ,
385416 } ,
386- features: BlindedHopFeatures :: empty( ) ,
387- } , u64 :: max_value( ) ) , ( dummy_pk, ForwardTlvs {
388- short_channel_id: 0 ,
389- payment_relay: PaymentRelay {
390- cltv_expiry_delta: 0 ,
391- fee_proportional_millionths: 500 ,
392- fee_base_msat: 200 ,
417+ htlc_maximum_msat: u64 :: max_value( )
418+ } , ForwardNode {
419+ node_id: dummy_pk,
420+ tlvs: ForwardTlvs {
421+ short_channel_id: 0 ,
422+ payment_relay: PaymentRelay {
423+ cltv_expiry_delta: 0 ,
424+ fee_proportional_millionths: 500 ,
425+ fee_base_msat: 200 ,
426+ } ,
427+ payment_constraints: PaymentConstraints {
428+ max_cltv_expiry: 0 ,
429+ htlc_minimum_msat: 2_000 ,
430+ } ,
431+ features: BlindedHopFeatures :: empty( ) ,
393432 } ,
394- payment_constraints: PaymentConstraints {
395- max_cltv_expiry: 0 ,
396- htlc_minimum_msat: 2_000 ,
397- } ,
398- features: BlindedHopFeatures :: empty( ) ,
399- } , u64 :: max_value( ) ) ] ;
433+ htlc_maximum_msat: u64 :: max_value( )
434+ } ] ;
400435 let recv_tlvs = ReceiveTlvs {
401436 payment_secret : PaymentSecret ( [ 0 ; 32 ] ) ,
402437 payment_constraints : PaymentConstraints {
@@ -418,31 +453,39 @@ mod tests {
418453 // Create a path with varying fees and `htlc_maximum_msat`s, and make sure the aggregated max
419454 // htlc ends up as the min (htlc_max - following_fees) along the path.
420455 let dummy_pk = PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ;
421- let intermediate_nodes = vec ! [ ( dummy_pk, ForwardTlvs {
422- short_channel_id: 0 ,
423- payment_relay: PaymentRelay {
424- cltv_expiry_delta: 0 ,
425- fee_proportional_millionths: 500 ,
426- fee_base_msat: 1_000 ,
456+ let intermediate_nodes = vec ! [ ForwardNode {
457+ node_id: dummy_pk,
458+ tlvs: ForwardTlvs {
459+ short_channel_id: 0 ,
460+ payment_relay: PaymentRelay {
461+ cltv_expiry_delta: 0 ,
462+ fee_proportional_millionths: 500 ,
463+ fee_base_msat: 1_000 ,
464+ } ,
465+ payment_constraints: PaymentConstraints {
466+ max_cltv_expiry: 0 ,
467+ htlc_minimum_msat: 1 ,
468+ } ,
469+ features: BlindedHopFeatures :: empty( ) ,
427470 } ,
428- payment_constraints : PaymentConstraints {
429- max_cltv_expiry : 0 ,
430- htlc_minimum_msat : 1 ,
431- } ,
432- features : BlindedHopFeatures :: empty ( ) ,
433- } , 5_000 ) , ( dummy_pk , ForwardTlvs {
434- short_channel_id : 0 ,
435- payment_relay : PaymentRelay {
436- cltv_expiry_delta : 0 ,
437- fee_proportional_millionths : 500 ,
438- fee_base_msat : 1 ,
439- } ,
440- payment_constraints : PaymentConstraints {
441- max_cltv_expiry : 0 ,
442- htlc_minimum_msat : 1 ,
471+ htlc_maximum_msat : 5_000 ,
472+ } , ForwardNode {
473+ node_id : dummy_pk ,
474+ tlvs : ForwardTlvs {
475+ short_channel_id : 0 ,
476+ payment_relay : PaymentRelay {
477+ cltv_expiry_delta : 0 ,
478+ fee_proportional_millionths : 500 ,
479+ fee_base_msat : 1 ,
480+ } ,
481+ payment_constraints : PaymentConstraints {
482+ max_cltv_expiry : 0 ,
483+ htlc_minimum_msat : 1 ,
484+ } ,
485+ features : BlindedHopFeatures :: empty ( ) ,
443486 } ,
444- features : BlindedHopFeatures :: empty ( ) ,
445- } , 10_000 ) ] ;
487+ htlc_maximum_msat : 10_000
488+ } ] ;
446489 let recv_tlvs = ReceiveTlvs {
447490 payment_secret : PaymentSecret ( [ 0 ; 32 ] ) ,
448491 payment_constraints : PaymentConstraints {
0 commit comments