From c47057b48410dc8618fb1df4bba67cf54ced22d5 Mon Sep 17 00:00:00 2001 From: ThomasV Date: Fri, 3 Jun 2022 12:52:42 +0200 Subject: [PATCH] Move get_wallet_delta to wallet class, because it requires wallet.is_mine Do not call it in AddressSynchronizer.get_tx_fee --- electrum/address_synchronizer.py | 66 +++++++++----------------------- electrum/wallet.py | 48 ++++++++++++++++++++++- 2 files changed, 66 insertions(+), 48 deletions(-) diff --git a/electrum/address_synchronizer.py b/electrum/address_synchronizer.py index 4342d20ec..657ad0bac 100644 --- a/electrum/address_synchronizer.py +++ b/electrum/address_synchronizer.py @@ -57,14 +57,6 @@ class HistoryItem(NamedTuple): balance: int -class TxWalletDelta(NamedTuple): - is_relevant: bool # "related to wallet?" - is_any_input_ismine: bool - is_all_input_ismine: bool - delta: int - fee: Optional[int] - - class AddressSynchronizer(Logger): """ address database """ @@ -110,6 +102,9 @@ class AddressSynchronizer(Logger): self.remove_local_transactions_we_dont_have() def is_mine(self, address: Optional[str]) -> bool: + """Returns whether an address is in our set + Note: This class has a larget set of addresses than the wallet + """ if not address: return False return self.db.is_addr_in_history(address) @@ -719,44 +714,6 @@ class AddressSynchronizer(Logger): delta += v return delta - def get_wallet_delta(self, tx: Transaction) -> TxWalletDelta: - """effect of tx on wallet""" - is_relevant = False # "related to wallet?" - num_input_ismine = 0 - v_in = v_in_mine = v_out = v_out_mine = 0 - with self.lock, self.transaction_lock: - for txin in tx.inputs(): - addr = self.get_txin_address(txin) - value = self.get_txin_value(txin, address=addr) - if self.is_mine(addr): - num_input_ismine += 1 - is_relevant = True - assert value is not None - v_in_mine += value - if value is None: - v_in = None - elif v_in is not None: - v_in += value - for txout in tx.outputs(): - v_out += txout.value - if self.is_mine(txout.address): - v_out_mine += txout.value - is_relevant = True - delta = v_out_mine - v_in_mine - if v_in is not None: - fee = v_in - v_out - else: - fee = None - if fee is None and isinstance(tx, PartialTransaction): - fee = tx.get_fee() - return TxWalletDelta( - is_relevant=is_relevant, - is_any_input_ismine=num_input_ismine > 0, - is_all_input_ismine=num_input_ismine == len(tx.inputs()), - delta=delta, - fee=fee, - ) - def get_tx_fee(self, txid: str) -> Optional[int]: """ Returns tx_fee or None. Use server fee only if tx is unconfirmed and not mine""" # check if stored fee is available @@ -782,7 +739,22 @@ class AddressSynchronizer(Logger): tx = self.db.get_transaction(txid) if not tx: return None - fee = self.get_wallet_delta(tx).fee + # compute fee if possible + v_in = v_out = 0 + with self.lock, self.transaction_lock: + for txin in tx.inputs(): + addr = self.get_txin_address(txin) + value = self.get_txin_value(txin, address=addr) + if value is None: + v_in = None + elif v_in is not None: + v_in += value + for txout in tx.outputs(): + v_out += txout.value + if v_in is not None: + fee = v_in - v_out + else: + fee = None # save result self.db.add_tx_fee_we_calculated(txid, fee) self.db.add_num_inputs_to_tx(txid, len(tx.inputs())) diff --git a/electrum/wallet.py b/electrum/wallet.py index ce24e842a..5d006c94c 100644 --- a/electrum/wallet.py +++ b/electrum/wallet.py @@ -243,6 +243,12 @@ class InternalAddressCorruption(Exception): return _("Wallet file corruption detected. " "Please restore your wallet from seed, and compare the addresses in both files") +class TxWalletDelta(NamedTuple): + is_relevant: bool # "related to wallet?" + is_any_input_ismine: bool + is_all_input_ismine: bool + delta: int + fee: Optional[int] class TxWalletDetails(NamedTuple): txid: Optional[str] @@ -655,8 +661,48 @@ class Abstract_Wallet(ABC): def is_swap_tx(self, tx: Transaction) -> bool: return bool(self.lnworker.swap_manager.get_swap_by_tx(tx)) if self.lnworker else False + def get_wallet_delta(self, tx: Transaction) -> TxWalletDelta: + """Return the effect a transaction has on the wallet. + This method must use self.is_mine, not self.adb.is_mine() + """ + is_relevant = False # "related to wallet?" + num_input_ismine = 0 + v_in = v_in_mine = v_out = v_out_mine = 0 + with self.lock, self.transaction_lock: + for txin in tx.inputs(): + addr = self.adb.get_txin_address(txin) + value = self.adb.get_txin_value(txin, address=addr) + if self.is_mine(addr): + num_input_ismine += 1 + is_relevant = True + assert value is not None + v_in_mine += value + if value is None: + v_in = None + elif v_in is not None: + v_in += value + for txout in tx.outputs(): + v_out += txout.value + if self.is_mine(txout.address): + v_out_mine += txout.value + is_relevant = True + delta = v_out_mine - v_in_mine + if v_in is not None: + fee = v_in - v_out + else: + fee = None + if fee is None and isinstance(tx, PartialTransaction): + fee = tx.get_fee() + return TxWalletDelta( + is_relevant=is_relevant, + is_any_input_ismine=num_input_ismine > 0, + is_all_input_ismine=num_input_ismine == len(tx.inputs()), + delta=delta, + fee=fee, + ) + def get_tx_info(self, tx: Transaction) -> TxWalletDetails: - tx_wallet_delta = self.adb.get_wallet_delta(tx) + tx_wallet_delta = self.get_wallet_delta(tx) is_relevant = tx_wallet_delta.is_relevant is_any_input_ismine = tx_wallet_delta.is_any_input_ismine is_swap = self.is_swap_tx(tx)