def parse(cls, s): '''Takes a byte stream and parses the tx_input at the start return a TxIn object ''' # reverse the prev tx hash (little endian to big endian) prev_tx = s.read(32)[::-1] prev_index = little_endian_to_int(s.read(4)) script_sig = Script.parse(s) sequence = little_endian_to_int(s.read(4)) return cls(prev_tx, prev_index, script_sig, sequence)
def parse(cls, s): '''Takes a byte stream and parses the tx_output at the start return a TxOut object ''' amount = little_endian_to_int(s.read(8)) script_pub = Script.parse(s) return cls(amount, script_pub)
def parse(cls, s): '''Takes a byte stream and parses a merkle block. Returns a Merkle Block object''' version = little_endian_to_int(s.read(4)) prev_block = s.read(32)[::-1] merkle_root = s.read(32)[::-1] timestamp = little_endian_to_int(s.read(4)) bits = s.read(4) nonce = s.read(4) total_tx_in_block = little_endian_to_int(s.read(4)) tx_hashes_number = read_varint(s) hashes = [] for i in range(tx_hashes_number): hashes.append(s.read(32)[::-1]) flag_length = read_varint(s) flags = s.read(flag_length) return cls(version, prev_block, merkle_root, timestamp, bits, nonce, total_tx_in_block, hashes, flags)
def check_pow(self): '''Returns whether this block satisfies proof of work''' # get the hash256 of the serialization of this block h256 = hash256(self.serialize()) # interpret this hash as a little-endian number proof = little_endian_to_int(h256) # return whether this integer is less than the target return proof < self.target()
def parse(cls, s): '''Takes a byte stream and parses a block. Returns a Block object''' # version - 4 bytes, little endian, interpret as int version: int = little_endian_to_int(s.read(4)) # prev_block - 32 bytes, little endian (use [::-1] to reverse) prev_block: bytes = s.read(32)[::-1] # merkle_root - 32 bytes, little endian (use [::-1] to reverse) merkle_root: bytes = s.read(32)[::-1] # timestamp - 4 bytes, little endian, interpret as int timestamp: int = little_endian_to_int(s.read(4)) # bits - 4 bytes bits: bytes = s.read(4) # nonce - 4 bytes nonce: bytes = s.read(4) return cls(version, prev_block, merkle_root, timestamp, bits, nonce)
def parse(cls, s, testnet=False): '''Takes a byte stream and parses the transaction at the start return a Tx object ''' version = little_endian_to_int(s.read(4)) num_inputs = read_varint(s) inputs = [] for _ in range(num_inputs): inputs.append(TxIn.parse(s)) num_outputs = read_varint(s) outputs = [] for _ in range(num_outputs): outputs.append(TxOut.parse(s)) locktime = little_endian_to_int(s.read(4)) return cls(version, inputs, outputs, locktime, testnet=testnet)
def load_cache(cls, filename): disk_cache = json.loads(open(filename, 'r').read()) for k, raw_hex in disk_cache.items(): raw = bytes.fromhex(raw_hex) if raw[4] == 0: raw = raw[:4] + raw[6:] tx = Tx.parse(BytesIO(raw)) tx.locktime = little_endian_to_int(raw[-4:]) else: tx = Tx.parse(BytesIO(raw)) cls.cache[k] = tx
def parse(cls, s): # get the length of the entire field length = read_varint(s) # initialize the cmds array cmds = [] # initialize the number of bytes we've read to 0 count = 0 # loop until we've read length bytes while count < length: # get the current byte current = s.read(1) # increment the bytes we've read count += 1 # convert the current byte to an integer current_int = current[0] # if the current byte is between 1 and 75 inclusive if current_int >= 1 and current_int <= 75: # we have an cmd set n to be the current byte n = current_int # add the next n bytes as an cmd cmds.append(s.read(n)) # increase the count by n count += n elif current_int == 76: # op_pushdata1 data_length = little_endian_to_int(s.read(1)) cmds.append(s.read(data_length)) count += data_length + 1 elif current_int == 77: # op_pushdata2 data_length = little_endian_to_int(s.read(2)) cmds.append(s.read(data_length)) count += data_length + 2 else: # we have an opcode. set the current byte to op_code op_code = current_int # add the op_code to the list of cmds cmds.append(op_code) if count != length: raise SyntaxError('parsing script failed') return cls(cmds)
def fetch(cls, tx_id, testnet=False, fresh=False): if fresh or (tx_id not in cls.cache): url = '{}/tx/{}.hex'.format(cls.get_url(testnet), tx_id) response = requests.get(url) try: raw = bytes.fromhex(response.text.strip()) except ValueError: raise ValueError('unexpected response: {}'.format( response.text)) # Todo: check this case. (segwit..?) if raw[4] == 0: raw = raw[:4] + raw[6:] tx = Tx.parse(BytesIO(raw), testnet=testnet) tx.locktime = little_endian_to_int(raw[-4:]) else: tx = Tx.parse(BytesIO(raw), testnet=testnet) if tx.id() != tx_id: # <1> raise ValueError('not the same id: {} vs {}'.format( tx.id(), tx_id)) cls.cache[tx_id] = tx cls.cache[tx_id].testnet = testnet return cls.cache[tx_id]
def coinbase_height(self): if not self.is_coinbase(): return None element = self.tx_ins[0].script_sig.cmds[0] return little_endian_to_int(element)