electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit d740475e7aabd4c4762ab7b07bc8d43d289df5fb
parent 3caccbebcd9249f442d9dc1196a65555ed56dee3
Author: Janus <ysangkok@gmail.com>
Date:   Mon, 16 Jul 2018 16:51:32 +0200

move channel_state into HTLCStateMachine

Diffstat:
Melectrum/gui/qt/channels_list.py | 3+--
Melectrum/lnbase.py | 20++++++++++++--------
Melectrum/lnhtlc.py | 2++
Melectrum/lnworker.py | 19++++++++++---------
Melectrum/tests/test_lnrouter.py | 2+-
5 files changed, 26 insertions(+), 20 deletions(-)

diff --git a/electrum/gui/qt/channels_list.py b/electrum/gui/qt/channels_list.py @@ -20,12 +20,11 @@ class ChannelsList(MyTreeWidget): self.status = QLabel('') def format_fields(self, chan): - status = self.parent.wallet.lnworker.channel_state[chan.channel_id] return [ bh2u(chan.node_id), self.parent.format_amount(chan.local_state.amount_msat//1000), self.parent.format_amount(chan.remote_state.amount_msat//1000), - status + chan.state ] def create_menu(self, position): diff --git a/electrum/lnbase.py b/electrum/lnbase.py @@ -292,7 +292,6 @@ class Peer(PrintError): self.privkey = lnworker.privkey self.network = lnworker.network self.channel_db = lnworker.network.channel_db - self.channel_state = lnworker.channel_state self.read_buffer = b'' self.ping_time = 0 self.initialized = asyncio.Future() @@ -305,10 +304,13 @@ class Peer(PrintError): self.announcement_signatures = defaultdict(asyncio.Queue) self.update_fail_htlc = defaultdict(asyncio.Queue) self.localfeatures = (0x08 if request_initial_sync else 0) - self.channels = lnworker.channels_for_peer(pubkey) self.invoices = lnworker.invoices self.attempted_route = {} + @property + def channels(self): + return self.lnworker.channels_for_peer(self.pubkey) + def diagnostic_name(self): return 'lnbase:' + str(self.host) @@ -630,13 +632,14 @@ class Peer(PrintError): assert success, success m.remote_state = m.remote_state._replace(ctn=0) m.local_state = m.local_state._replace(ctn=0, current_commitment_signature=remote_sig) + m.state = 'OPENING' return m @aiosafe async def reestablish_channel(self, chan): await self.initialized chan_id = chan.channel_id - self.channel_state[chan_id] = 'REESTABLISHING' + chan.state = 'REESTABLISHING' self.network.trigger_callback('channel', chan) self.send_message(gen_msg("channel_reestablish", channel_id=chan_id, @@ -644,7 +647,7 @@ class Peer(PrintError): next_remote_revocation_number=chan.remote_state.ctn )) await self.channel_reestablished[chan_id] - self.channel_state[chan_id] = 'OPENING' + chan.state = 'OPENING' if chan.local_state.funding_locked_received and chan.short_channel_id: self.mark_open(chan) self.network.trigger_callback('channel', chan) @@ -684,6 +687,7 @@ class Peer(PrintError): channel_id = payload['channel_id'] chan = self.channels.get(channel_id) if not chan: + print(self.channels) raise Exception("Got unknown funding_locked", channel_id) if not chan.local_state.funding_locked_received: our_next_point = chan.remote_state.next_per_commitment_point @@ -750,10 +754,10 @@ class Peer(PrintError): print("SENT CHANNEL ANNOUNCEMENT") def mark_open(self, chan): - if self.channel_state[chan.channel_id] == "OPEN": + if chan.state == "OPEN": return assert chan.local_state.funding_locked_received - self.channel_state[chan.channel_id] = "OPEN" + chan.state = "OPEN" self.network.trigger_callback('channel', chan) # add channel to database sorted_keys = list(sorted([self.pubkey, self.lnworker.pubkey])) @@ -827,7 +831,7 @@ class Peer(PrintError): @aiosafe async def pay(self, path, chan, amount_msat, payment_hash, pubkey_in_invoice, min_final_cltv_expiry): - assert self.channel_state[chan.channel_id] == "OPEN" + assert chan.state == "OPEN" assert amount_msat > 0, "amount_msat is not greater zero" height = self.network.get_local_height() route = self.network.path_finder.create_route_from_path(path, self.lnworker.pubkey) @@ -929,7 +933,7 @@ class Peer(PrintError): htlc_id = int.from_bytes(htlc["id"], 'big') assert htlc_id == chan.remote_state.next_htlc_id, (htlc_id, chan.remote_state.next_htlc_id) - assert self.channel_state[channel_id] == "OPEN" + assert chan.state == "OPEN" cltv_expiry = int.from_bytes(htlc["cltv_expiry"], 'big') # TODO verify sanity of their cltv expiry diff --git a/electrum/lnhtlc.py b/electrum/lnhtlc.py @@ -139,6 +139,8 @@ class HTLCStateMachine(PrintError): self.local_commitment = self.pending_local_commitment self.remote_commitment = self.pending_remote_commitment + self.state = 'DISCONNECTED' + def add_htlc(self, htlc): """ AddHTLC adds an HTLC to the state machine's local update log. This method diff --git a/electrum/lnworker.py b/electrum/lnworker.py @@ -40,7 +40,6 @@ class LNWorker(PrintError): self.peers = {} self.channels = {x.channel_id: x for x in map(HTLCStateMachine, wallet.storage.get("channels", []))} self.invoices = wallet.storage.get('lightning_invoices', {}) - self.channel_state = {chan.channel_id: "DISCONNECTED" for chan in self.channels.values()} for chan_id, chan in self.channels.items(): self.network.lnwatcher.watch_channel(chan, self.on_channel_utxos) peer_list = self.config.get('lightning_peers', node_list) @@ -71,8 +70,6 @@ class LNWorker(PrintError): def save_channel(self, openchannel): assert type(openchannel) is HTLCStateMachine - if openchannel.channel_id not in self.channel_state: - self.channel_state[openchannel.channel_id] = "OPENING" self.channels[openchannel.channel_id] = openchannel if openchannel.remote_state.next_per_commitment_point == openchannel.remote_state.current_per_commitment_point: raise Exception("Tried to save channel with next_point == current_point, this should not happen") @@ -87,7 +84,7 @@ class LNWorker(PrintError): If the Funding TX has not been mined, return None """ - assert self.channel_state[chan.channel_id] in ["OPEN", "OPENING"] + assert chan.state in ["OPEN", "OPENING"] peer = self.peers[chan.node_id] conf = self.wallet.get_tx_height(chan.funding_outpoint.txid)[1] if conf >= chan.constraints.funding_txn_minimum_depth: @@ -104,26 +101,30 @@ class LNWorker(PrintError): def on_channel_utxos(self, chan, utxos): outpoints = [Outpoint(x["tx_hash"], x["tx_pos"]) for x in utxos] if chan.funding_outpoint not in outpoints: - self.channel_state[chan.channel_id] = "CLOSED" + chan.state = "CLOSED" # FIXME is this properly GC-ed? (or too soon?) LNChanCloseHandler(self.network, self.wallet, chan) - elif self.channel_state[chan.channel_id] == 'DISCONNECTED': + elif chan.state == 'DISCONNECTED': + if chan.node_id not in self.peers: + self.print_error("received channel_utxos for channel which does not have peer (errored?)") + return peer = self.peers[chan.node_id] coro = peer.reestablish_channel(chan) asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop) def on_network_update(self, event, *args): for chan in self.channels.values(): - peer = self.peers[chan.node_id] - if self.channel_state[chan.channel_id] == "OPENING": + if chan.state == "OPENING": res = self.save_short_chan_id(chan) if not res: self.print_error("network update but funding tx is still not at sufficient depth") continue # this results in the channel being marked OPEN + peer = self.peers[chan.node_id] peer.funding_locked(chan) - elif self.channel_state[chan.channel_id] == "OPEN": + elif chan.state == "OPEN": conf = self.wallet.get_tx_height(chan.funding_outpoint.txid)[1] + peer = self.peers[chan.node_id] peer.on_network_update(chan, conf) async def _open_channel_coroutine(self, node_id, local_amount_sat, push_sat, password): diff --git a/electrum/tests/test_lnrouter.py b/electrum/tests/test_lnrouter.py @@ -31,9 +31,9 @@ class Test_LNRouter(unittest.TestCase): path_finder = lnrouter.LNPathFinder(fake_network.channel_db) privkey = bitcoin.sha256('privkeyseed') network = fake_network - channel_state = {} channels = [] invoices = {} + channels_for_peer = lambda x: [] p = Peer(fake_ln_worker, '', 0, 'a') 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')})