mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-09-01 09:45:18 +00:00
wallet/GUI: don't allow "removing" a LN force-close-tx from history
This commit is contained in:
parent
32acc2b10e
commit
7a574c3cbc
4 changed files with 15 additions and 12 deletions
|
@ -345,7 +345,7 @@ class AddressSynchronizer(Logger):
|
||||||
prevout = TxOutpoint(bfh(tx_hash), idx)
|
prevout = TxOutpoint(bfh(tx_hash), idx)
|
||||||
self.db.remove_prevout_by_scripthash(scripthash, prevout=prevout, value=txo.value)
|
self.db.remove_prevout_by_scripthash(scripthash, prevout=prevout, value=txo.value)
|
||||||
|
|
||||||
def get_depending_transactions(self, tx_hash):
|
def get_depending_transactions(self, tx_hash: str) -> Set[str]:
|
||||||
"""Returns all (grand-)children of tx_hash in this wallet."""
|
"""Returns all (grand-)children of tx_hash in this wallet."""
|
||||||
with self.transaction_lock:
|
with self.transaction_lock:
|
||||||
children = set()
|
children = set()
|
||||||
|
|
|
@ -186,7 +186,7 @@ class TxDialog(Factory.Popup):
|
||||||
for dict_entry in self.ids.output_list.data:
|
for dict_entry in self.ids.output_list.data:
|
||||||
dict_entry['color'], dict_entry['background_color'] = address_colors(self.wallet, dict_entry['address'])
|
dict_entry['color'], dict_entry['background_color'] = address_colors(self.wallet, dict_entry['address'])
|
||||||
|
|
||||||
self.is_local_tx = tx_mined_status.height == TX_HEIGHT_LOCAL
|
self.can_remove_tx = tx_details.can_remove
|
||||||
self.update_action_button()
|
self.update_action_button()
|
||||||
|
|
||||||
def update_action_button(self):
|
def update_action_button(self):
|
||||||
|
@ -195,7 +195,7 @@ class TxDialog(Factory.Popup):
|
||||||
ActionButtonOption(text=_('Sign'), func=lambda btn: self.do_sign(), enabled=self.can_sign),
|
ActionButtonOption(text=_('Sign'), func=lambda btn: self.do_sign(), enabled=self.can_sign),
|
||||||
ActionButtonOption(text=_('Broadcast'), func=lambda btn: self.do_broadcast(), enabled=self.can_broadcast),
|
ActionButtonOption(text=_('Broadcast'), func=lambda btn: self.do_broadcast(), enabled=self.can_broadcast),
|
||||||
ActionButtonOption(text=_('Bump fee'), func=lambda btn: self.do_rbf(), enabled=self.can_rbf),
|
ActionButtonOption(text=_('Bump fee'), func=lambda btn: self.do_rbf(), enabled=self.can_rbf),
|
||||||
ActionButtonOption(text=_('Remove'), func=lambda btn: self.remove_local_tx(), enabled=self.is_local_tx),
|
ActionButtonOption(text=_('Remove'), func=lambda btn: self.remove_local_tx(), enabled=self.can_remove_tx),
|
||||||
)
|
)
|
||||||
num_options = sum(map(lambda o: bool(o.enabled), options))
|
num_options = sum(map(lambda o: bool(o.enabled), options))
|
||||||
# if no options available, hide button
|
# if no options available, hide button
|
||||||
|
|
|
@ -632,12 +632,11 @@ class HistoryList(MyTreeView, AcceptFileDragDrop):
|
||||||
if not tx:
|
if not tx:
|
||||||
return
|
return
|
||||||
tx_URL = block_explorer_URL(self.config, 'tx', tx_hash)
|
tx_URL = block_explorer_URL(self.config, 'tx', tx_hash)
|
||||||
height = self.wallet.get_tx_height(tx_hash).height
|
tx_details = self.wallet.get_tx_info(tx)
|
||||||
is_relevant, is_mine, v, fee = self.wallet.get_wallet_delta(tx)
|
is_unconfirmed = tx_details.tx_mined_status.height <= 0
|
||||||
is_unconfirmed = height <= 0
|
|
||||||
invoice_keys = self.wallet._get_relevant_invoice_keys_for_tx(tx)
|
invoice_keys = self.wallet._get_relevant_invoice_keys_for_tx(tx)
|
||||||
menu = QMenu()
|
menu = QMenu()
|
||||||
if height in [TX_HEIGHT_FUTURE, TX_HEIGHT_LOCAL]:
|
if tx_details.can_remove:
|
||||||
menu.addAction(_("Remove"), lambda: self.remove_local_tx(tx_hash))
|
menu.addAction(_("Remove"), lambda: self.remove_local_tx(tx_hash))
|
||||||
menu.addAction(_("Copy Transaction ID"), lambda: self.place_text_on_clipboard(tx_hash, title="TXID"))
|
menu.addAction(_("Copy Transaction ID"), lambda: self.place_text_on_clipboard(tx_hash, title="TXID"))
|
||||||
self.add_copy_menu(menu, idx)
|
self.add_copy_menu(menu, idx)
|
||||||
|
@ -650,8 +649,7 @@ class HistoryList(MyTreeView, AcceptFileDragDrop):
|
||||||
menu.addAction(_("Details"), lambda: self.show_transaction(tx_item, tx))
|
menu.addAction(_("Details"), lambda: self.show_transaction(tx_item, tx))
|
||||||
if is_unconfirmed and tx:
|
if is_unconfirmed and tx:
|
||||||
# note: the current implementation of RBF *needs* the old tx fee
|
# note: the current implementation of RBF *needs* the old tx fee
|
||||||
rbf = is_mine and not tx.is_final() and fee is not None
|
if tx_details.can_bump and tx_details.fee is not None:
|
||||||
if rbf:
|
|
||||||
menu.addAction(_("Increase fee"), lambda: self.parent.bump_fee_dialog(tx))
|
menu.addAction(_("Increase fee"), lambda: self.parent.bump_fee_dialog(tx))
|
||||||
else:
|
else:
|
||||||
child_tx = self.wallet.cpfp(tx, 0)
|
child_tx = self.wallet.cpfp(tx, 0)
|
||||||
|
@ -663,9 +661,9 @@ class HistoryList(MyTreeView, AcceptFileDragDrop):
|
||||||
menu.addAction(_("View on block explorer"), lambda: webopen(tx_URL))
|
menu.addAction(_("View on block explorer"), lambda: webopen(tx_URL))
|
||||||
menu.exec_(self.viewport().mapToGlobal(position))
|
menu.exec_(self.viewport().mapToGlobal(position))
|
||||||
|
|
||||||
def remove_local_tx(self, delete_tx):
|
def remove_local_tx(self, tx_hash: str):
|
||||||
to_delete = {delete_tx}
|
to_delete = {tx_hash}
|
||||||
to_delete |= self.wallet.get_depending_transactions(delete_tx)
|
to_delete |= self.wallet.get_depending_transactions(tx_hash)
|
||||||
question = _("Are you sure you want to remove this transaction?")
|
question = _("Are you sure you want to remove this transaction?")
|
||||||
if len(to_delete) > 1:
|
if len(to_delete) > 1:
|
||||||
question = (_("Are you sure you want to remove this transaction and {} child transactions?")
|
question = (_("Are you sure you want to remove this transaction and {} child transactions?")
|
||||||
|
|
|
@ -210,6 +210,7 @@ class TxWalletDetails(NamedTuple):
|
||||||
fee: Optional[int]
|
fee: Optional[int]
|
||||||
tx_mined_status: TxMinedInfo
|
tx_mined_status: TxMinedInfo
|
||||||
mempool_depth_bytes: Optional[int]
|
mempool_depth_bytes: Optional[int]
|
||||||
|
can_remove: bool # whether user should be allowed to delete tx
|
||||||
|
|
||||||
|
|
||||||
class Abstract_Wallet(AddressSynchronizer, ABC):
|
class Abstract_Wallet(AddressSynchronizer, ABC):
|
||||||
|
@ -495,6 +496,9 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
|
||||||
and (tx_we_already_have_in_db is None or not tx_we_already_have_in_db.is_complete()))
|
and (tx_we_already_have_in_db is None or not tx_we_already_have_in_db.is_complete()))
|
||||||
label = ''
|
label = ''
|
||||||
tx_mined_status = self.get_tx_height(tx_hash)
|
tx_mined_status = self.get_tx_height(tx_hash)
|
||||||
|
# note: is_relevant check added to 'can_remove' as otherwise 'height' is unreliable (typically LOCAL).
|
||||||
|
# e.g. user should not be allowed to remove a lightning force-close-tx
|
||||||
|
can_remove = is_relevant and (tx_mined_status.height in [TX_HEIGHT_FUTURE, TX_HEIGHT_LOCAL])
|
||||||
if tx.is_complete():
|
if tx.is_complete():
|
||||||
if tx_we_already_have_in_db:
|
if tx_we_already_have_in_db:
|
||||||
label = self.get_label(tx_hash)
|
label = self.get_label(tx_hash)
|
||||||
|
@ -545,6 +549,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
|
||||||
fee=fee,
|
fee=fee,
|
||||||
tx_mined_status=tx_mined_status,
|
tx_mined_status=tx_mined_status,
|
||||||
mempool_depth_bytes=exp_n,
|
mempool_depth_bytes=exp_n,
|
||||||
|
can_remove=can_remove,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_spendable_coins(self, domain, *, nonlocal_only=False) -> Sequence[PartialTxInput]:
|
def get_spendable_coins(self, domain, *, nonlocal_only=False) -> Sequence[PartialTxInput]:
|
||||||
|
|
Loading…
Add table
Reference in a new issue