Skip to content

Commit 859b67a

Browse files
committed
scenarios: ensure ln_init can handle larger scale networks
1 parent 7171ec4 commit 859b67a

File tree

3 files changed

+71
-55
lines changed

3 files changed

+71
-55
lines changed

src/scenarios/ln_init.py

Lines changed: 66 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/usr/bin/env python3
2+
23
from time import sleep
34

45
from scenarios.utils import ensure_miner
@@ -15,83 +16,94 @@ def set_test_params(self):
1516

1617
def run_test(self):
1718
self.log.info("Get LN nodes and wallet addresses")
19+
ln_nodes = []
1820
recv_addrs = []
1921
for tank in self.warnet.tanks:
2022
if tank.lnnode is not None:
2123
recv_addrs.append(tank.lnnode.getnewaddress())
24+
ln_nodes.append(tank.index)
2225

2326
self.log.info("Fund LN wallets")
24-
miner = ensure_miner(self.nodes[3])
25-
addr = miner.getnewaddress()
26-
self.generatetoaddress(self.nodes[3], 110, addr)
27+
miner = ensure_miner(self.nodes[0])
28+
miner_addr = miner.getnewaddress()
29+
# 298 block base
30+
self.generatetoaddress(self.nodes[0], 298, miner_addr)
31+
# divvy up the goods
32+
split = miner.getbalance() // len(recv_addrs)
2733
for addr in recv_addrs:
28-
miner.sendtoaddress(addr, 50)
29-
self.generatetoaddress(self.nodes[3], 1, addr)
30-
31-
self.log.info("Waiting for funds to be spendable")
32-
ready = False
33-
while not ready:
34-
sleep(1)
35-
ready = True
34+
miner.sendtoaddress(addr, split)
35+
# confirm funds in block 299
36+
self.generatetoaddress(self.nodes[0], 1, miner_addr)
37+
38+
self.log.info(f"Waiting for funds to be spendable: {split} BTC each for {len(recv_addrs)} LN nodes")
39+
40+
def funded_lnnodes():
3641
for tank in self.warnet.tanks:
3742
if tank.lnnode is None:
3843
continue
39-
bal = tank.lnnode.get_wallet_balance()
40-
if int(bal["confirmed_balance"]) >= 50:
41-
continue
42-
ready = False
43-
break
44-
45-
self.log.info("Open channels")
46-
# TODO: This might belong in Warnet class as connect_ln_edges()
47-
# but that would need to ensure spendable funds first.
48-
# For now we consider this scenario "special".
49-
chan_pts = []
50-
ln_edges = []
44+
if int(tank.lnnode.get_wallet_balance()["confirmed_balance"]) < (split * 100000000):
45+
return False
46+
return True
47+
self.wait_until(funded_lnnodes, timeout=5*60)
48+
49+
ln_nodes_uri = ln_nodes.copy()
50+
while len(ln_nodes_uri) > 0:
51+
self.log.info(f"Waiting for all LN nodes to have URI, LN nodes remaining: {ln_nodes_uri}")
52+
for index in ln_nodes_uri:
53+
lnnode = self.warnet.tanks[index].lnnode
54+
if lnnode.getURI():
55+
ln_nodes_uri.remove(index)
56+
sleep(5)
57+
58+
self.log.info("Adding p2p connections to LN nodes")
59+
for edge in self.warnet.graph.edges(data=True):
60+
(src, dst, data) = edge
61+
# Copy the L1 p2p topology (where applicable) to L2
62+
# so we get a more robust p2p graph for lightning
63+
if "source-policy" not in data and self.warnet.tanks[src].lnnode and self.warnet.tanks[dst].lnnode:
64+
self.warnet.tanks[src].lnnode.connect_to_tank(dst)
65+
66+
# Start confirming channel opens in block 300
67+
self.log.info("Opening channels, one per block")
68+
chan_opens = []
5169
for edge in self.warnet.graph.edges(data=True):
5270
(src, dst, data) = edge
5371
if "source-policy" in data:
5472
src_node = self.warnet.get_ln_node_from_tank(src)
5573
assert src_node is not None
5674
assert self.warnet.get_ln_node_from_tank(dst) is not None
57-
ln_edges.append(edge)
75+
self.log.info(f"opening channel {src}->{dst}")
5876
chan_pt = src_node.open_channel_to_tank(dst, data["source-policy"])
59-
chan_pts.append(chan_pt)
60-
61-
self.log.info("Waiting for all channel open txs in mempool")
62-
while True:
63-
all_set = True
64-
mp = self.nodes[3].getrawmempool()
65-
for chan_pt in chan_pts:
66-
if chan_pt[:64] not in mp:
67-
all_set = False
68-
if all_set:
69-
break
70-
sleep(2)
71-
72-
self.log.info("Confirming channel opens")
73-
self.generatetoaddress(self.nodes[3], 6, addr)
74-
75-
self.log.info("Waiting for graph gossip sync")
76-
while True:
77-
all_set = True
78-
for tank in self.warnet.tanks:
79-
if tank.lnnode is not None:
80-
edges = tank.lnnode.lncli("describegraph")["edges"]
81-
if len(edges) != len(ln_edges):
82-
all_set = False
83-
if all_set:
84-
break
85-
sleep(2)
77+
# We can guarantee deterministic short channel IDs as long as
78+
# the change output is greater than the channel funding output,
79+
# which will then be output 0
80+
assert chan_pt[64:] == ":0"
81+
chan_opens.append((edge, chan_pt))
82+
self.log.info(f" pending channel point: {chan_pt}")
83+
self.wait_until(lambda chan_pt=chan_pt: chan_pt[:64] in self.nodes[0].getrawmempool())
84+
self.generatetoaddress(self.nodes[0], 1, miner_addr)
85+
assert chan_pt[:64] not in self.nodes[0].getrawmempool()
86+
self.log.info(f" confirmed in block {self.nodes[0].getblockcount()}")
87+
88+
# Ensure all channel opens are sufficiently confirmed
89+
self.generatetoaddress(self.nodes[0], 10, miner_addr)
90+
ln_nodes_gossip = ln_nodes.copy()
91+
while len(ln_nodes_gossip) > 0:
92+
self.log.info(f"Waiting for graph gossip sync, LN nodes remaining: {ln_nodes_gossip}")
93+
for index in ln_nodes_gossip:
94+
lnnode = self.warnet.tanks[index].lnnode
95+
if len(lnnode.lncli("describegraph")["edges"]) == len(chan_opens):
96+
ln_nodes_gossip.remove(index)
97+
sleep(5)
8698

8799
self.log.info("Updating channel policies")
88-
for i, edge in enumerate(ln_edges):
100+
for edge, chan_pt in chan_opens:
89101
(src, dst, data) = edge
90102
if "target-policy" in data:
91103
target_node = self.warnet.get_ln_node_from_tank(dst)
92-
target_node.update_channel_policy(chan_pts[i], data["target-policy"])
104+
target_node.update_channel_policy(chan_pt, data["target-policy"])
93105

94-
self.log.info(f"Warnet LN ready with {len(recv_addrs)} nodes and {len(ln_edges)} channels.")
106+
self.log.info(f"Warnet LN ready with {len(recv_addrs)} nodes and {len(chan_opens)} channels.")
95107

96108
if __name__ == "__main__":
97109
LNInit().main()

src/warnet/lnnode.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
"--accept-keysend",
1313
"--bitcoin.active",
1414
"--bitcoin.regtest",
15-
"--bitcoin.node=bitcoind"
15+
"--bitcoin.node=bitcoind",
16+
"--maxpendingchannels=64"
1617
])
1718

1819
class LNNode:
@@ -67,6 +68,8 @@ def getnewaddress(self):
6768

6869
def getURI(self):
6970
res = self.lncli("getinfo")
71+
if len(res["uris"]) < 1:
72+
return None
7073
return res["uris"][0]
7174

7275
def get_wallet_balance(self):

test/data/ln.graphml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
<edge id="1" source="0" target="1"></edge>
4040
<edge id="2" source="1" target="2"></edge>
4141
<edge id="3" source="2" target="3"></edge>
42+
<edge id="4" source="2" target="0"></edge>
4243
<edge id="4" source="3" target="0"></edge>
4344
<!-- LN channels -->
4445
<edge id="5" source="0" target="1">

0 commit comments

Comments
 (0)