async def request_nodes(
        self,
        receiver_node_id: NodeID,
        message: BaseMessage,
        endpoint: Optional[Endpoint] = None,
    ) -> Tuple[IncomingMessage, ...]:
        async with self.request_response_subscription(
                receiver_node_id,
                message,
                endpoint,
        ) as response_subscription:
            first_response = await response_subscription.receive()
            self.logger.debug(
                "Received %s from %s with request id %d",
                first_response,
                encode_hex(receiver_node_id),
                message.request_id,
            )
            if not isinstance(first_response.message, NodesMessage):
                raise UnexpectedMessage(
                    f"Peer {encode_hex(receiver_node_id)} responded with "
                    f"{first_response.message.__class__.__name__} instead of Nodes message"
                )

            total = first_response.message.total
            if total > MAX_NODES_MESSAGE_TOTAL:
                raise UnexpectedMessage(
                    f"Peer {encode_hex(receiver_node_id)} sent nodes message with a total value of "
                    f"{total} which is too big")
            self.logger.debug(
                "Received nodes response %d of %d from %s with request id %d",
                1,
                total,
                encode_hex(receiver_node_id),
                message.request_id,
            )

            responses = [first_response]
            for response_index in range(1, total):
                next_response = await response_subscription.receive()
                if not isinstance(first_response.message, NodesMessage):
                    raise UnexpectedMessage(
                        f"Peer {encode_hex(receiver_node_id)} responded with "
                        f"{next_response.message.__class__.__name__} instead of Nodes message"
                    )
                responses.append(next_response)
                self.logger.debug(
                    "Received nodes response %d of %d from %s with request id %d",
                    response_index + 1,
                    total,
                    encode_hex(receiver_node_id),
                    message.request_id,
                )
            return tuple(responses)
Exemplo n.º 2
0
 def handle_p2p_msg(self, cmd: protocol.Command, msg: protocol.PayloadType) -> None:
     """Handle the base protocol (P2P) messages."""
     if isinstance(cmd, Disconnect):
         msg = cast(Dict[str, Any], msg)
         raise RemoteDisconnected(msg['reason_name'])
     elif isinstance(cmd, Ping):
         self.base_protocol.send_pong()
     elif isinstance(cmd, Pong):
         # Currently we don't do anything when we get a pong, but eventually we should
         # update the last time we heard from a peer in our DB (which doesn't exist yet).
         pass
     else:
         raise UnexpectedMessage(f"Unexpected msg: {cmd} ({msg})")
Exemplo n.º 3
0
 def handle_p2p_msg(self, cmd: protocol.Command, msg: protocol._DecodedMsgType) -> None:
     """Handle the base protocol (P2P) messages."""
     if isinstance(cmd, Disconnect):
         msg = cast(Dict[str, Any], msg)
         self.logger.debug(
             "%s disconnected; reason given: %s", self, msg['reason_name'])
         self.close()
     elif isinstance(cmd, Ping):
         self.base_protocol.send_pong()
     elif isinstance(cmd, Pong):
         # Currently we don't do anything when we get a pong, but eventually we should
         # update the last time we heard from a peer in our DB (which doesn't exist yet).
         pass
     else:
         raise UnexpectedMessage("Unexpected msg: {} ({})".format(cmd, msg))
Exemplo n.º 4
0
    async def get_collations(self, collation_hashes: List[Hash32],
                             cancel_token: CancelToken) -> Set[Collation]:
        # Don't send empty request
        if len(collation_hashes) == 0:
            return set()

        request_id = gen_request_id()
        pending_reply: asyncio.Future[Tuple[
            Command, protocol._DecodedMsgType]] = asyncio.Future()
        self._pending_replies[request_id] = pending_reply
        cast(ShardingProtocol,
             self.sub_proto).send_get_collations(request_id, collation_hashes)
        cmd, msg = await wait_with_token(pending_reply, token=cancel_token)

        if not isinstance(cmd, Collations):
            raise UnexpectedMessage(
                "Expected Collations as response to GetCollations, but got %s",
                cmd.__class__.__name__)
        return set(msg["collations"])
Exemplo n.º 5
0
    async def _handle_peer(self, peer: LESPeer) -> None:
        self._announcement_queue.put_nowait((peer, peer.head_info))
        while True:
            try:
                cmd, msg = await peer.read_sub_proto_msg(self.cancel_token)
            except OperationCancelled:
                # Either the peer disconnected or our cancel_token has been triggered, so break
                # out of the loop to stop attempting to sync with this peer.
                break
            # We currently implement only the LES commands for retrieving data (apart from
            # Announce), and those should always come as a response to requests we make so will be
            # handled by LESPeer.handle_sub_proto_msg().
            if isinstance(cmd, les.Announce):
                peer.head_info = cmd.as_head_info(msg)
                self._announcement_queue.put_nowait((peer, peer.head_info))
            else:
                raise UnexpectedMessage("Unexpected msg from {}: {}".format(peer, msg))

        await self.drop_peer(peer)
        self.logger.debug("%s finished", peer)