URI: 
       tlnhtlc: add all_htlcs_ever, get_htlc_by_id, was_htlc_failed and use them - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit aba2e0f55a2401928bbcee584693e1170e494e1c
   DIR parent 51f42a25f9984a2c780d5aebc68efb5f576ac524
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Wed,  2 Sep 2020 21:21:49 +0200
       
       lnhtlc: add all_htlcs_ever, get_htlc_by_id, was_htlc_failed and use them
       
       ttowards encapsulation of hm.log
       
       Diffstat:
         M electrum/lnchannel.py               |      49 +++++++++++++------------------
         M electrum/lnhtlc.py                  |      22 +++++++++++++++++++---
         M electrum/lnpeer.py                  |       2 +-
       
       3 files changed, 41 insertions(+), 32 deletions(-)
       ---
   DIR diff --git a/electrum/lnchannel.py b/electrum/lnchannel.py
       t@@ -647,29 +647,25 @@ class Channel(AbstractChannel):
        
            def get_payments(self):
                out = []
       -        for subject in LOCAL, REMOTE:
       -            log = self.hm.log[subject]
       -            for htlc_id, htlc in log.get('adds', {}).items():
       -                if htlc_id in log.get('fails',{}):
       -                    status = 'failed'
       -                elif htlc_id in log.get('settles',{}):
       -                    status = 'settled'
       -                else:
       -                    status = 'inflight'
       -                direction = SENT if subject is LOCAL else RECEIVED
       -                rhash = bh2u(htlc.payment_hash)
       -                out.append((rhash, self.channel_id, htlc, direction, status))
       +        for direction, htlc in self.hm.all_htlcs_ever():
       +            htlc_proposer = LOCAL if direction is SENT else REMOTE
       +            if self.hm.was_htlc_failed(htlc_id=htlc.htlc_id, htlc_proposer=htlc_proposer):
       +                status = 'failed'
       +            elif self.hm.was_htlc_preimage_released(htlc_id=htlc.htlc_id, htlc_proposer=htlc_proposer):
       +                status = 'settled'
       +            else:
       +                status = 'inflight'
       +            rhash = htlc.payment_hash.hex()
       +            out.append((rhash, self.channel_id, htlc, direction, status))
                return out
        
            def get_settled_payments(self):
                out = defaultdict(list)
       -        for subject in LOCAL, REMOTE:
       -            log = self.hm.log[subject]
       -            for htlc_id, htlc in log.get('adds', {}).items():
       -                if htlc_id in log.get('settles',{}):
       -                    direction = SENT if subject is LOCAL else RECEIVED
       -                    rhash = bh2u(htlc.payment_hash)
       -                    out[rhash].append((self.channel_id, htlc, direction))
       +        for direction, htlc in self.hm.all_htlcs_ever():
       +            htlc_proposer = LOCAL if direction is SENT else REMOTE
       +            if self.hm.was_htlc_preimage_released(htlc_id=htlc.htlc_id, htlc_proposer=htlc_proposer):
       +                rhash = htlc.payment_hash.hex()
       +                out[rhash].append((self.channel_id, htlc, direction))
                return out
        
            def open_with_first_pcp(self, remote_pcp: bytes, remote_sig: bytes) -> None:
       t@@ -1206,15 +1202,13 @@ class Channel(AbstractChannel):
                """
                self.logger.info("settle_htlc")
                assert self.can_send_ctx_updates(), f"cannot update channel. {self.get_state()!r} {self.peer_state!r}"
       -        log = self.hm.log[REMOTE]
       -        htlc = log['adds'][htlc_id]
       +        htlc = self.hm.get_htlc_by_id(REMOTE, htlc_id)
                assert htlc.payment_hash == sha256(preimage)
       -        assert htlc_id not in log['settles']
       +        assert htlc_id not in self.hm.log[REMOTE]['settles']
                self.hm.send_settle(htlc_id)
        
            def get_payment_hash(self, htlc_id: int) -> bytes:
       -        log = self.hm.log[LOCAL]
       -        htlc = log['adds'][htlc_id]  # type: UpdateAddHtlc
       +        htlc = self.hm.get_htlc_by_id(LOCAL, htlc_id)
                return htlc.payment_hash
        
            def decode_onion_error(self, reason: bytes, route: Sequence['RouteEdge'],
       t@@ -1230,10 +1224,9 @@ class Channel(AbstractChannel):
                Action must be initiated by REMOTE.
                """
                self.logger.info("receive_htlc_settle")
       -        log = self.hm.log[LOCAL]
       -        htlc = log['adds'][htlc_id]
       +        htlc = self.hm.get_htlc_by_id(LOCAL, htlc_id)
                assert htlc.payment_hash == sha256(preimage)
       -        assert htlc_id not in log['settles']
       +        assert htlc_id not in self.hm.log[LOCAL]['settles']
                with self.db_lock:
                    self.hm.recv_settle(htlc_id)
        
       t@@ -1419,7 +1412,7 @@ class Channel(AbstractChannel):
                                      (REMOTE, SENT, self.get_oldest_unrevoked_ctn(LOCAL)),
                                      (REMOTE, SENT, self.get_latest_ctn(LOCAL)),):
                    for htlc_id, htlc in self.hm.htlcs_by_direction(subject=sub, direction=dir, ctn=ctn).items():
       -                if not self.hm.was_htlc_preimage_released(htlc_id=htlc_id, htlc_sender=REMOTE):
       +                if not self.hm.was_htlc_preimage_released(htlc_id=htlc_id, htlc_proposer=REMOTE):
                            continue
                        if htlc.cltv_expiry - recv_htlc_deadline > local_height:
                            continue
   DIR diff --git a/electrum/lnhtlc.py b/electrum/lnhtlc.py
       t@@ -294,6 +294,9 @@ class HTLCManager:
        
            ##### Queries re HTLCs:
        
       +    def get_htlc_by_id(self, htlc_proposer: HTLCOwner, htlc_id: int) -> UpdateAddHtlc:
       +        return self.log[htlc_proposer]['adds'][htlc_id]
       +
            @with_lock
            def is_htlc_active_at_ctn(self, *, ctx_owner: HTLCOwner, ctn: int,
                                      htlc_proposer: HTLCOwner, htlc_id: int) -> bool:
       t@@ -365,11 +368,18 @@ class HTLCManager:
                ctn = self.ctn_latest(subject) + 1
                return self.htlcs(subject, ctn)
        
       -    def was_htlc_preimage_released(self, *, htlc_id: int, htlc_sender: HTLCOwner) -> bool:
       -        settles = self.log[htlc_sender]['settles']
       +    def was_htlc_preimage_released(self, *, htlc_id: int, htlc_proposer: HTLCOwner) -> bool:
       +        settles = self.log[htlc_proposer]['settles']
                if htlc_id not in settles:
                    return False
       -        return settles[htlc_id][htlc_sender] is not None
       +        return settles[htlc_id][htlc_proposer] is not None
       +
       +    def was_htlc_failed(self, *, htlc_id: int, htlc_proposer: HTLCOwner) -> bool:
       +        """Returns whether an HTLC has been (or will be if we already know) failed."""
       +        fails = self.log[htlc_proposer]['fails']
       +        if htlc_id not in fails:
       +            return False
       +        return fails[htlc_id][htlc_proposer] is not None
        
            @with_lock
            def all_settled_htlcs_ever_by_direction(self, subject: HTLCOwner, direction: Direction,
       t@@ -403,6 +413,12 @@ class HTLCManager:
                return sent + received
        
            @with_lock
       +    def all_htlcs_ever(self) -> Sequence[Tuple[Direction, UpdateAddHtlc]]:
       +        sent = [(SENT, htlc) for htlc in self.log[LOCAL]['adds'].values()]
       +        received = [(RECEIVED, htlc) for htlc in self.log[LOCAL]['adds'].values()]
       +        return sent + received
       +
       +    @with_lock
            def get_balance_msat(self, whose: HTLCOwner, *, ctx_owner=HTLCOwner.LOCAL, ctn: int = None,
                                 initial_balance_msat: int) -> int:
                """Returns the balance of 'whose' in 'ctx' at 'ctn'.
   DIR diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py
       t@@ -1541,7 +1541,7 @@ class Peer(Logger):
                            if chan.get_oldest_unrevoked_ctn(REMOTE) <= remote_ctn:
                                continue
                            chan.logger.info(f'found unfulfilled htlc: {htlc_id}')
       -                    htlc = chan.hm.log[REMOTE]['adds'][htlc_id]
       +                    htlc = chan.hm.get_htlc_by_id(REMOTE, htlc_id)
                            payment_hash = htlc.payment_hash
                            error_reason = None  # type: Optional[OnionRoutingFailureMessage]
                            error_bytes = None  # type: Optional[bytes]