@@ -130,6 +130,95 @@ def setUp(self):
130130 esplora_endpoint = get_esplora_endpoint ()
131131 mine_and_wait (esplora_endpoint , 1 )
132132
133+ def _setup_two_nodes (self , esplora_endpoint ):
134+ tmp_dir_1 = tempfile .TemporaryDirectory ("_ldk_node_1" )
135+ listening_addresses_1 = ["127.0.0.1:2323" ]
136+ node_1 = setup_node (tmp_dir_1 .name , esplora_endpoint , listening_addresses_1 )
137+ node_1 .start ()
138+ node_id_1 = node_1 .node_id ()
139+
140+ tmp_dir_2 = tempfile .TemporaryDirectory ("_ldk_node_2" )
141+ listening_addresses_2 = ["127.0.0.1:2324" ]
142+ node_2 = setup_node (tmp_dir_2 .name , esplora_endpoint , listening_addresses_2 )
143+ node_2 .start ()
144+ node_id_2 = node_2 .node_id ()
145+
146+ return node_1 , node_2 , tmp_dir_1 , tmp_dir_2 , node_id_1 , node_id_2 , listening_addresses_2
147+
148+ def _fund_nodes (self , node_1 , node_2 , esplora_endpoint , amount_sats = 100000 ):
149+ address_1 = node_1 .onchain_payment ().new_address ()
150+ txid_1 = send_to_address (address_1 , amount_sats )
151+ address_2 = node_2 .onchain_payment ().new_address ()
152+ txid_2 = send_to_address (address_2 , amount_sats )
153+
154+ wait_for_tx (esplora_endpoint , txid_1 )
155+ wait_for_tx (esplora_endpoint , txid_2 )
156+ mine_and_wait (esplora_endpoint , 6 )
157+
158+ node_1 .sync_wallets ()
159+ node_2 .sync_wallets ()
160+
161+ def _open_channel_and_wait_ready (self , node_1 , node_2 , node_id_2 , listening_address_2 , esplora_endpoint , channel_amount_sats = 50000 ):
162+ node_1 .open_channel (node_id_2 , listening_address_2 , channel_amount_sats , None , None )
163+
164+ channel_pending_event_1 = expect_event (node_1 , Event .CHANNEL_PENDING )
165+ expect_event (node_2 , Event .CHANNEL_PENDING )
166+
167+ funding_txid = channel_pending_event_1 .funding_txo .txid
168+ wait_for_tx (esplora_endpoint , funding_txid )
169+ mine_and_wait (esplora_endpoint , 6 )
170+
171+ node_1 .sync_wallets ()
172+ node_2 .sync_wallets ()
173+
174+ channel_ready_event_1 = expect_event (node_1 , Event .CHANNEL_READY )
175+ channel_ready_event_2 = expect_event (node_2 , Event .CHANNEL_READY )
176+ return channel_ready_event_1 , channel_ready_event_2 , funding_txid
177+
178+ def _stop_and_cleanup (self , node_1 , node_2 , tmp_dir_1 , tmp_dir_2 ):
179+ node_1 .stop ()
180+ node_2 .stop ()
181+ time .sleep (1 )
182+ tmp_dir_1 .cleanup ()
183+ tmp_dir_2 .cleanup ()
184+
185+ def test_spontaneous_payment (self ):
186+ """Spontaneous payment test in python: keysend after channel ready."""
187+ esplora_endpoint = get_esplora_endpoint ()
188+
189+ node_1 , node_2 , tmp_dir_1 , tmp_dir_2 , node_id_1 , node_id_2 , listening_addresses_2 = self ._setup_two_nodes (esplora_endpoint )
190+ self ._fund_nodes (node_1 , node_2 , esplora_endpoint )
191+ self ._open_channel_and_wait_ready (node_1 , node_2 , node_id_2 , listening_addresses_2 [0 ], esplora_endpoint )
192+
193+ keysend_amount_msat = 2_500_000
194+ custom_tlvs = [CustomTlvRecord (type_num = 13377331 , value = bytes ([1 , 2 , 3 ]))]
195+ keysend_payment_id = node_1 .spontaneous_payment ().send_with_custom_tlvs (
196+ keysend_amount_msat , node_id_2 , None , custom_tlvs
197+ )
198+
199+ expect_event (node_1 , Event .PAYMENT_SUCCESSFUL )
200+ received_event = expect_event (node_2 , Event .PAYMENT_RECEIVED )
201+
202+ self .assertEqual (received_event .amount_msat , keysend_amount_msat )
203+ self .assertEqual (received_event .custom_records , custom_tlvs )
204+
205+ sender_payment = node_1 .payment (keysend_payment_id )
206+ receiver_payment = node_2 .payment (keysend_payment_id )
207+
208+ self .assertIsNotNone (sender_payment )
209+ self .assertIsNotNone (receiver_payment )
210+ self .assertEqual (sender_payment .status , PaymentStatus .SUCCEEDED )
211+ self .assertEqual (sender_payment .direction , PaymentDirection .OUTBOUND )
212+ self .assertEqual (sender_payment .amount_msat , keysend_amount_msat )
213+ self .assertTrue (sender_payment .kind .is_spontaneous ())
214+
215+ self .assertEqual (receiver_payment .status , PaymentStatus .SUCCEEDED )
216+ self .assertEqual (receiver_payment .direction , PaymentDirection .INBOUND )
217+ self .assertEqual (receiver_payment .amount_msat , keysend_amount_msat )
218+ self .assertTrue (receiver_payment .kind .is_spontaneous ())
219+
220+ self ._stop_and_cleanup (node_1 , node_2 , tmp_dir_1 , tmp_dir_2 )
221+
133222 def test_channel_full_cycle (self ):
134223 esplora_endpoint = get_esplora_endpoint ()
135224
0 commit comments