mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-23 15:00:34 +01:00
tests/test_pay.py: Motivating scenario for round-robin routehinting.
This commit is contained in:
parent
8c763bb7be
commit
f50951a0d6
1 changed files with 98 additions and 1 deletions
|
@ -6,7 +6,7 @@ from pyln.client import RpcError, Millisatoshi
|
||||||
from pyln.proto.onion import TlvPayload
|
from pyln.proto.onion import TlvPayload
|
||||||
from utils import (
|
from utils import (
|
||||||
DEVELOPER, wait_for, only_one, sync_blockheight, TIMEOUT,
|
DEVELOPER, wait_for, only_one, sync_blockheight, TIMEOUT,
|
||||||
EXPERIMENTAL_FEATURES, env
|
EXPERIMENTAL_FEATURES, env, VALGRIND
|
||||||
)
|
)
|
||||||
import copy
|
import copy
|
||||||
import os
|
import os
|
||||||
|
@ -3373,3 +3373,100 @@ def test_mpp_waitblockheight_routehint_conflict(node_factory, bitcoind, executor
|
||||||
|
|
||||||
# pay command should complete without error
|
# pay command should complete without error
|
||||||
fut.result(TIMEOUT)
|
fut.result(TIMEOUT)
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipIf(VALGRIND, "runs 7 nodes")
|
||||||
|
@unittest.skipIf(not DEVELOPER, "channel setup very slow (~10 minutes) if not DEVELOPER")
|
||||||
|
@pytest.mark.slow_test
|
||||||
|
@pytest.mark.xfail(strict=True)
|
||||||
|
def test_mpp_interference_2(node_factory, bitcoind, executor):
|
||||||
|
'''
|
||||||
|
We create a "public network" that looks like so.
|
||||||
|
Each channel is perfectly balanced, with 7 * unit
|
||||||
|
funds on each side.
|
||||||
|
|
||||||
|
4 -- 5
|
||||||
|
| /|
|
||||||
|
| / |
|
||||||
|
| / |
|
||||||
|
|/ |
|
||||||
|
6 -- 7
|
||||||
|
|
||||||
|
l1 is the payee, who will later issue some invoices.
|
||||||
|
It arranges unpublished channels from the above public
|
||||||
|
network:
|
||||||
|
|
||||||
|
l5->l1: 7 * unit
|
||||||
|
l6->l1: 5 * unit
|
||||||
|
l4->l1: 3 * unit
|
||||||
|
l7->l1: 2 * unit
|
||||||
|
|
||||||
|
l2 and l3 are payers.
|
||||||
|
They create some unpublished channels to the public network:
|
||||||
|
|
||||||
|
l2->l4, l2->l6: 6 * unit each
|
||||||
|
l3->l7, l3->l6: 6 * unit each
|
||||||
|
|
||||||
|
Finally, l1 issues 6 * unit invoices, simultaneously, to l1 and l2.
|
||||||
|
Both of them perform `pay` simultaneously, in order to test if
|
||||||
|
they interfere with each other.
|
||||||
|
|
||||||
|
This test then tries to check if both of them can pay, given
|
||||||
|
that there is sufficient incoming capacity, and then some,
|
||||||
|
to the payee, and the public network is perfectly balanced
|
||||||
|
with more than sufficient capacity, as well.
|
||||||
|
'''
|
||||||
|
l1, l2, l3, l4, l5, l6, l7 = node_factory.get_nodes(7, opts={'feerates': (1000, 1000, 1000, 1000)})
|
||||||
|
|
||||||
|
# Unit
|
||||||
|
unit = Millisatoshi(11000 * 1000)
|
||||||
|
|
||||||
|
# Build the public network.
|
||||||
|
public_network = [l4.fundbalancedchannel(l5, unit * 14),
|
||||||
|
l4.fundbalancedchannel(l6, unit * 14),
|
||||||
|
l5.fundbalancedchannel(l6, unit * 14),
|
||||||
|
l5.fundbalancedchannel(l7, unit * 14),
|
||||||
|
l6.fundbalancedchannel(l7, unit * 14)]
|
||||||
|
|
||||||
|
# Build unpublished channels to the merchant l1.
|
||||||
|
l4.rpc.connect(l1.info['id'], 'localhost', l1.port)
|
||||||
|
l5.rpc.connect(l1.info['id'], 'localhost', l1.port)
|
||||||
|
l6.rpc.connect(l1.info['id'], 'localhost', l1.port)
|
||||||
|
l7.rpc.connect(l1.info['id'], 'localhost', l1.port)
|
||||||
|
# The order in which the routes are built should not matter so
|
||||||
|
# shuffle them.
|
||||||
|
incoming_builders = [lambda: l5.fund_channel(l1, int((unit * 7).to_satoshi()), announce_channel=False),
|
||||||
|
lambda: l6.fund_channel(l1, int((unit * 5).to_satoshi()), announce_channel=False),
|
||||||
|
lambda: l4.fund_channel(l1, int((unit * 3).to_satoshi()), announce_channel=False),
|
||||||
|
lambda: l7.fund_channel(l1, int((unit * 2).to_satoshi()), announce_channel=False)]
|
||||||
|
random.shuffle(incoming_builders)
|
||||||
|
for b in incoming_builders:
|
||||||
|
b()
|
||||||
|
|
||||||
|
# Build unpublished channels from the buyers l2 and l3.
|
||||||
|
l2.rpc.connect(l4.info['id'], 'localhost', l4.port)
|
||||||
|
l2.rpc.connect(l6.info['id'], 'localhost', l6.port)
|
||||||
|
l3.rpc.connect(l7.info['id'], 'localhost', l7.port)
|
||||||
|
l3.rpc.connect(l6.info['id'], 'localhost', l6.port)
|
||||||
|
l2.fund_channel(l4, int((unit * 6).to_satoshi()), announce_channel=False)
|
||||||
|
l2.fund_channel(l6, int((unit * 6).to_satoshi()), announce_channel=False)
|
||||||
|
l3.fund_channel(l7, int((unit * 6).to_satoshi()), announce_channel=False)
|
||||||
|
l3.fund_channel(l6, int((unit * 6).to_satoshi()), announce_channel=False)
|
||||||
|
|
||||||
|
# Now wait for the buyers to learn the entire public network.
|
||||||
|
bitcoind.generate_block(5)
|
||||||
|
for channel in public_network:
|
||||||
|
wait_for(lambda: len(l2.rpc.listchannels(channel)['channels']) >= 2)
|
||||||
|
wait_for(lambda: len(l3.rpc.listchannels(channel)['channels']) >= 2)
|
||||||
|
|
||||||
|
# Buyers check out some purchaseable stuff from the merchant.
|
||||||
|
i2 = l1.rpc.invoice(unit * 6, 'i2', 'i2')['bolt11']
|
||||||
|
i3 = l1.rpc.invoice(unit * 6, 'i3', 'i3')['bolt11']
|
||||||
|
|
||||||
|
# Pay simultaneously!
|
||||||
|
p2 = executor.submit(l2.rpc.pay, i2)
|
||||||
|
p3 = executor.submit(l3.rpc.pay, i3)
|
||||||
|
|
||||||
|
# Both payments should succeed.
|
||||||
|
p2.result(TIMEOUT)
|
||||||
|
p3.result(TIMEOUT)
|
||||||
|
|
Loading…
Add table
Reference in a new issue