utxo details: show list of parents as a tree
This commit is contained in:
@@ -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."),
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user