Example #1
0
 def __init__(self, pubkey):
     assert len(pubkey) == 64 and isinstance(pubkey, str)
     self.pubkey = pubkey
     if k_id_size == 512:
         self.id = big_endian_to_int(pubkey)
     else:
         assert k_id_size == 256
         self.id = big_endian_to_int(sha3(pubkey))
Example #2
0
def main():
    # config
    import yaml
    import io
    import sys
    import signal
    import gevent
    from peermanager import PeerManager
    from jsonrpc import JSONRPCServer
    from discovery import NodeDiscovery
    import slogging
    log = slogging.get_logger('app')
    slogging.configure(config_string=':debug')

    # read config
    sample_config = """
p2p:
    num_peers: 10
    bootstrap_nodes:
        # local bootstrap
        # - enode://6ed2fecb28ff17dec8647f08aa4368b57790000e0e9b33a7b91f32c41b6ca9ba21600e9a8c44248ce63a71544388c6745fa291f88f8b81e109ba3da11f7b41b9@127.0.0.1:30303
        # go_bootstrap
        #- enode://6cdd090303f394a1cac34ecc9f7cda18127eafa2a3a06de39f6d920b0e583e062a7362097c7c65ee490a758b442acd5c80c6fce4b148c6a391e946b45131365b@54.169.166.226:30303
        # cpp_bootstrap
        - enode://4a44599974518ea5b0f14c31c4463692ac0329cb84851f3435e6d1b18ee4eae4aa495f846a0fa1219bd58035671881d44423876e57db2abd57254d0197da0ebe@5.1.83.226:30303

    listen_host: 0.0.0.0
    listen_port: 30303
node:
    privkey_hex: 65462b0520ef7d3df61b9992ed3bea0c56ead753be7c8b3614e0ce01e4cac41b
    """
    if len(sys.argv) == 1:
        config = yaml.load(io.BytesIO(sample_config))
        pubkey = crypto.privtopub(config['node']['privkey_hex'].decode('hex'))
        config['node']['id'] = crypto.sha3(pubkey)
    else:
        fn = sys.argv[1]
        log.info('loading config from', fn=fn)
        config = yaml.load(open(fn))

    # stop on every unhandled exception!
    gevent.get_hub().SYSTEM_ERROR = BaseException  # (KeyboardInterrupt, SystemExit, SystemError)

    print config
    # create app
    app = BaseApp(config)

    # register services
    NodeDiscovery.register_with_app(app)
    PeerManager.register_with_app(app)
    #  JSONRPCServer.register_with_app(app)

    # start app
    app.start()

    # wait for interupt
    evt = gevent.event.Event()
    # gevent.signal(signal.SIGQUIT, gevent.kill) ## killall pattern
    gevent.signal(signal.SIGQUIT, evt.set)
    gevent.signal(signal.SIGTERM, evt.set)
    gevent.signal(signal.SIGINT, evt.set)
    evt.wait()

    # finally stop
    app.stop()
Example #3
0
class P2PProtocol(BaseProtocol):
    name = 'p2p'
    version = 2

    # IF CHANGED, DO: git tag 0.6.<ETHEREUM_PROTOCOL_VERSION>
    CLIENT_VERSION = 'Ethereum(py)/%s/%s' % (sys.platform, '0.7.0')
    # the node s Unique Identifier and is the 512-bit hash that serves to
    # identify the node.
    NODE_ID = sha3('test')  # set in config
    NETWORK_ID = 0
    SYNCHRONIZATION_TOKEN = 0x22400891

    cmd_map = dict(hello=0, ping=1, pong=2, disconnect=3, getpeers=4, peers=5)

    def __init__(self, peer, cmd_offset, is_inititator=False):
        """
        initiater sends initial hello
        """
        super(P2PProtocol, self).__init__(peer, cmd_offset)
        self.is_inititator = is_inititator
        self.hello_received = False
        self.connection_monitor = ConnectionMonitor(self)
        self._handshake()

    def stop(self):
        self.connection_monitor.stop()

    @property
    def peermanager(self):
        return self.peer.peermanager

    @property
    def config(self):
        return self.peermanager.app.config

    @property
    def nodeid(self):
        return self.config.get('network', 'node_id')

    def _handshake(self):
        if self.is_inititator:
            self.send_hello()

    def _send_packet(self, cmd_name, data):
        assert isinstance(list, data)
        cmd_id = self.cmd_map['cmd_name'] + self.cmd_offset
        msg = serialization.Serializer.dump_packet([cmd_id] + data)
        self.peer.send(msg)

    def send_ping(self):
        log('p2p.send_ping', peer=self.peer)
        self._send_packet('ping', [])
        self.connection_monitor.track_request()

    def receive_ping(self, data):
        log('p2p.receive_ping', peer=self.peer)
        self.send_pong()

    def send_pong(self):
        log('p2p.send_pong', peer=self.peer)
        self._send_packet('pong')

    def receive_pong(self, data):
        log('p2p.receive_pong', peer=self.peer)
        self.connection_monitor.track_response()

    def send_disconnect(self, reason=''):
        log('p2p.send_disconnect', peer=self.peer, reason=reason)
        data = []
        if reason:
            data.append(serialization.Serializer.disconnect_reasons_map[reason]
                        )  # FIXME
        self._send_packet('disconnect', data)
        self.peer.stop()

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

    def send_getpeers(self):
        return self._send_packet('getpeers')

    def receive_getpeers(self):
        self.send_peers()

    def send_peers(self):
        '''
        :param peers: a sequence of (ip, port, pid)
        :return: None if no peers
        '''
        data = []
        for peer in self.peermanager.peers:
            ip, port = peer.ip_port
            assert ip.count('.') == 3
            ip = ''.join(chr(int(x)) for x in ip.split('.'))
            data.append([ip, port, peer.nodeid])
        return self._send_packet('peers', data)

    def receive_peers(self, data):
        pass  # FIXME

    def send_hello(self):
        """
        0x01 Hello: [0x01: P, protocolVersion: P, clientVersion: B, [cap0: B, cap1: B, ...]
        listenPort: P, id: B_64]

        protocolVersion: The underlying network protocol. 0
        clientVersion: The underlying client. A user-readable string.
        capN: A peer-network capability code, readable ASCII and 3 letters. Currently only "eth
        and "shh" are known.
        listenPort: The port on which the peer is listening for an incoming connection.
        id: The identity and public key of the peer.
        """
        log('p2p.send_hello', peer=self.peer)
        capabilities = [(p.name, p.version) for p in self.peer.protocols]

        data = [
            self.version, self.CLIENT_VERSION, capabilities,
            self.config.getint('network', 'listen_port'), self.nodeid
        ]
        self._send_packet('hello', data)

    def _recv_hello(self, data):
        log('p2p.receive_hello', peer=self.peer)
        # 0x01 Hello: [0x01: P, protocolVersion: P, clientVersion: B, [cap0: B,
        # cap1: B, ...], listenPort: P, id: B_64]
        _decode = (idec, str, list, idec, str)
        try:
            data = [_decode[i](x) for i, x in enumerate(data)]
            network_protocol_version, client_version = data[0], data[1]
            capabilities, listen_port, node_id = data[2], data[3], data[4]
            self.capabilities = [(p, ord(v)) for p, v in capabilities]
        except (IndexError, ValueError) as e:
            log('could not decode hello', peer=self, error=e)
            return self.send_Disconnect(
                reason='Incompatible network protocols')

        assert node_id
        if node_id == self.nodeid:
            log.critical('connected myself')
            return self.send_Disconnect(
                reason='Incompatible network protocols')

        self.capabilities = [(p, ord(v)) for p, v in capabilities]
        log('received hello',
            peer=self,
            network_protocol_version=network_protocol_version,
            node_id=node_id.encode('hex'),
            client_version=client_version,
            capabilities=self.capabilities)

        if network_protocol_version != self.version:
            log('incompatible network protocols',
                peer=self,
                expected=self.version,
                received=network_protocol_version)
            return self.send_Disconnect(
                reason='Incompatible network protocols')

        self.hello_received = True
        self.peer.client_version = client_version
        self.peer.nodeid = node_id
        self.peer.listen_port = listen_port  # replace connection port with listen port

        if not self.is_inititator:
            self.send_hello()

        # tell peermanager about spoken protocols
        self.peer.peermanager.on_hello_received(self, data)
        self.connection_monitor.start()