Esempio n. 1
0
async def handshake(
    remote: Node,
    privkey: datatypes.PrivateKey,
    peer_class: 'Type[BasePeer]',
    chaindb: BaseChainDB,
    network_id: int,
    received_msg_callback: Optional[_ReceivedMsgCallbackType] = None
) -> 'BasePeer':
    """Perform the auth and P2P handshakes with the given remote.

    Return an instance of the given peer_class (must be a subclass of BasePeer) connected to that
    remote in case both handshakes are successful and at least one of the sub-protocols supported
    by peer_class is also supported by the remote.

    Raises UnreachablePeer if we cannot connect to the peer or UselessPeer if none of the
    sub-protocols supported by us is also supported by the remote.
    """
    try:
        (aes_secret, mac_secret, egress_mac, ingress_mac, reader,
         writer) = await auth.handshake(remote, privkey)
    except (ConnectionRefusedError, OSError) as e:
        raise UnreachablePeer(e)
    peer = peer_class(remote=remote,
                      privkey=privkey,
                      reader=reader,
                      writer=writer,
                      aes_secret=aes_secret,
                      mac_secret=mac_secret,
                      egress_mac=egress_mac,
                      ingress_mac=ingress_mac,
                      chaindb=chaindb,
                      network_id=network_id,
                      received_msg_callback=received_msg_callback)
    peer.base_protocol.send_handshake()
    msg = await peer.read_msg()
    cmd, decoded = peer.process_msg(msg)
    if isinstance(cmd, Disconnect):
        # Peers may send a disconnect msg before they send the initial P2P handshake (e.g. when
        # they're not accepting more peers), so we special case that here because it's important
        # to distinguish this from a failed handshake (e.g. no matching protocols, etc).
        decoded = cast(Dict[str, Any], decoded)
        raise PeerDisconnected(
            "Peer disconnected before completing handshake: {}".format(
                decoded['reason_name']))
    if len(peer.enabled_sub_protocols) == 0:
        raise UselessPeer("No matching sub-protocols")
    for proto in peer.enabled_sub_protocols:
        proto.send_handshake(peer._local_chain_info)
    return peer
Esempio n. 2
0
async def handshake(remote, privkey, peer_class, chaindb, network_id):
    """Perform the auth and P2P handshakes with the given remote.

    Return an instance of the given peer_class (must be a subclass of BasePeer) connected to that
    remote in case both handshakes are successful and at least one of the sub-protocols supported
    by peer_class is also supported by the remote.

    Raises UnreachablePeer if we cannot connect to the peer or UselessPeer if none of the
    sub-protocols supported by us is also supported by the remote.
    """
    try:
        (aes_secret, mac_secret, egress_mac, ingress_mac, reader,
         writer) = await auth.handshake(remote, privkey)
    except (ConnectionRefusedError, OSError) as e:
        raise UnreachablePeer(e)
    peer = peer_class(remote=remote,
                      privkey=privkey,
                      reader=reader,
                      writer=writer,
                      aes_secret=aes_secret,
                      mac_secret=mac_secret,
                      egress_mac=egress_mac,
                      ingress_mac=ingress_mac,
                      chaindb=chaindb,
                      network_id=network_id)
    peer.base_protocol.send_handshake()
    msg = await peer.read_msg()
    decoded = peer.process_msg(msg)
    if get_devp2p_cmd_id(msg) == Disconnect._cmd_id:
        # Peers may send a disconnect msg before they send the initial P2P handshake (e.g. when
        # they're not accepting more peers), so we special case that here because it's important
        # to distinguish this from a failed handshake (e.g. no matching protocols, etc).
        raise PeerDisconnected("{} disconnected before handshake: {}".format(
            peer, decoded['reason_name']))
    if len(peer.enabled_sub_protocols) == 0:
        raise UselessPeer("No matching sub-protocols with {}".format(peer))
    for proto in peer.enabled_sub_protocols:
        proto.send_handshake(peer.head_info)
    return peer
Esempio n. 3
0
 def process_p2p_handshake(self, msg: bytes) -> None:
     cmd = self.get_protocol_command_for(msg)
     decoded_msg = cmd.handle(msg)
     decoded_msg = cast(Dict[str, Any], decoded_msg)
     if isinstance(cmd, Disconnect):
         # Peers may send a disconnect msg before they send the initial P2P handshake (e.g. when
         # they're not accepting more peers), so we special case that here because it's important
         # to distinguish this from a failed handshake (e.g. no matching protocols, etc).
         raise PeerDisconnected(
             "Peer disconnected before completing handshake: {}".format(
                 decoded_msg['reason_name']))
     remote_capabilities = decoded_msg['capabilities']
     self.sub_proto = self.select_sub_protocol(remote_capabilities)
     if self.sub_proto is None:
         self.logger.debug(
             "No matching capabilities between us (%s) and %s (%s), disconnecting",
             self.capabilities, self.remote, remote_capabilities)
         self.disconnect(DisconnectReason.useless_peer)
     else:
         self.logger.debug(
             "Finished P2P handshake with %s, using sub-protocol %s",
             self.remote, self.sub_proto)