@@ -90,6 +90,8 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized,
9090 & self , recipient : PublicKey , first_hops : Vec < ChannelDetails > , tlvs : ReceiveTlvs ,
9191 amount_msats : u64 , entropy_source : & ES , secp_ctx : & Secp256k1 < T >
9292 ) -> Result < Vec < ( BlindedPayInfo , BlindedPath ) > , ( ) > {
93+ let recipient_node_id = NodeId :: from_pubkey ( & recipient) ;
94+
9395 // Limit the number of blinded paths that are computed.
9496 const MAX_PAYMENT_PATHS : usize = 3 ;
9597
@@ -103,12 +105,15 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized,
103105 . filter ( |details| amount_msats <= details. inbound_capacity_msat )
104106 . filter ( |details| amount_msats >= details. inbound_htlc_minimum_msat . unwrap_or ( 0 ) )
105107 . filter ( |details| amount_msats <= details. inbound_htlc_maximum_msat . unwrap_or ( u64:: MAX ) )
106- . filter ( |details| network_graph
108+ // Limit to counterparties with announced channels
109+ . filter_map ( |details|
110+ network_graph
107111 . node ( & NodeId :: from_pubkey ( & details. counterparty . node_id ) )
108- . map ( |node_info| node_info. channels . len ( ) >= MIN_PEER_CHANNELS )
109- . unwrap_or ( false )
112+ . map ( |info| & info. channels [ ..] )
113+ . and_then ( |channels| ( channels. len ( ) >= MIN_PEER_CHANNELS ) . then ( || channels) )
114+ . map ( |channels| ( details, channels) )
110115 )
111- . filter_map ( |details| {
116+ . filter_map ( |( details, counterparty_channels ) | {
112117 let short_channel_id = match details. get_inbound_payment_scid ( ) {
113118 Some ( short_channel_id) => short_channel_id,
114119 None => return None ,
@@ -126,7 +131,7 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized,
126131 max_cltv_expiry : tlvs. payment_constraints . max_cltv_expiry + cltv_expiry_delta,
127132 htlc_minimum_msat : details. inbound_htlc_minimum_msat . unwrap_or ( 0 ) ,
128133 } ;
129- Some ( ForwardNode {
134+ let forward_node = ForwardNode {
130135 tlvs : ForwardTlvs {
131136 short_channel_id,
132137 payment_relay,
@@ -135,12 +140,59 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized,
135140 } ,
136141 node_id : details. counterparty . node_id ,
137142 htlc_maximum_msat : details. inbound_htlc_maximum_msat . unwrap_or ( u64:: MAX ) ,
138- } )
143+ } ;
144+ Some ( ( forward_node, counterparty_channels) )
139145 } )
140- . map ( |forward_node| {
141- BlindedPath :: new_for_payment (
142- & [ forward_node] , recipient, tlvs. clone ( ) , u64:: MAX , entropy_source, secp_ctx
143- )
146+ // Pair counterparties with their other channels
147+ . flat_map ( |( forward_node, counterparty_channels) |
148+ counterparty_channels
149+ . iter ( )
150+ . filter_map ( |scid| network_graph. channels ( ) . get_key_value ( scid) )
151+ . filter_map ( move |( scid, info) | info
152+ . as_directed_to ( & NodeId :: from_pubkey ( & forward_node. node_id ) )
153+ . map ( |( info, source) | ( source, * scid, info) )
154+ )
155+ . filter ( |( source, _, _) | * * source != recipient_node_id)
156+ . filter ( |( source, _, _) | network_graph
157+ . node ( source)
158+ . and_then ( |info| info. announcement_info . as_ref ( ) )
159+ . map ( |info| info. features . supports_route_blinding ( ) )
160+ . unwrap_or ( false )
161+ )
162+ . filter ( |( _, _, info) | amount_msats >= info. direction ( ) . htlc_minimum_msat )
163+ . filter ( |( _, _, info) | amount_msats <= info. direction ( ) . htlc_maximum_msat )
164+ . map ( move |( source, scid, info) | ( source, scid, info, forward_node. clone ( ) ) )
165+ )
166+ // Construct blinded paths where the counterparty's counterparty is the introduction
167+ // node:
168+ //
169+ // source --- info ---> counterparty --- counterparty_forward_node ---> recipient
170+ . filter_map ( |( introduction_node_id, scid, info, counterparty_forward_node) | {
171+ let htlc_minimum_msat = info. direction ( ) . htlc_minimum_msat ;
172+ let htlc_maximum_msat = info. direction ( ) . htlc_maximum_msat ;
173+ let payment_relay: PaymentRelay = match info. try_into ( ) {
174+ Ok ( payment_relay) => payment_relay,
175+ Err ( ( ) ) => return None ,
176+ } ;
177+ let payment_constraints = PaymentConstraints {
178+ max_cltv_expiry : payment_relay. cltv_expiry_delta as u32
179+ + counterparty_forward_node. tlvs . payment_constraints . max_cltv_expiry ,
180+ htlc_minimum_msat,
181+ } ;
182+ let introduction_forward_node = ForwardNode {
183+ tlvs : ForwardTlvs {
184+ short_channel_id : scid,
185+ payment_relay,
186+ payment_constraints,
187+ features : BlindedHopFeatures :: empty ( ) ,
188+ } ,
189+ node_id : introduction_node_id. as_pubkey ( ) . unwrap ( ) ,
190+ htlc_maximum_msat,
191+ } ;
192+ Some ( BlindedPath :: new_for_payment (
193+ & [ introduction_forward_node, counterparty_forward_node] , recipient,
194+ tlvs. clone ( ) , u64:: MAX , entropy_source, secp_ctx
195+ ) )
144196 } )
145197 . take ( MAX_PAYMENT_PATHS )
146198 . collect :: < Result < Vec < _ > , _ > > ( ) ;
0 commit comments