@@ -92,6 +92,9 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, ES: Deref, S: Deref,
92
92
& self , recipient : PublicKey , first_hops : Vec < ChannelDetails > , tlvs : ReceiveTlvs ,
93
93
amount_msats : u64 , secp_ctx : & Secp256k1 < T >
94
94
) -> Result < Vec < ( BlindedPayInfo , BlindedPath ) > , ( ) > {
95
+ let entropy_source = & * self . entropy_source ;
96
+ let recipient_node_id = NodeId :: from_pubkey ( & recipient) ;
97
+
95
98
// Limit the number of blinded paths that are computed.
96
99
const MAX_PAYMENT_PATHS : usize = 3 ;
97
100
@@ -100,17 +103,20 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, ES: Deref, S: Deref,
100
103
const MIN_PEER_CHANNELS : usize = 3 ;
101
104
102
105
let network_graph = self . network_graph . deref ( ) . read_only ( ) ;
103
- let paths = first_hops. into_iter ( )
106
+ let counterparty_channels = first_hops. into_iter ( )
104
107
. filter ( |details| details. counterparty . features . supports_route_blinding ( ) )
105
108
. filter ( |details| amount_msats <= details. inbound_capacity_msat )
106
109
. filter ( |details| amount_msats >= details. inbound_htlc_minimum_msat . unwrap_or ( 0 ) )
107
110
. 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
109
114
. 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) )
112
118
)
113
- . filter_map ( |details| {
119
+ . filter_map ( |( details, counterparty_channels ) | {
114
120
let short_channel_id = match details. get_inbound_payment_scid ( ) {
115
121
Some ( short_channel_id) => short_channel_id,
116
122
None => return None ,
@@ -128,7 +134,7 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, ES: Deref, S: Deref,
128
134
max_cltv_expiry : tlvs. payment_constraints . max_cltv_expiry + cltv_expiry_delta,
129
135
htlc_minimum_msat : details. inbound_htlc_minimum_msat . unwrap_or ( 0 ) ,
130
136
} ;
131
- Some ( payment:: ForwardNode {
137
+ let forward_node = payment:: ForwardNode {
132
138
tlvs : ForwardTlvs {
133
139
short_channel_id,
134
140
payment_relay,
@@ -137,29 +143,88 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, ES: Deref, S: Deref,
137
143
} ,
138
144
node_id : details. counterparty . node_id ,
139
145
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
+ ) )
141
201
} )
142
- . map ( |forward_node| {
202
+ . take ( MAX_PAYMENT_PATHS ) ;
203
+
204
+ let two_hop_paths = counterparty_channels
205
+ . map ( |( forward_node, _) | {
143
206
BlindedPath :: new_for_payment (
144
207
& [ forward_node] , recipient, tlvs. clone ( ) , u64:: MAX , MIN_FINAL_CLTV_EXPIRY_DELTA ,
145
- & * self . entropy_source , secp_ctx
208
+ entropy_source, secp_ctx
146
209
)
147
210
} )
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 ( ( ) )
163
228
}
164
229
}
165
230
0 commit comments