python ethereum 代码分析(一)

in #cn7 years ago (edited)

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
Sort:  

Congratulations @c1ay! You have completed some achievement on Steemit and have been rewarded with new badge(s) :

You made your First Comment

Click on any badge to view your own Board of Honor on SteemitBoard.
For more information about SteemitBoard, click here

If you no longer want to receive notifications, reply to this comment with the word STOP

By upvoting this notification, you can help all Steemit users. Learn how here!

Congratulations @c1ay! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 2 years!

You can view your badges on your Steem Board and compare to others on the Steem Ranking

Vote for @Steemitboard as a witness to get one more award and increased upvotes!