@@ -19,7 +19,7 @@ use crate::blinded_path::BlindedPath;
19
19
use crate :: events:: { Event , MessageSendEventsProvider , PaymentPurpose } ;
20
20
use crate :: ln:: channelmanager:: { PaymentId , RecentPaymentDetails , Retry } ;
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:: { OffersMessage , ParsedOnionMessageContents , PeeledOnion } ;
@@ -38,6 +38,34 @@ macro_rules! expect_recent_payment {
38
38
}
39
39
}
40
40
41
+ fn connect_peers < ' a , ' b , ' c > ( node_a : & Node < ' a , ' b , ' c > , node_b : & Node < ' a , ' b , ' c > ) {
42
+ let node_id_a = node_a. node . get_our_node_id ( ) ;
43
+ let node_id_b = node_b. node . get_our_node_id ( ) ;
44
+
45
+ let init_a = Init {
46
+ features : node_a. init_features ( & node_id_b) ,
47
+ networks : None ,
48
+ remote_network_address : None ,
49
+ } ;
50
+ let init_b = Init {
51
+ features : node_b. init_features ( & node_id_a) ,
52
+ networks : None ,
53
+ remote_network_address : None ,
54
+ } ;
55
+
56
+ node_a. node . peer_connected ( & node_id_b, & init_b, true ) . unwrap ( ) ;
57
+ node_b. node . peer_connected ( & node_id_a, & init_a, false ) . unwrap ( ) ;
58
+ node_a. onion_messenger . peer_connected ( & node_id_b, & init_b, true ) . unwrap ( ) ;
59
+ node_b. onion_messenger . peer_connected ( & node_id_a, & init_a, false ) . unwrap ( ) ;
60
+ }
61
+
62
+ fn disconnect_peers < ' a , ' b , ' c > ( node_a : & Node < ' a , ' b , ' c > , node_b : & Node < ' a , ' b , ' c > ) {
63
+ node_a. node . peer_disconnected ( & node_b. node . get_our_node_id ( ) ) ;
64
+ node_b. node . peer_disconnected ( & node_a. node . get_our_node_id ( ) ) ;
65
+ node_a. onion_messenger . peer_disconnected ( & node_b. node . get_our_node_id ( ) ) ;
66
+ node_b. onion_messenger . peer_disconnected ( & node_a. node . get_our_node_id ( ) ) ;
67
+ }
68
+
41
69
fn route_bolt12_payment < ' a , ' b , ' c > (
42
70
node : & Node < ' a , ' b , ' c > , path : & [ & Node < ' a , ' b , ' c > ] , invoice : & Bolt12Invoice
43
71
) {
@@ -101,6 +129,94 @@ fn extract_invoice<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, message: &OnionMessage)
101
129
}
102
130
}
103
131
132
+ #[ test]
133
+ fn creates_and_pays_for_offer_using_two_hop_blinded_path ( ) {
134
+ let chanmon_cfgs = create_chanmon_cfgs ( 6 ) ;
135
+ let node_cfgs = create_node_cfgs ( 6 , & chanmon_cfgs) ;
136
+ let node_chanmgrs = create_node_chanmgrs ( 6 , & node_cfgs, & [ None ; 6 ] ) ;
137
+ let nodes = create_network ( 6 , & node_cfgs, & node_chanmgrs) ;
138
+
139
+ create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 1_000_000_000 ) ;
140
+ create_unannounced_chan_between_nodes_with_value ( & nodes, 2 , 3 , 10_000_000 , 1_000_000_000 ) ;
141
+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 10_000_000 , 1_000_000_000 ) ;
142
+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 4 , 10_000_000 , 1_000_000_000 ) ;
143
+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 5 , 10_000_000 , 1_000_000_000 ) ;
144
+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 4 , 10_000_000 , 1_000_000_000 ) ;
145
+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 5 , 10_000_000 , 1_000_000_000 ) ;
146
+
147
+ let alice = & nodes[ 0 ] ;
148
+ let alice_id = alice. node . get_our_node_id ( ) ;
149
+ let bob = & nodes[ 1 ] ;
150
+ let bob_id = bob. node . get_our_node_id ( ) ;
151
+ let charlie = & nodes[ 2 ] ;
152
+ let charlie_id = charlie. node . get_our_node_id ( ) ;
153
+ let david = & nodes[ 3 ] ;
154
+ let david_id = david. node . get_our_node_id ( ) ;
155
+
156
+ disconnect_peers ( alice, charlie) ;
157
+ disconnect_peers ( alice, david) ;
158
+ disconnect_peers ( alice, & nodes[ 4 ] ) ;
159
+ disconnect_peers ( alice, & nodes[ 5 ] ) ;
160
+
161
+ disconnect_peers ( david, bob) ;
162
+ disconnect_peers ( david, & nodes[ 4 ] ) ;
163
+ disconnect_peers ( david, & nodes[ 5 ] ) ;
164
+
165
+ let offer = alice. node
166
+ . create_offer_builder ( "coffee" . to_string ( ) ) . unwrap ( )
167
+ . amount_msats ( 10_000_000 )
168
+ . build ( ) . unwrap ( ) ;
169
+ assert_ne ! ( offer. signing_pubkey( ) , alice_id) ;
170
+ assert ! ( !offer. paths( ) . is_empty( ) ) ;
171
+ for path in offer. paths ( ) {
172
+ dbg ! ( alice_id) ;
173
+ dbg ! ( bob_id) ;
174
+ dbg ! ( charlie_id) ;
175
+ dbg ! ( david_id) ;
176
+ assert_eq ! ( path. introduction_node_id, bob_id) ;
177
+ }
178
+
179
+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
180
+ david. node . pay_for_offer ( & offer, None , None , None , payment_id, Retry :: Attempts ( 0 ) , None )
181
+ . unwrap ( ) ;
182
+ expect_recent_payment ! ( david, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
183
+
184
+ connect_peers ( david, bob) ;
185
+
186
+ let onion_message = david. onion_messenger . next_onion_message_for_peer ( bob_id) . unwrap ( ) ;
187
+ bob. onion_messenger . handle_onion_message ( & david_id, & onion_message) ;
188
+
189
+ connect_peers ( alice, charlie) ;
190
+
191
+ let onion_message = bob. onion_messenger . next_onion_message_for_peer ( alice_id) . unwrap ( ) ;
192
+ alice. onion_messenger . handle_onion_message ( & bob_id, & onion_message) ;
193
+
194
+ let ( invoice_request, reply_path) = extract_invoice_request ( alice, & onion_message) ;
195
+ assert_eq ! ( invoice_request. amount_msats( ) , None ) ;
196
+ assert_ne ! ( invoice_request. payer_id( ) , david_id) ;
197
+ assert_eq ! ( reply_path. unwrap( ) . introduction_node_id, charlie_id) ;
198
+
199
+ let onion_message = alice. onion_messenger . next_onion_message_for_peer ( charlie_id) . unwrap ( ) ;
200
+ charlie. onion_messenger . handle_onion_message ( & alice_id, & onion_message) ;
201
+
202
+ let onion_message = charlie. onion_messenger . next_onion_message_for_peer ( david_id) . unwrap ( ) ;
203
+ david. onion_messenger . handle_onion_message ( & charlie_id, & onion_message) ;
204
+
205
+ let invoice = extract_invoice ( david, & onion_message) ;
206
+ assert_eq ! ( invoice. amount_msats( ) , 10_000_000 ) ;
207
+ assert_ne ! ( invoice. signing_pubkey( ) , alice_id) ;
208
+ assert ! ( !invoice. payment_paths( ) . is_empty( ) ) ;
209
+ for ( _, path) in invoice. payment_paths ( ) {
210
+ assert_eq ! ( path. introduction_node_id, bob_id) ;
211
+ }
212
+
213
+ route_bolt12_payment ( david, & [ charlie, bob, alice] , & invoice) ;
214
+ expect_recent_payment ! ( david, RecentPaymentDetails :: Pending , payment_id) ;
215
+
216
+ claim_bolt12_payment ( david, & [ charlie, bob, alice] ) ;
217
+ expect_recent_payment ! ( david, RecentPaymentDetails :: Fulfilled , payment_id) ;
218
+ }
219
+
104
220
/// Checks that an offer can be paid through blinded paths and that ephemeral pubkeys are used
105
221
/// rather than exposing a node's pubkey. Since a direct connection is currently required, the
106
222
/// node's pubkey is instead used as the introduction node in any blinded paths.
0 commit comments