Skip to content

Commit 0e67280

Browse files
committed
test LN
1 parent e137246 commit 0e67280

File tree

2 files changed

+59
-98
lines changed

2 files changed

+59
-98
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ jobs:
4444
- dag_connection_test.py
4545
- graph_test.py
4646
- logging_test.py
47+
- ln_test.py
4748
- ln_basic_test.py
4849
- rpc_test.py
4950
- services_test.py

test/ln_test.py

Lines changed: 58 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -6,127 +6,87 @@
66

77
from test_base import TestBase
88

9-
from warnet.cli.process import run_command
9+
from warnet.process import stream_command
1010

1111

1212
class LNTest(TestBase):
1313
def __init__(self):
1414
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"
1618

1719
def run_test(self):
1820
try:
21+
self.import_network()
1922
self.setup_network()
2023
self.run_ln_init_scenario()
2124
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()
2526
finally:
2627
self.cleanup()
2728

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+
2834
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}"))
3137
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)
3838

3939
def run_ln_init_scenario(self):
4040
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")
4342
self.wait_for_all_scenarios()
4443

4544
def test_channel_policies(self):
4645
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)
13090

13191

13292
if __name__ == "__main__":

0 commit comments

Comments
 (0)