diff --git a/server/db.py b/server/db.py index d58af24..4858f18 100644 --- a/server/db.py +++ b/server/db.py @@ -208,11 +208,6 @@ class DB(LoggedClass): tx_hash, height = self.fs_tx_hash(tx_num) yield UTXO(tx_num, tx_pos, tx_hash, height, value) - def get_utxos_sorted(self, hash168): - '''Returns all the UTXOs for an address sorted by height and - position in the block.''' - return sorted(self.get_utxos(hash168, limit=None)) - def get_utxo_hash168(self, tx_hash, index): '''Returns the hash168 for a UTXO. diff --git a/server/protocol.py b/server/protocol.py index 7a77b1e..e77ab39 100644 --- a/server/protocol.py +++ b/server/protocol.py @@ -350,7 +350,7 @@ class ElectrumX(Session): matches = self.hash168s.intersection(touched) for hash168 in matches: address = hash168_to_address(hash168) - status = self.address_status(hash168) + status = await self.address_status(hash168) payload = json_notification_payload( 'blockchain.address.subscribe', (address, status)) self.send_json(payload) @@ -374,11 +374,11 @@ class ElectrumX(Session): header = self.bp.read_headers(height, 1) return self.coin.electrum_header(header, height) - def address_status(self, hash168): + async def address_status(self, hash168): '''Returns status as 32 bytes.''' # Note history is ordered and mempool unordered in electrum-server # For mempool, height is -1 if unconfirmed txins, otherwise 0 - history = self.bp.get_history(hash168) + history = await self.async_get_history(hash168) mempool = self.bp.mempool_transactions(hash168) status = ''.join('{}:{:d}:'.format(hash_to_str(tx_hash), height) @@ -411,10 +411,10 @@ class ElectrumX(Session): return {"block_height": height, "merkle": merkle_branch, "pos": pos} - def get_history(self, hash168): + async def get_history(self, hash168): # Note history is ordered and mempool unordered in electrum-server # For mempool, height is -1 if unconfirmed txins, otherwise 0 - history = self.bp.get_history(hash168, limit=None) + history = await self.async_get_history(hash168) mempool = self.bp.mempool_transactions(hash168) conf = tuple({'tx_hash': hash_to_str(tx_hash), 'height': height} @@ -431,27 +431,44 @@ class ElectrumX(Session): count = min(next_height - start_height, chunk_size) return self.bp.read_headers(start_height, count).hex() - def get_balance(self, hash168): - confirmed = self.bp.get_balance(hash168) + async def async_get_history(self, hash168): + # Python 3.6: use async generators; update callers + history = [] + for item in self.bp.get_history(hash168, limit=None): + history.append(item) + if len(history) % 100 == 0: + await asyncio.sleep(0) + return history + + async def get_utxos(self, hash168): + # Python 3.6: use async generators; update callers + utxos = [] + for utxo in self.bp.get_utxos(hash168, limit=None): + utxos.append(utxo) + if len(utxos) % 25 == 0: + await asyncio.sleep(0) + return utxos + + async def get_balance(self, hash168): + utxos = await self.get_utxos(hash168) + confirmed = sum(utxo.value for utxo in utxos) unconfirmed = self.bp.mempool_value(hash168) return {'confirmed': confirmed, 'unconfirmed': unconfirmed} - def list_unspent(self, hash168): - utxos = self.bp.get_utxos_sorted(hash168) - return tuple({'tx_hash': hash_to_str(utxo.tx_hash), - 'tx_pos': utxo.tx_pos, 'height': utxo.height, - 'value': utxo.value} - for utxo in utxos) + async def list_unspent(self, hash168): + return [{'tx_hash': hash_to_str(utxo.tx_hash), 'tx_pos': utxo.tx_pos, + 'height': utxo.height, 'value': utxo.value} + for utxo in sorted(await self.get_utxos(hash168))] # --- blockchain commands async def address_get_balance(self, params): hash168 = self.extract_hash168(params) - return self.get_balance(hash168) + return await self.get_balance(hash168) async def address_get_history(self, params): hash168 = self.extract_hash168(params) - return self.get_history(hash168) + return await self.get_history(hash168) async def address_get_mempool(self, params): hash168 = self.extract_hash168(params) @@ -463,12 +480,12 @@ class ElectrumX(Session): async def address_listunspent(self, params): hash168 = self.extract_hash168(params) - return self.list_unspent(hash168) + return await self.list_unspent(hash168) async def address_subscribe(self, params): hash168 = self.extract_hash168(params) self.hash168s.add(hash168) - return self.address_status(hash168) + return await self.address_status(hash168) async def block_get_chunk(self, params): index = self.extract_non_negative_integer(params)