@@ -14,9 +14,10 @@ use bitcoin::hashes::Hash;
14
14
use bitcoin:: hashes:: sha256:: Hash as Sha256 ;
15
15
16
16
use crate :: blinded_path:: { BlindedHop , BlindedPath } ;
17
+ use crate :: blinded_path:: payment:: { ForwardNode , ForwardTlvs , PaymentConstraints , PaymentRelay , ReceiveTlvs } ;
17
18
use crate :: ln:: PaymentHash ;
18
19
use crate :: ln:: channelmanager:: { ChannelDetails , PaymentId } ;
19
- use crate :: ln:: features:: { Bolt11InvoiceFeatures , Bolt12InvoiceFeatures , ChannelFeatures , NodeFeatures } ;
20
+ use crate :: ln:: features:: { BlindedHopFeatures , Bolt11InvoiceFeatures , Bolt12InvoiceFeatures , ChannelFeatures , NodeFeatures } ;
20
21
use crate :: ln:: msgs:: { DecodeError , ErrorAction , LightningError , MAX_VALUE_MSAT } ;
21
22
use crate :: offers:: invoice:: { BlindedPayInfo , Bolt12Invoice } ;
22
23
use crate :: onion_message:: { DefaultMessageRouter , Destination , MessageRouter , OnionMessagePath } ;
@@ -82,6 +83,81 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized,
82
83
& random_seed_bytes
83
84
)
84
85
}
86
+
87
+ fn create_blinded_payment_paths <
88
+ ES : EntropySource + ?Sized , T : secp256k1:: Signing + secp256k1:: Verification
89
+ > (
90
+ & self , recipient : PublicKey , first_hops : Vec < ChannelDetails > , tlvs : ReceiveTlvs ,
91
+ amount_msats : u64 , entropy_source : & ES , secp_ctx : & Secp256k1 < T >
92
+ ) -> Result < Vec < ( BlindedPayInfo , BlindedPath ) > , ( ) > {
93
+ // Limit the number of blinded paths that are computed.
94
+ const MAX_PAYMENT_PATHS : usize = 3 ;
95
+
96
+ // Ensure peers have at least three channels so that it is more difficult to infer the
97
+ // recipient's node_id.
98
+ const MIN_PEER_CHANNELS : usize = 3 ;
99
+
100
+ let network_graph = self . network_graph . deref ( ) . read_only ( ) ;
101
+ let paths = first_hops. into_iter ( )
102
+ . filter ( |details| details. counterparty . features . supports_route_blinding ( ) )
103
+ . filter ( |details| amount_msats <= details. inbound_capacity_msat )
104
+ . filter ( |details| amount_msats >= details. inbound_htlc_minimum_msat . unwrap_or ( 0 ) )
105
+ . filter ( |details| amount_msats <= details. inbound_htlc_maximum_msat . unwrap_or ( 0 ) )
106
+ . filter ( |details| network_graph
107
+ . node ( & NodeId :: from_pubkey ( & details. counterparty . node_id ) )
108
+ . map ( |node_info| node_info. channels . len ( ) >= MIN_PEER_CHANNELS )
109
+ . unwrap_or ( false )
110
+ )
111
+ . filter_map ( |details| {
112
+ let short_channel_id = match details. get_inbound_payment_scid ( ) {
113
+ Some ( short_channel_id) => short_channel_id,
114
+ None => return None ,
115
+ } ;
116
+ let payment_relay: PaymentRelay = match details. counterparty . forwarding_info {
117
+ Some ( forwarding_info) => forwarding_info. into ( ) ,
118
+ None => return None ,
119
+ } ;
120
+
121
+ // Avoid exposing esoteric CLTV expiry deltas
122
+ let cltv_expiry_delta = match payment_relay. cltv_expiry_delta {
123
+ 0 ..=40 => 40u32 ,
124
+ 41 ..=80 => 80u32 ,
125
+ 81 ..=144 => 144u32 ,
126
+ 145 ..=216 => 216u32 ,
127
+ _ => return None ,
128
+ } ;
129
+
130
+ let payment_constraints = PaymentConstraints {
131
+ max_cltv_expiry : tlvs. payment_constraints . max_cltv_expiry + cltv_expiry_delta,
132
+ htlc_minimum_msat : details. inbound_htlc_minimum_msat . unwrap_or ( 0 ) ,
133
+ } ;
134
+ Some ( ForwardNode {
135
+ tlvs : ForwardTlvs {
136
+ short_channel_id,
137
+ payment_relay,
138
+ payment_constraints,
139
+ features : BlindedHopFeatures :: empty ( ) ,
140
+ } ,
141
+ node_id : details. counterparty . node_id ,
142
+ htlc_maximum_msat : details. inbound_htlc_maximum_msat . unwrap_or ( 0 ) ,
143
+ } )
144
+ } )
145
+ . map ( |forward_node| {
146
+ BlindedPath :: new_for_payment (
147
+ & [ forward_node] , recipient, tlvs. clone ( ) , u64:: MAX , entropy_source, secp_ctx
148
+ )
149
+ } )
150
+ . take ( MAX_PAYMENT_PATHS )
151
+ . collect :: < Result < Vec < _ > , _ > > ( ) ;
152
+
153
+ match paths {
154
+ Ok ( paths) if !paths. is_empty ( ) => Ok ( paths) ,
155
+ _ => {
156
+ BlindedPath :: one_hop_for_payment ( recipient, tlvs, entropy_source, secp_ctx)
157
+ . map ( |path| vec ! [ path] )
158
+ } ,
159
+ }
160
+ }
85
161
}
86
162
87
163
impl < G : Deref < Target = NetworkGraph < L > > + Clone , L : Deref , S : Deref , SP : Sized , Sc : ScoreLookUp < ScoreParams = SP > > MessageRouter for DefaultRouter < G , L , S , SP , Sc > where
@@ -129,6 +205,16 @@ pub trait Router: MessageRouter {
129
205
) -> Result < Route , LightningError > {
130
206
self . find_route ( payer, route_params, first_hops, inflight_htlcs)
131
207
}
208
+
209
+ /// Creates [`BlindedPath`]s for payment to the `recipient` node. The channels in `first_hops`
210
+ /// are assumed to be with the `recipient`'s peers. The payment secret and any constraints are
211
+ /// given in `tlvs`.
212
+ fn create_blinded_payment_paths <
213
+ ES : EntropySource + ?Sized , T : secp256k1:: Signing + secp256k1:: Verification
214
+ > (
215
+ & self , recipient : PublicKey , first_hops : Vec < ChannelDetails > , tlvs : ReceiveTlvs ,
216
+ amount_msats : u64 , entropy_source : & ES , secp_ctx : & Secp256k1 < T >
217
+ ) -> Result < Vec < ( BlindedPayInfo , BlindedPath ) > , ( ) > ;
132
218
}
133
219
134
220
/// [`ScoreLookUp`] implementation that factors in in-flight HTLC liquidity.
0 commit comments