electrum

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

commit aba2e0f55a2401928bbcee584693e1170e494e1c
parent 51f42a25f9984a2c780d5aebc68efb5f576ac524
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

towards encapsulation of hm.log

Diffstat:
Melectrum/lnchannel.py | 49+++++++++++++++++++++----------------------------
Melectrum/lnhtlc.py | 22+++++++++++++++++++---
Melectrum/lnpeer.py | 2+-
3 files changed, 41 insertions(+), 32 deletions(-)

diff --git a/electrum/lnchannel.py b/electrum/lnchannel.py @@ -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: @@ -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'], @@ -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) @@ -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 diff --git a/electrum/lnhtlc.py b/electrum/lnhtlc.py @@ -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: @@ -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, @@ -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'. diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py @@ -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]