From 21604cad1582c40d9dc8f8858230c28a221899e6 Mon Sep 17 00:00:00 2001 From: Neil Booth Date: Sun, 22 Jul 2018 22:52:08 +0800 Subject: [PATCH] Create a MemPoolTx object and use it --- electrumx/server/mempool.py | 83 ++++++++++++++++++++----------------- setup.py | 3 +- 2 files changed, 48 insertions(+), 38 deletions(-) diff --git a/electrumx/server/mempool.py b/electrumx/server/mempool.py index 7d51922..d2cc41c 100644 --- a/electrumx/server/mempool.py +++ b/electrumx/server/mempool.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, Neil Booth +# Copyright (c) 2016-2018, Neil Booth # # All rights reserved. # @@ -12,11 +12,22 @@ import itertools import time from collections import defaultdict +import attr + from electrumx.lib.hash import hash_to_hex_str, hex_str_to_hash from electrumx.lib.util import class_logger from electrumx.server.db import UTXO +@attr.s(slots=True) +class MemPoolTx(object): + hash = attr.ib() + in_pairs = attr.ib() + out_pairs = attr.ib() + fee = attr.ib() + size = attr.ib() + + class MemPool(object): '''Representation of the daemon's mempool. @@ -25,7 +36,7 @@ class MemPool(object): To that end we maintain the following maps: - tx_hash -> (txin_pairs, txout_pairs, tx_fee, tx_size) + tx_hash -> MemPoolTx hashX -> set of all tx hashes in which the hashX appears A pair is a (hashX, value) tuple. tx hashes are hex strings. @@ -119,15 +130,14 @@ class MemPool(object): for hex_hash in gone: unfetched.discard(hex_hash) unprocessed.pop(hex_hash, None) - item = txs.pop(hex_hash) - if item: - txin_pairs, txout_pairs, tx_fee, tx_size = item - fee_rate = tx_fee // tx_size - fee_hist[fee_rate] -= tx_size + tx = txs.pop(hex_hash) + if tx: + fee_rate = tx.fee // tx.size + fee_hist[fee_rate] -= tx.size if fee_hist[fee_rate] == 0: fee_hist.pop(fee_rate) - tx_hashXs = set(hashX for hashX, value in txin_pairs) - tx_hashXs.update(hashX for hashX, value in txout_pairs) + tx_hashXs = set(hashX for hashX, value in tx.in_pairs) + tx_hashXs.update(hashX for hashX, value in tx.out_pairs) for hashX in tx_hashXs: hashXs[hashX].remove(hex_hash) if not hashXs[hashX]: @@ -191,7 +201,8 @@ class MemPool(object): txin_pairs = [(hash_to_hex_str(txin.prev_hash), txin.prev_idx) for txin in tx.inputs] - pending.append((tx_hash, txin_pairs, txout_pairs, tx_size)) + pending.append(MemPoolTx(tx_hash, txin_pairs, txout_pairs, + 0, tx_size)) # Do this potentially slow operation in a thread so as not to # block @@ -202,8 +213,8 @@ class MemPool(object): # otherwise presumably in the DB. txs = self.txs db_prevouts = [(hex_str_to_hash(prev_hash), prev_idx) - for item in pending - for (prev_hash, prev_idx) in item[1] + for tx in pending + for (prev_hash, prev_idx) in tx.in_pairs if prev_hash not in txs] # If a lookup fails, it returns a None entry @@ -216,33 +227,33 @@ class MemPool(object): hashXs = self.hashXs fee_hist = self.fee_histogram - for item in pending: - tx_hash, previns, txout_pairs, tx_size = item - if tx_hash not in txs: + for tx in pending: + if tx.hash not in txs: continue - txin_pairs = [] + in_pairs = [] try: - for previn in previns: + for previn in tx.in_pairs: utxo = db_utxo_map.get(previn) if not utxo: prev_hash, prev_index = previn # This can raise a KeyError or TypeError utxo = txs[prev_hash][1][prev_index] - txin_pairs.append(utxo) + in_pairs.append(utxo) except (KeyError, TypeError): - deferred.append(item) + deferred.append(tx) continue + tx.in_pairs = in_pairs # Compute fee - tx_fee = (sum(v for hashX, v in txin_pairs) - - sum(v for hashX, v in txout_pairs)) - fee_rate = tx_fee // tx_size - fee_hist[fee_rate] += tx_size - txs[tx_hash] = (txin_pairs, txout_pairs, tx_fee, tx_size) - for hashX, value in itertools.chain(txin_pairs, txout_pairs): + tx_fee = (sum(v for hashX, v in tx.in_pairs) - + sum(v for hashX, v in tx.out_pairs)) + fee_rate = tx.fee // tx.size + fee_hist[fee_rate] += tx.size + txs[tx.hash] = tx + for hashX, value in itertools.chain(tx.in_pairs, tx.out_pairs): touched.add(hashX) - hashXs[hashX].add(tx_hash) + hashXs[hashX].add(tx.hash) return deferred @@ -302,9 +313,9 @@ class MemPool(object): # hashXs is a defaultdict if hashX in self.hashXs: for hex_hash in self.hashXs[hashX]: - txin_pairs, txout_pairs, tx_fee, tx_size = self.txs[hex_hash] - value -= sum(v for h168, v in txin_pairs if h168 == hashX) - value += sum(v for h168, v in txout_pairs if h168 == hashX) + tx = self.txs[hex_hash] + value -= sum(v for h168, v in tx.in_pairs if h168 == hashX) + value += sum(v for h168, v in tx.out_pairs if h168 == hashX) return value async def compact_fee_histogram(self): @@ -342,14 +353,13 @@ class MemPool(object): pairs = await self._raw_transactions(hashX) result = [] for hex_hash, raw_tx in pairs: - item = self.txs.get(hex_hash) - if not item or not raw_tx: + mempool_tx = self.txs.get(hex_hash) + if not mempool_tx or not raw_tx: continue - tx_fee = item[2] tx = deserializer(raw_tx).read_tx() unconfirmed = any(hash_to_hex_str(txin.prev_hash) in self.txs for txin in tx.inputs) - result.append((hex_hash, tx_fee, unconfirmed)) + result.append((hex_hash, mempool_tx.fee, unconfirmed)) return result async def unordered_UTXOs(self, hashX): @@ -362,11 +372,10 @@ class MemPool(object): utxos = [] # hashXs is a defaultdict, so use get() to query for hex_hash in self.hashXs.get(hashX, []): - item = self.txs.get(hex_hash) - if not item: + tx = self.txs.get(hex_hash) + if not tx: continue - txout_pairs = item[1] - for pos, (hX, value) in enumerate(txout_pairs): + for pos, (hX, value) in enumerate(tx.out_pairs): if hX == hashX: # Unfortunately UTXO holds a binary hash utxos.append(UTXO(-1, pos, hex_str_to_hash(hex_hash), diff --git a/setup.py b/setup.py index 6b446dc..d6e915e 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,8 @@ setuptools.setup( # "tribus_hash" package is required to sync Denarius network. # "blake256" package is required to sync Decred network. # "xevan_hash" package is required to sync Xuez network. - install_requires=['aiorpcX >= 0.5.6', 'plyvel', 'pylru', 'aiohttp >= 2'], + install_requires=['aiorpcX >= 0.5.6', 'attrs>=15', + 'plyvel', 'pylru', 'aiohttp >= 2'], packages=setuptools.find_packages(include=('electrumx*',)), description='ElectrumX Server', author='Neil Booth',