@@ -133,6 +133,8 @@ where
133
133
)
134
134
}
135
135
136
+ const MAX_CHANNEL_HINTS : usize = 3 ;
137
+
136
138
fn _create_phantom_invoice < ES : Deref , NS : Deref , L : Deref > (
137
139
amt_msat : Option < u64 > , payment_hash : Option < PaymentHash > , description : InvoiceDescription ,
138
140
invoice_expiry_delta_secs : u32 , phantom_route_hints : Vec < PhantomRouteHints > , entropy_source : ES ,
@@ -203,7 +205,8 @@ where
203
205
invoice = invoice. amount_milli_satoshis ( amt) ;
204
206
}
205
207
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 ) {
207
210
invoice = invoice. private_route ( route_hint) ;
208
211
}
209
212
@@ -230,36 +233,48 @@ where
230
233
///
231
234
/// [`PhantomKeysManager`]: lightning::sign::PhantomKeysManager
232
235
fn 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 >
234
237
where
235
238
L :: Target : Logger ,
236
239
{
237
- let mut phantom_hints: Vec < Vec < RouteHint > > = Vec :: new ( ) ;
240
+ let mut phantom_hints: Vec < _ > = Vec :: new ( ) ;
238
241
239
242
for PhantomRouteHints { channels, phantom_scid, real_node_pubkey } in phantom_route_hints {
240
243
log_trace ! ( logger, "Generating phantom route hints for node {}" ,
241
244
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) ;
243
246
244
247
// If we have any public channel, the route hints from `sort_and_filter_channels` will be
245
248
// empty. In that case we create a RouteHint on which we will push a single hop with the
246
249
// phantom route into the invoice, and let the sender find the path to the `real_node_pubkey`
247
250
// 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
+ } ) ;
263
278
264
279
phantom_hints. push ( route_hints) ;
265
280
}
@@ -268,29 +283,7 @@ where
268
283
// the hints across our real nodes we add one hint from each in turn until no node has any hints
269
284
// left (if one node has more hints than any other, these will accumulate at the end of the
270
285
// 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)
294
287
}
295
288
296
289
/// 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
603
596
/// * Sorted by lowest inbound capacity if an online channel with the minimum amount requested exists,
604
597
/// otherwise sort by highest inbound capacity to give the payment the best chance of succeeding.
605
598
fn 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
+ {
608
606
let mut filtered_channels: HashMap < PublicKey , ChannelDetails > = HashMap :: new ( ) ;
609
607
let min_inbound_capacity = min_inbound_capacity_msat. unwrap_or ( 0 ) ;
610
608
let mut min_capacity_channel_exists = false ;
611
609
let mut online_channel_exists = false ;
612
610
let mut online_min_capacity_channel_exists = false ;
613
611
let mut has_pub_unconf_chan = false ;
614
612
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
+
615
627
log_trace ! ( logger, "Considering {} channels for invoice route hints" , channels. len( ) ) ;
616
628
for channel in channels. into_iter ( ) . filter ( |chan| chan. is_channel_ready ) {
617
629
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>(
630
642
// look at the public channels instead.
631
643
log_trace ! ( logger, "Not including channels in invoice route hints on account of public channel {}" ,
632
644
log_bytes!( channel. channel_id) ) ;
633
- return vec ! [ ]
645
+ return vec ! [ ] . into_iter ( ) . take ( MAX_CHANNEL_HINTS ) . map ( route_hint_from_channel ) ;
634
646
}
635
647
}
636
648
@@ -690,19 +702,6 @@ fn sort_and_filter_channels<L: Deref>(
690
702
}
691
703
}
692
704
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
- } ;
706
705
// If all channels are private, prefer to return route hints which have a higher capacity than
707
706
// the payment value and where we're currently connected to the channel counterparty.
708
707
// 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>(
752
751
} else {
753
752
b. inbound_capacity_msat . cmp ( & a. inbound_capacity_msat )
754
753
} } ) ;
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)
756
756
}
757
757
758
758
/// prefer_current_channel chooses a channel to use for route hints between a currently selected and candidate
0 commit comments