Browse Source

wallet.remove_transaction: also rm dependent/child txs

Main motivation is that I often use wallet.remove_transaction
from the Qt console, and would find this behaviour more intuitive.
Note that previously if one were to call this on a tx with children,
the crash reporter would appear with "wallet.get_history() failed balance sanity-check".

related: https://github.com/spesmilo/electrum/issues/6960#issuecomment-764716533
patch-4
SomberNight 4 years ago
parent
commit
c4e9afa019
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 19
      electrum/address_synchronizer.py
  2. 5
      electrum/commands.py
  3. 10
      electrum/gui/kivy/uix/dialogs/tx_dialog.py
  4. 10
      electrum/gui/qt/history_list.py

19
electrum/address_synchronizer.py

@ -292,11 +292,7 @@ class AddressSynchronizer(Logger):
# this is a local tx that conflicts with non-local txns; drop.
return False
# keep this txn and remove all conflicting
to_remove = set()
to_remove |= conflicting_txns
for conflicting_tx_hash in conflicting_txns:
to_remove |= self.get_depending_transactions(conflicting_tx_hash)
for tx_hash2 in to_remove:
for tx_hash2 in conflicting_txns:
self.remove_transaction(tx_hash2)
# add inputs
def add_value_from_prev_output():
@ -342,6 +338,19 @@ class AddressSynchronizer(Logger):
return True
def remove_transaction(self, tx_hash: str) -> None:
"""Removes a transaction AND all its dependents/children
from the wallet history.
"""
with self.lock, self.transaction_lock:
to_remove = {tx_hash}
to_remove |= self.get_depending_transactions(tx_hash)
for txid in to_remove:
self._remove_transaction(txid)
def _remove_transaction(self, tx_hash: str) -> None:
"""Removes a single transaction from the wallet history, and attempts
to undo all effects of the tx (spending inputs, creating outputs, etc).
"""
def remove_from_spent_outpoints():
# undo spends in spent_outpoints
if tx is not None:

5
electrum/commands.py

@ -933,13 +933,10 @@ class Commands:
if not is_hash256_str(txid):
raise Exception(f"{repr(txid)} is not a txid")
height = wallet.get_tx_height(txid).height
to_delete = {txid}
if height != TX_HEIGHT_LOCAL:
raise Exception(f'Only local transactions can be removed. '
f'This tx has height: {height} != {TX_HEIGHT_LOCAL}')
to_delete |= wallet.get_depending_transactions(txid)
for tx_hash in to_delete:
wallet.remove_transaction(tx_hash)
wallet.remove_transaction(txid)
wallet.save_db()
@command('wn')

10
electrum/gui/kivy/uix/dialogs/tx_dialog.py

@ -348,17 +348,15 @@ class TxDialog(Factory.Popup):
def remove_local_tx(self):
txid = self.tx.txid()
to_delete = {txid}
to_delete |= self.wallet.get_depending_transactions(txid)
num_child_txs = len(self.wallet.get_depending_transactions(txid))
question = _("Are you sure you want to remove this transaction?")
if len(to_delete) > 1:
if num_child_txs > 0:
question = (_("Are you sure you want to remove this transaction and {} child transactions?")
.format(len(to_delete) - 1))
.format(num_child_txs))
def on_prompt(b):
if b:
for tx in to_delete:
self.wallet.remove_transaction(tx)
self.wallet.remove_transaction(txid)
self.wallet.save_db()
self.app._trigger_update_wallet() # FIXME private...
self.dismiss()

10
electrum/gui/qt/history_list.py

@ -710,17 +710,15 @@ class HistoryList(MyTreeView, AcceptFileDragDrop):
menu.exec_(self.viewport().mapToGlobal(position))
def remove_local_tx(self, tx_hash: str):
to_delete = {tx_hash}
to_delete |= self.wallet.get_depending_transactions(tx_hash)
num_child_txs = len(self.wallet.get_depending_transactions(tx_hash))
question = _("Are you sure you want to remove this transaction?")
if len(to_delete) > 1:
if num_child_txs > 0:
question = (_("Are you sure you want to remove this transaction and {} child transactions?")
.format(len(to_delete) - 1))
.format(num_child_txs))
if not self.parent.question(msg=question,
title=_("Please confirm")):
return
for tx in to_delete:
self.wallet.remove_transaction(tx)
self.wallet.remove_transaction(tx_hash)
self.wallet.save_db()
# need to update at least: history_list, utxo_list, address_list
self.parent.need_update.set()

Loading…
Cancel
Save