URI: 
       tlnhtlc: only store feerate once, don't store heights since we do not roll back - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit b26dc66567fe40f5623d274a47b131893e368ee9
   DIR parent e8471e483b303e6b65f9a2979b9eb9ea530b0490
  HTML Author: Janus <ysangkok@gmail.com>
       Date:   Thu, 11 Oct 2018 17:06:37 +0200
       
       lnhtlc: only store feerate once, don't store heights since we do not roll back
       
       Diffstat:
         M electrum/lnbase.py                  |      13 +++++--------
         M electrum/lnhtlc.py                  |      59 +++++++++++--------------------
         M electrum/lnutil.py                  |       3 +--
         M electrum/tests/test_lnhtlc.py       |      31 +++++++++++++++++--------------
       
       4 files changed, 43 insertions(+), 63 deletions(-)
       ---
   DIR diff --git a/electrum/lnbase.py b/electrum/lnbase.py
       t@@ -530,7 +530,7 @@ class Peer(PrintError):
                    chan.set_state('DISCONNECTED')
                    self.network.trigger_callback('channel', chan)
        
       -    def make_local_config(self, funding_sat, push_msat, initiator: HTLCOwner, feerate):
       +    def make_local_config(self, funding_sat, push_msat, initiator: HTLCOwner):
                # key derivation
                channel_counter = self.lnworker.get_and_inc_counter_for_channel_keys()
                keypair_generator = lambda family: generate_keypair(self.lnworker.ln_keystore, family, channel_counter)
       t@@ -552,7 +552,6 @@ class Peer(PrintError):
                    ctn=-1,
                    next_htlc_id=0,
                    amount_msat=initial_msat,
       -            feerate=feerate,
                )
                per_commitment_secret_seed = keypair_generator(LnKeyFamily.REVOCATION_ROOT).privkey
                return local_config, per_commitment_secret_seed
       t@@ -561,7 +560,7 @@ class Peer(PrintError):
            async def channel_establishment_flow(self, password, funding_sat, push_msat, temp_channel_id):
                await self.initialized
                feerate = self.current_feerate_per_kw()
       -        local_config, per_commitment_secret_seed = self.make_local_config(funding_sat, push_msat, LOCAL, feerate)
       +        local_config, per_commitment_secret_seed = self.make_local_config(funding_sat, push_msat, LOCAL)
                # for the first commitment transaction
                per_commitment_secret_first = get_per_commitment_secret_from_seed(per_commitment_secret_seed, RevocationStore.START_INDEX)
                per_commitment_point_first = secret_to_pubkey(int.from_bytes(per_commitment_secret_first, 'big'))
       t@@ -611,7 +610,6 @@ class Peer(PrintError):
                    ctn = -1,
                    amount_msat=push_msat,
                    next_htlc_id = 0,
       -            feerate=feerate,
        
                    next_per_commitment_point=remote_per_commitment_point,
                    current_per_commitment_point=None,
       t@@ -640,7 +638,7 @@ class Peer(PrintError):
                            current_commitment_signature = None,
                            current_htlc_signatures = None,
                        ),
       -                "constraints": ChannelConstraints(capacity=funding_sat, is_initiator=True, funding_txn_minimum_depth=funding_txn_minimum_depth),
       +                "constraints": ChannelConstraints(capacity=funding_sat, is_initiator=True, funding_txn_minimum_depth=funding_txn_minimum_depth, feerate=feerate),
                        "remote_commitment_to_be_revoked": None,
                }
                m = HTLCStateMachine(chan)
       t@@ -675,7 +673,7 @@ class Peer(PrintError):
                feerate = int.from_bytes(payload['feerate_per_kw'], 'big')
        
                temp_chan_id = payload['temporary_channel_id']
       -        local_config, per_commitment_secret_seed = self.make_local_config(funding_sat * 1000, push_msat, REMOTE, feerate)
       +        local_config, per_commitment_secret_seed = self.make_local_config(funding_sat * 1000, push_msat, REMOTE)
        
                # for the first commitment transaction
                per_commitment_secret_first = get_per_commitment_secret_from_seed(per_commitment_secret_seed, RevocationStore.START_INDEX)
       t@@ -723,7 +721,6 @@ class Peer(PrintError):
                            ctn = -1,
                            amount_msat=remote_balance_sat,
                            next_htlc_id = 0,
       -                    feerate=feerate,
        
                            next_per_commitment_point=payload['first_per_commitment_point'],
                            current_per_commitment_point=None,
       t@@ -737,7 +734,7 @@ class Peer(PrintError):
                            current_commitment_signature = None,
                            current_htlc_signatures = None,
                        ),
       -                "constraints": ChannelConstraints(capacity=funding_sat, is_initiator=False, funding_txn_minimum_depth=min_depth),
       +                "constraints": ChannelConstraints(capacity=funding_sat, is_initiator=False, funding_txn_minimum_depth=min_depth, feerate=feerate),
                        "remote_commitment_to_be_revoked": None,
                }
                m = HTLCStateMachine(chan)
   DIR diff --git a/electrum/lnhtlc.py b/electrum/lnhtlc.py
       t@@ -1,5 +1,5 @@
        # ported from lnd 42de4400bff5105352d0552155f73589166d162b
       -from collections import namedtuple
       +from collections import namedtuple, defaultdict
        import binascii
        import json
        from enum import Enum, auto
       t@@ -34,26 +34,14 @@ FUNDEE_SIGNED = FeeUpdateProgress.FUNDEE_SIGNED
        FUNDEE_ACKED = FeeUpdateProgress.FUNDEE_ACKED
        FUNDER_SIGNED = FeeUpdateProgress.FUNDER_SIGNED
        
       -from collections import namedtuple
       -
       -class FeeUpdate:
       +class FeeUpdate(defaultdict):
            def __init__(self, chan, rate):
       +        super().__init__(lambda: False)
                self.rate = rate
       -        self.progress = {FUNDEE_SIGNED: None, FUNDEE_ACKED: None, FUNDER_SIGNED: None}
                self.chan = chan
        
       -    def set(self, field):
       -        self.progress[field] = self.chan.current_height[LOCAL if self.chan.constraints.is_initiator else REMOTE]
       -
       -    def had(self, field):
       -        """
       -        returns true when the progress field given has been
       -        set at the current commitment number of the funder
       -        """
       -        return self.progress[field] is not None
       -
            def pending_feerate(self, subject):
       -        if self.had(FUNDEE_ACKED):
       +        if self[FUNDEE_ACKED]:
                    return self.rate
                if subject == REMOTE and self.chan.constraints.is_initiator:
                    return self.rate
       t@@ -230,9 +218,9 @@ class HTLCStateMachine(PrintError):
        
                for pending_fee in self.fee_mgr:
                    if not self.constraints.is_initiator:
       -                pending_fee.set(FUNDEE_SIGNED)
       -            if self.constraints.is_initiator and pending_fee.had(FUNDEE_ACKED):
       -                pending_fee.set(FUNDER_SIGNED)
       +                pending_fee[FUNDEE_SIGNED] = True
       +            if self.constraints.is_initiator and pending_fee[FUNDEE_ACKED]:
       +                pending_fee[FUNDER_SIGNED] = True
        
                self.process_new_offchain_ctx(pending_remote_commitment, ours=False)
        
       t@@ -283,9 +271,9 @@ class HTLCStateMachine(PrintError):
        
                for pending_fee in self.fee_mgr:
                    if not self.constraints.is_initiator:
       -                pending_fee.set(FUNDEE_SIGNED)
       -            if self.constraints.is_initiator and pending_fee.had(FUNDEE_ACKED):
       -                pending_fee.set(FUNDER_SIGNED)
       +                pending_fee[FUNDEE_SIGNED] = True
       +            if self.constraints.is_initiator and pending_fee[FUNDEE_ACKED]:
       +                pending_fee[FUNDER_SIGNED] = True
        
                self.process_new_offchain_ctx(pending_local_commitment, ours=True)
        
       t@@ -305,25 +293,23 @@ class HTLCStateMachine(PrintError):
        
                last_secret, this_point, next_point = self.points
        
       -        new_local_feerate = self.config[LOCAL].feerate
       -        new_remote_feerate = self.config[REMOTE].feerate
       +        new_feerate = self.constraints.feerate
        
                for pending_fee in self.fee_mgr[:]:
       -            if not self.constraints.is_initiator and pending_fee.had(FUNDEE_SIGNED):
       -                new_local_feerate = new_remote_feerate = pending_fee.rate
       +            if not self.constraints.is_initiator and pending_fee[FUNDEE_SIGNED]:
       +                new_feerate = pending_fee.rate
                        self.fee_mgr.remove(pending_fee)
                        print("FEERATE CHANGE COMPLETE (non-initiator)")
       -            if self.constraints.is_initiator and pending_fee.had(FUNDER_SIGNED):
       -                new_local_feerate = new_remote_feerate = pending_fee.rate
       +            if self.constraints.is_initiator and pending_fee[FUNDER_SIGNED]:
       +                new_feerate = pending_fee.rate
                        self.fee_mgr.remove(pending_fee)
                        print("FEERATE CHANGE COMPLETE (initiator)")
        
                self.config[LOCAL]=self.config[LOCAL]._replace(
                    ctn=self.config[LOCAL].ctn + 1,
       -            feerate=new_local_feerate
                )
       -        self.config[REMOTE]=self.config[REMOTE]._replace(
       -            feerate=new_remote_feerate
       +        self.constraints=self.constraints._replace(
       +            feerate=new_feerate
                )
        
                self.local_commitment = self.pending_local_commitment
       t@@ -427,7 +413,7 @@ class HTLCStateMachine(PrintError):
        
                for pending_fee in self.fee_mgr:
                    if self.constraints.is_initiator:
       -                pending_fee.set(FUNDEE_ACKED)
       +                pending_fee[FUNDEE_ACKED] = True
        
                self.local_commitment = self.pending_local_commitment
                self.remote_commitment = self.pending_remote_commitment
       t@@ -471,18 +457,13 @@ class HTLCStateMachine(PrintError):
                return self.make_commitment(REMOTE, this_point)
        
            def pending_feerate(self, subject):
       -        candidate = None
       +        candidate = self.constraints.feerate
                for pending_fee in self.fee_mgr:
                    x = pending_fee.pending_feerate(subject)
                    if x is not None:
                        candidate = x
        
       -        feerate = candidate if candidate is not None else self._committed_feerate[subject]
       -        return feerate
       -
       -    @property
       -    def _committed_feerate(self):
       -        return {LOCAL: self.config[LOCAL].feerate, REMOTE: self.config[REMOTE].feerate}
       +        return candidate
        
            @property
            def pending_local_commitment(self):
   DIR diff --git a/electrum/lnutil.py b/electrum/lnutil.py
       t@@ -26,7 +26,6 @@ common = [
            ('ctn' , int),
            ('amount_msat' , int),
            ('next_htlc_id' , int),
       -    ('feerate' , int),
            ('payment_basepoint' , Keypair),
            ('multisig_key' , Keypair),
            ('htlc_basepoint' , Keypair),
       t@@ -49,7 +48,7 @@ LocalConfig = NamedTuple('LocalConfig', common + [
            ('current_htlc_signatures', List[bytes]),
        ])
        
       -ChannelConstraints = namedtuple("ChannelConstraints", ["capacity", "is_initiator", "funding_txn_minimum_depth"])
       +ChannelConstraints = namedtuple("ChannelConstraints", ["capacity", "is_initiator", "funding_txn_minimum_depth", "feerate"])
        
        ScriptHtlc = namedtuple('ScriptHtlc', ['redeem_script', 'htlc'])
        
   DIR diff --git a/electrum/tests/test_lnhtlc.py b/electrum/tests/test_lnhtlc.py
       t@@ -34,7 +34,6 @@ def create_channel_state(funding_txid, funding_index, funding_sat, local_feerate
                        initial_msat=remote_amount,
                        ctn = 0,
                        next_htlc_id = 0,
       -                feerate=local_feerate,
                        amount_msat=remote_amount,
        
                        next_per_commitment_point=nex,
       t@@ -54,7 +53,6 @@ def create_channel_state(funding_txid, funding_index, funding_sat, local_feerate
                        initial_msat=local_amount,
                        ctn = 0,
                        next_htlc_id = 0,
       -                feerate=local_feerate,
                        amount_msat=local_amount,
        
                        per_commitment_secret_seed=seed,
       t@@ -63,7 +61,12 @@ def create_channel_state(funding_txid, funding_index, funding_sat, local_feerate
                        current_commitment_signature=None,
                        current_htlc_signatures=None,
                    ),
       -            "constraints":lnbase.ChannelConstraints(capacity=funding_sat, is_initiator=is_initiator, funding_txn_minimum_depth=3),
       +            "constraints":lnbase.ChannelConstraints(
       +                capacity=funding_sat,
       +                is_initiator=is_initiator,
       +                funding_txn_minimum_depth=3,
       +                feerate=local_feerate,
       +            ),
                    "node_id":other_node_id,
                    "remote_commitment_to_be_revoked": None,
                    'onion_keys': {},
       t@@ -271,20 +274,20 @@ class TestLNBaseHTLCStateMachine(unittest.TestCase):
        
                bob_channel.receive_new_commitment(alice_sig, alice_htlc_sigs)
        
       -        self.assertNotEqual(fee, bob_channel.config[LOCAL].feerate)
       +        self.assertNotEqual(fee, bob_channel.constraints.feerate)
                rev, _ = bob_channel.revoke_current_commitment()
       -        self.assertEqual(fee, bob_channel.config[LOCAL].feerate)
       +        self.assertEqual(fee, bob_channel.constraints.feerate)
        
                bob_sig, bob_htlc_sigs = bob_channel.sign_next_commitment()
                alice_channel.receive_revocation(rev)
                alice_channel.receive_new_commitment(bob_sig, bob_htlc_sigs)
        
       -        self.assertNotEqual(fee, alice_channel.config[LOCAL].feerate)
       +        self.assertNotEqual(fee, alice_channel.constraints.feerate)
                rev, _ = alice_channel.revoke_current_commitment()
       -        self.assertEqual(fee, alice_channel.config[LOCAL].feerate)
       +        self.assertEqual(fee, alice_channel.constraints.feerate)
        
                bob_channel.receive_revocation(rev)
       -        self.assertEqual(fee, bob_channel.config[REMOTE].feerate)
       +        self.assertEqual(fee, bob_channel.constraints.feerate)
        
        
            def test_UpdateFeeReceiverCommits(self):
       t@@ -300,20 +303,20 @@ class TestLNBaseHTLCStateMachine(unittest.TestCase):
                alice_sig, alice_htlc_sigs = alice_channel.sign_next_commitment()
                bob_channel.receive_new_commitment(alice_sig, alice_htlc_sigs)
        
       -        self.assertNotEqual(fee, bob_channel.config[LOCAL].feerate)
       +        self.assertNotEqual(fee, bob_channel.constraints.feerate)
                bob_revocation, _ = bob_channel.revoke_current_commitment()
       -        self.assertEqual(fee, bob_channel.config[LOCAL].feerate)
       +        self.assertEqual(fee, bob_channel.constraints.feerate)
        
                bob_sig, bob_htlc_sigs = bob_channel.sign_next_commitment()
                alice_channel.receive_revocation(bob_revocation)
                alice_channel.receive_new_commitment(bob_sig, bob_htlc_sigs)
        
       -        self.assertNotEqual(fee, alice_channel.config[LOCAL].feerate)
       +        self.assertNotEqual(fee, alice_channel.constraints.feerate)
                alice_revocation, _ = alice_channel.revoke_current_commitment()
       -        self.assertEqual(fee, alice_channel.config[LOCAL].feerate)
       +        self.assertEqual(fee, alice_channel.constraints.feerate)
        
                bob_channel.receive_revocation(alice_revocation)
       -        self.assertEqual(fee, bob_channel.config[REMOTE].feerate)
       +        self.assertEqual(fee, bob_channel.constraints.feerate)
        
        
        
       t@@ -323,7 +326,7 @@ class TestLNHTLCDust(unittest.TestCase):
        
                paymentPreimage = b"\x01" * 32
                paymentHash = bitcoin.sha256(paymentPreimage)
       -        fee_per_kw = alice_channel.config[LOCAL].feerate
       +        fee_per_kw = alice_channel.constraints.feerate
                self.assertEqual(fee_per_kw, 6000)
                htlcAmt = 500 + lnutil.HTLC_TIMEOUT_WEIGHT * (fee_per_kw // 1000)
                self.assertEqual(htlcAmt, 4478)