async def prepare_outgoing_message( self, receiver_node_id: NodeID, message: BaseMessage, ) -> OutgoingMessage: try: enr = await self.enr_db.get(receiver_node_id) except KeyError: raise ValueError( f"No ENR for peer {encode_hex(receiver_node_id)} known") try: ip_address = enr[IP_V4_ADDRESS_ENR_KEY] except KeyError: raise ValueError( f"ENR for peer {encode_hex(receiver_node_id)} does not contain an IP address" ) try: udp_port = enr[UDP_PORT_ENR_KEY] except KeyError: raise ValueError( f"ENR for peer {encode_hex(receiver_node_id)} does not contain a UDP port" ) outgoing_message = OutgoingMessage( message=message, receiver_endpoint=Endpoint( ip_address, udp_port, ), receiver_node_id=receiver_node_id, ) return outgoing_message
async def test_datagram_sender(socket_pair): sending_socket, receiving_socket = socket_pair receiver_endpoint = receiving_socket.getsockname() sender_endpoint = sending_socket.getsockname() send_channel, receive_channel = trio.open_memory_channel(1) async with background_trio_service(DatagramSender(receive_channel, sending_socket)): outgoing_datagram = OutgoingDatagram( b"some packet", Endpoint(inet_aton(receiver_endpoint[0]), receiver_endpoint[1]), ) await send_channel.send(outgoing_datagram) with trio.fail_after(0.5): data, sender = await receiving_socket.recvfrom(1024) assert data == outgoing_datagram.datagram assert sender == sender_endpoint
async def ping(self, node_id: NodeID) -> None: local_enr = await self.get_local_enr() ping = PingMessage( request_id=self.message_dispatcher.get_free_request_id(node_id), enr_seq=local_enr.sequence_number, ) try: with trio.fail_after(REQUEST_RESPONSE_TIMEOUT): incoming_message = await self.message_dispatcher.request( node_id, ping) except ValueError as value_error: self.logger.warning( f"Failed to send ping to %s: %s", encode_hex(node_id), value_error, ) except trio.TooSlowError: self.logger.warning(f"Ping to %s timed out", encode_hex(node_id)) else: if not isinstance(incoming_message.message, PongMessage): self.logger.warning( "Peer %s responded to Ping with %s instead of Pong", encode_hex(node_id), incoming_message.message.__class__.__name__, ) else: self.logger.debug("Received Pong from %s", encode_hex(node_id)) self.update_routing_table(node_id) pong = incoming_message.message local_endpoint = Endpoint( ip_address=pong.packet_ip, port=pong.packet_port, ) endpoint_vote = EndpointVote( endpoint=local_endpoint, node_id=node_id, timestamp=time.monotonic(), ) await self.endpoint_vote_send_channel.send(endpoint_vote) await self.maybe_request_remote_enr(incoming_message)
async def get_endpoint_from_node_db(self, receiver_node_id: NodeID) -> Endpoint: try: enr = self.node_db.get_enr(receiver_node_id) except KeyError: raise ValueError(f"No ENR for peer {encode_hex(receiver_node_id)} known") try: ip_address = enr[IP_V4_ADDRESS_ENR_KEY] except KeyError: raise ValueError( f"ENR for peer {encode_hex(receiver_node_id)} does not contain an IP address" ) try: udp_port = enr[UDP_PORT_ENR_KEY] except KeyError: raise ValueError( f"ENR for peer {encode_hex(receiver_node_id)} does not contain a UDP port" ) return Endpoint(ip_address, udp_port)