|
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