@@ -161,30 +161,7 @@ where
161161 F :: Target : FeeEstimator ,
162162 L :: Target : Logger ,
163163{
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) ;
188165
189166 // `create_inbound_payment` only returns an error if the amount is greater than the total bitcoin
190167 // supply.
@@ -221,6 +198,74 @@ where
221198 }
222199}
223200
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+
224269/// A [`Router`] implemented using [`find_route`].
225270pub struct DefaultRouter < G : Deref < Target = NetworkGraph > , L : Deref > where L :: Target : Logger {
226271 network_graph : G ,
@@ -317,7 +362,7 @@ mod test {
317362 let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
318363 let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
319364 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 ( ) ) ;
321366 let invoice = create_invoice_from_channelmanager_and_duration_since_epoch (
322367 & nodes[ 1 ] . node , nodes[ 1 ] . keys_manager , Currency :: BitcoinTestnet , Some ( 10_000 ) , "test" . to_string ( ) ,
323368 Duration :: from_secs ( 1234567 ) ) . unwrap ( ) ;
0 commit comments