tshow swaps as single line in history main_window.run_coroutine_from_thread - electrum - Electrum Bitcoin wallet (HTM) git clone https://git.parazyd.org/electrum (DIR) Log (DIR) Files (DIR) Refs (DIR) Submodules --- (DIR) commit f8dd62aec0b56acec03d95d8043f3555d72ac745 (DIR) parent 46770bfd71d7675abaca3d2e74cc7b8088cd8ac4 (HTM) Author: ThomasV <thomasv@electrum.org> Date: Tue, 26 May 2020 10:02:27 +0200 show swaps as single line in history main_window.run_coroutine_from_thread Diffstat: M electrum/gui/qt/main_window.py | 11 +++++++++++ M electrum/gui/qt/swap_dialog.py | 10 ++++------ M electrum/gui/qt/transaction_dialog… | 5 +++++ M electrum/lnworker.py | 28 ++++++++++++++++++++++++++++ M electrum/submarine_swaps.py | 24 ++++++++++++++++-------- M electrum/wallet.py | 2 +- 6 files changed, 65 insertions(+), 15 deletions(-) --- (DIR) diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py t@@ -299,6 +299,17 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger): Exception_Hook.maybe_setup(config=self.config, wallet=self.wallet) + def run_coroutine_from_thread(self, coro, on_result=None): + def task(): + try: + f = asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop) + r = f.result() + if on_result: + on_result(r) + except Exception as e: + self.show_error(str(e)) + self.wallet.thread.add(task) + def on_fx_history(self): self.history_model.refresh('fx_history') self.address_list.update() (DIR) diff --git a/electrum/gui/qt/swap_dialog.py b/electrum/gui/qt/swap_dialog.py t@@ -122,9 +122,7 @@ class SwapDialog(WindowModalDialog): self.send_amount_e.follows = False self.send_follows = True - def get_pairs(self): - fut = asyncio.run_coroutine_threadsafe(self.swap_manager.get_pairs(), self.network.asyncio_loop) - pairs = fut.result() + def on_pairs(self, pairs): fees = pairs['pairs']['BTC/BTC']['fees'] self.percentage = fees['percentage'] self.normal_fee = fees['minerFees']['baseAsset']['normal'] t@@ -181,14 +179,14 @@ class SwapDialog(WindowModalDialog): return x def run(self): - self.get_pairs() + self.window.run_coroutine_from_thread(self.swap_manager.get_pairs(), self.on_pairs) if not self.exec_(): return if self.is_reverse: lightning_amount = self.send_amount_e.get_amount() onchain_amount = self.recv_amount_e.get_amount() + self.claim_fee coro = self.swap_manager.reverse_swap(lightning_amount, onchain_amount) - asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop) + self.window.run_coroutine_from_thread(coro) else: lightning_amount = self.recv_amount_e.get_amount() onchain_amount = self.send_amount_e.get_amount() t@@ -196,4 +194,4 @@ class SwapDialog(WindowModalDialog): def do_normal_swap(self, lightning_amount, onchain_amount, password): coro = self.swap_manager.normal_swap(lightning_amount, onchain_amount, password) - asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop) + self.window.run_coroutine_from_thread(coro) (DIR) diff --git a/electrum/gui/qt/transaction_dialog.py b/electrum/gui/qt/transaction_dialog.py t@@ -414,6 +414,11 @@ class BaseTxDialog(QDialog, MessageBoxMixin): tx_mined_status = self.wallet.lnworker.lnwatcher.get_tx_height(txid) else: ln_amount = None + swap_history = self.wallet.lnworker.get_swap_history() if self.wallet.lnworker else {} + if txid in swap_history: + item = swap_history[txid] + ln_amount = item['lightning_amount'] + self.broadcast_button.setEnabled(tx_details.can_broadcast) can_sign = not self.tx.is_complete() and \ (self.wallet.can_sign(self.tx) or bool(self.external_keypairs)) (DIR) diff --git a/electrum/lnworker.py b/electrum/lnworker.py t@@ -626,9 +626,37 @@ class LNWallet(LNWorker): 'payment_hash': key, 'preimage': preimage, } + # add txid to merge item with onchain item + swap_info = self.swap_manager.get_swap(preimage) + if swap_info: + is_reverse = swap_info.get('invoice') + if is_reverse: + item['txid'] = swap_info.get('claim_txid') + lightning_amount = swap_info.get('lightning_amount') + item['label'] = 'Reverse swap' + ' ' + self.config.format_amount_and_units(lightning_amount) + else: + item['txid'] = swap_info.get('funding_txid') + onchain_amount = swap_info["expectedAmount"] + item['label'] = 'Normal swap' + ' ' + self.config.format_amount_and_units(onchain_amount) + # done out[payment_hash] = item return out + def get_swap_history(self): + out = {} + for k, swap_info in self.swap_manager.swaps.items(): + is_reverse = swap_info.get('invoice') + if is_reverse: + txid = swap_info.get('claim_txid') + else: + txid = swap_info.get('funding_txid') + if txid is None: + continue + out[txid] = { + 'lightning_amount': swap_info.get('lightning_amount', 0) * (-1 if is_reverse else 1) + } + return out + def get_onchain_history(self): out = {} # add funding events (DIR) diff --git a/electrum/submarine_swaps.py b/electrum/submarine_swaps.py t@@ -96,6 +96,9 @@ class SwapManager(Logger): address = self.wallet.get_unused_address() tx = create_claim_tx(txin, redeem_script, preimage, privkey, address, amount_sat, locktime) await self.network.broadcast_transaction(tx) + # save txid + what = 'claim_txid' if preimage else 'refund_txid' + self.swaps[preimage.hex()][what] = tx.txid() def get_tx_fee(self): return self.lnwatcher.config.estimate_fee(136, allow_fallback_to_static_rates=True) t@@ -106,8 +109,8 @@ class SwapManager(Logger): self.wallet = wallet self.lnworker = wallet.lnworker self.lnwatcher = self.wallet.lnworker.lnwatcher - swaps = self.wallet.db.get_dict('submarine_swaps') - for key, data in swaps.items(): + self.swaps = self.wallet.db.get_dict('submarine_swaps') + for data in self.swaps.values(): redeem_script = bytes.fromhex(data['redeemScript']) locktime = data['timeoutBlockHeight'] privkey = bytes.fromhex(data['privkey']) t@@ -121,6 +124,9 @@ class SwapManager(Logger): preimage = 0 self.add_lnwatcher_callback(lockup_address, onchain_amount, redeem_script, preimage, privkey, locktime) + def get_swap(self, preimage_hex): + return self.swaps.get(preimage_hex) + def add_lnwatcher_callback(self, lockup_address, onchain_amount, redeem_script, preimage, privkey, locktime): callback = lambda: self._claim_swap(lockup_address, onchain_amount, redeem_script, preimage, privkey, locktime) self.lnwatcher.add_callback(lockup_address, callback) t@@ -166,14 +172,16 @@ class SwapManager(Logger): assert onchain_amount <= expected_onchain_amount, (onchain_amount, expected_onchain_amount) # verify that they are not locking up funds for more than a day assert locktime - self.network.get_local_height() < 144 + # create funding tx + outputs = [PartialTxOutput.from_address_and_value(lockup_address, onchain_amount)] + tx = self.wallet.create_transaction(outputs=outputs, rbf=False, password=password) # save swap data in wallet in case we need a refund data['privkey'] = privkey.hex() data['preimage'] = preimage.hex() - swaps = self.wallet.db.get_dict('submarine_swaps') - swaps[response_id] = data + data['lightning_amount'] = lightning_amount + data['funding_txid'] = tx.txid() + self.swaps[preimage.hex()] = data self.add_lnwatcher_callback(lockup_address, onchain_amount, redeem_script, 0, privkey, locktime) - outputs = [PartialTxOutput.from_address_and_value(lockup_address, onchain_amount)] - tx = self.wallet.create_transaction(outputs=outputs, rbf=False, password=password) await self.network.broadcast_transaction(tx) # attempt = await self.lnworker.await_payment(payment_hash) t@@ -226,9 +234,9 @@ class SwapManager(Logger): # save swap data in wallet in case payment fails data['privkey'] = privkey.hex() data['preimage'] = preimage.hex() + data['lightning_amount'] = amount_sat # save data to wallet file - swaps = self.wallet.db.get_dict('submarine_swaps') - swaps[response_id] = data + self.swaps[preimage.hex()] = data # add callback to lnwatcher self.add_lnwatcher_callback(lockup_address, onchain_amount, redeem_script, preimage, privkey, locktime) # initiate payment. (DIR) diff --git a/electrum/wallet.py b/electrum/wallet.py t@@ -835,7 +835,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC): item = transactions_tmp[txid] item['label'] = tx_item['label'] item['type'] = tx_item['type'] - item['channel_id'] = tx_item['channel_id'] + #item['channel_id'] = tx_item['channel_id'] item['ln_value'] = Satoshis(ln_value) else: tx_item['lightning'] = True