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 模块
代码整体结构
[IMAGE: https://steemitimages.com/DQmcZ59aR3qAYLEa8rjLSmM5Ay1n5pojzpkNSCugihW9Aaj/image.png]
1.协议基类BaseProtocol 查看代码
子类协议继承BaseProtocol中的command类
来实现对不同command进行处理。
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