diff --git a/electrum/lnchannel.py b/electrum/lnchannel.py index 2f92050e1..bbe84e8ee 100644 --- a/electrum/lnchannel.py +++ b/electrum/lnchannel.py @@ -1354,6 +1354,7 @@ class Channel(AbstractChannel): feerate=feerate, is_local_initiator=self.constraints.is_initiator, round_to_sat=False, + has_anchors=self.has_anchors() ) htlc_fee_msat = fee_for_htlc_output(feerate=feerate) htlc_trim_func = received_htlc_trim_threshold_sat if ctx_owner == receiver else offered_htlc_trim_threshold_sat @@ -1364,6 +1365,7 @@ class Channel(AbstractChannel): feerate=2 * feerate, is_local_initiator=self.constraints.is_initiator, round_to_sat=False, + has_anchors=self.has_anchors() )[sender] max_send_msat = sender_balance_msat - sender_reserve_msat - fee_spike_buffer else: @@ -1546,6 +1548,7 @@ class Channel(AbstractChannel): num_htlcs=num_htlcs_in_ctx, feerate=feerate, is_local_initiator=self.constraints.is_initiator, + has_anchors=self.has_anchors() ) remainder = sender_balance_msat - sender_reserve_msat - ctx_fees_msat[sender] if remainder < 0: @@ -1595,6 +1598,7 @@ class Channel(AbstractChannel): num_htlcs=len(htlcs), feerate=feerate, is_local_initiator=self.constraints.is_initiator == (subject == LOCAL), + has_anchors=self.has_anchors(), ) assert self.is_static_remotekey_enabled() payment_pubkey = other_config.payment_basepoint.pubkey diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py index 359b4afc7..9cb991a9b 100644 --- a/electrum/lnpeer.py +++ b/electrum/lnpeer.py @@ -878,6 +878,7 @@ class Peer(Logger, EventListener): initial_feerate_per_kw=feerate, config=self.network.config, peer_features=self.features, + has_anchors=self.use_anchors(), ) # -> funding created @@ -1048,6 +1049,7 @@ class Peer(Logger, EventListener): initial_feerate_per_kw=feerate, config=self.network.config, peer_features=self.features, + has_anchors=self.use_anchors(), ) channel_flags = ord(payload['channel_flags']) diff --git a/electrum/lnutil.py b/electrum/lnutil.py index 012f4e650..28fe14ab0 100644 --- a/electrum/lnutil.py +++ b/electrum/lnutil.py @@ -48,6 +48,7 @@ _logger = get_logger(__name__) HTLC_TIMEOUT_WEIGHT = 663 HTLC_SUCCESS_WEIGHT = 703 COMMITMENT_TX_WEIGHT = 724 +COMMITMENT_TX_WEIGHT_ANCHORS = 1124 HTLC_OUTPUT_WEIGHT = 172 LN_MAX_FUNDING_SAT_LEGACY = pow(2, 24) - 1 @@ -158,6 +159,7 @@ class ChannelConfig(StoredObject): initial_feerate_per_kw: int, config: 'SimpleConfig', peer_features: 'LnFeatures', + has_anchors: bool, ) -> None: # first we validate the configs separately local_config.validate_params(funding_sat=funding_sat, config=config, peer_features=peer_features) @@ -183,7 +185,9 @@ class ChannelConfig(StoredObject): if funder_config.initial_msat < calc_fees_for_commitment_tx( num_htlcs=0, feerate=initial_feerate_per_kw, - is_local_initiator=is_local_initiator)[funder]: + is_local_initiator=is_local_initiator, + has_anchors=has_anchors, + )[funder]: raise Exception( "the funder's amount for the initial commitment transaction " "is not sufficient for full fee payment") @@ -1004,13 +1008,17 @@ def fee_for_htlc_output(*, feerate: int) -> int: def calc_fees_for_commitment_tx(*, num_htlcs: int, feerate: int, - is_local_initiator: bool, round_to_sat: bool = True) -> Dict['HTLCOwner', int]: + is_local_initiator: bool, round_to_sat: bool = True, has_anchors: bool) -> Dict['HTLCOwner', int]: # feerate is in sat/kw # returns fees in msats # note: BOLT-02 specifies that msat fees need to be rounded down to sat. # However, the rounding needs to happen for the total fees, so if the return value # is to be used as part of additional fee calculation then rounding should be done after that. - overall_weight = COMMITMENT_TX_WEIGHT + num_htlcs * HTLC_OUTPUT_WEIGHT + if has_anchors: + commitment_tx_weight = COMMITMENT_TX_WEIGHT_ANCHORS + else: + commitment_tx_weight = COMMITMENT_TX_WEIGHT + overall_weight = commitment_tx_weight + num_htlcs * HTLC_OUTPUT_WEIGHT fee = feerate * overall_weight if round_to_sat: fee = fee // 1000 * 1000 diff --git a/tests/test_lnutil.py b/tests/test_lnutil.py index aa51d57d1..640e0d3af 100644 --- a/tests/test_lnutil.py +++ b/tests/test_lnutil.py @@ -537,7 +537,7 @@ class TestLNUtil(ElectrumTestCase): local_amount=to_local_msat, remote_amount=to_remote_msat, dust_limit_sat=local_dust_limit_satoshi, - fees_per_participant=calc_fees_for_commitment_tx(num_htlcs=len(htlcs), feerate=local_feerate_per_kw, is_local_initiator=True), + fees_per_participant=calc_fees_for_commitment_tx(num_htlcs=len(htlcs), feerate=local_feerate_per_kw, is_local_initiator=True, has_anchors=False), 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) @@ -624,7 +624,7 @@ class TestLNUtil(ElectrumTestCase): local_amount=to_local_msat, remote_amount=to_remote_msat, dust_limit_sat=local_dust_limit_satoshi, - fees_per_participant=calc_fees_for_commitment_tx(num_htlcs=0, feerate=local_feerate_per_kw, is_local_initiator=True), + fees_per_participant=calc_fees_for_commitment_tx(num_htlcs=0, feerate=local_feerate_per_kw, is_local_initiator=True, has_anchors=False), htlcs=[]) self.sign_and_insert_remote_sig(our_commit_tx, remote_funding_pubkey, remote_signature, local_funding_pubkey, local_funding_privkey) @@ -653,7 +653,7 @@ class TestLNUtil(ElectrumTestCase): local_amount=to_local_msat, remote_amount=to_remote_msat, dust_limit_sat=local_dust_limit_satoshi, - fees_per_participant=calc_fees_for_commitment_tx(num_htlcs=0, feerate=local_feerate_per_kw, is_local_initiator=True), + fees_per_participant=calc_fees_for_commitment_tx(num_htlcs=0, feerate=local_feerate_per_kw, is_local_initiator=True, has_anchors=False), htlcs=[]) self.sign_and_insert_remote_sig(our_commit_tx, remote_funding_pubkey, remote_signature, local_funding_pubkey, local_funding_privkey) @@ -720,7 +720,7 @@ class TestLNUtil(ElectrumTestCase): local_amount=to_local_msat, remote_amount=to_remote_msat, dust_limit_sat=local_dust_limit_satoshi, - fees_per_participant=calc_fees_for_commitment_tx(num_htlcs=0, feerate=local_feerate_per_kw, is_local_initiator=True), + fees_per_participant=calc_fees_for_commitment_tx(num_htlcs=0, feerate=local_feerate_per_kw, is_local_initiator=True, has_anchors=False), htlcs=[]) self.sign_and_insert_remote_sig(our_commit_tx, remote_funding_pubkey, remote_signature, local_funding_pubkey, local_funding_privkey) ref_commit_tx_str = '02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8002c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de84311054a56a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400473044022051b75c73198c6deee1a875871c3961832909acd297c6b908d59e3319e5185a46022055c419379c5051a78d00dbbce11b5b664a0c22815fbcc6fcef6b1937c383693901483045022100f51d2e566a70ba740fc5d8c0f07b9b93d2ed741c3c0860c613173de7d39e7968022041376d520e9c0e1ad52248ddf4b22e12be8763007df977253ef45a4ca3bdb7c001475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220'