@@ -161,30 +161,7 @@ where
161
161
F :: Target : FeeEstimator ,
162
162
L :: Target : Logger ,
163
163
{
164
- // Marshall route hints.
165
- let our_channels = channelmanager. list_usable_channels ( ) ;
166
- let mut route_hints = vec ! [ ] ;
167
- for channel in our_channels {
168
- let short_channel_id = match channel. get_inbound_payment_scid ( ) {
169
- Some ( id) => id,
170
- None => continue ,
171
- } ;
172
- let forwarding_info = match channel. counterparty . forwarding_info {
173
- Some ( info) => info,
174
- None => continue ,
175
- } ;
176
- route_hints. push ( RouteHint ( vec ! [ RouteHintHop {
177
- src_node_id: channel. counterparty. node_id,
178
- short_channel_id,
179
- fees: RoutingFees {
180
- base_msat: forwarding_info. fee_base_msat,
181
- proportional_millionths: forwarding_info. fee_proportional_millionths,
182
- } ,
183
- cltv_expiry_delta: forwarding_info. cltv_expiry_delta,
184
- htlc_minimum_msat: None ,
185
- htlc_maximum_msat: None ,
186
- } ] ) ) ;
187
- }
164
+ let route_hints = filter_channels ( channelmanager. list_usable_channels ( ) , amt_msat) ;
188
165
189
166
// `create_inbound_payment` only returns an error if the amount is greater than the total bitcoin
190
167
// supply.
@@ -221,6 +198,74 @@ where
221
198
}
222
199
}
223
200
201
+ /// Filters the `channels` for an invoice, and returns the corresponding `RouteHint`s to include
202
+ /// in the invoice.
203
+ ///
204
+ /// The filtering is based on the following criteria:
205
+ /// * Only one channel per counterparty node
206
+ /// * Always select the channel with the highest inbound capacity per counterparty node
207
+ /// * Filter out channels with a lower inbound capacity than `min_inbound_capacity_msat`, if any
208
+ /// channel with a higher or equal inbound capacity than `min_inbound_capacity_msat` exists
209
+ /// * If any public channel exists, the returned `RouteHint`s will be empty, and the sender will
210
+ /// need to find the path by looking at the public channels instead
211
+ fn filter_channels ( channels : Vec < ChannelDetails > , min_inbound_capacity_msat : Option < u64 > ) -> Vec < RouteHint > {
212
+ let mut filtered_channels: HashMap < PublicKey , & ChannelDetails > = HashMap :: new ( ) ;
213
+ let min_inbound_capacity = min_inbound_capacity_msat. unwrap_or ( 0 ) ;
214
+ let mut min_capacity_channel_exists = false ;
215
+
216
+ for channel in channels. iter ( ) {
217
+ if channel. get_inbound_payment_scid ( ) . is_none ( ) || channel. counterparty . forwarding_info . is_none ( ) {
218
+ continue ;
219
+ }
220
+
221
+ if channel. is_public {
222
+ // If any public channel exists, return no hints and let the sender
223
+ // look at the public channels instead.
224
+ return vec ! [ ]
225
+ }
226
+
227
+ if channel. inbound_capacity_msat >= min_inbound_capacity {
228
+ min_capacity_channel_exists = true ;
229
+ } ;
230
+ match filtered_channels. entry ( channel. counterparty . node_id ) {
231
+ hash_map:: Entry :: Occupied ( mut entry) => {
232
+ let current_max_capacity = entry. get ( ) . inbound_capacity_msat ;
233
+ if channel. inbound_capacity_msat < current_max_capacity {
234
+ continue ;
235
+ }
236
+ entry. insert ( channel) ;
237
+ }
238
+ hash_map:: Entry :: Vacant ( entry) => {
239
+ entry. insert ( channel) ;
240
+ }
241
+ }
242
+ }
243
+
244
+ let route_hint_from_channel = |channel : & ChannelDetails | {
245
+ let forwarding_info = channel. counterparty . forwarding_info . as_ref ( ) . unwrap ( ) ;
246
+ RouteHint ( vec ! [ RouteHintHop {
247
+ src_node_id: channel. counterparty. node_id,
248
+ short_channel_id: channel. get_inbound_payment_scid( ) . unwrap( ) ,
249
+ fees: RoutingFees {
250
+ base_msat: forwarding_info. fee_base_msat,
251
+ proportional_millionths: forwarding_info. fee_proportional_millionths,
252
+ } ,
253
+ cltv_expiry_delta: forwarding_info. cltv_expiry_delta,
254
+ htlc_minimum_msat: None ,
255
+ htlc_maximum_msat: None , } ] )
256
+ } ;
257
+ // If all channels are private, return the route hint for the highest inbound capacity channel
258
+ // per counterparty node. If channels with an higher inbound capacity than the
259
+ // min_inbound_capacity exists, filter out the channels with a lower capacity than that.
260
+ filtered_channels. into_iter ( )
261
+ . filter ( |( _counterparty_id, channel) | {
262
+ min_capacity_channel_exists && channel. inbound_capacity_msat >= min_inbound_capacity ||
263
+ !min_capacity_channel_exists
264
+ } )
265
+ . map ( |( _counterparty_id, channel) | route_hint_from_channel ( & channel) )
266
+ . collect :: < Vec < RouteHint > > ( )
267
+ }
268
+
224
269
/// A [`Router`] implemented using [`find_route`].
225
270
pub struct DefaultRouter < G : Deref < Target = NetworkGraph > , L : Deref > where L :: Target : Logger {
226
271
network_graph : G ,
@@ -317,7 +362,7 @@ mod test {
317
362
let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
318
363
let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
319
364
let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
320
- let _chan = create_announced_chan_between_nodes ( & nodes, 0 , 1 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
365
+ create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
321
366
let invoice = create_invoice_from_channelmanager_and_duration_since_epoch (
322
367
& nodes[ 1 ] . node , nodes[ 1 ] . keys_manager , Currency :: BitcoinTestnet , Some ( 10_000 ) , "test" . to_string ( ) ,
323
368
Duration :: from_secs ( 1234567 ) ) . unwrap ( ) ;
0 commit comments