Mercurial > public > bitcaviar-plus
view src/block.py @ 4:e7a84094bf07
refactor code
author | Dennis Concepcion Martin <dennisconcepcionmartin@gmail.com> |
---|---|
date | Wed, 20 Oct 2021 19:36:39 +0200 |
parents | 3d83609e12a1 |
children | 1a8d94b500d8 |
line wrap: on
line source
import hashlib from src.block_structure import * def read_block(f): """ Deserialize block More info about block structure: https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch09.asciidoc More info about bytes order: https://en.wikipedia.org/wiki/Endianness :param f: buffer, required :return: """ block = Block() _ = f.read(4) # Magic number _ = f.read(4)[::-1] # Block size header_bytes = f.read(80) block.h = __get_hash(header_bytes) f.seek(8) block.header = __get_header(f) number_of_transactions = __get_variable_int(f) for transaction_number in range(number_of_transactions): block.transactions.append(__get_transaction(f)) return block.__dict__ def __get_header(f): """ Get block header :param f: buffer, required :return: dict """ header = Header() header.version = int.from_bytes(f.read(4), 'little') header.previous_block_hash = f.read(32)[::-1].hex() header.merkle_root = f.read(32)[::-1].hex() header.timestamp = int.from_bytes(f.read(4), 'little') header.bits = int.from_bytes(f.read(4), 'little') header.nonce = int.from_bytes(f.read(4), 'little') return header.__dict__ def __get_transaction(f): """ Get transaction :param f: buffer, required :return: dict """ transaction = Transaction() transaction.version = int.from_bytes(f.read(4)[::-1], 'big') number_of_inputs = __get_variable_int(f) for input_number in range(number_of_inputs): transaction_input = TransactionInput() transaction_input.id = f.read(32)[::-1].hex() if transaction_input.id == '0000000000000000000000000000000000000000000000000000000000000000': transaction_input.is_coinbase = True transaction_input.vout = int.from_bytes(f.read(4)[::-1], 'little') script_sig_size = __get_variable_int(f) transaction_input.script_sig = f.read(script_sig_size).hex() transaction_input.sequence = int.from_bytes(f.read(4)[::-1], 'little') transaction.inputs.append(transaction_input.__dict__) number_of_outputs = __get_variable_int(f) for output_number in range(number_of_outputs): transaction_output = TransactionOutput() transaction_output.value = float.fromhex(f.read(8)[::-1].hex()) transaction_output.value /= 100000000 # Satoshis to BTC script_pub_key_size = __get_variable_int(f) transaction_output.script_pub_key = f.read(script_pub_key_size) transaction.outputs.append(transaction_output.__dict__) transaction.lock_time = int.from_bytes(f.read(4)[::-1], 'little') print(transaction.outputs) print(transaction.inputs) print(transaction.__dict__) return transaction.__dict__ def __get_hash(buffer, bytes_order='backward'): """ Compute hash from bytes More info about bytes order: https://en.wikipedia.org/wiki/Endianness :param buffer: bytes, required :param bytes_order: string, 'backward' or 'forward', optional :return: string """ h = hashlib.sha256(buffer).digest() h = hashlib.sha256(h).digest() if bytes_order == 'backward': h = h[::-1] return h.hex() def __get_variable_int(f): """ Get variable int from transaction data More info: https://learnmeabitcoin.com/technical/varint :param f: buffer, required :return: int """ first_byte = f.read(1) if first_byte == b'\xfd': variable_int_bytes = f.read(2)[::-1] elif first_byte == b'\xfe': variable_int_bytes = f.read(4)[::-1] elif first_byte == b'\xff': variable_int_bytes = f.read(8)[::-1] else: variable_int_bytes = first_byte return int.from_bytes(variable_int_bytes, 'little')