Example #1
0
    def test_n_decoding(self):
        # We flip the signature recovery bit, which would normally give a different
        # pubkey.
        _, hrp, data = bech32_decode(lnencode(
            LnAddr(paymenthash=RHASH, amount=24, tags=[('d', '')]), PRIVKEY),
                                     ignore_long_length=True)
        databits = u5_to_bitarray(data)
        databits.invert(-1)
        lnaddr = lndecode(bech32_encode(segwit_addr.Encoding.BECH32, hrp,
                                        bitarray_to_u5(databits)),
                          verbose=True)
        assert lnaddr.pubkey.serialize() != PUBKEY

        # But not if we supply expliciy `n` specifier!
        _, hrp, data = bech32_decode(lnencode(
            LnAddr(paymenthash=RHASH,
                   amount=24,
                   tags=[('d', ''), ('n', PUBKEY)]), PRIVKEY),
                                     ignore_long_length=True)
        databits = u5_to_bitarray(data)
        databits.invert(-1)
        lnaddr = lndecode(bech32_encode(segwit_addr.Encoding.BECH32, hrp,
                                        bitarray_to_u5(databits)),
                          verbose=True)
        assert lnaddr.pubkey.serialize() == PUBKEY
    def test_features(self):
        lnaddr = lndecode("lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdees9qzsze992adudgku8p05pstl6zh7av6rx2f297pv89gu5q93a0hf3g7lynl3xq56t23dpvah6u7y9qey9lccrdml3gaqwc6nxsl5ktzm464sq73t7cl")
        self.assertEqual(514, lnaddr.get_tag('9'))
        self.assertEqual(LnFeatures(514), lnaddr.get_features())

        with self.assertRaises(UnknownEvenFeatureBits):
            lndecode("lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdees9q4pqqqqqqqqqqqqqqqqqqszk3ed62snp73037h4py4gry05eltlp0uezm2w9ajnerhmxzhzhsu40g9mgyx5v3ad4aqwkmvyftzk4k9zenz90mhjcy9hcevc7r3lx2sphzfxz7")
    def test_min_final_cltv_expiry_decoding(self):
        lnaddr = lndecode("lnsb500u1pdsgyf3pp5nmrqejdsdgs4n9ukgxcp2kcq265yhrxd4k5dyue58rxtp5y83s3qdqqcqzystrggccm9yvkr5yqx83jxll0qjpmgfg9ywmcd8g33msfgmqgyfyvqhku80qmqm8q6v35zvck2y5ccxsz5avtrauz8hgjj3uahppyq20qp6dvwxe",
                          expected_hrp="sb")
        self.assertEqual(144, lnaddr.get_min_final_cltv_expiry())

        lnaddr = lndecode("lntb15u1p0m6lzupp5zqjthgvaad9mewmdjuehwddyze9d8zyxcc43zhaddeegt37sndgsdq4xysyymr0vd4kzcmrd9hx7cqp7xqrrss9qy9qsqsp5vlhcs24hwm747w8f3uau2tlrdkvjaglffnsstwyamj84cxuhrn2s8tut3jqumepu42azyyjpgqa4w9w03204zp9h4clk499y2umstl6s29hqyj8vv4as6zt5567ux7l3f66m8pjhk65zjaq2esezk7ll2kcpljewkg",
                          expected_hrp="tb")
        self.assertEqual(30, lnaddr.get_min_final_cltv_expiry())
Example #4
0
        async def pay():
            await asyncio.wait_for(p1.initialized, 1)
            await asyncio.wait_for(p2.initialized, 1)
            # prep
            _maybe_send_commitment1 = p1.maybe_send_commitment
            _maybe_send_commitment2 = p2.maybe_send_commitment
            pay_req2 = await self.prepare_invoice(w2)
            lnaddr2 = lndecode(pay_req2, expected_hrp=constants.net.SEGWIT_HRP)
            pay_req1 = await self.prepare_invoice(w1)
            lnaddr1 = lndecode(pay_req1, expected_hrp=constants.net.SEGWIT_HRP)
            # create the htlc queues now (side-effecting defaultdict)
            q1 = w1.sent_htlcs[lnaddr2.paymenthash]
            q2 = w2.sent_htlcs[lnaddr1.paymenthash]
            # alice sends htlc BUT NOT COMMITMENT_SIGNED
            p1.maybe_send_commitment = lambda x: None
            route1, amount_msat1 = w1.create_routes_from_invoice(
                lnaddr2.get_amount_msat(), decoded_invoice=lnaddr2)[0]
            p1.pay(
                route=route1,
                chan=alice_channel,
                amount_msat=lnaddr2.get_amount_msat(),
                total_msat=lnaddr2.get_amount_msat(),
                payment_hash=lnaddr2.paymenthash,
                min_final_cltv_expiry=lnaddr2.get_min_final_cltv_expiry(),
                payment_secret=lnaddr2.payment_secret,
            )
            p1.maybe_send_commitment = _maybe_send_commitment1
            # bob sends htlc BUT NOT COMMITMENT_SIGNED
            p2.maybe_send_commitment = lambda x: None
            route2, amount_msat2 = w2.create_routes_from_invoice(
                lnaddr1.get_amount_msat(), decoded_invoice=lnaddr1)[0]
            p2.pay(
                route=route2,
                chan=bob_channel,
                amount_msat=lnaddr1.get_amount_msat(),
                total_msat=lnaddr1.get_amount_msat(),
                payment_hash=lnaddr1.paymenthash,
                min_final_cltv_expiry=lnaddr1.get_min_final_cltv_expiry(),
                payment_secret=lnaddr1.payment_secret,
            )
            p2.maybe_send_commitment = _maybe_send_commitment2
            # sleep a bit so that they both receive msgs sent so far
            await asyncio.sleep(0.2)
            # now they both send COMMITMENT_SIGNED
            p1.maybe_send_commitment(alice_channel)
            p2.maybe_send_commitment(bob_channel)

            htlc_log1 = await q1.get()
            assert htlc_log1.success
            htlc_log2 = await q2.get()
            assert htlc_log2.success
            raise PaymentDone()
Example #5
0
    def set_bolt11(self, invoice: str):
        """Parse ln invoice, and prepare the send tab for it."""
        try:
            lnaddr = lndecode(invoice)
        except LnInvoiceException as e:
            self.show_error(_("Error parsing Lightning invoice") + f":\n{e}")
            return
        except lnutil.IncompatibleOrInsaneFeatures as e:
            self.show_error(
                _("Invoice requires unknown or incompatible Lightning feature")
                + f":\n{e!r}")
            return

        pubkey = bh2u(lnaddr.pubkey.serialize())
        for k, v in lnaddr.tags:
            if k == 'd':
                description = v
                break
        else:
            description = ''
        self.payto_e.setFrozen(True)
        self.payto_e.setTextNoCheck(pubkey)
        self.payto_e.lightning_invoice = invoice
        if not self.message_e.text():
            self.message_e.setText(description)
        if lnaddr.get_amount_sat() is not None:
            self.amount_e.setAmount(lnaddr.get_amount_sat())
        self.set_onchain(False)
Example #6
0
 def test_close(self):
     alice_channel, bob_channel = create_test_channels()
     p1, p2, w1, w2, _q1, _q2 = self.prepare_peers(alice_channel, bob_channel)
     w1.network.config.set_key('dynamic_fees', False)
     w2.network.config.set_key('dynamic_fees', False)
     w1.network.config.set_key('fee_per_kb', 5000)
     w2.network.config.set_key('fee_per_kb', 1000)
     w2.enable_htlc_settle.clear()
     pay_req = run(self.prepare_invoice(w2))
     lnaddr = lndecode(pay_req, expected_hrp=constants.net.SEGWIT_HRP)
     async def pay():
         await asyncio.wait_for(p1.initialized, 1)
         await asyncio.wait_for(p2.initialized, 1)
         # alice sends htlc
         route = w1._create_route_from_invoice(decoded_invoice=lnaddr)
         htlc = p1.pay(route=route,
                       chan=alice_channel,
                       amount_msat=lnaddr.get_amount_msat(),
                       payment_hash=lnaddr.paymenthash,
                       min_final_cltv_expiry=lnaddr.get_min_final_cltv_expiry(),
                       payment_secret=lnaddr.payment_secret)
         # alice closes
         await p1.close_channel(alice_channel.channel_id)
         gath.cancel()
     async def set_settle():
         await asyncio.sleep(0.1)
         w2.enable_htlc_settle.set()
     gath = asyncio.gather(pay(), set_settle(), p1._message_loop(), p2._message_loop(), p1.htlc_switch(), p2.htlc_switch())
     async def f():
         await gath
     with self.assertRaises(concurrent.futures.CancelledError):
         run(f())
Example #7
0
 def test_payment_secret(self):
     lnaddr = lndecode(
         frombtc(
             "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsdq5vdhkven9v5sxyetpdees9q5sqqqqqqqqqqqqqqqpqsqvvh7ut50r00p3pg34ea68k7zfw64f8yx9jcdk35lh5ft8qdr8g4r0xzsdcrmcy9hex8un8d8yraewvhqc9l0sh8l0e0yvmtxde2z0hgpzsje5l"
         ))
     self.assertEqual((1 << 9) + (1 << 15) + (1 << 99), lnaddr.get_tag('9'))
     self.assertEqual(b"\x11" * 32, lnaddr.payment_secret)
Example #8
0
        async def pay():
            await asyncio.wait_for(p1.initialized, 1)
            await asyncio.wait_for(p2.initialized, 1)
            # prep
            _maybe_send_commitment1 = p1.maybe_send_commitment
            _maybe_send_commitment2 = p2.maybe_send_commitment
            pay_req2 = await self.prepare_invoice(w2)
            lnaddr2 = lndecode(pay_req2, expected_hrp=constants.net.SEGWIT_HRP)
            pay_req1 = await self.prepare_invoice(w1)
            lnaddr1 = lndecode(pay_req1, expected_hrp=constants.net.SEGWIT_HRP)
            # alice sends htlc BUT NOT COMMITMENT_SIGNED
            p1.maybe_send_commitment = lambda x: None
            p1.pay(
                route=w1._create_route_from_invoice(decoded_invoice=lnaddr2),
                chan=alice_channel,
                amount_msat=lnaddr2.get_amount_msat(),
                payment_hash=lnaddr2.paymenthash,
                min_final_cltv_expiry=lnaddr2.get_min_final_cltv_expiry(),
                payment_secret=lnaddr2.payment_secret,
            )
            w1.pending_payments[lnaddr2.paymenthash] = asyncio.Future()
            p1.maybe_send_commitment = _maybe_send_commitment1
            # bob sends htlc BUT NOT COMMITMENT_SIGNED
            p2.maybe_send_commitment = lambda x: None
            p2.pay(
                route=w2._create_route_from_invoice(decoded_invoice=lnaddr1),
                chan=bob_channel,
                amount_msat=lnaddr1.get_amount_msat(),
                payment_hash=lnaddr1.paymenthash,
                min_final_cltv_expiry=lnaddr1.get_min_final_cltv_expiry(),
                payment_secret=lnaddr1.payment_secret,
            )
            w2.pending_payments[lnaddr1.paymenthash] = asyncio.Future()
            p2.maybe_send_commitment = _maybe_send_commitment2
            # sleep a bit so that they both receive msgs sent so far
            await asyncio.sleep(0.1)
            # now they both send COMMITMENT_SIGNED
            p1.maybe_send_commitment(alice_channel)
            p2.maybe_send_commitment(bob_channel)

            payment_attempt1 = await w1.await_payment(lnaddr2.paymenthash)
            assert payment_attempt1.success
            payment_attempt2 = await w2.await_payment(lnaddr1.paymenthash)
            assert payment_attempt2.success
            raise PaymentDone()
Example #9
0
    def test_n_decoding(self):
        # We flip the signature recovery bit, which would normally give a different
        # pubkey.
        hrp, data = bech32_decode(lnencode(LnAddr(RHASH, amount=24, tags=[('d', '')]), PRIVKEY), True)
        databits = u5_to_bitarray(data)
        databits.invert(-1)
        lnaddr = lndecode(bech32_encode(hrp, bitarray_to_u5(databits)), True)
        assert lnaddr.pubkey.serialize() != PUBKEY

        # But not if we supply expliciy `n` specifier!
        hrp, data = bech32_decode(lnencode(LnAddr(RHASH, amount=24,
                                                  tags=[('d', ''),
                                                        ('n', PUBKEY)]),
                                           PRIVKEY), True)
        databits = u5_to_bitarray(data)
        databits.invert(-1)
        lnaddr = lndecode(bech32_encode(hrp, bitarray_to_u5(databits)), True)
        assert lnaddr.pubkey.serialize() == PUBKEY
    def test_roundtrip(self):
        longdescription = ('One piece of chocolate cake, one icecream cone, one'
                          ' pickle, one slice of swiss cheese, one slice of salami,'
                          ' one lollypop, one piece of cherry pie, one sausage, one'
                          ' cupcake, and one slice of watermelon')

        timestamp = 1615922274
        tests = [
            (LnAddr(date=timestamp, paymenthash=RHASH, tags=[('d', '')]),
             "lnbc1ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdqqd9n3kwjjwglnfne5p4rvkze998m3xcxrc8kunl5khkchlaqhwhlyztuuwkrglv47mqg96mcqjjx70hh9luaj4te0u4ww6aclxwve3fqpkmdxlj"),
            (LnAddr(date=timestamp, paymenthash=RHASH, amount=Decimal('0.001'), tags=[('d', '1 cup coffee'), ('x', 60)]),
             "lnbc1m1ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpu9rflz25dx0qw6kdg05u0c5hdc30yq6ga6ew4pz86n244va45nchns9zrs3wjxznsqnt37hz7pswvc56wvuhxcjyd6k3lqf4ujynyxuspmvr078"),
            (LnAddr(date=timestamp, paymenthash=RHASH, amount=Decimal('1'), tags=[('h', longdescription)]),
             "lnbc11ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs2qjafckq94q3js6lvqz2kmenn9ysjejyj8fm4hlx0xtqhaxfzlxjappkgp0hmm40dnuan4v3jy83lqjup2n0fdzgysg049y9l9uc98qq07kfd3"),
            (LnAddr(date=timestamp, paymenthash=RHASH, currency='tb', tags=[('f', 'mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP'), ('h', longdescription)]),
             "lntb1ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqfpp3x9et2e20v6pu37c5d9vax37wxq72un98hp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsr9zktgu78k8p9t8555ve37qwfvqn6ga37fnfwhgexmf20nzdpmuhwvuv7zra3xrh8y2ggxxuemqfsgka9x7uzsrcx8rfv85c8pmhq9gq4sampn"),
            (LnAddr(date=timestamp, paymenthash=RHASH, amount=24, tags=[
                ('r', [(unhexlify('029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255'), unhexlify('0102030405060708'), 1, 20, 3),
                       (unhexlify('039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255'), unhexlify('030405060708090a'), 2, 30, 4)]),
                ('f', '1RustyRX2oai4EYYDpQGWvEL62BBGqN9T'),
                ('h', longdescription)]),
             "lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqr9yq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzqfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85fhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsq68hmxx9ar8eh9nq6gcafxd4vn4mqy458f744t0lms3anm2svydxx2lv84ardcks83u0h34u3lvflh0x9y8qdgjj3q3lxqp5kzqueygqema2z9"),
            (LnAddr(date=timestamp, paymenthash=RHASH, amount=24, tags=[('f', '3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX'), ('h', longdescription)]),
             "lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqfppj3a24vwu6r8ejrss3axul8rxldph2q7z9hp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfa9a608cewefn0n6wflmd27s4nvevru262k2uj34wq58c4y5tqjrs77kvd5umnjgpndxfchde0h0mc07l65agyh9dqlgz5ujhpe8ewspsve8hh"),
            (LnAddr(date=timestamp, paymenthash=RHASH, amount=24, tags=[('f', 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'), ('h', longdescription)]),
             "lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqfppqw508d6qejxtdg4y5r3zarvary0c5xw7khp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqstrtguf9h6ur3n3dchft84q46yy50gf0vugq8g3n88txqcn25dhg98tt4wvlhy967cdarj6cznwn3uyssqeu0e3jgdt9mh5nz9xyqsggpnp2hht"),
            (LnAddr(date=timestamp, paymenthash=RHASH, amount=24, tags=[('f', 'bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3'), ('h', longdescription)]),
             "lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqfp4qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsvv679nlk4m93cahuxv04qqv6q8gshqu5f5tcgcasayuejxny4t4rpugqh4fy4zrma23ts93zclhsm694pu9ll0qlfaqkpstu7u02l8gq6fr4jy"),
            (LnAddr(date=timestamp, paymenthash=RHASH, amount=24, tags=[('n', PUBKEY), ('h', longdescription)]),
             "lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqnp4q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66hp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqst7hmgl7lmqxaael9g7w3e43acceyz93920457yv2egsfkcpnxqf9p0wu8x6dy34k580rulrtvt77f757g2k9lkf7ggph4pyux6e8wksq5ejkr3"),
            (LnAddr(date=timestamp, paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 514)]),
             "lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qzsz20x48k6dgxsrrsqhccvuwtsjny2flcyhlpyuz5lufn4wvjml7wwkaaxfyxpkk2j84hq4xdvm2pt265hm7jy97p5f34gu2tcwgvd9j4gqcam6kj"),
            (LnAddr(date=timestamp, paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 8))]),
             "lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qzg2f9ep5rqksjjdjzq20eqkwvsd0gx0llf2lv6x395l3ph82naeqkg3slj7s326sqnk4ql32acs2fft4p5tyjt8ujxtnhauu4mp7w4xgaqpp7a6ha"),
            (LnAddr(date=timestamp, paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 9))]),
             "lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qzs2035s0h84dfv9lykfcscuh5phy8mmq53nyu9szwln7d02xaz57t59p22pkzavenfa8qetvtkf27l9h9n3k55puvx6573d7fwhmwp6cvcqjvjqe7"),
            (LnAddr(date=timestamp, paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 7) + (1 << 11))]),
             "lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qrzy2tq24ful9ktl7dsnpr8y53dg5w6g2cak8q4pchzjepedmrxhv7qm3z5hhca5c3yjd34cvcc0qd7ntwgefrxxn0cmcsn4cxlnkvrmx5gcp3mmpw5"),
            (LnAddr(date=timestamp, paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 12))]),
             "lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qryq226vdxsf8jq83t80fmunnlkj3va9nmw54x9ze0tqnyvvqch675y29pm978ppkhgp6hnwj98g4zalgecpqkckr9x90ugq44e5tnfe7kxqplr63uz"),
            (LnAddr(date=timestamp, paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 13))]),
             "lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qrgq2f4fm9v4qzp3072d6vaslq99m0rhmfa7plx6wumu6rpdpz53l2zuhc56xekrzwqwsdaahsl8jg0vh3zhpvc78ywc9cas859mvs28xfpgpgn8usc"),
            (LnAddr(date=timestamp, paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 9) + (1 << 14))]),
             "lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qrss2y8hzphx329clpfz86r60zd3ctn2q0uuakge6qws075r7sf43r8wpmrv36ujj68mzdw6rhkxy4mal5zullec8v6yjnnsh093qjwc5cuspz34uag"),
            (LnAddr(date=timestamp, paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 9) + (1 << 15))]),
             "lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qypqs2gc0fc84x29vk0pmq6p4qcn2ttn9azxtfrf2xqz00e79cfvf4nqvx96hz94uqsh4j4hnyywp63nagddwm0zdscprvkqlhltysa478x3sqkee5v9"),
            (LnAddr(date=timestamp, paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 33282)], payment_secret=b"\x11" * 32),
             "lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygshp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qypqszrwfgrl5k3rt4q4mclc8t00p2tcjsf9pmpcq6lu5zhmampyvk43fk30eqpdm8t5qmdpzan25aqxqaqdzmy0smrtduazjcxx975vz78ccpx0qhev"),
        ]

        # Roundtrip
        for lnaddr1, invoice_str1 in tests:
            invoice_str2 = lnencode(lnaddr1, PRIVKEY)
            self.assertEqual(invoice_str1, invoice_str2)
            lnaddr2 = lndecode(invoice_str2, expected_hrp=lnaddr1.currency)
            self.compare(lnaddr1, lnaddr2)
Example #11
0
 def test_min_final_cltv_expiry_roundtrip(self):
     for cltv in (1, 15, 16, 31, 32, 33, 150, 511, 512, 513, 1023, 1024,
                  1025):
         lnaddr = LnAddr(paymenthash=RHASH,
                         amount=Decimal('0.001'),
                         tags=[('d', '1 cup coffee'), ('x', 60),
                               ('c', cltv)])
         invoice = lnencode(lnaddr, PRIVKEY)
         self.assertEqual(cltv,
                          lndecode(invoice).get_min_final_cltv_expiry())
Example #12
0
    def test_roundtrip(self):
        longdescription = (
            'One piece of chocolate cake, one icecream cone, one'
            ' pickle, one slice of swiss cheese, one slice of salami,'
            ' one lollypop, one piece of cherry pie, one sausage, one'
            ' cupcake, and one slice of watermelon')

        tests = [
            LnAddr(RHASH, tags=[('d', '')]),
            LnAddr(RHASH,
                   amount=Decimal('0.001'),
                   tags=[('d', '1 cup coffee'), ('x', 60)]),
            LnAddr(RHASH, amount=Decimal('1'), tags=[('h', longdescription)]),
            LnAddr(RHASH,
                   currency='tvips',
                   tags=[('f', 'vC85Vpqwn7T26MRixyQ2NVhVqCqLHLxfEG'),
                         ('h', longdescription)]),
            LnAddr(
                RHASH,
                amount=24,
                tags=
                [('r',
                  [(unhexlify(
                      '029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255'
                  ),
                    unhexlify('0102030405060708'), 1, 20, 3),
                   (unhexlify(
                       '039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255'
                   ), unhexlify('030405060708090a'), 2, 30, 4)]),
                 ('f', 'VB68oVqbDfEuxPzcFb8iDHyJPQ4CsmDX9b'),
                 ('h', longdescription)]),
            LnAddr(RHASH,
                   amount=24,
                   tags=[('f', 'MLy36ApB4YZb2cBtTc1uYJhYsP2JkYokaf'),
                         ('h', longdescription)]),
            LnAddr(RHASH,
                   amount=24,
                   tags=[('f', 'vips1qw508d6qejxtdg4y5r3zarvary0c5xw7kt9g2vs'),
                         ('h', longdescription)]),
            LnAddr(
                RHASH,
                amount=24,
                tags=
                [('f',
                  'vips1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qxrj3jc'
                  ), ('h', longdescription)]),
            LnAddr(RHASH,
                   amount=24,
                   tags=[('n', PUBKEY), ('h', longdescription)]),
        ]

        # Roundtrip
        for t in tests:
            o = lndecode(lnencode(t, PRIVKEY), expected_hrp=t.currency)
            self.compare(t, o)
Example #13
0
    def test_roundtrip(self):
        longdescription = (
            'One piece of chocolate cake, one icecream cone, one'
            ' pickle, one slice of swiss cheese, one slice of salami,'
            ' one lollypop, one piece of cherry pie, one sausage, one'
            ' cupcake, and one slice of watermelon')

        tests = [
            LnAddr(RHASH, tags=[('d', '')]),
            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=
                [('r',
                  [(unhexlify(
                      '029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255'
                  ),
                    unhexlify('0102030405060708'), 1, 20, 3),
                   (unhexlify(
                       '039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255'
                   ), unhexlify('030405060708090a'), 2, 30, 4)]),
                 ('f', '1RustyRX2oai4EYYDpQGWvEL62BBGqN9T'),
                 ('h', longdescription)]),
            LnAddr(RHASH,
                   amount=24,
                   tags=[('f', '3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX'),
                         ('h', longdescription)]),
            LnAddr(RHASH,
                   amount=24,
                   tags=[('f', 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'),
                         ('h', longdescription)]),
            LnAddr(
                RHASH,
                amount=24,
                tags=
                [('f',
                  'bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3'
                  ), ('h', longdescription)]),
            LnAddr(RHASH,
                   amount=24,
                   tags=[('n', PUBKEY), ('h', longdescription)]),
        ]

        # Roundtrip
        for t in tests:
            o = lndecode(lnencode(t, PRIVKEY), False, t.currency)
            self.compare(t, o)
Example #14
0
 def set_ln_invoice(self, invoice):
     try:
         lnaddr = lndecode(invoice, expected_hrp=constants.net.SEGWIT_HRP)
     except Exception as e:
         self.app.show_info(invoice + _(" is not a valid Lightning invoice: ") + repr(e)) # repr because str(Exception()) == ''
         return
     self.screen.address = invoice
     self.screen.message = dict(lnaddr.tags).get('d', None)
     self.screen.amount = self.app.format_amount_and_units(lnaddr.amount * bitcoin.COIN) if lnaddr.amount else ''
     self.payment_request = None
     self.screen.is_lightning = True
Example #15
0
 def set_ln_invoice(self, invoice: str):
     try:
         invoice = str(invoice).lower()
         lnaddr = lndecode(invoice)
     except LnInvoiceException as e:
         self.app.show_info(_("Invoice is not a valid Lightning invoice: ") + repr(e)) # repr because str(Exception()) == ''
         return
     self.address = invoice
     self.message = dict(lnaddr.tags).get('d', None)
     self.amount = self.app.format_amount_and_units(lnaddr.amount * bitcoin.COIN) if lnaddr.amount else ''
     self.payment_request = None
     self.is_lightning = True
Example #16
0
 async def f():
     async with TaskGroup() as group:
         for peer in peers:
             await group.spawn(peer._message_loop())
             await group.spawn(peer.htlc_switch())
         await asyncio.sleep(0.2)
         pay_req = await self.prepare_invoice(
             graph.w_d, include_routing_hints=True)
         invoice_features = LnFeatures(
             lndecode(pay_req).get_tag('9') or 0)
         self.assertFalse(
             invoice_features.supports(LnFeatures.BASIC_MPP_OPT))
         await group.spawn(pay(pay_req))
    def make_model(self, htlcs) -> QtGui.QStandardItemModel:
        model = QtGui.QStandardItemModel(0, 2)
        model.setHorizontalHeaderLabels(['HTLC', 'Property value'])
        parentItem = model.invisibleRootItem()
        folder_types = {
            'settled': _('Fulfilled HTLCs'),
            'inflight': _('HTLCs in current commitment transaction')
        }
        self.folders = {}
        self.keyname_rows = {}

        for keyname, i in folder_types.items():
            myFont = QtGui.QFont()
            myFont.setBold(True)
            folder = HTLCItem(i)
            folder.setFont(myFont)
            parentItem.appendRow(folder)
            self.folders[keyname] = folder
            mapping = {}
            num = 0

        invoices = dict(self.window.wallet.lnworker.invoices)
        for pay_hash, item in htlcs.items():
            chan_id, i, direction, status = item
            lnaddr = None
            if pay_hash in invoices:
                invoice = invoices[pay_hash][0]
                lnaddr = lndecode(invoice)
            if status == 'inflight':
                if lnaddr is not None:
                    it = self.make_inflight(lnaddr, i, direction)
                else:
                    it = self.make_htlc_item(i, direction)
            elif status == 'settled':
                it = self.make_htlc_item(i, direction)
                # if we made the invoice and still have it, we can show more info
                if lnaddr is not None:
                    self.append_lnaddr(it, lnaddr)
            self.folders[status].appendRow(it)
            mapping[i.payment_hash] = num
            num += 1
            self.keyname_rows[keyname] = mapping
        return model
Example #18
0
 def set_bolt11(self, invoice: str):
     try:
         invoice = str(invoice).lower()
         lnaddr = lndecode(invoice)
     except LnInvoiceException as e:
         self.app.show_info(
             _("Invoice is not a valid Lightning invoice: ") +
             repr(e))  # repr because str(Exception()) == ''
         return
     except lnutil.IncompatibleOrInsaneFeatures as e:
         self.app.show_info(
             _("Invoice requires unknown or incompatible Lightning feature")
             + f":\n{e!r}")
         return
     self.address = invoice
     self.message = lnaddr.get_description()
     self.amount = self.app.format_amount_and_units(
         lnaddr.amount * bitcoin.COIN) if lnaddr.amount else ''
     self.payment_request = None
     self.is_lightning = True
 def test_min_final_cltv_expiry_decoding(self):
     self.assertEqual(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.assertEqual(150, lndecode(invoice).get_min_final_cltv_expiry())
Example #21
0
class TestPeer(ElectrumTestCase):

    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        console_stderr_handler.setLevel(logging.DEBUG)

    def setUp(self):
        super().setUp()
        self.asyncio_loop, self._stop_loop, self._loop_thread = create_and_start_event_loop()
        self._lnworkers_created = []  # type: List[MockLNWallet]

    def tearDown(self):
        async def cleanup_lnworkers():
            async with TaskGroup() as group:
                for lnworker in self._lnworkers_created:
                    await group.spawn(lnworker.stop())
            self._lnworkers_created.clear()
        run(cleanup_lnworkers())

        self.asyncio_loop.call_soon_threadsafe(self._stop_loop.set_result, 1)
        self._loop_thread.join(timeout=1)
        super().tearDown()

    def prepare_peers(self, alice_channel, bob_channel):
        k1, k2 = keypair(), keypair()
        alice_channel.node_id = k2.pubkey
        bob_channel.node_id = k1.pubkey
        t1, t2 = transport_pair(k1, k2, alice_channel.name, bob_channel.name)
        q1, q2 = asyncio.Queue(), asyncio.Queue()
        w1 = MockLNWallet(local_keypair=k1, chans=[alice_channel], tx_queue=q1, name=bob_channel.name)
        w2 = MockLNWallet(local_keypair=k2, chans=[bob_channel], tx_queue=q2, name=alice_channel.name)
        self._lnworkers_created.extend([w1, w2])
        p1 = Peer(w1, k2.pubkey, t1)
        p2 = Peer(w2, k1.pubkey, t2)
        w1._peers[p1.pubkey] = p1
        w2._peers[p2.pubkey] = p2
        # mark_open won't work if state is already OPEN.
        # so set it to FUNDED
        alice_channel._state = ChannelState.FUNDED
        bob_channel._state = ChannelState.FUNDED
        # this populates the channel graph:
        p1.mark_open(alice_channel)
        p2.mark_open(bob_channel)
        return p1, p2, w1, w2, q1, q2

    def prepare_chans_and_peers_in_square(self) -> SquareGraph:
        key_a, key_b, key_c, key_d = [keypair() for i in range(4)]
        chan_ab, chan_ba = create_test_channels(alice_name="alice", bob_name="bob", alice_pubkey=key_a.pubkey, bob_pubkey=key_b.pubkey)
        chan_ac, chan_ca = create_test_channels(alice_name="alice", bob_name="carol", alice_pubkey=key_a.pubkey, bob_pubkey=key_c.pubkey)
        chan_bd, chan_db = create_test_channels(alice_name="bob", bob_name="dave", alice_pubkey=key_b.pubkey, bob_pubkey=key_d.pubkey)
        chan_cd, chan_dc = create_test_channels(alice_name="carol", bob_name="dave", alice_pubkey=key_c.pubkey, bob_pubkey=key_d.pubkey)
        trans_ab, trans_ba = transport_pair(key_a, key_b, chan_ab.name, chan_ba.name)
        trans_ac, trans_ca = transport_pair(key_a, key_c, chan_ac.name, chan_ca.name)
        trans_bd, trans_db = transport_pair(key_b, key_d, chan_bd.name, chan_db.name)
        trans_cd, trans_dc = transport_pair(key_c, key_d, chan_cd.name, chan_dc.name)
        txq_a, txq_b, txq_c, txq_d = [asyncio.Queue() for i in range(4)]
        w_a = MockLNWallet(local_keypair=key_a, chans=[chan_ab, chan_ac], tx_queue=txq_a, name="alice")
        w_b = MockLNWallet(local_keypair=key_b, chans=[chan_ba, chan_bd], tx_queue=txq_b, name="bob")
        w_c = MockLNWallet(local_keypair=key_c, chans=[chan_ca, chan_cd], tx_queue=txq_c, name="carol")
        w_d = MockLNWallet(local_keypair=key_d, chans=[chan_db, chan_dc], tx_queue=txq_d, name="dave")
        self._lnworkers_created.extend([w_a, w_b, w_c, w_d])
        peer_ab = Peer(w_a, key_b.pubkey, trans_ab)
        peer_ac = Peer(w_a, key_c.pubkey, trans_ac)
        peer_ba = Peer(w_b, key_a.pubkey, trans_ba)
        peer_bd = Peer(w_b, key_d.pubkey, trans_bd)
        peer_ca = Peer(w_c, key_a.pubkey, trans_ca)
        peer_cd = Peer(w_c, key_d.pubkey, trans_cd)
        peer_db = Peer(w_d, key_b.pubkey, trans_db)
        peer_dc = Peer(w_d, key_c.pubkey, trans_dc)
        w_a._peers[peer_ab.pubkey] = peer_ab
        w_a._peers[peer_ac.pubkey] = peer_ac
        w_b._peers[peer_ba.pubkey] = peer_ba
        w_b._peers[peer_bd.pubkey] = peer_bd
        w_c._peers[peer_ca.pubkey] = peer_ca
        w_c._peers[peer_cd.pubkey] = peer_cd
        w_d._peers[peer_db.pubkey] = peer_db
        w_d._peers[peer_dc.pubkey] = peer_dc

        w_b.network.config.set_key('lightning_forward_payments', True)
        w_c.network.config.set_key('lightning_forward_payments', True)

        # forwarding fees, etc
        chan_ab.forwarding_fee_proportional_millionths *= 500
        chan_ab.forwarding_fee_base_msat *= 500
        chan_ba.forwarding_fee_proportional_millionths *= 500
        chan_ba.forwarding_fee_base_msat *= 500
        chan_bd.forwarding_fee_proportional_millionths *= 500
        chan_bd.forwarding_fee_base_msat *= 500
        chan_db.forwarding_fee_proportional_millionths *= 500
        chan_db.forwarding_fee_base_msat *= 500

        # mark_open won't work if state is already OPEN.
        # so set it to FUNDED
        for chan in [chan_ab, chan_ac, chan_ba, chan_bd, chan_ca, chan_cd, chan_db, chan_dc]:
            chan._state = ChannelState.FUNDED
        # this populates the channel graph:
        peer_ab.mark_open(chan_ab)
        peer_ac.mark_open(chan_ac)
        peer_ba.mark_open(chan_ba)
        peer_bd.mark_open(chan_bd)
        peer_ca.mark_open(chan_ca)
        peer_cd.mark_open(chan_cd)
        peer_db.mark_open(chan_db)
        peer_dc.mark_open(chan_dc)
        return SquareGraph(
            w_a=w_a,
            w_b=w_b,
            w_c=w_c,
            w_d=w_d,
            peer_ab=peer_ab,
            peer_ac=peer_ac,
            peer_ba=peer_ba,
            peer_bd=peer_bd,
            peer_ca=peer_ca,
            peer_cd=peer_cd,
            peer_db=peer_db,
            peer_dc=peer_dc,
            chan_ab=chan_ab,
            chan_ac=chan_ac,
            chan_ba=chan_ba,
            chan_bd=chan_bd,
            chan_ca=chan_ca,
            chan_cd=chan_cd,
            chan_db=chan_db,
            chan_dc=chan_dc,
        )

    @staticmethod
    async def prepare_invoice(
            w2: MockLNWallet,  # receiver
            *,
            amount_msat=100_000_000,
            include_routing_hints=False,
    ) -> Tuple[LnAddr, str]:
        amount_btc = amount_msat/Decimal(COIN*1000)
        payment_preimage = os.urandom(32)
        RHASH = sha256(payment_preimage)
        info = PaymentInfo(RHASH, amount_msat, RECEIVED, PR_UNPAID)
        w2.save_preimage(RHASH, payment_preimage)
        w2.save_payment_info(info)
        if include_routing_hints:
            routing_hints = await w2._calc_routing_hints_for_invoice(amount_msat)
        else:
            routing_hints = []
        trampoline_hints = []
        for r in routing_hints:
            node_id, short_channel_id, fee_base_msat, fee_proportional_millionths, cltv_expiry_delta = r[1][0]
            if len(r[1])== 1 and w2.is_trampoline_peer(node_id):
                trampoline_hints.append(('t', (node_id, fee_base_msat, fee_proportional_millionths, cltv_expiry_delta)))
        invoice_features = w2.features.for_invoice()
        if invoice_features.supports(LnFeatures.PAYMENT_SECRET_OPT):
            payment_secret = derive_payment_secret_from_payment_preimage(payment_preimage)
        else:
            payment_secret = None
        lnaddr1 = LnAddr(
                    paymenthash=RHASH,
                    amount=amount_btc,
                    tags=[('c', lnutil.MIN_FINAL_CLTV_EXPIRY_FOR_INVOICE),
                          ('d', 'coffee'),
                          ('9', invoice_features),
                         ] + routing_hints + trampoline_hints,
                    payment_secret=payment_secret,
        )
        invoice = lnencode(lnaddr1, w2.node_keypair.privkey)
        lnaddr2 = lndecode(invoice)  # unlike lnaddr1, this now has a pubkey set
        return lnaddr2, invoice