Browse Source

make function for determining who pays fee

dependabot/pip/contrib/deterministic-build/ecdsa-0.13.3
Janus 6 years ago
committed by ThomasV
parent
commit
eabe23f6b8
  1. 9
      electrum/lnchan.py
  2. 58
      electrum/lnutil.py
  3. 10
      electrum/tests/test_lnutil.py

9
electrum/lnchan.py

@ -18,7 +18,7 @@ from .lnutil import sign_and_get_sig_string
from .lnutil import make_htlc_tx_with_open_channel, make_commitment, make_received_htlc, make_offered_htlc
from .lnutil import HTLC_TIMEOUT_WEIGHT, HTLC_SUCCESS_WEIGHT
from .lnutil import funding_output_script, LOCAL, REMOTE, HTLCOwner, make_closing_tx, make_outputs
from .lnutil import ScriptHtlc, SENT, RECEIVED, PaymentFailure
from .lnutil import ScriptHtlc, SENT, RECEIVED, PaymentFailure, calc_onchain_fees
from .transaction import Transaction, TxOutput, construct_witness
from .simple_config import SimpleConfig, FEERATE_FALLBACK_STATIC_FEE
@ -656,8 +656,8 @@ class Channel(PrintError):
this_config.multisig_key.pubkey,
other_config.multisig_key.pubkey,
payment_pubkey,
self.config[LOCAL].payment_basepoint.pubkey,
self.config[REMOTE].payment_basepoint.pubkey,
self.config[LOCAL if self.constraints.is_initiator else REMOTE].payment_basepoint.pubkey,
self.config[LOCAL if not self.constraints.is_initiator else REMOTE].payment_basepoint.pubkey,
other_revocation_pubkey,
derive_pubkey(this_config.delayed_basepoint.pubkey, this_point),
other_config.to_self_delay,
@ -666,9 +666,12 @@ class Channel(PrintError):
local_msat,
remote_msat,
this_config.dust_limit_sat,
calc_onchain_fees(
len(htlcs),
self.pending_feerate(subject),
subject == LOCAL,
self.constraints.is_initiator,
),
htlcs=htlcs)
def make_closing_tx(self, local_script: bytes, remote_script: bytes, fee_sat: Optional[int] = None) -> (bytes, int):

58
electrum/lnutil.py

@ -1,7 +1,7 @@
from enum import IntFlag, IntEnum
import json
from collections import namedtuple
from typing import NamedTuple, List, Tuple
from typing import NamedTuple, List, Tuple, Mapping
import re
from .util import bfh, bh2u, inv_dict
@ -313,12 +313,10 @@ def make_htlc_tx_with_open_channel(chan, pcp, for_us, we_receive, commit, htlc):
return htlc_tx
def make_funding_input(local_funding_pubkey: bytes, remote_funding_pubkey: bytes,
payment_basepoint: bytes, remote_payment_basepoint: bytes, we_are_initiator: bool,
payment_basepoint: bytes, remote_payment_basepoint: bytes,
funding_pos: int, funding_txid: bytes, funding_sat: int):
pubkeys = sorted([bh2u(local_funding_pubkey), bh2u(remote_funding_pubkey)])
payments = [payment_basepoint, remote_payment_basepoint]
if not we_are_initiator:
payments.reverse()
# commitment tx input
c_input = {
'type': 'p2wsh',
@ -332,11 +330,23 @@ def make_funding_input(local_funding_pubkey: bytes, remote_funding_pubkey: bytes
}
return c_input, payments
def make_outputs(fee_msat: int, we_pay_fee: bool, local_amount: int, remote_amount: int,
class HTLCOwner(IntFlag):
LOCAL = 1
REMOTE = -LOCAL
SENT = LOCAL
RECEIVED = REMOTE
SENT = HTLCOwner.SENT
RECEIVED = HTLCOwner.RECEIVED
LOCAL = HTLCOwner.LOCAL
REMOTE = HTLCOwner.REMOTE
def make_outputs(fees_per_participant: Mapping[HTLCOwner, int], local_amount: int, remote_amount: int,
local_tupl, remote_tupl, htlcs: List[ScriptHtlc], dust_limit_sat: int) -> Tuple[List[TxOutput], List[TxOutput]]:
to_local_amt = local_amount - (fee_msat if we_pay_fee else 0)
to_local_amt = local_amount - fees_per_participant[LOCAL]
to_local = TxOutput(*local_tupl, to_local_amt // 1000)
to_remote_amt = remote_amount - (fee_msat if not we_pay_fee else 0)
to_remote_amt = remote_amount - fees_per_participant[REMOTE]
to_remote = TxOutput(*remote_tupl, to_remote_amt // 1000)
non_htlc_outputs = [to_local, to_remote]
htlc_outputs = []
@ -349,16 +359,22 @@ def make_outputs(fee_msat: int, we_pay_fee: bool, local_amount: int, remote_amou
c_outputs_filtered = list(filter(lambda x: x.value >= dust_limit_sat, non_htlc_outputs + htlc_outputs))
return htlc_outputs, c_outputs_filtered
def calc_onchain_fees(num_htlcs, feerate, for_us, we_are_initiator):
we_pay_fee = for_us == we_are_initiator
overall_weight = 500 + 172 * num_htlcs + 224
fee = feerate * overall_weight
fee = fee // 1000 * 1000
return {LOCAL: fee if we_pay_fee else 0, REMOTE: fee if not we_pay_fee else 0}
def make_commitment(ctn, local_funding_pubkey, remote_funding_pubkey,
remote_payment_pubkey, payment_basepoint,
remote_payment_basepoint, revocation_pubkey,
delayed_pubkey, to_self_delay, funding_txid,
funding_pos, funding_sat, local_amount, remote_amount,
dust_limit_sat, local_feerate, for_us, we_are_initiator,
dust_limit_sat, fees_per_participant,
htlcs):
c_input, payments = make_funding_input(local_funding_pubkey, remote_funding_pubkey,
payment_basepoint, remote_payment_basepoint, we_are_initiator, funding_pos,
payment_basepoint, remote_payment_basepoint, funding_pos,
funding_txid, funding_sat)
obs = get_obscured_ctn(ctn, *payments)
locktime = (0x20 << 24) + (obs & 0xffffff)
@ -371,11 +387,8 @@ def make_commitment(ctn, local_funding_pubkey, remote_funding_pubkey,
local_address = make_commitment_output_to_local_address(revocation_pubkey, to_self_delay, delayed_pubkey)
remote_address = make_commitment_output_to_remote_address(remote_payment_pubkey)
# TODO trim htlc outputs here while also considering 2nd stage htlc transactions
fee = local_feerate * overall_weight(len(htlcs))
fee = fee // 1000 * 1000
we_pay_fee = for_us == we_are_initiator
htlc_outputs, c_outputs_filtered = make_outputs(fee, we_pay_fee, local_amount, remote_amount,
htlc_outputs, c_outputs_filtered = make_outputs(fees_per_participant, local_amount, remote_amount,
(bitcoin.TYPE_ADDRESS, local_address), (bitcoin.TYPE_ADDRESS, remote_address), htlcs, dust_limit_sat)
assert sum(x.value for x in c_outputs_filtered) <= funding_sat
@ -453,9 +466,6 @@ def extract_ctn_from_tx_and_chan(tx, chan) -> int:
funder_payment_basepoint=funder_conf.payment_basepoint.pubkey,
fundee_payment_basepoint=fundee_conf.payment_basepoint.pubkey)
def overall_weight(num_htlc):
return 500 + 172 * num_htlc + 224
def get_ecdh(priv: bytes, pub: bytes) -> bytes:
pt = ECPubkey(pub) * string_to_number(priv)
return sha256(pt.get_public_key_bytes())
@ -511,23 +521,11 @@ def get_compressed_pubkey_from_bech32(bech32_pubkey: str) -> bytes:
return bytes(data_8bits)
class HTLCOwner(IntFlag):
LOCAL = 1
REMOTE = -LOCAL
SENT = LOCAL
RECEIVED = REMOTE
SENT = HTLCOwner.SENT
RECEIVED = HTLCOwner.RECEIVED
LOCAL = HTLCOwner.LOCAL
REMOTE = HTLCOwner.REMOTE
def make_closing_tx(local_funding_pubkey: bytes, remote_funding_pubkey: bytes,
payment_basepoint: bytes, remote_payment_basepoint: bytes, we_are_initiator: bool,
payment_basepoint: bytes, remote_payment_basepoint: bytes,
funding_txid: bytes, funding_pos: int, funding_sat: int, outputs: List[TxOutput]):
c_input, payments = make_funding_input(local_funding_pubkey, remote_funding_pubkey,
payment_basepoint, remote_payment_basepoint, we_are_initiator, funding_pos,
payment_basepoint, remote_payment_basepoint, funding_pos,
funding_txid, funding_sat)
c_input['sequence'] = 0xFFFF_FFFF
tx = Transaction.from_io([c_input], outputs, locktime=0, version=2)

10
electrum/tests/test_lnutil.py

@ -6,7 +6,7 @@ from electrum.lnutil import (RevocationStore, get_per_commitment_secret_from_see
make_htlc_tx_inputs, secret_to_pubkey, derive_blinded_pubkey, derive_privkey,
derive_pubkey, make_htlc_tx, extract_ctn_from_tx, UnableToDeriveSecret,
get_compressed_pubkey_from_bech32, split_host_port, ConnStringFormatError,
ScriptHtlc, extract_nodeid)
ScriptHtlc, extract_nodeid, calc_onchain_fees)
from electrum import lnchan
from electrum.util import bh2u, bfh
from electrum.transaction import Transaction
@ -506,7 +506,7 @@ class TestLNUtil(unittest.TestCase):
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,
local_feerate_per_kw, True, we_are_initiator=True, htlcs=htlcs)
calc_onchain_fees(len(htlcs), local_feerate_per_kw, True, we_are_initiator=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)
@ -584,7 +584,7 @@ class TestLNUtil(unittest.TestCase):
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,
local_feerate_per_kw, True, we_are_initiator=True, htlcs=[])
calc_onchain_fees(0, local_feerate_per_kw, True, we_are_initiator=True), 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)
@ -603,7 +603,7 @@ class TestLNUtil(unittest.TestCase):
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,
local_feerate_per_kw, True, we_are_initiator=True, htlcs=[])
calc_onchain_fees(0, local_feerate_per_kw, True, we_are_initiator=True), 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)
@ -661,7 +661,7 @@ class TestLNUtil(unittest.TestCase):
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,
local_feerate_per_kw, True, we_are_initiator=True, htlcs=[])
calc_onchain_fees(0, local_feerate_per_kw, True, we_are_initiator=True), 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'
self.assertEqual(str(our_commit_tx), ref_commit_tx_str)

Loading…
Cancel
Save