def _handle_recv(self): while True: try: msg = MsgSerializable.stream_deserialize( self.conn.makefile(mode='r'), protover=self.protover) except Exception as e: msg = e if not self._stopflag.is_set(): print("Peer connection closed unexpectedly.") break finally: self.recvq.put(msg)
def _process_message(self, **kwargs): msg = MsgSerializable.stream_deserialize(Wrapper(self.my_socket)) if msg.command == b"version": # TODO conglomerate these message strings into a dictionary # Send Verack # print('version: ', msg.strSubVer, msg.nVersion) self.my_socket.send( msg_verack().to_bytes() ) return "version" elif msg.command == b"verack": # print("verack: ", msg) return "verack" elif msg.command == b"inv": pass # print("inv: ", msg.inv) # print(dir(msg)) # print(type(msg.inv)) elif msg.command == b"ping": # print("ping: ", msg) self.my_socket.send(msg_pong(msg.nonce).to_bytes()) elif msg.command == b"getheaders": pass # print("getheaders received ") elif msg.command == b"addr": # TODO this needs multi-message support # print("addr: size ", len(msg.addrs)) for address in msg.addrs: node = Link(address.ip, address.port) self.results.add(node) return True elif msg.command == b"getdata": # print("getdata: ", msg.inv) if 'transaction' not in kwargs: return False the_tx = kwargs['transaction'] for request in msg.inv: if request.hash == the_tx.GetHash(): print(threading.current_thread().name,"sending tx: ", self.link) # new message to send transaction to_send = msg_tx() to_send.tx = the_tx self.my_socket.send(to_send.to_bytes()) # print("SENT OUR PC BRO TRANSACTION") return "donedone" else: pass # print("something else: ", msg.command, msg) return False
def process_data(self): while True: if len(self.recvbuf) < 4: return if self.recvbuf[:4] != self.netmagic.MESSAGE_START: raise ValueError("got garbage %s" % repr(self.recvbuf)) if len(self.recvbuf) < 4 + 12 + 4 + 4: return msglen = struct.unpack("<i", self.recvbuf[4+12:4+12+4])[0] if len(self.recvbuf) < 4 + 12 + 4 + 4 + msglen: return message = self.recvbuf[:4+12+4+4+msglen] self.recvbuf = self.recvbuf[4+12+4+4+msglen:] f = BytesIO(message) try: msg = MsgSerializable.stream_deserialize(f) except ValueError: raise ValueError("invalid deserialization %s" % repr(self.recvbuf)) # noqa if msg is None: return self.got_message(msg)
def process_data(self): while True: if len(self.recvbuf) < 4: return if self.recvbuf[:4] != self.netmagic.MESSAGE_START: raise ValueError("got garbage %s" % repr(self.recvbuf)) if len(self.recvbuf) < 4 + 12 + 4 + 4: return msglen = struct.unpack("<i", self.recvbuf[4 + 12:4 + 12 + 4])[0] if len(self.recvbuf) < 4 + 12 + 4 + 4 + msglen: return message = self.recvbuf[:4 + 12 + 4 + 4 + msglen] self.recvbuf = self.recvbuf[4 + 12 + 4 + 4 + msglen:] f = BytesIO(message) try: msg = MsgSerializable.stream_deserialize(f) except ValueError: raise ValueError("invalid deserialization %s" % repr(self.recvbuf)) # noqa if msg is None: return self.got_message(msg)
def getblock(self, blkhash) -> CBlock: # block = self.blk_cache.get(blkhash) # if block is not None: # return block ser_hash = b2lx(blkhash) try: # Lookup the block index, seek in the file fpos = self.db.get(('blocks:'+ser_hash).encode()) fpos = struct.unpack('i', fpos)[0] self.blk_read.seek(fpos) # read and decode "block" msg msg = MsgSerializable.stream_deserialize(self.blk_read) if msg is None: return None block = msg.block except KeyError: return None # self.blk_cache.put(blkhash, block) return block
def test_read_msg_verack(self): f = BytesIO(self.verackbytes) m = MsgSerializable.stream_deserialize(f) self.assertEqual(m.command, msg_verack.command)
def test_fail_invalid_message(self): bad_verack_bytes = b'\xf8' + self.verackbytes[1:] f = BytesIO(bad_verack_bytes) with self.assertRaises(ValueError): MsgSerializable.stream_deserialize(f)
def run(self): try: self.s.connect((self.addr.ip, self.addr.port)) version_pkt(self.addr.ip, self.addr.port).stream_serialize(self.s) except Exception as e: print(e) print("{}, {}: Version handshake failed with {}:{}".format(datetime.datetime.now(), self.name, self.addr.ip, self.addr.port)) self._stop_request.set() # Make sure we dont send an addr or inv straight away self.lastaddr = time.time() self.lastinv = time.time() while not self._stop_request.is_set(): # Send at most one of these three if time.time() - self.lastping > PING_INTERVAL: msg_ping(random.getrandbits(64)).stream_serialize(self.s) self.lastping = time.time() elif time.time() - self.lastaddr > ADDR_INTERVAL: out = msg_addr() # Grab 10 random addresses with address_lock: random_addresses = random.sample(addresses, min(10, len(addresses))) for address in random_addresses: caddr = CAddress() # Lie a bit caddr.nTime = int(time.time()) - random.randrange(300) caddr.nServices = address.services caddr.port = address.port caddr.ip = address.ip out.addrs.append(caddr) out.stream_serialize(self.s) self.lastaddr = time.time() elif time.time() - self.lastinv > INV_INTERVAL: out = msg_inv() out_inv = CInv() out_inv.type = BLOCK_TYPE out_inv.hash = guess_latest_block() out.inv = [out_inv] out.stream_serialize(self.s) self.lastinv = time.time() try: msg = MsgSerializable.stream_deserialize(self.s) t = time.time() if isinstance(msg, msg_version): msg_verack().stream_serialize(self.s) elif isinstance(msg, msg_verack): print("{}, {}: Version handshake complete".format(datetime.datetime.now(), self.name)) elif isinstance(msg, msg_ping): result = push({ "me": { "ip": my_ipv4, "port": my_port }, "time": t, "type": "ping", "peer": { "ip": self.addr.ip, "port": self.addr.port }, "last": { "ping": self.lastping, "inv": self.lastinv, "addr": self.lastaddr }, "raw": base64.b64encode(msg.to_bytes()).decode('utf-8'), "data": msg.nonce }) msg_pong(nonce=msg.nonce).stream_serialize(self.s) elif isinstance(msg, msg_pong): result = push({ "me": { "ip": my_ipv4, "port": my_port }, "time": t, "type": "pong", "peer": { "ip": self.addr.ip, "port": self.addr.port }, "last": { "ping": self.lastping, "inv": self.lastinv, "addr": self.lastaddr }, "raw": base64.b64encode(msg.to_bytes()).decode('utf-8'), "data": msg.nonce }) elif isinstance(msg, msg_getheaders): pass elif isinstance(msg, msg_alert): pass elif isinstance(msg, msg_inv): if any(item.type == BLOCK_TYPE for item in msg.inv): result = push({ "me": { "ip": my_ipv4, "port": my_port }, "time": t, "type": "inv", "peer": { "ip": self.addr.ip, "port": self.addr.port }, "last": { "ping": self.lastping, "inv": self.lastinv, "addr": self.lastaddr }, "raw": base64.b64encode(msg.to_bytes()).decode('utf-8'), "data": [ { "type": "block" if item.type == BLOCK_TYPE else "tx", "hash": b2lx(item.hash) } for item in msg.inv ] }) for inv in msg.inv: if inv.type == BLOCK_TYPE: append_latest_block(inv.hash) elif isinstance(msg, msg_addr): discover_new_addresses(msg.addrs) else: print("{}, {}: Unhandled message type: {}".format(datetime.datetime.now(), self.name, msg.command.decode('utf-8'))) except socket.timeout: continue except SerializationTruncationError: print("{}, {}: **************** Socket closed. ****************".format(datetime.datetime.now(), self.name)) break self.s.close() print("{}, {}: Stopped.".format(datetime.datetime.now(), self.name))