diff --git a/btclib_node/__init__.py b/btclib_node/__init__.py index 766f0b7..d511526 100644 --- a/btclib_node/__init__.py +++ b/btclib_node/__init__.py @@ -47,17 +47,11 @@ def sigint_handler(signal, frame): self.download_window = [] - if config.p2p_port: - self.p2p_port = config.p2p_port - else: - self.p2p_port = None + self.p2p_port = config.p2p_port or None peer_db = PeerDB(self.chain, self.data_dir) self.p2p_manager = P2pManager(self, self.p2p_port, peer_db) - if config.rpc_port: - self.rpc_port = config.rpc_port - else: - self.rpc_port = None + self.rpc_port = config.rpc_port or None self.rpc_manager = RpcManager(self, self.rpc_port) def run(self): diff --git a/btclib_node/block_db/__init__.py b/btclib_node/block_db/__init__.py index a3a2a89..88887f7 100644 --- a/btclib_node/block_db/__init__.py +++ b/btclib_node/block_db/__init__.py @@ -20,12 +20,12 @@ def deserialize(cls, data, check_validity=False): stream = bytesio_from_binarydata(data) hash = stream.read(32) to_add = [] - for x in range(var_int.parse(stream)): + for _ in range(var_int.parse(stream)): out_point = OutPoint.parse(stream, check_validity) tx_out = TxOut.parse(stream, check_validity) to_add.append([out_point, tx_out]) to_remove = [] - for x in range(var_int.parse(stream)): + for _ in range(var_int.parse(stream)): out_point = OutPoint.parse(stream, check_validity) to_remove.append(out_point) return cls(hash, to_add, to_remove) @@ -175,8 +175,7 @@ def __add_data_to_file(self, file, data): def __get_data_from_file(self, file, index, size): file.seek(index) - data = file.read(size) - return data + return file.read(size) def add_block(self, block): block_hash = block.header.hash diff --git a/btclib_node/chainstate.py b/btclib_node/chainstate.py index df08dba..762cafd 100644 --- a/btclib_node/chainstate.py +++ b/btclib_node/chainstate.py @@ -49,13 +49,12 @@ def add_block(self, block): self.updated_utxo_set.pop(prevout_bytes) else: prevout = self.db.get(prevout_bytes) - if prevout: - prevout = TxOut.parse(prevout, check_validity=False) - prev_outputs.append(prevout) - self.removed_utxos.add(prevout_bytes) - else: + if not prevout: raise Exception + prevout = TxOut.parse(prevout, check_validity=False) + prev_outputs.append(prevout) + self.removed_utxos.add(prevout_bytes) removed.append((tx_in.prev_out, prevout)) for i, tx_out in enumerate(tx.vout): @@ -80,11 +79,10 @@ def apply_rev_block(self, rev_block): raise Exception if out_point_bytes in self.updated_utxo_set: self.updated_utxo_set.pop(out_point_bytes) + elif self.db.get(out_point_bytes): + self.removed_utxos.add(out_point_bytes) else: - if self.db.get(out_point_bytes): - self.removed_utxos.add(out_point_bytes) - else: - raise Exception + raise Exception for out_point, tx_out in rev_block.to_add: self.updated_utxo_set[out_point.serialize(check_validity=False)] = tx_out diff --git a/btclib_node/config.py b/btclib_node/config.py index f035f6c..d6e6d55 100644 --- a/btclib_node/config.py +++ b/btclib_node/config.py @@ -40,10 +40,7 @@ def __init__( else: raise ValueError - if data_dir: - data_dir = Path(data_dir) - else: - data_dir = Path.home() / ".btclib" + data_dir = Path(data_dir) if data_dir else Path.home() / ".btclib" self.data_dir = data_dir.absolute() / self.chain.name self.p2p_port = None diff --git a/btclib_node/download.py b/btclib_node/download.py index b2470df..38e66c1 100644 --- a/btclib_node/download.py +++ b/btclib_node/download.py @@ -5,46 +5,47 @@ def block_download(node): - if node.status >= NodeStatus.HeaderSynced: + if node.status < NodeStatus.HeaderSynced: + return + if not node.download_window: + node.download_window = node.index.get_download_candidates() + node.download_window = [ + x + for x in node.download_window + if not node.index.get_block_info(x).downloaded + ] + if not node.download_window: + return - if not node.download_window: - node.download_window = node.index.get_download_candidates() - node.download_window = [ - x - for x in node.download_window - if not node.index.get_block_info(x).downloaded + connections = list(node.p2p_manager.connections.values()) + pending = [] + exit = True + for conn in connections: + conn_queue = conn.block_download_queue + new_queue = [ + header + for header in conn_queue + if not node.index.get_block_info(header).downloaded ] - if not node.download_window: - return + conn.block_download_queue = new_queue + pending.extend(new_queue) + if not new_queue: + exit = False + if exit: + return - connections = list(node.p2p_manager.connections.values()) - pending = [] - exit = True - for conn in connections: - conn_queue = conn.block_download_queue - new_queue = [] - for header in conn_queue: - if not node.index.get_block_info(header).downloaded: - new_queue.append(header) - conn.block_download_queue = new_queue - pending.extend(new_queue) - if not new_queue: - exit = False - if exit: - return + waiting = [header for header in node.download_window if header not in pending] + pending = [x[0] for x in Counter(pending).most_common()[::-1]] - waiting = [header for header in node.download_window if header not in pending] - pending = [x[0] for x in Counter(pending).most_common()[::-1]] - - for conn in connections: - if conn.block_download_queue == []: - if waiting: - new = waiting[:16] - waiting = waiting[16:] - elif pending: - new = pending[:4] - pending = pending[4:] - else: - return - conn.block_download_queue = new - conn.send(Getdata([(0x40000002, hash) for hash in new])) + for conn in connections: + if conn.block_download_queue == []: + if waiting: + new = waiting[:16] + waiting = waiting[16:] + elif pending: + new = pending[:4] + pending = pending[4:] + else: + return + conn.block_download_queue = new + conn.send(Getdata([(0x40000002, hash) for hash in new])) diff --git a/btclib_node/index/__init__.py b/btclib_node/index/__init__.py index 7c1be79..9e97f79 100644 --- a/btclib_node/index/__init__.py +++ b/btclib_node/index/__init__.py @@ -110,10 +110,11 @@ def calculate_chainwork(self): block_info.chainwork = old_work + calculate_work(block_info.header) def generate_active_chain(self): - chain_dict = {} - for block_hash, block_info in self.header_dict.items(): - if block_info.status == BlockStatus.in_active_chain: - chain_dict[block_info.index] = block_hash + chain_dict = { + block_info.index: block_hash + for block_hash, block_info in self.header_dict.items() + if block_info.status == BlockStatus.in_active_chain + } for index in sorted(chain_dict.keys()): self.active_chain.append(chain_dict[index]) @@ -264,7 +265,7 @@ def get_download_candidates(self): break if not block_info.downloaded: new_candidates.append(candidate) - candidates = candidates + new_candidates[::-1] + candidates += new_candidates[::-1] return candidates[:1024] # return a list of block hashes looking at the current best chain @@ -272,9 +273,7 @@ def get_block_locator_hashes(self): i = 1 step = 1 block_locators = [] - while True: - if i > len(self.header_index): - break + while i <= len(self.header_index): block_locators.append(self.header_index[-i]) if i >= 10: step *= 2 diff --git a/btclib_node/log.py b/btclib_node/log.py index 9ef1c94..1e65d95 100644 --- a/btclib_node/log.py +++ b/btclib_node/log.py @@ -4,10 +4,7 @@ class Logger(logging.Logger): def __init__(self, filepath=None, debug=False, **kwargs): super().__init__(name="Logger", level=logging.DEBUG, **kwargs) - if debug: - handler = logging.StreamHandler() - else: - handler = logging.FileHandler(filepath) + handler = logging.StreamHandler() if debug else logging.FileHandler(filepath) formatter = logging.Formatter("%(asctime)s - %(message)s") handler.setFormatter(formatter) self.addHandler(handler) diff --git a/btclib_node/mempool.py b/btclib_node/mempool.py index 99815a4..321094f 100644 --- a/btclib_node/mempool.py +++ b/btclib_node/mempool.py @@ -15,15 +15,11 @@ def is_full(self): def get_missing(self, transactions): missing = [] if not self.is_full(): - for tx in transactions: - if tx not in self.transactions: - missing.append(tx) + missing.extend(tx for tx in transactions if tx not in self.transactions) return missing def get_tx(self, txid): - if txid in self.transactions: - return self.transactions[txid] - return None + return self.transactions[txid] if txid in self.transactions else None def add_tx(self, tx): if not self.is_full(): diff --git a/btclib_node/p2p/address.py b/btclib_node/p2p/address.py index 428dd21..4bcb2e9 100644 --- a/btclib_node/p2p/address.py +++ b/btclib_node/p2p/address.py @@ -11,7 +11,7 @@ def to_ipv6(ip): try: return IPv6Address(ip) except AddressValueError: - return IPv6Address("::ffff:" + ip) + return IPv6Address(f"::ffff:{ip}") @dataclass @@ -24,10 +24,7 @@ class NetworkAddress: @classmethod def deserialize(cls, data, version_msg=False): stream = bytesio_from_binarydata(data) - if not version_msg: - time = int.from_bytes(stream.read(4), "little") - else: - time = 0 + time = 0 if version_msg else int.from_bytes(stream.read(4), "little") services = int.from_bytes(stream.read(8), "little") a = stream.read(16) ip = IPv6Address(a) diff --git a/btclib_node/p2p/callbacks.py b/btclib_node/p2p/callbacks.py index d2a7b85..c356a9a 100644 --- a/btclib_node/p2p/callbacks.py +++ b/btclib_node/p2p/callbacks.py @@ -110,28 +110,24 @@ def inv(node, msg, conn): if node.status < NodeStatus.BlockSynced: return - transactions = [x[1] for x in inv.inventory if x[0] == 1 or x[0] == 0x40000001] - blocks = [x[1] for x in inv.inventory if x[0] == 2 or x[0] == 0x40000002] - if blocks: + transactions = [x[1] for x in inv.inventory if x[0] in [1, 0x40000001]] + if blocks := [x[1] for x in inv.inventory if x[0] in [2, 0x40000002]]: block_locators = node.index.get_block_locator_hashes() conn.send(Getheaders(ProtocolVersion, block_locators, blocks[-1])) - missing_tx = node.mempool.get_missing(transactions) - if missing_tx: + if missing_tx := node.mempool.get_missing(transactions): conn.send(Getdata([(0x40000001, tx) for tx in missing_tx])) def getdata(node, msg, conn): getdata = Getdata.deserialize(msg) - transactions = [x[1] for x in getdata.inventory if x[0] == 1 or x[0] == 0x40000001] - blocks = [x[1] for x in getdata.inventory if x[0] == 2 or x[0] == 0x40000002] + transactions = [x[1] for x in getdata.inventory if x[0] in [1, 0x40000001]] + blocks = [x[1] for x in getdata.inventory if x[0] in [2, 0x40000002]] for txid in transactions: - tx = node.mempool.get_tx(txid) - if tx: + if tx := node.mempool.get_tx(txid): conn.send(TxMsg(tx)) for block_hash in blocks: - block = node.block_db.get_block(block_hash) - if block: + if block := node.block_db.get_block(block_hash): conn.send(BlockMsg(block)) @@ -149,17 +145,15 @@ def headers(node, msg, conn): if len(headers) == 2000 and added: # we have to require more headers block_locators = node.index.get_block_locator_hashes() conn.send(Getheaders(ProtocolVersion, block_locators, b"\x00" * 32)) - else: - if node.status == NodeStatus.SyncingHeaders: - node.status = NodeStatus.HeaderSynced + elif node.status == NodeStatus.SyncingHeaders: + node.status = NodeStatus.HeaderSynced def getheaders(node, msg, conn): getheaders = Getheaders.deserialize(msg) - headers = node.index.get_headers_from_locators( + if headers := node.index.get_headers_from_locators( getheaders.block_hashes, getheaders.hash_stop - ) - if headers: + ): conn.send(Headers(headers)) diff --git a/btclib_node/p2p/main.py b/btclib_node/p2p/main.py index c8aa1fa..7962d9f 100644 --- a/btclib_node/p2p/main.py +++ b/btclib_node/p2p/main.py @@ -10,9 +10,7 @@ def handle_p2p_handshake(node): try: if conn.status == P2pConnStatus.Open: handshake_callbacks[msg_type](node, msg, conn) - elif conn.status == P2pConnStatus.Closed: - pass - else: + elif conn.status != P2pConnStatus.Closed: conn.stop() except Exception: conn.stop() @@ -28,9 +26,7 @@ def handle_p2p(node): if msg_type in callbacks: if conn.status == P2pConnStatus.Connected: callbacks[msg_type](node, msg, conn) - elif conn.status == P2pConnStatus.Closed: - pass - else: + elif conn.status != P2pConnStatus.Closed: conn.stop() node.logger.debug("Finished p2p\n") except Exception: diff --git a/btclib_node/p2p/manager.py b/btclib_node/p2p/manager.py index f2ec569..8edec7b 100644 --- a/btclib_node/p2p/manager.py +++ b/btclib_node/p2p/manager.py @@ -66,10 +66,7 @@ async def manage_connections(self, loop): conn.ping_nonce = ping_msg.nonce elif now - conn.ping_sent > 120: self.remove_connection(conn.id) - if self.node.status < NodeStatus.HeaderSynced: - connection_num = 1 - else: - connection_num = 10 + connection_num = 1 if self.node.status < NodeStatus.HeaderSynced else 10 if len(self.connections) < connection_num and not self.peer_db.is_empty(): already_connected = [conn.address for conn in self.connections.values()] try: diff --git a/btclib_node/p2p/messages/address.py b/btclib_node/p2p/messages/address.py index d11ff06..7adebbf 100644 --- a/btclib_node/p2p/messages/address.py +++ b/btclib_node/p2p/messages/address.py @@ -16,9 +16,7 @@ class Addr: def deserialize(cls, data): stream = bytesio_from_binarydata(data) len_addresses = var_int.parse(stream) - addresses = [] - for x in range(len_addresses): - addresses.append(NetworkAddress.deserialize(stream)) + addresses = [NetworkAddress.deserialize(stream) for _ in range(len_addresses)] return cls(addresses=addresses) def serialize(self): diff --git a/btclib_node/p2p/messages/compact.py b/btclib_node/p2p/messages/compact.py index 86a8365..7499b48 100644 --- a/btclib_node/p2p/messages/compact.py +++ b/btclib_node/p2p/messages/compact.py @@ -40,13 +40,11 @@ def deserialize(cls, data): stream = bytesio_from_binarydata(data) header = BlockHeader.parse(stream) nonce = int.from_bytes(stream.read(8), "little") - short_ids = [] short_ids_length = var_int.parse(stream) - for x in range(short_ids_length): - short_ids.append(stream.read(6)[::-1]) + short_ids = [stream.read(6)[::-1] for _ in range(short_ids_length)] prefilled_tx_list = [] prefilled_tx_num = var_int.parse(stream) - for x in range(prefilled_tx_num): + for _ in range(prefilled_tx_num): tx_index = var_int.parse(stream) tx = Tx.parse(stream) prefilled_tx_list.append((tx_index, tx)) diff --git a/btclib_node/p2p/messages/data.py b/btclib_node/p2p/messages/data.py index b9f4bf9..7e91a59 100644 --- a/btclib_node/p2p/messages/data.py +++ b/btclib_node/p2p/messages/data.py @@ -49,7 +49,7 @@ def deserialize(cls, data): stream = bytesio_from_binarydata(data) headers_num = var_int.parse(stream) headers = [] - for x in range(headers_num): + for _ in range(headers_num): header = BlockHeader.parse(stream) stream.read(1) headers.append(header) @@ -74,9 +74,7 @@ def deserialize(cls, data): stream = bytesio_from_binarydata(data) blockhash = stream.read(32)[::-1] num_transactions = var_int.parse(stream) - transactions = [] - for x in range(num_transactions): - transactions.append(TxData.parse(stream)) + transactions = [TxData.parse(stream) for _ in range(num_transactions)] return cls(blockhash=blockhash, transactions=transactions) def serialize(self): @@ -96,7 +94,7 @@ def deserialize(cls, data): stream = bytesio_from_binarydata(data) inventory_length = var_int.parse(stream) inventory = [] - for x in range(inventory_length): + for _ in range(inventory_length): item_type = int.from_bytes(stream.read(4), "little") item_hash = stream.read(32)[::-1] inventory.append((item_type, item_hash)) diff --git a/btclib_node/p2p/messages/errors.py b/btclib_node/p2p/messages/errors.py index eeeadda..6c7c21f 100644 --- a/btclib_node/p2p/messages/errors.py +++ b/btclib_node/p2p/messages/errors.py @@ -17,7 +17,7 @@ def deserialize(cls, data): stream = bytesio_from_binarydata(data) inventory_length = var_int.parse(stream) inventory = [] - for x in range(inventory_length): + for _ in range(inventory_length): item_type = int.from_bytes(stream.read(4), "little") item_hash = stream.read(32)[::-1] inventory.append((item_type, item_hash)) diff --git a/btclib_node/p2p/messages/getdata.py b/btclib_node/p2p/messages/getdata.py index a0332e0..30811ee 100644 --- a/btclib_node/p2p/messages/getdata.py +++ b/btclib_node/p2p/messages/getdata.py @@ -16,7 +16,7 @@ def deserialize(cls, data): stream = bytesio_from_binarydata(data) inventory_length = var_int.parse(stream) inventory = [] - for x in range(inventory_length): + for _ in range(inventory_length): item_type = int.from_bytes(stream.read(4), "little") item_hash = stream.read(32)[::-1] inventory.append((item_type, item_hash)) @@ -41,7 +41,7 @@ def deserialize(cls, data): stream = bytesio_from_binarydata(data) version = int.from_bytes(stream.read(4), "little") block_hashes = [] - for x in range(var_int.parse(stream)): + for _ in range(var_int.parse(stream)): block_hash = stream.read(32)[::-1] block_hashes.append(block_hash) hash_stop = stream.read(32)[::-1] @@ -67,7 +67,7 @@ def deserialize(cls, data): stream = bytesio_from_binarydata(data) version = int.from_bytes(stream.read(4), "little") block_hashes = [] - for x in range(var_int.parse(stream)): + for _ in range(var_int.parse(stream)): block_hash = stream.read(32)[::-1] block_hashes.append(block_hash) hash_stop = stream.read(32)[::-1] @@ -92,9 +92,7 @@ def deserialize(cls, data): stream = bytesio_from_binarydata(data) blockhash = stream.read(32)[::-1] num_indexes = var_int.parse(stream) - indexes = [] - for x in range(num_indexes): - indexes.append(var_int.parse(stream)) + indexes = [var_int.parse(stream) for _ in range(num_indexes)] return cls(blockhash=blockhash, indexes=indexes) def serialize(self): diff --git a/btclib_node/p2p/messages/ping.py b/btclib_node/p2p/messages/ping.py index 6534be8..fe69f22 100644 --- a/btclib_node/p2p/messages/ping.py +++ b/btclib_node/p2p/messages/ping.py @@ -11,10 +11,7 @@ class Ping: nonce: int def __init__(self, nonce=None): - if not nonce: - self.nonce = random.randint(0, 2 ** 64 - 1) - else: - self.nonce = nonce + self.nonce = nonce or random.randint(0, 2 ** 64 - 1) @classmethod def deserialize(cls, data): diff --git a/btclib_node/rpc/callbacks.py b/btclib_node/rpc/callbacks.py index 35590da..5d1b324 100644 --- a/btclib_node/rpc/callbacks.py +++ b/btclib_node/rpc/callbacks.py @@ -36,15 +36,13 @@ def get_peer_info(node, conn, _): addr = p2p_conn.client.getpeername() addrbind = p2p_conn.client.getsockname() - addrlocal_ip = p2p_conn.version_message.addr_from.ip.ipv4_mapped - if not addrlocal_ip: - addrlocal_ip = addrbind[0] - - conn_dict = {} - conn_dict["id"] = id - conn_dict["addr"] = f"{addr[0]}:{addr[1]}" - conn_dict["addrbind"] = f"{addrbind[0]}:{addrbind[1]}" - conn_dict["addrlocal"] = f"{addrlocal_ip}:{addrbind[1]}" + addrlocal_ip = p2p_conn.version_message.addr_from.ip.ipv4_mapped or addrbind[0] + conn_dict = { + "id": id, + "addr": f"{addr[0]}:{addr[1]}", + "addrbind": f"{addrbind[0]}:{addrbind[1]}", + "addrlocal": f"{addrlocal_ip}:{addrbind[1]}", + } out.append(conn_dict) return out diff --git a/btclib_node/rpc/connection.py b/btclib_node/rpc/connection.py index 379862b..e28e1f2 100644 --- a/btclib_node/rpc/connection.py +++ b/btclib_node/rpc/connection.py @@ -9,9 +9,7 @@ class JSONEncoder(json.JSONEncoder): def default(self, obj): - if isinstance(obj, bytes): - return obj.hex() - return super().default(obj) + return obj.hex() if isinstance(obj, bytes) else super().default(obj) class Connection: @@ -57,8 +55,7 @@ async def async_send(self, response): if len(response) == 1: response = response[0] output_str = json.dumps(response, separators=(",", ":"), cls=JSONEncoder) - response = "HTTP/1.1 200 OK\n" - response += "Content-Type: application/json\n" + response = "HTTP/1.1 200 OK\n" + "Content-Type: application/json\n" response += f"Content-Length: {len(output_str)+1}\n" response += "\n" # Important! response += output_str diff --git a/btclib_node/rpc/main.py b/btclib_node/rpc/main.py index 6923171..459d4fa 100644 --- a/btclib_node/rpc/main.py +++ b/btclib_node/rpc/main.py @@ -3,8 +3,7 @@ def get_connection(manager, id): try: - conn = manager.connections[id] - return conn + return manager.connections[id] except Exception: return None @@ -12,11 +11,7 @@ def get_connection(manager, id): def is_valid_rpc(request): if not isinstance(request, dict): return False - if "method" not in request: - return False - if "id" not in request: - return False - return True + return False if "method" not in request else "id" in request def error_msg(code): @@ -51,10 +46,7 @@ def handle_rpc(node): response.append(error_msg(-32601)) else: try: - if "params" in request: - params = request["params"] - else: - params = [] + params = request["params"] if "params" in request else [] response.append( { "jsonrpc": "2.0", diff --git a/tests/helpers.py b/tests/helpers.py index d4995eb..e51eeff 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -15,10 +15,7 @@ def generate_random_header_chain(length, start): # random.seed(42) chain = [] for x in range(length): - if chain: - previous_block_hash = chain[-1].hash - else: - previous_block_hash = start + previous_block_hash = chain[-1].hash if chain else start header = BlockHeader( version=70015, previous_block_hash=previous_block_hash, diff --git a/tests/unit/main.py b/tests/unit/main.py index c63b623..b65057a 100644 --- a/tests/unit/main.py +++ b/tests/unit/main.py @@ -24,6 +24,6 @@ def test(tmp_path): node.index.insert_block_info(block_info) for block in chain: node.block_db.add_block(block) - for x in range(len(chain)): + for _ in range(len(chain)): update_chain(node) assert len(node.index.active_chain) == length + 1