From a6302b3a124a2bc9a208e0e78ddcb81d53d6bdf9 Mon Sep 17 00:00:00 2001 From: SomberNight Date: Mon, 17 Feb 2020 16:33:54 +0100 Subject: [PATCH] fix wallet history order: incl both on-chain and LN, sorted by time GUIs now respect order of wallet.get_full_history(), which is probably the sane thing to do, given that is the order the "balance" column is calculated in. fixes #5958 --- electrum/gui/kivy/uix/screens.py | 2 +- electrum/gui/qt/history_list.py | 12 ++---------- electrum/wallet.py | 23 ++++++++++++++++------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/electrum/gui/kivy/uix/screens.py b/electrum/gui/kivy/uix/screens.py index f70586539..e780d6e5a 100644 --- a/electrum/gui/kivy/uix/screens.py +++ b/electrum/gui/kivy/uix/screens.py @@ -176,7 +176,7 @@ class HistoryScreen(CScreen): wallet = self.app.wallet if wallet is None: return - history = sorted(wallet.get_full_history(self.app.fx).values(), key=lambda x: x.get('timestamp') or float('inf'), reverse=True) + history = reversed(wallet.get_full_history(self.app.fx).values()) history_card = self.screen.ids.history_container history_card.data = [self.get_card(item) for item in history] diff --git a/electrum/gui/qt/history_list.py b/electrum/gui/qt/history_list.py index f317a22b0..dec6fc3fb 100644 --- a/electrum/gui/qt/history_list.py +++ b/electrum/gui/qt/history_list.py @@ -141,7 +141,6 @@ class HistoryModel(QAbstractItemModel, Logger): timestamp = tx_item['timestamp'] if is_lightning: status = 0 - txpos = tx_item['txpos'] if timestamp is None: status_str = 'unconfirmed' else: @@ -149,25 +148,18 @@ class HistoryModel(QAbstractItemModel, Logger): else: tx_hash = tx_item['txid'] conf = tx_item['confirmations'] - txpos = tx_item['txpos_in_block'] or 0 - height = tx_item['height'] try: status, status_str = self.tx_status_cache[tx_hash] except KeyError: tx_mined_info = self.tx_mined_info_from_tx_item(tx_item) status, status_str = self.parent.wallet.get_tx_status(tx_hash, tx_mined_info) - # we sort by timestamp - if timestamp is None: - timestamp = float("inf") - if role == Qt.UserRole: # for sorting d = { HistoryColumns.STATUS: - # height breaks ties for unverified txns - # txpos breaks ties for verified same block txns - (-timestamp, conf, -status, -height, -txpos) if not is_lightning else (-timestamp, 0,0,0,-txpos), + # respect sort order of self.transactions (wallet.get_full_history) + -index.row(), HistoryColumns.DESCRIPTION: tx_item['label'] if 'label' in tx_item else None, HistoryColumns.AMOUNT: diff --git a/electrum/wallet.py b/electrum/wallet.py index 65e2f031a..67580df37 100644 --- a/electrum/wallet.py +++ b/electrum/wallet.py @@ -578,13 +578,16 @@ class Abstract_Wallet(AddressSynchronizer, ABC): return balance def get_onchain_history(self, *, domain=None): + monotonic_timestamp = 0 for hist_item in self.get_history(domain=domain): + monotonic_timestamp = max(monotonic_timestamp, (hist_item.tx_mined_status.timestamp or float('inf'))) yield { 'txid': hist_item.txid, 'fee_sat': hist_item.fee, 'height': hist_item.tx_mined_status.height, 'confirmations': hist_item.tx_mined_status.conf, 'timestamp': hist_item.tx_mined_status.timestamp, + 'monotonic_timestamp': monotonic_timestamp, 'incoming': True if hist_item.delta>0 else False, 'bc_value': Satoshis(hist_item.delta), 'bc_balance': Satoshis(hist_item.balance), @@ -724,29 +727,35 @@ class Abstract_Wallet(AddressSynchronizer, ABC): @profiler def get_full_history(self, fx=None, *, onchain_domain=None, include_lightning=True): - transactions = OrderedDictWithIndex() + transactions_tmp = OrderedDictWithIndex() + # add on-chain txns onchain_history = self.get_onchain_history(domain=onchain_domain) for tx_item in onchain_history: txid = tx_item['txid'] - transactions[txid] = tx_item + transactions_tmp[txid] = tx_item + # add LN txns if self.lnworker and include_lightning: lightning_history = self.lnworker.get_history() else: lightning_history = [] - for i, tx_item in enumerate(lightning_history): txid = tx_item.get('txid') ln_value = Decimal(tx_item['amount_msat']) / 1000 - if txid and txid in transactions: - item = transactions[txid] + if txid and txid in transactions_tmp: + item = transactions_tmp[txid] item['label'] = tx_item['label'] item['ln_value'] = Satoshis(ln_value) else: tx_item['lightning'] = True tx_item['ln_value'] = Satoshis(ln_value) - tx_item['txpos'] = i # for sorting key = tx_item.get('txid') or tx_item['payment_hash'] - transactions[key] = tx_item + transactions_tmp[key] = tx_item + # sort on-chain and LN stuff into new dict, by timestamp + # (we rely on this being a *stable* sort) + transactions = OrderedDictWithIndex() + for k, v in sorted(list(transactions_tmp.items()), + key=lambda x: x[1].get('monotonic_timestamp') or x[1].get('timestamp') or float('inf')): + transactions[k] = v now = time.time() balance = 0 for item in transactions.values():