From 0ca3d66d15aac6900575c54a7fa26e19b8bd99fb Mon Sep 17 00:00:00 2001 From: ThomasV Date: Sat, 4 Jun 2022 16:48:19 +0200 Subject: [PATCH] persist_lnwatcher: split try_redeem into two methods: - maybe_add_redeem_tx - maybe_broadcast Before this commit, local tx that are now persisted are bot broadcast --- electrum/address_synchronizer.py | 7 +--- electrum/lnwatcher.py | 68 ++++++++++++++++++-------------- 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/electrum/address_synchronizer.py b/electrum/address_synchronizer.py index 657ad0bac..e06ef7952 100644 --- a/electrum/address_synchronizer.py +++ b/electrum/address_synchronizer.py @@ -639,12 +639,9 @@ class AddressSynchronizer(Logger): return cached_local_height return self.network.get_local_height() if self.network else self.db.get('stored_height', 0) - def add_future_tx(self, tx: Transaction, wanted_height: int) -> bool: + def set_future_tx(self, txid:str, wanted_height: int): with self.lock: - tx_was_added = self.add_transaction(tx) - if tx_was_added: - self.future_tx[tx.txid()] = wanted_height - return tx_was_added + self.future_tx[txid] = wanted_height def get_tx_height(self, tx_hash: str) -> TxMinedInfo: if tx_hash is None: # ugly backwards compat... diff --git a/electrum/lnwatcher.py b/electrum/lnwatcher.py index 7dd9888e0..0a1897f43 100644 --- a/electrum/lnwatcher.py +++ b/electrum/lnwatcher.py @@ -12,7 +12,7 @@ from . import util from .sql_db import SqlDB, sql from .wallet_db import WalletDB from .util import bh2u, bfh, log_exceptions, ignore_exceptions, TxMinedInfo, random_shuffled_copy -from .address_synchronizer import AddressSynchronizer, TX_HEIGHT_LOCAL, TX_HEIGHT_UNCONF_PARENT, TX_HEIGHT_UNCONFIRMED +from .address_synchronizer import AddressSynchronizer, TX_HEIGHT_LOCAL, TX_HEIGHT_UNCONF_PARENT, TX_HEIGHT_UNCONFIRMED, TX_HEIGHT_FUTURE from .transaction import Transaction, TxOutpoint from .transaction import match_script_against_template from .lnutil import WITNESS_TEMPLATE_RECEIVED_HTLC, WITNESS_TEMPLATE_OFFERED_HTLC @@ -308,7 +308,7 @@ class LNWatcher(Logger): return TxMinedDepth.SHALLOW elif height in (TX_HEIGHT_UNCONFIRMED, TX_HEIGHT_UNCONF_PARENT): return TxMinedDepth.MEMPOOL - elif height == TX_HEIGHT_LOCAL: + elif height in (TX_HEIGHT_LOCAL, TX_HEIGHT_FUTURE): return TxMinedDepth.FREE elif height > 0 and conf == 0: # unverified but claimed to be mined @@ -432,6 +432,7 @@ class LNWalletWatcher(LNWatcher): keep_watching=keep_watching) await self.lnworker.on_channel_update(chan) + @log_exceptions async def do_breach_remedy(self, funding_outpoint, closing_tx, spenders): chan = self.lnworker.channel_by_txo(funding_outpoint) if not chan: @@ -443,19 +444,20 @@ class LNWalletWatcher(LNWatcher): # create and broadcast transaction for prevout, sweep_info in sweep_info_dict.items(): name = sweep_info.name + ' ' + chan.get_id_for_log() - spender_txid = spenders.get(prevout) + spender_txid = self.maybe_add_redeem_tx(spenders, prevout, sweep_info, name) if spender_txid is not None: spender_tx = self.adb.get_transaction(spender_txid) if not spender_tx: keep_watching = True continue + await self.maybe_broadcast(prevout, sweep_info, name, spender_txid) e_htlc_tx = chan.maybe_sweep_revoked_htlc(closing_tx, spender_tx) if e_htlc_tx: - spender2 = spenders.get(spender_txid+':0') + spender2 = self.maybe_add_redeem_tx(spenders, spender_txid+':0', e_htlc_tx, name) if spender2: + await self.maybe_broadcast(prevout, sweep_info, name, spender2) keep_watching |= not self.is_deeply_mined(spender2) else: - await self.try_redeem(spender_txid+':0', e_htlc_tx, chan_id_for_log, name) keep_watching = True else: keep_watching |= not self.is_deeply_mined(spender_txid) @@ -464,12 +466,37 @@ class LNWalletWatcher(LNWatcher): spender_txin = spender_tx.inputs()[txin_idx] chan.extract_preimage_from_htlc_txin(spender_txin) else: - await self.try_redeem(prevout, sweep_info, chan_id_for_log, name) keep_watching = True return keep_watching - @log_exceptions - async def try_redeem(self, prevout: str, sweep_info: 'SweepInfo', chan_id_for_log: str, name: str) -> None: + def maybe_add_redeem_tx(self, spenders, prevout: str, sweep_info: 'SweepInfo', name: str): + txid = spenders.get(prevout) + if txid: + return txid + prev_txid, prev_index = prevout.split(':') + tx = sweep_info.gen_tx() + if tx is None: + self.logger.info(f'{name} could not claim output: {prevout}, dust') + return + txid = tx.txid() + # it's OK to add local transaction, the fee will be recomputed + try: + tx_was_added = self.adb.add_transaction(tx) + except Exception as e: + self.logger.info(f'could not add future tx: {name}. prevout: {prevout} {str(e)}') + tx_was_added = False + if tx_was_added: + self.lnworker.wallet.set_label(txid, name) + self.logger.info(f'added redeem tx: {name}. prevout: {prevout}') + util.trigger_callback('wallet_updated', self.lnworker.wallet) + return txid + + async def maybe_broadcast(self, prevout, sweep_info: 'SweepInfo', name: str, txid: str) -> None: + if self.get_tx_mined_depth(txid) != TxMinedDepth.FREE: + return + tx = self.adb.get_transaction(txid) + if tx is None: + return prev_txid, prev_index = prevout.split(':') broadcast = True local_height = self.network.get_local_height() @@ -477,32 +504,15 @@ class LNWalletWatcher(LNWatcher): wanted_height = sweep_info.cltv_expiry if wanted_height - local_height > 0: broadcast = False - reason = 'waiting for {}: CLTV ({} > {}), prevout {}'.format(name, local_height, sweep_info.cltv_expiry, prevout) + reason = 'waiting for {}: CLTV ({} > {})'.format(name, local_height, sweep_info.cltv_expiry) if sweep_info.csv_delay: prev_height = self.adb.get_tx_height(prev_txid) wanted_height = sweep_info.csv_delay + prev_height.height - 1 if prev_height.height <= 0 or wanted_height - local_height > 0: broadcast = False - reason = 'waiting for {}: CSV ({} >= {}), prevout: {}'.format(name, prev_height.conf, sweep_info.csv_delay, prevout) - tx = sweep_info.gen_tx() - if tx is None: - self.logger.info(f'{name} could not claim output: {prevout}, dust') - return - txid = tx.txid() - self.lnworker.wallet.set_label(txid, name) + reason = 'waiting for {}: CSV ({} >= {})'.format(name, prev_height.conf, sweep_info.csv_delay) if broadcast: await self.network.try_broadcasting(tx, name) else: - if txid in self.adb.future_tx: - return - self.logger.debug(f'(chan {chan_id_for_log}) trying to redeem {name}: {prevout}') - self.logger.info(reason) - # it's OK to add local transaction, the fee will be recomputed - try: - tx_was_added = self.adb.add_future_tx(tx, wanted_height) - except Exception as e: - self.logger.info(f'could not add future tx: {name}. prevout: {prevout} {str(e)}') - tx_was_added = False - if tx_was_added: - self.logger.info(f'added future tx: {name}. prevout: {prevout}') - util.trigger_callback('wallet_updated', self.lnworker.wallet) + self.adb.set_future_tx(tx.txid(), wanted_height) + util.trigger_callback('wallet_updated', self.lnworker.wallet)