Skip to content

Commit

Permalink
Namecoin / AuxPoW: Optimize away hex/binary conversions in parent coi…
Browse files Browse the repository at this point in the history
…nbase transaction parsing in deserialize_auxpow_header.
  • Loading branch information
JeremyRand committed Jul 1, 2018
1 parent 92da917 commit f6702cd
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 11 deletions.
7 changes: 3 additions & 4 deletions lib/auxpow.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,9 @@ def deserialize_auxpow_header(base_header, s, expect_trailing_data=False):

# The parent coinbase transaction is first.
# Deserialize it and save the trailing data.
parent_coinbase_tx = Transaction(bh2u(s), expect_trailing_data=True)
parent_coinbase_tx_dict, s_hex = fast_tx_deserialize(parent_coinbase_tx)
parent_coinbase_tx = Transaction(None, expect_trailing_data=True, raw_bytes=s, expect_trailing_bytes=True)
parent_coinbase_tx_dict, s = fast_tx_deserialize(parent_coinbase_tx)
auxpow_header['parent_coinbase_tx'] = parent_coinbase_tx
s = bfh(s_hex)

# Next is the parent block hash. According to the Bitcoin.it wiki,
# this field is not actually consensus-critical. So we don't save it.
Expand Down Expand Up @@ -304,7 +303,7 @@ def hex_to_int(s):
# This is calculated the same as the Transaction.txid() method, but doesn't
# reserialize it.
def fast_txid(tx):
return bh2u(Hash(bfh(tx.raw))[::-1])
return bh2u(Hash(tx.raw_bytes)[::-1])

def fast_tx_deserialize(tx):
def stub(_bytes, *, net=None):
Expand Down
31 changes: 24 additions & 7 deletions lib/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -560,8 +560,9 @@ def parse_output(vds, i):
return d


def deserialize(raw: str, force_full_parse=False, expect_trailing_data=False) -> dict:
raw_bytes = bfh(raw)
def deserialize(raw: str, force_full_parse=False, expect_trailing_data=False, raw_bytes=None, expect_trailing_bytes=False) -> dict:
if raw_bytes is None:
raw_bytes = bfh(raw)
d = {}
if raw_bytes[:5] == PARTIAL_TXN_HEADER_MAGIC:
d['partial'] = is_partial = True
Expand Down Expand Up @@ -596,6 +597,9 @@ def deserialize(raw: str, force_full_parse=False, expect_trailing_data=False) ->
raise SerializationError('extra junk at the end')
if not expect_trailing_data:
return d
# The caller is expecting trailing data to be present; return that trailing data in bytes format
if expect_trailing_bytes:
return d, raw_bytes[vds.read_cursor:]
# The caller is expecting trailing data to be present; return that trailing data in hex format
return d, bh2u(raw_bytes[vds.read_cursor:])

Expand Down Expand Up @@ -623,13 +627,16 @@ def __str__(self):
self.raw = self.serialize()
return self.raw

def __init__(self, raw, expect_trailing_data=False):
def __init__(self, raw, expect_trailing_data=False, raw_bytes=None, expect_trailing_bytes=False):
if raw is None:
self.raw = None
self.raw_bytes = raw_bytes
elif isinstance(raw, str):
self.raw = raw.strip() if raw else None
self.raw_bytes = raw_bytes
elif isinstance(raw, dict):
self.raw = raw['hex']
self.raw_bytes = raw_bytes
else:
raise Exception("cannot initialize transaction", raw)
self._inputs = None
Expand All @@ -641,6 +648,7 @@ def __init__(self, raw, expect_trailing_data=False):
self.is_partial_originally = True
self._segwit_ser = None # None means "don't know"
self.expect_trailing_data = expect_trailing_data
self.expect_trailing_bytes = expect_trailing_bytes

def update(self, raw):
self.raw = raw
Expand Down Expand Up @@ -717,23 +725,32 @@ def add_signature_to_txin(cls, txin, signingPos, sig):
txin['witness'] = None # force re-serialization

def deserialize(self, force_full_parse=False):
if self.raw is None:
if self.raw is None and self.raw_bytes is None:
return
#self.raw = self.serialize()
if self._inputs is not None:
return
if self.expect_trailing_data:
d, trailing_data = deserialize(self.raw, force_full_parse, expect_trailing_data=self.expect_trailing_data)
d, trailing_data = deserialize(self.raw, force_full_parse, expect_trailing_data=self.expect_trailing_data, raw_bytes=self.raw_bytes, expect_trailing_bytes=self.expect_trailing_bytes)
else:
d = deserialize(self.raw, force_full_parse)
d = deserialize(self.raw, force_full_parse, raw_bytes=self.raw_bytes)
self._inputs = d['inputs']
self._outputs = [(x['type'], x['address'], x['value']) for x in d['outputs']]
self.locktime = d['lockTime']
self.version = d['version']
self.is_partial_originally = d['partial']
self._segwit_ser = d['segwit_ser']
if self.expect_trailing_data:
self.raw = self.raw[:-len(trailing_data)]
if self.expect_trailing_bytes:
if self.raw is not None:
self.raw = self.raw[:(-2*len(trailing_data))]
if self.raw_bytes is not None:
self.raw_bytes = self.raw_bytes[:-len(trailing_data)]
else:
if self.raw is not None:
self.raw = self.raw[:-len(trailing_data)]
if self.raw_bytes is not None:
self.raw_bytes = self.raw_bytes[:(-len(trailing_data)//2)]
self.expect_trailing_data = False
return d, trailing_data
else:
Expand Down

0 comments on commit f6702cd

Please sign in to comment.