Browse Source

utxo details: show list of parents as a tree

master
ThomasV 3 years ago
parent
commit
33c7ecbaf8
  1. 45
      electrum/gui/qt/utxo_dialog.py
  2. 5
      electrum/wallet.py

45
electrum/gui/qt/utxo_dialog.py

@ -24,6 +24,7 @@
# SOFTWARE. # SOFTWARE.
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import copy
from PyQt5.QtCore import Qt, QUrl from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtGui import QTextCharFormat, QFont from PyQt5.QtGui import QTextCharFormat, QFont
@ -53,11 +54,8 @@ class UTXODialog(WindowModalDialog):
txid = self.utxo.prevout.txid.hex() txid = self.utxo.prevout.txid.hex()
parents = self.wallet.get_tx_parents(txid) parents = self.wallet.get_tx_parents(txid)
out = [] num_parents = len(parents)
for _txid, _list in sorted(parents.items()): parents_copy = copy.deepcopy(parents)
tx_height, tx_pos = self.wallet.adb.get_txpos(_txid)
label = self.wallet.get_label_for_txid(_txid) or "<no label>"
out.append((tx_height, tx_pos, _txid, label, _list))
self.parents_list = QTextBrowser() self.parents_list = QTextBrowser()
self.parents_list.setOpenLinks(False) # disable automatic link opening self.parents_list.setOpenLinks(False) # disable automatic link opening
@ -72,9 +70,27 @@ class UTXODialog(WindowModalDialog):
cursor = self.parents_list.textCursor() cursor = self.parents_list.textCursor()
ext = QTextCharFormat() ext = QTextCharFormat()
for tx_height, tx_pos, _txid, label, _list in reversed(sorted(out)): if num_parents < 200:
ASCII_EDGE = '└─'
ASCII_BRANCH = '├─'
ASCII_PIPE = '| '
ASCII_SPACE = ' '
else:
ASCII_EDGE = ''
ASCII_BRANCH = ''
ASCII_PIPE = '|'
ASCII_SPACE = ' '
def print_ascii_tree(_txid, prefix, is_last):
if _txid not in parents:
return
tx_height, tx_pos = self.wallet.adb.get_txpos(_txid)
key = "%dx%d"%(tx_height, tx_pos) if tx_pos >= 0 else _txid[0:8] key = "%dx%d"%(tx_height, tx_pos) if tx_pos >= 0 else _txid[0:8]
list_str = ','.join(filter(None, _list)) label = self.wallet.get_label_for_txid(_txid) or ""
if _txid not in parents_copy:
label = '[duplicate]'
c = '' if _txid == txid else (ASCII_EDGE if is_last else ASCII_BRANCH)
cursor.insertText(prefix + c, ext)
lnk = QTextCharFormat() lnk = QTextCharFormat()
lnk.setToolTip(_('Click to open, right-click for menu')) lnk.setToolTip(_('Click to open, right-click for menu'))
lnk.setAnchorHref(_txid) lnk.setAnchorHref(_txid)
@ -82,15 +98,20 @@ class UTXODialog(WindowModalDialog):
lnk.setAnchor(True) lnk.setAnchor(True)
lnk.setUnderlineStyle(QTextCharFormat.SingleUnderline) lnk.setUnderlineStyle(QTextCharFormat.SingleUnderline)
cursor.insertText(key, lnk) cursor.insertText(key, lnk)
cursor.insertText("\t", ext) cursor.insertText(" ", ext)
cursor.insertText("%-32s\t<- "%label[0:32], ext) cursor.insertText(label, ext)
cursor.insertText(list_str, ext)
cursor.insertBlock() cursor.insertBlock()
next_prefix = '' if txid == _txid else prefix + (ASCII_SPACE if is_last else ASCII_PIPE)
parents_list = parents_copy.pop(_txid, [])
for i, p in enumerate(parents_list):
is_last = i == len(parents_list) - 1
print_ascii_tree(p, next_prefix, is_last)
# recursively build the tree
print_ascii_tree(txid, '', False)
vbox = QVBoxLayout() vbox = QVBoxLayout()
vbox.addWidget(QLabel(_("Output point") + ": " + str(self.utxo.short_id))) vbox.addWidget(QLabel(_("Output point") + ": " + str(self.utxo.short_id)))
vbox.addWidget(QLabel(_("Amount") + ": " + self.main_window.format_amount_and_units(self.utxo.value_sats()))) vbox.addWidget(QLabel(_("Amount") + ": " + self.main_window.format_amount_and_units(self.utxo.value_sats())))
vbox.addWidget(QLabel(_("This UTXO has {} parent transactions in your wallet").format(len(parents)))) vbox.addWidget(QLabel(_("This UTXO has {} parent transactions in your wallet").format(num_parents)))
vbox.addWidget(self.parents_list) vbox.addWidget(self.parents_list)
msg = ' '.join([ msg = ' '.join([
_("Note: This analysis only shows parent transactions, and does not take address reuse into consideration."), _("Note: This analysis only shows parent transactions, and does not take address reuse into consideration."),

5
electrum/wallet.py

@ -864,8 +864,7 @@ class Abstract_Wallet(ABC, Logger, EventListener):
def get_tx_parents(self, txid) -> Dict: def get_tx_parents(self, txid) -> Dict:
""" """
recursively calls itself and returns a flat dict: recursively calls itself and returns a flat dict:
txid -> input_index -> prevout txid -> list of parent txids
note: this does not take into account address reuse
""" """
if not self.is_up_to_date(): if not self.is_up_to_date():
return {} return {}
@ -880,8 +879,8 @@ class Abstract_Wallet(ABC, Logger, EventListener):
parents = [] parents = []
tx = self.adb.get_transaction(txid) tx = self.adb.get_transaction(txid)
for i, txin in enumerate(tx.inputs()): for i, txin in enumerate(tx.inputs()):
parents.append(str(txin.short_id))
_txid = txin.prevout.txid.hex() _txid = txin.prevout.txid.hex()
parents.append(_txid)
if _txid in self._last_full_history.keys(): if _txid in self._last_full_history.keys():
result.update(self.get_tx_parents(_txid)) result.update(self.get_tx_parents(_txid))
result[txid] = parents result[txid] = parents

Loading…
Cancel
Save