ttest_lnhtlc.py - electrum - Electrum Bitcoin wallet
HTML git clone https://git.parazyd.org/electrum
DIR Log
DIR Files
DIR Refs
DIR Submodules
---
ttest_lnhtlc.py (11810B)
---
1 from pprint import pprint
2 import unittest
3 from typing import NamedTuple
4
5 from electrum.lnutil import RECEIVED, LOCAL, REMOTE, SENT, HTLCOwner, Direction
6 from electrum.lnhtlc import HTLCManager
7 from electrum.json_db import StoredDict
8
9 from . import ElectrumTestCase
10
11 class H(NamedTuple):
12 owner : str
13 htlc_id : int
14
15 class TestHTLCManager(ElectrumTestCase):
16 def test_adding_htlcs_race(self):
17 A = HTLCManager(StoredDict({}, None, []))
18 B = HTLCManager(StoredDict({}, None, []))
19 A.channel_open_finished()
20 B.channel_open_finished()
21 ah0, bh0 = H('A', 0), H('B', 0)
22 B.recv_htlc(A.send_htlc(ah0))
23 self.assertEqual(B.log[REMOTE]['locked_in'][0][LOCAL], 1)
24 A.recv_htlc(B.send_htlc(bh0))
25 self.assertEqual(B.get_htlcs_in_latest_ctx(LOCAL), [])
26 self.assertEqual(A.get_htlcs_in_latest_ctx(LOCAL), [])
27 self.assertEqual(B.get_htlcs_in_next_ctx(LOCAL), [(RECEIVED, ah0)])
28 self.assertEqual(A.get_htlcs_in_next_ctx(LOCAL), [(RECEIVED, bh0)])
29 A.send_ctx()
30 B.recv_ctx()
31 B.send_ctx()
32 A.recv_ctx()
33 self.assertEqual(B.get_htlcs_in_oldest_unrevoked_ctx(LOCAL), [])
34 self.assertEqual(A.get_htlcs_in_oldest_unrevoked_ctx(LOCAL), [])
35 self.assertEqual(B.get_htlcs_in_latest_ctx(LOCAL), [(RECEIVED, ah0)])
36 self.assertEqual(A.get_htlcs_in_latest_ctx(LOCAL), [(RECEIVED, bh0)])
37 B.send_rev()
38 A.recv_rev()
39 A.send_rev()
40 B.recv_rev()
41 self.assertEqual(B.get_htlcs_in_oldest_unrevoked_ctx(LOCAL), [(RECEIVED, ah0)])
42 self.assertEqual(A.get_htlcs_in_oldest_unrevoked_ctx(LOCAL), [(RECEIVED, bh0)])
43 self.assertEqual(B.get_htlcs_in_latest_ctx(LOCAL), [(RECEIVED, ah0)])
44 self.assertEqual(A.get_htlcs_in_latest_ctx(LOCAL), [(RECEIVED, bh0)])
45 A.send_ctx()
46 B.recv_ctx()
47 B.send_ctx()
48 A.recv_ctx()
49 self.assertEqual(B.get_htlcs_in_oldest_unrevoked_ctx(LOCAL), [(RECEIVED, ah0)])
50 self.assertEqual(A.get_htlcs_in_oldest_unrevoked_ctx(LOCAL), [(RECEIVED, bh0)])
51 self.assertEqual(B.get_htlcs_in_latest_ctx(LOCAL), [(RECEIVED, ah0), (SENT, bh0)][::-1])
52 self.assertEqual(A.get_htlcs_in_latest_ctx(LOCAL), [(RECEIVED, bh0), (SENT, ah0)][::-1])
53 B.send_rev()
54 A.recv_rev()
55 A.send_rev()
56 B.recv_rev()
57 self.assertEqual(B.get_htlcs_in_oldest_unrevoked_ctx(LOCAL), [(RECEIVED, ah0), (SENT, bh0)][::-1])
58 self.assertEqual(A.get_htlcs_in_oldest_unrevoked_ctx(LOCAL), [(RECEIVED, bh0), (SENT, ah0)][::-1])
59 self.assertEqual(B.get_htlcs_in_latest_ctx(LOCAL), [(RECEIVED, ah0), (SENT, bh0)][::-1])
60 self.assertEqual(A.get_htlcs_in_latest_ctx(LOCAL), [(RECEIVED, bh0), (SENT, ah0)][::-1])
61
62 def test_single_htlc_full_lifecycle(self):
63 def htlc_lifecycle(htlc_success: bool):
64 A = HTLCManager(StoredDict({}, None, []))
65 B = HTLCManager(StoredDict({}, None, []))
66 A.channel_open_finished()
67 B.channel_open_finished()
68 B.recv_htlc(A.send_htlc(H('A', 0)))
69 self.assertEqual(len(B.get_htlcs_in_next_ctx(REMOTE)), 0)
70 self.assertEqual(len(A.get_htlcs_in_next_ctx(REMOTE)), 1)
71 self.assertEqual(len(B.get_htlcs_in_next_ctx(LOCAL)), 1)
72 self.assertEqual(len(A.get_htlcs_in_next_ctx(LOCAL)), 0)
73 A.send_ctx()
74 B.recv_ctx()
75 B.send_rev()
76 A.recv_rev()
77 B.send_ctx()
78 A.recv_ctx()
79 A.send_rev()
80 B.recv_rev()
81 self.assertEqual(len(A.get_htlcs_in_latest_ctx(LOCAL)), 1)
82 self.assertEqual(len(B.get_htlcs_in_latest_ctx(LOCAL)), 1)
83 if htlc_success:
84 B.send_settle(0)
85 A.recv_settle(0)
86 else:
87 B.send_fail(0)
88 A.recv_fail(0)
89 self.assertEqual(list(A.htlcs_by_direction(REMOTE, RECEIVED).values()), [H('A', 0)])
90 self.assertNotEqual(A.get_htlcs_in_latest_ctx(LOCAL), [])
91 self.assertNotEqual(B.get_htlcs_in_latest_ctx(REMOTE), [])
92
93 self.assertEqual(A.get_htlcs_in_next_ctx(LOCAL), [])
94 self.assertNotEqual(A.get_htlcs_in_next_ctx(REMOTE), [])
95 self.assertEqual(A.get_htlcs_in_next_ctx(REMOTE), A.get_htlcs_in_latest_ctx(REMOTE))
96
97 self.assertEqual(B.get_htlcs_in_next_ctx(REMOTE), [])
98 B.send_ctx()
99 A.recv_ctx()
100 A.send_rev() # here pending_htlcs(REMOTE) should become empty
101 self.assertEqual(A.get_htlcs_in_next_ctx(REMOTE), [])
102
103 B.recv_rev()
104 A.send_ctx()
105 B.recv_ctx()
106 B.send_rev()
107 A.recv_rev()
108 self.assertEqual(B.get_htlcs_in_latest_ctx(LOCAL), [])
109 self.assertEqual(A.get_htlcs_in_latest_ctx(LOCAL), [])
110 self.assertEqual(A.get_htlcs_in_latest_ctx(REMOTE), [])
111 self.assertEqual(B.get_htlcs_in_latest_ctx(REMOTE), [])
112 self.assertEqual(len(A.all_settled_htlcs_ever(LOCAL)), int(htlc_success))
113 self.assertEqual(len(A.sent_in_ctn(2)), int(htlc_success))
114 self.assertEqual(len(B.received_in_ctn(2)), int(htlc_success))
115
116 A.recv_htlc(B.send_htlc(H('B', 0)))
117 self.assertEqual(A.get_htlcs_in_next_ctx(REMOTE), [])
118 self.assertNotEqual(A.get_htlcs_in_next_ctx(LOCAL), [])
119 self.assertNotEqual(B.get_htlcs_in_next_ctx(REMOTE), [])
120 self.assertEqual(B.get_htlcs_in_next_ctx(LOCAL), [])
121
122 B.send_ctx()
123 A.recv_ctx()
124 A.send_rev()
125 B.recv_rev()
126
127 self.assertNotEqual(A.get_htlcs_in_next_ctx(REMOTE), A.get_htlcs_in_latest_ctx(REMOTE))
128 self.assertEqual(A.get_htlcs_in_next_ctx(LOCAL), A.get_htlcs_in_latest_ctx(LOCAL))
129 self.assertEqual(B.get_htlcs_in_next_ctx(REMOTE), B.get_htlcs_in_latest_ctx(REMOTE))
130 self.assertNotEqual(B.get_htlcs_in_next_ctx(LOCAL), B.get_htlcs_in_next_ctx(REMOTE))
131
132 htlc_lifecycle(htlc_success=True)
133 htlc_lifecycle(htlc_success=False)
134
135 def test_remove_htlc_while_owing_commitment(self):
136 def htlc_lifecycle(htlc_success: bool):
137 A = HTLCManager(StoredDict({}, None, []))
138 B = HTLCManager(StoredDict({}, None, []))
139 A.channel_open_finished()
140 B.channel_open_finished()
141 ah0 = H('A', 0)
142 B.recv_htlc(A.send_htlc(ah0))
143 A.send_ctx()
144 B.recv_ctx()
145 B.send_rev()
146 A.recv_rev()
147 if htlc_success:
148 B.send_settle(0)
149 A.recv_settle(0)
150 else:
151 B.send_fail(0)
152 A.recv_fail(0)
153 self.assertEqual([], A.get_htlcs_in_oldest_unrevoked_ctx(LOCAL))
154 self.assertEqual([(Direction.RECEIVED, ah0)], A.get_htlcs_in_oldest_unrevoked_ctx(REMOTE))
155 self.assertEqual([], A.get_htlcs_in_latest_ctx(LOCAL))
156 self.assertEqual([(Direction.RECEIVED, ah0)], A.get_htlcs_in_latest_ctx(REMOTE))
157 self.assertEqual([], A.get_htlcs_in_next_ctx(LOCAL))
158 self.assertEqual([(Direction.RECEIVED, ah0)], A.get_htlcs_in_next_ctx(REMOTE))
159 B.send_ctx()
160 A.recv_ctx()
161 A.send_rev()
162 B.recv_rev()
163 self.assertEqual([], A.get_htlcs_in_oldest_unrevoked_ctx(LOCAL))
164 self.assertEqual([(Direction.RECEIVED, ah0)], A.get_htlcs_in_oldest_unrevoked_ctx(REMOTE))
165 self.assertEqual([], A.get_htlcs_in_latest_ctx(LOCAL))
166 self.assertEqual([(Direction.RECEIVED, ah0)], A.get_htlcs_in_latest_ctx(REMOTE))
167 self.assertEqual([], A.get_htlcs_in_next_ctx(LOCAL))
168 self.assertEqual([], A.get_htlcs_in_next_ctx(REMOTE))
169
170 htlc_lifecycle(htlc_success=True)
171 htlc_lifecycle(htlc_success=False)
172
173 def test_adding_htlc_between_send_ctx_and_recv_rev(self):
174 A = HTLCManager(StoredDict({}, None, []))
175 B = HTLCManager(StoredDict({}, None, []))
176 A.channel_open_finished()
177 B.channel_open_finished()
178 A.send_ctx()
179 B.recv_ctx()
180 B.send_rev()
181 ah0 = H('A', 0)
182 B.recv_htlc(A.send_htlc(ah0))
183 self.assertEqual([], A.get_htlcs_in_latest_ctx(LOCAL))
184 self.assertEqual([], A.get_htlcs_in_latest_ctx(REMOTE))
185 self.assertEqual([], A.get_htlcs_in_next_ctx(LOCAL))
186 self.assertEqual([(Direction.RECEIVED, ah0)], A.get_htlcs_in_next_ctx(REMOTE))
187 A.recv_rev()
188 self.assertEqual([], A.get_htlcs_in_latest_ctx(LOCAL))
189 self.assertEqual([], A.get_htlcs_in_latest_ctx(REMOTE))
190 self.assertEqual([], A.get_htlcs_in_next_ctx(LOCAL))
191 self.assertEqual([(Direction.RECEIVED, ah0)], A.get_htlcs_in_next_ctx(REMOTE))
192 A.send_ctx()
193 B.recv_ctx()
194 self.assertEqual([], A.get_htlcs_in_latest_ctx(LOCAL))
195 self.assertEqual([(Direction.RECEIVED, ah0)], A.get_htlcs_in_latest_ctx(REMOTE))
196 self.assertEqual([], A.get_htlcs_in_next_ctx(LOCAL))
197 self.assertEqual([(Direction.RECEIVED, ah0)], A.get_htlcs_in_next_ctx(REMOTE))
198 B.send_rev()
199 A.recv_rev()
200 self.assertEqual([], A.get_htlcs_in_latest_ctx(LOCAL))
201 self.assertEqual([(Direction.RECEIVED, ah0)], A.get_htlcs_in_latest_ctx(REMOTE))
202 self.assertEqual([(Direction.SENT, ah0)], A.get_htlcs_in_next_ctx(LOCAL))
203 self.assertEqual([(Direction.RECEIVED, ah0)], A.get_htlcs_in_next_ctx(REMOTE))
204 B.send_ctx()
205 A.recv_ctx()
206 self.assertEqual([], A.get_htlcs_in_oldest_unrevoked_ctx(LOCAL))
207 self.assertEqual([(Direction.SENT, ah0)], A.get_htlcs_in_latest_ctx(LOCAL))
208 self.assertEqual([(Direction.RECEIVED, ah0)], A.get_htlcs_in_latest_ctx(REMOTE))
209 self.assertEqual([(Direction.SENT, ah0)], A.get_htlcs_in_next_ctx(LOCAL))
210 self.assertEqual([(Direction.RECEIVED, ah0)], A.get_htlcs_in_next_ctx(REMOTE))
211 A.send_rev()
212 B.recv_rev()
213 self.assertEqual([(Direction.SENT, ah0)], A.get_htlcs_in_oldest_unrevoked_ctx(LOCAL))
214 self.assertEqual([(Direction.SENT, ah0)], A.get_htlcs_in_latest_ctx(LOCAL))
215 self.assertEqual([(Direction.RECEIVED, ah0)], A.get_htlcs_in_latest_ctx(REMOTE))
216 self.assertEqual([(Direction.SENT, ah0)], A.get_htlcs_in_next_ctx(LOCAL))
217 self.assertEqual([(Direction.RECEIVED, ah0)], A.get_htlcs_in_next_ctx(REMOTE))
218
219 def test_unacked_local_updates(self):
220 A = HTLCManager(StoredDict({}, None, []))
221 B = HTLCManager(StoredDict({}, None, []))
222 A.channel_open_finished()
223 B.channel_open_finished()
224 self.assertEqual({}, A.get_unacked_local_updates())
225
226 ah0 = H('A', 0)
227 B.recv_htlc(A.send_htlc(ah0))
228 A.store_local_update_raw_msg(b"upd_msg0", is_commitment_signed=False)
229 self.assertEqual({1: [b"upd_msg0"]}, A.get_unacked_local_updates())
230
231 ah1 = H('A', 1)
232 B.recv_htlc(A.send_htlc(ah1))
233 A.store_local_update_raw_msg(b"upd_msg1", is_commitment_signed=False)
234 self.assertEqual({1: [b"upd_msg0", b"upd_msg1"]}, A.get_unacked_local_updates())
235
236 A.send_ctx()
237 B.recv_ctx()
238 A.store_local_update_raw_msg(b"ctx1", is_commitment_signed=True)
239 self.assertEqual({1: [b"upd_msg0", b"upd_msg1", b"ctx1"]}, A.get_unacked_local_updates())
240
241 ah2 = H('A', 2)
242 B.recv_htlc(A.send_htlc(ah2))
243 A.store_local_update_raw_msg(b"upd_msg2", is_commitment_signed=False)
244 self.assertEqual({1: [b"upd_msg0", b"upd_msg1", b"ctx1"], 2: [b"upd_msg2"]}, A.get_unacked_local_updates())
245
246 B.send_rev()
247 A.recv_rev()
248 self.assertEqual({2: [b"upd_msg2"]}, A.get_unacked_local_updates())