t(fix) allow opening LN wallet with --offline - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit 1d187d36f0a90b13a88c8bd2f8e4f89f518b451d DIR parent 97c79d52f96cfcb191b75439185e068d37ca9f90 HTML Author: SomberNight <somber.night@protonmail.com> Date: Thu, 15 Oct 2020 14:20:51 +0200 (fix) allow opening LN wallet with --offline Diffstat: M electrum/gui/qt/channels_list.py | 2 +- M electrum/gui/qt/swap_dialog.py | 3 +++ M electrum/lnworker.py | 6 ++++-- M electrum/submarine_swaps.py | 33 +++++++++++++++++++++++-------- 4 files changed, 33 insertions(+), 11 deletions(-) --- DIR diff --git a/electrum/gui/qt/channels_list.py b/electrum/gui/qt/channels_list.py t@@ -79,7 +79,7 @@ class ChannelsList(MyTreeView): labels[subject] = label status = chan.get_state_for_GUI() closed = chan.is_closed() - if self.parent.network.is_lightning_running(): + if self.network and self.network.is_lightning_running(): node_info = self.parent.network.channel_db.get_node_info_for_node_id(chan.node_id) node_alias = (node_info.alias if node_info else '') or '' else: DIR diff --git a/electrum/gui/qt/swap_dialog.py b/electrum/gui/qt/swap_dialog.py t@@ -194,6 +194,9 @@ class SwapDialog(WindowModalDialog): self.fee_label.repaint() # macOS hack for #6269 def run(self): + if not self.network: + self.window.show_error(_("You are offline.")) + return self.window.run_coroutine_from_thread(self.swap_manager.get_pairs(), lambda x: self.update()) if not self.exec_(): return DIR diff --git a/electrum/lnworker.py b/electrum/lnworker.py t@@ -522,6 +522,8 @@ class LNWallet(LNWorker): self.pending_payments = defaultdict(asyncio.Future) # type: Dict[bytes, asyncio.Future[BarePaymentAttemptLog]] + self.swap_manager = SwapManager(wallet=self.wallet, lnworker=self) + @property def channels(self) -> Mapping[bytes, Channel]: """Returns a read-only copy of channels.""" t@@ -581,7 +583,7 @@ class LNWallet(LNWorker): self.lnwatcher = LNWalletWatcher(self, network) self.lnwatcher.start_network(network) self.network = network - self.swap_manager = SwapManager(self.wallet, network) + self.swap_manager.start_network(network=network, lnwatcher=self.lnwatcher) for chan in self.channels.values(): self.lnwatcher.add_channel(chan.funding_outpoint.to_str(), chan.get_funding_address()) t@@ -703,7 +705,7 @@ class LNWallet(LNWorker): out[closing_txid] = item # add info about submarine swaps settled_payments = self.get_settled_payments() - current_height = self.network.get_local_height() + current_height = self.wallet.get_local_height() for payment_hash_hex, swap in self.swap_manager.swaps.items(): txid = swap.spending_txid if swap.is_reverse else swap.funding_txid if txid is None: DIR diff --git a/electrum/submarine_swaps.py b/electrum/submarine_swaps.py t@@ -21,6 +21,8 @@ from . import constants if TYPE_CHECKING: from .network import Network from .wallet import Abstract_Wallet + from .lnwatcher import LNWalletWatcher + from .lnworker import LNWallet API_URL_MAINNET = 'https://swaps.electrum.org/api' t@@ -113,25 +115,23 @@ def create_claim_tx( class SwapManager(Logger): - def __init__(self, wallet: 'Abstract_Wallet', network: 'Network'): + network: Optional['Network'] = None + lnwatcher: Optional['LNWalletWatcher'] = None + + def __init__(self, *, wallet: 'Abstract_Wallet', lnworker: 'LNWallet'): Logger.__init__(self) self.normal_fee = 0 self.lockup_fee = 0 self.percentage = 0 self.min_amount = 0 self._max_amount = 0 - self.network = network self.wallet = wallet - self.lnworker = wallet.lnworker - self.lnwatcher = self.wallet.lnworker.lnwatcher + self.lnworker = lnworker self.swaps = self.wallet.db.get_dict('submarine_swaps') # type: Dict[str, SwapData] self.prepayments = {} # type: Dict[bytes, bytes] # fee_preimage -> preimage for k, swap in self.swaps.items(): if swap.is_reverse and swap.prepay_hash is not None: self.prepayments[swap.prepay_hash] = bytes.fromhex(k) - if swap.is_redeemed: - continue - self.add_lnwatcher_callback(swap) # api url if constants.net == constants.BitcoinMainnet: self.api_url = API_URL_MAINNET t@@ -140,8 +140,20 @@ class SwapManager(Logger): else: self.api_url = API_URL_REGTEST + def start_network(self, *, network: 'Network', lnwatcher: 'LNWalletWatcher'): + assert network + assert lnwatcher + self.network = network + self.lnwatcher = lnwatcher + for k, swap in self.swaps.items(): + if swap.is_redeemed: + continue + self.add_lnwatcher_callback(swap) + @log_exceptions async def _claim_swap(self, swap: SwapData) -> None: + assert self.network + assert self.lnwatcher if not self.lnwatcher.is_up_to_date(): return current_height = self.network.get_local_height() t@@ -189,7 +201,7 @@ class SwapManager(Logger): self.wallet.set_label(tx.txid(), 'Swap refund') def get_claim_fee(self): - return self.lnwatcher.config.estimate_fee(136, allow_fallback_to_static_rates=True) + return self.wallet.config.estimate_fee(136, allow_fallback_to_static_rates=True) def get_swap(self, payment_hash: bytes) -> Optional[SwapData]: # for history t@@ -207,6 +219,8 @@ class SwapManager(Logger): async def normal_swap(self, lightning_amount: int, expected_onchain_amount: int, password, *, tx: PartialTransaction = None) -> str: """send on-chain BTC, receive on Lightning""" + assert self.network + assert self.lnwatcher privkey = os.urandom(32) pubkey = ECPrivkey(privkey).get_public_key_bytes(compressed=True) lnaddr, invoice = await self.lnworker.create_invoice(lightning_amount, 'swap', expiry=3600*24) t@@ -283,6 +297,8 @@ class SwapManager(Logger): async def reverse_swap(self, amount_sat: int, expected_amount: int) -> bool: """send on Lightning, receive on-chain""" + assert self.network + assert self.lnwatcher privkey = os.urandom(32) pubkey = ECPrivkey(privkey).get_public_key_bytes(compressed=True) preimage = os.urandom(32) t@@ -370,6 +386,7 @@ class SwapManager(Logger): return success async def get_pairs(self) -> None: + assert self.network response = await self.network._send_http_on_proxy( 'get', self.api_url + '/getpairs',