Skip to content

Commit 8a54260

Browse files
authored
Merge pull request #923 from heyolaniran/feat/python_binding_test
Add python integration test for spontaneous keysend payments
2 parents 8dd06bf + b318ccd commit 8a54260

1 file changed

Lines changed: 104 additions & 50 deletions

File tree

bindings/python/src/ldk_node/test_ldk_node.py

Lines changed: 104 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import os
66
import re
77
import requests
8+
import socket
89

910
from ldk_node import *
1011

@@ -118,8 +119,68 @@ def expect_event(node, expected_event_type):
118119
assert isinstance(event, expected_event_type)
119120
print("EVENT:", event)
120121
node.event_handled()
121-
return event
122-
122+
return event
123+
124+
def find_two_free_ports():
125+
with socket.socket() as s1, socket.socket() as s2:
126+
s1.bind(("127.0.0.1", 0))
127+
s2.bind(("127.0.0.1",0))
128+
port_1 = s1.getsockname()[1]
129+
port_2 = s2.getsockname()[1]
130+
return port_1, port_2
131+
132+
def setup_two_nodes(esplora_endpoint):
133+
port_1, port_2 = find_two_free_ports()
134+
tmp_dir_1 = tempfile.TemporaryDirectory("_ldk_node_1")
135+
listening_addresses_1 = [f"127.0.0.1:{port_1}"]
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 = [f"127.0.0.1:{port_2}"]
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(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(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(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()
123184

124185
def assert_feature_helpers_return_bool(test_case, features):
125186
feature_methods = [
@@ -153,45 +214,57 @@ def setUp(self):
153214
esplora_endpoint = get_esplora_endpoint()
154215
mine_and_wait(esplora_endpoint, 1)
155216

156-
def test_channel_full_cycle(self):
217+
def test_spontaneous_payment(self):
218+
"""Spontaneous payment test in python: keysend after channel ready."""
157219
esplora_endpoint = get_esplora_endpoint()
158220

159-
## Setup Node 1
160-
tmp_dir_1 = tempfile.TemporaryDirectory("_ldk_node_1")
161-
print("TMP DIR 1:", tmp_dir_1.name)
221+
node_1, node_2, tmp_dir_1, tmp_dir_2, node_id_1, node_id_2, listening_addresses_2 = setup_two_nodes(esplora_endpoint)
222+
fund_nodes(node_1, node_2, esplora_endpoint)
223+
open_channel_and_wait_ready(node_1, node_2, node_id_2, listening_addresses_2[0], esplora_endpoint)
162224

163-
listening_addresses_1 = ["127.0.0.1:2323"]
164-
node_1 = setup_node(tmp_dir_1.name, esplora_endpoint, listening_addresses_1)
165-
node_1.start()
166-
node_id_1 = node_1.node_id()
167-
print("Node ID 1:", node_id_1)
225+
keysend_amount_msat = 2_500_000
226+
custom_tlvs = [CustomTlvRecord(type_num=13377331, value=bytes([1, 2, 3]))]
227+
keysend_payment_id = node_1.spontaneous_payment().send_with_custom_tlvs(
228+
keysend_amount_msat, node_id_2, None, custom_tlvs
229+
)
230+
231+
expect_event(node_1, Event.PAYMENT_SUCCESSFUL)
232+
received_event = expect_event(node_2, Event.PAYMENT_RECEIVED)
233+
234+
self.assertEqual(received_event.amount_msat, keysend_amount_msat)
235+
self.assertEqual(received_event.custom_records, custom_tlvs)
168236

169-
# Setup Node 2
170-
tmp_dir_2 = tempfile.TemporaryDirectory("_ldk_node_2")
171-
print("TMP DIR 2:", tmp_dir_2.name)
237+
sender_payment = node_1.payment(keysend_payment_id)
238+
receiver_payment = node_2.payment(keysend_payment_id)
239+
240+
self.assertIsNotNone(sender_payment)
241+
self.assertIsNotNone(receiver_payment)
242+
self.assertEqual(sender_payment.status, PaymentStatus.SUCCEEDED)
243+
self.assertEqual(sender_payment.direction, PaymentDirection.OUTBOUND)
244+
self.assertEqual(sender_payment.amount_msat, keysend_amount_msat)
245+
self.assertTrue(sender_payment.kind.is_spontaneous())
246+
247+
self.assertEqual(receiver_payment.status, PaymentStatus.SUCCEEDED)
248+
self.assertEqual(receiver_payment.direction, PaymentDirection.INBOUND)
249+
self.assertEqual(receiver_payment.amount_msat, keysend_amount_msat)
250+
self.assertTrue(receiver_payment.kind.is_spontaneous())
251+
252+
stop_and_cleanup(node_1, node_2, tmp_dir_1, tmp_dir_2)
253+
254+
def test_channel_full_cycle(self):
255+
esplora_endpoint = get_esplora_endpoint()
172256

173-
listening_addresses_2 = ["127.0.0.1:2324"]
174-
node_2 = setup_node(tmp_dir_2.name, esplora_endpoint, listening_addresses_2)
175-
node_2.start()
176-
node_id_2 = node_2.node_id()
257+
## Setup two nodes
258+
node_1, node_2, tmp_dir_1, tmp_dir_2, node_id_1, node_id_2, listening_addresses_2 = setup_two_nodes(esplora_endpoint)
259+
print("Node ID 1:", node_id_1)
177260
print("Node ID 2:", node_id_2)
178261

179262
# Check node-announcement features exposed through NodeStatus.
180263
for node in [node_1, node_2]:
181264
node_features_exposed(self, node.status().node_features)
182265

183-
address_1 = node_1.onchain_payment().new_address()
184-
txid_1 = send_to_address(address_1, 100000)
185-
address_2 = node_2.onchain_payment().new_address()
186-
txid_2 = send_to_address(address_2, 100000)
187-
188-
wait_for_tx(esplora_endpoint, txid_1)
189-
wait_for_tx(esplora_endpoint, txid_2)
190-
191-
mine_and_wait(esplora_endpoint, 6)
266+
fund_nodes(node_1, node_2, esplora_endpoint)
192267

193-
node_1.sync_wallets()
194-
node_2.sync_wallets()
195268

196269
spendable_balance_1 = node_1.list_balances().spendable_onchain_balance_sats
197270
spendable_balance_2 = node_2.list_balances().spendable_onchain_balance_sats
@@ -210,22 +283,9 @@ def test_channel_full_cycle(self):
210283
print("TOTAL 2:", total_balance_2)
211284
self.assertEqual(total_balance_2, 100000)
212285

213-
node_1.open_channel(node_id_2, listening_addresses_2[0], 50000, None, None)
214-
215-
216-
channel_pending_event_1 = expect_event(node_1, Event.CHANNEL_PENDING)
217-
channel_pending_event_2 = expect_event(node_2, Event.CHANNEL_PENDING)
218-
funding_txid = channel_pending_event_1.funding_txo.txid
219-
wait_for_tx(esplora_endpoint, funding_txid)
220-
mine_and_wait(esplora_endpoint, 6)
221-
222-
node_1.sync_wallets()
223-
node_2.sync_wallets()
224-
225-
channel_ready_event_1 = expect_event(node_1, Event.CHANNEL_READY)
286+
channel_ready_event_1, channel_ready_event_2, funding_txid = open_channel_and_wait_ready(node_1, node_2, node_id_2, listening_addresses_2[0], esplora_endpoint)
226287
print("funding_txo:", funding_txid)
227288

228-
channel_ready_event_2 = expect_event(node_2, Event.CHANNEL_READY)
229289

230290
# Check negotiated init features exposed through ChannelDetails.
231291
for channel in [node_1.list_channels()[0], node_2.list_channels()[0]]:
@@ -259,13 +319,7 @@ def test_channel_full_cycle(self):
259319
self.assertEqual(spendable_balance_after_close_2, 102500)
260320

261321
# Stop nodes
262-
node_1.stop()
263-
node_2.stop()
264-
265-
# Cleanup
266-
time.sleep(1) # Wait a sec so our logs can finish writing
267-
tmp_dir_1.cleanup()
268-
tmp_dir_2.cleanup()
322+
stop_and_cleanup(node_1, node_2, tmp_dir_1, tmp_dir_2)
269323

270324
if __name__ == '__main__':
271325
unittest.main()

0 commit comments

Comments
 (0)