tMerge pull request #4222 from SomberNight/wallet_get_address_history_speedup - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit ed0cbf11cda8243f17d9206fb43a12c46c26c5c4 DIR parent 76dfc2d3b864e912797b9386c6b5ae6e9a327363 HTML Author: ThomasV <thomasv@electrum.org> Date: Wed, 4 Apr 2018 15:22:35 +0200 Merge pull request #4222 from SomberNight/wallet_get_address_history_speedup wallet: speed up get_address_history Diffstat: M lib/wallet.py | 49 ++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 10 deletions(-) --- DIR diff --git a/lib/wallet.py b/lib/wallet.py t@@ -39,6 +39,7 @@ from functools import partial from collections import defaultdict from numbers import Number from decimal import Decimal +import itertools import sys t@@ -188,7 +189,12 @@ class Abstract_Wallet(PrintError): self.synchronizer = None self.verifier = None - self.gap_limit_for_change = 6 # constant + self.gap_limit_for_change = 6 # constant + + # locks: if you need to take multiple ones, acquire them in the order they are defined here! + self.lock = threading.RLock() + self.transaction_lock = threading.RLock() + # saved fields self.use_change = storage.get('use_change', True) self.multiple_change = storage.get('multiple_change', False) t@@ -219,10 +225,6 @@ class Abstract_Wallet(PrintError): # wallet.up_to_date is true when the wallet is synchronized (stronger requirement) self.up_to_date = False - # locks: if you need to take multiple ones, acquire them in the order they are defined here! - self.lock = threading.RLock() - self.transaction_lock = threading.RLock() - self.check_history() # save wallet type the first time t@@ -253,6 +255,7 @@ class Abstract_Wallet(PrintError): self.pruned_txo = self.storage.get('pruned_txo', {}) tx_list = self.storage.get('transactions', {}) self.transactions = {} + self._history_local = {} # address -> set(txid) for tx_hash, raw in tx_list.items(): tx = Transaction(raw) self.transactions[tx_hash] = tx t@@ -260,6 +263,8 @@ class Abstract_Wallet(PrintError): and (tx_hash not in self.pruned_txo.values()): self.print_error("removing unreferenced tx", tx_hash) self.transactions.pop(tx_hash) + else: + self._add_tx_to_local_history(tx_hash) @profiler def save_transactions(self, write=False): t@@ -669,8 +674,9 @@ class Abstract_Wallet(PrintError): def get_addr_balance(self, address): received, sent = self.get_addr_io(address) c = u = x = 0 + local_height = self.get_local_height() for txo, (tx_height, v, is_cb) in received.items(): - if is_cb and tx_height + COINBASE_MATURITY > self.get_local_height(): + if is_cb and tx_height + COINBASE_MATURITY > local_height: x += v elif tx_height > 0: c += v t@@ -732,12 +738,30 @@ class Abstract_Wallet(PrintError): # we need self.transaction_lock but get_tx_height will take self.lock # so we need to take that too here, to enforce order of locks with self.lock, self.transaction_lock: - for tx_hash in self.transactions: - if addr in self.txi.get(tx_hash, []) or addr in self.txo.get(tx_hash, []): - tx_height = self.get_tx_height(tx_hash)[0] - h.append((tx_hash, tx_height)) + related_txns = self._history_local.get(addr, set()) + for tx_hash in related_txns: + tx_height = self.get_tx_height(tx_hash)[0] + h.append((tx_hash, tx_height)) return h + def _add_tx_to_local_history(self, txid): + with self.transaction_lock: + for addr in itertools.chain(self.txi.get(txid, []), self.txo.get(txid, [])): + cur_hist = self._history_local.get(addr, set()) + cur_hist.add(txid) + self._history_local[addr] = cur_hist + + def _remove_tx_from_local_history(self, txid): + with self.transaction_lock: + for addr in itertools.chain(self.txi.get(txid, []), self.txo.get(txid, [])): + cur_hist = self._history_local.get(addr, set()) + try: + cur_hist.remove(txid) + except KeyError: + pass + else: + self._history_local[addr] = cur_hist + def get_txin_address(self, txi): addr = txi.get('address') if addr != "(pubkey)": t@@ -876,6 +900,9 @@ class Abstract_Wallet(PrintError): if dd.get(addr) is None: dd[addr] = [] dd[addr].append((ser, v)) + self._add_tx_to_local_history(next_tx) + # add to local history + self._add_tx_to_local_history(tx_hash) # save self.transactions[tx_hash] = tx return True t@@ -895,6 +922,8 @@ class Abstract_Wallet(PrintError): self.spent_outpoints.pop(ser, None) self.pruned_txo.pop(ser) + self._remove_tx_from_local_history(tx_hash) + # add tx to pruned_txo, and undo the txi addition for next_tx, dd in self.txi.items(): for addr, l in list(dd.items()):