|
1 | 1 | from fixtures import * # noqa: F401,F403 |
| 2 | +from hashlib import sha256 |
2 | 3 | from pyln.client import RpcError |
3 | 4 | from utils import ( |
4 | 5 | only_one, first_scid, GenChannel, generate_gossip_store, |
5 | | - sync_blockheight, wait_for |
| 6 | + sync_blockheight, wait_for, TEST_NETWORK, TIMEOUT |
6 | 7 | ) |
| 8 | +import os |
7 | 9 | import pytest |
8 | 10 | import subprocess |
9 | 11 | import time |
@@ -993,3 +995,64 @@ def test_real_data(node_factory, bitcoind): |
993 | 995 | best = n |
994 | 996 |
|
995 | 997 | assert (len(fees[best]), len(improved), total_first_fee, total_final_fee, percent_fee_reduction) == (8, 95, 6007785, 564997, 91) |
| 998 | + |
| 999 | + |
| 1000 | +def test_askrene_fake_channeld(node_factory, bitcoind): |
| 1001 | + outfile = tempfile.NamedTemporaryFile(prefix='gossip-store-') |
| 1002 | + nodeids = subprocess.check_output(['devtools/gossmap-compress', |
| 1003 | + 'decompress', |
| 1004 | + '--node-map=3301=022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d59', |
| 1005 | + 'tests/data/gossip-store-2024-09-22.compressed', |
| 1006 | + outfile.name]).decode('utf-8').splitlines() |
| 1007 | + AMOUNT = 100_000_000 |
| 1008 | + |
| 1009 | + # l2 will warn l1 about its invalid gossip: ignore. |
| 1010 | + # We throttle l1's gossip to avoid massive log spam. |
| 1011 | + l1, l2 = node_factory.line_graph(2, |
| 1012 | + # This is in sats, so 1000x amount we send. |
| 1013 | + fundamount=AMOUNT, |
| 1014 | + opts=[{'gossip_store_file': outfile.name, |
| 1015 | + 'subdaemon': 'channeld:../tests/plugins/channeld_fakenet', |
| 1016 | + 'allow_warning': True, |
| 1017 | + 'dev-throttle-gossip': None}, |
| 1018 | + {'allow_bad_gossip': True}]) |
| 1019 | + |
| 1020 | + # l1 needs to know l2's shaseed for the channel so it can make revocations |
| 1021 | + hsmfile = os.path.join(l2.daemon.lightning_dir, TEST_NETWORK, "hsm_secret") |
| 1022 | + # Needs peer node id and channel dbid (1, it's the first channel), prints out: |
| 1023 | + # "shaseed: xxxxxxx\n" |
| 1024 | + shaseed = subprocess.check_output(["tools/hsmtool", "dumpcommitments", l1.info['id'], "1", "0", hsmfile]).decode('utf-8').strip().partition(": ")[2] |
| 1025 | + l1.rpc.dev_peer_shachain(l2.info['id'], shaseed) |
| 1026 | + |
| 1027 | + for n in range(0, 100): |
| 1028 | + if n in (62, 76, 80, 97): |
| 1029 | + continue |
| 1030 | + |
| 1031 | + routes = l1.rpc.getroutes(source=l1.info['id'], |
| 1032 | + destination=nodeids[n], |
| 1033 | + amount_msat=AMOUNT, |
| 1034 | + layers=['auto.sourcefree', 'auto.localchans'], |
| 1035 | + maxfee_msat=AMOUNT, |
| 1036 | + final_cltv=18) |
| 1037 | + |
| 1038 | + preimage_hex = f'{n:02}' + '00' * 31 |
| 1039 | + hash_hex = sha256(bytes.fromhex(preimage_hex)).hexdigest() |
| 1040 | + |
| 1041 | + # Sendpay wants a different format, so we convert. |
| 1042 | + for i, r in enumerate(routes['routes']): |
| 1043 | + hops = [{'id': h['next_node_id'], |
| 1044 | + 'channel': h['short_channel_id_dir'].split('/')[0]} |
| 1045 | + for h in r['path']] |
| 1046 | + # delay and amount_msat for sendpay are amounts at *end* of hop, not start! |
| 1047 | + with_end = r['path'] + [{'amount_msat': r['amount_msat'], 'delay': r['final_cltv']}] |
| 1048 | + for n, h in enumerate(hops): |
| 1049 | + h['delay'] = with_end[n + 1]['delay'] |
| 1050 | + h['amount_msat'] = with_end[n + 1]['amount_msat'] |
| 1051 | + |
| 1052 | + l1.rpc.sendpay(hops, hash_hex, |
| 1053 | + amount_msat=AMOUNT, |
| 1054 | + payment_secret='00' * 32, |
| 1055 | + partid=i + 1, groupid=1) |
| 1056 | + |
| 1057 | + for i, _ in enumerate(routes['routes']): |
| 1058 | + assert l1.rpc.waitsendpay(hash_hex, timeout=TIMEOUT, partid=i + 1, groupid=1)['payment_preimage'] == preimage_hex |
0 commit comments