async def listen(self, maddr: Multiaddr, nursery: trio.Nursery) -> None: """ put listener in listening mode and wait for incoming connections. :param maddr: maddr of peer :return: return True if successful """ async def serve_tcp( handler: Callable[[trio.SocketStream], Awaitable[None]], port: int, host: str, task_status: TaskStatus[Sequence[trio.SocketListener]] = None, ) -> None: """Just a proxy function to add logging here.""" logger.debug("serve_tcp %s %s", host, port) await trio.serve_tcp(handler, port, host=host, task_status=task_status) async def handler(stream: trio.SocketStream) -> None: tcp_stream = TrioTCPStream(stream) await self.handler(tcp_stream) listeners = await nursery.start( serve_tcp, handler, int(maddr.value_for_protocol("tcp")), maddr.value_for_protocol("ip4"), ) self.listeners.extend(listeners)
async def make_p2pd_pair_unix( daemon_executable: str, enable_control: bool, enable_connmgr: bool, enable_dht: bool, enable_pubsub: bool, ) -> AsyncIterator[DaemonTuple]: name = str(uuid.uuid4())[:8] control_maddr = Multiaddr(f"/unix/tmp/test_p2pd_control_{name}.sock") listen_maddr = Multiaddr(f"/unix/tmp/test_p2pd_listen_{name}.sock") # Remove the existing unix socket files if they are existing try: os.unlink(control_maddr.value_for_protocol(protocols.P_UNIX)) except FileNotFoundError: pass try: os.unlink(listen_maddr.value_for_protocol(protocols.P_UNIX)) except FileNotFoundError: pass async with make_p2pd_pair( daemon_executable=daemon_executable, control_maddr=control_maddr, listen_maddr=listen_maddr, enable_control=enable_control, enable_connmgr=enable_connmgr, enable_dht=enable_dht, enable_pubsub=enable_pubsub, ) as pair: yield pair
async def dial_peer_maddr(self, maddr: Multiaddr) -> None: """ Parse `maddr`, get the ip:port and PeerID, and call `dial_peer` with the parameters. """ ip = maddr.value_for_protocol(protocols.P_IP4) port = maddr.value_for_protocol(protocols.P_TCP) peer_id = ID.from_base58(maddr.value_for_protocol(protocols.P_P2P)) await self.dial_peer(ip=ip, port=port, peer_id=peer_id)
async def dial(self, maddr: Multiaddr) -> IRawConnection: """ dial a transport to peer listening on multiaddr :param maddr: multiaddr of peer :return: `RawConnection` if successful """ self.host = maddr.value_for_protocol("ip4") self.port = int(maddr.value_for_protocol("tcp")) reader, writer = await asyncio.open_connection(self.host, self.port) return RawConnection(reader, writer, True)
async def dial_peer_maddr(self, maddr: Multiaddr) -> None: """ Parse `maddr`, get the ip:port and PeerID, and call `dial_peer` with the parameters. """ try: ip = maddr.value_for_protocol(protocols.P_IP4) port = maddr.value_for_protocol(protocols.P_TCP) peer_id = ID.from_base58(maddr.value_for_protocol(protocols.P_P2P)) await self.dial_peer_with_retries(ip=ip, port=port, peer_id=peer_id) except Exception: traceback.print_exc() raise
def multiAddrTcp4(maddr): ipaddr, port = None, 0 try: multi = Multiaddr(maddr) except BaseException: return ipaddr, port for proto in multi.protocols(): if proto.name == 'ip4': ipaddr = multi.value_for_protocol(proto.code) if proto.name == 'tcp': port = int(multi.value_for_protocol(proto.code)) return ipaddr, port
def multiAddrTcp4(maddr): ipaddr, port = None, 0 try: multi = Multiaddr(maddr) except BaseException as err: log.debug(f'Invalid multiaddr {maddr}, error: {err}') return ipaddr, port for proto in multi.protocols(): if proto.name == 'ip4': ipaddr = multi.value_for_protocol(proto.code) if proto.name == 'tcp': port = int(multi.value_for_protocol(proto.code)) return ipaddr, port
async def dial_peer_maddr_with_retries(self, maddr: Multiaddr) -> None: """ Dial the peer with given multi-address repeatedly for `DIAL_RETRY_COUNT` times """ try: p2p_id = maddr.value_for_protocol(protocols.P_P2P) except (BinaryParseError, ProtocolLookupError) as error: self.logger.debug("Invalid maddr: %s, error: %s", maddr, error) raise DialPeerError from error peer_id = ID.from_base58(p2p_id) for i in range(DIAL_RETRY_COUNT): try: # exponential backoff... await asyncio.sleep(2**i + random.random()) await self.dial_peer_maddr(maddr, peer_id) return except DialPeerError: self.logger.debug( "Could not dial peer: %s, maddr: %s retrying attempt %d of %d...", peer_id, maddr, i, DIAL_RETRY_COUNT, ) continue raise DialPeerError
async def dial(self, maddr: Multiaddr) -> IRawConnection: """ dial a transport to peer listening on multiaddr :param maddr: multiaddr of peer :return: `RawConnection` if successful :raise OpenConnectionError: raised when failed to open connection """ self.host = maddr.value_for_protocol("ip4") self.port = int(maddr.value_for_protocol("tcp")) try: reader, writer = await asyncio.open_connection( self.host, self.port) except (ConnectionAbortedError, ConnectionRefusedError) as error: raise OpenConnectionError(error) return RawConnection(reader, writer, True)
async def dial(self, maddr: Multiaddr) -> IRawConnection: """ dial a transport to peer listening on multiaddr. :param maddr: multiaddr of peer :return: `RawConnection` if successful :raise OpenConnectionError: raised when failed to open connection """ self.host = maddr.value_for_protocol("ip4") self.port = int(maddr.value_for_protocol("tcp")) try: stream = await trio.open_tcp_stream(self.host, self.port) except OSError as error: raise OpenConnectionError from error read_write_closer = TrioTCPStream(stream) return RawConnection(read_write_closer, True)
async def make_p2pd_pair_unix( id_generator, enable_control, enable_connmgr, enable_dht, enable_pubsub): socket_id = id_generator() control_maddr = Multiaddr(f"/unix/tmp/test_p2pd_control_{socket_id}.sock") listen_maddr = Multiaddr(f"/unix/tmp/test_p2pd_listen_{socket_id}.sock") # remove the existing unix socket files if they are existing try: os.unlink(control_maddr.value_for_protocol(protocols.P_UNIX)) except FileNotFoundError: pass try: os.unlink(listen_maddr.value_for_protocol(protocols.P_UNIX)) except FileNotFoundError: pass return await _make_p2pd_pair( control_maddr=control_maddr, listen_maddr=listen_maddr, enable_control=enable_control, enable_connmgr=enable_connmgr, enable_dht=enable_dht, enable_pubsub=enable_pubsub, )
async def listen(self, maddr: Multiaddr) -> bool: """ put listener in listening mode and wait for incoming connections :param maddr: maddr of peer :return: return True if successful """ self.server = await asyncio.start_server( self.handler, maddr.value_for_protocol("ip4"), maddr.value_for_protocol("tcp"), ) socket = self.server.sockets[0] self.multiaddrs.append(_multiaddr_from_socket(socket)) return True
async def add_peer_from_maddr(self, maddr: Multiaddr) -> None: """ Connect to the eth2 peer at ``maddr`` and incorporate them into our view of the network. """ peer_id_encoded = maddr.value_for_protocol("p2p") peer_id = PeerID.from_base58(peer_id_encoded) try: await self.connect(PeerInfo(peer_id=peer_id, addrs=[maddr])) local_status = self._status_provider() remote_status = await self.exchange_status(peer_id, local_status) if self._peer_is_compatible(local_status, remote_status): self._peers.add(peer_id) await self._peer_updater(peer_id, remote_status) else: await self.disconnect(peer_id) except Exception as e: self.logger.exception(e)
def __init__( self, local_node_key: PrivateKey, eth2_config: Eth2Config, clock: Clock, chain: BaseBeaconChain, validator_api_port: int, client_identifier: str, p2p_maddr: Multiaddr, preferred_nodes: Collection[Multiaddr], bootstrap_nodes: Collection[Multiaddr], ) -> None: self._local_key_pair = create_new_key_pair(local_node_key.to_bytes()) self._eth2_config = eth2_config self._clock = clock self._chain = chain self._block_pool: Set[SignedBeaconBlock] = set() self._slashable_block_pool: Set[SignedBeaconBlock] = set() # FIXME: can we provide `p2p_maddr` as a default listening interface for `_mk_host`? peer_id = PeerID.from_pubkey(self._local_key_pair.public_key) if "p2p" in p2p_maddr: existing_peer_id = p2p_maddr.value_for_protocol("p2p") existing_p2p_maddr = Multiaddr(f"/p2p/{existing_peer_id}") self.logger.warning( "peer identity derived from local key pair %s overriding given identity %s", peer_id, existing_peer_id, ) p2p_maddr = p2p_maddr.decapsulate(existing_p2p_maddr) self._p2p_maddr = p2p_maddr.encapsulate(Multiaddr(f"/p2p/{peer_id}")) # TODO: persist metadata and handle updates... self._metadata_provider = lambda: MetaData.create() self._peer_updater, self._peer_updates = trio.open_memory_channel[ Tuple[PeerID, Any]](0) self._host = Host( self._local_key_pair, peer_id, self._accept_peer_updates, self._get_status, self._get_finalized_root_by_epoch, self._get_block_by_slot, self._get_block_by_root, self._metadata_provider, self._get_fork_digest, self._eth2_config, ) self._preferred_nodes = preferred_nodes self._bootstrap_nodes = bootstrap_nodes self._sync_notifier, self._sync_requests = trio.open_memory_channel[ SyncRequest](0) self._syncer = _mk_syncer() api_context = Context( client_identifier, eth2_config, self._syncer, self._chain, self._clock, _mk_block_broadcaster(self), ) self.validator_api_port = validator_api_port self._validator_api_server = _mk_validator_api_server( self.validator_api_port, api_context)
def _derive_port(maddr: Multiaddr, orchestration_profile: str) -> Multiaddr: offset = ord(orchestration_profile[:1]) - ord("a") port = int(maddr.value_for_protocol("tcp")) + offset return Multiaddr.join(f"/ip4/{maddr.value_for_protocol('ip4')}", f"/tcp/{port}")