def read_txout(data, decompress=False): value_compressed, offset = base.read_varint(data) value = decompress_value(value_compressed) script = decompress_script(data[offset:]) if decompress else read_script( data[offset:]) return (script, value)
def read_coin(data, decompress=False): code, offset = base.read_varint(data) block_height = code >> 1 is_coinbase = code & 1 txout = read_txout(data[offset:], decompress) return (block_height, txout, is_coinbase)
def classify_compressed_script(script, is_obfuscated_snapshot=False): is_compressed = True res = None if script[0] == 0x00: # P2PKH res = ScriptType.P2PKH elif script[0] == 0x01: # P2SH res = ScriptType.P2SH elif script[0] in [0x02, 0x03]: # P2PK compressed res = ScriptType.P2PK_COMP elif script[0] in [0x04, 0x05]: # P2PK uncompressed res = ScriptType.P2PK_NONC else: # No compressable script, fall back to uncompressed classification if is_obfuscated_snapshot: if script[0] == 0x06: res = ScriptType.CoinpruneP2PKH elif script[0] == 0x07: res = ScriptType.CoinpruneP2SH elif script[0] == 0x08: res = ScriptType.CoinpruneP2WPKH elif script[0] == 0x09: res = ScriptType.CoinpruneP2WSH if res is None: is_compressed = False len_script, offset = base.read_varint(script) res = classify_uncompressed_script(script[offset:(offset + len_script)]) if res == ScriptType.OTHER: log.error( f'Detected OTHER script: {hexlify(script)} vs. {hexlify(script[offset:(offset + len_script)])}' ) log.error(f'Len script: {len_script}, Offset: {offset}') return res, is_compressed
def read_script(data): size, _ = base.read_varint(data) if size < SPECIAL_SCRIPTS: size = 20 if size in [0, 1] else 32 else: size -= SPECIAL_SCRIPTS return data[:(size + 1)]
def get_script_payload_compressed(script, is_obfuscated_snapshot=False): _, is_compressed = classify_compressed_script( script, is_obfuscated_snapshot=is_obfuscated_snapshot) if is_compressed: return script[1:] else: len_script, offset = base.read_varint(script) return get_script_payload_uncompressed(script[offset:(offset + len_script)])
def decompress_script( data, is_obfuscated_snapshot=False): # see bitcoin core compressor.h:63 size, offset = base.read_varint(data) data = data[offset:] if size < SPECIAL_SCRIPTS: case = size size = 20 if size in [0, 1 ] else 32 # see bitcoin core compressor.cpp:87 script_payload = data[:size] return decompress_payload( case, script_payload, is_obfuscated_snapshot=is_obfuscated_snapshot)
elif script_type == ScriptType.P2WPKH: case = SPECIAL_SCRIPTS + 0x02 elif script_type == ScriptType.P2WSH: case = SPECIAL_SCRIPTS + 0x03 res = bytes([case]) + payload obfuscated = True compressed = True elif script_type in [ScriptType.P2PK_NONC, ScriptType.P2PK_COMP ] and is_compressed: res = script obfuscated = False compressed = True else: res = script res, offset = base.read_varint(script) res = script[offset:] res = base.write_varint(SPECIAL_SCRIPTS + 4 + len(res)) + res obfuscated = False compressed = is_compressed add_case(script_type) return res, obfuscated, compressed def obfuscate_compressed_script_file(file_handler, script): script_new, _, _ = obfuscate_compressed_script(script) file_handler.write(script_new)