Refactor channel states:
- persisted states are saved - state transitions are checked - transient states are stored in channel.peer_state - new channel states: 'PREOPENING', 'FUNDED' and 'REDEEMED' - upgrade storage to version 21
This commit is contained in:
@@ -40,6 +40,7 @@ from .lnaddr import lnencode, LnAddr, lndecode
|
||||
from .ecc import der_sig_from_sig_string
|
||||
from .ecc_fast import is_using_fast_ecc
|
||||
from .lnchannel import Channel, ChannelJsonEncoder
|
||||
from .lnchannel import channel_states, peer_states
|
||||
from . import lnutil
|
||||
from .lnutil import funding_output_script
|
||||
from .bitcoin import redeem_script_to_address
|
||||
@@ -420,10 +421,21 @@ class LNWallet(LNWorker):
|
||||
|
||||
def peer_closed(self, peer):
|
||||
for chan in self.channels_for_peer(peer.pubkey).values():
|
||||
chan.set_state('DISCONNECTED')
|
||||
chan.peer_state = peer_states.DISCONNECTED
|
||||
self.network.trigger_callback('channel', chan)
|
||||
self.peers.pop(peer.pubkey)
|
||||
|
||||
def get_channel_status(self, chan):
|
||||
# status displayed in the GUI
|
||||
cs = chan.get_state()
|
||||
if chan.is_closed():
|
||||
return cs.name
|
||||
peer = self.peers.get(chan.node_id)
|
||||
ps = chan.peer_state
|
||||
if ps != peer_states.GOOD:
|
||||
return ps.name
|
||||
return cs.name
|
||||
|
||||
def payment_completed(self, chan: Channel, direction: Direction,
|
||||
htlc: UpdateAddHtlc):
|
||||
chan_id = chan.channel_id
|
||||
@@ -629,7 +641,6 @@ class LNWallet(LNWorker):
|
||||
block_height, tx_pos, chan.funding_outpoint.output_index)
|
||||
self.logger.info(f"save_short_channel_id: {chan.short_channel_id}")
|
||||
self.save_channel(chan)
|
||||
self.on_channels_updated()
|
||||
|
||||
def channel_by_txo(self, txo):
|
||||
with self.lock:
|
||||
@@ -644,23 +655,25 @@ class LNWallet(LNWorker):
|
||||
chan = self.channel_by_txo(funding_outpoint)
|
||||
if not chan:
|
||||
return
|
||||
#self.logger.debug(f'on_channel_open {funding_outpoint}')
|
||||
self.channel_timestamps[bh2u(chan.channel_id)] = funding_txid, funding_height.height, funding_height.timestamp, None, None, None
|
||||
self.storage.put('lightning_channel_timestamps', self.channel_timestamps)
|
||||
chan.set_funding_txo_spentness(False)
|
||||
# send event to GUI
|
||||
self.network.trigger_callback('channel', chan)
|
||||
|
||||
if self.should_channel_be_closed_due_to_expiring_htlcs(chan):
|
||||
if chan.get_state() == channel_states.OPEN and self.should_channel_be_closed_due_to_expiring_htlcs(chan):
|
||||
self.logger.info(f"force-closing due to expiring htlcs")
|
||||
await self.force_close_channel(chan.channel_id)
|
||||
return
|
||||
if chan.short_channel_id is None:
|
||||
self.save_short_chan_id(chan)
|
||||
if chan.get_state() == "OPENING" and chan.short_channel_id:
|
||||
peer = self.peers[chan.node_id]
|
||||
peer.send_funding_locked(chan)
|
||||
elif chan.get_state() == "OPEN":
|
||||
|
||||
if chan.get_state() == channel_states.OPENING:
|
||||
if chan.short_channel_id is None:
|
||||
self.save_short_chan_id(chan)
|
||||
if chan.short_channel_id:
|
||||
chan.set_state(channel_states.FUNDED)
|
||||
self.channel_timestamps[bh2u(chan.channel_id)] = chan.funding_outpoint.txid, funding_height.height, funding_height.timestamp, None, None, None
|
||||
self.storage.put('lightning_channel_timestamps', self.channel_timestamps)
|
||||
|
||||
if chan.get_state() == channel_states.FUNDED:
|
||||
peer = self.peers.get(chan.node_id)
|
||||
if peer:
|
||||
peer.send_funding_locked(chan)
|
||||
|
||||
elif chan.get_state() == channel_states.OPEN:
|
||||
peer = self.peers.get(chan.node_id)
|
||||
if peer is None:
|
||||
self.logger.info("peer not found for {}".format(bh2u(chan.node_id)))
|
||||
@@ -669,7 +682,8 @@ class LNWallet(LNWorker):
|
||||
await peer.bitcoin_fee_update(chan)
|
||||
conf = self.lnwatcher.get_tx_height(chan.funding_outpoint.txid).conf
|
||||
peer.on_network_update(chan, conf)
|
||||
elif chan.force_closed and chan.get_state() != 'CLOSED':
|
||||
|
||||
elif chan.get_state() == channel_states.FORCE_CLOSING:
|
||||
txid = chan.force_close_tx().txid()
|
||||
height = self.lnwatcher.get_tx_height(txid).height
|
||||
self.logger.info(f"force closing tx {txid}, height {height}")
|
||||
@@ -677,21 +691,27 @@ class LNWallet(LNWorker):
|
||||
self.logger.info('REBROADCASTING CLOSING TX')
|
||||
await self.force_close_channel(chan.channel_id)
|
||||
|
||||
@ignore_exceptions
|
||||
@log_exceptions
|
||||
async def on_update_closed_channel(self, event, funding_outpoint, spenders, funding_txid, funding_height, closing_txid, closing_height, closing_tx):
|
||||
async def on_update_closed_channel(self, event, funding_outpoint, spenders, funding_txid, funding_height, closing_txid, closing_height, closing_tx, keep_watching):
|
||||
chan = self.channel_by_txo(funding_outpoint)
|
||||
if not chan:
|
||||
return
|
||||
#self.logger.debug(f'on_channel_closed {funding_outpoint}')
|
||||
|
||||
# fixme: this is wasteful
|
||||
self.channel_timestamps[bh2u(chan.channel_id)] = funding_txid, funding_height.height, funding_height.timestamp, closing_txid, closing_height.height, closing_height.timestamp
|
||||
self.storage.put('lightning_channel_timestamps', self.channel_timestamps)
|
||||
chan.set_funding_txo_spentness(True)
|
||||
chan.set_state('CLOSED')
|
||||
self.on_channels_updated()
|
||||
self.network.trigger_callback('channel', chan)
|
||||
|
||||
# remove from channel_db
|
||||
if chan.short_channel_id is not None:
|
||||
self.channel_db.remove_channel(chan.short_channel_id)
|
||||
|
||||
if chan.get_state() < channel_states.CLOSED:
|
||||
chan.set_state(channel_states.CLOSED)
|
||||
|
||||
if chan.get_state() == channel_states.CLOSED and not keep_watching:
|
||||
chan.set_state(channel_states.REDEEMED)
|
||||
|
||||
# detect who closed and set sweep_info
|
||||
sweep_info_dict = chan.sweep_ctx(closing_tx)
|
||||
self.logger.info(f'sweep_info_dict length: {len(sweep_info_dict)}')
|
||||
@@ -800,11 +820,8 @@ class LNWallet(LNWorker):
|
||||
temp_channel_id=os.urandom(32))
|
||||
self.save_channel(chan)
|
||||
self.lnwatcher.add_channel(chan.funding_outpoint.to_str(), chan.get_funding_address())
|
||||
self.on_channels_updated()
|
||||
return chan
|
||||
|
||||
def on_channels_updated(self):
|
||||
self.network.trigger_callback('channels_updated', self.wallet)
|
||||
return chan
|
||||
|
||||
@log_exceptions
|
||||
async def add_peer(self, connect_str: str) -> Peer:
|
||||
@@ -1149,7 +1166,7 @@ class LNWallet(LNWorker):
|
||||
# note: currently we add *all* our channels; but this might be a privacy leak?
|
||||
for chan in channels:
|
||||
# check channel is open
|
||||
if chan.get_state() != "OPEN":
|
||||
if chan.get_state() != channel_states.OPEN:
|
||||
continue
|
||||
# check channel has sufficient balance
|
||||
# FIXME because of on-chain fees of ctx, this check is insufficient
|
||||
@@ -1206,7 +1223,7 @@ class LNWallet(LNWorker):
|
||||
'channel_id': format_short_channel_id(chan.short_channel_id) if chan.short_channel_id else None,
|
||||
'full_channel_id': bh2u(chan.channel_id),
|
||||
'channel_point': chan.funding_outpoint.to_str(),
|
||||
'state': chan.get_state(),
|
||||
'state': chan.get_state().name,
|
||||
'remote_pubkey': bh2u(chan.node_id),
|
||||
'local_balance': chan.balance(LOCAL)//1000,
|
||||
'remote_balance': chan.balance(REMOTE)//1000,
|
||||
@@ -1220,9 +1237,7 @@ class LNWallet(LNWorker):
|
||||
async def force_close_channel(self, chan_id):
|
||||
chan = self.channels[chan_id]
|
||||
tx = chan.force_close_tx()
|
||||
chan.set_force_closed()
|
||||
self.save_channel(chan)
|
||||
self.on_channels_updated()
|
||||
chan.set_state(channel_states.FORCE_CLOSING)
|
||||
try:
|
||||
await self.network.broadcast_transaction(tx)
|
||||
except Exception as e:
|
||||
@@ -1276,6 +1291,7 @@ class LNWallet(LNWorker):
|
||||
if ratio < 0.5:
|
||||
self.logger.warning(f"fee level for channel {bh2u(chan.channel_id)} is {chan_feerate} sat/kiloweight, "
|
||||
f"current recommended feerate is {self.current_feerate_per_kw()} sat/kiloweight, consider force closing!")
|
||||
# reestablish
|
||||
if not chan.should_try_to_reestablish_peer():
|
||||
continue
|
||||
peer = self.peers.get(chan.node_id, None)
|
||||
|
||||
Reference in New Issue
Block a user