@@ -92,6 +92,9 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, ES: Deref, S: Deref,
9292 & self , recipient : PublicKey , first_hops : Vec < ChannelDetails > , tlvs : ReceiveTlvs ,
9393 amount_msats : u64 , secp_ctx : & Secp256k1 < T >
9494 ) -> Result < Vec < ( BlindedPayInfo , BlindedPath ) > , ( ) > {
95+ let entropy_source = & * self . entropy_source ;
96+ let recipient_node_id = NodeId :: from_pubkey ( & recipient) ;
97+
9598 // Limit the number of blinded paths that are computed.
9699 const MAX_PAYMENT_PATHS : usize = 3 ;
97100
@@ -100,17 +103,20 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, ES: Deref, S: Deref,
100103 const MIN_PEER_CHANNELS : usize = 3 ;
101104
102105 let network_graph = self . network_graph . deref ( ) . read_only ( ) ;
103- let paths = first_hops. into_iter ( )
106+ let counterparty_channels = first_hops. into_iter ( )
104107 . filter ( |details| details. counterparty . features . supports_route_blinding ( ) )
105108 . filter ( |details| amount_msats <= details. inbound_capacity_msat )
106109 . filter ( |details| amount_msats >= details. inbound_htlc_minimum_msat . unwrap_or ( 0 ) )
107110 . filter ( |details| amount_msats <= details. inbound_htlc_maximum_msat . unwrap_or ( u64:: MAX ) )
108- . filter ( |details| network_graph
111+ // Limit to counterparties with announced channels
112+ . filter_map ( |details|
113+ network_graph
109114 . node ( & NodeId :: from_pubkey ( & details. counterparty . node_id ) )
110- . map ( |node_info| node_info. channels . len ( ) >= MIN_PEER_CHANNELS )
111- . unwrap_or ( false )
115+ . map ( |info| & info. channels [ ..] )
116+ . and_then ( |channels| ( channels. len ( ) >= MIN_PEER_CHANNELS ) . then ( || channels) )
117+ . map ( |channels| ( details, channels) )
112118 )
113- . filter_map ( |details| {
119+ . filter_map ( |( details, counterparty_channels ) | {
114120 let short_channel_id = match details. get_inbound_payment_scid ( ) {
115121 Some ( short_channel_id) => short_channel_id,
116122 None => return None ,
@@ -128,7 +134,7 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, ES: Deref, S: Deref,
128134 max_cltv_expiry : tlvs. payment_constraints . max_cltv_expiry + cltv_expiry_delta,
129135 htlc_minimum_msat : details. inbound_htlc_minimum_msat . unwrap_or ( 0 ) ,
130136 } ;
131- Some ( payment:: ForwardNode {
137+ let forward_node = payment:: ForwardNode {
132138 tlvs : ForwardTlvs {
133139 short_channel_id,
134140 payment_relay,
@@ -137,29 +143,88 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, ES: Deref, S: Deref,
137143 } ,
138144 node_id : details. counterparty . node_id ,
139145 htlc_maximum_msat : details. inbound_htlc_maximum_msat . unwrap_or ( u64:: MAX ) ,
140- } )
146+ } ;
147+ Some ( ( forward_node, counterparty_channels) )
148+ } ) ;
149+
150+ let three_hop_paths = counterparty_channels. clone ( )
151+ // Pair counterparties with their other channels
152+ . flat_map ( |( forward_node, counterparty_channels) |
153+ counterparty_channels
154+ . iter ( )
155+ . filter_map ( |scid| network_graph. channels ( ) . get_key_value ( scid) )
156+ . filter_map ( move |( scid, info) | info
157+ . as_directed_to ( & NodeId :: from_pubkey ( & forward_node. node_id ) )
158+ . map ( |( info, source) | ( source, * scid, info) )
159+ )
160+ . filter ( |( source, _, _) | * * source != recipient_node_id)
161+ . filter ( |( source, _, _) | network_graph
162+ . node ( source)
163+ . and_then ( |info| info. announcement_info . as_ref ( ) )
164+ . map ( |info| info. features . supports_route_blinding ( ) )
165+ . unwrap_or ( false )
166+ )
167+ . filter ( |( _, _, info) | amount_msats >= info. direction ( ) . htlc_minimum_msat )
168+ . filter ( |( _, _, info) | amount_msats <= info. direction ( ) . htlc_maximum_msat )
169+ . map ( move |( source, scid, info) | ( source, scid, info, forward_node. clone ( ) ) )
170+ )
171+ // Construct blinded paths where the counterparty's counterparty is the introduction
172+ // node:
173+ //
174+ // source --- info ---> counterparty --- counterparty_forward_node ---> recipient
175+ . filter_map ( |( introduction_node_id, scid, info, counterparty_forward_node) | {
176+ let htlc_minimum_msat = info. direction ( ) . htlc_minimum_msat ;
177+ let htlc_maximum_msat = info. direction ( ) . htlc_maximum_msat ;
178+ let payment_relay: PaymentRelay = match info. try_into ( ) {
179+ Ok ( payment_relay) => payment_relay,
180+ Err ( ( ) ) => return None ,
181+ } ;
182+ let payment_constraints = PaymentConstraints {
183+ max_cltv_expiry : payment_relay. cltv_expiry_delta as u32
184+ + counterparty_forward_node. tlvs . payment_constraints . max_cltv_expiry ,
185+ htlc_minimum_msat,
186+ } ;
187+ let introduction_forward_node = payment:: ForwardNode {
188+ tlvs : ForwardTlvs {
189+ short_channel_id : scid,
190+ payment_relay,
191+ payment_constraints,
192+ features : BlindedHopFeatures :: empty ( ) ,
193+ } ,
194+ node_id : introduction_node_id. as_pubkey ( ) . unwrap ( ) ,
195+ htlc_maximum_msat,
196+ } ;
197+ Some ( BlindedPath :: new_for_payment (
198+ & [ introduction_forward_node, counterparty_forward_node] , recipient,
199+ tlvs. clone ( ) , u64:: MAX , MIN_FINAL_CLTV_EXPIRY_DELTA , entropy_source, secp_ctx
200+ ) )
141201 } )
142- . map ( |forward_node| {
202+ . take ( MAX_PAYMENT_PATHS ) ;
203+
204+ let two_hop_paths = counterparty_channels
205+ . map ( |( forward_node, _) | {
143206 BlindedPath :: new_for_payment (
144207 & [ forward_node] , recipient, tlvs. clone ( ) , u64:: MAX , MIN_FINAL_CLTV_EXPIRY_DELTA ,
145- & * self . entropy_source , secp_ctx
208+ entropy_source, secp_ctx
146209 )
147210 } )
148- . take ( MAX_PAYMENT_PATHS )
149- . collect :: < Result < Vec < _ > , _ > > ( ) ;
150-
151- match paths {
152- Ok ( paths) if !paths. is_empty ( ) => Ok ( paths) ,
153- _ => {
154- if network_graph. nodes ( ) . contains_key ( & NodeId :: from_pubkey ( & recipient) ) {
155- BlindedPath :: one_hop_for_payment (
156- recipient, tlvs, MIN_FINAL_CLTV_EXPIRY_DELTA , & * self . entropy_source , secp_ctx
157- ) . map ( |path| vec ! [ path] )
158- } else {
159- Err ( ( ) )
160- }
161- } ,
162- }
211+ . take ( MAX_PAYMENT_PATHS ) ;
212+
213+ three_hop_paths
214+ . collect :: < Result < Vec < _ > , _ > > ( ) . ok ( )
215+ . and_then ( |paths| ( !paths. is_empty ( ) ) . then ( || paths) )
216+ . or_else ( || two_hop_paths. collect :: < Result < Vec < _ > , _ > > ( ) . ok ( ) )
217+ . and_then ( |paths| ( !paths. is_empty ( ) ) . then ( || paths) )
218+ . or_else ( || network_graph
219+ . node ( & NodeId :: from_pubkey ( & recipient) ) . ok_or ( ( ) )
220+ . and_then ( |_| BlindedPath :: one_hop_for_payment (
221+ recipient, tlvs, MIN_FINAL_CLTV_EXPIRY_DELTA , entropy_source, secp_ctx
222+ )
223+ )
224+ . map ( |path| vec ! [ path] )
225+ . ok ( )
226+ )
227+ . ok_or ( ( ) )
163228 }
164229}
165230
0 commit comments