electrum

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

commit ee24c74f192960f3e2d31ffb6b910e6bfb6bd90f
parent 7110fde25d1f6c4cc6420a226f504dcc1a32cbca
Author: SomberNight <somber.night@protonmail.com>
Date:   Fri, 23 Oct 2020 02:35:20 +0200

lnchan.receive_revocation: tolerate not having htlc fail reason

If we get a revack after reestablish, but the fail_htlc was already
committed in a previous app-session, the fail_htlc will not be re-sent and
we will not have the reason (as it's not persisted).

fixes #6675

Diffstat:
Melectrum/lnchannel.py | 12++++++++++--
Melectrum/lnworker.py | 10++++++++--
2 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/electrum/lnchannel.py b/electrum/lnchannel.py @@ -997,14 +997,22 @@ class Channel(AbstractChannel): self.lnworker.payment_sent(self, htlc.payment_hash) failed = self.hm.failed_in_ctn(new_ctn) for htlc in failed: - error_bytes, failure_message = self._receive_fail_reasons.pop(htlc.htlc_id) + try: + error_bytes, failure_message = self._receive_fail_reasons.pop(htlc.htlc_id) + except KeyError: + error_bytes, failure_message = None, None # if we are forwarding, save error message to disk if self.lnworker.get_payment_info(htlc.payment_hash) is None: self.save_fail_htlc_reason(htlc.htlc_id, error_bytes, failure_message) else: self.lnworker.payment_failed(self, htlc.payment_hash, error_bytes, failure_message) - def save_fail_htlc_reason(self, htlc_id, error_bytes, failure_message): + def save_fail_htlc_reason( + self, + htlc_id: int, + error_bytes: Optional[bytes], + failure_message: Optional['OnionRoutingFailureMessage'], + ): error_hex = error_bytes.hex() if error_bytes else None failure_hex = failure_message.to_bytes().hex() if failure_message else None self.hm.log['fail_htlc_reasons'][htlc_id] = (error_hex, failure_hex) diff --git a/electrum/lnworker.py b/electrum/lnworker.py @@ -59,7 +59,7 @@ from .lnutil import (Outpoint, LNPeerAddr, BarePaymentAttemptLog, derive_payment_secret_from_payment_preimage) from .lnutil import ln_dummy_address, ln_compare_features, IncompatibleLightningFeatures from .transaction import PartialTxOutput, PartialTransaction, PartialTxInput -from .lnonion import OnionFailureCode, process_onion_packet, OnionPacket +from .lnonion import OnionFailureCode, process_onion_packet, OnionPacket, OnionRoutingFailureMessage from .lnmsg import decode_msg from .i18n import _ from .lnrouter import (RouteEdge, LNPaymentRoute, LNPaymentPath, is_route_sane_to_use, @@ -1241,7 +1241,13 @@ class LNWallet(LNWorker): info = info._replace(status=status) self.save_payment_info(info) - def payment_failed(self, chan, payment_hash: bytes, error_bytes: bytes, failure_message): + def payment_failed( + self, + chan: Channel, + payment_hash: bytes, + error_bytes: Optional[bytes], + failure_message: Optional['OnionRoutingFailureMessage'], + ): self.set_payment_status(payment_hash, PR_UNPAID) f = self.pending_payments.get(payment_hash) if f and not f.cancelled():