From d4104c15aa204a51c3e15dfd6dfc3f631ccbc337 Mon Sep 17 00:00:00 2001 From: trueptolemy Date: Thu, 5 Sep 2019 22:44:19 +0800 Subject: [PATCH] pytest: Test `pay` can exclude error node --- tests/test_pay.py | 66 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/tests/test_pay.py b/tests/test_pay.py index d1981365f..50b7b1256 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -121,6 +121,72 @@ def test_pay_limits(node_factory): assert status[0]['strategy'] == "Initial attempt" +def test_pay_exclude_node(node_factory, bitcoind): + """Test excluding the node if there's the NODE-level error in the failure_code + """ + # FIXME: Remove our reliance on HTLCs failing on startup and the need for + # this plugin + opts = [{}, {'plugin': os.path.join(os.getcwd(), 'tests/plugins/fail_htlcs.py')}, {}] + l1, l2, l3 = node_factory.line_graph(3, opts=opts, wait_for_announce=True) + amount = 10**8 + + inv = l3.rpc.invoice(amount, "test1", 'description')['bolt11'] + with pytest.raises(RpcError): + l1.rpc.pay(inv) + + # It should have retried (once without routehint, too) + status = l1.rpc.call('paystatus', {'bolt11': inv})['pay'][0]['attempts'] + + # Excludes channel, then ignores routehint which includes that, then + # it excludes other channel. + assert len(status) == 2 + assert status[0]['strategy'] == "Initial attempt" + assert status[0]['failure']['data']['failcodename'] == 'WIRE_TEMPORARY_NODE_FAILURE' + assert status[1]['strategy'].startswith("Excluded node {}".format(l2.info['id'])) + assert 'failure' in status[1] + + # l1->l4->l5->l3 is the longer route. This makes sure this route won't be + # tried for the first pay attempt. + l4 = node_factory.get_node() + l5 = node_factory.get_node() + l1.rpc.connect(l4.info['id'], 'localhost', l4.port) + l4.rpc.connect(l5.info['id'], 'localhost', l5.port) + l5.rpc.connect(l3.info['id'], 'localhost', l3.port) + scid14 = l1.fund_channel(l4, 10**6, wait_for_active=False) + scid45 = l4.fund_channel(l5, 10**6, wait_for_active=False) + scid53 = l5.fund_channel(l3, 10**6, wait_for_active=False) + bitcoind.generate_block(5) + + l1.daemon.wait_for_logs([r'update for channel {}/0 now ACTIVE' + .format(scid14), + r'update for channel {}/1 now ACTIVE' + .format(scid14), + r'update for channel {}/0 now ACTIVE' + .format(scid45), + r'update for channel {}/1 now ACTIVE' + .format(scid45), + r'update for channel {}/0 now ACTIVE' + .format(scid53), + r'update for channel {}/1 now ACTIVE' + .format(scid53)]) + + inv = l3.rpc.invoice(amount, "test2", 'description')['bolt11'] + + # This `pay` will work + l1.rpc.pay(inv) + + # It should have retried (once without routehint, too) + status = l1.rpc.call('paystatus', {'bolt11': inv})['pay'][0]['attempts'] + + # Excludes channel, then ignores routehint which includes that, then + # it excludes other channel. + assert len(status) == 2 + assert status[0]['strategy'] == "Initial attempt" + assert status[0]['failure']['data']['failcodename'] == 'WIRE_TEMPORARY_NODE_FAILURE' + assert status[1]['strategy'].startswith("Excluded node {}".format(l2.info['id'])) + assert 'success' in status[1] + + def test_pay0(node_factory): """Test paying 0 amount """