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
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
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)