|
8 | 8 | from . import util |
9 | 9 | from .util import ( |
10 | 10 | TxMinedInfo, BelowDustLimit, NoDynamicFeeEstimates, OldTaskGroup, EventListener, event_listener, log_exceptions, |
11 | | - ignore_exceptions, now |
| 11 | + ignore_exceptions, now, send_exception_to_crash_reporter |
12 | 12 | ) |
13 | 13 | from .transaction import Transaction, TxOutpoint |
14 | 14 | from .logging import Logger |
15 | 15 | from .address_synchronizer import TX_HEIGHT_LOCAL |
16 | 16 | from .lnutil import REDEEM_AFTER_DOUBLE_SPENT_DELAY |
17 | | -from .lnsweep import KeepWatchingTXO, SweepInfo |
| 17 | +from .lnsweep import KeepWatchingTXO, SweepInfo, MaybeSweepInfo |
18 | 18 |
|
19 | 19 | if TYPE_CHECKING: |
20 | 20 | from .network import Network |
@@ -201,58 +201,74 @@ async def sweep_commitment_transaction(self, funding_outpoint: str, closing_tx: |
201 | 201 | chan = self.lnworker.channel_by_txo(funding_outpoint) |
202 | 202 | if not chan: |
203 | 203 | return False |
204 | | - local_height = self.adb.get_local_height() |
205 | 204 | self._pending_force_closes.pop(chan, None) # recomputed below |
206 | 205 | # detect who closed and get information about how to claim outputs |
207 | 206 | is_local_ctx, sweep_info_dict = chan.get_ctx_sweep_info(closing_tx) |
208 | 207 | # note: we need to keep watching *at least* until the closing tx is deeply mined, |
209 | 208 | # possibly longer if there are TXOs to sweep |
210 | 209 | keep_watching = not self.adb.is_deeply_mined(closing_tx.txid()) |
211 | 210 | # create and broadcast transactions |
212 | | - for prevout, sweep_info in sweep_info_dict.items(): # FIXME isolate iterations (error-wise) |
213 | | - prev_txid, prev_index = prevout.split(':') |
214 | | - name = sweep_info.name + ' ' + chan.get_id_for_log() |
215 | | - self.lnworker.wallet.set_default_label(prevout, name) |
216 | | - if isinstance(sweep_info, KeepWatchingTXO): # haven't yet decided if we want to sweep |
217 | | - keep_watching |= sweep_info.until_height > local_height |
218 | | - continue |
219 | | - assert isinstance(sweep_info, SweepInfo), sweep_info |
220 | | - if not self.adb.get_transaction(prev_txid): |
221 | | - # do not keep watching if prevout does not exist |
222 | | - self.logger.info(f'prevout does not exist for {name}: {prevout}') |
223 | | - continue |
224 | | - watch_sweep_info = self.maybe_redeem(sweep_info) |
225 | | - spender_txid = self.adb.get_spender(prevout) # note: LOCAL spenders don't count |
226 | | - spender_tx = self.adb.get_transaction(spender_txid) if spender_txid else None |
227 | | - if spender_tx: |
228 | | - # the spender might be the remote, revoked or not |
229 | | - htlc_sweepinfo = chan.maybe_sweep_htlcs(closing_tx, spender_tx) |
230 | | - if htlc_sweepinfo: |
231 | | - self.adb.subscribe_to_outputs(spender_txid) |
232 | | - for prevout2, htlc_sweep_info in htlc_sweepinfo.items(): |
233 | | - self.lnworker.wallet.set_default_label(prevout2, htlc_sweep_info.name) |
234 | | - if isinstance(htlc_sweep_info, KeepWatchingTXO): # haven't yet decided if we want to sweep |
235 | | - keep_watching |= htlc_sweep_info.until_height > local_height |
236 | | - continue |
237 | | - assert isinstance(htlc_sweep_info, SweepInfo), htlc_sweep_info |
238 | | - watch_htlc_sweep_info = self.maybe_redeem(htlc_sweep_info) |
239 | | - htlc_tx_spender = self.adb.get_spender(prevout2) |
240 | | - if htlc_tx_spender: |
241 | | - keep_watching |= not self.adb.is_deeply_mined(htlc_tx_spender) |
242 | | - self.maybe_add_accounting_address(htlc_tx_spender, htlc_sweep_info) |
243 | | - else: |
244 | | - keep_watching |= watch_htlc_sweep_info |
245 | | - keep_watching |= not self.adb.is_deeply_mined(spender_txid) |
246 | | - self.maybe_extract_preimage(chan, spender_tx, prevout) |
247 | | - self.maybe_add_accounting_address(spender_txid, sweep_info) |
248 | | - else: |
249 | | - keep_watching |= watch_sweep_info |
250 | | - self.maybe_add_pending_forceclose( |
251 | | - chan=chan, |
252 | | - spender_txid=spender_txid, |
253 | | - is_local_ctx=is_local_ctx, |
254 | | - sweep_info=sweep_info, |
255 | | - ) |
| 211 | + for prevout, sweep_info in sweep_info_dict.items(): |
| 212 | + try: |
| 213 | + keep_watching |= self._sweep_ctx_output(prevout, sweep_info, chan, closing_tx, is_local_ctx) |
| 214 | + except Exception as e: |
| 215 | + # in case a single sweep crashes we keep sweeping the other outputs |
| 216 | + send_exception_to_crash_reporter(e) # logs too |
| 217 | + keep_watching = True |
| 218 | + return keep_watching |
| 219 | + |
| 220 | + def _sweep_ctx_output( |
| 221 | + self, |
| 222 | + prevout: str, |
| 223 | + sweep_info: MaybeSweepInfo, |
| 224 | + chan: 'AbstractChannel', |
| 225 | + closing_tx: Transaction, |
| 226 | + is_local_ctx: bool, |
| 227 | + ) -> bool: |
| 228 | + keep_watching = False |
| 229 | + local_height = self.adb.get_local_height() |
| 230 | + prev_txid, prev_index = prevout.split(':') |
| 231 | + name = sweep_info.name + ' ' + chan.get_id_for_log() |
| 232 | + self.lnworker.wallet.set_default_label(prevout, name) |
| 233 | + if isinstance(sweep_info, KeepWatchingTXO): # haven't yet decided if we want to sweep |
| 234 | + return sweep_info.until_height > local_height |
| 235 | + assert isinstance(sweep_info, SweepInfo), sweep_info |
| 236 | + if not self.adb.get_transaction(prev_txid): |
| 237 | + # do not keep watching if prevout does not exist |
| 238 | + self.logger.info(f'prevout does not exist for {name}: {prevout}') |
| 239 | + return False |
| 240 | + watch_sweep_info = self.maybe_redeem(sweep_info) |
| 241 | + spender_txid = self.adb.get_spender(prevout) # note: LOCAL spenders don't count |
| 242 | + spender_tx = self.adb.get_transaction(spender_txid) if spender_txid else None |
| 243 | + if spender_tx: |
| 244 | + # the spender might be the remote, revoked or not |
| 245 | + htlc_sweepinfo = chan.maybe_sweep_htlcs(closing_tx, spender_tx) |
| 246 | + if htlc_sweepinfo: |
| 247 | + self.adb.subscribe_to_outputs(spender_txid) |
| 248 | + for prevout2, htlc_sweep_info in htlc_sweepinfo.items(): |
| 249 | + self.lnworker.wallet.set_default_label(prevout2, htlc_sweep_info.name) |
| 250 | + if isinstance(htlc_sweep_info, KeepWatchingTXO): # haven't yet decided if we want to sweep |
| 251 | + keep_watching |= htlc_sweep_info.until_height > local_height |
| 252 | + continue |
| 253 | + assert isinstance(htlc_sweep_info, SweepInfo), htlc_sweep_info |
| 254 | + watch_htlc_sweep_info = self.maybe_redeem(htlc_sweep_info) |
| 255 | + htlc_tx_spender = self.adb.get_spender(prevout2) |
| 256 | + if htlc_tx_spender: |
| 257 | + keep_watching |= not self.adb.is_deeply_mined(htlc_tx_spender) |
| 258 | + self.maybe_add_accounting_address(htlc_tx_spender, htlc_sweep_info) |
| 259 | + else: |
| 260 | + keep_watching |= watch_htlc_sweep_info |
| 261 | + keep_watching |= not self.adb.is_deeply_mined(spender_txid) |
| 262 | + self.maybe_extract_preimage(chan, spender_tx, prevout) |
| 263 | + self.maybe_add_accounting_address(spender_txid, sweep_info) |
| 264 | + else: |
| 265 | + keep_watching |= watch_sweep_info |
| 266 | + self.maybe_add_pending_forceclose( |
| 267 | + chan=chan, |
| 268 | + spender_txid=spender_txid, |
| 269 | + is_local_ctx=is_local_ctx, |
| 270 | + sweep_info=sweep_info, |
| 271 | + ) |
256 | 272 | return keep_watching |
257 | 273 |
|
258 | 274 | def get_pending_force_closes(self) -> Dict['AbstractChannel', int]: |
|
0 commit comments