Mercurial > public > bitcaviar-plus
changeset 5:1a8d94b500d8
finish basic parser
author | Dennis Concepcion Martin <dennisconcepcionmartin@gmail.com> |
---|---|
date | Thu, 21 Oct 2021 18:52:54 +0200 |
parents | e7a84094bf07 |
children | 5f6d1a28051a |
files | main.py src/block.py src/block_structure.py src/helpers.py test_block_0.json |
diffstat | 5 files changed, 123 insertions(+), 62 deletions(-) [+] |
line wrap: on
line diff
--- a/main.py Wed Oct 20 19:36:39 2021 +0200 +++ b/main.py Thu Oct 21 18:52:54 2021 +0200 @@ -1,13 +1,13 @@ +import json from src.block import read_block def main(): with open('/Users/dennis/Bitcoin/blocks/blk00000.dat', 'rb') as f: - block = read_block(f) - - import json - with open('test_block_0.json', 'w') as f_test: - json.dump(block, f_test, ensure_ascii=False, indent=4) + for i in range(1): + block = read_block(f) + with open('test_block_0.json', 'w') as f_test: + json.dump(block, f_test, ensure_ascii=False, indent=4) if __name__ == '__main__':
--- a/src/block.py Wed Oct 20 19:36:39 2021 +0200 +++ b/src/block.py Thu Oct 21 18:52:54 2021 +0200 @@ -1,4 +1,5 @@ -import hashlib +from src.helpers import __get_hash +from src.helpers import __get_variable_int from src.block_structure import * @@ -15,14 +16,19 @@ _ = f.read(4) # Magic number _ = f.read(4)[::-1] # Block size header_bytes = f.read(80) - block.h = __get_hash(header_bytes) + block.block_hash = __get_hash(header_bytes) f.seek(8) block.header = __get_header(f) number_of_transactions = __get_variable_int(f) + + transactions = [] for transaction_number in range(number_of_transactions): - block.transactions.append(__get_transaction(f)) + transactions.append(__get_transaction(f)) - return block.__dict__ + block_dict = block.__dict__ + block_dict['transactions'] = transactions + + return block_dict def __get_header(f): @@ -50,77 +56,71 @@ :return: dict """ + transaction_data_start = f.tell() + transaction = Transaction() transaction.version = int.from_bytes(f.read(4)[::-1], 'big') number_of_inputs = __get_variable_int(f) + inputs = [] 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__) + inputs.append(__get_input(f)) number_of_outputs = __get_variable_int(f) + outputs = [] 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__) + outputs.append(__get_outputs(f)) transaction.lock_time = int.from_bytes(f.read(4)[::-1], 'little') - print(transaction.outputs) - print(transaction.inputs) - print(transaction.__dict__) + transaction_dict = transaction.__dict__ + transaction_dict['inputs'] = inputs + transaction_dict['outputs'] = outputs + + transaction_data_end = f.tell() - return transaction.__dict__ + # Get transaction id + transaction_data_size = transaction_data_end - transaction_data_start + f.seek(transaction_data_start) + transaction_data = f.read(transaction_data_size) + transaction.id = __get_hash(transaction_data) + + return transaction_dict -def __get_hash(buffer, bytes_order='backward'): +def __get_input(buffer): """ - Compute hash from bytes - More info about bytes order: https://en.wikipedia.org/wiki/Endianness + Get input from transaction data :param buffer: bytes, required - :param bytes_order: string, 'backward' or 'forward', optional - :return: string + :return: dict """ - h = hashlib.sha256(buffer).digest() - h = hashlib.sha256(h).digest() + transaction_input = TransactionInput() + transaction_input.id = buffer.read(32)[::-1].hex() + + if transaction_input.id == '0000000000000000000000000000000000000000000000000000000000000000': + transaction_input.is_coinbase = True - if bytes_order == 'backward': - h = h[::-1] + transaction_input.vout = int.from_bytes(buffer.read(4)[::-1], 'little') + script_sig_size = __get_variable_int(buffer) + transaction_input.script_sig = buffer.read(script_sig_size).hex() + transaction_input.sequence = int.from_bytes(buffer.read(4)[::-1], 'little') - return h.hex() + return transaction_input.__dict__ -def __get_variable_int(f): +def __get_outputs(buffer): """ - Get variable int from transaction data - More info: https://learnmeabitcoin.com/technical/varint - :param f: buffer, required - :return: int + Get output from transaction data + :param buffer: bytes, required + :return: dict """ - first_byte = f.read(1) + transaction_output = TransactionOutput() + transaction_output.value = float.fromhex(buffer.read(8)[::-1].hex()) + transaction_output.value /= 100000000 # Satoshis to BTC + script_pub_key_size = __get_variable_int(buffer) + transaction_output.script_pub_key = buffer.read(script_pub_key_size).hex() - 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') + return transaction_output.__dict__
--- a/src/block_structure.py Wed Oct 20 19:36:39 2021 +0200 +++ b/src/block_structure.py Thu Oct 21 18:52:54 2021 +0200 @@ -1,7 +1,6 @@ class Block: - h = str() # Block hash + block_hash = str() # Block hash header = dict() - transactions = [] class Header: @@ -14,9 +13,8 @@ class Transaction: + id = str() version = int() - inputs = [] - outputs = [] lock_time = int()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/helpers.py Thu Oct 21 18:52:54 2021 +0200 @@ -0,0 +1,41 @@ +import hashlib + + +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') \ No newline at end of file
--- a/test_block_0.json Wed Oct 20 19:36:39 2021 +0200 +++ b/test_block_0.json Thu Oct 21 18:52:54 2021 +0200 @@ -1,5 +1,5 @@ { - "h": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", + "block_hash": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", "header": { "version": 1, "previous_block_hash": "0000000000000000000000000000000000000000000000000000000000000000", @@ -7,5 +7,27 @@ "timestamp": 1231006505, "bits": 486604799, "nonce": 2083236893 - } + }, + "transactions": [ + { + "version": 1, + "lock_time": 0, + "inputs": [ + { + "id": "0000000000000000000000000000000000000000000000000000000000000000", + "is_coinbase": true, + "vout": 4294967295, + "script_sig": "04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73", + "sequence": 4294967295 + } + ], + "outputs": [ + { + "value": 50.0, + "script_pub_key": "4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac" + } + ], + "id": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" + } + ] } \ No newline at end of file