URI: 
       tlnhtlc: move 'next_htlc_id' from ChannelConfig to lnhtlc log - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit c046f2cc1c7741ff8e0b8da50cc1365120c20ba7
   DIR parent c8b19aec2ac45eb6464454a35413ad0baf79cb44
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Fri,  2 Aug 2019 20:54:41 +0200
       
       lnhtlc: move 'next_htlc_id' from ChannelConfig to lnhtlc log
       
       Diffstat:
         M electrum/lnchannel.py               |       8 ++++----
         M electrum/lnhtlc.py                  |      12 ++++++++++++
         M electrum/lnpeer.py                  |      10 +++++-----
         M electrum/lnutil.py                  |       2 --
         M electrum/tests/test_lnchannel.py    |       2 --
       
       5 files changed, 21 insertions(+), 13 deletions(-)
       ---
   DIR diff --git a/electrum/lnchannel.py b/electrum/lnchannel.py
       t@@ -243,10 +243,10 @@ class Channel(Logger):
                    htlc = UpdateAddHtlc(**htlc)
                assert isinstance(htlc, UpdateAddHtlc)
                self._check_can_pay(htlc.amount_msat)
       -        htlc = htlc._replace(htlc_id=self.config[LOCAL].next_htlc_id)
       +        if htlc.htlc_id is None:
       +            htlc = htlc._replace(htlc_id=self.hm.get_next_htlc_id(LOCAL))
                self.hm.send_htlc(htlc)
                self.logger.info("add_htlc")
       -        self.config[LOCAL]=self.config[LOCAL]._replace(next_htlc_id=htlc.htlc_id + 1)
                return htlc
        
            def receive_htlc(self, htlc: UpdateAddHtlc) -> UpdateAddHtlc:
       t@@ -260,14 +260,14 @@ class Channel(Logger):
                if isinstance(htlc, dict):  # legacy conversion  # FIXME remove
                    htlc = UpdateAddHtlc(**htlc)
                assert isinstance(htlc, UpdateAddHtlc)
       -        htlc = htlc._replace(htlc_id=self.config[REMOTE].next_htlc_id)
       +        if htlc.htlc_id is None:  # used in unit tests
       +            htlc = htlc._replace(htlc_id=self.hm.get_next_htlc_id(REMOTE))
                if 0 <= self.available_to_spend(REMOTE) < htlc.amount_msat:
                    raise RemoteMisbehaving('Remote dipped below channel reserve.' +\
                            f' Available at remote: {self.available_to_spend(REMOTE)},' +\
                            f' HTLC amount: {htlc.amount_msat}')
                self.hm.recv_htlc(htlc)
                self.logger.info("receive_htlc")
       -        self.config[REMOTE]=self.config[REMOTE]._replace(next_htlc_id=htlc.htlc_id + 1)
                return htlc
        
            def sign_next_commitment(self):
   DIR diff --git a/electrum/lnhtlc.py b/electrum/lnhtlc.py
       t@@ -18,6 +18,7 @@ class HTLCManager:
                        'fails': {},
                        'fee_updates': [],
                        'revack_pending': False,
       +                'next_htlc_id': 0,
                    }
                    log = {LOCAL: deepcopy(initial), REMOTE: deepcopy(initial)}
                else:
       t@@ -54,6 +55,9 @@ class HTLCManager:
            def _set_revack_pending(self, sub: HTLCOwner, pending: bool) -> None:
                self.log[sub]['revack_pending'] = pending
        
       +    def get_next_htlc_id(self, sub: HTLCOwner) -> int:
       +        return self.log[sub]['next_htlc_id']
       +
            def to_save(self):
                log = deepcopy(self.log)
                for sub in (LOCAL, REMOTE):
       t@@ -75,14 +79,22 @@ class HTLCManager:
        
            def send_htlc(self, htlc: UpdateAddHtlc) -> UpdateAddHtlc:
                htlc_id = htlc.htlc_id
       +        if htlc_id != self.get_next_htlc_id(LOCAL):
       +            raise Exception(f"unexpected local htlc_id. next should be "
       +                            f"{self.get_next_htlc_id(LOCAL)} but got {htlc_id}")
                self.log[LOCAL]['adds'][htlc_id] = htlc
                self.log[LOCAL]['locked_in'][htlc_id] = {LOCAL: None, REMOTE: self.ctn_latest(REMOTE)+1}
       +        self.log[LOCAL]['next_htlc_id'] += 1
                return htlc
        
            def recv_htlc(self, htlc: UpdateAddHtlc) -> None:
                htlc_id = htlc.htlc_id
       +        if htlc_id != self.get_next_htlc_id(REMOTE):
       +            raise Exception(f"unexpected remote htlc_id. next should be "
       +                            f"{self.get_next_htlc_id(REMOTE)} but got {htlc_id}")
                self.log[REMOTE]['adds'][htlc_id] = htlc
                self.log[REMOTE]['locked_in'][htlc_id] = {LOCAL: self.ctn_latest(LOCAL)+1, REMOTE: None}
       +        self.log[REMOTE]['next_htlc_id'] += 1
        
            def send_settle(self, htlc_id: int) -> None:
                self.log[REMOTE]['settles'][htlc_id] = {LOCAL: None, REMOTE: self.ctn_latest(REMOTE) + 1}
   DIR diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py
       t@@ -434,7 +434,6 @@ class Peer(Logger):
                    max_accepted_htlcs=5,
                    initial_msat=initial_msat,
                    ctn=-1,
       -            next_htlc_id=0,
                    reserve_sat=546,
                    per_commitment_secret_seed=keypair_generator(LnKeyFamily.REVOCATION_ROOT).privkey,
                    funding_locked_received=False,
       t@@ -518,7 +517,6 @@ class Peer(Logger):
                    max_accepted_htlcs=max_accepted_htlcs,
                    initial_msat=push_msat,
                    ctn = -1,
       -            next_htlc_id = 0,
                    reserve_sat = remote_reserve_sat,
                    htlc_minimum_msat = htlc_min,
        
       t@@ -621,7 +619,6 @@ class Peer(Logger):
                            max_accepted_htlcs=int.from_bytes(payload['max_accepted_htlcs'], 'big'), # TODO validate
                            initial_msat=remote_balance_sat,
                            ctn = -1,
       -                    next_htlc_id = 0,
                            reserve_sat = remote_reserve_sat,
                            htlc_minimum_msat=int.from_bytes(payload['htlc_minimum_msat'], 'big'), # TODO validate
                            next_per_commitment_point=payload['first_per_commitment_point'],
       t@@ -1142,11 +1139,14 @@ class Peer(Logger):
                processed_onion = process_onion_packet(onion_packet, associated_data=payment_hash, our_onion_private_key=self.privkey)
                chan = self.channels[channel_id]
                assert chan.get_state() == "OPEN"
       -        assert htlc_id == chan.config[REMOTE].next_htlc_id, (htlc_id, chan.config[REMOTE].next_htlc_id)  # TODO fail channel instead
                if cltv_expiry >= 500_000_000:
                    pass  # TODO fail the channel
                # add htlc
       -        htlc = UpdateAddHtlc(amount_msat=amount_msat_htlc, payment_hash=payment_hash, cltv_expiry=cltv_expiry, timestamp=int(time.time()))
       +        htlc = UpdateAddHtlc(amount_msat=amount_msat_htlc,
       +                             payment_hash=payment_hash,
       +                             cltv_expiry=cltv_expiry,
       +                             timestamp=int(time.time()),
       +                             htlc_id=htlc_id)
                htlc = chan.receive_htlc(htlc)
                local_ctn = chan.get_current_ctn(LOCAL)
                remote_ctn = chan.get_current_ctn(REMOTE)
   DIR diff --git a/electrum/lnutil.py b/electrum/lnutil.py
       t@@ -35,7 +35,6 @@ OnlyPubkeyKeypair = namedtuple("OnlyPubkeyKeypair", ["pubkey"])
        class LocalConfig(NamedTuple):
            # shared channel config fields (DUPLICATED code!!)
            ctn: int
       -    next_htlc_id: int
            payment_basepoint: 'Keypair'
            multisig_key: 'Keypair'
            htlc_basepoint: 'Keypair'
       t@@ -59,7 +58,6 @@ class LocalConfig(NamedTuple):
        class RemoteConfig(NamedTuple):
            # shared channel config fields (DUPLICATED code!!)
            ctn: int
       -    next_htlc_id: int
            payment_basepoint: 'Keypair'
            multisig_key: 'Keypair'
            htlc_basepoint: 'Keypair'
   DIR diff --git a/electrum/tests/test_lnchannel.py b/electrum/tests/test_lnchannel.py
       t@@ -59,7 +59,6 @@ def create_channel_state(funding_txid, funding_index, funding_sat, is_initiator,
                        max_accepted_htlcs=5,
                        initial_msat=remote_amount,
                        ctn = -1,
       -                next_htlc_id = 0,
                        reserve_sat=0,
                        htlc_minimum_msat=1,
        
       t@@ -79,7 +78,6 @@ def create_channel_state(funding_txid, funding_index, funding_sat, is_initiator,
                        max_accepted_htlcs=5,
                        initial_msat=local_amount,
                        ctn = 0,
       -                next_htlc_id = 0,
                        reserve_sat=0,
        
                        per_commitment_secret_seed=seed,