URI: 
       tjson_db: make get operations threadsafe - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 1e519f2dd0255862a6db0e55e0485e1668dfa257
   DIR parent 3631c27ed7a23c91f5bbab95f0a5ab90b520f26f
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Thu, 28 Feb 2019 15:47:42 +0100
       
       json_db: make get operations threadsafe
       
       Diffstat:
         M electrum/address_synchronizer.py    |       8 ++++----
         M electrum/json_db.py                 |      48 +++++++++++++++++++++++--------
       
       2 files changed, 40 insertions(+), 16 deletions(-)
       ---
   DIR diff --git a/electrum/address_synchronizer.py b/electrum/address_synchronizer.py
       t@@ -292,7 +292,7 @@ class AddressSynchronizer(PrintError):
                            self.db.remove_spent_outpoint(prevout_hash, prevout_n)
                    else:
                        # expensive but always works
       -                for prevout_hash, prevout_n in list(self.db.list_spent_outpoints()):
       +                for prevout_hash, prevout_n in self.db.list_spent_outpoints():
                            spending_txid = self.db.get_spent_outpoint(prevout_hash, prevout_n)
                            if spending_txid == tx_hash:
                                self.db.remove_spent_outpoint(prevout_hash, prevout_n)
       t@@ -348,7 +348,7 @@ class AddressSynchronizer(PrintError):
            def load_local_history(self):
                self._history_local = {}  # address -> set(txid)
                self._address_history_changed_events = defaultdict(asyncio.Event)  # address -> Event
       -        for txid in itertools.chain(self.db.get_txi_keys(), self.db.get_txo_keys()):
       +        for txid in itertools.chain(self.db.list_txi(), self.db.list_txo()):
                    self._add_tx_to_local_history(txid)
        
            @profiler
       t@@ -372,7 +372,7 @@ class AddressSynchronizer(PrintError):
                    self.storage.write()
        
            def remove_local_transactions_we_dont_have(self):
       -        for txid in itertools.chain(list(self.db.get_txi_keys()), list(self.db.get_txo_keys())):
       +        for txid in itertools.chain(self.db.list_txi(), self.db.list_txo()):
                    tx_height = self.get_tx_height(txid).height
                    if tx_height == TX_HEIGHT_LOCAL and txid not in self.db.list_transactions():
                        self.remove_transaction(txid)
       t@@ -519,7 +519,7 @@ class AddressSynchronizer(PrintError):
                '''Used by the verifier when a reorg has happened'''
                txs = set()
                with self.lock:
       -            for tx_hash in list(self.db.list_verified_tx()):
       +            for tx_hash in self.db.list_verified_tx():
                        info = self.db.get_verified_tx(tx_hash)
                        tx_height = info.height
                        if tx_height >= height:
   DIR diff --git a/electrum/json_db.py b/electrum/json_db.py
       t@@ -70,6 +70,13 @@ class JsonDB(PrintError):
                        return func(self, *args, **kwargs)
                return wrapper
        
       +    def locked(func):
       +        def wrapper(self, *args, **kwargs):
       +            with self.lock:
       +                return func(self, *args, **kwargs)
       +        return wrapper
       +
       +    @locked
            def get(self, key, default=None):
                v = self.data.get(key)
                if v is None:
       t@@ -443,7 +450,6 @@ class JsonDB(PrintError):
            def convert_account(self):
                if not self._is_upgrade_method_needed(0, 13):
                    return
       -
                self.put('accounts', None)
        
            def _is_upgrade_method_needed(self, min_version, max_version):
       t@@ -457,6 +463,7 @@ class JsonDB(PrintError):
                else:
                    return True
        
       +    @locked
            def get_seed_version(self):
                seed_version = self.get('seed_version')
                if not seed_version:
       t@@ -488,16 +495,19 @@ class JsonDB(PrintError):
                        msg += "\nPlease open this file with Electrum 1.9.8, and move your coins to a new wallet."
                raise WalletFileException(msg)
        
       -
       +    @locked
            def get_txi(self, tx_hash):
       -        return self.txi.get(tx_hash, {}).keys()
       +        return list(self.txi.get(tx_hash, {}).keys())
        
       +    @locked
            def get_txo(self, tx_hash):
       -        return self.txo.get(tx_hash, {}).keys()
       +        return list(self.txo.get(tx_hash, {}).keys())
        
       +    @locked
            def get_txi_addr(self, tx_hash, address):
                return self.txi.get(tx_hash, {}).get(address, [])
        
       +    @locked
            def get_txo_addr(self, tx_hash, address):
                return self.txo.get(tx_hash, {}).get(address, [])
        
       t@@ -521,11 +531,13 @@ class JsonDB(PrintError):
                    d[addr] = set()
                d[addr].add((n, v, is_coinbase))
        
       -    def get_txi_keys(self):
       -        return self.txi.keys()
       +    @locked
       +    def list_txi(self):
       +        return list(self.txi.keys())
        
       -    def get_txo_keys(self):
       -        return self.txo.keys()
       +    @locked
       +    def list_txo(self):
       +        return list(self.txo.keys())
        
            @modifier
            def remove_txi(self, tx_hash):
       t@@ -535,15 +547,18 @@ class JsonDB(PrintError):
            def remove_txo(self, tx_hash):
                self.txo.pop(tx_hash, None)
        
       +    @locked
            def list_spent_outpoints(self):
                return [(h, n)
                        for h in self.spent_outpoints.keys()
                        for n in self.get_spent_outpoints(h)
                ]
        
       +    @locked
            def get_spent_outpoints(self, prevout_hash):
       -        return self.spent_outpoints.get(prevout_hash, {}).keys()
       +        return list(self.spent_outpoints.get(prevout_hash, {}).keys())
        
       +    @locked
            def get_spent_outpoint(self, prevout_hash, prevout_n):
                return self.spent_outpoints.get(prevout_hash, {}).get(str(prevout_n))
        
       t@@ -567,16 +582,20 @@ class JsonDB(PrintError):
            def remove_transaction(self, tx_hash):
                self.transactions.pop(tx_hash, None)
        
       +    @locked
            def get_transaction(self, tx_hash):
                tx = self.transactions.get(tx_hash)
                return Transaction(tx) if tx else None
        
       +    @locked
            def list_transactions(self):
       -        return self.transactions.keys()
       +        return list(self.transactions.keys())
        
       +    @locked
            def get_history(self):
       -        return self.history.keys()
       +        return list(self.history.keys())
        
       +    @locked
            def get_addr_history(self, addr):
                return self.history.get(addr, [])
        
       t@@ -588,9 +607,11 @@ class JsonDB(PrintError):
            def remove_addr_history(self, addr):
                self.history.pop(addr, None)
        
       +    @locked
            def list_verified_tx(self):
       -        return self.verified_tx.keys()
       +        return list(self.verified_tx.keys())
        
       +    @locked
            def get_verified_tx(self, txid):
                if txid not in self.verified_tx:
                    return None
       t@@ -613,6 +634,7 @@ class JsonDB(PrintError):
            def update_tx_fees(self, d):
                return self.tx_fees.update(d)
        
       +    @locked
            def get_tx_fee(self, txid):
                return self.tx_fees.get(txid)
        
       t@@ -620,6 +642,7 @@ class JsonDB(PrintError):
            def remove_tx_fee(self, txid):
                self.tx_fees.pop(txid, None)
        
       +    @locked
            def get_data_ref(self, name):
                if name not in self.data:
                    self.data[name] = {}
       t@@ -656,6 +679,7 @@ class JsonDB(PrintError):
                            self.print_error("removing unreferenced spent outpoint")
                            d.pop(prevout_n)
        
       +    @modifier
            def clear_history(self):
                self.txi.clear()
                self.txo.clear()