tfix channel_reestablish - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit aafbe74a28a48a50369ab81133b341941f1077d1 DIR parent 1f6646fa256516e72b5840d7fe8c746b9a38e1aa HTML Author: ThomasV <thomasv@electrum.org> Date: Tue, 29 May 2018 11:30:38 +0200 fix channel_reestablish Diffstat: M gui/qt/lightning_channels_list.py | 2 +- M lib/lnbase.py | 40 +++++++++++-------------------- M lib/lnrouter.py | 2 +- M lib/lnworker.py | 25 ++++--------------------- M lib/tests/test_lnbase.py | 2 +- 5 files changed, 21 insertions(+), 50 deletions(-) --- DIR diff --git a/gui/qt/lightning_channels_list.py b/gui/qt/lightning_channels_list.py t@@ -45,7 +45,7 @@ class LightningChannelsList(QtWidgets.QWidget): push_amt = int(push_amt_inp.text()) assert local_amt >= 200000 assert local_amt >= push_amt - obj = self.lnworker.open_channel_from_other_thread(node_id, local_amt, push_amt, self.update_rows.emit, password) + obj = self.lnworker.open_channel(node_id, local_amt, push_amt, password) @QtCore.pyqtSlot(dict) def do_update_single_row(self, new): DIR diff --git a/lib/lnbase.py b/lib/lnbase.py t@@ -568,8 +568,7 @@ def is_synced(network): class Peer(PrintError): - def __init__(self, host, port, pubkey, privkey, network, channel_db, path_finder, channel_state, handle_channel_reestablish, request_initial_sync=False): - self.handle_channel_reestablish = handle_channel_reestablish + def __init__(self, host, port, pubkey, privkey, network, channel_db, path_finder, channel_state, channels, request_initial_sync=False): self.update_add_htlc_event = asyncio.Event() self.channel_update_event = asyncio.Event() self.host = host t@@ -594,7 +593,6 @@ class Peer(PrintError): self.local_funding_locked = defaultdict(asyncio.Future) self.remote_funding_locked = defaultdict(asyncio.Future) self.revoke_and_ack = defaultdict(asyncio.Future) - self.channel_reestablish = defaultdict(asyncio.Future) self.update_fulfill_htlc = defaultdict(asyncio.Future) self.commitment_signed = defaultdict(asyncio.Future) self.initialized = asyncio.Future() t@@ -602,6 +600,7 @@ class Peer(PrintError): self.unfulfilled_htlcs = [] self.channel_state = channel_state self.nodes = {} + self.channels = channels def diagnostic_name(self): return self.host t@@ -714,13 +713,6 @@ class Peer(PrintError): l = int.from_bytes(payload['num_pong_bytes'], 'big') self.send_message(gen_msg('pong', byteslen=l)) - def on_channel_reestablish(self, payload): - chan_id = int.from_bytes(payload["channel_id"], 'big') - if chan_id in self.channel_reestablish: - self.channel_reestablish[chan_id].set_result(payload) - else: - asyncio.run_coroutine_threadsafe(self.handle_channel_reestablish(chan_id, payload), self.network.asyncio_loop).result() - def on_accept_channel(self, payload): temp_chan_id = payload["temporary_channel_id"] if temp_chan_id not in self.channel_accepted: raise Exception("Got unknown accept_channel") t@@ -795,6 +787,8 @@ class Peer(PrintError): self.process_message(msg) # initialized self.initialized.set_result(msg) + # reestablish channels + [await self.reestablish_channel(c) for c in self.channels] # loop while True: self.ping_if_required() t@@ -963,33 +957,29 @@ class Peer(PrintError): async def reestablish_channel(self, chan): assert chan.channel_id not in self.channel_state - - await self.initialized self.send_message(gen_msg("channel_reestablish", channel_id=chan.channel_id, next_local_commitment_number=chan.local_state.ctn+1, next_remote_revocation_number=chan.remote_state.ctn )) - channel_reestablish_msg = await self.channel_reestablish[chan.channel_id] - print(channel_reestablish_msg) - # { - # 'channel_id': b'\xfa\xce\x0b\x8cjZ6\x03\xd2\x99k\x12\x86\xc7\xed\xe5\xec\x80\x85F\xf2\x1bzn\xa1\xd30I\xf9_V\xfa', - # 'next_local_commitment_number': b'\x00\x00\x00\x00\x00\x00\x00\x01', - # 'next_remote_revocation_number': b'\x00\x00\x00\x00\x00\x00\x00\x00', - # 'your_last_per_commitment_secret': b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - # 'my_current_per_commitment_point': b'\x03\x18\xb9\x1b\x99\xd4\xc3\xf1\x92\x0f\xfe\xe4c\x9e\xae\xa4\xf1\xdeX\xcf4\xa9[\xd1\tAh\x80\x88\x01b*[' - # } + + def on_channel_reestablish(self, payload): + chan_id = int.from_bytes(payload["channel_id"], 'big') + for chan in self.channels: + if chan.channel_id == chan_id: + break + else: + print("Warning: received unknown channel_reestablish", chan_id, list(self.channels)) + return + channel_reestablish_msg = payload remote_ctn = int.from_bytes(channel_reestablish_msg["next_local_commitment_number"], 'big') if remote_ctn != chan.remote_state.ctn + 1: raise Exception("expected remote ctn {}, got {}".format(chan.remote_state.ctn + 1, remote_ctn)) - local_ctn = int.from_bytes(channel_reestablish_msg["next_remote_revocation_number"], 'big') if local_ctn != chan.local_state.ctn: raise Exception("expected local ctn {}, got {}".format(chan.local_state.ctn, local_ctn)) - if channel_reestablish_msg["my_current_per_commitment_point"] != chan.remote_state.last_per_commitment_point: raise Exception("Remote PCP mismatch") - self.channel_state[chan.channel_id] = "OPEN" async def funding_locked(self, chan): t@@ -1009,9 +999,7 @@ class Peer(PrintError): finally: del self.remote_funding_locked[channel_id] self.print_error('Done waiting for remote_funding_locked', remote_funding_locked_msg) - self.channel_state[chan.channel_id] = "OPEN" - return chan._replace(short_channel_id=short_channel_id, remote_state=chan.remote_state._replace(next_per_commitment_point=remote_funding_locked_msg["next_per_commitment_point"])) def on_update_fail_htlc(self, payload): DIR diff --git a/lib/lnrouter.py b/lib/lnrouter.py t@@ -120,7 +120,7 @@ class ChannelDB(PrintError): try: channel_info = self._id_to_channel_info[short_channel_id] except KeyError: - print("could not find", short_channel_id) + self.print_error("could not find", short_channel_id) else: channel_info.on_channel_update(msg_payload) DIR diff --git a/lib/lnworker.py b/lib/lnworker.py t@@ -98,7 +98,6 @@ class LNWorker: self.nodes = {} # received node announcements self.channel_db = lnrouter.ChannelDB() self.path_finder = lnrouter.LNPathFinder(self.channel_db) - self.channels = [reconstruct_namedtuples(x) for x in wallet.storage.get("channels", {})] peer_list = network.config.get('lightning_peers', node_list) self.channel_state = {} t@@ -109,15 +108,11 @@ class LNWorker: self.on_network_update('updated') # shortcut (don't block) if funding tx locked and verified def add_peer(self, host, port, pubkey): - peer = Peer(host, int(port), binascii.unhexlify(pubkey), self.privkey, - self.network, self.channel_db, self.path_finder, self.channel_state, self.handle_channel_reestablish) + node_id = bfh(pubkey) + channels = list(filter(lambda x: x.node_id == node_id, self.channels)) + peer = Peer(host, int(port), node_id, self.privkey, self.network, self.channel_db, self.path_finder, self.channel_state, channels) self.network.futures.append(asyncio.run_coroutine_threadsafe(peer.main_loop(), asyncio.get_event_loop())) - self.peers[bfh(pubkey)] = peer - - async def handle_channel_reestablish(self, chan_id, payload): - chans = [x for x in self.channels if x.channel_id == chan_id ] - chan = chans[0] - await self.peers[chan.node_id].reestablish_channel(chan) + self.peers[node_id] = peer def save_channel(self, openchannel): self.channels = [openchannel] # TODO multiple channels t@@ -179,17 +174,6 @@ class LNWorker: def list_channels(self): return serialize_channels(self.channels) - def reestablish_channels(self): - coro = self._reestablish_channels_coroutine() - return asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop).result() - - # not aiosafe because we call .result() which will propagate an exception - async def _reestablish_channels_coroutine(self): - if self.channels is None or len(self.channels) < 1: - raise Exception("Can't reestablish: No channel saved") - peer = self.peers[self.channels[0].node_id] - await peer.reestablish_channel(self.channels[0]) - # not aiosafe because we call .result() which will propagate an exception async def _pay_coroutine(self, invoice): openchannel = self.channels[0] t@@ -216,7 +200,6 @@ class LNWorker: openchannel = await peer.receive_commitment_revoke_ack(openchannel, expected_received_msat, payment_preimage) self.save_channel(openchannel) - def subscribe_payment_received_from_other_thread(self, emit_function): pass DIR diff --git a/lib/tests/test_lnbase.py b/lib/tests/test_lnbase.py t@@ -256,7 +256,7 @@ class Test_LNBase(unittest.TestCase): def test_find_path_for_payment(self): channel_db = lnrouter.ChannelDB() path_finder = lnrouter.LNPathFinder(channel_db) - p = Peer('', 0, 'a', bitcoin.sha256('privkeyseed'), None, channel_db, path_finder, {}, lambda x, y: None) + p = Peer('', 0, 'a', bitcoin.sha256('privkeyseed'), None, channel_db, path_finder, {}, []) p.on_channel_announcement({'node_id_1': b'b', 'node_id_2': b'c', 'short_channel_id': bfh('0000000000000001')}) p.on_channel_announcement({'node_id_1': b'b', 'node_id_2': b'e', 'short_channel_id': bfh('0000000000000002')}) p.on_channel_announcement({'node_id_1': b'a', 'node_id_2': b'b', 'short_channel_id': bfh('0000000000000003')})