def parse(cls, s): 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 = little_endian_to_int(s.read(4)) num_hashes = read_varint(s) hashes = [] for _ in range(num_hashes): hashes.append(s.read(32)[::-1]) flags_length = read_varint(s) flags = s.read(flags_length) return cls( version, prev_block, merkle_root, timestamp, bits, nonce, total, hashes, flags, )
def parse_segwit(cls, s, testnet=False): version = little_endian_to_int(s.read(4)) marker = s.read(2) if marker != b"\x00\x01": raise RuntimeError("Not a segwit transaction {}".format(marker)) 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)) for tx_in in inputs: num_items = read_varint(s) items = [] for _ in range(num_items): item_len = read_varint(s) if item_len == 0: items.append(0) else: items.append(s.read(item_len)) tx_in.witness = items locktime = little_endian_to_int(s.read(4)) return cls(version, inputs, outputs, locktime, testnet=testnet, segwit=True)
def parse(cls, s): length = read_varint(s) cmds = [] count = 0 while count < length: current = s.read(1) count += 1 current_byte = current[0] if current_byte >= 1 and current_byte <= 75: n = current_byte cmds.append(s.read(n)) count += n # OP_PUSHDATA1 elif current_byte == 76: data_length = little_endian_to_int(s.read(1)) cmds.append(s.read(data_length)) count += data_length + 1 # OP_PUSHDATA2 elif current_byte == 77: data_length = little_endian_to_int(s.read(2)) cmds.append(s.read(data_length)) count += data_length + 2 else: op_code = current_byte cmds.append(op_code) if count != length: raise SyntaxError("parsing script failed") return cls(cmds)
def parse(cls, s): 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) return cls(version, prev_block, merkle_root, timestamp, bits, nonce)
def parse_legacy(cls, s, testnet=False): 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, segwit=False)
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 test_parse(self): from io import BytesIO hex_merkle_block = "00000020df3b053dc46f162a9b00c7f0d5124e2676d47bbe7c5d0793a500000000000000ef445fef2ed495c275892206ca533e7411907971013ab83e3b47bd0d692d14d4dc7c835b67d8001ac157e670bf0d00000aba412a0d1480e370173072c9562becffe87aa661c1e4a6dbc305d38ec5dc088a7cf92e6458aca7b32edae818f9c2c98c37e06bf72ae0ce80649a38655ee1e27d34d9421d940b16732f24b94023e9d572a7f9ab8023434a4feb532d2adfc8c2c2158785d1bd04eb99df2e86c54bc13e139862897217400def5d72c280222c4cbaee7261831e1550dbb8fa82853e9fe506fc5fda3f7b919d8fe74b6282f92763cef8e625f977af7c8619c32a369b832bc2d051ecd9c73c51e76370ceabd4f25097c256597fa898d404ed53425de608ac6bfe426f6e2bb457f1c554866eb69dcb8d6bf6f880e9a59b3cd053e6c7060eeacaacf4dac6697dac20e4bd3f38a2ea2543d1ab7953e3430790a9f81e1c67f5b58c825acf46bd02848384eebe9af917274cdfbb1a28a5d58a23a17977def0de10d644258d9c54f886d47d293a411cb6226103b55635" mb = MerkleBlock.parse(BytesIO(bytes.fromhex(hex_merkle_block))) version = 0x20000000 self.assertEqual(mb.version, version) merkle_root_hex = ( "ef445fef2ed495c275892206ca533e7411907971013ab83e3b47bd0d692d14d4") merkle_root = bytes.fromhex(merkle_root_hex)[::-1] self.assertEqual(mb.merkle_root, merkle_root) prev_block_hex = ( "df3b053dc46f162a9b00c7f0d5124e2676d47bbe7c5d0793a500000000000000") prev_block = bytes.fromhex(prev_block_hex)[::-1] self.assertEqual(mb.prev_block, prev_block) timestamp = little_endian_to_int(bytes.fromhex("dc7c835b")) self.assertEqual(mb.timestamp, timestamp) bits = bytes.fromhex("67d8001a") self.assertEqual(mb.bits, bits) nonce = bytes.fromhex("c157e670") self.assertEqual(mb.nonce, nonce) total = little_endian_to_int(bytes.fromhex("bf0d0000")) self.assertEqual(mb.total, total) hex_hashes = [ "ba412a0d1480e370173072c9562becffe87aa661c1e4a6dbc305d38ec5dc088a", "7cf92e6458aca7b32edae818f9c2c98c37e06bf72ae0ce80649a38655ee1e27d", "34d9421d940b16732f24b94023e9d572a7f9ab8023434a4feb532d2adfc8c2c2", "158785d1bd04eb99df2e86c54bc13e139862897217400def5d72c280222c4cba", "ee7261831e1550dbb8fa82853e9fe506fc5fda3f7b919d8fe74b6282f92763ce", "f8e625f977af7c8619c32a369b832bc2d051ecd9c73c51e76370ceabd4f25097", "c256597fa898d404ed53425de608ac6bfe426f6e2bb457f1c554866eb69dcb8d", "6bf6f880e9a59b3cd053e6c7060eeacaacf4dac6697dac20e4bd3f38a2ea2543", "d1ab7953e3430790a9f81e1c67f5b58c825acf46bd02848384eebe9af917274c", "dfbb1a28a5d58a23a17977def0de10d644258d9c54f886d47d293a411cb62261", ] hashes = [bytes.fromhex(h)[::-1] for h in hex_hashes] self.assertEqual(mb.hashes, hashes) flags = bytes.fromhex("b55635") self.assertEqual(mb.flags, flags)
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)) if raw[4] == 0: raw = raw[:4] + raw[6:] tx = Tx.parse(BytesIO(raw), testnet) tx.locktime = little_endian_to_int(raw[-4:]) else: tx = Tx.parse(BytesIO(raw), testnet) if tx.id() != tx_id: 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 parse(cls, s, testnet=False): magic = s.read(4) if magic == b"": raise IOError("Connection reset!") if testnet: expected_magic = TESTNET_NETWORK_MAGIC else: expected_magic = NETWORK_MAGIC if magic != expected_magic: raise SyntaxError("magic is not right {} vs {}".format( magic.hex(), expected_magic.hex())) command = s.read(12) command = command.strip(b"\x00") payload_length = little_endian_to_int(s.read(4)) checksum = s.read(4) payload = s.read(payload_length) calculated_checksum = hash256(payload)[:4] if calculated_checksum != checksum: raise IOError("checksum does not match") return cls(command, payload, testnet=testnet)
def coinbase_height(self): if not self.is_coinbase(): return None first_cmd = self.tx_ins[0].script_sig.cmds[0] return little_endian_to_int(first_cmd)
def parse(cls, s): amount = little_endian_to_int(s.read(8)) script_pubkey = Script.parse(s) return cls(amount, script_pubkey)
def parse(cls, s): 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 check_pow(self): sha = hash256(self.serialize()) proof = little_endian_to_int(sha) return proof < self.target()