Browse Source

test_pay.py: Add test for blockheight disagreement.

travis-debug
ZmnSCPxj 5 years ago
committed by Christian Decker
parent
commit
72a24a2bdd
  1. 54
      tests/test_pay.py

54
tests/test_pay.py

@ -2744,3 +2744,57 @@ def test_createonion_limits(node_factory):
with pytest.raises(RpcError, match=r'Payloads exceed maximum onion packet size.'): with pytest.raises(RpcError, match=r'Payloads exceed maximum onion packet size.'):
hops[0]['payload'] += '01' hops[0]['payload'] += '01'
l1.rpc.createonion(hops=hops, assocdata="BB" * 32) l1.rpc.createonion(hops=hops, assocdata="BB" * 32)
@pytest.mark.xfail(strict=True)
@unittest.skipIf(not DEVELOPER, "needs use_shadow")
def test_blockheight_disagreement(node_factory, bitcoind, executor):
"""
While a payment is in-transit from payer to payee, a block
might be mined, so that the blockheight the payer used to
initiate the payment is no longer the blockheight when the
payee receives it.
This leads to a failure which *used* to be
`final_expiry_too_soon`, a non-permanent failure, but
which is *now* `incorrect_or_unknown_payment_details`,
a permanent failure.
`pay` treats permanent failures as, well, permanent, and
gives up on receiving such failure from the payee, but
this particular subcase of blockheight disagreement is
actually a non-permanent failure (the payer only needs
to synchronize to the same blockheight as the payee).
"""
l1, l2 = node_factory.line_graph(2)
sync_blockheight(bitcoind, [l1, l2])
# Arrange l1 to stop getting new blocks.
def no_more_blocks(req):
return {"result": None,
"error": {"code": -8, "message": "Block height out of range"}, "id": req['id']}
l1.daemon.rpcproxy.mock_rpc('getblockhash', no_more_blocks)
# Increase blockheight and make sure l2 knows it.
# Why 2? Because `pay` uses min_final_cltv_expiry + 1.
# But 2 blocks coming in close succession, plus slow
# forwarding nodes and block propagation, are still
# possible on the mainnet, thus this test.
bitcoind.generate_block(2)
sync_blockheight(bitcoind, [l2])
# Have l2 make an invoice.
inv = l2.rpc.invoice(1000, 'l', 'd')['bolt11']
# Have l1 pay l2
def pay(l1, inv):
l1.rpc.dev_pay(inv, use_shadow=False)
fut = executor.submit(pay, l1, inv)
# Make sure l1 sends out the HTLC.
l1.daemon.wait_for_logs([r'NEW:: HTLC LOCAL'])
# Unblock l1 from new blocks.
l1.daemon.rpcproxy.mock_rpc('getblockhash', None)
# pay command should complete without error
fut.result()

Loading…
Cancel
Save