4th Street Bar Hive-Bar

Hive-Bar Powered by Hive beta-fdb5b5b

Community post

python ethereum 代码分析(一)

python 版本以太坊

项目地址
https://github.com/ethereum/pyethapp
https://github.com/ethereum/pyethereum
https://github.com/ethereum/pydevp2p
其中 pyethapp 依赖pyethereum 和 pydevp2p。pyethereum主要包括对block的处理,对transaction的处理以及以太坊虚拟机部分;pydevp2p 是p2p网络库,主要包括节点发现协议(Node Discovery)的实现,p2p通信协议的实现,并定义了protocol基类和service基类

pydevp2p 模块

代码整体结构

1.协议基类BaseProtocol 查看代码

子类协议继承BaseProtocol中的command类
来实现对不同command进行处理。

receive_packet方法

    def _setup(self):

        # collect commands
        klasses = [k for k in self.__class__.__dict__.values()
                   if isinstance(k, type) and issubclass(k, self.command) and k != self.command]
        assert len(set(k.cmd_id for k in klasses)) == len(klasses)

        def create_methods(klass):
            instance = klass()

            def receive(packet):
                "decode rlp, create dict, call receive"
                assert isinstance(packet, Packet)
                instance.receive(proto=self, data=klass.decode_payload(packet.payload))

            def create(*args, **kargs):
                "get data, rlp encode, return packet"
                res = instance.create(self, *args, **kargs)
                payload = klass.encode_payload(res)
                return Packet(self.protocol_id, klass.cmd_id, payload=payload)

            def send(*args, **kargs):
                "create and send packet"
                packet = create(*args, **kargs)
                self.send_packet(packet)

            return receive, create, send, instance.receive_callbacks

        for klass in klasses:
            receive, create, send, receive_callbacks = create_methods(klass)
            setattr(self, '_receive_' + klass.__name__, receive)
            setattr(self, 'receive_' + klass.__name__ + '_callbacks', receive_callbacks)
            setattr(self, 'create_' + klass.__name__, create)
            setattr(self, 'send_' + klass.__name__, send)

        self.cmd_by_id = dict((klass.cmd_id, klass.__name__) for klass in klasses)

2.启动peermanager Service

基类BaseService,一个service对应一个WireProtocol

先看下客户端启动时用到哪些服务:
ethapp启动的服务

其中NodeDiscovery(节点发现服务), PeerManager(节点管理服务)在pydevp2p 模块中实现。
注册服务并启动

    for service in services + contrib_services:
        assert issubclass(service, BaseService)
        if service.name not in app.config['deactivated_services'] + [AccountsService.name]:
            assert service.name not in app.services
            service.register_with_app(app)
            assert hasattr(app.services, service.name)

    # start app
    log.info('starting')
    app.start()

app.start() 中调用了所有service的start方法
先看peermanager的start方法

    def start(self):
        log.info('starting peermanager')
        # try upnp nat
        self.nat_upnp = add_portmap(
            self.config['p2p']['listen_port'],
            'TCP',
            'Ethereum DEVP2P Peermanager'
        )
        # start a listening server
        log.info('starting listener', addr=self.listen_addr)
        self.server.set_handle(self._on_new_connection)
        self.server.start()
        super(PeerManager, self).start()
        gevent.spawn_later(0.001, self._bootstrap, self.config['p2p']['bootstrap_nodes'])
        gevent.spawn_later(1, self._discovery_loop)

gevent.spawn_later(0.001, self._bootstrap, self.config[‘p2p’][‘bootstrap_nodes’]) 将_bootstrap方法加入协程调度队列,_bootstrap方法将初始化节点(bootstrap_nodes)生成peer对象并开始监听,如果没有bootstrap_nodes,则节点无法加入网络。
gevent.spawn_later(1, self._discovery_loop) 启动节点发现服务

self.server.start()启动gevent的StreamServer并用_on_new_connection函数处理新链接

    def _on_new_connection(self, connection, address):
        log.debug('incoming connection', connection=connection)
        peer = self._start_peer(connection, address)
        # Explicit join is required in gevent >= 1.1.
        # See: https://github.com/gevent/gevent/issues/594
        # and http://www.gevent.org/whatsnew_1_1.html#compatibility
        peer.join()

    def _start_peer(self, connection, address, remote_pubkey=None):
        # create peer
        peer = Peer(self, connection, remote_pubkey=remote_pubkey)
        peer.link(on_peer_exit)
        log.debug('created new peer', peer=peer, fno=connection.fileno())
        self.peers.append(peer)
        # loop
        peer.start()
        log.debug('peer started', peer=peer, fno=connection.fileno())
        assert not connection.closed
        return peer
2 upvotes $0.00

Replies (2)

Review before signing

Posting as . Signing with . Keychain permission: Posting. Hive Keychain will ask you to approve this action next.


  
Technical details

Operation fingerprint: