Ejemplo n.º 1
0
    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.get_next_fee(LOCAL), 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)
Ejemplo n.º 2
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)
Ejemplo n.º 3
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)
Ejemplo n.º 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]
Ejemplo n.º 5
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)
Ejemplo n.º 6
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])
Ejemplo n.º 7
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)
Ejemplo n.º 8
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)