Exemple #1
0
    async def process_sub_proto_handshake(self, cmd: Command,
                                          msg: _DecodedMsgType) -> None:
        if not isinstance(cmd, Status):
            await self.disconnect(DisconnectReason.other)
            raise HandshakeFailure(
                "Expected a HLS Status msg, got {}, disconnecting".format(cmd))

        msg = cast(Dict[str, Any], msg)
        if msg['network_id'] != self.network_id:
            await self.disconnect(DisconnectReason.useless_peer)
            raise HandshakeFailure(
                "{} network ({}) does not match ours ({}), disconnecting".
                format(self, msg['network_id'], self.network_id))

        chain_info = await self._local_chain_info
        genesis_block_hash = chain_info.genesis_block_hash
        if msg['genesis_block_hash'] != genesis_block_hash:
            await self.disconnect(DisconnectReason.useless_peer)
            raise HandshakeFailure(
                "{} genesis ({}) does not match ours ({}), disconnecting".
                format(self, encode_hex(msg['genesis_block_hash']),
                       encode_hex(genesis_block_hash)))

        self.node_type = msg['node_type']
        self.send_wallet_address_verification(self.local_salt, msg['salt'])

        # After the sub_proto handshake, the peer will send back a signed message containing the wallet address
        cmd, msg = await self.read_msg()
        if isinstance(cmd, Disconnect):
            # Peers sometimes send a disconnect msg before they send the sub-proto handshake.
            raise HandshakeFailure(
                "{} disconnected before completing wallet address verification: {}"
                .format(self, msg['reason_name']))
        await self.process_sub_proto_wallet_address_verification(cmd, msg)
Exemple #2
0
 async def process_sub_proto_handshake(self, cmd: Command,
                                       msg: _DecodedMsgType) -> None:
     if not isinstance(cmd, (Status, StatusV2)):
         await self.disconnect(DisconnectReason.subprotocol_error)
         raise HandshakeFailure(
             "Expected a LES Status msg, got {}, disconnecting".format(cmd))
     msg = cast(Dict[str, Any], msg)
     if msg['networkId'] != self.network_id:
         await self.disconnect(DisconnectReason.useless_peer)
         raise HandshakeFailure(
             "{} network ({}) does not match ours ({}), disconnecting".
             format(self, msg['networkId'], self.network_id))
     genesis = await self.genesis
     if msg['genesisHash'] != genesis.hash:
         await self.disconnect(DisconnectReason.useless_peer)
         raise HandshakeFailure(
             "{} genesis ({}) does not match ours ({}), disconnecting".
             format(self, encode_hex(msg['genesisHash']), genesis.hex_hash))
     # Eventually we might want to keep connections to peers where we are the only side serving
     # data, but right now both our chain syncer and the Peer.boot() method expect the remote
     # to reply to header requests, so if they don't we simply disconnect here.
     if 'serveHeaders' not in msg:
         await self.disconnect(DisconnectReason.useless_peer)
         raise HandshakeFailure(
             f"{self} doesn't serve headers, disconnecting")
     self.head_td = msg['headTd']
     self.head_hash = msg['headHash']
     self.head_number = msg['headNum']
Exemple #3
0
async def _handshake(
    initiator: 'HandshakeInitiator',
    reader: asyncio.StreamReader,
    writer: asyncio.StreamWriter,
    token: CancelToken,
) -> Tuple[bytes, bytes, sha3.keccak_256, sha3.keccak_256]:
    """See the handshake() function above.

    This code was factored out into this helper so that we can create Peers with directly
    connected readers/writers for our tests.
    """
    initiator_nonce = keccak(os.urandom(HASH_LEN))
    auth_msg = initiator.create_auth_message(initiator_nonce)
    auth_init = initiator.encrypt_auth_message(auth_msg)
    writer.write(auth_init)

    auth_ack = await token.cancellable_wait(
        reader.read(ENCRYPTED_AUTH_ACK_LEN), timeout=REPLY_TIMEOUT)

    if reader.at_eof():
        # This is what happens when Parity nodes have blacklisted us
        # (https://github.com/ethereum/py-evm/issues/901).
        raise HandshakeFailure("%s disconnected before sending auth ack",
                               repr(initiator.remote))

    ephemeral_pubkey, responder_nonce = initiator.decode_auth_ack_message(
        auth_ack)
    aes_secret, mac_secret, egress_mac, ingress_mac = initiator.derive_secrets(
        initiator_nonce, responder_nonce, ephemeral_pubkey, auth_init,
        auth_ack)

    return aes_secret, mac_secret, egress_mac, ingress_mac
Exemple #4
0
 async def process_p2p_handshake(self, cmd: protocol.Command,
                                 msg: protocol.PayloadType) -> None:
     msg = cast(Dict[str, Any], msg)
     if not isinstance(cmd, Hello):
         await self.disconnect(DisconnectReason.bad_protocol)
         raise HandshakeFailure(
             f"Expected a Hello msg, got {cmd}, disconnecting")
     remote_capabilities = msg['capabilities']
     try:
         self.sub_proto = self.select_sub_protocol(remote_capabilities)
     except NoMatchingPeerCapabilities:
         await self.disconnect(DisconnectReason.useless_peer)
         raise HandshakeFailure(
             f"No matching capabilities between us ({self.capabilities}) and {self.remote} "
             f"({remote_capabilities}), disconnecting")
     self.logger.debug(
         "Finished P2P handshake with %s, using sub-protocol %s",
         self.remote, self.sub_proto)
Exemple #5
0
    async def process_sub_proto_wallet_address_verification(
            self, cmd: Command, msg: _DecodedMsgType) -> None:
        if not isinstance(cmd, WalletAddressVerification):
            await self.disconnect(DisconnectReason.other)
            raise HandshakeFailure(
                "Expected a HLS WalletAddressVerification msg, got {}, disconnecting"
                .format(cmd))
        msg = cast(Dict[str, Any], msg)

        # make sure the salt they replied with is the salt we sent:
        if msg['peer_salt'] != self.local_salt:
            raise HandshakeFailure(
                "The peer replied with a signed message using the wrong salt")

        salt = msg['local_salt'] + msg['peer_salt']
        validate_transaction_signature(salt, msg['v'], msg['r'], msg['s'])

        self.wallet_address = extract_wallet_verification_sender(
            salt, msg['v'], msg['r'], msg['s'])
Exemple #6
0
    async def do_p2p_handshake(self) -> None:
        """Perform the handshake for the P2P base protocol.

        Raises HandshakeFailure if the handshake is not successful.
        """
        self.base_protocol.send_handshake()

        try:
            cmd, msg = await self.read_msg()
        except rlp.DecodingError:
            raise HandshakeFailure(
                "Got invalid rlp_templates data during handshake")
        except MalformedMessage as e:
            raise HandshakeFailure(
                "Got malformed message during handshake") from e

        if isinstance(cmd, Disconnect):
            msg = cast(Dict[str, Any], msg)
            # Peers sometimes send a disconnect msg before they send the initial P2P handshake.
            raise HandshakeFailure(
                f"{self} disconnected before completing sub-proto handshake: {msg['reason_name']}"
            )
        await self.process_p2p_handshake(cmd, msg)
Exemple #7
0
    async def do_sub_proto_handshake(self) -> None:
        """Perform the handshake for the sub-protocol agreed with the remote peer.

        Raises HandshakeFailure if the handshake is not successful.
        """
        await self.send_sub_proto_handshake()
        cmd, msg = await self.read_msg()
        if isinstance(cmd, Ping):
            # Parity sends a Ping before the sub-proto handshake, so respond to that and read the
            # next one, which hopefully will be the actual handshake.
            self.base_protocol.send_pong()
            cmd, msg = await self.read_msg()
        if isinstance(cmd, Disconnect):
            msg = cast(Dict[str, Any], msg)
            # Peers sometimes send a disconnect msg before they send the sub-proto handshake.
            raise HandshakeFailure(
                f"{self} disconnected before completing sub-proto handshake: {msg['reason_name']}"
            )
        await self.process_sub_proto_handshake(cmd, msg)
        self.logger.debug("Finished %s handshake with %s", self.sub_proto,
                          self.remote)