From 3643e1bd905b807dcf5bfdda036482f8a733319a Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 9 Oct 2018 19:16:52 +1030 Subject: [PATCH] pytest: add test for when an incoming fulfilled HTLC expires before outgoing. Usually, we only close an incoming HTLC once the outgoing HTLC is completely resolved. However, we short-cut this in the FULFILL case: we have the preimage, so might as well use it immediately (in fact, we wait for it to be committed, but we don't need to in theory). As a side-effect of this, our assumption that every outgoing HTLC has a corresponding incoming HTLC is incorrect, and this test (xfail) tickles that corner case. Signed-off-by: Rusty Russell --- tests/test_connection.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/test_connection.py b/tests/test_connection.py index b4a56c7c0..2086b8aff 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -1331,3 +1331,37 @@ def test_restart_multi_htlc_rexmit(node_factory, bitcoind, executor): # Payments will fail due to restart, but we can see results in listpayments. print(l1.rpc.listpayments()) wait_for(lambda: [p['status'] for p in l1.rpc.listpayments()['payments']] == ['complete', 'complete']) + + +@pytest.mark.xfail(strict=True) +@unittest.skipIf(not DEVELOPER, "needs dev-disconnect") +def test_fulfill_incoming_first(node_factory, bitcoind): + """Test that we handle the case where we completely resolve incoming htlc + before fulfilled outgoing htlc""" + + # We agree on fee change first, then add HTLC, then remove; stop after remove. + disconnects = ['+WIRE_COMMITMENT_SIGNED*3'] + # We manually reconnect l2 & l3, after 100 blocks; hence allowing manual + # reconnect, but disabling auto coneect, and massive cltv so 2/3 doesn't + # time out. + l1, l2, l3 = node_factory.line_graph(3, opts=[{}, + {'may_reconnect': True, + 'dev-no-reconnect': None}, + {'may_reconnect': True, + 'dev-no-reconnect': None, + 'disconnect': disconnects, + 'cltv-final': 200}], + announce=True) + + # This succeeds. + l1.rpc.pay(l3.rpc.invoice(200000000, 'test_fulfill_incoming_first', 'desc')['bolt11']) + + # l1 can shutdown, fine. + l1.rpc.close(l2.info['id']) + l1.wait_for_channel_onchain(l2.info['id']) + bitcoind.generate_block(100) + l2.daemon.wait_for_log('onchaind complete, forgetting peer') + + # Now, l2 should restore from DB fine, even though outgoing HTLC no longer + # has an incoming. + l2.restart()