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