commit 7a080352f8864077875206658bb610113eded7e6
parent cfbd83c43230ad6b31e98120daff8336c3ac0b7a
Author: ThomasV <thomasv@electrum.org>
Date: Fri, 29 Nov 2019 18:24:08 +0100
Merge pull request #5809 from SomberNight/201911_invoice_paid_detection
wallet: better (outgoing) invoice "paid" detection
Diffstat:
8 files changed, 152 insertions(+), 66 deletions(-)
diff --git a/electrum/address_synchronizer.py b/electrum/address_synchronizer.py
@@ -26,7 +26,7 @@ import threading
import asyncio
import itertools
from collections import defaultdict
-from typing import TYPE_CHECKING, Dict, Optional, Set, Tuple, NamedTuple, Sequence
+from typing import TYPE_CHECKING, Dict, Optional, Set, Tuple, NamedTuple, Sequence, List
from . import bitcoin
from .bitcoin import COINBASE_MATURITY
@@ -207,7 +207,7 @@ class AddressSynchronizer(Logger):
conflicting_txns -= {tx_hash}
return conflicting_txns
- def add_transaction(self, tx: Transaction, allow_unrelated=False) -> bool:
+ def add_transaction(self, tx: Transaction, *, allow_unrelated=False) -> bool:
"""Returns whether the tx was successfully added to the wallet history."""
assert tx, tx
assert tx.is_complete()
@@ -283,6 +283,8 @@ class AddressSynchronizer(Logger):
for n, txo in enumerate(tx.outputs()):
v = txo.value
ser = tx_hash + ':%d'%n
+ scripthash = bitcoin.script_to_scripthash(txo.scriptpubkey.hex())
+ self.db.add_prevout_by_scripthash(scripthash, prevout=TxOutpoint.from_str(ser), value=v)
addr = self.get_txout_address(txo)
if addr and self.is_mine(addr):
self.db.add_txo_addr(tx_hash, addr, n, v, is_coinbase)
@@ -299,7 +301,7 @@ class AddressSynchronizer(Logger):
self.db.add_num_inputs_to_tx(tx_hash, len(tx.inputs()))
return True
- def remove_transaction(self, tx_hash):
+ def remove_transaction(self, tx_hash: str) -> None:
def remove_from_spent_outpoints():
# undo spends in spent_outpoints
if tx is not None:
@@ -317,7 +319,7 @@ class AddressSynchronizer(Logger):
if spending_txid == tx_hash:
self.db.remove_spent_outpoint(prevout_hash, prevout_n)
- with self.transaction_lock:
+ with self.lock, self.transaction_lock:
self.logger.info(f"removing tx from history {tx_hash}")
tx = self.db.remove_transaction(tx_hash)
remove_from_spent_outpoints()
@@ -327,6 +329,13 @@ class AddressSynchronizer(Logger):
self.db.remove_txi(tx_hash)
self.db.remove_txo(tx_hash)
self.db.remove_tx_fee(tx_hash)
+ self.db.remove_verified_tx(tx_hash)
+ self.unverified_tx.pop(tx_hash, None)
+ if tx:
+ for idx, txo in enumerate(tx.outputs()):
+ scripthash = bitcoin.script_to_scripthash(txo.scriptpubkey.hex())
+ prevout = TxOutpoint(bfh(tx_hash), idx)
+ self.db.remove_prevout_by_scripthash(scripthash, prevout=prevout, value=txo.value)
def get_depending_transactions(self, tx_hash):
"""Returns all (grand-)children of tx_hash in this wallet."""
@@ -338,7 +347,7 @@ class AddressSynchronizer(Logger):
children |= self.get_depending_transactions(other_hash)
return children
- def receive_tx_callback(self, tx_hash, tx, tx_height):
+ def receive_tx_callback(self, tx_hash: str, tx: Transaction, tx_height: int) -> None:
self.add_unverified_tx(tx_hash, tx_height)
self.add_transaction(tx, allow_unrelated=True)
diff --git a/electrum/gui/kivy/main_window.py b/electrum/gui/kivy/main_window.py
@@ -1028,18 +1028,12 @@ class ElectrumWindow(App):
status, msg = True, tx.txid()
Clock.schedule_once(lambda dt: on_complete(status, msg))
- def broadcast(self, tx, invoice=None):
+ def broadcast(self, tx):
def on_complete(ok, msg):
if ok:
self.show_info(_('Payment sent.'))
if self.send_screen:
self.send_screen.do_clear()
- if invoice:
- key = invoice['id']
- txid = tx.txid()
- self.wallet.set_label(txid, invoice['message'])
- self.wallet.set_paid(key, txid)
- self.update_tab('invoices')
else:
msg = msg or ''
self.show_error(msg)
diff --git a/electrum/gui/kivy/uix/screens.py b/electrum/gui/kivy/uix/screens.py
@@ -380,14 +380,14 @@ class SendScreen(CScreen):
if fee > feerate_warning * tx.estimated_size() / 1000:
msg.append(_('Warning') + ': ' + _("The fee for this transaction seems unusually high."))
msg.append(_("Enter your PIN code to proceed"))
- self.app.protected('\n'.join(msg), self.send_tx, (tx, invoice))
+ self.app.protected('\n'.join(msg), self.send_tx, (tx,))
- def send_tx(self, tx, invoice, password):
+ def send_tx(self, tx, password):
if self.app.wallet.has_password() and password is None:
return
def on_success(tx):
if tx.is_complete():
- self.app.broadcast(tx, invoice)
+ self.app.broadcast(tx)
else:
self.app.tx_dialog(tx)
def on_failure(error):
diff --git a/electrum/gui/qt/invoice_list.py b/electrum/gui/qt/invoice_list.py
@@ -96,7 +96,8 @@ class InvoiceList(MyTreeView):
_list = self.parent.wallet.get_invoices()
# filter out paid invoices unless we have the log
lnworker_logs = self.parent.wallet.lnworker.logs if self.parent.wallet.lnworker else {}
- _list = [x for x in _list if x and x.get('status') != PR_PAID or x.get('rhash') in lnworker_logs]
+ _list = [x for x in _list
+ if x and (x.get('status') != PR_PAID or x.get('rhash') in lnworker_logs)]
self.model().clear()
self.update_headers(self.__class__.headers)
for idx, item in enumerate(_list):
diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py
@@ -928,9 +928,9 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
d = address_dialog.AddressDialog(self, addr)
d.exec_()
- def show_transaction(self, tx, *, invoice=None, tx_desc=None):
+ def show_transaction(self, tx, *, tx_desc=None):
'''tx_desc is set only for txs created in the Send tab'''
- show_transaction(tx, parent=self, invoice=invoice, desc=tx_desc)
+ show_transaction(tx, parent=self, desc=tx_desc)
def create_receive_tab(self):
# A 4-column grid layout. All the stretch is in the last column.
@@ -1472,7 +1472,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
self.pay_lightning_invoice(invoice['invoice'], amount_sat=invoice['amount'])
elif invoice['type'] == PR_TYPE_ONCHAIN:
outputs = invoice['outputs']
- self.pay_onchain_dialog(self.get_coins(), outputs, invoice=invoice)
+ self.pay_onchain_dialog(self.get_coins(), outputs)
else:
raise Exception('unknown invoice type')
@@ -1492,7 +1492,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
def pay_onchain_dialog(self, inputs: Sequence[PartialTxInput],
outputs: List[PartialTxOutput], *,
- invoice=None, external_keypairs=None) -> None:
+ external_keypairs=None) -> None:
# trustedcoin requires this
if run_hook('abort_send', self):
return
@@ -1508,8 +1508,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
return
if self.config.get('advanced_preview'):
self.preview_tx_dialog(make_tx=make_tx,
- external_keypairs=external_keypairs,
- invoice=invoice)
+ external_keypairs=external_keypairs)
return
output_value = '!' if '!' in output_values else sum(output_values)
@@ -1524,27 +1523,26 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
if is_send:
def sign_done(success):
if success:
- self.broadcast_or_show(tx, invoice=invoice)
+ self.broadcast_or_show(tx)
self.sign_tx_with_password(tx, callback=sign_done, password=password,
external_keypairs=external_keypairs)
else:
self.preview_tx_dialog(make_tx=make_tx,
- external_keypairs=external_keypairs,
- invoice=invoice)
+ external_keypairs=external_keypairs)
- def preview_tx_dialog(self, *, make_tx, external_keypairs=None, invoice=None):
+ def preview_tx_dialog(self, *, make_tx, external_keypairs=None):
d = PreviewTxDialog(make_tx=make_tx, external_keypairs=external_keypairs,
- window=self, invoice=invoice)
+ window=self)
d.show()
- def broadcast_or_show(self, tx, *, invoice=None):
+ def broadcast_or_show(self, tx: Transaction):
if not self.network:
self.show_error(_("You can't broadcast a transaction without a live network connection."))
- self.show_transaction(tx, invoice=invoice)
+ self.show_transaction(tx)
elif not tx.is_complete():
- self.show_transaction(tx, invoice=invoice)
+ self.show_transaction(tx)
else:
- self.broadcast_transaction(tx, invoice=invoice)
+ self.broadcast_transaction(tx)
@protected
def sign_tx(self, tx, *, callback, external_keypairs, password):
@@ -1568,7 +1566,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
msg = _('Signing transaction...')
WaitingDialog(self, msg, task, on_success, on_failure)
- def broadcast_transaction(self, tx: Transaction, *, invoice=None, tx_desc=None):
+ def broadcast_transaction(self, tx: Transaction):
def broadcast_thread():
# non-GUI thread
@@ -1584,11 +1582,6 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
return False, repr(e)
# success
txid = tx.txid()
- if tx_desc:
- self.wallet.set_label(txid, tx_desc)
- if invoice:
- self.wallet.set_paid(invoice['id'], txid)
- self.wallet.set_label(txid, invoice['message'])
if pr:
self.payment_request = None
refund_address = self.wallet.get_receiving_address()
@@ -2709,7 +2702,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
scriptpubkey = bfh(bitcoin.address_to_script(addr))
outputs = [PartialTxOutput(scriptpubkey=scriptpubkey, value='!')]
self.warn_if_watching_only()
- self.pay_onchain_dialog(coins, outputs, invoice=None, external_keypairs=keypairs)
+ self.pay_onchain_dialog(coins, outputs, external_keypairs=keypairs)
def _do_import(self, title, header_layout, func):
text = text_dialog(self, title, header_layout, _('Import'), allow_multi=True)
diff --git a/electrum/gui/qt/transaction_dialog.py b/electrum/gui/qt/transaction_dialog.py
@@ -75,9 +75,9 @@ _logger = get_logger(__name__)
dialogs = [] # Otherwise python randomly garbage collects the dialogs...
-def show_transaction(tx: Transaction, *, parent: 'ElectrumWindow', invoice=None, desc=None, prompt_if_unsaved=False):
+def show_transaction(tx: Transaction, *, parent: 'ElectrumWindow', desc=None, prompt_if_unsaved=False):
try:
- d = TxDialog(tx, parent=parent, invoice=invoice, desc=desc, prompt_if_unsaved=prompt_if_unsaved)
+ d = TxDialog(tx, parent=parent, desc=desc, prompt_if_unsaved=prompt_if_unsaved)
except SerializationError as e:
_logger.exception('unable to deserialize the transaction')
parent.show_critical(_("Electrum was unable to deserialize the transaction:") + "\n" + str(e))
@@ -88,7 +88,7 @@ def show_transaction(tx: Transaction, *, parent: 'ElectrumWindow', invoice=None,
class BaseTxDialog(QDialog, MessageBoxMixin):
- def __init__(self, *, parent: 'ElectrumWindow', invoice, desc, prompt_if_unsaved, finalized: bool, external_keypairs=None):
+ def __init__(self, *, parent: 'ElectrumWindow', desc, prompt_if_unsaved, finalized: bool, external_keypairs=None):
'''Transactions in the wallet will show their description.
Pass desc to give a description for txs not yet in the wallet.
'''
@@ -103,7 +103,6 @@ class BaseTxDialog(QDialog, MessageBoxMixin):
self.prompt_if_unsaved = prompt_if_unsaved
self.saved = False
self.desc = desc
- self.invoice = invoice
self.setMinimumWidth(950)
self.set_title()
@@ -213,7 +212,7 @@ class BaseTxDialog(QDialog, MessageBoxMixin):
def do_broadcast(self):
self.main_window.push_top_level_window(self)
try:
- self.main_window.broadcast_transaction(self.tx, invoice=self.invoice, tx_desc=self.desc)
+ self.main_window.broadcast_transaction(self.tx)
finally:
self.main_window.pop_top_level_window(self)
self.saved = True
@@ -592,8 +591,8 @@ class TxDetailLabel(QLabel):
class TxDialog(BaseTxDialog):
- def __init__(self, tx: Transaction, *, parent: 'ElectrumWindow', invoice, desc, prompt_if_unsaved):
- BaseTxDialog.__init__(self, parent=parent, invoice=invoice, desc=desc, prompt_if_unsaved=prompt_if_unsaved, finalized=True)
+ def __init__(self, tx: Transaction, *, parent: 'ElectrumWindow', desc, prompt_if_unsaved):
+ BaseTxDialog.__init__(self, parent=parent, desc=desc, prompt_if_unsaved=prompt_if_unsaved, finalized=True)
self.set_tx(tx)
self.update()
@@ -601,9 +600,9 @@ class TxDialog(BaseTxDialog):
class PreviewTxDialog(BaseTxDialog, TxEditor):
- def __init__(self, *, make_tx, external_keypairs, window: 'ElectrumWindow', invoice):
+ def __init__(self, *, make_tx, external_keypairs, window: 'ElectrumWindow'):
TxEditor.__init__(self, window=window, make_tx=make_tx, is_sweep=bool(external_keypairs))
- BaseTxDialog.__init__(self, parent=window, invoice=invoice, desc='', prompt_if_unsaved=False,
+ BaseTxDialog.__init__(self, parent=window, desc='', prompt_if_unsaved=False,
finalized=False, external_keypairs=external_keypairs)
self.update_tx()
self.update()
diff --git a/electrum/json_db.py b/electrum/json_db.py
@@ -31,16 +31,16 @@ from collections import defaultdict
from typing import Dict, Optional, List, Tuple, Set, Iterable, NamedTuple, Sequence
from . import util, bitcoin
-from .util import profiler, WalletFileException, multisig_type, TxMinedInfo
+from .util import profiler, WalletFileException, multisig_type, TxMinedInfo, bfh
from .keystore import bip44_derivation
-from .transaction import Transaction
+from .transaction import Transaction, TxOutpoint
from .logging import Logger
# seed_version is now used for the version of the wallet file
OLD_SEED_VERSION = 4 # electrum versions < 2.0
NEW_SEED_VERSION = 11 # electrum versions >= 2.0
-FINAL_SEED_VERSION = 21 # electrum >= 2.7 will set this to prevent
+FINAL_SEED_VERSION = 22 # electrum >= 2.7 will set this to prevent
# old versions from overwriting new format
@@ -215,6 +215,7 @@ class JsonDB(Logger):
self._convert_version_19()
self._convert_version_20()
self._convert_version_21()
+ self._convert_version_22()
self.put('seed_version', FINAL_SEED_VERSION) # just to be sure
self._after_upgrade_tasks()
@@ -496,6 +497,24 @@ class JsonDB(Logger):
self.put('channels', channels)
self.put('seed_version', 21)
+ def _convert_version_22(self):
+ # construct prevouts_by_scripthash
+ if not self._is_upgrade_method_needed(21, 21):
+ return
+
+ from .bitcoin import script_to_scripthash
+ transactions = self.get('transactions', {}) # txid -> raw_tx
+ prevouts_by_scripthash = defaultdict(list)
+ for txid, raw_tx in transactions.items():
+ tx = Transaction(raw_tx)
+ for idx, txout in enumerate(tx.outputs()):
+ outpoint = f"{txid}:{idx}"
+ scripthash = script_to_scripthash(txout.scriptpubkey.hex())
+ prevouts_by_scripthash[scripthash].append((outpoint, txout.value))
+ self.put('prevouts_by_scripthash', prevouts_by_scripthash)
+
+ self.put('seed_version', 22)
+
def _convert_imported(self):
if not self._is_upgrade_method_needed(0, 13):
return
@@ -661,6 +680,25 @@ class JsonDB(Logger):
self.spent_outpoints[prevout_hash][prevout_n] = tx_hash
@modifier
+ def add_prevout_by_scripthash(self, scripthash: str, *, prevout: TxOutpoint, value: int) -> None:
+ assert isinstance(prevout, TxOutpoint)
+ if scripthash not in self._prevouts_by_scripthash:
+ self._prevouts_by_scripthash[scripthash] = set()
+ self._prevouts_by_scripthash[scripthash].add((prevout.to_str(), value))
+
+ @modifier
+ def remove_prevout_by_scripthash(self, scripthash: str, *, prevout: TxOutpoint, value: int) -> None:
+ assert isinstance(prevout, TxOutpoint)
+ self._prevouts_by_scripthash[scripthash].discard((prevout.to_str(), value))
+ if not self._prevouts_by_scripthash[scripthash]:
+ self._prevouts_by_scripthash.pop(scripthash)
+
+ @locked
+ def get_prevouts_by_scripthash(self, scripthash: str) -> Set[Tuple[TxOutpoint, int]]:
+ prevouts_and_values = self._prevouts_by_scripthash.get(scripthash, set())
+ return {(TxOutpoint.from_str(prevout), value) for prevout, value in prevouts_and_values}
+
+ @modifier
def add_transaction(self, tx_hash: str, tx: Transaction) -> None:
assert isinstance(tx, Transaction)
self.transactions[tx_hash] = tx
@@ -863,14 +901,19 @@ class JsonDB(Logger):
self.history = self.get_data_ref('addr_history') # address -> list of (txid, height)
self.verified_tx = self.get_data_ref('verified_tx3') # txid -> (height, timestamp, txpos, header_hash)
self.tx_fees = self.get_data_ref('tx_fees') # type: Dict[str, TxFeesValue]
+ # scripthash -> set of (outpoint, value)
+ self._prevouts_by_scripthash = self.get_data_ref('prevouts_by_scripthash') # type: Dict[str, Set[Tuple[str, int]]]
# convert raw hex transactions to Transaction objects
for tx_hash, raw_tx in self.transactions.items():
self.transactions[tx_hash] = Transaction(raw_tx)
- # convert list to set
+ # convert txi, txo: list to set
for t in self.txi, self.txo:
for d in t.values():
for addr, lst in d.items():
d[addr] = set([tuple(x) for x in lst])
+ # convert prevouts_by_scripthash: list to set, list to tuple
+ for scripthash, lst in self._prevouts_by_scripthash.items():
+ self._prevouts_by_scripthash[scripthash] = {(prevout, value) for prevout, value in lst}
# remove unreferenced tx
for tx_hash in list(self.transactions.keys()):
if not self.get_txi_addresses(tx_hash) and not self.get_txo_addresses(tx_hash):
diff --git a/electrum/wallet.py b/electrum/wallet.py
@@ -36,9 +36,10 @@ import errno
import traceback
import operator
from functools import partial
+from collections import defaultdict
from numbers import Number
from decimal import Decimal
-from typing import TYPE_CHECKING, List, Optional, Tuple, Union, NamedTuple, Sequence, Dict, Any
+from typing import TYPE_CHECKING, List, Optional, Tuple, Union, NamedTuple, Sequence, Dict, Any, Set
from .i18n import _
from .bip32 import BIP32Node
@@ -252,6 +253,7 @@ class Abstract_Wallet(AddressSynchronizer):
if invoice.get('type') == PR_TYPE_ONCHAIN:
outputs = [PartialTxOutput.from_legacy_tuple(*output) for output in invoice.get('outputs')]
invoice['outputs'] = outputs
+ self._prepare_onchain_invoice_paid_detection()
self.calc_unused_change_addresses()
# save wallet type the first time
if self.storage.get('wallet_type') is None:
@@ -614,7 +616,10 @@ class Abstract_Wallet(AddressSynchronizer):
elif invoice_type == PR_TYPE_ONCHAIN:
key = bh2u(sha256(repr(invoice))[0:16])
invoice['id'] = key
- invoice['txid'] = None
+ outputs = invoice['outputs'] # type: List[PartialTxOutput]
+ with self.transaction_lock:
+ for txout in outputs:
+ self._invoices_from_scriptpubkey_map[txout.scriptpubkey].add(key)
else:
raise Exception('Unsupported invoice type')
self.invoices[key] = invoice
@@ -632,27 +637,73 @@ class Abstract_Wallet(AddressSynchronizer):
out.sort(key=operator.itemgetter('time'))
return out
- def set_paid(self, key, txid):
- if key not in self.invoices:
- return
- invoice = self.invoices[key]
- assert invoice.get('type') == PR_TYPE_ONCHAIN
- invoice['txid'] = txid
- self.storage.put('invoices', self.invoices)
-
def get_invoice(self, key):
if key not in self.invoices:
return
item = copy.copy(self.invoices[key])
request_type = item.get('type')
if request_type == PR_TYPE_ONCHAIN:
- item['status'] = PR_PAID if item.get('txid') is not None else PR_UNPAID
+ item['status'] = PR_PAID if self._is_onchain_invoice_paid(item)[0] else PR_UNPAID
elif self.lnworker and request_type == PR_TYPE_LN:
item['status'] = self.lnworker.get_payment_status(bfh(item['rhash']))
else:
return
return item
+ def _get_relevant_invoice_keys_for_tx(self, tx: Transaction) -> Set[str]:
+ relevant_invoice_keys = set()
+ for txout in tx.outputs():
+ for invoice_key in self._invoices_from_scriptpubkey_map.get(txout.scriptpubkey, set()):
+ relevant_invoice_keys.add(invoice_key)
+ return relevant_invoice_keys
+
+ def _prepare_onchain_invoice_paid_detection(self):
+ # scriptpubkey -> list(invoice_keys)
+ self._invoices_from_scriptpubkey_map = defaultdict(set) # type: Dict[bytes, Set[str]]
+ for invoice_key, invoice in self.invoices.items():
+ if invoice.get('type') == PR_TYPE_ONCHAIN:
+ outputs = invoice['outputs'] # type: List[PartialTxOutput]
+ for txout in outputs:
+ self._invoices_from_scriptpubkey_map[txout.scriptpubkey].add(invoice_key)
+
+ def _is_onchain_invoice_paid(self, invoice) -> Tuple[bool, Sequence[str]]:
+ """Returns whether on-chain invoice is satisfied, and list of relevant TXIDs."""
+ assert invoice.get('type') == PR_TYPE_ONCHAIN
+ invoice_amounts = defaultdict(int) # type: Dict[bytes, int] # scriptpubkey -> value_sats
+ for txo in invoice['outputs']: # type: PartialTxOutput
+ invoice_amounts[txo.scriptpubkey] += 1 if txo.value == '!' else txo.value
+ relevant_txs = []
+ with self.transaction_lock:
+ for invoice_scriptpubkey, invoice_amt in invoice_amounts.items():
+ scripthash = bitcoin.script_to_scripthash(invoice_scriptpubkey.hex())
+ prevouts_and_values = self.db.get_prevouts_by_scripthash(scripthash)
+ relevant_txs += [prevout.txid.hex() for prevout, v in prevouts_and_values]
+ total_received = sum([v for prevout, v in prevouts_and_values])
+ if total_received < invoice_amt:
+ return False, []
+ return True, relevant_txs
+
+ def _maybe_set_tx_label_based_on_invoices(self, tx: Transaction) -> bool:
+ tx_hash = tx.txid()
+ with self.transaction_lock:
+ labels = []
+ for invoice_key in self._get_relevant_invoice_keys_for_tx(tx):
+ invoice = self.invoices.get(invoice_key)
+ if invoice is None: continue
+ assert invoice.get('type') == PR_TYPE_ONCHAIN
+ if invoice['message']:
+ labels.append(invoice['message'])
+ if labels:
+ self.set_label(tx_hash, "; ".join(labels))
+ return bool(labels)
+
+ def add_transaction(self, tx, *, allow_unrelated=False):
+ tx_was_added = super().add_transaction(tx, allow_unrelated=allow_unrelated)
+
+ if tx_was_added:
+ self._maybe_set_tx_label_based_on_invoices(tx)
+ return tx_was_added
+
@profiler
def get_full_history(self, fx=None, *, onchain_domain=None, include_lightning=True):
transactions = OrderedDictWithIndex()
@@ -1877,10 +1928,6 @@ class Imported_Wallet(Simple_Wallet):
self.db.remove_addr_history(address)
for tx_hash in transactions_to_remove:
self.remove_transaction(tx_hash)
- self.db.remove_tx_fee(tx_hash)
- self.db.remove_verified_tx(tx_hash)
- self.unverified_tx.pop(tx_hash, None)
- self.db.remove_transaction(tx_hash)
self.set_label(address, None)
self.remove_payment_request(address)
self.set_frozen_state_of_addresses([address], False)