@@ -90,6 +90,8 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized,
90
90
& self , recipient : PublicKey , first_hops : Vec < ChannelDetails > , tlvs : ReceiveTlvs ,
91
91
amount_msats : u64 , entropy_source : & ES , secp_ctx : & Secp256k1 < T >
92
92
) -> Result < Vec < ( BlindedPayInfo , BlindedPath ) > , ( ) > {
93
+ let recipient_node_id = NodeId :: from_pubkey ( & recipient) ;
94
+
93
95
// Limit the number of blinded paths that are computed.
94
96
const MAX_PAYMENT_PATHS : usize = 3 ;
95
97
@@ -98,37 +100,88 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized,
98
100
const MIN_PEER_CHANNELS : usize = 3 ;
99
101
100
102
let network_graph = self . network_graph . deref ( ) . read_only ( ) ;
101
- first_hops. into_iter ( )
102
- . filter ( |details| details. is_public )
103
+ first_hops. iter ( )
103
104
. filter ( |details| details. counterparty . features . supports_route_blinding ( ) )
104
105
. filter ( |details| amount_msats <= details. inbound_capacity_msat )
105
106
. filter ( |details| amount_msats >= details. inbound_htlc_minimum_msat . unwrap_or ( 0 ) )
106
107
. filter ( |details| amount_msats <= details. inbound_htlc_maximum_msat . unwrap_or ( 0 ) )
107
- . filter ( |details| network_graph
108
- . node ( & NodeId :: from_pubkey ( & details. counterparty . node_id ) )
109
- . map ( |node_info| node_info. channels . len ( ) >= MIN_PEER_CHANNELS )
110
- . unwrap_or ( false )
108
+ . map ( |details| ( details, NodeId :: from_pubkey ( & details. counterparty . node_id ) ) )
109
+ // Limit to counterparties with announced channels
110
+ . filter_map ( |( details, counterparty_node_id) |
111
+ network_graph
112
+ . node ( & counterparty_node_id)
113
+ . map ( |info| & info. channels [ ..] )
114
+ . and_then ( |channels| ( channels. len ( ) >= MIN_PEER_CHANNELS ) . then ( || channels) )
115
+ . map ( |channels| ( details, counterparty_node_id, channels) )
116
+ )
117
+ // Pair counterparties with their other channels
118
+ . flat_map ( |( details, counterparty_node_id, counterparty_channels) |
119
+ counterparty_channels
120
+ . iter ( )
121
+ . filter_map ( |scid| network_graph. channels ( ) . get_key_value ( scid) )
122
+ . filter_map ( move |( scid, info) | info
123
+ . as_directed_to ( & counterparty_node_id)
124
+ . map ( |( info, source) | ( source, * scid, info) )
125
+ )
126
+ . filter ( |( source, _, _) | * * source != recipient_node_id)
127
+ . filter ( |( source, _, _) | network_graph
128
+ . node ( source)
129
+ . and_then ( |info| info. announcement_info . as_ref ( ) )
130
+ . map ( |info| info. features . supports_route_blinding ( ) )
131
+ . unwrap_or ( false )
132
+ )
133
+ . filter ( |( _, _, info) | amount_msats >= info. direction ( ) . htlc_minimum_msat )
134
+ . filter ( |( _, _, info) | amount_msats <= info. direction ( ) . htlc_maximum_msat )
135
+ . map ( move |( source, scid, info) | ( source, scid, info, details) )
111
136
)
112
- . map ( |details| {
113
- let short_channel_id = details. get_inbound_payment_scid ( ) . unwrap ( ) ;
114
- let payment_relay: PaymentRelay = details. counterparty . forwarding_info . unwrap ( ) . into ( ) ;
115
- let payment_constraints = PaymentConstraints {
116
- max_cltv_expiry : tlvs. payment_constraints . max_cltv_expiry
117
- + payment_relay. cltv_expiry_delta as u32 ,
118
- htlc_minimum_msat : details. inbound_htlc_minimum_msat . unwrap_or ( 0 ) ,
137
+ // Construct blinded paths where the counterparty's counterparty is the introduction
138
+ // node:
139
+ //
140
+ // source --- info ---> counterparty --- details ---> recipient
141
+ . map ( |( introduction_node_id, scid, info, details) | {
142
+ let counterparty_forward_node = {
143
+ let short_channel_id = details. get_inbound_payment_scid ( ) . unwrap ( ) ;
144
+ let payment_relay: PaymentRelay =
145
+ details. counterparty . forwarding_info . clone ( ) . unwrap ( ) . into ( ) ;
146
+ let payment_constraints = PaymentConstraints {
147
+ max_cltv_expiry : payment_relay. cltv_expiry_delta as u32
148
+ + tlvs. payment_constraints . max_cltv_expiry ,
149
+ htlc_minimum_msat : details. inbound_htlc_minimum_msat . unwrap_or ( 0 ) ,
150
+ } ;
151
+ ForwardNode {
152
+ tlvs : ForwardTlvs {
153
+ short_channel_id,
154
+ payment_relay,
155
+ payment_constraints,
156
+ features : BlindedHopFeatures :: empty ( ) ,
157
+ } ,
158
+ node_id : details. counterparty . node_id ,
159
+ htlc_maximum_msat : details. inbound_htlc_maximum_msat . unwrap_or ( 0 ) ,
160
+ }
119
161
} ;
120
- let forward_node = ForwardNode {
121
- tlvs : ForwardTlvs {
122
- short_channel_id,
123
- payment_relay,
124
- payment_constraints,
125
- features : BlindedHopFeatures :: empty ( ) ,
126
- } ,
127
- node_id : details. counterparty . node_id ,
128
- htlc_maximum_msat : details. inbound_htlc_maximum_msat . unwrap_or ( 0 ) ,
162
+ let introduction_forward_node = {
163
+ let htlc_minimum_msat = info. direction ( ) . htlc_minimum_msat ;
164
+ let htlc_maximum_msat = info. direction ( ) . htlc_maximum_msat ;
165
+ let payment_relay: PaymentRelay = info. into ( ) ;
166
+ let payment_constraints = PaymentConstraints {
167
+ max_cltv_expiry : payment_relay. cltv_expiry_delta as u32
168
+ + counterparty_forward_node. tlvs . payment_constraints . max_cltv_expiry ,
169
+ htlc_minimum_msat,
170
+ } ;
171
+ ForwardNode {
172
+ tlvs : ForwardTlvs {
173
+ short_channel_id : scid,
174
+ payment_relay,
175
+ payment_constraints,
176
+ features : BlindedHopFeatures :: empty ( ) ,
177
+ } ,
178
+ node_id : introduction_node_id. as_pubkey ( ) . unwrap ( ) ,
179
+ htlc_maximum_msat,
180
+ }
129
181
} ;
130
182
BlindedPath :: new_for_payment (
131
- & [ forward_node] , recipient, tlvs. clone ( ) , u64:: MAX , entropy_source, secp_ctx
183
+ & [ introduction_forward_node, counterparty_forward_node] , recipient,
184
+ tlvs. clone ( ) , u64:: MAX , entropy_source, secp_ctx
132
185
)
133
186
} )
134
187
. take ( MAX_PAYMENT_PATHS )
0 commit comments