Create a MemPoolTx object and use it
This commit is contained in:
parent
4b3ceff0d2
commit
21604cad15
@ -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),
|
||||
|
||||
3
setup.py
3
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',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user