diff --git a/docs/PERFORMANCE-NOTES b/docs/PERFORMANCE-NOTES index 629cc96..9335a7b 100644 --- a/docs/PERFORMANCE-NOTES +++ b/docs/PERFORMANCE-NOTES @@ -1,4 +1,4 @@ -Just some notes on performance with Python 3.5. I am taking this into +Just some notes on performance with Python 3.5. We are taking these into account in the code. - 60% faster to create lists with [] list comprehensions than tuples @@ -16,11 +16,21 @@ account in the code. - struct.pack, struct.unpack are over 60% faster than int.to_bytes and int.from_bytes. They are faster little endian (presumably because - it matches the host) than big endian regardless of length. + it matches the host) than big endian regardless of length. Furthermore, + using stored packing and unpacking methods from Struct classes is faster + than using the flexible-format struct.[un]pack equivalents. + + After storing the Struct('= end + assert self.binary_length >= end return self.binary[cursor:end] def _read_varbytes(self): @@ -149,27 +151,27 @@ class Deserializer(object): return self._read_le_uint64() def _read_le_int32(self): - result, = unpack_from('= len(tx.outputs): return None diff --git a/server/daemon.py b/server/daemon.py index 3bfa4f0..a0f6e32 100644 --- a/server/daemon.py +++ b/server/daemon.py @@ -18,7 +18,7 @@ from time import strptime import aiohttp -import lib.util as util +from lib.util import LoggedClass, int_to_varint, hex_to_bytes from lib.hash import hex_str_to_hash @@ -26,7 +26,7 @@ class DaemonError(Exception): '''Raised when the daemon returns an error in its results.''' -class Daemon(util.LoggedClass): +class Daemon(LoggedClass): '''Handles connections to a daemon at the given URL.''' WARMING_UP = -28 @@ -208,7 +208,7 @@ class Daemon(util.LoggedClass): params_iterable = ((h, False) for h in hex_hashes) blocks = await self._send_vector('getblock', params_iterable) # Convert hex string to bytes - return [bytes.fromhex(block) for block in blocks] + return [hex_to_bytes(block) for block in blocks] async def mempool_hashes(self): '''Update our record of the daemon's mempool hashes.''' @@ -240,7 +240,7 @@ class Daemon(util.LoggedClass): txs = await self._send_vector('getrawtransaction', params_iterable, replace_errs=replace_errs) # Convert hex strings to bytes - return [bytes.fromhex(tx) if tx else None for tx in txs] + return [hex_to_bytes(tx) if tx else None for tx in txs] async def sendrawtransaction(self, params): '''Broadcast a transaction to the network.''' @@ -336,7 +336,7 @@ class LegacyRPCDaemon(Daemon): raw_block = header num_txs = len(transactions) if num_txs > 0: - raw_block += util.int_to_varint(num_txs) + raw_block += int_to_varint(num_txs) raw_block += b''.join(transactions) else: raw_block += b'\x00' diff --git a/tests/lib/test_util.py b/tests/lib/test_util.py index f84a6d2..74411b4 100644 --- a/tests/lib/test_util.py +++ b/tests/lib/test_util.py @@ -57,6 +57,7 @@ def test_increment_byte_string(): assert util.increment_byte_string(b'\x01\x01') == b'\x01\x02' assert util.increment_byte_string(b'\xff\xff') is None + def test_is_valid_hostname(): is_valid_hostname = util.is_valid_hostname assert not is_valid_hostname('') @@ -116,3 +117,22 @@ def test_protocol_version(): assert util.protocol_version(["0.8", "0.9"], "1.0", "1.1") is None assert util.protocol_version(["1.1", "1.2"], "1.0", "1.1") == (1, 1) assert util.protocol_version(["1.2", "1.3"], "1.0", "1.1") is None + + +def test_unpackers(): + b = bytes(range(256)) + assert util.unpack_int32_from(b, 0) == (50462976,) + assert util.unpack_int32_from(b, 42) == (757869354,) + assert util.unpack_int64_from(b, 0) == (506097522914230528,) + assert util.unpack_int64_from(b, 42) == (3544384782113450794,) + + assert util.unpack_uint16_from(b, 0) == (256,) + assert util.unpack_uint16_from(b, 42) == (11050,) + assert util.unpack_uint32_from(b, 0) == (50462976,) + assert util.unpack_uint32_from(b, 42) == (757869354,) + assert util.unpack_uint64_from(b, 0) == (506097522914230528,) + assert util.unpack_uint64_from(b, 42) == (3544384782113450794,) + +def test_hex_transforms(): + h = "AABBCCDDEEFF" + assert util.hex_to_bytes(h) == b'\xaa\xbb\xcc\xdd\xee\xff' \ No newline at end of file