electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

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:
Melectrum/lnhtlc.py | 10++++++----
Melectrum/lnutil.py | 7+++----
Melectrum/tests/test_lnhtlc.py | 21+++++++++++++++------
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():