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进行处理。
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
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
Congratulations @c1ay! You received a personal award!
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!