|
6 | 6 |
|
7 | 7 | from test_base import TestBase |
8 | 8 |
|
9 | | -from warnet.cli.process import run_command |
| 9 | +from warnet.process import stream_command |
10 | 10 |
|
11 | 11 |
|
12 | 12 | class LNTest(TestBase): |
13 | 13 | def __init__(self): |
14 | 14 | super().__init__() |
15 | | - self.network_dir = Path(os.path.dirname(__file__)) / "data" / "ln" |
| 15 | + self.graph_file = Path(os.path.dirname(__file__)) / "data" / "LN_10.json" |
| 16 | + self.imported_network_dir = self.tmpdir / "imported_network" |
| 17 | + self.scen_dir = Path(os.path.dirname(__file__)).parent / "resources" / "scenarios" |
16 | 18 |
|
17 | 19 | def run_test(self): |
18 | 20 | try: |
| 21 | + self.import_network() |
19 | 22 | self.setup_network() |
20 | 23 | self.run_ln_init_scenario() |
21 | 24 | self.test_channel_policies() |
22 | | - self.test_ln_payment_0_to_2() |
23 | | - self.test_ln_payment_2_to_0() |
24 | | - # self.test_simln() |
| 25 | + self.test_payments() |
25 | 26 | finally: |
26 | 27 | self.cleanup() |
27 | 28 |
|
| 29 | + def import_network(self): |
| 30 | + self.log.info("Importing network graph from JSON...") |
| 31 | + res = self.warnet(f"import-network {self.graph_file} {self.imported_network_dir}") |
| 32 | + self.log.info(f"\n{res}") |
| 33 | + |
28 | 34 | def setup_network(self): |
29 | | - self.log.info("Setting up network") |
30 | | - self.log.info(self.warcli(f"network deploy {self.network_dir}")) |
| 35 | + self.log.info("Setting up network...") |
| 36 | + self.log.info(self.warnet(f"deploy {self.imported_network_dir}")) |
31 | 37 | self.wait_for_all_tanks_status(target="running") |
32 | | - self.wait_for_all_edges() |
33 | | - |
34 | | - def get_cb_forwards(self, pod: str): |
35 | | - cmd = f"kubectl exec {pod} -- wget -q -O - 127.0.0.1:9235/api/forwarding_history" |
36 | | - res = run_command(cmd) |
37 | | - return json.loads(res) |
38 | 38 |
|
39 | 39 | def run_ln_init_scenario(self): |
40 | 40 | self.log.info("Running LN Init scenario") |
41 | | - self.warnet("bitcoin rpc tank-0000 getblockcount") |
42 | | - self.warnet("scenarios run ln_init") |
| 41 | + stream_command(f"warnet run {self.scen_dir / 'ln_init.py'} --debug") |
43 | 42 | self.wait_for_all_scenarios() |
44 | 43 |
|
45 | 44 | def test_channel_policies(self): |
46 | 45 | self.log.info("Ensuring node-level channel policy settings") |
47 | | - node2pub, node2host = json.loads(self.warnet("ln rpc tank-0002-ln getinfo"))["uris"][ |
48 | | - 0 |
49 | | - ].split("@") |
50 | | - chan_id = json.loads(self.warnet("ln rpc tank-0002-ln listchannels"))["channels"][0][ |
51 | | - "chan_id" |
52 | | - ] |
53 | | - chan = json.loads(self.warnet(f"ln rpc tank-0002-ln getchaninfo {chan_id}")) |
54 | | - |
55 | | - # node_1 or node_2 is tank 2 with its non-default --bitcoin.timelockdelta=33 |
56 | | - if chan["node1_policy"]["time_lock_delta"] != 33: |
57 | | - assert ( |
58 | | - chan["node2_policy"]["time_lock_delta"] == 33 |
59 | | - ), "Expected time_lock_delta to be 33" |
60 | | - |
61 | | - self.log.info("Ensuring no circuit breaker forwards yet") |
62 | | - assert ( |
63 | | - len(self.get_cb_forwards("tank-0001-ln")["forwards"]) == 0 |
64 | | - ), "Expected no circuit breaker forwards" |
65 | | - |
66 | | - def test_ln_payment_0_to_2(self): |
67 | | - self.log.info("Test LN payment from 0 -> 2") |
68 | | - inv = json.loads(self.warnet("ln rpc tank-0002-ln addinvoice --amt=2000"))[ |
69 | | - "payment_request" |
70 | | - ] |
71 | | - self.log.info(f"Got invoice from node tank-0002-ln: {inv}") |
72 | | - self.log.info("Paying invoice from node 0...") |
73 | | - self.log.info(self.warnet(f"ln rpc tank-0000-ln payinvoice -f {inv}")) |
74 | | - |
75 | | - self.wait_for_predicate(self.check_invoice_settled) |
76 | | - |
77 | | - self.log.info("Ensuring channel-level channel policy settings: source") |
78 | | - payment = json.loads(self.warnet("ln rpc tank-0000-ln listpayments"))["payments"][0] |
79 | | - assert ( |
80 | | - payment["fee_msat"] == "5506" |
81 | | - ), f"Expected fee_msat to be 5506, got {payment['fee_msat']}" |
82 | | - |
83 | | - self.log.info("Ensuring circuit breaker tracked payment") |
84 | | - assert ( |
85 | | - len(self.get_cb_forwards("tank-0001-ln")["forwards"]) == 1 |
86 | | - ), "Expected one circuit breaker forward" |
87 | | - |
88 | | - def test_ln_payment_2_to_0(self): |
89 | | - self.log.info("Test LN payment from 2 -> 0") |
90 | | - inv = json.loads(self.warnet("ln rpc tank-0000-ln addinvoice --amt=1000"))[ |
91 | | - "payment_request" |
92 | | - ] |
93 | | - self.log.info(f"Got invoice from node 0: {inv}") |
94 | | - self.log.info("Paying invoice from node 2...") |
95 | | - self.log.info(self.warnet(f"ln rpc tank-0002-ln payinvoice -f {inv}")) |
96 | | - |
97 | | - self.wait_for_predicate(lambda: self.check_invoices("tank-0000-ln") == 1) |
98 | | - |
99 | | - self.log.info("Ensuring channel-level channel policy settings: target") |
100 | | - payment = json.loads(self.warnet("ln rpc tank-0002-ln listpayments"))["payments"][0] |
101 | | - assert ( |
102 | | - payment["fee_msat"] == "2213" |
103 | | - ), f"Expected fee_msat to be 2213, got {payment['fee_msat']}" |
104 | | - |
105 | | - # def test_simln(self): |
106 | | - # self.log.info("Engaging simln") |
107 | | - # node2pub, _ = json.loads(self.warnet("ln rpc 2 getinfo"))["uris"][0].split("@") |
108 | | - # activity = [ |
109 | | - # {"source": "ln-0", "destination": node2pub, "interval_secs": 1, "amount_msat": 2000} |
110 | | - # ] |
111 | | - # self.warnet( |
112 | | - # f"network export --exclude=[1] --activity={json.dumps(activity).replace(' ', '')}" |
113 | | - # ) |
114 | | - # self.wait_for_predicate(lambda: self.check_invoices(2) > 1) |
115 | | - # assert self.check_invoices(0) == 1, "Expected one invoice for node 0" |
116 | | - # assert self.check_invoices(1) == 0, "Expected no invoices for node 1" |
117 | | - |
118 | | - def check_invoice_settled(self): |
119 | | - invs = json.loads(self.warnet("ln rpc tank-0002-ln listinvoices"))["invoices"] |
120 | | - if len(invs) > 0 and invs[0]["state"] == "SETTLED": |
121 | | - self.log.info("Invoice settled") |
122 | | - return True |
123 | | - return False |
124 | | - |
125 | | - def check_invoices(self, pod: str): |
126 | | - invs = json.loads(self.warnet(f"ln rpc {pod} listinvoices"))["invoices"] |
127 | | - settled = sum(1 for inv in invs if inv["state"] == "SETTLED") |
128 | | - self.log.debug(f"lnd {pod} has {settled} settled invoices") |
129 | | - return settled |
| 46 | + graphs = [] |
| 47 | + for n in range(10): |
| 48 | + ln = f"tank-{n:04d}-ln" |
| 49 | + res = self.warnet(f"ln rpc {ln} describegraph") |
| 50 | + graphs.append(json.loads(res)["edges"]) |
| 51 | + |
| 52 | + def check_policy(node: int, index: int, field: str, values: tuple): |
| 53 | + self.log.info(f"Checking policy: Node={node} ch={index} Expected={field}:{values}") |
| 54 | + graph = graphs[node] |
| 55 | + assert len(graph) == 13 |
| 56 | + ch = graph[index] |
| 57 | + a = int(ch["node1_policy"][field]) |
| 58 | + b = int(ch["node2_policy"][field]) |
| 59 | + assert values == (a, b) or values == ( |
| 60 | + b, |
| 61 | + a, |
| 62 | + ), f"policy check failed:\nActual:\n{ch}\nExpected:\n{field}:{values}" |
| 63 | + |
| 64 | + # test one property of one channel from each node |
| 65 | + check_policy(0, 0, "fee_base_msat", (250, 1000)) |
| 66 | + check_policy(1, 1, "time_lock_delta", (40, 100)) |
| 67 | + check_policy(2, 2, "fee_rate_milli_msat", (1, 4000)) |
| 68 | + check_policy(3, 3, "fee_rate_milli_msat", (499, 4000)) |
| 69 | + check_policy(4, 4, "time_lock_delta", (40, 144)) |
| 70 | + check_policy(5, 5, "max_htlc_msat", (1980000000, 1500000000)) |
| 71 | + check_policy(6, 6, "fee_rate_milli_msat", (550, 71)) |
| 72 | + check_policy(7, 7, "min_htlc", (1000, 1)) |
| 73 | + check_policy(8, 8, "time_lock_delta", (80, 144)) |
| 74 | + check_policy(9, 9, "fee_base_msat", (616, 1000)) |
| 75 | + |
| 76 | + def test_payments(self): |
| 77 | + def get_and_pay(src, tgt): |
| 78 | + src = f"tank-{src:04d}-ln" |
| 79 | + tgt = f"tank-{tgt:04d}-ln" |
| 80 | + invoice = json.loads(self.warnet(f"ln rpc {tgt} addinvoice --amt 230118"))[ |
| 81 | + "payment_request" |
| 82 | + ] |
| 83 | + print(self.warnet(f"ln rpc {src} payinvoice {invoice} --force")) |
| 84 | + |
| 85 | + get_and_pay(0, 5) |
| 86 | + get_and_pay(2, 3) |
| 87 | + get_and_pay(1, 9) |
| 88 | + get_and_pay(8, 7) |
| 89 | + get_and_pay(4, 6) |
130 | 90 |
|
131 | 91 |
|
132 | 92 | if __name__ == "__main__": |
|
0 commit comments