Browse Source

Add is_generation memeber to TxInput

Use it in preference to is_gen_outpoint
patch-2
Neil Booth 7 years ago
parent
commit
ab17b4d529
  1. 9
      electrumx/lib/tx.py
  2. 5
      electrumx/server/block_processor.py
  3. 11
      electrumx/server/mempool.py
  4. 23
      tests/server/test_mempool.py

9
electrumx/lib/tx.py

@ -40,11 +40,6 @@ ZERO = bytes(32)
MINUS_1 = 4294967295 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 Tx(namedtuple("Tx", "version inputs outputs locktime")):
'''Class representing a transaction.''' '''Class representing a transaction.'''
@ -67,6 +62,10 @@ class TxInput(namedtuple("TxInput", "prev_hash prev_idx script sequence")):
return ("Input({}, {:d}, script={}, sequence={:d})" return ("Input({}, {:d}, script={}, sequence={:d})"
.format(prev_hash, self.prev_idx, script, self.sequence)) .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): def serialize(self):
return b''.join(( return b''.join((
self.prev_hash, self.prev_hash,

5
electrumx/server/block_processor.py

@ -18,7 +18,6 @@ from functools import partial
from aiorpcx import TaskGroup, run_in_thread from aiorpcx import TaskGroup, run_in_thread
import electrumx import electrumx
from electrumx.lib.tx import is_gen_outpoint
from electrumx.server.daemon import DaemonError from electrumx.server.daemon import DaemonError
from electrumx.lib.hash import hash_to_hex_str, HASHX_LEN from electrumx.lib.hash import hash_to_hex_str, HASHX_LEN
from electrumx.lib.util import chunks, class_logger from electrumx.lib.util import chunks, class_logger
@ -413,7 +412,7 @@ class BlockProcessor(object):
# Spend the inputs # Spend the inputs
for txin in tx.inputs: for txin in tx.inputs:
if is_gen_outpoint(txin.prev_hash, txin.prev_idx): if txin.is_generation():
continue continue
cache_value = spend_utxo(txin.prev_hash, txin.prev_idx) cache_value = spend_utxo(txin.prev_hash, txin.prev_idx)
undo_info_append(cache_value) undo_info_append(cache_value)
@ -493,7 +492,7 @@ class BlockProcessor(object):
# Restore the inputs # Restore the inputs
for txin in reversed(tx.inputs): for txin in reversed(tx.inputs):
if is_gen_outpoint(txin.prev_hash, txin.prev_idx): if txin.is_generation():
continue continue
n -= undo_entry_len n -= undo_entry_len
undo_item = undo_info[n:n + undo_entry_len] undo_item = undo_info[n:n + undo_entry_len]

11
electrumx/server/mempool.py

@ -17,7 +17,6 @@ import attr
from aiorpcx import TaskGroup, run_in_thread, sleep from aiorpcx import TaskGroup, run_in_thread, sleep
from electrumx.lib.hash import hash_to_hex_str, hex_str_to_hash 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.lib.util import class_logger, chunks
from electrumx.server.db import UTXO from electrumx.server.db import UTXO
@ -173,9 +172,6 @@ class MemPool(object):
in_pairs = [] in_pairs = []
try: try:
for prevout in tx.prevouts: for prevout in tx.prevouts:
# Skip generation like prevouts
if is_gen_outpoint(*prevout):
continue
utxo = utxo_map.get(prevout) utxo = utxo_map.get(prevout)
if not utxo: if not utxo:
prev_hash, prev_index = prevout prev_hash, prev_index = prevout
@ -277,8 +273,10 @@ class MemPool(object):
continue continue
tx, tx_size = deserializer(raw_tx).read_tx_and_vsize() tx, tx_size = deserializer(raw_tx).read_tx_and_vsize()
# Convert the inputs and outputs into (hashX, value) pairs # 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) 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) txout_pairs = tuple((to_hashX(txout.pk_script), txout.value)
for txout in tx.outputs) for txout in tx.outputs)
txs[hash] = MemPoolTx(txin_pairs, None, txout_pairs, txs[hash] = MemPoolTx(txin_pairs, None, txout_pairs,
@ -295,8 +293,7 @@ class MemPool(object):
# generation-like. # generation-like.
prevouts = tuple(prevout for tx in tx_map.values() prevouts = tuple(prevout for tx in tx_map.values()
for prevout in tx.prevouts for prevout in tx.prevouts
if (prevout[0] not in all_hashes and if prevout[0] not in all_hashes)
not is_gen_outpoint(*prevout)))
utxos = await self.api.lookup_utxos(prevouts) utxos = await self.api.lookup_utxos(prevouts)
utxo_map = {prevout: utxo for prevout, utxo in zip(prevouts, utxos)} utxo_map = {prevout: utxo for prevout, utxo in zip(prevouts, utxos)}

23
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.server.mempool import MemPool, MemPoolAPI
from electrumx.lib.coins import BitcoinCash from electrumx.lib.coins import BitcoinCash
from electrumx.lib.hash import HASHX_LEN, hex_str_to_hash, hash_to_hex_str 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 from electrumx.lib.util import make_logger
@ -35,7 +35,9 @@ def random_tx(hash160s, utxos):
inputs.append(TxInput(prevout[0], prevout[1], b'', 4294967295)) inputs.append(TxInput(prevout[0], prevout[1], b'', 4294967295))
input_value += value input_value += value
# Add a generation/coinbase like input that is present in some coins # 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)) inputs.append(TxInput(bytes(32), 4294967295, b'', 4294967295))
fee = min(input_value, randrange(500)) fee = min(input_value, randrange(500))
@ -102,7 +104,8 @@ class API(MemPoolAPI):
def mempool_spends(self): def mempool_spends(self):
return [(input.prev_hash, input.prev_idx) 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): def balance_deltas(self):
# Return mempool balance deltas indexed by hashX # Return mempool balance deltas indexed by hashX
@ -110,9 +113,9 @@ class API(MemPoolAPI):
utxos = self.mempool_utxos() utxos = self.mempool_utxos()
for tx_hash, tx in self.txs.items(): for tx_hash, tx in self.txs.items():
for n, input in enumerate(tx.inputs): for n, input in enumerate(tx.inputs):
prevout = (input.prev_hash, input.prev_idx) if input.is_generation():
if is_gen_outpoint(input.prev_hash, input.prev_idx):
continue continue
prevout = (input.prev_hash, input.prev_idx)
if prevout in utxos: if prevout in utxos:
utxos.pop(prevout) utxos.pop(prevout)
else: else:
@ -128,9 +131,9 @@ class API(MemPoolAPI):
utxos = self.mempool_utxos() utxos = self.mempool_utxos()
for tx_hash, tx in self.txs.items(): for tx_hash, tx in self.txs.items():
for n, input in enumerate(tx.inputs): for n, input in enumerate(tx.inputs):
prevout = (input.prev_hash, input.prev_idx) if input.is_generation():
if is_gen_outpoint(input.prev_hash, input.prev_idx):
continue continue
prevout = (input.prev_hash, input.prev_idx)
if prevout in utxos: if prevout in utxos:
hashX, value = utxos.pop(prevout) hashX, value = utxos.pop(prevout)
else: else:
@ -147,7 +150,7 @@ class API(MemPoolAPI):
hashXs = set() hashXs = set()
has_ui = False has_ui = False
for n, input in enumerate(tx.inputs): for n, input in enumerate(tx.inputs):
if is_gen_outpoint(input.prev_hash, input.prev_idx): if input.is_generation():
continue continue
has_ui = has_ui or (input.prev_hash in self.txs) has_ui = has_ui or (input.prev_hash in self.txs)
prevout = (input.prev_hash, input.prev_idx) prevout = (input.prev_hash, input.prev_idx)
@ -173,7 +176,7 @@ class API(MemPoolAPI):
for tx_hash in tx_hashes: for tx_hash in tx_hashes:
tx = self.txs[tx_hash] tx = self.txs[tx_hash]
for n, input in enumerate(tx.inputs): for n, input in enumerate(tx.inputs):
if is_gen_outpoint(input.prev_hash, input.prev_idx): if input.is_generation():
continue continue
prevout = (input.prev_hash, input.prev_idx) prevout = (input.prev_hash, input.prev_idx)
if prevout in utxos: if prevout in utxos:
@ -484,8 +487,6 @@ async def test_notifications():
api._height = new_height api._height = new_height
api.db_utxos.update(first_utxos) api.db_utxos.update(first_utxos)
for spend in first_spends: for spend in first_spends:
if is_gen_outpoint(*spend):
continue
del api.db_utxos[spend] del api.db_utxos[spend]
api.raw_txs = {hash: raw_txs[hash] for hash in second_hashes} api.raw_txs = {hash: raw_txs[hash] for hash in second_hashes}
api.txs = {hash: txs[hash] for hash in second_hashes} api.txs = {hash: txs[hash] for hash in second_hashes}

Loading…
Cancel
Save