Beispiel #1
0
 def part3(self):
     # Add a HTLC of 2 BTC to Alice, and the settle it.
     # Resulting balances:
     #	Alice:	3.0
     #	Bob:	7.0
     paymentPreimage = b"\x01" * 32
     paymentHash = bitcoin.sha256(paymentPreimage)
     htlc_dict = {
         'payment_hash': paymentHash,
         'amount_msat': int(2 * one_bitcoin_in_msat),
         'cltv_expiry': 5,
         'timestamp': 0,
     }
     alice_idx = self.alice_channel.add_htlc(htlc_dict).htlc_id
     bob_idx = self.bob_channel.receive_htlc(htlc_dict).htlc_id
     force_state_transition(self.alice_channel, self.bob_channel)
     self.check_bals(
         one_bitcoin_in_msat * 3 - self.alice_channel.get_next_fee(LOCAL),
         one_bitcoin_in_msat * 5)
     self.bob_channel.settle_htlc(paymentPreimage, bob_idx)
     self.alice_channel.receive_htlc_settle(paymentPreimage, alice_idx)
     force_state_transition(self.alice_channel, self.bob_channel)
     self.check_bals(
         one_bitcoin_in_msat * 3 - self.alice_channel.get_next_fee(LOCAL),
         one_bitcoin_in_msat * 7)
     # And now let Bob add an HTLC of 1 BTC. This will take Bob's balance
     # all the way down to his channel reserve, but since he is not paying
     # the fee this is okay.
     htlc_dict['amount_msat'] = one_bitcoin_in_msat
     self.bob_channel.add_htlc(htlc_dict)
     self.alice_channel.receive_htlc(htlc_dict)
     force_state_transition(self.alice_channel, self.bob_channel)
     self.check_bals(one_bitcoin_in_msat * 3 \
                     - self.alice_channel.get_next_fee(LOCAL),
                     one_bitcoin_in_msat * 6)
    def test_DustLimit(self):
        alice_channel, bob_channel = create_test_channels()

        paymentPreimage = b"\x01" * 32
        paymentHash = bitcoin.sha256(paymentPreimage)
        fee_per_kw = alice_channel.get_next_feerate(LOCAL)
        self.assertEqual(fee_per_kw, 6000)
        htlcAmt = 500 + lnutil.HTLC_TIMEOUT_WEIGHT * (fee_per_kw // 1000)
        self.assertEqual(htlcAmt, 4478)
        htlc = {
            'payment_hash' : paymentHash,
            'amount_msat' :  1000 * htlcAmt,
            'cltv_expiry' :  5, # also in create_test_channels
            'timestamp'   :  0,
        }

        old_values = [x.value for x in bob_channel.get_latest_commitment(LOCAL).outputs() ]
        aliceHtlcIndex = alice_channel.add_htlc(htlc).htlc_id
        bobHtlcIndex = bob_channel.receive_htlc(htlc).htlc_id
        force_state_transition(alice_channel, bob_channel)
        alice_ctx = alice_channel.get_latest_commitment(LOCAL)
        bob_ctx = bob_channel.get_latest_commitment(LOCAL)
        new_values = [x.value for x in bob_ctx.outputs() ]
        self.assertNotEqual(old_values, new_values)
        self.assertEqual(len(alice_ctx.outputs()), 3)
        self.assertEqual(len(bob_ctx.outputs()), 2)
        default_fee = calc_static_fee(0)
        self.assertEqual(bob_channel.pending_local_fee(), default_fee + htlcAmt)
        bob_channel.settle_htlc(paymentPreimage, bobHtlcIndex)
        alice_channel.receive_htlc_settle(paymentPreimage, aliceHtlcIndex)
        force_state_transition(bob_channel, alice_channel)
        self.assertEqual(len(alice_channel.get_next_commitment(LOCAL).outputs()), 2)
        self.assertEqual(alice_channel.total_msat(SENT) // 1000, htlcAmt)
Beispiel #3
0
 def part2(self):
     paymentPreimage = b"\x01" * 32
     paymentHash = bitcoin.sha256(paymentPreimage)
     # Now we'll add HTLC of 3.5 BTC to Alice's commitment, this should put
     # Alice's balance at 1.5 BTC.
     #
     # Resulting balances:
     #	Alice:	1.5
     #	Bob:	9.5
     htlc_dict = {
         'payment_hash': paymentHash,
         'amount_msat': int(3.5 * one_bitcoin_in_msat),
         'cltv_expiry': 5,
     }
     self.alice_channel.add_htlc(htlc_dict)
     self.bob_channel.receive_htlc(htlc_dict)
     # Add a second HTLC of 1 BTC. This should fail because it will take
     # Alice's balance all the way down to her channel reserve, but since
     # she is the initiator the additional transaction fee makes her
     # balance dip below.
     htlc_dict['amount_msat'] = one_bitcoin_in_msat
     with self.assertRaises(lnutil.PaymentFailure):
         self.alice_channel.add_htlc(htlc_dict)
     with self.assertRaises(lnutil.RemoteMisbehaving):
         self.bob_channel.receive_htlc(htlc_dict)
Beispiel #4
0
    def setUp(self):
        super().setUp()
        # Create a test channel which will be used for the duration of this
        # unittest. The channel will be funded evenly with Alice having 5 BTC,
        # and Bob having 5 BTC.
        self.alice_channel, self.bob_channel = create_test_channels()

        self.paymentPreimage = b"\x01" * 32
        paymentHash = bitcoin.sha256(self.paymentPreimage)
        self.htlc_dict = {
            'payment_hash': paymentHash,
            'amount_msat': one_bitcoin_in_msat,
            'cltv_expiry': 5,
            'timestamp': 0,
        }

        # First Alice adds the outgoing HTLC to her local channel's state
        # update log. Then Alice sends this wire message over to Bob who adds
        # this htlc to his remote state update log.
        self.aliceHtlcIndex = self.alice_channel.add_htlc(
            self.htlc_dict).htlc_id
        self.assertNotEqual(
            list(
                self.alice_channel.hm.htlcs_by_direction(REMOTE, RECEIVED,
                                                         1).values()), [])

        before = self.bob_channel.balance_minus_outgoing_htlcs(REMOTE)
        beforeLocal = self.bob_channel.balance_minus_outgoing_htlcs(LOCAL)

        self.bobHtlcIndex = self.bob_channel.receive_htlc(
            self.htlc_dict).htlc_id

        self.htlc = self.bob_channel.hm.log[REMOTE]['adds'][0]
Beispiel #5
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()

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

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

    @staticmethod
    def prepare_invoice(
            w2,  # receiver
            *,
            amount_sat=100_000,
    ):
        amount_btc = amount_sat/Decimal(COIN)
        payment_preimage = os.urandom(32)
        RHASH = sha256(payment_preimage)
        info = PaymentInfo(RHASH, amount_sat, RECEIVED, PR_UNPAID)
        w2.save_preimage(RHASH, payment_preimage)
        w2.save_payment_info(info)
        lnaddr = LnAddr(
                    RHASH,
                    amount_btc,
                    tags=[('c', lnutil.MIN_FINAL_CLTV_EXPIRY_FOR_INVOICE),
                          ('d', 'coffee')
                         ])
        return lnencode(lnaddr, w2.node_keypair.privkey)
Beispiel #6
0
    def test_part1(self):
        # Add an HTLC that will increase Bob's balance. This should succeed,
        # since Alice stays above her channel reserve, and Bob increases his
        # balance (while still being below his channel reserve).
        #
        # Resulting balances:
        #	Alice:	4.5
        #	Bob:	5.0
        paymentPreimage = b"\x01" * 32
        paymentHash = bitcoin.sha256(paymentPreimage)
        htlc_dict = {
            'payment_hash': paymentHash,
            'amount_msat': int(.5 * one_bitcoin_in_msat),
            'cltv_expiry': 5,
            'timestamp': 0,
        }
        self.alice_channel.add_htlc(htlc_dict)
        self.bob_channel.receive_htlc(htlc_dict)
        # Force a state transition, making sure this HTLC is considered valid
        # even though the channel reserves are not met.
        force_state_transition(self.alice_channel, self.bob_channel)

        aliceSelfBalance = self.alice_channel.balance(LOCAL)\
                - lnchannel.htlcsum(self.alice_channel.hm.htlcs_by_direction(LOCAL, SENT).values())
        bobBalance = self.bob_channel.balance(REMOTE)\
                - lnchannel.htlcsum(self.alice_channel.hm.htlcs_by_direction(REMOTE, SENT).values())
        self.assertEqual(aliceSelfBalance, one_bitcoin_in_msat * 4.5)
        self.assertEqual(bobBalance, one_bitcoin_in_msat * 5)
        # Now let Bob try to add an HTLC. This should fail, since it will
        # decrease his balance, which is already below the channel reserve.
        #
        # Resulting balances:
        #	Alice:	4.5
        #	Bob:	5.0
        with self.assertRaises(lnutil.PaymentFailure):
            htlc_dict['payment_hash'] = bitcoin.sha256(32 * b'\x02')
            self.bob_channel.add_htlc(htlc_dict)
        with self.assertRaises(lnutil.RemoteMisbehaving):
            self.alice_channel.receive_htlc(htlc_dict)
Beispiel #7
0
    def test_AddHTLCNegativeBalance(self):
        # the test in lnd doesn't set the fee to zero.
        # probably lnd subtracts commitment fee after deciding weather
        # an htlc can be added. so we set the fee to zero so that
        # the test can work.
        self.alice_to_bob_fee_update(0)
        force_state_transition(self.alice_channel, self.bob_channel)

        self.htlc_dict['payment_hash'] = bitcoin.sha256(32 * b'\x02')
        self.alice_channel.add_htlc(self.htlc_dict)
        self.htlc_dict['payment_hash'] = bitcoin.sha256(32 * b'\x03')
        self.alice_channel.add_htlc(self.htlc_dict)
        # now there are three htlcs (one was in setUp)

        # Alice now has an available balance of 2 BTC. We'll add a new HTLC of
        # value 2 BTC, which should make Alice's balance negative (since she
        # has to pay a commitment fee).
        new = dict(self.htlc_dict)
        new['amount_msat'] *= 2.5
        new['payment_hash'] = bitcoin.sha256(32 * b'\x04')
        with self.assertRaises(lnutil.PaymentFailure) as cm:
            self.alice_channel.add_htlc(new)
        self.assertIn('Not enough local balance', cm.exception.args[0])
Beispiel #8
0
 def prepare_invoice(w2 # receiver
         ):
     amount_sat = 100000
     amount_btc = amount_sat/Decimal(COIN)
     payment_preimage = os.urandom(32)
     RHASH = sha256(payment_preimage)
     info = PaymentInfo(RHASH, amount_sat, RECEIVED, PR_UNPAID)
     w2.save_preimage(RHASH, payment_preimage)
     w2.save_payment_info(info)
     lnaddr = LnAddr(
                 RHASH,
                 amount_btc,
                 tags=[('c', lnutil.MIN_FINAL_CLTV_EXPIRY_FOR_INVOICE),
                       ('d', 'coffee')
                      ])
     return lnencode(lnaddr, w2.node_keypair.privkey)
Beispiel #9
0
 def test_shachain_produce_consume(self):
     seed = bitcoin.sha256(b"shachaintest")
     consumer = RevocationStore()
     for i in range(10000):
         secret = get_per_commitment_secret_from_seed(
             seed, RevocationStore.START_INDEX - i)
         try:
             consumer.add_next_entry(secret)
         except Exception as e:
             raise Exception("iteration " + str(i) + ": " + str(e))
         if i % 1000 == 0:
             self.assertEqual(
                 consumer.serialize(),
                 RevocationStore.from_json_obj(
                     json.loads(json.dumps(
                         consumer.serialize()))).serialize())
 def test_shachain_produce_consume(self):
     seed = bitcoin.sha256(b"shachaintest")
     consumer = RevocationStore(StoredDict({}, None, []))
     for i in range(10000):
         secret = get_per_commitment_secret_from_seed(
             seed, RevocationStore.START_INDEX - i)
         try:
             consumer.add_next_entry(secret)
         except Exception as e:
             raise Exception("iteration " + str(i) + ": " + str(e))
         if i % 1000 == 0:
             c1 = consumer
             s1 = json.dumps(c1.storage, cls=MyEncoder)
             c2 = RevocationStore(StoredDict(json.loads(s1), None, []))
             s2 = json.dumps(c2.storage, cls=MyEncoder)
             self.assertEqual(s1, s2)
Beispiel #11
0
    def test_DesyncHTLCs(self):
        alice_channel, bob_channel = create_test_channels()
        self.assertEqual(499986152000, alice_channel.available_to_spend(LOCAL))
        self.assertEqual(500000000000, bob_channel.available_to_spend(LOCAL))

        paymentPreimage = b"\x01" * 32
        paymentHash = bitcoin.sha256(paymentPreimage)
        htlc_dict = {
            'payment_hash': paymentHash,
            'amount_msat': one_bitcoin_in_msat * 41 // 10,
            'cltv_expiry': 5,
            'timestamp': 0,
        }

        alice_idx = alice_channel.add_htlc(htlc_dict).htlc_id
        bob_idx = bob_channel.receive_htlc(htlc_dict).htlc_id
        self.assertEqual(89984088000, alice_channel.available_to_spend(LOCAL))
        self.assertEqual(500000000000, bob_channel.available_to_spend(LOCAL))

        force_state_transition(alice_channel, bob_channel)
        bob_channel.fail_htlc(bob_idx)
        alice_channel.receive_fail_htlc(alice_idx, error_bytes=None)
        self.assertEqual(89984088000, alice_channel.available_to_spend(LOCAL))
        self.assertEqual(500000000000, bob_channel.available_to_spend(LOCAL))
        # Alice now has gotten all her original balance (5 BTC) back, however,
        # adding a new HTLC at this point SHOULD fail, since if she adds the
        # HTLC and signs the next state, Bob cannot assume she received the
        # FailHTLC, and must assume she doesn't have the necessary balance
        # available.
        # We try adding an HTLC of value 1 BTC, which should fail because the
        # balance is unavailable.
        htlc_dict = {
            'payment_hash': paymentHash,
            'amount_msat': one_bitcoin_in_msat,
            'cltv_expiry': 5,
            'timestamp': 0,
        }
        with self.assertRaises(lnutil.PaymentFailure):
            alice_channel.add_htlc(htlc_dict)
        # Now do a state transition, which will ACK the FailHTLC, making Alice
        # able to add the new HTLC.
        force_state_transition(alice_channel, bob_channel)
        self.assertEqual(499986152000, alice_channel.available_to_spend(LOCAL))
        self.assertEqual(500000000000, bob_channel.available_to_spend(LOCAL))
        alice_channel.add_htlc(htlc_dict)
Beispiel #12
0
    def test_max_htlc_value(self):
        alice_channel, bob_channel = create_test_channels()
        paymentPreimage = b"\x01" * 32
        paymentHash = bitcoin.sha256(paymentPreimage)
        htlc_dict = {
            'payment_hash': paymentHash,
            'amount_msat': one_bitcoin_in_msat * 41 // 10,
            'cltv_expiry': 5,
            'timestamp': 0,
        }

        alice_channel._ignore_max_htlc_value = False
        bob_channel._ignore_max_htlc_value = False
        with self.assertRaises(lnutil.PaymentFailure):
            alice_channel.add_htlc(htlc_dict)
        with self.assertRaises(lnutil.RemoteMisbehaving):
            bob_channel.receive_htlc(htlc_dict)

        alice_channel._ignore_max_htlc_value = True
        bob_channel._ignore_max_htlc_value = True
        alice_channel.add_htlc(htlc_dict)
        bob_channel.receive_htlc(htlc_dict)
Beispiel #13
0
    def test_concurrent_reversed_payment(self):
        self.htlc_dict['payment_hash'] = bitcoin.sha256(32 * b'\x02')
        self.htlc_dict['amount_msat'] += 1000
        self.bob_channel.add_htlc(self.htlc_dict)
        self.alice_channel.receive_htlc(self.htlc_dict)

        self.assertEqual(
            len(self.alice_channel.get_latest_commitment(LOCAL).outputs()), 2)
        self.assertEqual(
            len(self.alice_channel.get_next_commitment(LOCAL).outputs()), 3)
        self.assertEqual(
            len(self.alice_channel.get_latest_commitment(REMOTE).outputs()), 2)
        self.assertEqual(
            len(self.alice_channel.get_next_commitment(REMOTE).outputs()), 3)

        self.alice_channel.receive_new_commitment(
            *self.bob_channel.sign_next_commitment())

        self.assertEqual(
            len(self.alice_channel.get_latest_commitment(LOCAL).outputs()), 3)
        self.assertEqual(
            len(self.alice_channel.get_next_commitment(LOCAL).outputs()), 3)
        self.assertEqual(
            len(self.alice_channel.get_latest_commitment(REMOTE).outputs()), 2)
        self.assertEqual(
            len(self.alice_channel.get_next_commitment(REMOTE).outputs()), 3)

        self.alice_channel.revoke_current_commitment()

        self.assertEqual(
            len(self.alice_channel.get_latest_commitment(LOCAL).outputs()), 3)
        self.assertEqual(
            len(self.alice_channel.get_next_commitment(LOCAL).outputs()), 3)
        self.assertEqual(
            len(self.alice_channel.get_latest_commitment(REMOTE).outputs()), 2)
        self.assertEqual(
            len(self.alice_channel.get_next_commitment(REMOTE).outputs()), 4)
Beispiel #14
0
            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_sat=100_000,
        include_routing_hints=False,
    ):
        amount_btc = amount_sat / Decimal(COIN)
        payment_preimage = os.urandom(32)
        RHASH = sha256(payment_preimage)
        info = PaymentInfo(RHASH, amount_sat, 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_sat
                                                                     )
        else:
            routing_hints = []
        lnaddr = LnAddr(paymenthash=RHASH,
                        amount=amount_btc,
                        tags=[('c', lnutil.MIN_FINAL_CLTV_EXPIRY_FOR_INVOICE),
                              ('d', 'coffee')] + routing_hints)
        return lnencode(lnaddr, w2.node_keypair.privkey)

    def test_reestablish(self):
Beispiel #15
0
    def test_commitment_tx_with_all_five_HTLCs_untrimmed_minimum_feerate(self):
        to_local_msat = 6988000000
        to_remote_msat = 3000000000
        local_feerate_per_kw = 0
        # base commitment transaction fee = 0
        # actual commitment transaction fee = 0

        per_commitment_secret = 0x1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100
        per_commitment_point = secret_to_pubkey(per_commitment_secret)

        remote_htlcpubkey = remotepubkey
        local_htlcpubkey = localpubkey

        htlc_cltv_timeout = {}
        htlc_payment_preimage = {}
        htlc = {}

        htlc_cltv_timeout[2] = 502
        htlc_payment_preimage[2] = b"\x02" * 32
        htlc[2] = make_offered_htlc(local_revocation_pubkey, remote_htlcpubkey,
                                    local_htlcpubkey,
                                    bitcoin.sha256(htlc_payment_preimage[2]))

        htlc_cltv_timeout[3] = 503
        htlc_payment_preimage[3] = b"\x03" * 32
        htlc[3] = make_offered_htlc(local_revocation_pubkey, remote_htlcpubkey,
                                    local_htlcpubkey,
                                    bitcoin.sha256(htlc_payment_preimage[3]))

        htlc_cltv_timeout[0] = 500
        htlc_payment_preimage[0] = b"\x00" * 32
        htlc[0] = make_received_htlc(local_revocation_pubkey,
                                     remote_htlcpubkey, local_htlcpubkey,
                                     bitcoin.sha256(htlc_payment_preimage[0]),
                                     htlc_cltv_timeout[0])

        htlc_cltv_timeout[1] = 501
        htlc_payment_preimage[1] = b"\x01" * 32
        htlc[1] = make_received_htlc(local_revocation_pubkey,
                                     remote_htlcpubkey, local_htlcpubkey,
                                     bitcoin.sha256(htlc_payment_preimage[1]),
                                     htlc_cltv_timeout[1])

        htlc_cltv_timeout[4] = 504
        htlc_payment_preimage[4] = b"\x04" * 32
        htlc[4] = make_received_htlc(local_revocation_pubkey,
                                     remote_htlcpubkey, local_htlcpubkey,
                                     bitcoin.sha256(htlc_payment_preimage[4]),
                                     htlc_cltv_timeout[4])

        remote_signature = "304402204fd4928835db1ccdfc40f5c78ce9bd65249b16348df81f0c44328dcdefc97d630220194d3869c38bc732dd87d13d2958015e2fc16829e74cd4377f84d215c0b70606"
        output_commit_tx = "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8007e80300000000000022002052bfef0479d7b293c27e0f1eb294bea154c63a3294ef092c19af51409bce0e2ad007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5d007000000000000220020748eba944fedc8827f6b06bc44678f93c0f9e6078b35c6331ed31e75f8ce0c2db80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110e0a06a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e04004730440220275b0c325a5e9355650dc30c0eccfbc7efb23987c24b556b9dfdd40effca18d202206caceb2c067836c51f296740c7ae807ffcbfbf1dd3a0d56b6de9a5b247985f060147304402204fd4928835db1ccdfc40f5c78ce9bd65249b16348df81f0c44328dcdefc97d630220194d3869c38bc732dd87d13d2958015e2fc16829e74cd4377f84d215c0b7060601475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220"

        htlc_obj = {}
        for num, msat in [(0, 1000 * 1000), (2, 2000 * 1000), (1, 2000 * 1000),
                          (3, 3000 * 1000), (4, 4000 * 1000)]:
            htlc_obj[num] = UpdateAddHtlc(amount_msat=msat,
                                          payment_hash=bitcoin.sha256(
                                              htlc_payment_preimage[num]),
                                          cltv_expiry=0,
                                          htlc_id=None,
                                          timestamp=0)
        htlcs = [ScriptHtlc(htlc[x], htlc_obj[x]) for x in range(5)]

        our_commit_tx = make_commitment(commitment_number,
                                        local_funding_pubkey,
                                        remote_funding_pubkey,
                                        remotepubkey,
                                        local_payment_basepoint,
                                        remote_payment_basepoint,
                                        local_revocation_pubkey,
                                        local_delayedpubkey,
                                        local_delay,
                                        funding_tx_id,
                                        funding_output_index,
                                        funding_amount_satoshi,
                                        to_local_msat,
                                        to_remote_msat,
                                        local_dust_limit_satoshi,
                                        calc_onchain_fees(
                                            len(htlcs), local_feerate_per_kw,
                                            True),
                                        htlcs=htlcs)
        self.sign_and_insert_remote_sig(our_commit_tx, remote_funding_pubkey,
                                        remote_signature, local_funding_pubkey,
                                        local_funding_privkey)
        self.assertEqual(str(our_commit_tx), output_commit_tx)

        signature_for_output_remote_htlc = {}
        signature_for_output_remote_htlc[
            0] = "304402206a6e59f18764a5bf8d4fa45eebc591566689441229c918b480fb2af8cc6a4aeb02205248f273be447684b33e3c8d1d85a8e0ca9fa0bae9ae33f0527ada9c162919a6"
        signature_for_output_remote_htlc[
            2] = "3045022100d5275b3619953cb0c3b5aa577f04bc512380e60fa551762ce3d7a1bb7401cff9022037237ab0dac3fe100cde094e82e2bed9ba0ed1bb40154b48e56aa70f259e608b"
        signature_for_output_remote_htlc[
            1] = "304402201b63ec807771baf4fdff523c644080de17f1da478989308ad13a58b51db91d360220568939d38c9ce295adba15665fa68f51d967e8ed14a007b751540a80b325f202"
        signature_for_output_remote_htlc[
            3] = "3045022100daee1808f9861b6c3ecd14f7b707eca02dd6bdfc714ba2f33bc8cdba507bb182022026654bf8863af77d74f51f4e0b62d461a019561bb12acb120d3f7195d148a554"
        signature_for_output_remote_htlc[
            4] = "304402207e0410e45454b0978a623f36a10626ef17b27d9ad44e2760f98cfa3efb37924f0220220bd8acd43ecaa916a80bd4f919c495a2c58982ce7c8625153f8596692a801d"

        output_htlc_tx = {}
        SUCCESS = True
        TIMEOUT = False
        output_htlc_tx[0] = (
            SUCCESS,
            "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219700000000000000000001e8030000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402206a6e59f18764a5bf8d4fa45eebc591566689441229c918b480fb2af8cc6a4aeb02205248f273be447684b33e3c8d1d85a8e0ca9fa0bae9ae33f0527ada9c162919a60147304402207cb324fa0de88f452ffa9389678127ebcf4cabe1dd848b8e076c1a1962bf34720220116ed922b12311bd602d67e60d2529917f21c5b82f25ff6506c0f87886b4dfd5012000000000000000000000000000000000000000000000000000000000000000008a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f401b175ac686800000000"
        )

        output_htlc_tx[2] = (
            TIMEOUT,
            "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219701000000000000000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100d5275b3619953cb0c3b5aa577f04bc512380e60fa551762ce3d7a1bb7401cff9022037237ab0dac3fe100cde094e82e2bed9ba0ed1bb40154b48e56aa70f259e608b01483045022100c89172099507ff50f4c925e6c5150e871fb6e83dd73ff9fbb72f6ce829a9633f02203a63821d9162e99f9be712a68f9e589483994feae2661e4546cd5b6cec007be501008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000"
        )

        output_htlc_tx[1] = (
            SUCCESS,
            "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219702000000000000000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402201b63ec807771baf4fdff523c644080de17f1da478989308ad13a58b51db91d360220568939d38c9ce295adba15665fa68f51d967e8ed14a007b751540a80b325f20201483045022100def389deab09cee69eaa1ec14d9428770e45bcbe9feb46468ecf481371165c2f022015d2e3c46600b2ebba8dcc899768874cc6851fd1ecb3fffd15db1cc3de7e10da012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000"
        )

        output_htlc_tx[3] = (
            TIMEOUT,
            "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219703000000000000000001b80b0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100daee1808f9861b6c3ecd14f7b707eca02dd6bdfc714ba2f33bc8cdba507bb182022026654bf8863af77d74f51f4e0b62d461a019561bb12acb120d3f7195d148a554014730440220643aacb19bbb72bd2b635bc3f7375481f5981bace78cdd8319b2988ffcc6704202203d27784ec8ad51ed3bd517a05525a5139bb0b755dd719e0054332d186ac0872701008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000"
        )

        output_htlc_tx[4] = (
            SUCCESS,
            "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219704000000000000000001a00f0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402207e0410e45454b0978a623f36a10626ef17b27d9ad44e2760f98cfa3efb37924f0220220bd8acd43ecaa916a80bd4f919c495a2c58982ce7c8625153f8596692a801d014730440220549e80b4496803cbc4a1d09d46df50109f546d43fbbf86cd90b174b1484acd5402205f12a4f995cb9bded597eabfee195a285986aa6d93ae5bb72507ebc6a4e2349e012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000"
        )

        htlc_output_index = {0: 0, 1: 2, 2: 1, 3: 3, 4: 4}

        for i in range(5):
            self.assertEqual(
                output_htlc_tx[i][1],
                self.htlc_tx(
                    htlc[i], htlc_output_index[i], htlcs[i].htlc.amount_msat,
                    htlc_payment_preimage[i],
                    signature_for_output_remote_htlc[i], output_htlc_tx[i][0],
                    htlc_cltv_timeout[i] if not output_htlc_tx[i][0] else 0,
                    local_feerate_per_kw, our_commit_tx))