def messageHandler(self, clientsocket, addr): while True: dataReceived = clientsocket.recv(1024) if not dataReceived: #will close the socket break; msg = MsgSerializable().from_bytes(dataReceived) print('received ',msg) print( isinstance(msg,msg_version)) if isinstance(msg,msg_version): clientsocket.send(msg_verack().to_bytes()) self.inbound_connections.add(addr[0]) print('sent verack') clientsocket.send( messages.version_pkt(MY_IP, addr[0],self.port).to_bytes() ) print('sent version_pkt') if isinstance(msg,msg_getaddr): perrAddrs = [] for peer in self.inbound_connections: perrAddr = CAddress() perrAddr.port=self.port perrAddr.nTime = int(time.time()) perrAddr.ip = peer perrAddrs.append(perrAddr) rMsg= msg_addr() rMsg.addrs = perrAddrs print(rMsg) clientsocket.send(rMsg.to_bytes()) print('sent msg_addr') time.sleep(SLEEP_TIME) clientsocket.close()
def messageHandler(self, sSocket): serverAddr= sSocket.getpeername()[0] serverPort=sSocket.getpeername()[1] sSocket.send(messages.version_pkt(MY_IP, serverAddr,serverPort).to_bytes()) while True: dataReceived = sSocket.recv(1024) if not dataReceived: #will close the socket break; msg = MsgSerializable().from_bytes(dataReceived) print('on_new_server') print('received ',msg) if isinstance(msg,msg_version): self.outbound_connections.add(serverAddr) sSocket.send(msg_verack().to_bytes()) print('sent verack') sSocket.send(msg_getaddr().to_bytes()) print('sent msg_getaddr') if isinstance(msg,msg_addr): for peer in msg.addrs: if peer.ip not in self.outbound_connections and peer.ip != MY_IP: print('new peer found'+peer.ip) t = threading.Thread(target=self.connect,args=(peer.ip, peer.port)) t.start() time.sleep(SLEEP_TIME) sSocket.close()
def connection_mock(signed_transaction): connection = MagicMock() connection.getsockname.return_value = ('127.0.0.1', 8800) connection.getpeername.return_value = ('127.0.0.1', 8800) connection.getpeername.return_value = ('127.0.0.1', 8800) protocol_version = 6002 version = msg_version(protocol_version).to_bytes() verack = msg_verack(protocol_version).to_bytes() getdata = msg_getdata(protocol_version) getdata = getdata.msg_deser(BytesIO(b'\x01\x01\x00\x00\x00' + signed_transaction.tx.GetHash())).to_bytes() connection.recv.side_effect = ( version + verack, getdata, ) capture = BitcoinTestNet.capture_messages def capture_messages_mock(*args, **kwargs): if msg_reject in args[1]: return None else: return capture(*args, **kwargs) with patch('socket.create_connection', return_value=connection): with patch('socket.gethostbyname_ex', return_value=(None, None, ['127.0.0.1'])): with patch.object(BitcoinTestNet, 'capture_messages', new=capture_messages_mock): yield
def _handle_pkt(self, pkt): if isinstance(pkt, messages.msg_version): self.ver_pkt = pkt self.last_useful = time.time() return messages.msg_verack() elif isinstance(pkt, messages.msg_ping): return messages.msg_pong(nonce=pkt.nonce) elif isinstance(pkt, messages.msg_verack): self.verack_received = True self.last_useful = time.time() return None elif isinstance(pkt, messages.msg_addr): if len(pkt.addrs) > 10: self._handle_addr(pkt) return False # disconnect, we got what we wanted else: return None # usually either forwarded or self-announcement, neither is useful elif isinstance(pkt, (messages.msg_getheaders, messages.msg_inv, messages.msg_alert, messages.msg_getblocks)): pass # irrelevant but common, don't want to spam log else: log.debug(f'other pkt from -> {self.ip}: {pkt}') if self.pkt_count > 6 and not self.getaddr_sent: self.getaddr_sent = True # some clients advertise their own address first, and only then seem to properly react to getaddr # and sometimes it seems to be unrelated to that, so just wait a few packets, then it usually # works, except for clients that just don't reply at all, which also happens # (which is why we have last_useful to expire connections that don't yield addresses in reasonable time) return messages.msg_getaddr() return None
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 send_verack(self, timeout: int = 2) -> bool: ''' Sending version acknowledge message. Args: timeout (int): timeout for communication with connected node Returns: bool: True if the message was sent, False otherwise. Example: >>> network.send_verack() True ''' return self.send_message(msg_verack(self.protocol_version.nVersion), timeout)
def test_msg_verack_to_bytes(self): m = msg_verack() b = m.to_bytes() self.assertEqual(self.verackbytes, b)
s = socket.socket() server_ip = "192.168.0.149" client_ip = "192.168.0.13" s.connect( (server_ip,PORT) ) # Send Version packet s.send( version_pkt(client_ip, server_ip).to_bytes() ) # Get Version reply print(s.recv(1924)) # Send Verack s.send( msg_verack().to_bytes() ) # Get Verack print(s.recv(1024)) # Send Addrs s.send( addr_pkt(["252.11.1.2", "EEEE:7777:8888:AAAA::1"]).to_bytes() ) time.sleep(1) s.close() # debug log on the server should look like: # accepted connection 192.168.0.13:39979 # send version message: version 70002, blocks=317947, us=****, them=0.0.0.0:0, peer=192.168.0.13:39979 # receive version message: /pythonbitcoin0.0.1/: version 70002, blocks=-1, us=192.168.0.149:18333, them=192.168.0.13:18333, peer=192.168.0.13:39979 # Added 2 addresses from 192.168.0.13: 3 tried, 1706 new # disconnecting node 192.168.0.13:39979
def got_message(self, message): gevent.sleep() if self.last_sent + 30 * 60 < time.time(): self.send_message(messages.msg_ping(self.ver_send)) self.log.debug("recv %s" % repr(message)) if message.command == "version": self.ver_send = min(self.params.PROTO_VERSION, message.nVersion) if self.ver_send < self.params.MIN_PROTO_VERSION: self.log.info("Obsolete version %d, closing" % (self.ver_send,)) self.handle_close() return if (self.ver_send >= self.params.NOBLKS_VERSION_START and self.ver_send <= self.params.NOBLKS_VERSION_END): self.getblocks_ok = False self.remote_height = message.nStartingHeight self.send_message(messages.msg_verack(self.ver_send)) if self.ver_send >= self.params.CADDR_TIME_VERSION: self.send_message(messages.msg_getaddr(self.ver_send)) self.request_latest() self.client_version = message.strSubVer elif message.command == "verack": self.ver_recv = self.ver_send if self.ver_send >= self.params.MEMPOOL_GD_VERSION: self.send_message(messages.msg_mempool()) elif message.command == "ping": if self.ver_send > self.params.BIP0031_VERSION: self.send_message(messages.msg_pong(self.ver_send)) elif message.command == "addr": self.peermgr.new_addrs(message.addrs) elif message.command == "inv": # special message sent to kick getblocks if (len(message.inv) == 1 and message.inv[0].type == messages.MSG_BLOCK and self.chaindb.haveblock(message.inv[0].hash, True)): self.request_latest(False) return want = messages.msg_getdata(self.ver_send) for i in message.inv: if i.type == 1: want.inv.append(i) elif i.type == 2: want.inv.append(i) if len(want.inv): self.send_message(want) elif message.command == "tx": if self.chaindb.tx_is_orphan(message.tx): self.log.info( "MemPool: Ignoring orphan TX {}" .format(message.tx.GetHash().encode('hex'))) elif not self.chaindb.tx_signed(message.tx, None, True): self.log.info( "MemPool: Ignoring failed-sig TX {}" .format(message.tx.GetHash().encode('hex'))) else: self.mempool.add(message.tx) elif message.command == "block": self.chaindb.putblock(message.block) self.last_block_rx = time.time() elif message.command == "headers": self.chaindb.putblock(message.block) self.last_block_rx = time.time() elif message.command == "getdata": self.getdata(message) elif message.command == "getblocks": self.getblocks(message) elif message.command == "getheaders": self.getheaders(message) elif message.command == "getaddr": msg = messages.msg_addr() msg.addrs = self.peermgr.random_addrs() self.send_message(msg) elif message.command == "mempool": msg = messages.msg_inv() for k in self.mempool.pool.iterkeys(): inv = net.CInv() inv.type = messages.MSG_TX inv.hash = k msg.inv.append(inv) if len(msg.inv) == 50000: break self.send_message(msg) # if we haven't seen a 'block' message in a little while, # and we're still not caught up, send another getblocks last_blkmsg = time.time() - self.last_block_rx if last_blkmsg > 5: self.request_latest()
def got_message(self, message): gevent.sleep() if self.last_sent + 30 * 60 < time.time(): self.send_message(msg_ping(self.ver_send)) if verbose_recvmsg(message): self.log.info("recv %s" % repr(message)) if message.command == b"version": self.ver_send = min(PROTO_VERSION, message.nVersion) if self.ver_send < MIN_PROTO_VERSION: self.log.info("Obsolete version %d, closing" % (self.ver_send, )) self.handle_close() return self.remote_height = message.nStartingHeight self.send_message(msg_verack(self.ver_send)) if self.ver_send >= CADDR_TIME_VERSION: self.send_message(msg_getaddr(self.ver_send)) # self.send_getblocks() elif message.command == b'ping': if self.ver_send > BIP0031_VERSION: self.send_message(msg_pong(self.ver_send)) elif message.command == b"verack": self.ver_recv = self.ver_send self.send_message(msg_addr()) self.send_getaddr() elif message.command == b"inv": # special message sent to kick getblocks # if (len(message.inv) == 1 and # message.inv[0].type == MSG_BLOCK and # self.chaindb.haveblock(message.inv[0].hash, True)): # self.send_getblocks(False) # return want = msg_getdata(self.ver_send) for i in message.inv: if i.type == 1: want.inv.append(i) elif i.type == 2: want.inv.append(i) self.last_want = i.hash if len(want.inv): self.send_message(want) # elif message.command == b"block": # bhash = b2lx(message.block.GetHash()) # self.chaindb.putblock(message.block) # self.last_block_rx = time.time() # if self.last_want == 0: # gevent.spawn(self.send_getblocks) # elif bhash == b2lx(self.last_want): # gevent.spawn(self.send_getblocks) elif message.command == b"addr": self.peermgr.new_addrs(message.addrs) for addr in message.addrs: self.peermgr.add(addr.ip, addr.port) elif message.command == b'getheaders': self.send_message(msg_headers())
def btc_verack_pkt(s): return s.btc_add_magic(msg_verack())
def got_message(self, message): gevent.sleep() if self.last_sent + 30 * 60 < time.time(): self.send_message(messages.msg_ping(self.ver_send)) self.log.debug("recv %s" % repr(message)) if message.command == "version": self.ver_send = min(self.params.PROTO_VERSION, message.nVersion) if self.ver_send < self.params.MIN_PROTO_VERSION: self.log.info("Obsolete version %d, closing" % (self.ver_send, )) self.handle_close() return if (self.ver_send >= self.params.NOBLKS_VERSION_START and self.ver_send <= self.params.NOBLKS_VERSION_END): self.getblocks_ok = False self.remote_height = message.nStartingHeight self.send_message(messages.msg_verack(self.ver_send)) if self.ver_send >= self.params.CADDR_TIME_VERSION: self.send_message(messages.msg_getaddr(self.ver_send)) self.request_latest() self.client_version = message.strSubVer elif message.command == "verack": self.ver_recv = self.ver_send if self.ver_send >= self.params.MEMPOOL_GD_VERSION: self.send_message(messages.msg_mempool()) elif message.command == "ping": if self.ver_send > self.params.BIP0031_VERSION: self.send_message(messages.msg_pong(self.ver_send)) elif message.command == "addr": self.peermgr.new_addrs(message.addrs) elif message.command == "inv": # special message sent to kick getblocks if (len(message.inv) == 1 and message.inv[0].type == messages.MSG_BLOCK and self.chaindb.haveblock(message.inv[0].hash, True)): self.request_latest(False) return want = messages.msg_getdata(self.ver_send) for i in message.inv: if i.type == 1: want.inv.append(i) elif i.type == 2: want.inv.append(i) if len(want.inv): self.send_message(want) elif message.command == "tx": if self.chaindb.tx_is_orphan(message.tx): self.log.info("MemPool: Ignoring orphan TX {}".format( message.tx.GetHash().encode('hex'))) elif not self.chaindb.tx_signed(message.tx, None, True): self.log.info("MemPool: Ignoring failed-sig TX {}".format( message.tx.GetHash().encode('hex'))) else: self.mempool.add(message.tx) elif message.command == "block": self.chaindb.putblock(message.block) self.last_block_rx = time.time() elif message.command == "headers": self.chaindb.putblock(message.block) self.last_block_rx = time.time() elif message.command == "getdata": self.getdata(message) elif message.command == "getblocks": self.getblocks(message) elif message.command == "getheaders": self.getheaders(message) elif message.command == "getaddr": msg = messages.msg_addr() msg.addrs = self.peermgr.random_addrs() self.send_message(msg) elif message.command == "mempool": msg = messages.msg_inv() for k in self.mempool.pool.iterkeys(): inv = net.CInv() inv.type = messages.MSG_TX inv.hash = k msg.inv.append(inv) if len(msg.inv) == 50000: break self.send_message(msg) # if we haven't seen a 'block' message in a little while, # and we're still not caught up, send another getblocks last_blkmsg = time.time() - self.last_block_rx if last_blkmsg > 5: self.request_latest()
def handle_version(self, _): # Respond with a "verack" message to a "version" message msg = msg_verack() self.send_message(msg)
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))
def got_message(self, message): gevent.sleep() if self.last_sent + 30 * 60 < time.time(): self.send_message(msg_ping(self.ver_send)) if verbose_recvmsg(message): self.log.info("recv %s" % repr(message)) if message.command == b"version": self.ver_send = min(PROTO_VERSION, message.nVersion) if self.ver_send < MIN_PROTO_VERSION: self.log.info("Obsolete version %d, closing" % (self.ver_send, )) self.handle_close() return self.remote_height = message.nStartingHeight self.send_message(msg_verack(self.ver_send)) # if self.ver_send >= CADDR_TIME_VERSION: # self.send_message(msg_getaddr(self.ver_send)) self.send_getblocks() elif message.command == b'ping': if self.ver_send > BIP0031_VERSION: self.send_message(msg_pong(self.ver_send)) elif message.command == b"verack": self.ver_recv = self.ver_send self.send_message(msg_addr()) # self.send_getaddr() elif message.command == b"inv": # special message sent to kick getblocks # if (len(message.inv) == 1 and # message.inv[0].type == MSG_BLOCK and # self.chaindb.haveblock(message.inv[0].hash, True)): # self.send_getblocks(False) # return want = msg_getdata(self.ver_send) for i in message.inv: if i.type == 1: want.inv.append(i) elif i.type == 2: want.inv.append(i) # break #UNDO self.last_want = i.hash if len(want.inv): self.send_message(want) elif message.command == b"tx": if self.chaindb.tx_is_orphan(message.tx): self.log.info("MemPool: Ignoring orphan TX %s" % (b2lx(message.tx.GetHash()), )) # elif not self.chaindb.tx_signed(message.tx, None, True): # self.log.info("MemPool: Ignoring failed-sig TX %s" % (b2lx(message.tx.GetHash()),)) else: self.chaindb.mempool_add(message.tx) elif message.command == b"block": bhash = b2lx(message.block.GetHash()) self.chaindb.putblock(message.block) # b = BytesIO() # message.block.stream_serialize(b) # s = b.getvalue() # print(b2lx(s)) self.last_block_rx = time.time() #UNDO if self.last_want == 0: gevent.spawn(self.send_getblocks) elif bhash == b2lx(self.last_want): gevent.spawn(self.send_getblocks) elif message.command == b"getheaders": self.getheaders(message) # elif message.command == b"addr": # if len(message.addrs) == 1: # gevent.spawn(self.send_getblocks) # for addr in message.addrs: # host = '%s:%s' % (addr.ip, addr.port) # if host not in self.addresses_seen: # self.addresses_seen.append(host) # elif message.command == b'tx': # for idx, vout in enumerate(message.tx.vout): # script = vout.scriptPubKey # if len(script) >= 38 and script[:6] == bitcoin.core.WITNESS_COINBASE_SCRIPTPUBKEY_MAGIC: # continue # script = CScript(vout.scriptPubKey) # if script.is_unspendable(): # print("Unspendable %s" % vout.scriptPubKey) # if vout.scriptPubKey[:4] == b'j\x07\xfe\xab': # print(vout.scriptPubKey[4:].decode('utf-8')) # continue last_blkmsg = time.time() - self.last_block_rx if last_blkmsg > 5: self.send_getblocks()
def send_verack(self, timeout: int = 2) -> bool: return self.send_message(msg_verack(self.protocol_version.nVersion), timeout)
s = socket.socket() server_ip = "192.168.0.149" client_ip = "192.168.0.13" s.connect((server_ip, PORT)) # Send Version packet s.send(version_pkt(client_ip, server_ip).to_bytes()) # Get Version reply print(s.recv(1924)) # Send Verack s.send(msg_verack().to_bytes()) # Get Verack print(s.recv(1024)) # Send Addrs s.send(addr_pkt(["252.11.1.2", "EEEE:7777:8888:AAAA::1"]).to_bytes()) time.sleep(1) s.close() # debug log on the server should look like: # accepted connection 192.168.0.13:39979 # send version message: version 70002, blocks=317947, us=****, them=0.0.0.0:0, peer=192.168.0.13:39979 # receive version message: /pythonbitcoin0.0.1/: version 70002, blocks=-1, us=192.168.0.149:18333, them=192.168.0.13:18333, peer=192.168.0.13:39979 # Added 2 addresses from 192.168.0.13: 3 tried, 1706 new # disconnecting node 192.168.0.13:39979