Пример #1
0
    async def connect(self, remote: NodeAPI) -> 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 self._handshake_locks.is_locked(remote):
            self.logger.debug2("Skipping %s; already shaking hands", remote)
            raise IneligiblePeer(f"Already shaking hands with {remote}")

        async with self._handshake_locks.lock(remote):

            if remote in self.connected_nodes:
                self.logger.debug2("Skipping %s; already connected to it", remote)
                raise IneligiblePeer(f"Already connected to {remote}")

            try:
                should_connect = await self.wait(
                    self.connection_tracker.should_connect_to(remote),
                    timeout=1,
                )
            except TimeoutError:
                self.logger.warning("ConnectionTracker.should_connect_to request timed out.")
                raise

            if not should_connect:
                raise IneligiblePeer(f"Peer database rejected peer candidate: {remote}")

            try:
                self.logger.debug2("Connecting to %s...", remote)
                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
                # `COMMON_PEER_CONNECTION_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)
                raise
            except MalformedMessage:
                # This is kept separate from the
                # `COMMON_PEER_CONNECTION_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)
                raise
            except HandshakeFailure as e:
                self.logger.debug("Could not complete handshake with %r: %s", remote, repr(e))
                self.connection_tracker.record_failure(remote, e)
                raise
            except COMMON_PEER_CONNECTION_EXCEPTIONS as e:
                self.logger.debug("Could not complete handshake with %r: %s", remote, repr(e))
                raise
            except Exception:
                self.logger.exception("Unexpected error during auth/p2p handshake with %r", remote)
                raise
Пример #2
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 in self.connected_nodes:
            self.logger.debug2("Skipping %s; already connected to it", remote)
            raise IneligiblePeer(f"Already connected to {remote}")
        if not self.peer_info.should_connect_to(remote):
            raise IneligiblePeer(
                f"Peer database rejected peer candidate: {remote}")

        try:
            self.logger.debug2("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
            # `COMMON_PEER_CONNECTION_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)
            raise
        except MalformedMessage:
            # This is kept separate from the
            # `COMMON_PEER_CONNECTION_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)
            raise
        except HandshakeFailure as e:
            self.logger.debug("Could not complete handshake with %r: %s",
                              remote, repr(e))
            self.peer_info.record_failure(remote, e)
            raise
        except COMMON_PEER_CONNECTION_EXCEPTIONS as e:
            self.logger.debug("Could not complete handshake with %r: %s",
                              remote, repr(e))
            raise
        except Exception:
            self.logger.exception(
                "Unexpected error during auth/p2p handshake with %r", remote)
            raise
Пример #3
0
def main():
    """
    Create a Peer instance connected to a local geth instance and log messages exchanged with it.

    Use the following command line to run geth:

        ~/Codes/gohome/bin/geth -vmodule p2p=4,p2p/discv5=0,eth/*=0 \
          -nodekeyhex 45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8 \
          -testnet -lightserv 90
    """

    import argparse
    import signal
    from evm.chains.ropsten import RopstenChain, ROPSTEN_GENESIS_HEADER
    from evm.db.backends.memory import MemoryDB
    from tests.p2p.integration_test_helpers import FakeAsyncChainDB
    logging.basicConfig(level=logging.DEBUG,
                        format='%(asctime)s %(levelname)s: %(message)s')

    # The default remoteid can be used if you pass nodekeyhex as above to geth.
    nodekey = keys.PrivateKey(
        decode_hex(
            "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8")
    )
    remoteid = nodekey.public_key.to_hex()
    parser = argparse.ArgumentParser()
    parser.add_argument('-remoteid', type=str, default=remoteid)
    parser.add_argument('-light',
                        action='store_true',
                        help="Connect as a light node")
    args = parser.parse_args()

    peer_class = ETHPeer  # type: ignore
    if args.light:
        peer_class = LESPeer  # type: ignore
    remote = Node(keys.PublicKey(decode_hex(args.remoteid)),
                  Address('127.0.0.1', 30303, 30303))
    chaindb = FakeAsyncChainDB(MemoryDB())
    chaindb.persist_header(ROPSTEN_GENESIS_HEADER)
    network_id = RopstenChain.network_id
    loop = asyncio.get_event_loop()
    peer = loop.run_until_complete(
        asyncio.wait_for(
            handshake(remote, ecies.generate_privkey(), peer_class, chaindb,
                      network_id), HANDSHAKE_TIMEOUT))

    async def request_stuff():
        # Request some stuff from ropsten's block 2440319
        # (https://ropsten.etherscan.io/block/2440319), just as a basic test.
        nonlocal peer
        block_hash = decode_hex(
            '0x59af08ab31822c992bb3dad92ddb68d820aa4c69e9560f07081fa53f1009b152'
        )
        if peer_class == ETHPeer:
            peer = cast(ETHPeer, peer)
            peer.sub_proto.send_get_block_headers(block_hash, 1)
            peer.sub_proto.send_get_block_bodies([block_hash])
            peer.sub_proto.send_get_receipts([block_hash])
        else:
            peer = cast(LESPeer, peer)
            request_id = 1
            peer.sub_proto.send_get_block_headers(block_hash, 1, request_id)
            peer.sub_proto.send_get_block_bodies([block_hash], request_id + 1)
            peer.sub_proto.send_get_receipts(block_hash, request_id + 2)

    for sig in [signal.SIGINT, signal.SIGTERM]:
        loop.add_signal_handler(sig, peer.cancel_token.trigger)

    asyncio.ensure_future(request_stuff())
    loop.run_until_complete(peer.run())
    loop.close()