Ejemplo n.º 1
0
    def _recv_Hello(self, data):
        # check compatibility
        peer_protocol_version = idec(data[0])

        logger.debug('received Hello protocol_version:{0:#04x}'.format(
                     peer_protocol_version))

        if peer_protocol_version != packeter.PROTOCOL_VERSION:
            return self.send_Disconnect(
                reason='Incompatible network protocols.'
                ' Expected:{0:#04x} received:{1:#04x}'.format(
                    packeter.PROTOCOL_VERSION, peer_protocol_version))

        if idec(data[1]) != packeter.NETWORK_ID:
            return self.send_Disconnect(reason='Wrong genesis block')

        # add to known peers list in handshake signal
        self.hello_received = True
        if len(data) == 6:
            self.node_id = data[5]
            self.port = idec(data[3]) # replace connection port with listen port

        # reply with hello if not send
        if not self.hello_sent:
            self.send_Hello()

        signals.peer_handshake_success.send(sender=Peer, peer=self)
Ejemplo n.º 2
0
    def load_packet(cls, packet):
        '''
        Though TCP provides a connection-oriented medium, Ethereum nodes
        communicate in terms of packets. These packets are formed as a 4-byte
        synchronisation token (0x22400891), a 4-byte "payload size", to be
        interpreted as a big-endian integer and finally an N-byte
        RLP-serialised data structure, where N is the aforementioned
        "payload size". To be clear, the payload size specifies the number of
        bytes in the packet ''following'' the first 8.

        :return: (success, result), where result should be None when fail,
        and (header, payload_len, cmd, data) when success
        '''
        header = idec(packet[:4])
        if header != cls.SYNCHRONIZATION_TOKEN:
            return False, 'check header failed, skipping message,'\
                'sync token was hex: {0:x}'.format(header)

        try:
            payload_len = idec(packet[4:8])
            payload = lrlp_decode(packet[8:8 + payload_len])
        except Exception as e:
            return False, str(e)

        if (not len(payload)) or (idec(payload[0]) not in cls.cmd_map):
            return False, 'check cmd failed'

        cmd = Packeter.cmd_map.get(idec(payload[0]))
        return True, (header, payload_len, cmd, payload[1:])
Ejemplo n.º 3
0
    def _recv_Status(self, data):
        # [0x10: P, protocolVersion: P, networkID: P, totalDifficulty: P, latestHash: B_32, genesisHash: B_32]
        # check compatibility
        try:
            ethereum_protocol_version, network_id = idec(data[0]), idec(data[1])
            total_difficulty, head_hash, genesis_hash = idec(data[2]), data[3], data[4]
        except IndexError:
            return self.send_Disconnect(reason="Incompatible network protocols")

        logger.debug(
            "%r, received Status ETHPROTOCOL:%r TD:%d HEAD:%r GENESIS:%r",
            self,
            ethereum_protocol_version,
            total_difficulty,
            head_hash.encode("hex"),
            genesis_hash.encode("hex"),
        )

        if ethereum_protocol_version != packeter.ETHEREUM_PROTOCOL_VERSION:
            return self.send_Disconnect(reason="Incompatible network protocols")

        if network_id != packeter.NETWORK_ID:
            return self.send_Disconnect(reason="Wrong genesis block")

        if genesis_hash != blocks.genesis().hash:
            return self.send_Disconnect(reason="Wrong genesis block")

        self.status_received = True
        self.status_head_hash = head_hash
        self.status_total_difficulty = total_difficulty
        signals.peer_status_received.send(sender=Peer, peer=self)
Ejemplo n.º 4
0
    def load_packet(cls, packet):
        '''
        Though TCP provides a connection-oriented medium, Ethereum nodes
        communicate in terms of packets. These packets are formed as a 4-byte
        synchronisation token (0x22400891), a 4-byte "payload size", to be
        interpreted as a big-endian integer and finally an N-byte
        RLP-serialised data structure, where N is the aforementioned
        "payload size". To be clear, the payload size specifies the number of
        bytes in the packet ''following'' the first 8.

        :return: (success, result), where result should be None when fail,
        and (header, payload_len, cmd, data) when success
        '''
        header = idec(packet[:4])
        if header != cls.SYNCHRONIZATION_TOKEN:
            return False, 'check header failed, skipping message,'\
                'sync token was hex: {0:x}'.format(header)

        try:
            payload_len = idec(packet[4:8])
            payload = lrlp_decode(packet[8:8 + payload_len])
        except Exception as e:
            return False, str(e)

        if (not len(payload)) or (idec(payload[0]) not in cls.cmd_map):
            return False, 'check cmd failed'

        cmd = Packeter.cmd_map.get(idec(payload[0]))
        return True, (header, payload_len, cmd, payload[1:])
Ejemplo n.º 5
0
    def _recv_Hello(self, data):
        # check compatibility
        client_id, peer_protocol_version = data[2], idec(data[0])
        logger.debug('received Hello %s V:%r', client_id,
                     peer_protocol_version)

        if peer_protocol_version != packeter.PROTOCOL_VERSION:
            return self.send_Disconnect(
                reason='Incompatible network protocols')

        if idec(data[1]) != packeter.NETWORK_ID:
            return self.send_Disconnect(reason='Wrong genesis block')

        # add to known peers list in handshake signal
        self.hello_received = True
        if len(data) == 6:
            self.node_id = data[5]
            self.port = idec(
                data[3])  # replace connection port with listen port

        # reply with hello if not send
        if not self.hello_sent:
            self.send_Hello()

        signals.peer_handshake_success.send(sender=Peer, peer=self)
Ejemplo n.º 6
0
    def _recv_Hello(self, data):
        # check compatibility
        peer_protocol_version, network_id, client_id = idec(data[0]), idec(data[1]), data[2]
        capabilities, listen_port, node_id = idec(data[3]), idec(data[4]), data[5]

        logger.debug('received Hello %s V:%r N:%r C:%r P:%r I:%s', client_id,
                     peer_protocol_version, network_id, capabilities, listen_port,
                     node_id.encode('hex'))

        if peer_protocol_version != packeter.PROTOCOL_VERSION:
            return self.send_Disconnect(
                reason='Incompatible network protocols')

        if network_id != packeter.NETWORK_ID:
            return self.send_Disconnect(reason='Wrong genesis block')

        # add to known peers list in handshake signal
        self.hello_received = True
        self.client_id = client_id
        self.node_id = node_id
        self.port = listen_port  # replace connection port with listen port

        # reply with hello if not send
        if not self.hello_sent:
            self.send_Hello()

        signals.peer_handshake_success.send(sender=Peer, peer=self)
Ejemplo n.º 7
0
    def _recv_Status(self, data):
        # [0x10: P, protocolVersion: P, networkID: P, totalDifficulty: P, latestHash: B_32, genesisHash: B_32]
        # check compatibility
        try:
            ethereum_protocol_version, network_id = idec(data[0]), idec(data[1])
            total_difficulty, head_hash, genesis_hash = idec(data[2]), data[3], data[4]
        except IndexError:
            return self.send_Disconnect(reason='Incompatible network protocols')

        log_eth.debug('received Status',
                      remote_id=self,
                      ethereum_protocol_version=ethereum_protocol_version,
                      total_difficulty=total_difficulty,
                      head=head_hash.encode('hex'),
                      genesis=genesis_hash.encode('hex'))

        if ethereum_protocol_version != packeter.ETHEREUM_PROTOCOL_VERSION:
            return self.send_Disconnect(reason='Incompatible network protocols')

        if network_id != packeter.NETWORK_ID:
            return self.send_Disconnect(reason='Wrong genesis block')

        self.status_received = True
        self.status_head_hash = head_hash
        self.status_total_difficulty = total_difficulty
        signals.peer_status_received.send(sender=Peer, genesis_hash=genesis_hash, peer=self)
Ejemplo n.º 8
0
    def _recv_Status(self, data):
        # [0x10: P, protocolVersion: P, networkID: P, totalDifficulty: P, latestHash: B_32, genesisHash: B_32]
        # check compatibility
        try:
            ethereum_protocol_version, network_id = idec(data[0]), idec(
                data[1])
            total_difficulty, head_hash, genesis_hash = idec(
                data[2]), data[3], data[4]
        except IndexError:
            return self.send_Disconnect(
                reason='Incompatible network protocols')

        logger.debug(
            '%r, received Status ETHPROTOCOL:%r TD:%d HEAD:%r GENESIS:%r',
            self, ethereum_protocol_version, total_difficulty,
            head_hash.encode('hex'), genesis_hash.encode('hex'))

        if ethereum_protocol_version != packeter.ETHEREUM_PROTOCOL_VERSION:
            return self.send_Disconnect(
                reason='Incompatible network protocols')

        if network_id != packeter.NETWORK_ID:
            return self.send_Disconnect(reason='Wrong genesis block')

        if genesis_hash != blocks.genesis().hash:
            return self.send_Disconnect(reason='Wrong genesis block')

        self.status_received = True
        self.status_head_hash = head_hash
        self.status_total_difficulty = total_difficulty
        signals.peer_status_received.send(sender=Peer, peer=self)
Ejemplo n.º 9
0
def dump_packet(packet):
    try:
        header = idec(packet[:4])
        payload_len = idec(packet[4:8])
        data = lrlp_decode(packet[8:8 + payload_len])
        cmd = WireProtocol.cmd_map.get(
            idec(data[0]), 'unknown %s' % idec(data[0]))
        return [header, payload_len, cmd] + data[1:]
    except Exception as e:
        return ['DUMP failed', packet, e]
Ejemplo n.º 10
0
    def _rcv_Hello(self, peer, data):
        """
        [0x00, PROTOCOL_VERSION, NETWORK_ID, CLIENT_ID, CAPABILITIES,
        LISTEN_PORT, NODE_ID]
        First packet sent over the connection, and sent once by both sides.
        No other messages may be sent until a Hello is received.
        PROTOCOL_VERSION is one of:
            0x00 for PoC-1;
            0x01 for PoC-2;
            0x07 for PoC-3.
            0x08 sent by Ethereum(++)/v0.3.11/brew/Darwin/unknown
        NETWORK_ID should be 0.
        CLIENT_ID Specifies the client software identity, as a human-readable
            string (e.g. "Ethereum(++)/1.0.0").
        CAPABILITIES specifies the capabilities of the client as a set of
            flags; presently three bits are used:
            0x01 for peers discovery,
            0x02 for transaction relaying,
            0x04 for block-chain querying.
        LISTEN_PORT specifies the port that the client is listening on
            (on the interface that the present connection traverses).
            If 0 it indicates the client is not listening.
        NODE_ID is optional and specifies a 512-bit hash, (potentially to be
            used as public key) that identifies this node.
        """
        logger.debug(data[:-1] + [data[-1][20]])
        # check compatibility
        if idec(data[0]) != self.PROTOCOL_VERSION:
            return self.send_Disconnect(
                peer,
                reason='Incompatible network protocols')

        if idec(data[1]) != self.NETWORK_ID:
            return self.send_Disconnect(peer, reason='Wrong genesis block')

        """
        spec has CAPABILITIES after PORT, CPP client the other way round.
        emulating the latter, see  https://github.com/ethereum/cpp-ethereum
        /blob/master/libethereum/PeerNetwork.cpp#L144
        """

        # TODO add to known peers list
        peer.hello_received = True
        if len(data) == 6:
            peer.node_id = data[5]

        # reply with hello if not send
        if not peer.hello_sent:
            peer.send_packet(peer, self.packeter.dump_Hello())
            peer.hello_sent = True
Ejemplo n.º 11
0
    def rcv_Hello(self, peer, data):
        """
        [0x00, PROTOCOL_VERSION, NETWORK_ID, CLIENT_ID, CAPABILITIES, LISTEN_PORT, NODE_ID]
        First packet sent over the connection, and sent once by both sides.
        No other messages may be sent until a Hello is received.
        PROTOCOL_VERSION is one of:
            0x00 for PoC-1;
            0x01 for PoC-2;
            0x07 for PoC-3.
            0x08 sent by Ethereum(++)/v0.3.11/brew/Darwin/unknown
        NETWORK_ID should be 0.
        CLIENT_ID Specifies the client software identity, as a human-readable string
                    (e.g. "Ethereum(++)/1.0.0").
        CAPABILITIES specifies the capabilities of the client as a set of flags;
                    presently three bits are used:
                    0x01 for peers discovery, 0x02 for transaction relaying, 0x04 for block-chain querying.
        LISTEN_PORT specifies the port that the client is listening on
                    (on the interface that the present connection traverses).
                    If 0 it indicates the client is not listening.
        NODE_ID is optional and specifies a 512-bit hash, (potentially to be used as public key)
                    that identifies this node.

        [574621841, 116, 'Hello', '\x08', '', 'Ethereum(++)/v0.3.11/brew/Darwin/unknown', '\x07', 'v_', "\xc5\xfe\xc6\xea\xe4TKvz\x9e\xdc\xa7\x01\xf6b?\x7fB\xe7\xfc(#t\xe9}\xafh\xf3Ot'\xe5u\x07\xab\xa3\xe5\x95\x14 |P\xb0C\xa2\xe4jU\xc8z|\x86\xa6ZV!Q6\x82\xebQ$4+"]
        [574621841, 27, 'Hello', '\x08', '\x00', 'Ethereum(py)/0.0.1', 'vb', '\x07']
        """

        # check compatibility
        if idec(data[0]) != self.PROTOCOL_VERSION:
            return self.send_Disconnect(
                peer,
                reason='Incompatible network protocols')

        if idec(data[1]) != self.NETWORK_ID:
            return self.send_Disconnect(peer, reason='Wrong genesis block')

        """
        spec has CAPABILITIES after PORT, CPP client the other way round. emulating the latter
        https://github.com/ethereum/cpp-ethereum/blob/master/libethereum/PeerNetwork.cpp#L144
        """

        # TODO add to known peers list
        peer.hello_received = True
        if len(data) == 6:
            peer.node_id = data[5]

        # reply with hello if not send
        if not peer.hello_sent:
            self.send_Hello(peer)
Ejemplo n.º 12
0
 def _recv_Peers(self, data):
     for ip, port, pid in data:
         assert isinstance(ip, list)
         ip = '.'.join(str(ord(b or '\x00')) for b in ip)
         port = idec(port)
         logger.debug('received peer address: {0}:{1}'.format(ip, port))
         signals.new_peer_received.send((ip, port, pid))
Ejemplo n.º 13
0
 def _recv_Peers(self, data):
     addresses = []
     for ip, port, pid in data:
         assert len(ip) == 4
         ip = '.'.join(str(ord(b)) for b in ip)
         port = idec(port)
         log_p2p.trace('received peer address', remote_id=self, ip=ip, port=port)
         addresses.append([ip, port, pid])
     signals.peer_addresses_received.send(sender=Peer, addresses=addresses)
Ejemplo n.º 14
0
 def _recv_Disconnect(self, data):
     if len(data):
         reason = packeter.disconnect_reasons_map_by_id[idec(data[0])]
         forget = reason in self.reasons_to_forget
     else:
         forget = None
         reason = None
     log_p2p.debug('received disconnect', remote_id=self, reason=None)
     signals.peer_disconnect_requested.send(sender=Peer, remote_id=self, forget=forget)
Ejemplo n.º 15
0
 def _recv_Disconnect(self, data):
     if len(data):
         reason = packeter.disconnect_reasons_map_by_id[idec(data[0])]
         logger.info('{0} sent disconnect, {1} '.format(repr(self), reason))
         forget = reason in self.reasons_to_forget
     else:
         forget = None
     signals.peer_disconnect_requested.send(
             sender=Peer, peer=self, forget=forget)
Ejemplo n.º 16
0
 def _recv_Disconnect(self, data):
     if len(data):
         reason = packeter.disconnect_reasons_map_by_id[idec(data[0])]
         logger.info('%r received disconnect: %r', self, reason)
         forget = reason in self.reasons_to_forget
     else:
         forget = None
         logger.info('%r received disconnect: w/o reason', self)
     signals.peer_disconnect_requested.send(sender=Peer, peer=self, forget=forget)
Ejemplo n.º 17
0
 def _recv_Peers(self, data):
     addresses = []
     for ip, port, pid in data:
         assert len(ip) == 4
         ip = '.'.join(str(ord(b)) for b in ip)
         port = idec(port)
         logger.debug('received peer address: {0}:{1}'.format(ip, port))
         addresses.append([ip, port, pid])
     signals.peer_addresses_received.send(sender=Peer, addresses=addresses)
Ejemplo n.º 18
0
    def rcv_packet(self, peer, packet):
        """
        Though TCP provides a connection-oriented medium, Ethereum nodes communicate
        in terms of packets. These packets are formed as a 4-byte synchronisation token
        (0x22400891), a 4-byte "payload size", to be interpreted as a big-endian integer
        and finally an N-byte RLP-serialised data structure, where N is the aforementioned
        "payload size". To be clear, the payload size specifies the number of bytes in the
        packet ''following'' the first 8.
        """

        # check header
        if not idec(packet[:4]) == self.SYNCHRONIZATION_TOKEN:
            logger.warn('check header failed, skipping message, sync token was {0}'
                        .format(idec(packet[:4])))
            return

        # unpack message
        payload_len = idec(packet[4:8])
        # assert 8 + payload_len <= len(packet) # this get's sometimes raised!?
        data = lrlp_decode(packet[8:8 + payload_len])

        # check cmd
        if (not len(data)) or (idec(data[0]) not in self.cmd_map):
            logger.warn('check cmd failed')
            return self.send_Disconnect(peer, reason='Bad protocol')

        # good peer
        peer.last_valid_packet_received = time.time()

        cmd_id = idec(data.pop(0))
        func_name = "rcv_%s" % self.cmd_map[cmd_id]
        if not hasattr(self, func_name):
            logger.warn('unknown cmd \'{0}\''.format(func_name))
            return
            """
            return self.send_Disconnect(
                peer,
                reason='Incompatible network protocols')
            raise NotImplementedError('%s not implmented')
            """
        # check Hello was sent

        # call the correspondig method
        return getattr(self, func_name)(peer, data)
Ejemplo n.º 19
0
 def _recv_Disconnect(self, data):
     if len(data):
         reason = packeter.disconnect_reasons_map_by_id[idec(data[0])]
         forget = reason in self.reasons_to_forget
     else:
         forget = None
         reason = None
     log_p2p.debug('received disconnect', remote_id=self, reason=None)
     signals.peer_disconnect_requested.send(sender=Peer,
                                            remote_id=self,
                                            forget=forget)
Ejemplo n.º 20
0
 def _recv_Disconnect(self, data):
     if len(data):
         reason = packeter.disconnect_reasons_map_by_id[idec(data[0])]
         logger.info('%r received disconnect: %r', self, reason)
         forget = reason in self.reasons_to_forget
     else:
         forget = None
         logger.info('%r received disconnect: w/o reason', self)
     signals.peer_disconnect_requested.send(sender=Peer,
                                            peer=self,
                                            forget=forget)
Ejemplo n.º 21
0
 def _recv_Peers(self, data):
     addresses = []
     for ip, port, pid in data:
         assert len(ip) == 4
         ip = '.'.join(str(ord(b)) for b in ip)
         port = idec(port)
         log_p2p.trace('received peer address',
                       remote_id=self,
                       ip=ip,
                       port=port)
         addresses.append([ip, port, pid])
     signals.peer_addresses_received.send(sender=Peer, addresses=addresses)
Ejemplo n.º 22
0
    def _recv_NewBlock(self, data):
        """
        NewBlock [+0x07, [blockHeader, transactionList, uncleList], totalDifficulty]
        Specify a single block that the peer should know about.
        The composite item in the list (following the message ID) is a block in
        the format described in the main Ethereum specification.

        totalDifficulty is the total difficulty of the block (aka score).
        """
        total_difficulty = idec(data[1])
        transient_block = blocks.TransientBlock(rlp.encode(data[0]))
        log_eth.debug('NewBlock', block=transient_block)
        signals.new_block_received.send(sender=Peer, peer=self, block=transient_block)
Ejemplo n.º 23
0
    def _recv_Hello(self, data):
        # check compatibility
        if idec(data[0]) != packeter.PROTOCOL_VERSION:
            return self.send_Disconnect(
                reason='Incompatible network protocols')

        if idec(data[1]) != packeter.NETWORK_ID:
            return self.send_Disconnect(reason='Wrong genesis block')

        """
        spec has CAPABILITIES after PORT, CPP client the other way round.
        emulating the latter, see  https://github.com/ethereum/cpp-ethereum
        /blob/master/libethereum/PeerNetwork.cpp#L144
        """

        # TODO add to known peers list
        self.hello_received = True
        if len(data) == 6:
            self.node_id = data[5]

        # reply with hello if not send
        if not self.hello_sent:
            self.send_Hello()
Ejemplo n.º 24
0
 def _recv_GetChain(self, data):
     """
     [0x14, Parent1, Parent2, ..., ParentN, Count]
     Request the peer to send Count (to be interpreted as an integer) blocks
     in the current canonical block chain that are children of Parent1
     (to be interpreted as a SHA3 block hash). If Parent1 is not present in
     the block chain, it should instead act as if the request were for
     Parent2 &c. through to ParentN. If the designated parent is the present
     block chain head, an empty reply should be sent. If none of the parents
     are in the current canonical block chain, then NotInChain should be
     sent along with ParentN (i.e. the last Parent in the parents list).
     If no parents are passed, then reply need not be made.
     """
     signals.local_chain_requested.send(
         sender=Peer, peer=self, block_hashes=data[:-1], count=idec(data[-1]))
Ejemplo n.º 25
0
    def _recv_Hello(self, data):
        # check compatibility
        peer_protocol_version = idec(data[0])

        logger.debug('received Hello protocol_version:{0:#04x}'.format(
                     peer_protocol_version))

        if peer_protocol_version != packeter.PROTOCOL_VERSION:
            return self.send_Disconnect(
                reason='Incompatible network protocols'
                'expected:{0:#04x} received:{1:#04x}'.format(
                    packeter.PROTOCOL_VERSION, peer_protocol_version))

        if idec(data[1]) != packeter.NETWORK_ID:
            return self.send_Disconnect(reason='Wrong genesis block')

        # TODO add to known peers list
        self.hello_received = True
        if len(data) == 6:
            self.node_id = data[5]

        # reply with hello if not send
        if not self.hello_sent:
            self.send_Hello()
Ejemplo n.º 26
0
    def _recv_NewBlock(self, data):
        """
        NewBlock [+0x07, [blockHeader, transactionList, uncleList], totalDifficulty]
        Specify a single block that the peer should know about.
        The composite item in the list (following the message ID) is a block in
        the format described in the main Ethereum specification.

        totalDifficulty is the total difficulty of the block (aka score).
        """
        total_difficulty = idec(data[1])
        transient_block = blocks.TransientBlock(rlp.encode(data[0]))
        log_eth.debug('NewBlock', block=transient_block)
        signals.new_block_received.send(sender=Peer,
                                        peer=self,
                                        block=transient_block)
Ejemplo n.º 27
0
    def _rcv_Peers(self, peer, data):
        """
        [0x11, [IP1, Port1, Id1], [IP2, Port2, Id2], ... ]
        Specifies a number of known peers. IP is a 4-byte array 'ABCD' that
        should be interpreted as the IP address A.B.C.D. Port is a 2-byte array
        that should be interpreted as a 16-bit big-endian integer.
        Id is the 512-bit hash that acts as the unique identifier of the node.

        IPs look like this: ['6', '\xcc', '\n', ')']
        """
        for ip, port, pid in data:
            assert isinstance(ip, list)
            ip = '.'.join(str(ord(b or '\x00')) for b in ip)
            port = idec(port)
            logger.debug('received peer address: {0}:{1}'.format(ip, port))
            self.peer_manager.add_peer_address(ip, port, pid)
Ejemplo n.º 28
0
    def _recv_Peers(self, peer, data):
        """
        [0x11, [IP1, Port1, Id1], [IP2, Port2, Id2], ... ]
        Specifies a number of known peers. IP is a 4-byte array 'ABCD' that
        should be interpreted as the IP address A.B.C.D. Port is a 2-byte array
        that should be interpreted as a 16-bit big-endian integer.
        Id is the 512-bit hash that acts as the unique identifier of the node.

        IPs look like this: ['6', '\xcc', '\n', ')']
        """
        for ip, port, pid in data:
            assert isinstance(ip, list)
            ip = '.'.join(str(ord(b or '\x00')) for b in ip)
            port = idec(port)
            logger.debug('received peer address: {0}:{1}'.format(ip, port))
            self.peer_manager.add_peer_address(ip, port, pid)
Ejemplo n.º 29
0
 def _recv_GetChain(self, data):
     """
     [0x14, Parent1, Parent2, ..., ParentN, Count]
     Request the peer to send Count (to be interpreted as an integer) blocks
     in the current canonical block chain that are children of Parent1
     (to be interpreted as a SHA3 block hash). If Parent1 is not present in
     the block chain, it should instead act as if the request were for
     Parent2 &c. through to ParentN. If the designated parent is the present
     block chain head, an empty reply should be sent. If none of the parents
     are in the current canonical block chain, then NotInChain should be
     sent along with ParentN (i.e. the last Parent in the parents list).
     If no parents are passed, then reply need not be made.
     """
     signals.local_chain_requested.send(sender=Peer,
                                        peer=self,
                                        block_hashes=data[:-1],
                                        count=idec(data[-1]))
Ejemplo n.º 30
0
    def _recv_GetChain(self, data):
        """
        [0x14, Parent1, Parent2, ..., ParentN, Count]
        Request the peer to send Count (to be interpreted as an integer) blocks
        in the current canonical block chain that are children of Parent1
        (to be interpreted as a SHA3 block hash). If Parent1 is not present in
        the block chain, it should instead act as if the request were for
        Parent2 &c. through to ParentN. If the designated parent is the present
        block chain head, an empty reply should be sent. If none of the parents
        are in the current canonical block chain, then NotInChain should be
        sent along with ParentN (i.e. the last Parent in the parents list).
        If no parents are passed, then reply need not be made.
        """
        block_hashes = data[:-1]
        count = idec(data[-1])

        if count > MAX_GET_CHAIN_REQUEST_BLOCKS:
            logger.warn('GetChain: Peer asking for too many blocks %d', count)

        if len(block_hashes) > MAX_GET_CHAIN_ACCEPT_HASHES:
            logger.warn('GetChain: Peer sending too many block hashes %d', len(block_hashes))

        signals.local_chain_requested.send(
            sender=Peer, peer=self, block_hashes=block_hashes, count=count)
Ejemplo n.º 31
0
 def receive_disconnect(self, data):
     reason = serialization.Serializer.disconnect_reasons_map_by_id[idec(
         data[0])]
     log('p2p.receive_disconnect', peer=self.peer, reason=reason)
     self.peer.stop()
Ejemplo n.º 32
0
 def _recv_GetBlockHashes(self, data):
     block_hash, count = data[0], idec(data[1])
     signals.get_block_hashes_received.send(sender=Peer,
                                            block_hash=block_hash,
                                            count=count,
                                            peer=self)
Ejemplo n.º 33
0
 def _rcv_Disconnect(self, peer, data):
     if len(data):
         reason = self.packeter.disconnect_reasons_map_by_id[idec(data[0])]
         logger.info('{0} sent disconnect, {1} '.format(repr(peer), reason))
     self.peer_manager.remove_peer(peer)
Ejemplo n.º 34
0
 def packet_size(cls, packet):
     return idec(packet[4:8]) + 8
Ejemplo n.º 35
0
 def packet_cmd(cls, packet):
     try:
         v = idec(rlp.descend(packet[8:200], 0))
     except rlp.DecodingError:
         v = -1
     return v
Ejemplo n.º 36
0
 def _recv_Disconnect(self, peer, data):
     if len(data):
         reason = self.packeter.disconnect_reasons_map_by_id[idec(data[0])]
         logger.info('{0} sent disconnect, {1} '.format(repr(peer), reason))
     self.peer_manager.remove_peer(peer)
Ejemplo n.º 37
0
 def _recv_Disconnect(self, data):
     if len(data):
         reason = packeter.disconnect_reasons_map_by_id[idec(data[0])]
         logger.info('{0} sent disconnect, {1} '.format(repr(self), reason))
     signals.disconnect_requested.send(sender=self)
Ejemplo n.º 38
0
    def receive_authentication(self, other, ciphertext):
        """
        Verification (function, upon receive of PresetAuthentication):
        3. remote generates ecdhe-random and nonce and creates auth
        4. remote receives auth and decrypts (ECIES performs authentication before
        decryption)
            - If address is known, lookup token and public key to be authenticated
            - derive signature-message = sha3(token || addr^addrRemote)
            - success -> AcknowledgeAuthentication
        5. remote sends auth
        6. remote derives shared-secret, aes-secret, mac-secret, ingress-mac, egress-mac
"""

        # eciesEncrypt(remote-pubk, sign(privkey, token^nonce) || 0x80 || ecdhe-random || nonce )

        data = self.node.decrypt(ciphertext)
        assert len(data) == 64 + 1 + 64 + 32
        signature = data[:65]
        assert data[65] == '0x80'
        remote_ecdhe_pubkey = data[65:65 + 64]
        token_or_nonce = idec(data[-32:])

        # verify signature
        if not self.node.verify(signature, token_or_nonce):
            return self.disconnect()

        # recover remote pubkey
        remote_pubkey = ecdsa_recover(token_or_nonce, signature)

        # lookup pubkey and related token
        token_database = dict()  # FIXME
        token = token_database.get(remote_pubkey, None)
        if token and token != token_or_nonce:
            # something fishy
            # FIXME reset node reputation
            pass

        remote_nonce = token_or_nonce

        # send authentication if not yet
        if not self._authentication_sent:
            remote_node = RemoteNode(remote_pubkey)  # FIXME LOOKUP
            self.send_authentication(remote_node)

            # - success -> AcknowledgeAuthentication
            self.acknowledge_authentication(other, remote_pubkey,
                                            remote_ecdhe_pubkey)

        # ecdhe_shared_secret = ecdh.agree(ecdhe-random, ecdhe-random-public)
        # Compute public key with the local private key and return a 512bits shared key
        ecdhe_shared_secret = self.ephemeral_ecc.get_ecdh_key(remote_pubkey)
        ecdhe_pubkey = ephemeral_ecc.get_pubkey()
        # shared-secret = sha3(ecdhe-shared-secret || sha3(nonce || remote-nonce))
        shared_secret = sha3(ecdhe_shared_secret +
                             sha3(ienc(self.nonce) + ienc(remote_nonce)))

        self.aes_secret = sha3_256(ecdhe_shared_secret + shared_secret)
        self.mac_secret = sha3_256(ecdhe_shared_secret + self.aes_secret)
        # egress-mac = sha3(mac-secret^nonce || auth)
        self.egress_mac = sha3_256(
            sxor(self.mac_secret, self.nonce) + ciphertext)
        # ingress-mac = sha3(mac-secret^remote-nonce || auth)
        self.ingress_mac = sha3_256(
            sxor(self.mac_secret, remote_nonce) + ciphertext)
        self.token = sha3(shared_secret)

        iv = pyelliptic.Cipher.gen_IV('aes-256-ctr')
        self.aes_enc = pyelliptic.Cipher(self.aes_secret,
                                         iv,
                                         1,
                                         ciphername='aes-256-ctr')
        self.aes_dec = pyelliptic.Cipher(self.aes_secret,
                                         iv,
                                         0,
                                         ciphername='aes-256-ctr')

        self.is_ready = True
Ejemplo n.º 39
0
 def _recv_GetBlockHashes(self, data):
     block_hash, count = data[0], idec(data[1])
     signals.get_block_hashes_received.send(
         sender=Peer, block_hash=block_hash, count=count, peer=self)
Ejemplo n.º 40
0
 def _rcv_Disconnect(self, peer, data):
     if len(data):
         reason = self.packeter.disconnect_reasons_map_by_id[idec(data[0])]