Browse Source

ln: handle channel limits better, show remote limits in details dialog, replace rusty's testnet peer (doesn't work currently)

regtest_lnd
Janus 6 years ago
committed by SomberNight
parent
commit
22e34d3d8f
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 10
      electrum/gui/qt/channel_details.py
  2. 36
      electrum/lnbase.py
  3. 2
      electrum/lnchan.py
  4. 10
      electrum/lnutil.py
  5. 2
      electrum/lnworker.py

10
electrum/gui/qt/channel_details.py

@ -157,6 +157,16 @@ class ChannelDetailsDialog(QtWidgets.QDialog):
form_layout.addRow(_('Received (mSAT):'), self.received_label)
self.sent_label = SelectableLabel()
form_layout.addRow(_('Sent (mSAT):'), self.sent_label)
self.htlc_minimum_msat = SelectableLabel(str(chan.config[REMOTE].htlc_minimum_msat))
form_layout.addRow(_('Minimum HTLC value accepted by peer (mSAT):'), self.htlc_minimum_msat)
self.max_htlcs = SelectableLabel(str(chan.config[REMOTE].max_accepted_htlcs))
form_layout.addRow(_('Maximum number of concurrent HTLCs accepted by peer:'), self.max_htlcs)
self.max_htlc_value = SelectableLabel(self.window.format_amount_and_units(chan.config[REMOTE].max_htlc_value_in_flight_msat / 1000))
form_layout.addRow(_('Maximum value of in-flight HTLCs accepted by peer:'), self.max_htlc_value)
self.dust_limit = SelectableLabel(self.window.format_amount_and_units(chan.config[REMOTE].dust_limit_sat))
form_layout.addRow(_('Remote dust limit:'), self.dust_limit)
self.reserve = SelectableLabel(self.window.format_amount_and_units(chan.config[REMOTE].reserve_sat))
form_layout.addRow(_('Remote channel reserve:'), self.reserve)
# add htlc tree view to vbox (wouldn't scale correctly in QFormLayout)
form_layout.addRow(_('Payments (HTLCs):'), None)

36
electrum/lnbase.py

@ -33,7 +33,9 @@ from .lnutil import (Outpoint, LocalConfig, RECEIVED, UpdateAddHtlc,
secret_to_pubkey, LNPeerAddr, PaymentFailure, LnLocalFeatures,
LOCAL, REMOTE, HTLCOwner, generate_keypair, LnKeyFamily,
get_ln_flag_pair_of_bit, privkey_to_pubkey, UnknownPaymentHash, MIN_FINAL_CLTV_EXPIRY_ACCEPTED,
LightningPeerConnectionClosed, HandshakeFailed, LNPeerAddr, NotFoundChanAnnouncementForUpdate)
LightningPeerConnectionClosed, HandshakeFailed, LNPeerAddr, NotFoundChanAnnouncementForUpdate,
MINIMUM_MAX_HTLC_VALUE_IN_FLIGHT_ACCEPTED, MAXIMUM_HTLC_MINIMUM_MSAT_ACCEPTED,
MAXIMUM_REMOTE_TO_SELF_DELAY_ACCEPTED)
from .lntransport import LNTransport, LNTransportBase
if TYPE_CHECKING:
@ -400,7 +402,7 @@ class Peer(PrintError):
revocation_basepoint=keypair_generator(LnKeyFamily.REVOCATION_BASE),
to_self_delay=9,
dust_limit_sat=546,
max_htlc_value_in_flight_msat=0xffffffffffffffff,
max_htlc_value_in_flight_msat=200000000,
max_accepted_htlcs=5,
initial_msat=initial_msat,
ctn=-1,
@ -418,6 +420,7 @@ class Peer(PrintError):
@log_exceptions
async def channel_establishment_flow(self, password: Optional[str], funding_sat: int,
push_msat: int, temp_channel_id: bytes) -> Channel:
assert push_msat == 0, "push_msat not supported currently"
wallet = self.lnworker.wallet
# dry run creating funding tx to see if we even have enough funds
funding_tx_test = wallet.mktx([TxOutput(bitcoin.TYPE_ADDRESS, wallet.dummy_address(), funding_sat)],
@ -448,33 +451,49 @@ class Peer(PrintError):
max_htlc_value_in_flight_msat=local_config.max_htlc_value_in_flight_msat,
channel_flags=0x00, # not willing to announce channel
channel_reserve_satoshis=local_config.reserve_sat,
htlc_minimum_msat=1,
)
payload = await self.channel_accepted[temp_channel_id].get()
if payload.get('error'):
raise Exception('Remote Lightning peer reported error: ' + repr(payload.get('error')))
remote_per_commitment_point = payload['first_per_commitment_point']
funding_txn_minimum_depth = int.from_bytes(payload['minimum_depth'], 'big')
assert funding_txn_minimum_depth > 0, funding_txn_minimum_depth
remote_dust_limit_sat = int.from_bytes(payload['dust_limit_satoshis'], byteorder='big')
assert remote_dust_limit_sat < 600, remote_dust_limit_sat
assert int.from_bytes(payload['htlc_minimum_msat'], 'big') < 600 * 1000
remote_reserve_sat = self.validate_remote_reserve(payload["channel_reserve_satoshis"], remote_dust_limit_sat, funding_sat)
if remote_dust_limit_sat > remote_reserve_sat:
raise Exception(f"Remote Lightning peer reports dust_limit_sat > reserve_sat which is a BOLT-02 protocol violation.")
htlc_min = int.from_bytes(payload['htlc_minimum_msat'], 'big')
if htlc_min > MAXIMUM_HTLC_MINIMUM_MSAT_ACCEPTED:
raise Exception(f"Remote Lightning peer reports htlc_minimum_msat={htlc_min} mSAT," +
f" which is above Electrums required maximum limit of that parameter ({MAXIMUM_HTLC_MINIMUM_MSAT_ACCEPTED} mSAT).")
remote_max = int.from_bytes(payload['max_htlc_value_in_flight_msat'], 'big')
assert remote_max >= 198 * 1000 * 1000, remote_max
if remote_max < MINIMUM_MAX_HTLC_VALUE_IN_FLIGHT_ACCEPTED:
raise Exception(f"Remote Lightning peer reports max_htlc_value_in_flight_msat at only {remote_max} mSAT" +
f" which is below Electrums required minimum ({MINIMUM_MAX_HTLC_VALUE_IN_FLIGHT_ACCEPTED} mSAT).")
max_accepted_htlcs = int.from_bytes(payload["max_accepted_htlcs"], 'big')
if max_accepted_htlcs > 483:
raise Exception("Remote Lightning peer reports max_accepted_htlcs > 483, which is a BOLT-02 protocol violation.")
remote_to_self_delay = int.from_bytes(payload['to_self_delay'], byteorder='big')
if remote_to_self_delay > MAXIMUM_REMOTE_TO_SELF_DELAY_ACCEPTED:
raise Exception(f"Remote Lightning peer reports to_self_delay={remote_to_self_delay}," +
f" which is above Electrums required maximum ({MAXIMUM_REMOTE_TO_SELF_DELAY_ACCEPTED})")
their_revocation_store = RevocationStore()
remote_reserve_sat = self.validate_remote_reserve(payload["channel_reserve_satoshis"], remote_dust_limit_sat, funding_sat)
remote_config = RemoteConfig(
payment_basepoint=OnlyPubkeyKeypair(payload['payment_basepoint']),
multisig_key=OnlyPubkeyKeypair(payload["funding_pubkey"]),
htlc_basepoint=OnlyPubkeyKeypair(payload['htlc_basepoint']),
delayed_basepoint=OnlyPubkeyKeypair(payload['delayed_payment_basepoint']),
revocation_basepoint=OnlyPubkeyKeypair(payload['revocation_basepoint']),
to_self_delay=int.from_bytes(payload['to_self_delay'], byteorder='big'),
to_self_delay=remote_to_self_delay,
dust_limit_sat=remote_dust_limit_sat,
max_htlc_value_in_flight_msat=remote_max,
max_accepted_htlcs=int.from_bytes(payload["max_accepted_htlcs"], 'big'),
max_accepted_htlcs=max_accepted_htlcs,
initial_msat=push_msat,
ctn = -1,
next_htlc_id = 0,
reserve_sat = remote_reserve_sat,
htlc_minimum_msat = htlc_min,
next_per_commitment_point=remote_per_commitment_point,
current_per_commitment_point=None,
@ -531,6 +550,7 @@ class Peer(PrintError):
raise Exception('wrong chain_hash')
funding_sat = int.from_bytes(payload['funding_satoshis'], 'big')
push_msat = int.from_bytes(payload['push_msat'], 'big')
assert push_msat == 0, "push_msat not supported currently"
feerate = int.from_bytes(payload['feerate_per_kw'], 'big')
temp_chan_id = payload['temporary_channel_id']

2
electrum/lnchan.py

@ -206,7 +206,7 @@ class Channel(PrintError):
current_htlc_sum = htlcsum(self.hm.htlcs_by_direction(LOCAL, SENT)) + htlcsum(self.hm.htlcs_by_direction(LOCAL, RECEIVED))
if current_htlc_sum + amount_msat > self.config[REMOTE].max_htlc_value_in_flight_msat:
raise PaymentFailure(f'HTLC value sum (sum of pending htlcs: {current_htlc_sum/1000} sat plus new htlc: {amount_msat/1000} sat) would exceed max allowed: {self.config[REMOTE].max_htlc_value_in_flight_msat/1000} sat')
if amount_msat <= 0: # FIXME htlc_minimum_msat
if amount_msat < self.config[REMOTE].htlc_minimum_msat:
raise PaymentFailure(f'HTLC value too small: {amount_msat} msat')
def can_pay(self, amount_msat):

10
electrum/lnutil.py

@ -71,6 +71,7 @@ class RemoteConfig(NamedTuple):
max_accepted_htlcs: int
initial_msat: int
reserve_sat: int
htlc_minimum_msat: int
# specific to "REMOTE" config
next_per_commitment_point: bytes
revocation_store: 'RevocationStore'
@ -103,6 +104,15 @@ MIN_FINAL_CLTV_EXPIRY_ACCEPTED = 144
MIN_FINAL_CLTV_EXPIRY_FOR_INVOICE = MIN_FINAL_CLTV_EXPIRY_ACCEPTED + 1
# When we open a channel, the remote peer has to support at least this
# value of mSATs in HTLCs accumulated on the channel, or we refuse opening.
# Number is based on observed testnet limit https://github.com/spesmilo/electrum/issues/5032
MINIMUM_MAX_HTLC_VALUE_IN_FLIGHT_ACCEPTED = 19_800 * 1000
MAXIMUM_HTLC_MINIMUM_MSAT_ACCEPTED = 1000
MAXIMUM_REMOTE_TO_SELF_DELAY_ACCEPTED = 2016
class RevocationStore:
""" Taken from LND, see license in lnchan.py. """

2
electrum/lnworker.py

@ -53,7 +53,7 @@ GRAPH_DOWNLOAD_SECONDS = 600
FALLBACK_NODE_LIST_TESTNET = (
LNPeerAddr('ecdsa.net', 9735, bfh('038370f0e7a03eded3e1d41dc081084a87f0afa1c5b22090b4f3abb391eb15d8ff')),
LNPeerAddr('165.227.30.200', 9735, bfh('023ea0a53af875580899da0ab0a21455d9c19160c4ea1b7774c9d4be6810b02d2c')),
LNPeerAddr('180.181.208.42', 9735, bfh('038863cf8ab91046230f561cd5b386cbff8309fa02e3f0c3ed161a3aeb64a643b9')),
)
FALLBACK_NODE_LIST_MAINNET = (
LNPeerAddr('104.198.32.198', 9735, bfh('02f6725f9c1c40333b67faea92fd211c183050f28df32cac3f9d69685fe9665432')), # Blockstream

Loading…
Cancel
Save