ln: trim dust htlc outputs
This commit is contained in:
@@ -8,7 +8,7 @@ import lib.util as util
|
||||
import os
|
||||
import binascii
|
||||
|
||||
def create_channel_state(funding_txid, funding_index, funding_sat, local_feerate, is_initiator, local_amount, remote_amount, privkeys, other_pubkeys, seed, cur, nex, other_node_id):
|
||||
def create_channel_state(funding_txid, funding_index, funding_sat, local_feerate, is_initiator, local_amount, remote_amount, privkeys, other_pubkeys, seed, cur, nex, other_node_id, l_dust, r_dust, l_csv, r_csv):
|
||||
assert local_amount > 0
|
||||
assert remote_amount > 0
|
||||
channel_id, _ = lnbase.channel_id_from_funding_tx(funding_txid, funding_index)
|
||||
@@ -19,8 +19,8 @@ def create_channel_state(funding_txid, funding_index, funding_sat, local_feerate
|
||||
htlc_basepoint=privkeys[2],
|
||||
delayed_basepoint=privkeys[3],
|
||||
revocation_basepoint=privkeys[4],
|
||||
to_self_delay=143,
|
||||
dust_limit_sat=10,
|
||||
to_self_delay=l_csv,
|
||||
dust_limit_sat=l_dust,
|
||||
max_htlc_value_in_flight_msat=500000 * 1000,
|
||||
max_accepted_htlcs=5
|
||||
)
|
||||
@@ -30,8 +30,8 @@ def create_channel_state(funding_txid, funding_index, funding_sat, local_feerate
|
||||
htlc_basepoint=other_pubkeys[2],
|
||||
delayed_basepoint=other_pubkeys[3],
|
||||
revocation_basepoint=other_pubkeys[4],
|
||||
to_self_delay=143,
|
||||
dust_limit_sat=10,
|
||||
to_self_delay=r_csv,
|
||||
dust_limit_sat=r_dust,
|
||||
max_htlc_value_in_flight_msat=500000 * 1000,
|
||||
max_accepted_htlcs=5
|
||||
)
|
||||
@@ -92,9 +92,11 @@ def create_test_channels():
|
||||
bob_cur = lnbase.secret_to_pubkey(int.from_bytes(lnbase.get_per_commitment_secret_from_seed(bob_seed, 2**48 - 1), "big"))
|
||||
bob_next = lnbase.secret_to_pubkey(int.from_bytes(lnbase.get_per_commitment_secret_from_seed(bob_seed, 2**48 - 2), "big"))
|
||||
|
||||
return lnhtlc.HTLCStateMachine(
|
||||
create_channel_state(funding_txid, funding_index, funding_sat, 20000, True, local_amount, remote_amount, alice_privkeys, bob_pubkeys, alice_seed, bob_cur, bob_next, b"\x02"*33), "alice"), lnhtlc.HTLCStateMachine(
|
||||
create_channel_state(funding_txid, funding_index, funding_sat, 20000, False, remote_amount, local_amount, bob_privkeys, alice_pubkeys, bob_seed, alice_cur, alice_next, b"\x01"*33), "bob")
|
||||
return \
|
||||
lnhtlc.HTLCStateMachine(
|
||||
create_channel_state(funding_txid, funding_index, funding_sat, 6000, True, local_amount, remote_amount, alice_privkeys, bob_pubkeys, alice_seed, bob_cur, bob_next, b"\x02"*33, l_dust=200, r_dust=1300, l_csv=5, r_csv=4), "alice"), \
|
||||
lnhtlc.HTLCStateMachine(
|
||||
create_channel_state(funding_txid, funding_index, funding_sat, 6000, False, remote_amount, local_amount, bob_privkeys, alice_pubkeys, bob_seed, alice_cur, alice_next, b"\x01"*33, l_dust=1300, r_dust=200, l_csv=4, r_csv=5), "bob")
|
||||
|
||||
one_bitcoin_in_msat = bitcoin.COIN * 1000
|
||||
|
||||
@@ -230,3 +232,59 @@ class TestLNBaseHTLCStateMachine(unittest.TestCase):
|
||||
# revocation.
|
||||
self.assertEqual(alice_channel.local_update_log, [], "alice's local not updated, should be empty, has %s entries instead"% len(alice_channel.local_update_log))
|
||||
self.assertEqual(alice_channel.remote_update_log, [], "alice's remote not updated, should be empty, has %s entries instead"% len(alice_channel.remote_update_log))
|
||||
|
||||
def test_HTLCDustLimit(self):
|
||||
alice_channel, bob_channel = create_test_channels()
|
||||
|
||||
paymentPreimage = b"\x01" * 32
|
||||
paymentHash = bitcoin.sha256(paymentPreimage)
|
||||
fee_per_kw = alice_channel.state.constraints.feerate
|
||||
self.assertEqual(fee_per_kw, 6000)
|
||||
htlcAmt = 500 + lnbase.HTLC_TIMEOUT_WEIGHT * (fee_per_kw // 1000)
|
||||
self.assertEqual(htlcAmt, 4478)
|
||||
htlc = lnhtlc.UpdateAddHtlc(
|
||||
payment_hash = paymentHash,
|
||||
amount_msat = 1000 * htlcAmt,
|
||||
cltv_expiry = 5, # also in create_test_channels
|
||||
total_fee = 0
|
||||
)
|
||||
|
||||
aliceHtlcIndex = alice_channel.add_htlc(htlc)
|
||||
|
||||
bobHtlcIndex = bob_channel.receive_htlc(htlc)
|
||||
|
||||
force_state_transition(alice_channel, bob_channel)
|
||||
|
||||
self.assertEqual(len(alice_channel.local_commitment.outputs()), 3)
|
||||
|
||||
self.assertEqual(len(bob_channel.local_commitment.outputs()), 2)
|
||||
|
||||
default_fee = calc_static_fee(0)
|
||||
|
||||
self.assertEqual(bob_channel.local_commit_fee, default_fee)
|
||||
|
||||
bob_channel.settle_htlc(paymentPreimage, htlc.htlc_id)
|
||||
alice_channel.receive_htlc_settle(paymentPreimage, aliceHtlcIndex)
|
||||
|
||||
force_state_transition(bob_channel, alice_channel)
|
||||
|
||||
self.assertEqual(len(alice_channel.local_commitment.outputs()), 2)
|
||||
|
||||
self.assertEqual(alice_channel.total_msat_sent // 1000, htlcAmt)
|
||||
|
||||
def force_state_transition(chanA, chanB):
|
||||
chanB.receive_new_commitment(*chanA.sign_next_commitment())
|
||||
rev, _ = chanB.revoke_current_commitment()
|
||||
bob_sig, bob_htlc_sigs = chanB.sign_next_commitment()
|
||||
chanA.receive_revocation(rev)
|
||||
chanA.receive_new_commitment(bob_sig, bob_htlc_sigs)
|
||||
chanB.receive_revocation(chanA.revoke_current_commitment()[0])
|
||||
|
||||
# calcStaticFee calculates appropriate fees for commitment transactions. This
|
||||
# function provides a simple way to allow test balance assertions to take fee
|
||||
# calculations into account.
|
||||
def calc_static_fee(numHTLCs):
|
||||
commitWeight = 724
|
||||
htlcWeight = 172
|
||||
feePerKw = 24//4 * 1000
|
||||
return feePerKw * (commitWeight + htlcWeight*numHTLCs) // 1000
|
||||
|
||||
Reference in New Issue
Block a user