Change read_tx interface of deserializer
Most callers didn't want the hash, so create a separate call that does both. Add a new call that returns the TX and its vsize.
This commit is contained in:
parent
9377ea54de
commit
e5b4f5f316
75
lib/tx.py
75
lib/tx.py
@ -71,7 +71,8 @@ class TxOutput(namedtuple("TxOutput", "value pk_script")):
|
|||||||
class Deserializer(object):
|
class Deserializer(object):
|
||||||
'''Deserializes blocks into transactions.
|
'''Deserializes blocks into transactions.
|
||||||
|
|
||||||
External entry points are read_tx() and read_block().
|
External entry points are read_tx(), read_tx_and_hash(),
|
||||||
|
read_tx_and_vsize() and read_block().
|
||||||
|
|
||||||
This code is performance sensitive as it is executed 100s of
|
This code is performance sensitive as it is executed 100s of
|
||||||
millions of times during sync.
|
millions of times during sync.
|
||||||
@ -84,25 +85,32 @@ class Deserializer(object):
|
|||||||
self.cursor = start
|
self.cursor = start
|
||||||
|
|
||||||
def read_tx(self):
|
def read_tx(self):
|
||||||
'''Return a (Deserialized TX, TX_HASH) pair.
|
'''Return a deserialized transaction.'''
|
||||||
|
|
||||||
The hash needs to be reversed for human display; for efficiency
|
|
||||||
we process it in the natural serialized order.
|
|
||||||
'''
|
|
||||||
start = self.cursor
|
|
||||||
return Tx(
|
return Tx(
|
||||||
self._read_le_int32(), # version
|
self._read_le_int32(), # version
|
||||||
self._read_inputs(), # inputs
|
self._read_inputs(), # inputs
|
||||||
self._read_outputs(), # outputs
|
self._read_outputs(), # outputs
|
||||||
self._read_le_uint32() # locktime
|
self._read_le_uint32() # locktime
|
||||||
), double_sha256(self.binary[start:self.cursor])
|
)
|
||||||
|
|
||||||
|
def read_tx_and_hash(self):
|
||||||
|
'''Return a (deserialized TX, tx_hash) pair.
|
||||||
|
|
||||||
|
The hash needs to be reversed for human display; for efficiency
|
||||||
|
we process it in the natural serialized order.
|
||||||
|
'''
|
||||||
|
start = self.cursor
|
||||||
|
return self.read_tx(), double_sha256(self.binary[start:self.cursor])
|
||||||
|
|
||||||
|
def read_tx_and_vsize(self):
|
||||||
|
'''Return a (deserialized TX, vsize) pair.'''
|
||||||
|
return self.read_tx(), self.binary_length
|
||||||
|
|
||||||
def read_tx_block(self):
|
def read_tx_block(self):
|
||||||
'''Returns a list of (deserialized_tx, tx_hash) pairs.'''
|
'''Returns a list of (deserialized_tx, tx_hash) pairs.'''
|
||||||
read_tx = self.read_tx
|
read = self.read_tx_and_hash
|
||||||
txs = [read_tx() for _ in range(self._read_varint())]
|
|
||||||
# Some coins have excess data beyond the end of the transactions
|
# Some coins have excess data beyond the end of the transactions
|
||||||
return txs
|
return [read() for _ in range(self._read_varint())]
|
||||||
|
|
||||||
def _read_inputs(self):
|
def _read_inputs(self):
|
||||||
read_input = self._read_input
|
read_input = self._read_input
|
||||||
@ -198,15 +206,12 @@ class DeserializerSegWit(Deserializer):
|
|||||||
read_varbytes = self._read_varbytes
|
read_varbytes = self._read_varbytes
|
||||||
return [read_varbytes() for i in range(self._read_varint())]
|
return [read_varbytes() for i in range(self._read_varint())]
|
||||||
|
|
||||||
def read_tx(self):
|
def _read_tx_parts(self):
|
||||||
'''Return a (Deserialized TX, TX_HASH) pair.
|
'''Return a (deserialized TX, tx_hash, vsize) tuple.'''
|
||||||
|
|
||||||
The hash needs to be reversed for human display; for efficiency
|
|
||||||
we process it in the natural serialized order.
|
|
||||||
'''
|
|
||||||
marker = self.binary[self.cursor + 4]
|
marker = self.binary[self.cursor + 4]
|
||||||
if marker:
|
if marker:
|
||||||
return super().read_tx()
|
tx, tx_hash = super().read_tx_and_hash()
|
||||||
|
return tx, tx_hash, self.binary_size
|
||||||
|
|
||||||
# Ugh, this is nasty.
|
# Ugh, this is nasty.
|
||||||
start = self.cursor
|
start = self.cursor
|
||||||
@ -221,14 +226,27 @@ class DeserializerSegWit(Deserializer):
|
|||||||
outputs = self._read_outputs()
|
outputs = self._read_outputs()
|
||||||
orig_ser += self.binary[start:self.cursor]
|
orig_ser += self.binary[start:self.cursor]
|
||||||
|
|
||||||
|
base_size = self.cursor - start
|
||||||
witness = self._read_witness(len(inputs))
|
witness = self._read_witness(len(inputs))
|
||||||
|
|
||||||
start = self.cursor
|
start = self.cursor
|
||||||
locktime = self._read_le_uint32()
|
locktime = self._read_le_uint32()
|
||||||
orig_ser += self.binary[start:self.cursor]
|
orig_ser += self.binary[start:self.cursor]
|
||||||
|
vsize = (3 * base_size + self.binary_length) // 4
|
||||||
|
|
||||||
return TxSegWit(version, marker, flag, inputs,
|
return TxSegWit(version, marker, flag, inputs, outputs, witness,
|
||||||
outputs, witness, locktime), double_sha256(orig_ser)
|
locktime), double_sha256(orig_ser), vsize
|
||||||
|
|
||||||
|
def read_tx(self):
|
||||||
|
return self._read_tx_parts()[0]
|
||||||
|
|
||||||
|
def read_tx_and_hash(self):
|
||||||
|
tx, tx_hash, vsize = self._read_tx_parts()
|
||||||
|
return tx, tx_hash
|
||||||
|
|
||||||
|
def read_tx_and_vsize(self):
|
||||||
|
tx, tx_hash, vsize = self._read_tx_parts()
|
||||||
|
return tx, vsize
|
||||||
|
|
||||||
|
|
||||||
class DeserializerAuxPow(Deserializer):
|
class DeserializerAuxPow(Deserializer):
|
||||||
@ -289,7 +307,6 @@ class TxJoinSplit(namedtuple("Tx", "version inputs outputs locktime")):
|
|||||||
|
|
||||||
class DeserializerZcash(DeserializerEquihash):
|
class DeserializerZcash(DeserializerEquihash):
|
||||||
def read_tx(self):
|
def read_tx(self):
|
||||||
start = self.cursor
|
|
||||||
base_tx = TxJoinSplit(
|
base_tx = TxJoinSplit(
|
||||||
self._read_le_int32(), # version
|
self._read_le_int32(), # version
|
||||||
self._read_inputs(), # inputs
|
self._read_inputs(), # inputs
|
||||||
@ -302,7 +319,7 @@ class DeserializerZcash(DeserializerEquihash):
|
|||||||
self.cursor += joinsplit_size * 1802 # JSDescription
|
self.cursor += joinsplit_size * 1802 # JSDescription
|
||||||
self.cursor += 32 # joinSplitPubKey
|
self.cursor += 32 # joinSplitPubKey
|
||||||
self.cursor += 64 # joinSplitSig
|
self.cursor += 64 # joinSplitSig
|
||||||
return base_tx, double_sha256(self.binary[start:self.cursor])
|
return base_tx
|
||||||
|
|
||||||
|
|
||||||
class TxTime(namedtuple("Tx", "version time inputs outputs locktime")):
|
class TxTime(namedtuple("Tx", "version time inputs outputs locktime")):
|
||||||
@ -315,21 +332,17 @@ class TxTime(namedtuple("Tx", "version time inputs outputs locktime")):
|
|||||||
|
|
||||||
class DeserializerTxTime(Deserializer):
|
class DeserializerTxTime(Deserializer):
|
||||||
def read_tx(self):
|
def read_tx(self):
|
||||||
start = self.cursor
|
|
||||||
|
|
||||||
return TxTime(
|
return TxTime(
|
||||||
self._read_le_int32(), # version
|
self._read_le_int32(), # version
|
||||||
self._read_le_uint32(), # time
|
self._read_le_uint32(), # time
|
||||||
self._read_inputs(), # inputs
|
self._read_inputs(), # inputs
|
||||||
self._read_outputs(), # outputs
|
self._read_outputs(), # outputs
|
||||||
self._read_le_uint32(), # locktime
|
self._read_le_uint32(), # locktime
|
||||||
), double_sha256(self.binary[start:self.cursor])
|
)
|
||||||
|
|
||||||
|
|
||||||
class DeserializerReddcoin(Deserializer):
|
class DeserializerReddcoin(Deserializer):
|
||||||
def read_tx(self):
|
def read_tx(self):
|
||||||
start = self.cursor
|
|
||||||
|
|
||||||
version = self._read_le_int32()
|
version = self._read_le_int32()
|
||||||
inputs = self._read_inputs()
|
inputs = self._read_inputs()
|
||||||
outputs = self._read_outputs()
|
outputs = self._read_outputs()
|
||||||
@ -339,13 +352,7 @@ class DeserializerReddcoin(Deserializer):
|
|||||||
else:
|
else:
|
||||||
time = 0
|
time = 0
|
||||||
|
|
||||||
return TxTime(
|
return TxTime(version, time, inputs, outputs, locktime)
|
||||||
version,
|
|
||||||
time,
|
|
||||||
inputs,
|
|
||||||
outputs,
|
|
||||||
locktime,
|
|
||||||
), double_sha256(self.binary[start:self.cursor])
|
|
||||||
|
|
||||||
|
|
||||||
class DeserializerTxTimeAuxPow(DeserializerTxTime):
|
class DeserializerTxTimeAuxPow(DeserializerTxTime):
|
||||||
|
|||||||
@ -873,7 +873,7 @@ class Controller(ServerBase):
|
|||||||
if not raw_tx:
|
if not raw_tx:
|
||||||
return None
|
return None
|
||||||
raw_tx = util.hex_to_bytes(raw_tx)
|
raw_tx = util.hex_to_bytes(raw_tx)
|
||||||
tx, tx_hash = self.coin.DESERIALIZER(raw_tx).read_tx()
|
tx = self.coin.DESERIALIZER(raw_tx).read_tx()
|
||||||
if index >= len(tx.outputs):
|
if index >= len(tx.outputs):
|
||||||
return None
|
return None
|
||||||
return self.coin.address_from_script(tx.outputs[index].pk_script)
|
return self.coin.address_from_script(tx.outputs[index].pk_script)
|
||||||
|
|||||||
@ -217,7 +217,7 @@ class MemPool(util.LoggedClass):
|
|||||||
for tx_hash, raw_tx in raw_tx_map.items():
|
for tx_hash, raw_tx in raw_tx_map.items():
|
||||||
if tx_hash not in txs:
|
if tx_hash not in txs:
|
||||||
continue
|
continue
|
||||||
tx, _tx_hash = deserializer(raw_tx).read_tx()
|
tx = deserializer(raw_tx).read_tx()
|
||||||
|
|
||||||
# Convert the tx outputs into (hashX, value) pairs
|
# Convert the tx outputs into (hashX, value) pairs
|
||||||
txout_pairs = [(script_hashX(txout.pk_script), txout.value)
|
txout_pairs = [(script_hashX(txout.pk_script), txout.value)
|
||||||
@ -301,7 +301,7 @@ class MemPool(util.LoggedClass):
|
|||||||
txin_pairs, txout_pairs = item
|
txin_pairs, txout_pairs = item
|
||||||
tx_fee = (sum(v for hashX, v in txin_pairs) -
|
tx_fee = (sum(v for hashX, v in txin_pairs) -
|
||||||
sum(v for hashX, v in txout_pairs))
|
sum(v for hashX, v in txout_pairs))
|
||||||
tx, tx_hash = deserializer(raw_tx).read_tx()
|
tx = deserializer(raw_tx).read_tx()
|
||||||
unconfirmed = any(hash_to_str(txin.prev_hash) in self.txs
|
unconfirmed = any(hash_to_str(txin.prev_hash) in self.txs
|
||||||
for txin in tx.inputs)
|
for txin in tx.inputs)
|
||||||
result.append((hex_hash, tx_fee, unconfirmed))
|
result.append((hex_hash, tx_fee, unconfirmed))
|
||||||
@ -319,7 +319,7 @@ class MemPool(util.LoggedClass):
|
|||||||
for hex_hash, raw_tx in pairs:
|
for hex_hash, raw_tx in pairs:
|
||||||
if not raw_tx:
|
if not raw_tx:
|
||||||
continue
|
continue
|
||||||
tx, tx_hash = deserializer(raw_tx).read_tx()
|
tx = deserializer(raw_tx).read_tx()
|
||||||
for txin in tx.inputs:
|
for txin in tx.inputs:
|
||||||
spends.add((txin.prev_hash, txin.prev_idx))
|
spends.add((txin.prev_hash, txin.prev_idx))
|
||||||
return spends
|
return spends
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user