URI: 
       tln: handle channel limits better, show remote limits in details dialog, replace rusty's testnet peer (doesn't work currently) - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit e6bd3959e08c57ec5eea31e92ac12a4a6f42c3c3
   DIR parent 0a08ccc1c6ff910661059a47fa79b1462a927512
  HTML Author: Janus <ysangkok@gmail.com>
       Date:   Mon, 28 Jan 2019 20:13:09 +0100
       
       ln: handle channel limits better, show remote limits in details dialog, replace rusty's testnet peer (doesn't work currently)
       
       Diffstat:
         M electrum/gui/qt/channel_details.py  |      10 ++++++++++
         M electrum/lnbase.py                  |      36 ++++++++++++++++++++++++-------
         M electrum/lnchan.py                  |       2 +-
         M electrum/lnutil.py                  |      10 ++++++++++
         M electrum/lnworker.py                |       2 +-
       
       5 files changed, 50 insertions(+), 10 deletions(-)
       ---
   DIR diff --git a/electrum/gui/qt/channel_details.py b/electrum/gui/qt/channel_details.py
       t@@ -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)
   DIR diff --git a/electrum/lnbase.py b/electrum/lnbase.py
       t@@ -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:
       t@@ -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,
       t@@ -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)],
       t@@ -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,
       t@@ -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']
   DIR diff --git a/electrum/lnchan.py b/electrum/lnchan.py
       t@@ -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):
   DIR diff --git a/electrum/lnutil.py b/electrum/lnutil.py
       t@@ -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'
       t@@ -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. """
        
   DIR diff --git a/electrum/lnworker.py b/electrum/lnworker.py
       t@@ -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