From ac8a7a07849ea64a9c70f42c5f68e5e4d2b7152f Mon Sep 17 00:00:00 2001 From: accumulator Date: Tue, 16 May 2023 15:08:26 +0200 Subject: [PATCH] channel_db: raise specific exception when channelDB not loaded, allowing lnworker to mark payment as failed. (#8431) On mobile, it can take a while before channelDB is loaded. If payment is attempted before the DB is fully loaded, this would result in a payment failure, but also leaves the payment attempt in IN_PROGRESS state. This patch adds a more specific ChannelDBNotLoaded exception class, so we can handle this case more gracefully, since we know the payment didn't succeed. --- electrum/channel_db.py | 9 ++++++--- electrum/lnworker.py | 5 ++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/electrum/channel_db.py b/electrum/channel_db.py index e7b6e5f9e..e557261bf 100644 --- a/electrum/channel_db.py +++ b/electrum/channel_db.py @@ -38,7 +38,7 @@ from aiorpcx import NetAddress from .sql_db import SqlDB, sql from . import constants, util -from .util import profiler, get_headers_dir, is_ip_address, json_normalize +from .util import profiler, get_headers_dir, is_ip_address, json_normalize, UserFacingException from .logging import Logger from .lnutil import (LNPeerAddr, format_short_channel_id, ShortChannelID, validate_features, IncompatibleOrInsaneFeatures, InvalidGossipMsg) @@ -59,6 +59,9 @@ FLAG_DISABLE = 1 << 1 FLAG_DIRECTION = 1 << 0 +class ChannelDBNotLoaded(UserFacingException): pass + + class ChannelInfo(NamedTuple): short_channel_id: ShortChannelID node1_id: bytes @@ -375,7 +378,7 @@ class ChannelDB(SqlDB): def get_recent_peers(self): if not self.data_loaded.is_set(): - raise Exception("channelDB data not loaded yet!") + raise ChannelDBNotLoaded("channelDB data not loaded yet!") with self.lock: ret = [self.get_last_good_address(node_id) for node_id in self._recent_peers] @@ -842,7 +845,7 @@ class ChannelDB(SqlDB): ) -> Set[ShortChannelID]: """Returns the set of short channel IDs where node_id is one of the channel participants.""" if not self.data_loaded.is_set(): - raise Exception("channelDB data not loaded yet!") + raise ChannelDBNotLoaded("channelDB data not loaded yet!") relevant_channels = self._channels_for_node.get(node_id) or set() relevant_channels = set(relevant_channels) # copy # add our own channels # TODO maybe slow? diff --git a/electrum/lnworker.py b/electrum/lnworker.py index 0994b4e38..2abe2662c 100644 --- a/electrum/lnworker.py +++ b/electrum/lnworker.py @@ -79,7 +79,7 @@ from .lnwatcher import LNWalletWatcher from .crypto import pw_encode_with_version_and_mac, pw_decode_with_version_and_mac from .lnutil import ImportedChannelBackupStorage, OnchainChannelBackupStorage from .lnchannel import ChannelBackup -from .channel_db import UpdateStatus +from .channel_db import UpdateStatus, ChannelDBNotLoaded from .channel_db import get_mychannel_info, get_mychannel_policy from .submarine_swaps import SwapManager from .channel_db import ChannelInfo, Policy @@ -1202,6 +1202,9 @@ class LNWallet(LNWorker): except PaymentFailure as e: self.logger.info(f'payment failure: {e!r}') reason = str(e) + except ChannelDBNotLoaded as e: + self.logger.info(f'payment failure: {e!r}') + reason = str(e) finally: self.logger.info(f"pay_invoice ending session for RHASH={payment_hash.hex()}. {success=}") if success: