17
17
use core:: time:: Duration ;
18
18
use crate :: blinded_path:: BlindedPath ;
19
19
use crate :: events:: { Event , MessageSendEventsProvider , PaymentPurpose } ;
20
- use crate :: ln:: channelmanager:: { PaymentId , RecentPaymentDetails , Retry } ;
20
+ use crate :: ln:: channelmanager:: { PaymentId , RecentPaymentDetails , Retry , self } ;
21
21
use crate :: ln:: functional_test_utils:: * ;
22
- use crate :: ln:: msgs:: { OnionMessage , OnionMessageHandler } ;
22
+ use crate :: ln:: msgs:: { ChannelMessageHandler , Init , OnionMessage , OnionMessageHandler } ;
23
23
use crate :: offers:: invoice:: Bolt12Invoice ;
24
24
use crate :: offers:: invoice_request:: InvoiceRequest ;
25
25
use crate :: onion_message:: messenger:: PeeledOnion ;
@@ -40,6 +40,36 @@ macro_rules! expect_recent_payment {
40
40
}
41
41
}
42
42
43
+ fn connect_peers < ' a , ' b , ' c > ( node_a : & Node < ' a , ' b , ' c > , node_b : & Node < ' a , ' b , ' c > ) {
44
+ let node_id_a = node_a. node . get_our_node_id ( ) ;
45
+ let node_id_b = node_b. node . get_our_node_id ( ) ;
46
+
47
+ let init_a = Init {
48
+ features : node_a. init_features ( & node_id_b) ,
49
+ networks : None ,
50
+ remote_network_address : None ,
51
+ } ;
52
+ let init_b = Init {
53
+ features : node_b. init_features ( & node_id_a) ,
54
+ networks : None ,
55
+ remote_network_address : None ,
56
+ } ;
57
+
58
+ node_a. node . peer_connected ( & node_id_b, & init_b, true ) . unwrap ( ) ;
59
+ node_b. node . peer_connected ( & node_id_a, & init_a, false ) . unwrap ( ) ;
60
+ node_a. onion_messenger . peer_connected ( & node_id_b, & init_b, true ) . unwrap ( ) ;
61
+ node_b. onion_messenger . peer_connected ( & node_id_a, & init_a, false ) . unwrap ( ) ;
62
+ }
63
+
64
+ fn disconnect_peers < ' a , ' b , ' c > ( node_a : & Node < ' a , ' b , ' c > , peers : & [ & Node < ' a , ' b , ' c > ] ) {
65
+ for node_b in peers {
66
+ node_a. node . peer_disconnected ( & node_b. node . get_our_node_id ( ) ) ;
67
+ node_b. node . peer_disconnected ( & node_a. node . get_our_node_id ( ) ) ;
68
+ node_a. onion_messenger . peer_disconnected ( & node_b. node . get_our_node_id ( ) ) ;
69
+ node_b. onion_messenger . peer_disconnected ( & node_a. node . get_our_node_id ( ) ) ;
70
+ }
71
+ }
72
+
43
73
fn route_bolt12_payment < ' a , ' b , ' c > (
44
74
node : & Node < ' a , ' b , ' c > , path : & [ & Node < ' a , ' b , ' c > ] , invoice : & Bolt12Invoice
45
75
) {
@@ -103,6 +133,175 @@ fn extract_invoice<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, message: &OnionMessage)
103
133
}
104
134
}
105
135
136
+ /// Checks that an offer can be paid through blinded paths and that ephemeral pubkeys are used
137
+ /// rather than exposing a node's pubkey.
138
+ #[ test]
139
+ fn creates_and_pays_for_offer_using_two_hop_blinded_path ( ) {
140
+ let mut accept_forward_cfg = test_default_channel_config ( ) ;
141
+ accept_forward_cfg. accept_forwards_to_priv_channels = true ;
142
+
143
+ let mut features = channelmanager:: provided_init_features ( & accept_forward_cfg) ;
144
+ features. set_onion_messages_optional ( ) ;
145
+ features. set_route_blinding_optional ( ) ;
146
+
147
+ let chanmon_cfgs = create_chanmon_cfgs ( 6 ) ;
148
+ let node_cfgs = create_node_cfgs ( 6 , & chanmon_cfgs) ;
149
+
150
+ * node_cfgs[ 1 ] . override_init_features . borrow_mut ( ) = Some ( features) ;
151
+
152
+ let node_chanmgrs = create_node_chanmgrs (
153
+ 6 , & node_cfgs, & [ None , Some ( accept_forward_cfg) , None , None , None , None ]
154
+ ) ;
155
+ let nodes = create_network ( 6 , & node_cfgs, & node_chanmgrs) ;
156
+
157
+ create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 1_000_000_000 ) ;
158
+ create_unannounced_chan_between_nodes_with_value ( & nodes, 2 , 3 , 10_000_000 , 1_000_000_000 ) ;
159
+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 10_000_000 , 1_000_000_000 ) ;
160
+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 4 , 10_000_000 , 1_000_000_000 ) ;
161
+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 5 , 10_000_000 , 1_000_000_000 ) ;
162
+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 4 , 10_000_000 , 1_000_000_000 ) ;
163
+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 5 , 10_000_000 , 1_000_000_000 ) ;
164
+
165
+ let ( alice, bob, charlie, david) = ( & nodes[ 0 ] , & nodes[ 1 ] , & nodes[ 2 ] , & nodes[ 3 ] ) ;
166
+ let alice_id = alice. node . get_our_node_id ( ) ;
167
+ let bob_id = bob. node . get_our_node_id ( ) ;
168
+ let charlie_id = charlie. node . get_our_node_id ( ) ;
169
+ let david_id = david. node . get_our_node_id ( ) ;
170
+
171
+ disconnect_peers ( alice, & [ charlie, david, & nodes[ 4 ] , & nodes[ 5 ] ] ) ;
172
+ disconnect_peers ( david, & [ bob, & nodes[ 4 ] , & nodes[ 5 ] ] ) ;
173
+
174
+ let offer = alice. node
175
+ . create_offer_builder ( "coffee" . to_string ( ) ) . unwrap ( )
176
+ . amount_msats ( 10_000_000 )
177
+ . build ( ) . unwrap ( ) ;
178
+ assert_ne ! ( offer. signing_pubkey( ) , alice_id) ;
179
+ assert ! ( !offer. paths( ) . is_empty( ) ) ;
180
+ for path in offer. paths ( ) {
181
+ assert_eq ! ( path. introduction_node_id, bob_id) ;
182
+ }
183
+
184
+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
185
+ david. node . pay_for_offer ( & offer, None , None , None , payment_id, Retry :: Attempts ( 0 ) , None )
186
+ . unwrap ( ) ;
187
+ expect_recent_payment ! ( david, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
188
+
189
+ connect_peers ( david, bob) ;
190
+
191
+ let onion_message = david. onion_messenger . next_onion_message_for_peer ( bob_id) . unwrap ( ) ;
192
+ bob. onion_messenger . handle_onion_message ( & david_id, & onion_message) ;
193
+
194
+ connect_peers ( alice, charlie) ;
195
+
196
+ let onion_message = bob. onion_messenger . next_onion_message_for_peer ( alice_id) . unwrap ( ) ;
197
+ alice. onion_messenger . handle_onion_message ( & bob_id, & onion_message) ;
198
+
199
+ let ( invoice_request, reply_path) = extract_invoice_request ( alice, & onion_message) ;
200
+ assert_eq ! ( invoice_request. amount_msats( ) , None ) ;
201
+ assert_ne ! ( invoice_request. payer_id( ) , david_id) ;
202
+ assert_eq ! ( reply_path. unwrap( ) . introduction_node_id, charlie_id) ;
203
+
204
+ let onion_message = alice. onion_messenger . next_onion_message_for_peer ( charlie_id) . unwrap ( ) ;
205
+ charlie. onion_messenger . handle_onion_message ( & alice_id, & onion_message) ;
206
+
207
+ let onion_message = charlie. onion_messenger . next_onion_message_for_peer ( david_id) . unwrap ( ) ;
208
+ david. onion_messenger . handle_onion_message ( & charlie_id, & onion_message) ;
209
+
210
+ let invoice = extract_invoice ( david, & onion_message) ;
211
+ assert_eq ! ( invoice. amount_msats( ) , 10_000_000 ) ;
212
+ assert_ne ! ( invoice. signing_pubkey( ) , alice_id) ;
213
+ assert ! ( !invoice. payment_paths( ) . is_empty( ) ) ;
214
+ for ( _, path) in invoice. payment_paths ( ) {
215
+ assert_eq ! ( path. introduction_node_id, bob_id) ;
216
+ }
217
+
218
+ route_bolt12_payment ( david, & [ charlie, bob, alice] , & invoice) ;
219
+ expect_recent_payment ! ( david, RecentPaymentDetails :: Pending , payment_id) ;
220
+
221
+ claim_bolt12_payment ( david, & [ charlie, bob, alice] ) ;
222
+ expect_recent_payment ! ( david, RecentPaymentDetails :: Fulfilled , payment_id) ;
223
+ }
224
+
225
+ /// Checks that a refund can be paid through blinded paths and that ephemeral pubkeys are used
226
+ /// rather than exposing a node's pubkey.
227
+ #[ test]
228
+ fn creates_and_pays_for_refund_using_two_hop_blinded_path ( ) {
229
+ let mut accept_forward_cfg = test_default_channel_config ( ) ;
230
+ accept_forward_cfg. accept_forwards_to_priv_channels = true ;
231
+
232
+ let mut features = channelmanager:: provided_init_features ( & accept_forward_cfg) ;
233
+ features. set_onion_messages_optional ( ) ;
234
+ features. set_route_blinding_optional ( ) ;
235
+
236
+ let chanmon_cfgs = create_chanmon_cfgs ( 6 ) ;
237
+ let node_cfgs = create_node_cfgs ( 6 , & chanmon_cfgs) ;
238
+
239
+ * node_cfgs[ 1 ] . override_init_features . borrow_mut ( ) = Some ( features) ;
240
+
241
+ let node_chanmgrs = create_node_chanmgrs (
242
+ 6 , & node_cfgs, & [ None , Some ( accept_forward_cfg) , None , None , None , None ]
243
+ ) ;
244
+ let nodes = create_network ( 6 , & node_cfgs, & node_chanmgrs) ;
245
+
246
+ create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 1_000_000_000 ) ;
247
+ create_unannounced_chan_between_nodes_with_value ( & nodes, 2 , 3 , 10_000_000 , 1_000_000_000 ) ;
248
+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 10_000_000 , 1_000_000_000 ) ;
249
+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 4 , 10_000_000 , 1_000_000_000 ) ;
250
+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 5 , 10_000_000 , 1_000_000_000 ) ;
251
+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 4 , 10_000_000 , 1_000_000_000 ) ;
252
+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 5 , 10_000_000 , 1_000_000_000 ) ;
253
+
254
+ let ( alice, bob, charlie, david) = ( & nodes[ 0 ] , & nodes[ 1 ] , & nodes[ 2 ] , & nodes[ 3 ] ) ;
255
+ let alice_id = alice. node . get_our_node_id ( ) ;
256
+ let bob_id = bob. node . get_our_node_id ( ) ;
257
+ let charlie_id = charlie. node . get_our_node_id ( ) ;
258
+ let david_id = david. node . get_our_node_id ( ) ;
259
+
260
+ disconnect_peers ( alice, & [ charlie, david, & nodes[ 4 ] , & nodes[ 5 ] ] ) ;
261
+ disconnect_peers ( david, & [ bob, & nodes[ 4 ] , & nodes[ 5 ] ] ) ;
262
+
263
+ let absolute_expiry = Duration :: from_secs ( u64:: MAX ) ;
264
+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
265
+ let refund = david. node
266
+ . create_refund_builder (
267
+ "refund" . to_string ( ) , 10_000_000 , absolute_expiry, payment_id, Retry :: Attempts ( 0 ) , None
268
+ )
269
+ . unwrap ( )
270
+ . build ( ) . unwrap ( ) ;
271
+ assert_eq ! ( refund. amount_msats( ) , 10_000_000 ) ;
272
+ assert_eq ! ( refund. absolute_expiry( ) , Some ( absolute_expiry) ) ;
273
+ assert_ne ! ( refund. payer_id( ) , david_id) ;
274
+ assert ! ( !refund. paths( ) . is_empty( ) ) ;
275
+ for path in refund. paths ( ) {
276
+ assert_eq ! ( path. introduction_node_id, charlie_id) ;
277
+ }
278
+ expect_recent_payment ! ( david, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
279
+
280
+ alice. node . request_refund_payment ( & refund) . unwrap ( ) ;
281
+
282
+ connect_peers ( alice, charlie) ;
283
+
284
+ let onion_message = alice. onion_messenger . next_onion_message_for_peer ( charlie_id) . unwrap ( ) ;
285
+ charlie. onion_messenger . handle_onion_message ( & alice_id, & onion_message) ;
286
+
287
+ let onion_message = charlie. onion_messenger . next_onion_message_for_peer ( david_id) . unwrap ( ) ;
288
+ david. onion_messenger . handle_onion_message ( & charlie_id, & onion_message) ;
289
+
290
+ let invoice = extract_invoice ( david, & onion_message) ;
291
+ assert_eq ! ( invoice. amount_msats( ) , 10_000_000 ) ;
292
+ assert_ne ! ( invoice. signing_pubkey( ) , alice_id) ;
293
+ assert ! ( !invoice. payment_paths( ) . is_empty( ) ) ;
294
+ for ( _, path) in invoice. payment_paths ( ) {
295
+ assert_eq ! ( path. introduction_node_id, bob_id) ;
296
+ }
297
+
298
+ route_bolt12_payment ( david, & [ charlie, bob, alice] , & invoice) ;
299
+ expect_recent_payment ! ( david, RecentPaymentDetails :: Pending , payment_id) ;
300
+
301
+ claim_bolt12_payment ( david, & [ charlie, bob, alice] ) ;
302
+ expect_recent_payment ! ( david, RecentPaymentDetails :: Fulfilled , payment_id) ;
303
+ }
304
+
106
305
/// Checks that an offer can be paid through a one-hop blinded path and that ephemeral pubkeys are
107
306
/// used rather than exposing a node's pubkey. However, the node's pubkey is still used as the
108
307
/// introduction node of the blinded path.
0 commit comments