|
2 | 2 | from pyln.client import RpcError |
3 | 3 | from utils import ( |
4 | 4 | only_one, first_scid, GenChannel, generate_gossip_store, |
5 | | - TEST_NETWORK |
| 5 | + TEST_NETWORK, sync_blockheight, wait_for |
6 | 6 | ) |
7 | 7 | import os |
8 | 8 | import pytest |
@@ -415,3 +415,76 @@ def test_getroutes_auto_localchans(node_factory): |
415 | 415 | paths=[[{'short_channel_id': scid12, 'amount_msat': 102010, 'delay': 99 + 6 + 6}, |
416 | 416 | {'short_channel_id': '0x1x0', 'amount_msat': 102010, 'delay': 99 + 6 + 6}, |
417 | 417 | {'short_channel_id': '1x2x1', 'amount_msat': 101000, 'delay': 99 + 6}]]) |
| 418 | + |
| 419 | + |
| 420 | +def test_fees_dont_exceed_constraints(node_factory): |
| 421 | + l1 = node_factory.get_node(start=False) |
| 422 | + |
| 423 | + msat = 100000000 |
| 424 | + max_msat = int(msat * 0.45) |
| 425 | + # 0 has to use two paths (1 and 2) to reach 3. But we tell it 0->1 has limited capacity. |
| 426 | + gsfile, nodemap = generate_gossip_store([GenChannel(0, 1, capacity_sats=msat // 1000, forward=GenChannel.Half(propfee=10000)), |
| 427 | + GenChannel(0, 2, capacity_sats=msat // 1000, forward=GenChannel.Half(propfee=10000)), |
| 428 | + GenChannel(1, 3, capacity_sats=msat // 1000, forward=GenChannel.Half(propfee=10000)), |
| 429 | + GenChannel(2, 3, capacity_sats=msat // 1000, forward=GenChannel.Half(propfee=10000))]) |
| 430 | + |
| 431 | + # Set up l1 with this as the gossip_store |
| 432 | + shutil.copy(gsfile.name, os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, 'gossip_store')) |
| 433 | + l1.start() |
| 434 | + |
| 435 | + chan = only_one([c for c in l1.rpc.listchannels(source=nodemap[0])['channels'] if c['destination'] == nodemap[1]]) |
| 436 | + l1.rpc.askrene_inform_channel(layer='test_layers', |
| 437 | + short_channel_id=chan['short_channel_id'], |
| 438 | + direction=chan['direction'], |
| 439 | + maximum_msat=max_msat) |
| 440 | + |
| 441 | + routes = l1.rpc.getroutes(source=nodemap[0], |
| 442 | + destination=nodemap[3], |
| 443 | + amount_msat=msat, |
| 444 | + layers=['test_layers'], |
| 445 | + maxfee_msat=msat, |
| 446 | + final_cltv=99)['routes'] |
| 447 | + assert len(routes) == 2 |
| 448 | + for hop in routes[0]['path'] + routes[1]['path']: |
| 449 | + if hop['short_channel_id'] == chan['short_channel_id']: |
| 450 | + amount = hop['amount_msat'] |
| 451 | + assert amount <= max_msat |
| 452 | + |
| 453 | + |
| 454 | +def test_mpp_pay2(node_factory, bitcoind): |
| 455 | + l1, l2, l3 = node_factory.get_nodes(3) |
| 456 | + l1.fundwallet(10_000_000) |
| 457 | + l2.fundwallet(10_000_000) |
| 458 | + l1.rpc.connect(l2.info['id'], 'localhost', port=l2.port) |
| 459 | + l2.rpc.connect(l3.info['id'], 'localhost', port=l3.port) |
| 460 | + |
| 461 | + capacities = (100_000, 100_000, 200_000, 300_000, 400_000) |
| 462 | + for capacity in capacities: |
| 463 | + l1.rpc.fundchannel(l2.info["id"], capacity, mindepth=1) |
| 464 | + l2.rpc.fundchannel(l3.info["id"], capacity, mindepth=1) |
| 465 | + |
| 466 | + bitcoind.generate_block(1, wait_for_mempool=2) |
| 467 | + sync_blockheight(bitcoind, [l1, l2]) |
| 468 | + |
| 469 | + bitcoind.generate_block(5) |
| 470 | + wait_for(lambda: len(l1.rpc.listchannels()["channels"]) == 2 * 2 * len(capacities)) |
| 471 | + |
| 472 | + routes = l1.rpc.getroutes( |
| 473 | + source=l1.info["id"], |
| 474 | + destination=l3.info["id"], |
| 475 | + amount_msat=800_000_000, |
| 476 | + layers=["auto.localchans", "auto.sourcefree"], |
| 477 | + maxfee_msat=50_000_000, |
| 478 | + final_cltv=10, |
| 479 | + ) |
| 480 | + |
| 481 | + # Don't exceed spendable_msat |
| 482 | + maxes = {} |
| 483 | + for chan in l1.rpc.listpeerchannels()['channels']: |
| 484 | + maxes["{}/{}".format(chan['short_channel_id'], chan['direction'])] = chan['spendable_msat'] |
| 485 | + |
| 486 | + for r in routes['routes']: |
| 487 | + for p in r['path']: |
| 488 | + scidd = "{}/{}".format(p['short_channel_id'], p['direction']) |
| 489 | + if scidd in maxes: |
| 490 | + assert p['amount_msat'] <= maxes[scidd] |
0 commit comments