@@ -10,7 +10,7 @@ use lightning::chain;
10
10
use lightning:: chain:: chaininterface:: { BroadcasterInterface , FeeEstimator } ;
11
11
use lightning:: chain:: keysinterface:: { Recipient , KeysInterface , Sign } ;
12
12
use lightning:: ln:: { PaymentHash , PaymentPreimage , PaymentSecret } ;
13
- use lightning:: ln:: channelmanager:: { ChannelDetails , ChannelManager , PaymentId , PaymentSendFailure , MIN_FINAL_CLTV_EXPIRY } ;
13
+ use lightning:: ln:: channelmanager:: { ChannelDetails , ChannelManager , CounterpartyForwardingInfo , PaymentId , PaymentSendFailure , MIN_FINAL_CLTV_EXPIRY } ;
14
14
#[ cfg( feature = "std" ) ]
15
15
use lightning:: ln:: channelmanager:: { PhantomRouteHints , MIN_CLTV_EXPIRY_DELTA } ;
16
16
use lightning:: ln:: msgs:: LightningError ;
@@ -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,91 @@ where
221
198
}
222
199
}
223
200
201
+ /// Filters channels for an invoice, and returns the corresponding route hints to include
202
+ /// in the invoice.
203
+ ///
204
+ /// The filtering ensures that the `RouteHints` returned only include the highest inbound capacity
205
+ /// channel per counterparty node. If any channel with a higher inbound capacity than the given
206
+ /// `min_inbound_capacity_msat` exists, channels to other counterparty nodes with a lower inbound
207
+ /// capacity than `min_inbound_capacity_msat` will be filtered out, even if they are the highest
208
+ /// inbound capacity channel for that specific counterparty node.
209
+ /// If any public channel exists, the function returns no RouteHints, and the sender will need to
210
+ /// look at the public channels to find a path instead.
211
+ ///
212
+ /// Input:
213
+ /// `channels`: The channels to filter.
214
+ /// `min_inbound_capacity_msat`: Defines the lowest inbound capacity channels must have to not
215
+ /// be filtered out, if any other channel above that amount exists.
216
+ ///
217
+ /// Result:
218
+ /// `Vec<RouteHint>`: The filtered `RouteHints`, which will be empty if any public channel exists.
219
+ fn filter_channels ( channels : Vec < ChannelDetails > , min_inbound_capacity_msat : Option < u64 > ) -> Vec < RouteHint > {
220
+ let mut filtered_channels: HashMap < PublicKey , ( u64 , RouteHint ) > = HashMap :: new ( ) ;
221
+ let min_inbound_capacity = min_inbound_capacity_msat. unwrap_or ( 0 ) ;
222
+ let mut min_capacity_channel_exists = false ;
223
+
224
+ let route_hint_from_channel = |channel : & ChannelDetails , short_channel_id : u64 , forwarding_info : & CounterpartyForwardingInfo | {
225
+ RouteHint ( vec ! [ RouteHintHop {
226
+ src_node_id: channel. counterparty. node_id,
227
+ short_channel_id,
228
+ fees: RoutingFees {
229
+ base_msat: forwarding_info. fee_base_msat,
230
+ proportional_millionths: forwarding_info. fee_proportional_millionths,
231
+ } ,
232
+ cltv_expiry_delta: forwarding_info. cltv_expiry_delta,
233
+ htlc_minimum_msat: None ,
234
+ htlc_maximum_msat: None , } ] )
235
+ } ;
236
+ for channel in channels {
237
+ let short_channel_id = match channel. get_inbound_payment_scid ( ) {
238
+ Some ( id) => id,
239
+ None => continue ,
240
+ } ;
241
+ let forwarding_info = match & channel. counterparty . forwarding_info {
242
+ Some ( info) => info,
243
+ None => continue ,
244
+ } ;
245
+ if channel. is_public {
246
+ // If any public channel exists, return no hints and let the sender
247
+ // look at the public channels instead.
248
+ return vec ! [ ]
249
+ }
250
+
251
+ if channel. inbound_capacity_msat >= min_inbound_capacity {
252
+ min_capacity_channel_exists = true ;
253
+ } ;
254
+ match filtered_channels. entry ( channel. counterparty . node_id ) {
255
+ hash_map:: Entry :: Occupied ( mut entry) => {
256
+ let current_max_capacity = entry. get ( ) . 0 ;
257
+ if channel. inbound_capacity_msat < current_max_capacity {
258
+ continue ;
259
+ }
260
+ entry. insert ( (
261
+ channel. inbound_capacity_msat ,
262
+ route_hint_from_channel ( & channel, short_channel_id, forwarding_info) ,
263
+ ) ) ;
264
+ }
265
+ hash_map:: Entry :: Vacant ( entry) => {
266
+ entry. insert ( (
267
+ channel. inbound_capacity_msat ,
268
+ route_hint_from_channel ( & channel, short_channel_id, forwarding_info) ,
269
+ ) ) ;
270
+ }
271
+ }
272
+ }
273
+
274
+ // If all channels are private, return the route hint for the highest inbound capacity channel
275
+ // per counterparty node. If channels with an higher inbound capacity than the
276
+ // min_inbound_capacity exists, filter out the channels with a lower capacity than that.
277
+ filtered_channels. into_iter ( )
278
+ . filter ( |( _channel, ( capacity, _route_hint) ) | {
279
+ min_capacity_channel_exists && capacity >= & min_inbound_capacity ||
280
+ !min_capacity_channel_exists
281
+ } )
282
+ . map ( |( _channel, ( _max_capacity, route_hint) ) | route_hint)
283
+ . collect :: < Vec < RouteHint > > ( )
284
+ }
285
+
224
286
/// A [`Router`] implemented using [`find_route`].
225
287
pub struct DefaultRouter < G : Deref < Target = NetworkGraph > , L : Deref > where L :: Target : Logger {
226
288
network_graph : G ,
@@ -317,7 +379,7 @@ mod test {
317
379
let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
318
380
let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
319
381
let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
320
- let _chan = create_announced_chan_between_nodes ( & nodes, 0 , 1 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
382
+ create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
321
383
let invoice = create_invoice_from_channelmanager_and_duration_since_epoch (
322
384
& nodes[ 1 ] . node , nodes[ 1 ] . keys_manager , Currency :: BitcoinTestnet , Some ( 10_000 ) , "test" . to_string ( ) ,
323
385
Duration :: from_secs ( 1234567 ) ) . unwrap ( ) ;
0 commit comments