Пример #1
0
 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
Пример #2
0
 def got_message(self, msg):
     if msg.command == 'ping':
         pong = msg_pong(nonce=msg.nonce)
         self.sock.send(pong.to_bytes())
     elif msg.command == 'inv':
         for i in msg.inv:
             # transaction/block/txlrequest/txlvote
             if i.type in (1, 2, 4, 5):
                 gd = msg_getdata()
                 gd.inv.append(i)
                 self.sock.send(gd.to_bytes())
     if msg.command in self.route:
         self.route[msg.command](msg)
Пример #3
0
 def got_message(self, msg):
     if msg.command == 'ping':
         pong = msg_pong(nonce=msg.nonce)
         self.sock.send(pong.to_bytes())
     elif msg.command == 'inv':
         for i in msg.inv:
             # transaction/block/txlrequest/txlvote
             if i.type in (1, 2, 4, 5):
                 gd = msg_getdata()
                 gd.inv.append(i)
                 self.sock.send(gd.to_bytes())
     if msg.command in self.route:
         self.route[msg.command](msg)
Пример #4
0
	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
Пример #5
0
    def send_pong(self, ping: msg_ping, timeout: int = 1) -> bool:
        '''
        Sends pong message in response to ping message.

        Args:
            ping (bitcoin.messages.msg_ping): ping message that where received
            timeout (int): timeout for communication with connected node

        Returns:
            bool: True if the message was sent, False otherwise.

        Example:
            >>> network.send_pong(ping_message)
            True
        '''
        return self.send_message(
            msg_pong(self.protocol_version.nVersion, ping.nonce), timeout)
Пример #6
0
 def send_pong(self, ping, timeout: int = 1) -> bool:
     return self.send_message(
         msg_pong(self.protocol_version.nVersion, ping.nonce), timeout)
Пример #7
0
    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()
Пример #8
0
    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()
Пример #9
0
    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())
Пример #10
0
    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()
Пример #11
0
 def handle_ping(self, ping_message):
     # Respond with a pong message to a ping message
     msg = msg_pong()
     msg.nonce = ping_message.nonce
     self.send_message(msg)
Пример #12
0
    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))