@@ -16,6 +16,18 @@ use crate::util::ser::{Readable, Writeable, Writer};
1616
1717use core:: convert:: TryFrom ;
1818
19+ /// An intermediate node, its outbound channel, and relay parameters.
20+ #[ derive( Clone , Debug ) ]
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( Clone , 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 ( ( ) ) }
@@ -215,16 +226,16 @@ pub(super) fn compute_payinfo(
215226
216227 let mut htlc_minimum_msat: u64 = 1 ;
217228 let mut htlc_maximum_msat: u64 = 21_000_000 * 100_000_000 * 1_000 ; // Total bitcoin supply
218- for ( _ , tlvs , max_htlc_candidate ) in intermediate_nodes. iter ( ) {
229+ for node in intermediate_nodes. iter ( ) {
219230 // The min htlc for an intermediate node is that node's min minus the fees charged by all of the
220231 // following hops for forwarding that min, since that fee amount will automatically be included
221232 // in the amount that this node receives and contribute towards reaching its min.
222233 htlc_minimum_msat = amt_to_forward_msat (
223- core:: cmp:: max ( tlvs. payment_constraints . htlc_minimum_msat , htlc_minimum_msat) ,
224- & tlvs. payment_relay
234+ core:: cmp:: max ( node . tlvs . payment_constraints . htlc_minimum_msat , htlc_minimum_msat) ,
235+ & node . tlvs . payment_relay
225236 ) . unwrap_or ( 1 ) ; // If underflow occurs, we definitely reached this node's min
226237 htlc_maximum_msat = amt_to_forward_msat (
227- core:: cmp:: min ( * max_htlc_candidate , htlc_maximum_msat) , & tlvs. payment_relay
238+ core:: cmp:: min ( node . htlc_maximum_msat , htlc_maximum_msat) , & node . tlvs . payment_relay
228239 ) . ok_or ( ( ) ) ?; // If underflow occurs, we cannot send to this hop without exceeding their max
229240 }
230241 htlc_minimum_msat = core:: cmp:: max (
@@ -257,7 +268,7 @@ impl_writeable_msg!(PaymentConstraints, {
257268#[ cfg( test) ]
258269mod tests {
259270 use bitcoin:: secp256k1:: PublicKey ;
260- use crate :: blinded_path:: payment:: { ForwardTlvs , ReceiveTlvs , PaymentConstraints , PaymentRelay } ;
271+ use crate :: blinded_path:: payment:: { ForwardNode , ForwardTlvs , ReceiveTlvs , PaymentConstraints , PaymentRelay } ;
261272 use crate :: ln:: PaymentSecret ;
262273 use crate :: ln:: features:: BlindedHopFeatures ;
263274
@@ -266,31 +277,39 @@ mod tests {
266277 // Taken from the spec example for aggregating blinded payment info. See
267278 // https://github.com/lightning/bolts/blob/master/proposals/route-blinding.md#blinded-payments
268279 let dummy_pk = PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ;
269- let intermediate_nodes = vec ! [ ( dummy_pk, ForwardTlvs {
270- short_channel_id: 0 ,
271- payment_relay: PaymentRelay {
272- cltv_expiry_delta: 144 ,
273- fee_proportional_millionths: 500 ,
274- fee_base_msat: 100 ,
275- } ,
276- payment_constraints: PaymentConstraints {
277- max_cltv_expiry: 0 ,
278- htlc_minimum_msat: 100 ,
280+ let intermediate_nodes = vec ! [ ForwardNode {
281+ node_id: dummy_pk,
282+ tlvs: 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 ,
288+ } ,
289+ payment_constraints: PaymentConstraints {
290+ max_cltv_expiry: 0 ,
291+ htlc_minimum_msat: 100 ,
292+ } ,
293+ features: BlindedHopFeatures :: empty( ) ,
279294 } ,
280- features: BlindedHopFeatures :: empty( ) ,
281- } , u64 :: max_value( ) ) , ( dummy_pk, ForwardTlvs {
282- short_channel_id: 0 ,
283- payment_relay: PaymentRelay {
284- cltv_expiry_delta: 144 ,
285- fee_proportional_millionths: 500 ,
286- fee_base_msat: 100 ,
295+ htlc_maximum_msat: u64 :: max_value( ) ,
296+ } , ForwardNode {
297+ node_id: dummy_pk,
298+ tlvs: ForwardTlvs {
299+ short_channel_id: 0 ,
300+ payment_relay: PaymentRelay {
301+ cltv_expiry_delta: 144 ,
302+ fee_proportional_millionths: 500 ,
303+ fee_base_msat: 100 ,
304+ } ,
305+ payment_constraints: PaymentConstraints {
306+ max_cltv_expiry: 0 ,
307+ htlc_minimum_msat: 1_000 ,
308+ } ,
309+ features: BlindedHopFeatures :: empty( ) ,
287310 } ,
288- payment_constraints: PaymentConstraints {
289- max_cltv_expiry: 0 ,
290- htlc_minimum_msat: 1_000 ,
291- } ,
292- features: BlindedHopFeatures :: empty( ) ,
293- } , u64 :: max_value( ) ) ] ;
311+ htlc_maximum_msat: u64 :: max_value( ) ,
312+ } ] ;
294313 let recv_tlvs = ReceiveTlvs {
295314 payment_secret : PaymentSecret ( [ 0 ; 32 ] ) ,
296315 payment_constraints : PaymentConstraints {
@@ -329,31 +348,39 @@ mod tests {
329348 // If no hops charge fees, the htlc_minimum_msat should just be the maximum htlc_minimum_msat
330349 // along the path.
331350 let dummy_pk = PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ;
332- let intermediate_nodes = vec ! [ ( dummy_pk, ForwardTlvs {
333- short_channel_id: 0 ,
334- payment_relay: PaymentRelay {
335- cltv_expiry_delta: 0 ,
336- fee_proportional_millionths: 0 ,
337- fee_base_msat: 0 ,
351+ let intermediate_nodes = vec ! [ ForwardNode {
352+ node_id: dummy_pk,
353+ tlvs: ForwardTlvs {
354+ short_channel_id: 0 ,
355+ payment_relay: PaymentRelay {
356+ cltv_expiry_delta: 0 ,
357+ fee_proportional_millionths: 0 ,
358+ fee_base_msat: 0 ,
359+ } ,
360+ payment_constraints: PaymentConstraints {
361+ max_cltv_expiry: 0 ,
362+ htlc_minimum_msat: 1 ,
363+ } ,
364+ features: BlindedHopFeatures :: empty( ) ,
338365 } ,
339- payment_constraints : PaymentConstraints {
340- max_cltv_expiry : 0 ,
341- htlc_minimum_msat : 1 ,
342- } ,
343- features : BlindedHopFeatures :: empty ( ) ,
344- } , u64 :: max_value ( ) ) , ( dummy_pk , ForwardTlvs {
345- short_channel_id : 0 ,
346- payment_relay : PaymentRelay {
347- cltv_expiry_delta : 0 ,
348- fee_proportional_millionths : 0 ,
349- fee_base_msat : 0 ,
350- } ,
351- payment_constraints : PaymentConstraints {
352- max_cltv_expiry : 0 ,
353- htlc_minimum_msat : 2_000 ,
366+ htlc_maximum_msat : u64 :: max_value ( )
367+ } , ForwardNode {
368+ node_id : dummy_pk ,
369+ tlvs : ForwardTlvs {
370+ short_channel_id : 0 ,
371+ payment_relay : PaymentRelay {
372+ cltv_expiry_delta : 0 ,
373+ fee_proportional_millionths : 0 ,
374+ fee_base_msat : 0 ,
375+ } ,
376+ payment_constraints : PaymentConstraints {
377+ max_cltv_expiry : 0 ,
378+ htlc_minimum_msat : 2_000 ,
379+ } ,
380+ features : BlindedHopFeatures :: empty ( ) ,
354381 } ,
355- features : BlindedHopFeatures :: empty ( ) ,
356- } , u64 :: max_value ( ) ) ] ;
382+ htlc_maximum_msat : u64 :: max_value ( )
383+ } ] ;
357384 let recv_tlvs = ReceiveTlvs {
358385 payment_secret : PaymentSecret ( [ 0 ; 32 ] ) ,
359386 payment_constraints : PaymentConstraints {
@@ -371,31 +398,39 @@ mod tests {
371398 // Create a path with varying fees and htlc_mins, and make sure htlc_minimum_msat ends up as the
372399 // max (htlc_min - following_fees) along the path.
373400 let dummy_pk = PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ;
374- let intermediate_nodes = vec ! [ ( dummy_pk, ForwardTlvs {
375- short_channel_id: 0 ,
376- payment_relay: PaymentRelay {
377- cltv_expiry_delta: 0 ,
378- fee_proportional_millionths: 500 ,
379- fee_base_msat: 1_000 ,
380- } ,
381- payment_constraints: PaymentConstraints {
382- max_cltv_expiry: 0 ,
383- htlc_minimum_msat: 5_000 ,
401+ let intermediate_nodes = vec ! [ ForwardNode {
402+ node_id: dummy_pk,
403+ tlvs: ForwardTlvs {
404+ short_channel_id: 0 ,
405+ payment_relay: PaymentRelay {
406+ cltv_expiry_delta: 0 ,
407+ fee_proportional_millionths: 500 ,
408+ fee_base_msat: 1_000 ,
409+ } ,
410+ payment_constraints: PaymentConstraints {
411+ max_cltv_expiry: 0 ,
412+ htlc_minimum_msat: 5_000 ,
413+ } ,
414+ features: BlindedHopFeatures :: empty( ) ,
384415 } ,
385- features: BlindedHopFeatures :: empty( ) ,
386- } , u64 :: max_value( ) ) , ( dummy_pk, ForwardTlvs {
387- short_channel_id: 0 ,
388- payment_relay: PaymentRelay {
389- cltv_expiry_delta: 0 ,
390- fee_proportional_millionths: 500 ,
391- fee_base_msat: 200 ,
416+ htlc_maximum_msat: u64 :: max_value( )
417+ } , ForwardNode {
418+ node_id: dummy_pk,
419+ tlvs: ForwardTlvs {
420+ short_channel_id: 0 ,
421+ payment_relay: PaymentRelay {
422+ cltv_expiry_delta: 0 ,
423+ fee_proportional_millionths: 500 ,
424+ fee_base_msat: 200 ,
425+ } ,
426+ payment_constraints: PaymentConstraints {
427+ max_cltv_expiry: 0 ,
428+ htlc_minimum_msat: 2_000 ,
429+ } ,
430+ features: BlindedHopFeatures :: empty( ) ,
392431 } ,
393- payment_constraints: PaymentConstraints {
394- max_cltv_expiry: 0 ,
395- htlc_minimum_msat: 2_000 ,
396- } ,
397- features: BlindedHopFeatures :: empty( ) ,
398- } , u64 :: max_value( ) ) ] ;
432+ htlc_maximum_msat: u64 :: max_value( )
433+ } ] ;
399434 let recv_tlvs = ReceiveTlvs {
400435 payment_secret : PaymentSecret ( [ 0 ; 32 ] ) ,
401436 payment_constraints : PaymentConstraints {
@@ -417,31 +452,39 @@ mod tests {
417452 // Create a path with varying fees and `htlc_maximum_msat`s, and make sure the aggregated max
418453 // htlc ends up as the min (htlc_max - following_fees) along the path.
419454 let dummy_pk = PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ;
420- let intermediate_nodes = vec ! [ ( dummy_pk, ForwardTlvs {
421- short_channel_id: 0 ,
422- payment_relay: PaymentRelay {
423- cltv_expiry_delta: 0 ,
424- fee_proportional_millionths: 500 ,
425- fee_base_msat: 1_000 ,
455+ let intermediate_nodes = vec ! [ ForwardNode {
456+ node_id: dummy_pk,
457+ tlvs: ForwardTlvs {
458+ short_channel_id: 0 ,
459+ payment_relay: PaymentRelay {
460+ cltv_expiry_delta: 0 ,
461+ fee_proportional_millionths: 500 ,
462+ fee_base_msat: 1_000 ,
463+ } ,
464+ payment_constraints: PaymentConstraints {
465+ max_cltv_expiry: 0 ,
466+ htlc_minimum_msat: 1 ,
467+ } ,
468+ features: BlindedHopFeatures :: empty( ) ,
426469 } ,
427- payment_constraints : PaymentConstraints {
428- max_cltv_expiry : 0 ,
429- htlc_minimum_msat : 1 ,
430- } ,
431- features : BlindedHopFeatures :: empty ( ) ,
432- } , 5_000 ) , ( dummy_pk , ForwardTlvs {
433- short_channel_id : 0 ,
434- payment_relay : PaymentRelay {
435- cltv_expiry_delta : 0 ,
436- fee_proportional_millionths : 500 ,
437- fee_base_msat : 1 ,
438- } ,
439- payment_constraints : PaymentConstraints {
440- max_cltv_expiry : 0 ,
441- htlc_minimum_msat : 1 ,
470+ htlc_maximum_msat : 5_000 ,
471+ } , ForwardNode {
472+ node_id : dummy_pk ,
473+ tlvs : ForwardTlvs {
474+ short_channel_id : 0 ,
475+ payment_relay : PaymentRelay {
476+ cltv_expiry_delta : 0 ,
477+ fee_proportional_millionths : 500 ,
478+ fee_base_msat : 1 ,
479+ } ,
480+ payment_constraints : PaymentConstraints {
481+ max_cltv_expiry : 0 ,
482+ htlc_minimum_msat : 1 ,
483+ } ,
484+ features : BlindedHopFeatures :: empty ( ) ,
442485 } ,
443- features : BlindedHopFeatures :: empty ( ) ,
444- } , 10_000 ) ] ;
486+ htlc_maximum_msat : 10_000
487+ } ] ;
445488 let recv_tlvs = ReceiveTlvs {
446489 payment_secret : PaymentSecret ( [ 0 ; 32 ] ) ,
447490 payment_constraints : PaymentConstraints {
0 commit comments