diff --git a/electrumx/lib/tx.py b/electrumx/lib/tx.py index 3f26cbb..4aa80e2 100644 --- a/electrumx/lib/tx.py +++ b/electrumx/lib/tx.py @@ -40,11 +40,6 @@ ZERO = bytes(32) MINUS_1 = 4294967295 -def is_gen_outpoint(hash, index): - '''Test if an outpoint is a generation/coinbase like''' - return index == MINUS_1 and hash == ZERO - - class Tx(namedtuple("Tx", "version inputs outputs locktime")): '''Class representing a transaction.''' @@ -67,6 +62,10 @@ class TxInput(namedtuple("TxInput", "prev_hash prev_idx script sequence")): return ("Input({}, {:d}, script={}, sequence={:d})" .format(prev_hash, self.prev_idx, script, self.sequence)) + def is_generation(self): + '''Test if an input is generation/coinbase like''' + return self.prev_idx == MINUS_1 and self.prev_hash == ZERO + def serialize(self): return b''.join(( self.prev_hash, diff --git a/electrumx/server/block_processor.py b/electrumx/server/block_processor.py index 2af4ff7..6fc4dff 100644 --- a/electrumx/server/block_processor.py +++ b/electrumx/server/block_processor.py @@ -18,7 +18,6 @@ from functools import partial from aiorpcx import TaskGroup, run_in_thread import electrumx -from electrumx.lib.tx import is_gen_outpoint from electrumx.server.daemon import DaemonError from electrumx.lib.hash import hash_to_hex_str, HASHX_LEN from electrumx.lib.util import chunks, class_logger @@ -413,7 +412,7 @@ class BlockProcessor(object): # Spend the inputs for txin in tx.inputs: - if is_gen_outpoint(txin.prev_hash, txin.prev_idx): + if txin.is_generation(): continue cache_value = spend_utxo(txin.prev_hash, txin.prev_idx) undo_info_append(cache_value) @@ -493,7 +492,7 @@ class BlockProcessor(object): # Restore the inputs for txin in reversed(tx.inputs): - if is_gen_outpoint(txin.prev_hash, txin.prev_idx): + if txin.is_generation(): continue n -= undo_entry_len undo_item = undo_info[n:n + undo_entry_len] diff --git a/electrumx/server/mempool.py b/electrumx/server/mempool.py index 0894f95..98453a3 100644 --- a/electrumx/server/mempool.py +++ b/electrumx/server/mempool.py @@ -17,7 +17,6 @@ import attr from aiorpcx import TaskGroup, run_in_thread, sleep from electrumx.lib.hash import hash_to_hex_str, hex_str_to_hash -from electrumx.lib.tx import is_gen_outpoint from electrumx.lib.util import class_logger, chunks from electrumx.server.db import UTXO @@ -173,9 +172,6 @@ class MemPool(object): in_pairs = [] try: for prevout in tx.prevouts: - # Skip generation like prevouts - if is_gen_outpoint(*prevout): - continue utxo = utxo_map.get(prevout) if not utxo: prev_hash, prev_index = prevout @@ -277,8 +273,10 @@ class MemPool(object): continue tx, tx_size = deserializer(raw_tx).read_tx_and_vsize() # Convert the inputs and outputs into (hashX, value) pairs + # Drop generation-like inputs from MemPoolTx.prevouts txin_pairs = tuple((txin.prev_hash, txin.prev_idx) - for txin in tx.inputs) + for txin in tx.inputs + if not txin.is_generation()) txout_pairs = tuple((to_hashX(txout.pk_script), txout.value) for txout in tx.outputs) txs[hash] = MemPoolTx(txin_pairs, None, txout_pairs, @@ -295,8 +293,7 @@ class MemPool(object): # generation-like. prevouts = tuple(prevout for tx in tx_map.values() for prevout in tx.prevouts - if (prevout[0] not in all_hashes and - not is_gen_outpoint(*prevout))) + if prevout[0] not in all_hashes) utxos = await self.api.lookup_utxos(prevouts) utxo_map = {prevout: utxo for prevout, utxo in zip(prevouts, utxos)} diff --git a/tests/server/test_mempool.py b/tests/server/test_mempool.py index 191d862..8fd0994 100644 --- a/tests/server/test_mempool.py +++ b/tests/server/test_mempool.py @@ -11,7 +11,7 @@ from aiorpcx import Event, TaskGroup, sleep, spawn, ignore_after from electrumx.server.mempool import MemPool, MemPoolAPI from electrumx.lib.coins import BitcoinCash from electrumx.lib.hash import HASHX_LEN, hex_str_to_hash, hash_to_hex_str -from electrumx.lib.tx import Tx, TxInput, TxOutput, is_gen_outpoint +from electrumx.lib.tx import Tx, TxInput, TxOutput from electrumx.lib.util import make_logger @@ -35,8 +35,10 @@ def random_tx(hash160s, utxos): inputs.append(TxInput(prevout[0], prevout[1], b'', 4294967295)) input_value += value - # Add a generation/coinbase like input that is present in some coins - inputs.append(TxInput(bytes(32), 4294967295, b'', 4294967295)) + # Seomtimes add a generation/coinbase like input that is present + # in some coins + if randrange(0, 10) == 0: + inputs.append(TxInput(bytes(32), 4294967295, b'', 4294967295)) fee = min(input_value, randrange(500)) input_value -= fee @@ -102,7 +104,8 @@ class API(MemPoolAPI): def mempool_spends(self): return [(input.prev_hash, input.prev_idx) - for tx in self.txs.values() for input in tx.inputs] + for tx in self.txs.values() for input in tx.inputs + if not input.is_generation()] def balance_deltas(self): # Return mempool balance deltas indexed by hashX @@ -110,9 +113,9 @@ class API(MemPoolAPI): utxos = self.mempool_utxos() for tx_hash, tx in self.txs.items(): for n, input in enumerate(tx.inputs): - prevout = (input.prev_hash, input.prev_idx) - if is_gen_outpoint(input.prev_hash, input.prev_idx): + if input.is_generation(): continue + prevout = (input.prev_hash, input.prev_idx) if prevout in utxos: utxos.pop(prevout) else: @@ -128,9 +131,9 @@ class API(MemPoolAPI): utxos = self.mempool_utxos() for tx_hash, tx in self.txs.items(): for n, input in enumerate(tx.inputs): - prevout = (input.prev_hash, input.prev_idx) - if is_gen_outpoint(input.prev_hash, input.prev_idx): + if input.is_generation(): continue + prevout = (input.prev_hash, input.prev_idx) if prevout in utxos: hashX, value = utxos.pop(prevout) else: @@ -147,7 +150,7 @@ class API(MemPoolAPI): hashXs = set() has_ui = False for n, input in enumerate(tx.inputs): - if is_gen_outpoint(input.prev_hash, input.prev_idx): + if input.is_generation(): continue has_ui = has_ui or (input.prev_hash in self.txs) prevout = (input.prev_hash, input.prev_idx) @@ -173,7 +176,7 @@ class API(MemPoolAPI): for tx_hash in tx_hashes: tx = self.txs[tx_hash] for n, input in enumerate(tx.inputs): - if is_gen_outpoint(input.prev_hash, input.prev_idx): + if input.is_generation(): continue prevout = (input.prev_hash, input.prev_idx) if prevout in utxos: @@ -484,8 +487,6 @@ async def test_notifications(): api._height = new_height api.db_utxos.update(first_utxos) for spend in first_spends: - if is_gen_outpoint(*spend): - continue del api.db_utxos[spend] api.raw_txs = {hash: raw_txs[hash] for hash in second_hashes} api.txs = {hash: txs[hash] for hash in second_hashes}