commit 9853cc6f3139d8f4734d366c0536989aee71009c
parent 66e7b4d25020ce1a01903116f63fd7f79b2a6d48
Author: Janus <ysangkok@gmail.com>
Date: Fri, 20 Jul 2018 16:17:18 +0200
ln: do not use mSAT accuracy for commitment fees
Diffstat:
3 files changed, 24 insertions(+), 14 deletions(-)
diff --git a/electrum/lnhtlc.py b/electrum/lnhtlc.py
@@ -2,7 +2,7 @@
from collections import namedtuple
import binascii
import json
-from .util import bfh, PrintError
+from .util import bfh, PrintError, bh2u
from .bitcoin import Hash
from .bitcoin import redeem_script_to_address
from .crypto import sha256
@@ -199,14 +199,16 @@ class HTLCStateMachine(PrintError):
for_us = False
+ feerate = self.pending_remote_feerate
+
htlcsigs = []
for we_receive, htlcs in zip([True, False], [self.htlcs_in_remote, self.htlcs_in_local]):
assert len(htlcs) <= 1
for htlc in htlcs:
weight = HTLC_SUCCESS_WEIGHT if we_receive else HTLC_TIMEOUT_WEIGHT
- fee = self.remote_state.feerate // 1000 * weight
+ fee = feerate // 1000 * weight
if htlc.amount_msat // 1000 < self.remote_config.dust_limit_sat + fee:
- print("value too small, skipping. htlc amt: {}, weight: {}, remote feerate {}, remote dust limit {}".format( htlc.amount_msat, weight, self.remote_state.feerate, self.remote_config.dust_limit_sat))
+ print("value too small, skipping. htlc amt: {}, weight: {}, remote feerate {}, remote dust limit {}".format( htlc.amount_msat, weight, feerate, self.remote_config.dust_limit_sat))
continue
original_htlc_output_index = 0
args = [self.remote_state.next_per_commitment_point, for_us, we_receive, htlc.amount_msat + htlc.total_fee, htlc.cltv_expiry, htlc.payment_hash, self.pending_remote_commitment, original_htlc_output_index]
@@ -244,7 +246,7 @@ class HTLCStateMachine(PrintError):
preimage_hex = self.pending_local_commitment.serialize_preimage(0)
pre_hash = Hash(bfh(preimage_hex))
if not ecc.verify_signature(self.remote_config.multisig_key.pubkey, sig, pre_hash):
- raise Exception('failed verifying signature of our updated commitment transaction: ' + str(sig))
+ raise Exception('failed verifying signature of our updated commitment transaction: ' + bh2u(sig) + ' preimage is ' + preimage_hex)
_, this_point, _ = self.points
diff --git a/electrum/lnutil.py b/electrum/lnutil.py
@@ -153,6 +153,7 @@ def make_htlc_tx_output(amount_msat, local_feerate, revocationpubkey, local_dela
p2wsh = bitcoin.redeem_script_to_address('p2wsh', bh2u(script))
weight = HTLC_SUCCESS_WEIGHT if success else HTLC_TIMEOUT_WEIGHT
fee = local_feerate * weight
+ fee = fee // 1000 * 1000
final_amount_sat = (amount_msat - fee) // 1000
assert final_amount_sat > 0, final_amount_sat
output = (bitcoin.TYPE_ADDRESS, p2wsh, final_amount_sat)
@@ -242,7 +243,7 @@ def make_htlc_tx_with_open_channel(chan, pcp, for_us, we_receive, amount_msat, c
is_htlc_success = for_us == we_receive
htlc_tx_output = make_htlc_tx_output(
amount_msat = amount_msat,
- local_feerate = chan.local_state.feerate if for_us else chan.remote_state.feerate,
+ local_feerate = chan.pending_local_feerate if for_us else chan.pending_remote_feerate,
revocationpubkey=revocation_pubkey,
local_delayedpubkey=delayedpubkey,
success = is_htlc_success,
@@ -295,13 +296,11 @@ def make_commitment(ctn, local_funding_pubkey, remote_funding_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))
- assert type(fee) is int
+ fee = fee // 1000 * 1000
we_pay_fee = for_us == we_are_initiator
to_local_amt = local_amount - (fee if we_pay_fee else 0)
- assert type(to_local_amt) is int
to_local = (bitcoin.TYPE_ADDRESS, local_address, to_local_amt // 1000)
to_remote_amt = remote_amount - (fee if not we_pay_fee else 0)
- assert type(to_remote_amt) is int
to_remote = (bitcoin.TYPE_ADDRESS, remote_address, to_remote_amt // 1000)
c_outputs = [to_local, to_remote]
for script, msat_amount in htlcs:
diff --git a/electrum/tests/test_lnhtlc.py b/electrum/tests/test_lnhtlc.py
@@ -74,12 +74,12 @@ def bip32(sequence):
assert type(k) is bytes
return k
-def create_test_channels():
+def create_test_channels(feerate=6000, local=None, remote=None):
funding_txid = binascii.hexlify(os.urandom(32)).decode("ascii")
funding_index = 0
- funding_sat = bitcoin.COIN * 10
- local_amount = (funding_sat * 1000) // 2
- remote_amount = (funding_sat * 1000) // 2
+ funding_sat = ((local + remote) // 1000) if local is not None and remote is not None else (bitcoin.COIN * 10)
+ local_amount = local if local is not None else (funding_sat * 1000 // 2)
+ remote_amount = remote if remote is not None else (funding_sat * 1000 // 2)
alice_raw = [ bip32("m/" + str(i)) for i in range(5) ]
bob_raw = [ bip32("m/" + str(i)) for i in range(5,11) ]
alice_privkeys = [lnbase.Keypair(lnbase.privkey_to_pubkey(x), x) for x in alice_raw]
@@ -97,12 +97,21 @@ def create_test_channels():
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"), \
+ create_channel_state(funding_txid, funding_index, funding_sat, feerate, 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")
+ create_channel_state(funding_txid, funding_index, funding_sat, feerate, 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
+class TestFee(unittest.TestCase):
+ """
+ test
+ https://github.com/lightningnetwork/lightning-rfc/blob/e0c436bd7a3ed6a028e1cb472908224658a14eca/03-transactions.md#requirements-2
+ """
+ def test_SimpleAddSettleWorkflow(self):
+ alice_channel, bob_channel = create_test_channels(253, 10000000000, 5000000000)
+ self.assertIn(9999817, [x[2] for x in alice_channel.local_commitment.outputs()])
+
class TestLNBaseHTLCStateMachine(unittest.TestCase):
def assertOutputExistsByValue(self, tx, amt_sat):
for typ, scr, val in tx.outputs():