Browse Source

lnworker: start watching already redeemed chans if txs are missing

This fixes a bug where if one runs `wallet.clear_history()` they would see exceptions later:
```
Traceback (most recent call last):
  File "/home/user/wspace/electrum/electrum/gui/qt/main_window.py", line 866, in timer_actions
	self.update_wallet()
  File "/home/user/wspace/electrum/electrum/gui/qt/main_window.py", line 1021, in update_wallet
	self.update_tabs()
  File "/home/user/wspace/electrum/electrum/gui/qt/main_window.py", line 1033, in update_tabs
	self.utxo_list.update()
  File "/home/user/wspace/electrum/electrum/gui/qt/utxo_list.py", line 103, in update
	self.refresh_row(name, idx)
  File "/home/user/wspace/electrum/electrum/gui/qt/utxo_list.py", line 124, in refresh_row
	parents = self.wallet.get_tx_parents(txid)
  File "/home/user/wspace/electrum/electrum/wallet.py", line 885, in get_tx_parents
	result.update(self.get_tx_parents(_txid))
  File "/home/user/wspace/electrum/electrum/wallet.py", line 881, in get_tx_parents
	for i, txin in enumerate(tx.inputs()):
AttributeError: 'NoneType' object has no attribute 'inputs'
```
This is related to the privacy analysis, which assumes that for each tx item in the history list
we should have the raw tx in the db. This is no longer true after wallet.clear_history(), if
the wallet has certain LN channels. E.g. an already redeemed channel that was local-force-closed,
as that closing tx is not related to the wallet directly.

In commit 3541ecb576, we decided not to watch already redeemed channels.
This is potentially good for e.g. privacy, as the server would otherwise see us subscribe to that chan.
However it means that after running wallet.clear_history() txs related to the channel but not to the
wallet won't be re-downloaded.

Instead, now if there are missing txs for a redeemed channel, we start watching it, hence the
synchronizer will re-downloaded the txs.
master
SomberNight 3 years ago
parent
commit
d11237d6a1
No known key found for this signature in database
GPG Key ID: B33B5F232C6271E9
  1. 23
      electrum/lnchannel.py
  2. 4
      electrum/lnworker.py
  3. 1
      electrum/wallet.py

23
electrum/lnchannel.py

@ -230,6 +230,29 @@ class AbstractChannel(Logger, ABC):
def is_redeemed(self):
return self.get_state() == ChannelState.REDEEMED
def need_to_subscribe(self) -> bool:
"""Whether lnwatcher/synchronizer need to be watching this channel."""
if not self.is_redeemed():
return True
# Chan already deeply closed. Still, if some txs are missing, we should sub.
# check we have funding tx
# note: tx might not be directly related to the wallet, e.g. chan opened by remote
if (funding_item := self.get_funding_height()) is None:
return True
if self.lnworker:
funding_txid, funding_height, funding_timestamp = funding_item
if self.lnworker.wallet.adb.get_transaction(funding_txid) is None:
return True
# check we have closing tx
# note: tx might not be directly related to the wallet, e.g. local-fclose
if (closing_item := self.get_closing_height()) is None:
return True
if self.lnworker:
closing_txid, closing_height, closing_timestamp = closing_item
if self.lnworker.wallet.adb.get_transaction(closing_txid) is None:
return True
return False
@abstractmethod
def get_close_options(self) -> Sequence[ChanCloseOption]:
pass

4
electrum/lnworker.py

@ -762,10 +762,10 @@ class LNWallet(LNWorker):
self.lnrater = LNRater(self, network)
for chan in self.channels.values():
if not chan.is_redeemed():
if chan.need_to_subscribe():
self.lnwatcher.add_channel(chan.funding_outpoint.to_str(), chan.get_funding_address())
for cb in self.channel_backups.values():
if not cb.is_redeemed():
if cb.need_to_subscribe():
self.lnwatcher.add_channel(cb.funding_outpoint.to_str(), cb.get_funding_address())
for coro in [

1
electrum/wallet.py

@ -878,6 +878,7 @@ class Abstract_Wallet(ABC, Logger, EventListener):
result = {}
parents = []
tx = self.adb.get_transaction(txid)
assert tx, f"cannot find {txid} in db"
for i, txin in enumerate(tx.inputs()):
_txid = txin.prevout.txid.hex()
parents.append(_txid)

Loading…
Cancel
Save