def getblockheader(self, block_hash, verbose=False): """Get block header <block_hash> verbose - If true a dict is returned with the values returned by getblockheader that are not in the block header itself (height, nextblockhash, etc.) Raises IndexError if block_hash is not valid. """ try: block_hash = b2lx(block_hash) except TypeError: raise TypeError('%s.getblockheader(): block_hash must be bytes; got %r instance' % (self.__class__.__name__, block_hash.__class__)) try: r = self._call('getblockheader', block_hash, verbose) except InvalidAddressOrKeyError as ex: raise IndexError('%s.getblockheader(): %s (%d)' % (self.__class__.__name__, ex.error['message'], ex.error['code'])) if verbose: nextblockhash = None if 'nextblockhash' in r: nextblockhash = lx(r['nextblockhash']) return {'confirmations':r['confirmations'], 'height':r['height'], 'mediantime':r['mediantime'], 'nextblockhash':nextblockhash, 'chainwork':x(r['chainwork'])} else: return CBlockHeader.deserialize(unhexlify(r))
def getblockheader(self, block_hash, verbose=False): """Get block header <block_hash> verbose - If true a dict is returned with the values returned by getblockheader that are not in the block header itself (height, nextblockhash, etc.) Raises IndexError if block_hash is not valid. """ try: block_hash = b2lx(block_hash) except TypeError: raise TypeError( '%s.getblockheader(): block_hash must be bytes; got %r instance' % (self.__class__.__name__, block_hash.__class__)) try: r = self._call('getblockheader', block_hash, verbose) except InvalidAddressOrKeyError as ex: raise IndexError('%s.getblockheader(): %s (%d)' % (self.__class__.__name__, ex.error['message'], ex.error['code'])) if verbose: nextblockhash = None if 'nextblockhash' in r: nextblockhash = lx(r['nextblockhash']) return { 'confirmations': r['confirmations'], 'height': r['height'], 'mediantime': r['mediantime'], 'nextblockhash': nextblockhash, 'chainwork': x(r['chainwork']) } else: return CBlockHeader.deserialize(unhexlify(r))
def deserialize(self, raw): """Deserialize hex-encoded block/block header.""" only_header = False if len(raw) == 160: only_header = True block = None block_header = None try: if only_header: block_header = CBlockHeader.deserialize(x(raw)) else: # We don't use block.get_header() in case the header is # correct but the rest of the block isn't. block_header = CBlockHeader.deserialize(x(raw[0:160])) block = CBlock.deserialize(x(raw)) except Exception: pass return (block, block_header)
def get_block_header(self, block_hash: bytes, verbose: bool = False) -> CBlockHeader: payload = { "method": "getblockheader", "params": [block_hash.hex(), verbose], "jsonrpc": "2.0", "id": 0, } json_response = self.make_request(payload) result = json_response["result"] header_bytes = bytes.fromhex(result) return CBlockHeader.deserialize(header_bytes)
def getblockheader(self, block_hash): """Get block header <block_hash> Raises IndexError if block_hash is not valid. """ try: block_hash = b2lx(block_hash) except TypeError: raise TypeError('%s.getblockheader(): block_hash must be bytes; got %r instance' % (self.__class__.__name__, block_hash.__class__)) try: r = self._call('getblockheader', block_hash, False) except JSONRPCError as ex: raise IndexError('%s.getblockheader(): %s (%d)' % (self.__class__.__name__, ex.error['message'], ex.error['code'])) return CBlockHeader.deserialize(unhexlify(r))
def getblockheader(self, block_hash): """Get block header <block_hash> Raises IndexError if block_hash is not valid. """ try: block_hash = b2lx(block_hash) except TypeError: raise TypeError( '%s.getblockheader(): block_hash must be bytes; got %r instance' % (self.__class__.__name__, block_hash.__class__)) try: r = self._call('getblockheader', block_hash, False) except JSONRPCError as ex: raise IndexError('%s.getblockheader(): %s (%d)' % (self.__class__.__name__, ex.error['message'], ex.error['code'])) return CBlockHeader.deserialize(unhexlify(r))
def getblockheader(self, block_hash): """Get block header <block_hash> Raises IndexError if block_hash is not valid. There's no getblockheader RPC command, so it actually calls getblock but only deserializes the first 80 bytes. """ try: block_hash = b2lx(block_hash) except TypeError: raise TypeError('%s.getblock(): block_hash must be bytes; got %r instance' % (self.__class__.__name__, block_hash.__class__)) try: r = self._call('getblock', block_hash, False) except JSONRPCException as ex: raise IndexError('%s.getblockheader(): %s (%d)' % (self.__class__.__name__, ex.error['message'], ex.error['code'])) return CBlockHeader.deserialize(unhexlify(r[0:80*2]))
def getblockheader(self, block_hash): """Get block header <block_hash> Raises IndexError if block_hash is not valid. There's no getblockheader RPC command, so it actually calls getblock but only deserializes the first 80 bytes. """ try: block_hash = b2lx(block_hash) except TypeError: raise TypeError( '%s.getblock(): block_hash must be bytes; got %r instance' % (self.__class__.__name__, block_hash.__class__)) try: r = self._call('getblock', block_hash, False) except JSONRPCException as ex: raise IndexError('%s.getblockheader(): %s (%d)' % (self.__class__.__name__, ex.error['message'], ex.error['code'])) return CBlockHeader.deserialize(unhexlify(r[0:80 * 2]))
def connect(self): self.send_lock.acquire() self.recv_transaction_cache = FlaggedArraySet(1000) self.send_transaction_cache = FlaggedArraySet(1000) self.relay_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.relay_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) try: try: self.relay_sock.connect((self.server, 8336)) self.relay_sock.sendall(pack('>3I', self.MAGIC_BYTES, self.VERSION_TYPE, len(self.VERSION_STRING))) self.relay_sock.sendall(self.VERSION_STRING) finally: self.send_lock.release() while True: msg_header = unpack('>3I', self.relay_sock.recv(3 * 4, socket.MSG_WAITALL)) if msg_header[0] != self.MAGIC_BYTES: raise ProtocolError("Invalid magic bytes: " + str(msg_header[0]) + " != " + str(self.MAGIC_BYTES)) if msg_header[2] > 1000000: raise ProtocolError("Got message too large: " + str(msg_header[2])) if msg_header[1] == self.VERSION_TYPE: version = self.relay_sock.recv(msg_header[2], socket.MSG_WAITALL) if version != self.VERSION_STRING: raise ProtocolError("Got back unknown version type " + str(version)) print("Connected to relay node with protocol version " + str(version)) elif msg_header[1] == self.BLOCK_TYPE: if msg_header[2] > 10000: raise ProtocolError("Got a BLOCK message with far too many transactions: " + str(msg_header[2])) wire_bytes = 3 * 4 header_data = self.relay_sock.recv(80, socket.MSG_WAITALL) wire_bytes += 80 self.data_recipient.provide_block_header(header_data) if deserialize_utils: header = CBlockHeader.deserialize(header_data) print("Got block header: " + str(b2lx(header.GetHash()))) if msg_header[2] < 0xfd: block_data = header_data + pack('B', msg_header[2]) elif msg_header[2] < 0xffff: block_data = header_data + b'\xfd' + pack('<H', msg_header[2]) elif msg_header[2] < 0xffffffff: block_data = header_data + b'\xfe' + pack('<I', msg_header[2]) else: raise ProtocolError("WTF?????") for i in range(0, msg_header[2]): index = unpack('>H', self.relay_sock.recv(2, socket.MSG_WAITALL))[0] wire_bytes += 2 if index == 0xffff: data_length = unpack('>HB', self.relay_sock.recv(3, socket.MSG_WAITALL)) wire_bytes += 3 data_length = data_length[0] << 8 | data_length[1] if data_length > 1000000: raise ProtocolError("Got in-block transaction of size > MAX_BLOCK_SIZE: " + str(dat_length)) transaction_data = self.relay_sock.recv(data_length, socket.MSG_WAITALL) wire_bytes += data_length if deserialize_utils: transaction = CTransaction.deserialize(transaction_data) print("Got in-block full transaction: " + str(b2lx(transaction.GetHash())) + " of length " + str(data_length)) else: print("Got in-block full transaction of length " + str(data_length)) block_data += transaction_data else: transaction_data = self.recv_transaction_cache.get_by_index(index) if transaction_data is None: raise ProtocolError("Got index for a transaction we didn't have") self.recv_transaction_cache.remove(transaction_data) block_data += transaction_data self.data_recipient.provide_block(block_data) if deserialize_utils: print("Got full block " + str(b2lx(header.GetHash())) + " with " + str(msg_header[2]) + " transactions in " + str(wire_bytes) + " wire bytes") block = CBlock.deserialize(block_data) print("Deserialized full block " + str(b2lx(block.GetHash()))) else: print("Got full block with " + str(msg_header[2]) + " transactions in " + str(wire_bytes) + " wire bytes") if unpack('>3I', self.relay_sock.recv(3 * 4, socket.MSG_WAITALL)) != (self.MAGIC_BYTES, self.END_BLOCK_TYPE, 0): raise ProtocolError("Invalid END_BLOCK message after block") elif msg_header[1] == self.TRANSACTION_TYPE: if msg_header[2] > self.MAX_RELAY_TRANSACTION_BYTES and (self.recv_transaction_cache.get_flag_count() >= self.MAX_EXTRA_OVERSIZE_TRANSACTIONS or msg_header[2] > self.MAX_RELAY_OVERSIZE_TRANSACTION_BYTES): raise ProtocolError("Got a freely relayed transaction too large (" + str(msg_header[2]) + ") bytes") transaction_data = self.relay_sock.recv(msg_header[2], socket.MSG_WAITALL) self.recv_transaction_cache.add(transaction_data, msg_header[2] > self.MAX_RELAY_OVERSIZE_TRANSACTION_BYTES) self.data_recipient.provide_transaction(transaction_data) if deserialize_utils: transaction = CTransaction.deserialize(transaction_data) print("Got transaction: " + str(b2lx(transaction.GetHash()))) else: print("Got transaction of length " + str(msg_header[2])) elif msg_header[1] == self.MAX_VERSION_TYPE: version = self.relay_sock.recv(msg_header[2], socket.MSG_WAITALL) print("Relay network now uses version " + str(version) + " (PLEASE UPGRADE)") else: raise ProtocolError("Unknown message type: " + str(msg_header[1])) except (OSError, socket.error) as err: print("Lost connect to relay node:", err) self.reconnect() except ProtocolError as err: print("Error processing data from relay node:", err) self.reconnect() except Exception as err: print("Unknown error processing data from relay node:", err) self.reconnect()
def block_header(block_header_bytes): yield CBlockHeader.deserialize(block_header_bytes)