commit c4e9afa019e74a46585ca9af3eef433f19f338b9
parent 4f3a28b87e244a158d6a038fdf791c480f583418
Author: SomberNight <somber.night@protonmail.com>
Date: Thu, 21 Jan 2021 18:05:48 +0100
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
Diffstat:
4 files changed, 23 insertions(+), 21 deletions(-)
diff --git a/electrum/address_synchronizer.py b/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:
diff --git a/electrum/commands.py b/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')
diff --git a/electrum/gui/kivy/uix/dialogs/tx_dialog.py b/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()
diff --git a/electrum/gui/qt/history_list.py b/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()