diff --git a/electrum/interface.py b/electrum/interface.py index 36cfb13c4..1e42fce6d 100644 --- a/electrum/interface.py +++ b/electrum/interface.py @@ -328,6 +328,9 @@ class PaddedRSTransport(RSTransport): MIN_PACKET_SIZE = 1024 WAIT_FOR_BUFFER_GROWTH_SECONDS = 1.0 + # (unpadded) amount of bytes sent instantly before beginning with polling. + # This makes the initial handshake where a few small messages are exchanged faster. + WARMUP_BUDGET_SIZE = 1024 session: Optional['RPCSession'] @@ -361,6 +364,7 @@ class PaddedRSTransport(RSTransport): self._force_send or len(buf) >= self.MIN_PACKET_SIZE or self._last_send + self.WAIT_FOR_BUFFER_GROWTH_SECONDS < time.monotonic() + or self.session.send_size < self.WARMUP_BUDGET_SIZE ): return assert buf[-2:] in (b"}\n", b"]\n"), f"unexpected json-rpc terminator: {buf[-2:]=!r}" @@ -950,6 +954,7 @@ class Interface(Logger): proxy=self.proxy, transport=PaddedRSTransport, ) as session: + start = time.perf_counter() self.session = session # type: NotificationSession self.session.set_default_timeout(self.network.get_network_timeout_seconds(NetworkTimeout.Generic)) try: @@ -964,7 +969,15 @@ class Interface(Logger): if not self.network.check_interface_against_healthy_spread_of_connected_servers(self): raise GracefulDisconnect(f'too many connected servers already ' f'in bucket {self.bucket_based_on_ipaddress()}') - self.logger.info(f"connection established. version: {ver}") + + try: + features = await session.send_request('server.features') + server_genesis_hash = assert_dict_contains_field(features, field_name='genesis_hash') + except (aiorpcx.jsonrpc.RPCError, RequestCorrupted) as e: + raise GracefulDisconnect(e) + if server_genesis_hash != constants.net.GENESIS: + raise GracefulDisconnect(f'server on different chain: {server_genesis_hash=}. ours: {constants.net.GENESIS}') + self.logger.info(f"connection established. version: {ver}, handshake duration: {(time.perf_counter() - start) * 1000:.2f} ms") try: async with self.taskgroup as group: diff --git a/tests/test_interface.py b/tests/test_interface.py index da4f607cd..07b13338e 100644 --- a/tests/test_interface.py +++ b/tests/test_interface.py @@ -11,6 +11,7 @@ from electrum.util import OldTaskGroup, bfh from electrum.logging import Logger from electrum.simple_config import SimpleConfig from electrum.transaction import Transaction +from electrum import constants from . import ElectrumTestCase @@ -130,6 +131,7 @@ class ServerSession(aiorpcx.RPCSession, Logger): async def handle_request(self, request): handlers = { 'server.version': self._handle_server_version, + 'server.features': self._handle_server_features, 'blockchain.estimatefee': self._handle_estimatefee, 'blockchain.headers.subscribe': self._handle_headers_subscribe, 'blockchain.block.header': self._handle_block_header, @@ -146,6 +148,17 @@ class ServerSession(aiorpcx.RPCSession, Logger): async def _handle_server_version(self, client_name='', protocol_version=None): return ['best_server_impl/0.1', '1.4'] + async def _handle_server_features(self) -> dict: + return { + 'genesis_hash': constants.net.GENESIS, + 'hosts': {"14.3.140.101": {"tcp_port": 51001, "ssl_port": 51002}}, + 'protocol_max': '1.7.0', + 'protocol_min': '1.4.3', + 'pruning': None, + 'server_version': 'ElectrumX 1.19.0', + 'hash_function': 'sha256', + } + async def _handle_estimatefee(self, number, mode=None): return 1000