From 4dca8cf7e52529941c49bb55058138a76645a6d3 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 29 Oct 2025 13:45:22 +1030 Subject: [PATCH] pytest: test for xpay waiting when the destination complains about blockheight. Signed-off-by: Rusty Russell --- tests/test_xpay.py | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/test_xpay.py b/tests/test_xpay.py index 71e6e8bc6..2b94dcc1b 100644 --- a/tests/test_xpay.py +++ b/tests/test_xpay.py @@ -1018,3 +1018,42 @@ def test_xpay_bip353(node_factory): node_factory.join_nodes([l2, l1]) l2.rpc.xpay('fake@fake.com', 100) + + +@pytest.mark.xfail(strict=True) +def test_xpay_blockheight_mismatch(node_factory, bitcoind, executor): + """We should wait a (reasonable) amount if the final node gives us a blockheight that would explain our failure.""" + l1, l2, l3 = node_factory.line_graph(3, wait_for_announce=True) + sync_blockheight(bitcoind, [l1, l2, l3]) + + # Pin `send` at the current height. by not returning the next + # blockhash. This error is special-cased not to count as the + # backend failing since it is used to poll for the next block. + def mock_getblockhash(req): + return { + "id": req['id'], + "error": { + "code": -8, + "message": "Block height out of range" + } + } + + l1.daemon.rpcproxy.mock_rpc('getblockhash', mock_getblockhash) + bitcoind.generate_block(4) + sync_blockheight(bitcoind, [l2, l3]) + l1_height = l1.rpc.getinfo()['blockheight'] + l3_height = l3.rpc.getinfo()['blockheight'] + + inv = l3.rpc.invoice(42, 'lbl', 'desc')['bolt11'] + + # This will wait, then fail. + with pytest.raises(RpcError, match=f'Timed out waiting for blockheight {l3_height}'): + l1.rpc.xpay(invstring=inv, retry_for=10) + + # This will succeed, because we wait for the blocks. + fut = executor.submit(l1.rpc.xpay, invstring=inv, retry_for=60) + l1.daemon.wait_for_log(fr"Our blockheight may be too low: waiting .* seconds for height {l3_height} \(we are at {l1_height}\)") + + # Now let it catch up, and it will retry, and succeed. + l1.daemon.rpcproxy.mock_rpc('getblockhash') + fut.result(TIMEOUT)