@@ -133,6 +133,8 @@ where
133133 )
134134}
135135
136+ const MAX_CHANNEL_HINTS : usize = 3 ;
137+
136138fn _create_phantom_invoice < ES : Deref , NS : Deref , L : Deref > (
137139 amt_msat : Option < u64 > , payment_hash : Option < PaymentHash > , description : InvoiceDescription ,
138140 invoice_expiry_delta_secs : u32 , phantom_route_hints : Vec < PhantomRouteHints > , entropy_source : ES ,
@@ -203,7 +205,8 @@ where
203205 invoice = invoice. amount_milli_satoshis ( amt) ;
204206 }
205207
206- for route_hint in select_phantom_hints ( amt_msat, phantom_route_hints, logger) {
208+
209+ for route_hint in select_phantom_hints ( amt_msat, phantom_route_hints, logger) . take ( MAX_CHANNEL_HINTS ) {
207210 invoice = invoice. private_route ( route_hint) ;
208211 }
209212
@@ -230,36 +233,48 @@ where
230233///
231234/// [`PhantomKeysManager`]: lightning::sign::PhantomKeysManager
232235fn select_phantom_hints < L : Deref > ( amt_msat : Option < u64 > , phantom_route_hints : Vec < PhantomRouteHints > ,
233- logger : L ) -> Vec < RouteHint >
236+ logger : L ) -> impl Iterator < Item = RouteHint >
234237where
235238 L :: Target : Logger ,
236239{
237- let mut phantom_hints: Vec < Vec < RouteHint > > = Vec :: new ( ) ;
240+ let mut phantom_hints: Vec < _ > = Vec :: new ( ) ;
238241
239242 for PhantomRouteHints { channels, phantom_scid, real_node_pubkey } in phantom_route_hints {
240243 log_trace ! ( logger, "Generating phantom route hints for node {}" ,
241244 log_pubkey!( real_node_pubkey) ) ;
242- let mut route_hints = sort_and_filter_channels ( channels, amt_msat, & logger) ;
245+ let route_hints = sort_and_filter_channels ( channels, amt_msat, & logger) ;
243246
244247 // If we have any public channel, the route hints from `sort_and_filter_channels` will be
245248 // empty. In that case we create a RouteHint on which we will push a single hop with the
246249 // phantom route into the invoice, and let the sender find the path to the `real_node_pubkey`
247250 // node by looking at our public channels.
248- if route_hints. is_empty ( ) {
249- route_hints. push ( RouteHint ( vec ! [ ] ) )
250- }
251- for route_hint in & mut route_hints {
252- route_hint. 0 . push ( RouteHintHop {
253- src_node_id : real_node_pubkey,
254- short_channel_id : phantom_scid,
255- fees : RoutingFees {
256- base_msat : 0 ,
257- proportional_millionths : 0 ,
258- } ,
259- cltv_expiry_delta : MIN_CLTV_EXPIRY_DELTA ,
260- htlc_minimum_msat : None ,
261- htlc_maximum_msat : None , } ) ;
262- }
251+ let empty_route_hints = route_hints. len ( ) == 0 ;
252+ let mut have_pushed_empty = false ;
253+ let route_hints = route_hints
254+ . chain ( core:: iter:: from_fn ( move || {
255+ if empty_route_hints && !have_pushed_empty {
256+ // set flag of having handled the empty route_hints and ensure empty vector
257+ // returned only once
258+ have_pushed_empty = true ;
259+ Some ( RouteHint ( Vec :: new ( ) ) )
260+ } else {
261+ None
262+ }
263+ } ) )
264+ . map ( move |mut hint| {
265+ hint. 0 . push ( RouteHintHop {
266+ src_node_id : real_node_pubkey,
267+ short_channel_id : phantom_scid,
268+ fees : RoutingFees {
269+ base_msat : 0 ,
270+ proportional_millionths : 0 ,
271+ } ,
272+ cltv_expiry_delta : MIN_CLTV_EXPIRY_DELTA ,
273+ htlc_minimum_msat : None ,
274+ htlc_maximum_msat : None ,
275+ } ) ;
276+ hint
277+ } ) ;
263278
264279 phantom_hints. push ( route_hints) ;
265280 }
@@ -268,29 +283,7 @@ where
268283 // the hints across our real nodes we add one hint from each in turn until no node has any hints
269284 // left (if one node has more hints than any other, these will accumulate at the end of the
270285 // vector).
271- let mut invoice_hints: Vec < RouteHint > = Vec :: new ( ) ;
272- let mut hint_idx = 0 ;
273-
274- loop {
275- let mut remaining_hints = false ;
276-
277- for hints in phantom_hints. iter ( ) {
278- if invoice_hints. len ( ) == 3 {
279- return invoice_hints
280- }
281-
282- if hint_idx < hints. len ( ) {
283- invoice_hints. push ( hints[ hint_idx] . clone ( ) ) ;
284- remaining_hints = true
285- }
286- }
287-
288- if !remaining_hints {
289- return invoice_hints
290- }
291-
292- hint_idx +=1 ;
293- }
286+ rotate_through_iterators ( phantom_hints)
294287}
295288
296289/// Draw items iteratively from multiple iterators. The items are retrieved by index and
@@ -603,15 +596,34 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has
603596/// * Sorted by lowest inbound capacity if an online channel with the minimum amount requested exists,
604597/// otherwise sort by highest inbound capacity to give the payment the best chance of succeeding.
605598fn sort_and_filter_channels < L : Deref > (
606- channels : Vec < ChannelDetails > , min_inbound_capacity_msat : Option < u64 > , logger : & L
607- ) -> Vec < RouteHint > where L :: Target : Logger {
599+ channels : Vec < ChannelDetails > ,
600+ min_inbound_capacity_msat : Option < u64 > ,
601+ logger : & L ,
602+ ) -> impl ExactSizeIterator < Item = RouteHint >
603+ where
604+ L :: Target : Logger ,
605+ {
608606 let mut filtered_channels: HashMap < PublicKey , ChannelDetails > = HashMap :: new ( ) ;
609607 let min_inbound_capacity = min_inbound_capacity_msat. unwrap_or ( 0 ) ;
610608 let mut min_capacity_channel_exists = false ;
611609 let mut online_channel_exists = false ;
612610 let mut online_min_capacity_channel_exists = false ;
613611 let mut has_pub_unconf_chan = false ;
614612
613+ let route_hint_from_channel = |channel : ChannelDetails | {
614+ let forwarding_info = channel. counterparty . forwarding_info . as_ref ( ) . unwrap ( ) ;
615+ RouteHint ( vec ! [ RouteHintHop {
616+ src_node_id: channel. counterparty. node_id,
617+ short_channel_id: channel. get_inbound_payment_scid( ) . unwrap( ) ,
618+ fees: RoutingFees {
619+ base_msat: forwarding_info. fee_base_msat,
620+ proportional_millionths: forwarding_info. fee_proportional_millionths,
621+ } ,
622+ cltv_expiry_delta: forwarding_info. cltv_expiry_delta,
623+ htlc_minimum_msat: channel. inbound_htlc_minimum_msat,
624+ htlc_maximum_msat: channel. inbound_htlc_maximum_msat, } ] )
625+ } ;
626+
615627 log_trace ! ( logger, "Considering {} channels for invoice route hints" , channels. len( ) ) ;
616628 for channel in channels. into_iter ( ) . filter ( |chan| chan. is_channel_ready ) {
617629 if channel. get_inbound_payment_scid ( ) . is_none ( ) || channel. counterparty . forwarding_info . is_none ( ) {
@@ -630,7 +642,7 @@ fn sort_and_filter_channels<L: Deref>(
630642 // look at the public channels instead.
631643 log_trace ! ( logger, "Not including channels in invoice route hints on account of public channel {}" ,
632644 log_bytes!( channel. channel_id) ) ;
633- return vec ! [ ]
645+ return vec ! [ ] . into_iter ( ) . take ( MAX_CHANNEL_HINTS ) . map ( route_hint_from_channel ) ;
634646 }
635647 }
636648
@@ -690,19 +702,6 @@ fn sort_and_filter_channels<L: Deref>(
690702 }
691703 }
692704
693- let route_hint_from_channel = |channel : ChannelDetails | {
694- let forwarding_info = channel. counterparty . forwarding_info . as_ref ( ) . unwrap ( ) ;
695- RouteHint ( vec ! [ RouteHintHop {
696- src_node_id: channel. counterparty. node_id,
697- short_channel_id: channel. get_inbound_payment_scid( ) . unwrap( ) ,
698- fees: RoutingFees {
699- base_msat: forwarding_info. fee_base_msat,
700- proportional_millionths: forwarding_info. fee_proportional_millionths,
701- } ,
702- cltv_expiry_delta: forwarding_info. cltv_expiry_delta,
703- htlc_minimum_msat: channel. inbound_htlc_minimum_msat,
704- htlc_maximum_msat: channel. inbound_htlc_maximum_msat, } ] )
705- } ;
706705 // If all channels are private, prefer to return route hints which have a higher capacity than
707706 // the payment value and where we're currently connected to the channel counterparty.
708707 // Even if we cannot satisfy both goals, always ensure we include *some* hints, preferring
@@ -752,7 +751,8 @@ fn sort_and_filter_channels<L: Deref>(
752751 } else {
753752 b. inbound_capacity_msat . cmp ( & a. inbound_capacity_msat )
754753 } } ) ;
755- eligible_channels. into_iter ( ) . take ( 3 ) . map ( route_hint_from_channel) . collect :: < Vec < RouteHint > > ( )
754+
755+ eligible_channels. into_iter ( ) . take ( MAX_CHANNEL_HINTS ) . map ( route_hint_from_channel)
756756}
757757
758758/// prefer_current_channel chooses a channel to use for route hints between a currently selected and candidate
0 commit comments