diff --git a/electrum/lnchannel.py b/electrum/lnchannel.py index fecc5a191236..dd08135daa08 100644 --- a/electrum/lnchannel.py +++ b/electrum/lnchannel.py @@ -61,6 +61,7 @@ from .lnutil import CHANNEL_OPENING_TIMEOUT from .lnutil import ChannelBackupStorage, ImportedChannelBackupStorage, OnchainChannelBackupStorage from .lnutil import format_short_channel_id +from .simple_config import FEERATE_PER_KW_MIN_RELAY_LIGHTNING if TYPE_CHECKING: from .lnworker import LNWallet @@ -1346,6 +1347,8 @@ def update_fee(self, feerate: int, from_us: bool) -> None: # feerate uses sat/kw if self.constraints.is_initiator != from_us: raise Exception(f"Cannot update_fee: wrong initiator. us: {from_us}") + if feerate < FEERATE_PER_KW_MIN_RELAY_LIGHTNING: + raise Exception(f"Cannot update_fee: feerate lower than min relay fee. {feerate} sat/kw. us: {from_us}") sender = LOCAL if from_us else REMOTE ctx_owner = -sender ctn = self.get_next_ctn(ctx_owner) diff --git a/electrum/lnutil.py b/electrum/lnutil.py index 7cc1bfb5e756..2e3441c9a5e1 100644 --- a/electrum/lnutil.py +++ b/electrum/lnutil.py @@ -169,6 +169,9 @@ def cross_validate_params( raise Exception( "both to_local and to_remote amounts for the initial commitment " "transaction are less than or equal to channel_reserve_satoshis") + from .simple_config import FEERATE_PER_KW_MIN_RELAY_LIGHTNING + if initial_feerate_per_kw < FEERATE_PER_KW_MIN_RELAY_LIGHTNING: + raise Exception(f"feerate lower than min relay fee. {initial_feerate_per_kw} sat/kw.") @attr.s diff --git a/electrum/lnworker.py b/electrum/lnworker.py index 41771a48809c..7a60bd885278 100644 --- a/electrum/lnworker.py +++ b/electrum/lnworker.py @@ -2096,12 +2096,13 @@ async def reestablish_peers_and_channels(self): def current_feerate_per_kw(self): from .simple_config import FEE_LN_ETA_TARGET, FEERATE_FALLBACK_STATIC_FEE, FEERATE_REGTEST_HARDCODED + from .simple_config import FEERATE_PER_KW_MIN_RELAY_LIGHTNING if constants.net is constants.BitcoinRegtest: return FEERATE_REGTEST_HARDCODED // 4 feerate_per_kvbyte = self.network.config.eta_target_to_fee(FEE_LN_ETA_TARGET) if feerate_per_kvbyte is None: feerate_per_kvbyte = FEERATE_FALLBACK_STATIC_FEE - return max(253, feerate_per_kvbyte // 4) + return max(FEERATE_PER_KW_MIN_RELAY_LIGHTNING, feerate_per_kvbyte // 4) def create_channel_backup(self, channel_id): chan = self._channels[channel_id] diff --git a/electrum/simple_config.py b/electrum/simple_config.py index 2c207db07796..8320b63f4063 100644 --- a/electrum/simple_config.py +++ b/electrum/simple_config.py @@ -34,6 +34,12 @@ 50000, 70000, 100000, 150000, 200000, 300000] FEERATE_REGTEST_HARDCODED = 180000 # for eclair compat +# The min feerate_per_kw that can be used in lightning so that +# the resulting onchain tx pays the min relay fee. +# This would be FEERATE_DEFAULT_RELAY / 4 if not for rounding errors, +# see https://github.com/ElementsProject/lightning/commit/2e687b9b352c9092b5e8bd4a688916ac50b44af0 +FEERATE_PER_KW_MIN_RELAY_LIGHTNING = 253 + FEE_RATIO_HIGH_WARNING = 0.05 # warn user if fee/amount for on-chain tx is higher than this diff --git a/electrum/tests/test_lnchannel.py b/electrum/tests/test_lnchannel.py index 0d1373073b27..eb6230e4ee13 100644 --- a/electrum/tests/test_lnchannel.py +++ b/electrum/tests/test_lnchannel.py @@ -532,7 +532,7 @@ def test_SimpleAddSettleWorkflow(self): self.assertEqual(bob_channel.total_msat(SENT), 5 * one_bitcoin_in_msat, "bob satoshis sent incorrect") - def alice_to_bob_fee_update(self, fee=111): + def alice_to_bob_fee_update(self, fee=1111): aoldctx = self.alice_channel.get_next_commitment(REMOTE).outputs() self.alice_channel.update_fee(fee, True) anewctx = self.alice_channel.get_next_commitment(REMOTE).outputs()