async def test_send_endpoint_vote(ping_sender, routing_table,
                                  incoming_message_channels,
                                  outgoing_message_channels,
                                  endpoint_vote_channels, local_enr,
                                  remote_enr, remote_endpoint):
    # wait for ping
    with trio.fail_after(ROUTING_TABLE_PING_INTERVAL):
        outgoing_message = await outgoing_message_channels[1].receive()
    ping = outgoing_message.message

    # respond with pong
    fake_local_endpoint = EndpointFactory()
    pong = PongMessage(
        request_id=ping.request_id,
        enr_seq=0,
        packet_ip=fake_local_endpoint.ip_address,
        packet_port=fake_local_endpoint.port,
    )
    incoming_message = IncomingMessage(
        message=pong,
        sender_endpoint=outgoing_message.receiver_endpoint,
        sender_node_id=outgoing_message.receiver_node_id,
    )
    await incoming_message_channels[0].send(incoming_message)
    await wait_all_tasks_blocked()

    # receive endpoint vote
    endpoint_vote = endpoint_vote_channels[1].receive_nowait()
    assert endpoint_vote.endpoint == fake_local_endpoint
    assert endpoint_vote.node_id == incoming_message.sender_node_id
Пример #2
0
    async def handle_incoming_packet_post_handshake(self, incoming_packet: IncomingPacket) -> None:
        if not self.is_post_handshake:
            raise ValueError("Can only handle packets post handshake")
        if self.session_keys is None:
            raise TypeError("session_keys are None even though handshake has been completed")

        if isinstance(incoming_packet.packet, AuthTagPacket):
            try:
                message = incoming_packet.packet.decrypt_message(
                    self.session_keys.decryption_key,
                    self.message_type_registry,
                )
            except DecryptionError:
                self.logger.info(
                    "Failed to decrypt message from peer, starting another handshake as recipient"
                )
                self.reset_handshake_state()
                await self.handle_incoming_packet_pre_handshake(incoming_packet)
            except ValidationError as validation_error:
                self.logger.warning("Received invalid packet: %s", validation_error)
                raise  # let the service fail
            else:
                incoming_message = IncomingMessage(
                    message,
                    incoming_packet.sender_endpoint,
                    self.remote_node_id,
                )
                self.logger.debug("Received %s", incoming_message)
                await self.incoming_message_send_channel.send(incoming_message)
        else:
            self.logger.debug(
                "Dropping %s as handshake has already been completed",
                incoming_packet,
            )
Пример #3
0
    async def respond_with_remote_enrs(
            self, incoming_message: IncomingMessage) -> None:
        """Send a Nodes message containing ENRs of peers at a given node distance."""
        node_ids = self.routing_table.get_nodes_at_log_distance(
            incoming_message.message.distance)

        enrs = []
        for node_id in node_ids:
            try:
                enr = self.node_db.get_enr(node_id)
            except KeyError:
                self.logger.warning("Missing ENR for node %s",
                                    encode_hex(node_id))
            else:
                enrs.append(enr)

        enr_partitions = partition_enrs(enrs,
                                        NODES_MESSAGE_PAYLOAD_SIZE) or ((), )
        self.logger.debug(
            "Responding to %s with %d Nodes message containing %d ENRs at distance %d",
            incoming_message.sender_endpoint,
            len(enr_partitions),
            len(enrs),
            incoming_message.message.distance,
        )
        for partition in enr_partitions:
            nodes_message = NodesMessage(
                request_id=incoming_message.message.request_id,
                total=len(enr_partitions),
                enrs=partition,
            )
            outgoing_message = incoming_message.to_response(nodes_message)
            await self.outgoing_message_send_channel.send(outgoing_message)
Пример #4
0
    async def handle_request_on_remote():
        async for outgoing_message in outgoing_message_channels[1]:
            assert outgoing_message.message == request
            assert outgoing_message.receiver_endpoint == remote_endpoint
            assert outgoing_message.receiver_node_id == remote_enr.node_id

            await incoming_message_channels[0].send(IncomingMessage(
                message=response,
                sender_endpoint=remote_endpoint,
                sender_node_id=remote_enr.node_id,
            ))
Пример #5
0
    async def respond_with_local_enr(
            self, incoming_message: IncomingMessage) -> None:
        """Send a Nodes message containing the local ENR in response to an incoming message."""
        local_enr = await self.get_local_enr()
        nodes_message = NodesMessage(
            request_id=incoming_message.message.request_id,
            total=1,
            enrs=(local_enr, ),
        )
        outgoing_message = incoming_message.to_response(nodes_message)

        self.logger.debug(
            "Responding to %s with Nodes message containing local ENR",
            incoming_message.sender_endpoint,
        )
        await self.outgoing_message_send_channel.send(outgoing_message)
async def test_request_handling(message_dispatcher, incoming_message_channels,
                                remote_enr, remote_endpoint):
    ping_send_channel, ping_receive_channel = trio.open_memory_channel(0)

    async with message_dispatcher.add_request_handler(
            PingMessage) as request_subscription:

        incoming_message = IncomingMessage(
            message=PingMessageFactory(),
            sender_endpoint=remote_endpoint,
            sender_node_id=remote_enr.node_id,
        )
        await incoming_message_channels[0].send(incoming_message)

        with trio.fail_after(1):
            handled_incoming_message = await request_subscription.receive()
        assert handled_incoming_message == incoming_message
async def test_response_handling(message_dispatcher, remote_enr,
                                 incoming_message_channels):
    request_id = message_dispatcher.get_free_request_id(remote_enr.node_id)
    async with message_dispatcher.add_response_handler(
            remote_enr.node_id,
            request_id,
    ) as response_subscription:

        incoming_message = IncomingMessage(
            message=PingMessageFactory(request_id=request_id, ),
            sender_endpoint=remote_endpoint,
            sender_node_id=remote_enr.node_id,
        )
        await incoming_message_channels[0].send(incoming_message)

        with trio.fail_after(1):
            handled_response = await response_subscription.receive()
        assert handled_response == incoming_message
Пример #8
0
    async def respond_with_pong(self,
                                incoming_message: IncomingMessage) -> None:
        if not isinstance(incoming_message.message, PingMessage):
            raise TypeError(f"Can only respond with Pong to Ping, not "
                            f"{incoming_message.message.__class__.__name__}")

        local_enr = await self.get_local_enr()

        pong = PongMessage(
            request_id=incoming_message.message.request_id,
            enr_seq=local_enr.sequence_number,
            packet_ip=incoming_message.sender_endpoint.ip_address,
            packet_port=incoming_message.sender_endpoint.port,
        )
        outgoing_message = incoming_message.to_response(pong)
        self.logger.debug(
            "Responding with Pong to %s",
            encode_hex(outgoing_message.receiver_node_id),
        )
        await self.outgoing_message_send_channel.send(outgoing_message)
Пример #9
0
    async def handle_incoming_packet_during_handshake(self,
                                                      incoming_packet: IncomingPacket,
                                                      ) -> None:
        if not self.is_during_handshake:
            raise ValueError("Can only handle packets during handshake")
        if self.handshake_participant is None:
            raise TypeError("handshake_participant is None even though handshake is in progress")

        packet = incoming_packet.packet

        if self.handshake_participant.is_response_packet(packet):
            self.logger.debug("Received %s as handshake response", packet.__class__.__name__)
        else:
            self.logger.debug("Dropping %s unexpectedly received during handshake", incoming_packet)
            return

        try:
            handshake_result = self.handshake_participant.complete_handshake(packet)
        except HandshakeFailure as handshake_failure:
            self.logger.warning(
                "Handshake with %s has failed: %s",
                encode_hex(self.remote_node_id),
                handshake_failure,
            )
            raise  # let the service fail
        else:
            self.logger.info("Handshake with %s was successful", encode_hex(self.remote_node_id))
            self.handshake_successful_event.set()

            # copy message backlog before we reset it
            outgoing_message_backlog = tuple(self.outgoing_message_backlog)
            self.reset_handshake_state()
            self.session_keys = handshake_result.session_keys
            if not self.is_post_handshake:
                raise Exception(
                    "Invariant: As session_keys are set now, peer packer is in post handshake state"
                )

            if handshake_result.enr is not None:
                self.logger.debug("Updating ENR in DB with %r", handshake_result.enr)
                await self.enr_db.insert_or_update(handshake_result.enr)

            if handshake_result.auth_header_packet is not None:
                outgoing_packet = OutgoingPacket(
                    handshake_result.auth_header_packet,
                    incoming_packet.sender_endpoint,
                )
                self.logger.debug(
                    "Sending %s packet to let peer complete handshake",
                    outgoing_packet,
                )
                await self.outgoing_packet_send_channel.send(outgoing_packet)

            if handshake_result.message:
                incoming_message = IncomingMessage(
                    handshake_result.message,
                    incoming_packet.sender_endpoint,
                    self.remote_node_id,
                )
                self.logger.debug("Received %s during handshake", incoming_message)
                await self.incoming_message_send_channel.send(incoming_message)

            self.logger.debug("Sending %d messages from backlog", len(outgoing_message_backlog))
            for outgoing_message in outgoing_message_backlog:
                await self.handle_outgoing_message(outgoing_message)