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