Browse Source

lnpeer: raise chan fees using update_fee more aggressively

The existing logic of only updating the fee if it is not within 2x of
the current 2-block-eta does not work well for the current mempool.

The current mempool looks a bit weird: you need ~20 sat/vbyte to even get into it,
but there is only around 5 MB of txs paying >25 sat/vbyte.
The estimates look like this:
```
>>> config.fee_estimates
{144: 25764, 25: 27075, 10: 34538, 5: 34538, 2: 34538}
```

This commit changes the logic so that we send update_fee if the old rate is
- below 75% of the current 2-block-eta (instead of 50%), or
- below the 25-block-eta
master
SomberNight 2 years ago
parent
commit
e6a0455ced
No known key found for this signature in database
GPG Key ID: B33B5F232C6271E9
  1. 25
      electrum/lnpeer.py
  2. 14
      electrum/lnworker.py
  3. 3
      electrum/simple_config.py

25
electrum/lnpeer.py

@ -52,7 +52,7 @@ from .interface import GracefulDisconnect
from .lnrouter import fee_for_edge_msat
from .json_db import StoredDict
from .invoices import PR_PAID
from .simple_config import FEE_LN_ETA_TARGET
from .simple_config import FEE_LN_ETA_TARGET, FEERATE_PER_KW_MIN_RELAY_LIGHTNING
from .trampoline import decode_routing_info
if TYPE_CHECKING:
@ -738,7 +738,7 @@ class Peer(Logger):
raise Exception('Cannot create public channels')
channel_flags = CF_ANNOUNCE_CHANNEL if public else 0
feerate = self.lnworker.current_feerate_per_kw()
feerate = self.lnworker.current_target_feerate_per_kw()
# we set a channel type for internal bookkeeping
open_channel_tlvs = {}
assert self.their_features.supports(LnFeatures.OPTION_STATIC_REMOTEKEY_OPT)
@ -2219,7 +2219,17 @@ class Peer(Logger):
"""
if not chan.can_send_ctx_updates():
return
feerate_per_kw = self.lnworker.current_feerate_per_kw()
feerate_per_kw = self.lnworker.current_target_feerate_per_kw()
def does_chan_fee_need_update(chan_feerate: Union[float, int]) -> bool:
# We raise fees more aggressively than we lower them. Overpaying is not too bad,
# but lowballing can be fatal if we can't even get into the mempool...
high_fee = 2 * feerate_per_kw # type: Union[float, int]
low_fee = self.lnworker.current_low_feerate_per_kw() # type: Union[float, int]
low_fee = max(low_fee, 0.75 * feerate_per_kw)
# make sure low_feerate and target_feerate are not too close to each other:
low_fee = min(low_fee, feerate_per_kw - FEERATE_PER_KW_MIN_RELAY_LIGHTNING)
assert low_fee < high_fee, (low_fee, high_fee)
return not (low_fee < chan_feerate < high_fee)
if not chan.constraints.is_initiator:
if constants.net is not constants.BitcoinRegtest:
chan_feerate = chan.get_latest_feerate(LOCAL)
@ -2232,14 +2242,13 @@ class Peer(Logger):
f"({chan.get_id_for_log()}) feerate is {chan_feerate} sat/kw, "
f"current recommended feerate is {feerate_per_kw} sat/kw, consider force closing!")
return
# it is our responsibility to update the fee
chan_fee = chan.get_next_feerate(REMOTE)
if feerate_per_kw < chan_fee / 2:
self.logger.info("FEES HAVE FALLEN")
elif feerate_per_kw > chan_fee * 2:
self.logger.info("FEES HAVE RISEN")
if does_chan_fee_need_update(chan_fee):
self.logger.info(f"({chan.get_id_for_log()}) onchain fees have changed considerably. updating fee.")
elif chan.get_latest_ctn(REMOTE) == 0:
# workaround eclair issue https://github.com/ACINQ/eclair/issues/1730
self.logger.info("updating fee to bump remote ctn")
self.logger.info(f"({chan.get_id_for_log()}) updating fee to bump remote ctn")
if feerate_per_kw == chan_fee:
feerate_per_kw += 1
else:

14
electrum/lnworker.py

@ -2914,7 +2914,7 @@ class LNWallet(LNWorker):
else:
await self.taskgroup.spawn(self.reestablish_peer_for_given_channel(chan))
def current_feerate_per_kw(self):
def current_target_feerate_per_kw(self) -> int:
from .simple_config import FEE_LN_ETA_TARGET, FEERATE_FALLBACK_STATIC_FEE
from .simple_config import FEERATE_PER_KW_MIN_RELAY_LIGHTNING
if constants.net is constants.BitcoinRegtest:
@ -2925,6 +2925,18 @@ class LNWallet(LNWorker):
feerate_per_kvbyte = FEERATE_FALLBACK_STATIC_FEE
return max(FEERATE_PER_KW_MIN_RELAY_LIGHTNING, feerate_per_kvbyte // 4)
def current_low_feerate_per_kw(self) -> int:
from .simple_config import FEE_LN_LOW_ETA_TARGET
from .simple_config import FEERATE_PER_KW_MIN_RELAY_LIGHTNING
if constants.net is constants.BitcoinRegtest:
feerate_per_kvbyte = 0
else:
feerate_per_kvbyte = self.network.config.eta_target_to_fee(FEE_LN_LOW_ETA_TARGET) or 0
low_feerate_per_kw = max(FEERATE_PER_KW_MIN_RELAY_LIGHTNING, feerate_per_kvbyte // 4)
# make sure this is never higher than the target feerate:
low_feerate_per_kw = min(low_feerate_per_kw, self.current_target_feerate_per_kw())
return low_feerate_per_kw
def create_channel_backup(self, channel_id: bytes):
chan = self._channels[channel_id]
# do not backup old-style channels

3
electrum/simple_config.py

@ -24,7 +24,8 @@ from .logging import get_logger, Logger
FEE_ETA_TARGETS = [25, 10, 5, 2]
FEE_DEPTH_TARGETS = [10_000_000, 5_000_000, 2_000_000, 1_000_000,
800_000, 600_000, 400_000, 250_000, 100_000]
FEE_LN_ETA_TARGET = 2 # note: make sure the network is asking for estimates for this target
FEE_LN_ETA_TARGET = 2 # note: make sure the network is asking for estimates for this target
FEE_LN_LOW_ETA_TARGET = 25 # note: make sure the network is asking for estimates for this target
# satoshi per kbyte
FEERATE_MAX_DYNAMIC = 1500000

Loading…
Cancel
Save