diff --git a/electrum/lnsweep.py b/electrum/lnsweep.py index cbd3230184f5..84b542411ce8 100644 --- a/electrum/lnsweep.py +++ b/electrum/lnsweep.py @@ -5,7 +5,7 @@ from typing import Optional, Dict, List, Tuple, TYPE_CHECKING, NamedTuple, Callable from enum import Enum, auto -from .util import bfh, bh2u +from .util import bfh, bh2u, UneconomicFee from .bitcoin import redeem_script_to_address, dust_threshold, construct_witness from . import coinchooser from . import ecc @@ -28,6 +28,9 @@ _logger = get_logger(__name__) +HTLC_TRANSACTION_DEADLINE_FRACTION = 4 +HTLC_TRANSACTION_SWEEP_TARGET = 10 + class SweepInfo(NamedTuple): name: str @@ -301,11 +304,14 @@ def create_txns_for_htlc( subject=LOCAL, ctn=ctn) for (direction, htlc), (ctx_output_idx, htlc_relative_idx) in htlc_to_ctx_output_idx_map.items(): - create_txns_for_htlc( - htlc=htlc, - htlc_direction=direction, - ctx_output_idx=ctx_output_idx, - htlc_relative_idx=htlc_relative_idx) + try: + create_txns_for_htlc( + htlc=htlc, + htlc_direction=direction, + ctx_output_idx=ctx_output_idx, + htlc_relative_idx=htlc_relative_idx) + except UneconomicFee: + continue return txs @@ -566,9 +572,28 @@ def create_htlctx_that_spends_from_our_ctx( if chan.has_anchors(): wallet = chan.lnworker.wallet coins = wallet.get_spendable_coins(None) + def fee_estimator(size): - # TODO: set reasonable fee - return wallet.config.estimate_fee_for_feerate(fee_per_kb=10*1000, size=size) + if htlc_direction == SENT: + # we deal with an offered HTLC and therefore with a timeout transaction + # in this case it is not time critical for us to sweep unless we + # become a forwarding node + fee_per_kb = wallet.config.eta_target_to_fee(HTLC_TRANSACTION_SWEEP_TARGET) + else: + # in the case of a received HTLC, if we have the hash preimage, + # we should sweep before the timelock expires + expiry_height = htlc.cltv_expiry + current_height = wallet.network.blockchain().height() + deadline_blocks = expiry_height - current_height + # target block inclusion with a safety buffer + target = int(deadline_blocks / HTLC_TRANSACTION_DEADLINE_FRACTION) + fee_per_kb = wallet.config.eta_target_to_fee(target) + fee = wallet.config.estimate_fee_for_feerate(fee_per_kb=fee_per_kb, size=size) + # we only sweep if it is makes sense economically + if fee > htlc.amount_msat // 1000: + raise UneconomicFee + return fee + coin_chooser = coinchooser.get_coin_chooser(wallet.config) change_address = wallet.get_single_change_address_for_new_transaction() funded_htlc_tx = coin_chooser.make_tx( diff --git a/electrum/util.py b/electrum/util.py index 9a40d4fe40d2..bb41dcd0f747 100644 --- a/electrum/util.py +++ b/electrum/util.py @@ -139,6 +139,11 @@ def __str__(self): return _("Insufficient funds") +class UneconomicFee(Exception): + def __str__(self): + return _("The fee for the transaction is higher than the funds gained from it.") + + class NoDynamicFeeEstimates(Exception): def __str__(self): return _('Dynamic fee estimates not available')