electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit e6a0b641d54b0c6f3b1425ca51714b16690ff49e
parent 384fd665b38f9a37c448028be1361653867e3bbd
Author: SomberNight <somber.night@protonmail.com>
Date:   Wed, 17 Oct 2018 17:49:59 +0200

lnaddr: encode min_final_cltv into invoice

Diffstat:
Melectrum/lnaddr.py | 14++++++++++++--
Melectrum/lnworker.py | 2+-
Melectrum/tests/test_bolt11.py | 12++++++++----
3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/electrum/lnaddr.py b/electrum/lnaddr.py @@ -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)) @@ -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( @@ -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 @@ -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)) diff --git a/electrum/lnworker.py b/electrum/lnworker.py @@ -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]: diff --git a/electrum/tests/test_bolt11.py b/electrum/tests/test_bolt11.py @@ -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=[ @@ -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())