Пример #1
0
    async def connect(self, remote: Node) -> BasePeer:
        """
        Connect to the given remote and return a Peer instance when successful.
        Returns None if the remote is unreachable, times out or is useless.
        """
        if remote.pubkey == self.privkey.public_key:
            Logger.warning_every_n(
                "Skipping {} that has the same public key as local node, quite possible we are trying to connect to ourselves"
                .format(remote),
                100,
            )
            return None
        if remote in self.connected_nodes:
            self.logger.debug("Skipping %s; already connected to it", remote)
            return None
        expected_exceptions = (
            HandshakeFailure,
            PeerConnectionLost,
            TimeoutError,
            UnreachablePeer,
        )
        try:
            self.logger.debug("Connecting to %s...", remote)
            # We use self.wait() as well as passing our CancelToken to handshake() as a workaround
            # for https://github.com/ethereum/py-evm/issues/670.
            peer = await self.wait(handshake(remote, self.get_peer_factory()))

            return peer
        except OperationCancelled:
            # Pass it on to instruct our main loop to stop.
            raise
        except BadAckMessage:
            # This is kept separate from the `expected_exceptions` to be sure that we aren't
            # silencing an error in our authentication code.
            self.logger.error("Got bad auth ack from %r", remote)
            # dump the full stacktrace in the debug logs
            self.logger.debug("Got bad auth ack from %r",
                              remote,
                              exc_info=True)
        except MalformedMessage:
            # This is kept separate from the `expected_exceptions` to be sure that we aren't
            # silencing an error in how we decode messages during handshake.
            self.logger.error(
                "Got malformed response from %r during handshake", remote)
            # dump the full stacktrace in the debug logs
            self.logger.debug("Got malformed response from %r",
                              remote,
                              exc_info=True)
        except expected_exceptions as e:
            self.logger.debug("Could not complete handshake with %r: %s",
                              remote, repr(e))
        except Exception:
            self.logger.exception(
                "Unexpected error during auth/p2p handshake with %r", remote)
        return None
Пример #2
0
 def get_random_nodes(self, count: int) -> Iterator[Node]:
     if count > len(self):
         if time.monotonic() - self._initialized_at > 30:
             Logger.warning_every_n(
                 "Cannot get {} nodes as RoutingTable contains only {} nodes"
                 .format(count, len(self)),
                 100,
             )
         count = len(self)
     seen = []
     # This is a rather inneficient way of randomizing nodes from all buckets, but even if we
     # iterate over all nodes in the routing table, the time it takes would still be
     # insignificant compared to the time it takes for the network roundtrips when connecting
     # to nodes.
     while len(seen) < count:
         bucket = random.choice(self.buckets)
         if not bucket.nodes:
             continue
         node = random.choice(bucket.nodes)
         if node not in seen:
             yield node
             seen.append(node)
Пример #3
0
    async def connect(self, remote: Node) -> BasePeer:
        """
        Connect to the given remote and return a Peer instance when successful.
        Returns None if the remote is unreachable, times out or is useless.
        """
        if remote.pubkey == self.privkey.public_key:
            Logger.warning_every_n(
                "Skipping {} that has the same public key as local node, quite possible we are trying to connect to ourselves"
                .format(remote),
                100,
            )
            return None
        if remote in self.connected_nodes:
            self.logger.debug("Skipping %s; already connected to it", remote)
            return None
        if self.chk_dialout_blacklist(remote.address):
            Logger.warning_every_n(
                "failed to connect {} at least once, will not connect again; discovery should have removed it"
                .format(remote.address), 100)
            return None
        blacklistworthy_exceptions = (
            HandshakeFailure,  # after secure handshake handshake, when negotiating p2p command, eg. parsing hello failed; no matching p2p capabilities
            PeerConnectionLost,  # conn lost while reading
            TimeoutError,  # eg. read timeout (raised by CancelToken)
            UnreachablePeer,  # ConnectionRefusedError, OSError
        )
        expected_exceptions = (
            HandshakeDisconnectedFailure,  # during secure handshake, disconnected before getting ack; or got Disconnect cmd for some known reason
        )
        try:
            self.logger.debug("Connecting to %s...", remote)
            # We use self.wait() as well as passing our CancelToken to handshake() as a workaround
            # for https://github.com/ethereum/py-evm/issues/670.
            peer = await self.wait(handshake(remote, self.get_peer_factory()))

            return peer
        except OperationCancelled:
            # Pass it on to instruct our main loop to stop.
            raise
        except BadAckMessage:
            # This is kept separate from the `expected_exceptions` to be sure that we aren't
            # silencing an error in our authentication code.
            Logger.error_every_n("Got bad auth ack from {}".format(remote),
                                 100)
            # dump the full stacktrace in the debug logs
            self.logger.debug("Got bad auth ack from %r",
                              remote,
                              exc_info=True)
            self.dialout_blacklist(remote.address)
        except MalformedMessage:
            # This is kept separate from the `expected_exceptions` to be sure that we aren't
            # silencing an error in how we decode messages during handshake.
            Logger.error_every_n(
                "Got malformed response from {} during handshake".format(
                    remote), 100)
            # dump the full stacktrace in the debug logs
            self.logger.debug("Got malformed response from %r",
                              remote,
                              exc_info=True)
            self.dialout_blacklist(remote.address)
        except blacklistworthy_exceptions as e:
            self.logger.debug("Could not complete handshake with %r: %s",
                              remote, repr(e))
            Logger.error_every_n(
                "Could not complete handshake with {}: {}".format(
                    repr(remote), repr(e)), 100)
            self.dialout_blacklist(remote.address)
        except expected_exceptions as e:
            self.logger.debug("Disconnected during handshake %r: %s", remote,
                              repr(e))
            Logger.error_every_n(
                "Disconnected during handshake {}: {}".format(
                    repr(remote), repr(e)), 100)
        except Exception:
            self.logger.exception(
                "Unexpected error during auth/p2p handshake with %r", remote)
            self.dialout_blacklist(remote.address)
        if remote.__repr__() in auth.opened_connections:
            reader, writer = auth.opened_connections[remote.__repr__()]
            reader.feed_eof()
            writer.close()
            Logger.error_every_n(
                "Closing connection to {}".format(remote.__repr__()), 100)
            del auth.opened_connections[remote.__repr__()]
        return None