@@ -62,9 +62,17 @@ pub fn create_phantom_invoice<Signer: Sign, K: Deref>(
6262 if let Some ( amt) = amt_msat {
6363 invoice = invoice. amount_milli_satoshis ( amt) ;
6464 }
65+ let mut route_hints: HashMap < PublicKey , ( u64 , RouteHint ) > = HashMap :: new ( ) ;
66+ let min_capacity_required = match amt_msat {
67+ Some ( amt) => amt,
68+ None => 0 ,
69+ } ;
6570
6671 for hint in phantom_route_hints {
6772 for channel in & hint. channels {
73+ // Filter the channels to ensure that the `route_hints` only include the highest
74+ // inbound capacity channel per real node in the phantom invoice, and that channels
75+ // with a lower inbound capacity than the invoice amount aren't included in the hints.
6876 let short_channel_id = match channel. short_channel_id {
6977 Some ( id) => id,
7078 None => continue ,
@@ -73,33 +81,75 @@ pub fn create_phantom_invoice<Signer: Sign, K: Deref>(
7381 Some ( info) => info. clone ( ) ,
7482 None => continue ,
7583 } ;
76- invoice = invoice. private_route ( RouteHint ( vec ! [
77- RouteHintHop {
78- src_node_id: channel. counterparty. node_id,
79- short_channel_id,
80- fees: RoutingFees {
81- base_msat: forwarding_info. fee_base_msat,
82- proportional_millionths: forwarding_info. fee_proportional_millionths,
83- } ,
84- cltv_expiry_delta: forwarding_info. cltv_expiry_delta,
85- htlc_minimum_msat: None ,
86- htlc_maximum_msat: None ,
87- } ,
88- RouteHintHop {
89- src_node_id: hint. real_node_pubkey,
90- short_channel_id: hint. phantom_scid,
91- fees: RoutingFees {
92- base_msat: 0 ,
93- proportional_millionths: 0 ,
94- } ,
95- cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA ,
96- htlc_minimum_msat: None ,
97- htlc_maximum_msat: None ,
98- } ] )
99- ) ;
84+ if channel. inbound_capacity_msat < min_capacity_required {
85+ continue ;
86+ } ;
87+ match route_hints. entry ( hint. real_node_pubkey ) {
88+ hash_map:: Entry :: Occupied ( mut entry) => {
89+ let current_max_capacity = entry. get ( ) . 0 ;
90+ if channel. inbound_capacity_msat < current_max_capacity {
91+ continue ;
92+ }
93+ entry. insert ( (
94+ channel. inbound_capacity_msat ,
95+ RouteHint ( vec ! [
96+ RouteHintHop {
97+ src_node_id: channel. counterparty. node_id,
98+ short_channel_id,
99+ fees: RoutingFees {
100+ base_msat: forwarding_info. fee_base_msat,
101+ proportional_millionths: forwarding_info. fee_proportional_millionths,
102+ } ,
103+ cltv_expiry_delta: forwarding_info. cltv_expiry_delta,
104+ htlc_minimum_msat: None ,
105+ htlc_maximum_msat: None ,
106+ } ,
107+ RouteHintHop {
108+ src_node_id: hint. real_node_pubkey,
109+ short_channel_id: hint. phantom_scid,
110+ fees: RoutingFees {
111+ base_msat: 0 ,
112+ proportional_millionths: 0 ,
113+ } ,
114+ cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA ,
115+ htlc_minimum_msat: None ,
116+ htlc_maximum_msat: None ,
117+ } ] ) ) ) ;
118+ }
119+ hash_map:: Entry :: Vacant ( entry) => {
120+ entry. insert ( (
121+ channel. inbound_capacity_msat ,
122+ RouteHint ( vec ! [
123+ RouteHintHop {
124+ src_node_id: channel. counterparty. node_id,
125+ short_channel_id,
126+ fees: RoutingFees {
127+ base_msat: forwarding_info. fee_base_msat,
128+ proportional_millionths: forwarding_info. fee_proportional_millionths,
129+ } ,
130+ cltv_expiry_delta: forwarding_info. cltv_expiry_delta,
131+ htlc_minimum_msat: None ,
132+ htlc_maximum_msat: None ,
133+ } ,
134+ RouteHintHop {
135+ src_node_id: hint. real_node_pubkey,
136+ short_channel_id: hint. phantom_scid,
137+ fees: RoutingFees {
138+ base_msat: 0 ,
139+ proportional_millionths: 0 ,
140+ } ,
141+ cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA ,
142+ htlc_minimum_msat: None ,
143+ htlc_maximum_msat: None ,
144+ } ] ) ) ) ;
145+ }
146+ }
100147 }
101148 }
102149
150+ for ( _, ( _, hint) ) in & route_hints {
151+ invoice = invoice. private_route ( hint. clone ( ) ) ;
152+ }
103153 let raw_invoice = match invoice. build_raw ( ) {
104154 Ok ( inv) => inv,
105155 Err ( e) => return Err ( SignOrCreationError :: CreationError ( e) )
0 commit comments