1
1
#!/usr/bin/env python3
2
+
2
3
from time import sleep
3
4
4
5
from scenarios .utils import ensure_miner
@@ -15,83 +16,94 @@ def set_test_params(self):
15
16
16
17
def run_test (self ):
17
18
self .log .info ("Get LN nodes and wallet addresses" )
19
+ ln_nodes = []
18
20
recv_addrs = []
19
21
for tank in self .warnet .tanks :
20
22
if tank .lnnode is not None :
21
23
recv_addrs .append (tank .lnnode .getnewaddress ())
24
+ ln_nodes .append (tank .index )
22
25
23
26
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 )
27
33
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 ():
36
41
for tank in self .warnet .tanks :
37
42
if tank .lnnode is None :
38
43
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 = []
51
69
for edge in self .warnet .graph .edges (data = True ):
52
70
(src , dst , data ) = edge
53
71
if "source-policy" in data :
54
72
src_node = self .warnet .get_ln_node_from_tank (src )
55
73
assert src_node is not None
56
74
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 } " )
58
76
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 )
86
98
87
99
self .log .info ("Updating channel policies" )
88
- for i , edge in enumerate ( ln_edges ) :
100
+ for edge , chan_pt in chan_opens :
89
101
(src , dst , data ) = edge
90
102
if "target-policy" in data :
91
103
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" ])
93
105
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." )
95
107
96
108
if __name__ == "__main__" :
97
109
LNInit ().main ()
0 commit comments