Skip to content

Commit 229fc3f

Browse files
committed
xpay: make the xpay layer persistent.
As the first user of a persistent layer, this tripped tests which assumed the datastore would be empty! Signed-off-by: Rusty Russell <[email protected]>
1 parent c93153e commit 229fc3f

File tree

5 files changed

+57
-8
lines changed

5 files changed

+57
-8
lines changed

plugins/xpay/xpay.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,6 +1582,7 @@ static const char *init(struct command *init_cmd,
15821582
plugin_broken_cb,
15831583
"askrene-create-layer");
15841584
json_add_string(req->js, "layer", "xpay");
1585+
json_add_bool(req->js, "persistent", true);
15851586
send_outreq(req);
15861587

15871588
start_aging_timer(plugin);

tests/test_askrene.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,8 @@ def test_layers(node_factory):
294294

295295
def test_layer_persistence(node_factory):
296296
"""Test persistence of layers across restart"""
297-
l1, l2 = node_factory.line_graph(2, wait_for_announce=True)
297+
l1, l2 = node_factory.line_graph(2, wait_for_announce=True,
298+
opts={'disable-plugin': 'cln-xpay'})
298299

299300
assert l1.rpc.askrene_listlayers() == {'layers': []}
300301
with pytest.raises(RpcError, match="Unknown layer"):

tests/test_misc.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3509,7 +3509,8 @@ def test_datastore_escapeing(node_factory):
35093509

35103510

35113511
def test_datastore(node_factory):
3512-
l1 = node_factory.get_node()
3512+
# Suppress xpay, which makes a layer
3513+
l1 = node_factory.get_node(options={"disable-plugin": "cln-xpay"})
35133514

35143515
# Starts empty
35153516
assert l1.rpc.listdatastore() == {'datastore': []}
@@ -3623,7 +3624,8 @@ def test_datastore(node_factory):
36233624

36243625

36253626
def test_datastore_keylist(node_factory):
3626-
l1 = node_factory.get_node()
3627+
# Suppress xpay, which makes a layer
3628+
l1 = node_factory.get_node(options={"disable-plugin": "cln-xpay"})
36273629

36283630
# Starts empty
36293631
assert l1.rpc.listdatastore() == {'datastore': []}
@@ -3685,7 +3687,7 @@ def test_datastore_keylist(node_factory):
36853687

36863688

36873689
def test_datastoreusage(node_factory):
3688-
l1: LightningNode = node_factory.get_node()
3690+
l1: LightningNode = node_factory.get_node(options={"disable-plugin": "cln-xpay"})
36893691
assert l1.rpc.datastoreusage() == {'datastoreusage': {'key': '[]', 'total_bytes': 0}}
36903692

36913693
data = 'somedatatostoreinthedatastore' # len 29

tests/test_opening.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,10 @@ def test_v2_rbf_liquidity_ad(node_factory, bitcoind, chainparams):
576576

577577
l1, l2 = node_factory.get_nodes(2, opts=opts)
578578

579+
# Other plugins use datastore, but we want to make sure our own
580+
# data is cleared!
581+
empty_datastore = l1.rpc.listdatastore()
582+
579583
# what happens when we RBF?
580584
feerate = 2000
581585
amount = 500000
@@ -632,16 +636,16 @@ def test_v2_rbf_liquidity_ad(node_factory, bitcoind, chainparams):
632636
l1.rpc.openchannel_signed(chan_id, signed_psbt)
633637

634638
# There's data in the datastore now (l2 only)
635-
assert l1.rpc.listdatastore() == {'datastore': []}
639+
assert l1.rpc.listdatastore() == empty_datastore
636640
only_one(l2.rpc.listdatastore("funder/{}".format(chan_id))['datastore'])
637641

638642
# what happens when the channel opens?
639643
bitcoind.generate_block(6)
640644
l1.daemon.wait_for_log('to CHANNELD_NORMAL')
641645

642646
# Datastore should be cleaned up!
643-
assert l1.rpc.listdatastore() == {'datastore': []}
644-
wait_for(lambda: l2.rpc.listdatastore() == {'datastore': []})
647+
assert l1.rpc.listdatastore() == empty_datastore
648+
wait_for(lambda: l2.rpc.listdatastore() == empty_datastore)
645649

646650
# This should be the accepter's amount
647651
fundings = only_one(l1.rpc.listpeerchannels()['channels'])['funding']

tests/test_xpay.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ def test_xpay_fake_channeld(node_factory, bitcoind, chainparams):
229229
shaseed = subprocess.check_output(["tools/hsmtool", "dumpcommitments", l1.info['id'], "1", "0", hsmfile]).decode('utf-8').strip().partition(": ")[2]
230230
l1.rpc.dev_peer_shachain(l2.info['id'], shaseed)
231231

232+
failed_parts = []
232233
for n in range(0, 100):
233234
if n in (62, 76, 80, 97):
234235
continue
@@ -246,7 +247,47 @@ def test_xpay_fake_channeld(node_factory, bitcoind, chainparams):
246247
f"d=Paying node {n}",
247248
f"amount={AMOUNT}msat"]).decode('utf-8').strip()
248249
assert l1.rpc.decode(inv)['payee'] == nodeids[n]
249-
l1.rpc.xpay(inv)
250+
failed_parts.append(l1.rpc.xpay(inv)['failed_parts'])
251+
252+
# Should be no reservations left (clean up happens after return though)
253+
wait_for(lambda: l1.rpc.askrene_listreservations() == {'reservations': []})
254+
255+
# It should remember the information it learned across restarts!
256+
# FIXME: channeld_fakenet doesn't restart properly, so just redo xpay.
257+
layers = l1.rpc.askrene_listlayers()
258+
# Temporary layers should be gone.
259+
assert len(layers['layers']) == 1
260+
261+
l1.rpc.plugin_stop("cln-askrene")
262+
l1.rpc.plugin_start(os.path.join(os.getcwd(), 'plugins/cln-askrene'))
263+
layers_after = l1.rpc.askrene_listlayers()
264+
assert layers == layers_after
265+
266+
failed_parts_retry = []
267+
for n in range(0, 100):
268+
if n in (62, 76, 80, 97):
269+
continue
270+
271+
print(f"PAYING Node #{n}")
272+
273+
preimage_hex = bytes([n + 100]).hex() + '00' * 31
274+
hash_hex = sha256(bytes.fromhex(preimage_hex)).hexdigest()
275+
inv = subprocess.check_output(["devtools/bolt11-cli",
276+
"encode",
277+
n.to_bytes(length=8, byteorder=sys.byteorder).hex() + '01' * 24,
278+
f"p={hash_hex}",
279+
f"s={'00' * 32}",
280+
f"d=Paying node {n}",
281+
f"amount={AMOUNT}msat"]).decode('utf-8').strip()
282+
assert l1.rpc.decode(inv)['payee'] == nodeids[n]
283+
failed_parts_retry.append(l1.rpc.xpay(inv)['failed_parts'])
284+
285+
# At least some will have improved!
286+
assert failed_parts_retry != failed_parts
287+
288+
# Now, we should be as good *or better* than the first time, since we remembered!
289+
for p in zip(failed_parts_retry, failed_parts):
290+
assert p[0] <= p[1]
250291

251292

252293
def test_xpay_timeout(node_factory, executor):

0 commit comments

Comments
 (0)