Skip to content

Commit

Permalink
pytest: add more multi-part-payment tests.
Browse files Browse the repository at this point in the history
Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell committed Dec 3, 2019
1 parent 012b652 commit 911b53b
Showing 1 changed file with 73 additions and 0 deletions.
73 changes: 73 additions & 0 deletions tests/test_pay.py
Original file line number Diff line number Diff line change
Expand Up @@ -2645,3 +2645,76 @@ def test_partial_payment(node_factory, bitcoind, executor):
assert pay['status'] == 'complete'
assert pay['number_of_parts'] == 2
assert pay['amount_sent_msat'] == Millisatoshi(1002)


@unittest.skipIf(not EXPERIMENTAL_FEATURES, "needs parallel_id support")
def test_partial_payment_timeout(node_factory, bitcoind):
l1, l2 = node_factory.line_graph(2)

inv = l2.rpc.invoice(1000, 'inv', 'inv')
paysecret = l2.rpc.decodepay(inv['bolt11'])['payment_secret']

route = l1.rpc.getroute(l2.info['id'], 500, 1)['route']
l1.rpc.call('sendpay', [route, inv['payment_hash'], None, 1000, inv['bolt11'], paysecret, 1])

with pytest.raises(RpcError, match=r'WIRE_MPP_TIMEOUT'):
l1.rpc.call('waitsendpay', [inv['payment_hash'], 70 + TIMEOUT // 4, 1])

# We can still pay it normally.
l1.rpc.call('sendpay', [route, inv['payment_hash'], None, 1000, inv['bolt11'], paysecret, 1])
l1.rpc.call('sendpay', [route, inv['payment_hash'], None, 1000, inv['bolt11'], paysecret, 2])
l1.rpc.call('waitsendpay', [inv['payment_hash'], TIMEOUT, 1])
l1.rpc.call('waitsendpay', [inv['payment_hash'], TIMEOUT, 2])


@unittest.skipIf(not EXPERIMENTAL_FEATURES, "needs parallel_id support")
def test_partial_payment_restart(node_factory, bitcoind):
"""Test that we discard a set when the HTLC is lost"""
l1, l2, l3 = node_factory.line_graph(3, wait_for_announce=True,
opts=[{}]
+ [{'may_reconnect': True}] * 2)

inv = l3.rpc.invoice(1000, 'inv', 'inv')
paysecret = l3.rpc.decodepay(inv['bolt11'])['payment_secret']

route = l1.rpc.getroute(l3.info['id'], 500, 1)['route']

l1.rpc.call('sendpay', [route, inv['payment_hash'], None, 1000, inv['bolt11'], paysecret, 1])

wait_for(lambda: [f['status'] for f in l2.rpc.listforwards()['forwards']] == ['offered'])

# Restart, and make sure it's reconnected to l2.
l3.restart()
print(l2.rpc.listpeers())
wait_for(lambda: [p['connected'] for p in l2.rpc.listpeers()['peers']] == [True, True])

# Pay second part.
l1.rpc.call('sendpay', [route, inv['payment_hash'], None, 1000, inv['bolt11'], paysecret, 2])

l1.rpc.call('waitsendpay', [inv['payment_hash'], TIMEOUT, 1])
l1.rpc.call('waitsendpay', [inv['payment_hash'], TIMEOUT, 2])


@unittest.skipIf(not DEVELOPER, "needs dev-fail")
@unittest.skipIf(not EXPERIMENTAL_FEATURES, "needs parallel_id support")
def test_partial_payment_htlc_loss(node_factory, bitcoind):
"""Test that we discard a set when the HTLC is lost"""
l1, l2, l3 = node_factory.line_graph(3, wait_for_announce=True)

inv = l3.rpc.invoice(1000, 'inv', 'inv')
paysecret = l3.rpc.decodepay(inv['bolt11'])['payment_secret']

route = l1.rpc.getroute(l3.info['id'], 500, 1)['route']

l1.rpc.call('sendpay', [route, inv['payment_hash'], None, 1000, inv['bolt11'], paysecret, 1])
wait_for(lambda: [f['status'] for f in l2.rpc.listforwards()['forwards']] == ['offered'])

l2.rpc.dev_fail(l3.info['id'])

# Since HTLC is missing from commit (dust), it's closed as soon as l2 sees
# it onchain. l3 shouldn't crash though.
bitcoind.generate_block(1, wait_for_mempool=1)

with pytest.raises(RpcError,
match=r'WIRE_PERMANENT_CHANNEL_FAILURE \(reply from remote\)'):
l1.rpc.call('waitsendpay', [inv['payment_hash'], TIMEOUT, 1])

0 comments on commit 911b53b

Please sign in to comment.