Browse Source

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
hard-fail-on-bad-server-string
SomberNight 5 years ago
parent
commit
a6302b3a12
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 2
      electrum/gui/kivy/uix/screens.py
  2. 12
      electrum/gui/qt/history_list.py
  3. 23
      electrum/wallet.py

2
electrum/gui/kivy/uix/screens.py

@ -176,7 +176,7 @@ class HistoryScreen(CScreen):
wallet = self.app.wallet wallet = self.app.wallet
if wallet is None: if wallet is None:
return 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 = self.screen.ids.history_container
history_card.data = [self.get_card(item) for item in history] history_card.data = [self.get_card(item) for item in history]

12
electrum/gui/qt/history_list.py

@ -141,7 +141,6 @@ class HistoryModel(QAbstractItemModel, Logger):
timestamp = tx_item['timestamp'] timestamp = tx_item['timestamp']
if is_lightning: if is_lightning:
status = 0 status = 0
txpos = tx_item['txpos']
if timestamp is None: if timestamp is None:
status_str = 'unconfirmed' status_str = 'unconfirmed'
else: else:
@ -149,25 +148,18 @@ class HistoryModel(QAbstractItemModel, Logger):
else: else:
tx_hash = tx_item['txid'] tx_hash = tx_item['txid']
conf = tx_item['confirmations'] conf = tx_item['confirmations']
txpos = tx_item['txpos_in_block'] or 0
height = tx_item['height']
try: try:
status, status_str = self.tx_status_cache[tx_hash] status, status_str = self.tx_status_cache[tx_hash]
except KeyError: except KeyError:
tx_mined_info = self.tx_mined_info_from_tx_item(tx_item) 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) 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: if role == Qt.UserRole:
# for sorting # for sorting
d = { d = {
HistoryColumns.STATUS: HistoryColumns.STATUS:
# height breaks ties for unverified txns # respect sort order of self.transactions (wallet.get_full_history)
# txpos breaks ties for verified same block txns -index.row(),
(-timestamp, conf, -status, -height, -txpos) if not is_lightning else (-timestamp, 0,0,0,-txpos),
HistoryColumns.DESCRIPTION: HistoryColumns.DESCRIPTION:
tx_item['label'] if 'label' in tx_item else None, tx_item['label'] if 'label' in tx_item else None,
HistoryColumns.AMOUNT: HistoryColumns.AMOUNT:

23
electrum/wallet.py

@ -578,13 +578,16 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
return balance return balance
def get_onchain_history(self, *, domain=None): def get_onchain_history(self, *, domain=None):
monotonic_timestamp = 0
for hist_item in self.get_history(domain=domain): for hist_item in self.get_history(domain=domain):
monotonic_timestamp = max(monotonic_timestamp, (hist_item.tx_mined_status.timestamp or float('inf')))
yield { yield {
'txid': hist_item.txid, 'txid': hist_item.txid,
'fee_sat': hist_item.fee, 'fee_sat': hist_item.fee,
'height': hist_item.tx_mined_status.height, 'height': hist_item.tx_mined_status.height,
'confirmations': hist_item.tx_mined_status.conf, 'confirmations': hist_item.tx_mined_status.conf,
'timestamp': hist_item.tx_mined_status.timestamp, 'timestamp': hist_item.tx_mined_status.timestamp,
'monotonic_timestamp': monotonic_timestamp,
'incoming': True if hist_item.delta>0 else False, 'incoming': True if hist_item.delta>0 else False,
'bc_value': Satoshis(hist_item.delta), 'bc_value': Satoshis(hist_item.delta),
'bc_balance': Satoshis(hist_item.balance), 'bc_balance': Satoshis(hist_item.balance),
@ -724,29 +727,35 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
@profiler @profiler
def get_full_history(self, fx=None, *, onchain_domain=None, include_lightning=True): 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) onchain_history = self.get_onchain_history(domain=onchain_domain)
for tx_item in onchain_history: for tx_item in onchain_history:
txid = tx_item['txid'] txid = tx_item['txid']
transactions[txid] = tx_item transactions_tmp[txid] = tx_item
# add LN txns
if self.lnworker and include_lightning: if self.lnworker and include_lightning:
lightning_history = self.lnworker.get_history() lightning_history = self.lnworker.get_history()
else: else:
lightning_history = [] lightning_history = []
for i, tx_item in enumerate(lightning_history): for i, tx_item in enumerate(lightning_history):
txid = tx_item.get('txid') txid = tx_item.get('txid')
ln_value = Decimal(tx_item['amount_msat']) / 1000 ln_value = Decimal(tx_item['amount_msat']) / 1000
if txid and txid in transactions: if txid and txid in transactions_tmp:
item = transactions[txid] item = transactions_tmp[txid]
item['label'] = tx_item['label'] item['label'] = tx_item['label']
item['ln_value'] = Satoshis(ln_value) item['ln_value'] = Satoshis(ln_value)
else: else:
tx_item['lightning'] = True tx_item['lightning'] = True
tx_item['ln_value'] = Satoshis(ln_value) tx_item['ln_value'] = Satoshis(ln_value)
tx_item['txpos'] = i # for sorting
key = tx_item.get('txid') or tx_item['payment_hash'] 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() now = time.time()
balance = 0 balance = 0
for item in transactions.values(): for item in transactions.values():

Loading…
Cancel
Save