URI: 
       ttest_bolt11.py - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
       ttest_bolt11.py (8619B)
       ---
            1 from hashlib import sha256
            2 from decimal import Decimal
            3 from binascii import unhexlify, hexlify
            4 import pprint
            5 import unittest
            6 
            7 from electrum.lnaddr import shorten_amount, unshorten_amount, LnAddr, lnencode, lndecode, u5_to_bitarray, bitarray_to_u5
            8 from electrum.segwit_addr import bech32_encode, bech32_decode
            9 from electrum.lnutil import UnknownEvenFeatureBits, derive_payment_secret_from_payment_preimage, LnFeatures
           10 
           11 from . import ElectrumTestCase
           12 
           13 
           14 RHASH=unhexlify('0001020304050607080900010203040506070809000102030405060708090102')
           15 CONVERSION_RATE=1200
           16 PRIVKEY=unhexlify('e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734')
           17 PUBKEY=unhexlify('03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad')
           18 
           19 
           20 class TestBolt11(ElectrumTestCase):
           21     def test_shorten_amount(self):
           22         tests = {
           23             Decimal(10)/10**12: '10p',
           24             Decimal(1000)/10**12: '1n',
           25             Decimal(1200)/10**12: '1200p',
           26             Decimal(123)/10**6: '123u',
           27             Decimal(123)/1000: '123m',
           28             Decimal(3): '3',
           29         }
           30 
           31         for i, o in tests.items():
           32             assert shorten_amount(i) == o
           33             assert unshorten_amount(shorten_amount(i)) == i
           34 
           35     @staticmethod
           36     def compare(a, b):
           37 
           38         if len([t[1] for t in a.tags if t[0] == 'h']) == 1:
           39             h1 = sha256([t[1] for t in a.tags if t[0] == 'h'][0].encode('utf-8')).digest()
           40             h2 = [t[1] for t in b.tags if t[0] == 'h'][0]
           41             assert h1 == h2
           42 
           43         # Need to filter out these, since they are being modified during
           44         # encoding, i.e., hashed
           45         a.tags = [t for t in a.tags if t[0] != 'h' and t[0] != 'n']
           46         b.tags = [t for t in b.tags if t[0] != 'h' and t[0] != 'n']
           47 
           48         assert b.pubkey.serialize() == PUBKEY, (hexlify(b.pubkey.serialize()), hexlify(PUBKEY))
           49         assert b.signature != None
           50 
           51         # Unset these, they are generated during encoding/decoding
           52         b.pubkey = None
           53         b.signature = None
           54 
           55         assert a.__dict__ == b.__dict__, (pprint.pformat([a.__dict__, b.__dict__]))
           56 
           57     def test_roundtrip(self):
           58         longdescription = ('One piece of chocolate cake, one icecream cone, one'
           59                           ' pickle, one slice of swiss cheese, one slice of salami,'
           60                           ' one lollypop, one piece of cherry pie, one sausage, one'
           61                           ' cupcake, and one slice of watermelon')
           62 
           63 
           64         tests = [
           65             LnAddr(paymenthash=RHASH, tags=[('d', '')]),
           66             LnAddr(paymenthash=RHASH, amount=Decimal('0.001'), tags=[('d', '1 cup coffee'), ('x', 60)]),
           67             LnAddr(paymenthash=RHASH, amount=Decimal('1'), tags=[('h', longdescription)]),
           68             LnAddr(paymenthash=RHASH, currency='tb', tags=[('f', 'mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP'), ('h', longdescription)]),
           69             LnAddr(paymenthash=RHASH, amount=24, tags=[
           70                 ('r', [(unhexlify('029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255'), unhexlify('0102030405060708'), 1, 20, 3),
           71                        (unhexlify('039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255'), unhexlify('030405060708090a'), 2, 30, 4)]),
           72                 ('f', '1RustyRX2oai4EYYDpQGWvEL62BBGqN9T'),
           73                 ('h', longdescription)]),
           74             LnAddr(paymenthash=RHASH, amount=24, tags=[('f', '3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX'), ('h', longdescription)]),
           75             LnAddr(paymenthash=RHASH, amount=24, tags=[('f', 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'), ('h', longdescription)]),
           76             LnAddr(paymenthash=RHASH, amount=24, tags=[('f', 'bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3'), ('h', longdescription)]),
           77             LnAddr(paymenthash=RHASH, amount=24, tags=[('n', PUBKEY), ('h', longdescription)]),
           78             LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 514)]),
           79             LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 8))]),
           80             LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 9))]),
           81             LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 7) + (1 << 11))]),
           82             LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 12))]),
           83             LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 13))]),
           84             LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 9) + (1 << 14))]),
           85             LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 9) + (1 << 15))]),
           86             LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 33282)], payment_secret=b"\x11" * 32),
           87         ]
           88 
           89         # Roundtrip
           90         for t in tests:
           91             o = lndecode(lnencode(t, PRIVKEY), expected_hrp=t.currency)
           92             self.compare(t, o)
           93 
           94     def test_n_decoding(self):
           95         # We flip the signature recovery bit, which would normally give a different
           96         # pubkey.
           97         hrp, data = bech32_decode(lnencode(LnAddr(paymenthash=RHASH, amount=24, tags=[('d', '')]), PRIVKEY), True)
           98         databits = u5_to_bitarray(data)
           99         databits.invert(-1)
          100         lnaddr = lndecode(bech32_encode(hrp, bitarray_to_u5(databits)), verbose=True)
          101         assert lnaddr.pubkey.serialize() != PUBKEY
          102 
          103         # But not if we supply expliciy `n` specifier!
          104         hrp, data = bech32_decode(lnencode(LnAddr(paymenthash=RHASH, amount=24,
          105                                                   tags=[('d', ''),
          106                                                         ('n', PUBKEY)]),
          107                                            PRIVKEY), True)
          108         databits = u5_to_bitarray(data)
          109         databits.invert(-1)
          110         lnaddr = lndecode(bech32_encode(hrp, bitarray_to_u5(databits)), verbose=True)
          111         assert lnaddr.pubkey.serialize() == PUBKEY
          112 
          113     def test_min_final_cltv_expiry_decoding(self):
          114         lnaddr = lndecode("lnsb500u1pdsgyf3pp5nmrqejdsdgs4n9ukgxcp2kcq265yhrxd4k5dyue58rxtp5y83s3qdqqcqzystrggccm9yvkr5yqx83jxll0qjpmgfg9ywmcd8g33msfgmqgyfyvqhku80qmqm8q6v35zvck2y5ccxsz5avtrauz8hgjj3uahppyq20qp6dvwxe",
          115                           expected_hrp="sb")
          116         self.assertEqual(144, lnaddr.get_min_final_cltv_expiry())
          117 
          118         lnaddr = lndecode("lntb15u1p0m6lzupp5zqjthgvaad9mewmdjuehwddyze9d8zyxcc43zhaddeegt37sndgsdq4xysyymr0vd4kzcmrd9hx7cqp7xqrrss9qy9qsqsp5vlhcs24hwm747w8f3uau2tlrdkvjaglffnsstwyamj84cxuhrn2s8tut3jqumepu42azyyjpgqa4w9w03204zp9h4clk499y2umstl6s29hqyj8vv4as6zt5567ux7l3f66m8pjhk65zjaq2esezk7ll2kcpljewkg",
          119                           expected_hrp="tb")
          120         self.assertEqual(30, lnaddr.get_min_final_cltv_expiry())
          121 
          122     def test_min_final_cltv_expiry_roundtrip(self):
          123         for cltv in (1, 15, 16, 31, 32, 33, 150, 511, 512, 513, 1023, 1024, 1025):
          124             lnaddr = LnAddr(paymenthash=RHASH, amount=Decimal('0.001'), tags=[('d', '1 cup coffee'), ('x', 60), ('c', cltv)])
          125             invoice = lnencode(lnaddr, PRIVKEY)
          126             self.assertEqual(cltv, lndecode(invoice).get_min_final_cltv_expiry())
          127 
          128     def test_features(self):
          129         lnaddr = lndecode("lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdees9qzsze992adudgku8p05pstl6zh7av6rx2f297pv89gu5q93a0hf3g7lynl3xq56t23dpvah6u7y9qey9lccrdml3gaqwc6nxsl5ktzm464sq73t7cl")
          130         self.assertEqual(514, lnaddr.get_tag('9'))
          131         self.assertEqual(LnFeatures(514), lnaddr.get_features())
          132 
          133         with self.assertRaises(UnknownEvenFeatureBits):
          134             lndecode("lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdees9q4pqqqqqqqqqqqqqqqqqqszk3ed62snp73037h4py4gry05eltlp0uezm2w9ajnerhmxzhzhsu40g9mgyx5v3ad4aqwkmvyftzk4k9zenz90mhjcy9hcevc7r3lx2sphzfxz7")
          135 
          136     def test_payment_secret(self):
          137         lnaddr = lndecode("lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsdq5vdhkven9v5sxyetpdees9q5sqqqqqqqqqqqqqqqpqsqvvh7ut50r00p3pg34ea68k7zfw64f8yx9jcdk35lh5ft8qdr8g4r0xzsdcrmcy9hex8un8d8yraewvhqc9l0sh8l0e0yvmtxde2z0hgpzsje5l")
          138         self.assertEqual((1 << 9) + (1 << 15) + (1 << 99), lnaddr.get_tag('9'))
          139         self.assertEqual(b"\x11" * 32, lnaddr.payment_secret)
          140 
          141     def test_derive_payment_secret_from_payment_preimage(self):
          142         preimage = bytes.fromhex("cc3fc000bdeff545acee53ada12ff96060834be263f77d645abbebc3a8d53b92")
          143         self.assertEqual("bfd660b559b3f452c6bb05b8d2906f520c151c107b733863ed0cc53fc77021a8",
          144                          derive_payment_secret_from_payment_preimage(preimage).hex())