URI: 
       tlnaddr: encode min_final_cltv into invoice - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit e6a0b641d54b0c6f3b1425ca51714b16690ff49e
   DIR parent 384fd665b38f9a37c448028be1361653867e3bbd
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Wed, 17 Oct 2018 17:49:59 +0200
       
       lnaddr: encode min_final_cltv into invoice
       
       Diffstat:
         M electrum/lnaddr.py                  |      14 ++++++++++++--
         M electrum/lnworker.py                |       2 +-
         M electrum/tests/test_bolt11.py       |      12 ++++++++----
       
       3 files changed, 21 insertions(+), 7 deletions(-)
       ---
   DIR diff --git a/electrum/lnaddr.py b/electrum/lnaddr.py
       t@@ -205,6 +205,12 @@ def lnencode(addr, privkey):
                    data += tagged_bytes('h', sha256(v.encode('utf-8')).digest())
                elif k == 'n':
                    data += tagged_bytes('n', v)
       +        elif k == 'c':
       +            # Get minimal length by trimming leading 5 bits at a time.
       +            finalcltvbits = bitstring.pack('intbe:64', v)[4:64]
       +            while finalcltvbits.startswith('0b00000'):
       +                finalcltvbits = finalcltvbits[5:]
       +            data += tagged('c', finalcltvbits)
                else:
                    # FIXME: Support unknown tags?
                    raise ValueError("Unknown tag {}".format(k))
       t@@ -240,7 +246,7 @@ class LnAddr(object):
                self.pubkey = None
                self.currency = constants.net.SEGWIT_HRP if currency is None else currency
                self.amount = amount
       -        self.min_final_cltv_expiry = 9
       +        self._min_final_cltv_expiry = 9
        
            def __str__(self):
                return "LnAddr[{}, amount={}{} tags=[{}]]".format(
       t@@ -249,6 +255,10 @@ class LnAddr(object):
                    ", ".join([k + '=' + str(v) for k, v in self.tags])
                )
        
       +    def get_min_final_cltv_expiry(self) -> int:
       +        return self._min_final_cltv_expiry
       +
       +
        def lndecode(a, verbose=False, expected_hrp=None):
            if expected_hrp is None:
                expected_hrp = constants.net.SEGWIT_HRP
       t@@ -354,7 +364,7 @@ def lndecode(a, verbose=False, expected_hrp=None):
                    pubkeybytes = trim_to_bytes(tagdata)
                    addr.pubkey = pubkeybytes
                elif tag == 'c':
       -            addr.min_final_cltv_expiry = tagdata.int
       +            addr._min_final_cltv_expiry = tagdata.int
                else:
                    addr.unknown_tags.append((tag, tagdata))
        
   DIR diff --git a/electrum/lnworker.py b/electrum/lnworker.py
       t@@ -263,7 +263,7 @@ class LNWorker(PrintError):
                        break
                else:
                    raise Exception("ChannelDB returned path with short_channel_id {} that is not in channel list".format(bh2u(short_channel_id)))
       -        coro = peer.pay(route, chan, amount_msat, payment_hash, addr.min_final_cltv_expiry)
       +        coro = peer.pay(route, chan, amount_msat, payment_hash, addr.get_min_final_cltv_expiry())
                return addr, peer, asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop)
        
            def _create_route_from_invoice(self, decoded_invoice, amount_msat) -> List[RouteEdge]:
   DIR diff --git a/electrum/tests/test_bolt11.py b/electrum/tests/test_bolt11.py
       t@@ -57,8 +57,7 @@ class TestBolt11(unittest.TestCase):
        
                tests = [
                    LnAddr(RHASH, tags=[('d', '')]),
       -            LnAddr(RHASH, amount=Decimal('0.001'),
       -                   tags=[('d', '1 cup coffee'), ('x', 60)]),
       +            LnAddr(RHASH, amount=Decimal('0.001'), tags=[('d', '1 cup coffee'), ('x', 60)]),
                    LnAddr(RHASH, amount=Decimal('1'), tags=[('h', longdescription)]),
                    LnAddr(RHASH, currency='tb', tags=[('f', 'mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP'), ('h', longdescription)]),
                    LnAddr(RHASH, amount=24, tags=[
       t@@ -93,5 +92,10 @@ class TestBolt11(unittest.TestCase):
                lnaddr = lndecode(bech32_encode(hrp, bitarray_to_u5(databits)), True)
                assert lnaddr.pubkey.serialize() == PUBKEY
        
       -    def test_min_final_cltv_expiry(self):
       -        self.assertEquals(lndecode("lnsb500u1pdsgyf3pp5nmrqejdsdgs4n9ukgxcp2kcq265yhrxd4k5dyue58rxtp5y83s3qdqqcqzystrggccm9yvkr5yqx83jxll0qjpmgfg9ywmcd8g33msfgmqgyfyvqhku80qmqm8q6v35zvck2y5ccxsz5avtrauz8hgjj3uahppyq20qp6dvwxe", expected_hrp="sb").min_final_cltv_expiry, 144)
       +    def test_min_final_cltv_expiry_decoding(self):
       +        self.assertEquals(144, lndecode("lnsb500u1pdsgyf3pp5nmrqejdsdgs4n9ukgxcp2kcq265yhrxd4k5dyue58rxtp5y83s3qdqqcqzystrggccm9yvkr5yqx83jxll0qjpmgfg9ywmcd8g33msfgmqgyfyvqhku80qmqm8q6v35zvck2y5ccxsz5avtrauz8hgjj3uahppyq20qp6dvwxe", expected_hrp="sb").get_min_final_cltv_expiry())
       +
       +    def test_min_final_cltv_expiry_roundtrip(self):
       +        lnaddr = LnAddr(RHASH, amount=Decimal('0.001'), tags=[('d', '1 cup coffee'), ('x', 60), ('c', 150)])
       +        invoice = lnencode(lnaddr, PRIVKEY)
       +        self.assertEquals(150, lndecode(invoice).get_min_final_cltv_expiry())