URI: 
       tfix wallet history order: incl both on-chain and LN, sorted by time - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit a6302b3a124a2bc9a208e0e78ddcb81d53d6bdf9
   DIR parent 0869e09275c535b43e04a6208bdfe046f2f2b319
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Mon, 17 Feb 2020 16:33:54 +0100
       
       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
       tthing to do, given that is the order the "balance" column is calculated in.
       
       fixes #5958
       
       Diffstat:
         M electrum/gui/kivy/uix/screens.py    |       2 +-
         M electrum/gui/qt/history_list.py     |      12 ++----------
         M electrum/wallet.py                  |      23 ++++++++++++++++-------
       
       3 files changed, 19 insertions(+), 18 deletions(-)
       ---
   DIR diff --git a/electrum/gui/kivy/uix/screens.py b/electrum/gui/kivy/uix/screens.py
       t@@ -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]
        
   DIR diff --git a/electrum/gui/qt/history_list.py b/electrum/gui/qt/history_list.py
       t@@ -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:
       t@@ -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:
   DIR diff --git a/electrum/wallet.py b/electrum/wallet.py
       t@@ -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),
       t@@ -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():