1
0

unit tests: test anchors in lnpeer and lnchannel

* testing of anchor channels is controlled via TEST_ANCHOR_CHANNELS
* rewrite tests in test_lnchannel.py
This commit is contained in:
bitromortac
2021-09-13 14:06:35 +02:00
committed by ThomasV
parent 3a3f5059b4
commit a3dc2b847e
2 changed files with 144 additions and 92 deletions

View File

@@ -35,6 +35,7 @@ from electrum import lnutil
from electrum import bip32 as bip32_utils
from electrum.crypto import privkey_to_pubkey
from electrum.lnutil import SENT, LOCAL, REMOTE, RECEIVED, UpdateAddHtlc
from electrum.lnutil import effective_htlc_tx_weight
from electrum.logging import console_stderr_handler
from electrum.lnchannel import ChannelState
from electrum.json_db import StoredDict
@@ -42,6 +43,7 @@ from electrum.coinchooser import PRNG
from . import ElectrumTestCase
TEST_ANCHOR_CHANNELS = True
one_bitcoin_in_msat = bitcoin.COIN * 1000
@@ -49,10 +51,13 @@ one_bitcoin_in_msat = bitcoin.COIN * 1000
def create_channel_state(funding_txid, funding_index, funding_sat, is_initiator,
local_amount, remote_amount, privkeys, other_pubkeys,
seed, cur, nex, other_node_id, l_dust, r_dust, l_csv,
r_csv):
r_csv, anchor_outputs=TEST_ANCHOR_CHANNELS):
#assert local_amount > 0
#assert remote_amount > 0
channel_id, _ = lnpeer.channel_id_from_funding_tx(funding_txid, funding_index)
channel_type = lnutil.ChannelType.OPTION_STATIC_REMOTEKEY
if anchor_outputs:
channel_type |= lnutil.ChannelType.OPTION_ANCHOR_OUTPUTS
state = {
"channel_id":channel_id.hex(),
"short_channel_id":channel_id[:8],
@@ -111,7 +116,7 @@ def create_channel_state(funding_txid, funding_index, funding_sat, is_initiator,
'log': {},
'unfulfilled_htlcs': {},
'revocation_store': {},
'channel_type': lnutil.ChannelType.OPTION_STATIC_REMOTEKEY
'channel_type': channel_type,
}
return StoredDict(state, None, [])
@@ -124,7 +129,8 @@ def bip32(sequence):
def create_test_channels(*, feerate=6000, local_msat=None, remote_msat=None,
alice_name="alice", bob_name="bob",
alice_pubkey=b"\x01"*33, bob_pubkey=b"\x02"*33, random_seed=None):
alice_pubkey=b"\x01"*33, bob_pubkey=b"\x02"*33, random_seed=None,
anchor_outputs=TEST_ANCHOR_CHANNELS):
if random_seed is None: # needed for deterministic randomness
random_seed = os.urandom(32)
random_gen = PRNG(random_seed)
@@ -156,7 +162,7 @@ def create_test_channels(*, feerate=6000, local_msat=None, remote_msat=None,
funding_txid, funding_index, funding_sat, True, local_amount,
remote_amount, alice_privkeys, bob_pubkeys, alice_seed, None,
bob_first, other_node_id=bob_pubkey, l_dust=200, r_dust=1300,
l_csv=5, r_csv=4
l_csv=5, r_csv=4, anchor_outputs=anchor_outputs
),
name=f"{alice_name}->{bob_name}",
initial_feerate=feerate),
@@ -165,7 +171,7 @@ def create_test_channels(*, feerate=6000, local_msat=None, remote_msat=None,
funding_txid, funding_index, funding_sat, False, remote_amount,
local_amount, bob_privkeys, alice_pubkeys, bob_seed, None,
alice_first, other_node_id=alice_pubkey, l_dust=1300, r_dust=200,
l_csv=4, r_csv=5
l_csv=4, r_csv=5, anchor_outputs=anchor_outputs
),
name=f"{bob_name}->{alice_name}",
initial_feerate=feerate)
@@ -210,8 +216,9 @@ class TestFee(ElectrumTestCase):
def test_fee(self):
alice_channel, bob_channel = create_test_channels(feerate=253,
local_msat=10000000000,
remote_msat=5000000000)
self.assertIn(9999817, [x.value for x in alice_channel.get_latest_commitment(LOCAL).outputs()])
remote_msat=5000000000, anchor_outputs=TEST_ANCHOR_CHANNELS)
expected_value = 9999056 if TEST_ANCHOR_CHANNELS else 9999817
self.assertIn(expected_value, [x.value for x in alice_channel.get_latest_commitment(LOCAL).outputs()])
class TestChannel(ElectrumTestCase):
maxDiff = 999
@@ -223,6 +230,9 @@ class TestChannel(ElectrumTestCase):
else:
self.assertFalse()
def assertNumberNonAnchorOutputs(self, number, tx):
self.assertEqual(number, len(tx.outputs()) - (2 if TEST_ANCHOR_CHANNELS else 0))
@classmethod
def setUpClass(cls):
super().setUpClass()
@@ -233,15 +243,15 @@ class TestChannel(ElectrumTestCase):
# 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.alice_channel, self.bob_channel = create_test_channels(anchor_outputs=TEST_ANCHOR_CHANNELS)
self.paymentPreimage = b"\x01" * 32
paymentHash = bitcoin.sha256(self.paymentPreimage)
self.htlc_dict = {
'payment_hash' : paymentHash,
'amount_msat' : one_bitcoin_in_msat,
'cltv_abs' : 5,
'timestamp' : 0,
'payment_hash': paymentHash,
'amount_msat': one_bitcoin_in_msat,
'cltv_abs': 5,
'timestamp': 0,
}
# First Alice adds the outgoing HTLC to her local channel's state
@@ -263,40 +273,60 @@ class TestChannel(ElectrumTestCase):
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.assertNumberNonAnchorOutputs(2, self.alice_channel.get_latest_commitment(LOCAL))
self.assertNumberNonAnchorOutputs(3, self.alice_channel.get_next_commitment(LOCAL))
self.assertNumberNonAnchorOutputs(2, self.alice_channel.get_latest_commitment(REMOTE))
self.assertNumberNonAnchorOutputs(3, self.alice_channel.get_next_commitment(REMOTE))
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.assertNumberNonAnchorOutputs(3, self.alice_channel.get_latest_commitment(LOCAL))
self.assertNumberNonAnchorOutputs(3, self.alice_channel.get_next_commitment(LOCAL))
self.assertNumberNonAnchorOutputs(2, self.alice_channel.get_latest_commitment(REMOTE))
self.assertNumberNonAnchorOutputs(3, self.alice_channel.get_next_commitment(REMOTE))
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)
self.assertNumberNonAnchorOutputs(3, self.alice_channel.get_latest_commitment(LOCAL))
self.assertNumberNonAnchorOutputs(3, self.alice_channel.get_next_commitment(LOCAL))
self.assertNumberNonAnchorOutputs(2, self.alice_channel.get_latest_commitment(REMOTE))
self.assertNumberNonAnchorOutputs(4, self.alice_channel.get_next_commitment(REMOTE))
def test_SimpleAddSettleWorkflow(self):
alice_channel, bob_channel = self.alice_channel, self.bob_channel
htlc = self.htlc
# Starting point: alice has sent an update_add_htlc message to bob
# but the htlc is not yet committed to
alice_out = alice_channel.get_latest_commitment(LOCAL).outputs()
short_idx, = [idx for idx, x in enumerate(alice_out) if len(x.address) == 42]
long_idx, = [idx for idx, x in enumerate(alice_out) if len(x.address) == 62]
self.assertLess(alice_out[long_idx].value, 5 * 10**8, alice_out)
self.assertEqual(alice_out[short_idx].value, 5 * 10**8, alice_out)
if not alice_channel.has_anchors():
# ctx outputs are ordered by increasing amounts
low_amt_idx = 0
assert len(alice_out[low_amt_idx].address) == 62 # p2wsh
high_amt_idx = 1
assert len(alice_out[high_amt_idx].address) == 42 # p2wpkh
else:
# using anchor outputs, all outputs are p2wsh
low_amt_idx = 2
assert len(alice_out[low_amt_idx].address) == 62
high_amt_idx = 3
assert len(alice_out[high_amt_idx].address) == 62
self.assertLess(alice_out[low_amt_idx].value, 5 * 10**8, alice_out)
self.assertEqual(alice_out[high_amt_idx].value, 5 * 10**8, alice_out)
alice_out = alice_channel.get_latest_commitment(REMOTE).outputs()
short_idx, = [idx for idx, x in enumerate(alice_out) if len(x.address) == 42]
long_idx, = [idx for idx, x in enumerate(alice_out) if len(x.address) == 62]
self.assertLess(alice_out[short_idx].value, 5 * 10**8)
self.assertEqual(alice_out[long_idx].value, 5 * 10**8)
if not alice_channel.has_anchors():
low_amt_idx = 0
assert len(alice_out[low_amt_idx].address) == 42
high_amt_idx = 1
assert len(alice_out[high_amt_idx].address) == 62
else:
low_amt_idx = 2
assert len(alice_out[low_amt_idx].address) == 62
high_amt_idx = 3
assert len(alice_out[high_amt_idx].address) == 62
self.assertLess(alice_out[low_amt_idx].value, 5 * 10**8)
self.assertEqual(alice_out[high_amt_idx].value, 5 * 10**8)
self.assertTrue(alice_channel.signature_fits(alice_channel.get_latest_commitment(LOCAL)))
@@ -341,7 +371,7 @@ class TestChannel(ElectrumTestCase):
self.assertTrue(bob_channel.signature_fits(bob_channel.get_latest_commitment(LOCAL)))
self.assertEqual(bob_channel.get_oldest_unrevoked_ctn(REMOTE), 0)
self.assertEqual(bob_channel.included_htlcs(LOCAL, RECEIVED, 1), [htlc])#
self.assertEqual(bob_channel.included_htlcs(LOCAL, RECEIVED, 1), [htlc])
self.assertEqual(alice_channel.included_htlcs(REMOTE, RECEIVED, 0), [])
self.assertEqual(alice_channel.included_htlcs(REMOTE, RECEIVED, 1), [htlc])
@@ -369,10 +399,10 @@ class TestChannel(ElectrumTestCase):
self.assertTrue(alice_channel.signature_fits(alice_channel.get_latest_commitment(LOCAL)))
# so far: Alice added htlc, Alice signed.
self.assertEqual(len(alice_channel.get_latest_commitment(LOCAL).outputs()), 2)
self.assertEqual(len(alice_channel.get_next_commitment(LOCAL).outputs()), 2)
self.assertEqual(len(alice_channel.get_oldest_unrevoked_commitment(REMOTE).outputs()), 2)
self.assertEqual(len(alice_channel.get_latest_commitment(REMOTE).outputs()), 3)
self.assertNumberNonAnchorOutputs(2, alice_channel.get_latest_commitment(LOCAL))
self.assertNumberNonAnchorOutputs(2, alice_channel.get_next_commitment(LOCAL))
self.assertNumberNonAnchorOutputs(2, alice_channel.get_oldest_unrevoked_commitment(REMOTE))
self.assertNumberNonAnchorOutputs(3, alice_channel.get_latest_commitment(REMOTE))
# Alice then processes this revocation, sending her own revocation for
# her prior commitment transaction. Alice shouldn't have any HTLCs to
@@ -381,21 +411,21 @@ class TestChannel(ElectrumTestCase):
self.assertTrue(alice_channel.signature_fits(alice_channel.get_latest_commitment(LOCAL)))
self.assertEqual(len(alice_channel.get_latest_commitment(LOCAL).outputs()), 2)
self.assertEqual(len(alice_channel.get_latest_commitment(REMOTE).outputs()), 3)
self.assertEqual(len(alice_channel.force_close_tx().outputs()), 2)
self.assertNumberNonAnchorOutputs(2, alice_channel.get_latest_commitment(LOCAL))
self.assertNumberNonAnchorOutputs(3, alice_channel.get_latest_commitment(REMOTE))
self.assertNumberNonAnchorOutputs(2, alice_channel.force_close_tx())
self.assertEqual(len(alice_channel.hm.log[LOCAL]['adds']), 1)
self.assertEqual(alice_channel.get_next_commitment(LOCAL).outputs(),
bob_channel.get_latest_commitment(REMOTE).outputs())
# Alice then processes bob's signature, and since she just received
# the revocation, she expect this signature to cover everything up to
# the revocation, she expects this signature to cover everything up to
# the point where she sent her signature, including the HTLC.
alice_channel.receive_new_commitment(bobSig, bobHtlcSigs)
self.assertEqual(len(alice_channel.get_latest_commitment(REMOTE).outputs()), 3)
self.assertEqual(len(alice_channel.force_close_tx().outputs()), 3)
self.assertNumberNonAnchorOutputs(3, alice_channel.get_latest_commitment(REMOTE))
self.assertNumberNonAnchorOutputs(3, alice_channel.force_close_tx())
self.assertEqual(len(alice_channel.hm.log[LOCAL]['adds']), 1)
@@ -433,8 +463,8 @@ class TestChannel(ElectrumTestCase):
# them should be exactly the amount of the HTLC.
alice_ctx = alice_channel.get_next_commitment(LOCAL)
bob_ctx = bob_channel.get_next_commitment(LOCAL)
self.assertEqual(len(alice_ctx.outputs()), 3, "alice should have three commitment outputs, instead have %s"% len(alice_ctx.outputs()))
self.assertEqual(len(bob_ctx.outputs()), 3, "bob should have three commitment outputs, instead have %s"% len(bob_ctx.outputs()))
self.assertNumberNonAnchorOutputs(3, alice_ctx)
self.assertNumberNonAnchorOutputs(3, bob_ctx)
self.assertOutputExistsByValue(alice_ctx, htlc.amount_msat // 1000)
self.assertOutputExistsByValue(bob_ctx, htlc.amount_msat // 1000)
@@ -482,7 +512,7 @@ class TestChannel(ElectrumTestCase):
aliceRevocation2 = alice_channel.revoke_current_commitment()
aliceSig2, aliceHtlcSigs2 = alice_channel.sign_next_commitment()
self.assertEqual(aliceHtlcSigs2, [], "alice should generate no htlc signatures")
self.assertEqual(len(bob_channel.get_latest_commitment(LOCAL).outputs()), 3)
self.assertNumberNonAnchorOutputs(3, bob_channel.get_latest_commitment(LOCAL))
bob_channel.receive_revocation(aliceRevocation2)
bob_channel.receive_new_commitment(aliceSig2, aliceHtlcSigs2)
@@ -643,7 +673,7 @@ class TestChannel(ElectrumTestCase):
class TestAvailableToSpend(ElectrumTestCase):
def test_DesyncHTLCs(self):
alice_channel, bob_channel = create_test_channels()
self.assertEqual(499986152000, alice_channel.available_to_spend(LOCAL))
self.assertEqual(499986152000 if not alice_channel.has_anchors() else 499980692000, alice_channel.available_to_spend(LOCAL))
self.assertEqual(500000000000, bob_channel.available_to_spend(LOCAL))
paymentPreimage = b"\x01" * 32
@@ -657,13 +687,13 @@ class TestAvailableToSpend(ElectrumTestCase):
alice_idx = alice_channel.add_htlc(htlc).htlc_id
bob_idx = bob_channel.receive_htlc(htlc).htlc_id
self.assertEqual(89984088000, alice_channel.available_to_spend(LOCAL))
self.assertEqual(89984088000 if not alice_channel.has_anchors() else 89978628000, 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(89984088000 if not alice_channel.has_anchors() else 89978628000, 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
@@ -683,7 +713,7 @@ class TestAvailableToSpend(ElectrumTestCase):
# 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(499986152000 if not alice_channel.has_anchors() else 499980692000, alice_channel.available_to_spend(LOCAL))
self.assertEqual(500000000000, bob_channel.available_to_spend(LOCAL))
alice_channel.add_htlc(htlc)
@@ -720,10 +750,10 @@ class TestChanReserve(ElectrumTestCase):
paymentPreimage = b"\x01" * 32
paymentHash = bitcoin.sha256(paymentPreimage)
htlc_dict = {
'payment_hash' : paymentHash,
'amount_msat' : int(.5 * one_bitcoin_in_msat),
'cltv_abs' : 5,
'timestamp' : 0,
'payment_hash': paymentHash,
'amount_msat': int(.5 * one_bitcoin_in_msat),
'cltv_abs': 5,
'timestamp': 0,
}
self.alice_channel.add_htlc(htlc_dict)
self.bob_channel.receive_htlc(htlc_dict)
@@ -759,9 +789,9 @@ class TestChanReserve(ElectrumTestCase):
# Alice: 1.5
# Bob: 9.5
htlc_dict = {
'payment_hash' : paymentHash,
'amount_msat' : int(3.5 * one_bitcoin_in_msat),
'cltv_abs' : 5,
'payment_hash': paymentHash,
'amount_msat': int(3.5 * one_bitcoin_in_msat),
'cltv_abs': 5,
}
self.alice_channel.add_htlc(htlc_dict)
self.bob_channel.receive_htlc(htlc_dict)
@@ -783,10 +813,10 @@ class TestChanReserve(ElectrumTestCase):
paymentPreimage = b"\x01" * 32
paymentHash = bitcoin.sha256(paymentPreimage)
htlc_dict = {
'payment_hash' : paymentHash,
'amount_msat' : int(2 * one_bitcoin_in_msat),
'cltv_abs' : 5,
'timestamp' : 0,
'payment_hash': paymentHash,
'amount_msat': int(2 * one_bitcoin_in_msat),
'cltv_abs': 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
@@ -819,38 +849,61 @@ class TestChanReserve(ElectrumTestCase):
class TestDust(ElectrumTestCase):
def test_DustLimit(self):
"""Test that addition of an HTLC below the dust limit changes the balances."""
alice_channel, bob_channel = create_test_channels()
dust_limit_alice = alice_channel.config[LOCAL].dust_limit_sat
dust_limit_bob = bob_channel.config[LOCAL].dust_limit_sat
self.assertLess(dust_limit_alice, dust_limit_bob)
bob_ctx = bob_channel.get_latest_commitment(LOCAL)
bobs_original_outputs = [x.value for x in bob_ctx.outputs()]
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)
success_weight = effective_htlc_tx_weight(success=True, has_anchors=TEST_ANCHOR_CHANNELS)
# we put a single sat less into the htlc than bob can afford
# to pay for his htlc success transaction
below_dust_for_bob = dust_limit_bob - 1
htlc_amt = below_dust_for_bob + success_weight * (fee_per_kw // 1000)
htlc = {
'payment_hash' : paymentHash,
'amount_msat' : 1000 * htlcAmt,
'cltv_abs' : 5, # also in create_test_channels
'timestamp' : 0,
'payment_hash': paymentHash,
'amount_msat': 1000 * htlc_amt,
'cltv_abs': 5, # consistent with channel policy
'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
# add the htlc
alice_htlc_id = alice_channel.add_htlc(htlc).htlc_id
bob_htlc_id = 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)
bobs_second_outputs = [x.value for x in bob_ctx.outputs()]
self.assertNotEqual(bobs_original_outputs, bobs_second_outputs)
# the htlc appears as an output in alice's ctx, as she has a lower
# dust limit (also because her timeout tx costs less)
self.assertEqual(3, len(alice_ctx.outputs()) - (2 if TEST_ANCHOR_CHANNELS else 0))
# htlc in bob's case goes to miner fees
self.assertEqual(2, len(bob_ctx.outputs()) - (2 if TEST_ANCHOR_CHANNELS else 0))
self.assertEqual(htlc_amt, sum(bobs_original_outputs) - sum(bobs_second_outputs))
empty_ctx_fee = lnutil.calc_fees_for_commitment_tx(
num_htlcs=0, feerate=fee_per_kw, is_local_initiator=True,
round_to_sat=True, has_anchors=TEST_ANCHOR_CHANNELS)[LOCAL] // 1000
self.assertEqual(empty_ctx_fee + htlc_amt, bob_channel.get_next_fee(LOCAL))
bob_channel.settle_htlc(paymentPreimage, bob_htlc_id)
alice_channel.receive_htlc_settle(paymentPreimage, alice_htlc_id)
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)
bob_ctx = bob_channel.get_latest_commitment(LOCAL)
bobs_third_outputs = [x.value for x in bob_ctx.outputs()]
# htlc is added back into the balance
self.assertEqual(sum(bobs_original_outputs), sum(bobs_third_outputs))
# balance shifts in bob's direction after settlement
self.assertEqual(htlc_amt, bobs_third_outputs[1 + (2 if TEST_ANCHOR_CHANNELS else 0)] - bobs_original_outputs[1 + (2 if TEST_ANCHOR_CHANNELS else 0)])
self.assertEqual(2, len(alice_channel.get_next_commitment(LOCAL).outputs()) - (2 if TEST_ANCHOR_CHANNELS else 0))
self.assertEqual(2, len(bob_channel.get_next_commitment(LOCAL).outputs()) - (2 if TEST_ANCHOR_CHANNELS else 0))
self.assertEqual(htlc_amt, alice_channel.total_msat(SENT) // 1000)
def force_state_transition(chanA, chanB):
chanB.receive_new_commitment(*chanA.sign_next_commitment())
@@ -859,12 +912,3 @@ def force_state_transition(chanA, chanB):
chanA.receive_revocation(rev)
chanA.receive_new_commitment(bob_sig, bob_htlc_sigs)
chanB.receive_revocation(chanA.revoke_current_commitment())
# 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

View File

@@ -45,9 +45,16 @@ from electrum.invoices import PR_PAID, PR_UNPAID
from electrum.interface import GracefulDisconnect
from electrum.simple_config import SimpleConfig
from .test_lnchannel import create_test_channels
from .test_lnchannel import create_test_channels as create_test_channels_anchors
from . import ElectrumTestCase
TEST_ANCHOR_CHANNELS = True
def create_test_channels(*args, **kwargs):
return create_test_channels_anchors(*args, **kwargs, anchor_outputs=TEST_ANCHOR_CHANNELS)
def keypair():
priv = ECPrivkey.generate_random_key().get_secret_bytes()
k1 = Keypair(
@@ -169,6 +176,7 @@ class MockLNWallet(Logger, EventListener, NetworkRetryManager[LNPeerAddr]):
self.features |= LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT_ELECTRUM
self.features |= LnFeatures.OPTION_CHANNEL_TYPE_OPT
self.features |= LnFeatures.OPTION_SCID_ALIAS_OPT
self.features |= LnFeatures.OPTION_STATIC_REMOTEKEY_OPT
self.pending_payments = defaultdict(asyncio.Future)
for chan in chans:
chan.lnworker = self
@@ -387,7 +395,7 @@ low_fee_channel = {
}
depleted_channel = {
'local_balance_msat': 0,
'local_balance_msat': 330 * 1000, # local pays anchors
'remote_balance_msat': 10 * bitcoin.COIN * 1000,
'local_base_fee_msat': 1_000,
'local_fee_rate_millionths': 1,