Browse Source

Merge pull request #4222 from SomberNight/wallet_get_address_history_speedup

wallet: speed up get_address_history
3.2.x
ThomasV 7 years ago
committed by GitHub
parent
commit
ed0cbf11cd
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 49
      lib/wallet.py

49
lib/wallet.py

@ -39,6 +39,7 @@ from functools import partial
from collections import defaultdict from collections import defaultdict
from numbers import Number from numbers import Number
from decimal import Decimal from decimal import Decimal
import itertools
import sys import sys
@ -188,7 +189,12 @@ class Abstract_Wallet(PrintError):
self.synchronizer = None self.synchronizer = None
self.verifier = 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 # saved fields
self.use_change = storage.get('use_change', True) self.use_change = storage.get('use_change', True)
self.multiple_change = storage.get('multiple_change', False) self.multiple_change = storage.get('multiple_change', False)
@ -219,10 +225,6 @@ class Abstract_Wallet(PrintError):
# wallet.up_to_date is true when the wallet is synchronized (stronger requirement) # wallet.up_to_date is true when the wallet is synchronized (stronger requirement)
self.up_to_date = False 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() self.check_history()
# save wallet type the first time # save wallet type the first time
@ -253,6 +255,7 @@ class Abstract_Wallet(PrintError):
self.pruned_txo = self.storage.get('pruned_txo', {}) self.pruned_txo = self.storage.get('pruned_txo', {})
tx_list = self.storage.get('transactions', {}) tx_list = self.storage.get('transactions', {})
self.transactions = {} self.transactions = {}
self._history_local = {} # address -> set(txid)
for tx_hash, raw in tx_list.items(): for tx_hash, raw in tx_list.items():
tx = Transaction(raw) tx = Transaction(raw)
self.transactions[tx_hash] = tx self.transactions[tx_hash] = tx
@ -260,6 +263,8 @@ class Abstract_Wallet(PrintError):
and (tx_hash not in self.pruned_txo.values()): and (tx_hash not in self.pruned_txo.values()):
self.print_error("removing unreferenced tx", tx_hash) self.print_error("removing unreferenced tx", tx_hash)
self.transactions.pop(tx_hash) self.transactions.pop(tx_hash)
else:
self._add_tx_to_local_history(tx_hash)
@profiler @profiler
def save_transactions(self, write=False): def save_transactions(self, write=False):
@ -669,8 +674,9 @@ class Abstract_Wallet(PrintError):
def get_addr_balance(self, address): def get_addr_balance(self, address):
received, sent = self.get_addr_io(address) received, sent = self.get_addr_io(address)
c = u = x = 0 c = u = x = 0
local_height = self.get_local_height()
for txo, (tx_height, v, is_cb) in received.items(): 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 x += v
elif tx_height > 0: elif tx_height > 0:
c += v c += v
@ -732,12 +738,30 @@ class Abstract_Wallet(PrintError):
# we need self.transaction_lock but get_tx_height will take self.lock # 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 # so we need to take that too here, to enforce order of locks
with self.lock, self.transaction_lock: with self.lock, self.transaction_lock:
for tx_hash in self.transactions: related_txns = self._history_local.get(addr, set())
if addr in self.txi.get(tx_hash, []) or addr in self.txo.get(tx_hash, []): for tx_hash in related_txns:
tx_height = self.get_tx_height(tx_hash)[0] tx_height = self.get_tx_height(tx_hash)[0]
h.append((tx_hash, tx_height)) h.append((tx_hash, tx_height))
return h 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): def get_txin_address(self, txi):
addr = txi.get('address') addr = txi.get('address')
if addr != "(pubkey)": if addr != "(pubkey)":
@ -876,6 +900,9 @@ class Abstract_Wallet(PrintError):
if dd.get(addr) is None: if dd.get(addr) is None:
dd[addr] = [] dd[addr] = []
dd[addr].append((ser, v)) 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 # save
self.transactions[tx_hash] = tx self.transactions[tx_hash] = tx
return True return True
@ -895,6 +922,8 @@ class Abstract_Wallet(PrintError):
self.spent_outpoints.pop(ser, None) self.spent_outpoints.pop(ser, None)
self.pruned_txo.pop(ser) self.pruned_txo.pop(ser)
self._remove_tx_from_local_history(tx_hash)
# add tx to pruned_txo, and undo the txi addition # add tx to pruned_txo, and undo the txi addition
for next_tx, dd in self.txi.items(): for next_tx, dd in self.txi.items():
for addr, l in list(dd.items()): for addr, l in list(dd.items()):

Loading…
Cancel
Save