Mercurial > public > bitcaviar-plus
changeset 8:4d259e84160d
fix OverFlow bug
author | Dennis Concepcion Martin <dennisconcepcionmartin@gmail.com> |
---|---|
date | Sun, 24 Oct 2021 17:38:23 +0200 |
parents | e4afde8d5a7e |
children | e218f70e19e9 |
files | main.py src/puppy/block.py src/puppy/block_structure.py src/puppy/helpers.py |
diffstat | 4 files changed, 196 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/main.py Sun Oct 24 15:19:56 2021 +0200 +++ b/main.py Sun Oct 24 17:38:23 2021 +0200 @@ -1,8 +1,15 @@ -def main(): - file_path = '/Users/dennis/Bitcoin/blocks/blk00000.dat' +import os +from puppy.block import deserialize_block + - with open(file_path, 'rb') as f: - pass +def main(): + filename = '/Users/dennis/Bitcoin/blocks/blk00000.dat' + file_size = os.path.getsize(filename) + print('File size in bytes: {}'. format(file_size)) + + with open(filename, 'rb') as f: + while f.tell() < file_size: + block = deserialize_block(f) if __name__ == '__main__':
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/puppy/block.py Sun Oct 24 17:38:23 2021 +0200 @@ -0,0 +1,108 @@ +from puppy.block_structure import * +from puppy.helpers import get_var_int +from puppy.helpers import compute_hash + +""" +Deserialize methods +""" + + +def deserialize_block(f): + """ + Deserialize block + :param f: buffer, required + :return: dict + """ + + block = Block() + block.magic_number = f.read(4).hex() + block.block_size = f.read(4)[::-1].hex() + block_header, block.block_hash = deserialize_header(f) + block.number_of_transactions = get_var_int(f) + + transactions = [] + for transaction_number in range(int(block.number_of_transactions, 16)): + transactions.append(deserialize_transaction_data(f, block.block_size)) + + block_dict = block.__dict__ + block_dict['header'] = block_header + block_dict['transactions'] = transactions + + return block_dict + + +def deserialize_header(f): + """ + Deserialize block header + More info: https://learnmeabitcoin.com/technical/block-header + :param f: buffer, required + :return: (dict, string) + """ + + # Compute block hash + before = f.tell() + header = f.read(80) + block_hash = compute_hash(header) + f.seek(before) + + header = Header() + header.version = f.read(4)[::-1].hex() + header.previous_block_hash = f.read(32)[::-1].hex() + header.merkle_root = f.read(32)[::-1].hex() + header.time = f.read(4)[::-1].hex() + header.bits = f.read(4)[::-1].hex() + header.nonce = f.read(4)[::-1].hex() + + return header.__dict__, block_hash + + +def deserialize_transaction_data(f, block_size): + """ + Deserialize transaction data + More info: https://learnmeabitcoin.com/technical/transaction-data + :param f: buffer, required + :param block_size: string, required + :return: dict + """ + + start_transaction_data = f.tell() + + transaction = Transaction() + transaction.version = f.read(4)[::-1].hex() + transaction.number_of_inputs = get_var_int(f) + + transaction_inputs = [] + for input_number in range(int(transaction.number_of_inputs, 16)): + transaction_input = TransactionInput() + transaction_input.id = f.read(32)[::-1].hex() + transaction_input.vout = f.read(4)[::-1].hex() + transaction_input.script_sig_size = get_var_int(f) + transaction_input.script_sig = f.read(int(transaction_input.script_sig_size, 16)).hex() + transaction_input.sequence = f.read(4)[::-1].hex() + transaction_inputs.append(transaction_input.__dict__) + + transaction.number_of_outputs = get_var_int(f) + + transaction_outputs = [] + for output_number in range(int(transaction.number_of_outputs, 16)): + transaction_output = TransactionOutput() + transaction_output.value = f.read(8)[::-1].hex() + transaction_output.script_pub_key_size = get_var_int(f) + transaction_output.script_pub_key = f.read(int(transaction_output.script_pub_key_size, 16)).hex() + transaction_outputs.append(transaction_output.__dict__) + + transaction.lock_time = f.read(4)[::-1].hex() + + # Compute transaction id + end_transaction_data = f.tell() + transaction_data_size = end_transaction_data - start_transaction_data + f.seek(start_transaction_data) + transaction_data = f.read(transaction_data_size) + f.seek(end_transaction_data) + transaction.id = compute_hash(transaction_data) + + transaction_dict = transaction.__dict__ + transaction_dict['inputs'] = transaction_inputs + transaction_dict['outputs'] = transaction_outputs + + return transaction_dict
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/puppy/block_structure.py Sun Oct 24 17:38:23 2021 +0200 @@ -0,0 +1,36 @@ +class Block: + block_hash = str() + magic_number = str() + block_size = str() + number_of_transactions = str() + + +class Header: + version = str() + previous_block_hash = str() + merkle_root = str() + time = str() + bits = str() + nonce = str() + + +class Transaction: + id = str() + version = str() + number_of_inputs = str() + number_of_outputs = str() + lock_time = str() + + +class TransactionInput: + id = str() + vout = str() + script_sig_size = str() + script_sig = str() + sequence = str() + + +class TransactionOutput: + value = str() + script_pub_key_size = str() + script_pub_key = str()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/puppy/helpers.py Sun Oct 24 17:38:23 2021 +0200 @@ -0,0 +1,41 @@ +import hashlib + +""" +Helper methods +""" + + +def get_var_int(f): + """ + A VarInt (variable integer) is a field used in transaction data to indicate the number of upcoming fields, + or the length of an upcoming field. + More info: https://learnmeabitcoin.com/technical/varint + :param f: buffer, required + :return: string + """ + + prefix = f.read(1).hex() + + if int(prefix, 16) == 253: + number_of_transactions = f.read(2)[::-1].hex() + elif int(prefix, 16) == 254: + number_of_transactions = f.read(4)[::-1].hex() + elif int(prefix, 16) == 255: + number_of_transactions = f.read(8)[::-1].hex() + else: + number_of_transactions = prefix + + return number_of_transactions + + +def compute_hash(data): + """ + Get hash + :param data: bytes, required + :return: string + """ + + h = hashlib.sha256(data).digest() + h = hashlib.sha256(h).digest() + + return h[::-1].hex() \ No newline at end of file