Mercurial > public > bitcaviar-plus
changeset 12:6a0a8cce058e
refactor code
author | Dennis Concepcion Martin <dennisconcepcionmartin@gmail.com> |
---|---|
date | Tue, 26 Oct 2021 09:38:38 +0200 |
parents | 4987a219a704 |
children | 4bbe48c95079 |
files | .idea/bitcaviar-plus.iml .idea/misc.xml .idea/modules.xml .idea/puppy.iml main.py setup.cfg src/bitcaviar_plus/__init__.py src/bitcaviar_plus/block.py src/bitcaviar_plus/block_structure.py src/bitcaviar_plus/helpers.py src/puppy/__init__.py src/puppy/block.py src/puppy/block_structure.py src/puppy/helpers.py tests/test_block.py |
diffstat | 13 files changed, 205 insertions(+), 228 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/bitcaviar-plus.iml Tue Oct 26 09:38:38 2021 +0200 @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="PYTHON_MODULE" version="4"> + <component name="NewModuleRootManager"> + <content url="file://$MODULE_DIR$"> + <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> + <excludeFolder url="file://$MODULE_DIR$/venv" /> + <excludeFolder url="file://$MODULE_DIR$/tests/output_files" /> + <excludeFolder url="file://$MODULE_DIR$/.idea/ZeppelinRemoteNotebooks" /> + </content> + <orderEntry type="jdk" jdkName="Python 3.8 (bitcaviar-plus)" jdkType="Python SDK" /> + <orderEntry type="sourceFolder" forTests="false" /> + </component> +</module> \ No newline at end of file
--- a/.idea/misc.xml Tue Oct 26 08:57:11 2021 +0200 +++ b/.idea/misc.xml Tue Oct 26 09:38:38 2021 +0200 @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="UTF-8"?> <project version="4"> - <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (puppy)" project-jdk-type="Python SDK" /> + <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (bitcaviar-plus)" project-jdk-type="Python SDK" /> </project> \ No newline at end of file
--- a/.idea/modules.xml Tue Oct 26 08:57:11 2021 +0200 +++ b/.idea/modules.xml Tue Oct 26 09:38:38 2021 +0200 @@ -2,7 +2,7 @@ <project version="4"> <component name="ProjectModuleManager"> <modules> - <module fileurl="file://$PROJECT_DIR$/.idea/puppy.iml" filepath="$PROJECT_DIR$/.idea/puppy.iml" /> + <module fileurl="file://$PROJECT_DIR$/.idea/bitcaviar-plus.iml" filepath="$PROJECT_DIR$/.idea/bitcaviar-plus.iml" /> </modules> </component> </project> \ No newline at end of file
--- a/.idea/puppy.iml Tue Oct 26 08:57:11 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<module type="PYTHON_MODULE" version="4"> - <component name="NewModuleRootManager"> - <content url="file://$MODULE_DIR$"> - <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> - <excludeFolder url="file://$MODULE_DIR$/venv" /> - <excludeFolder url="file://$MODULE_DIR$/.idea/ZeppelinRemoteNotebooks" /> - <excludeFolder url="file://$MODULE_DIR$/tests/output_files" /> - </content> - <orderEntry type="inheritedJdk" /> - <orderEntry type="sourceFolder" forTests="false" /> - </component> -</module> \ No newline at end of file
--- a/main.py Tue Oct 26 08:57:11 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -import os -from puppy.block import deserialize_block - - -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: - - counter = 0 - while f.tell() < file_size: - counter += 1 - block = deserialize_block(f) - if counter == 3456: - print(block) - exit() - - -if __name__ == '__main__': - main()
--- a/setup.cfg Tue Oct 26 08:57:11 2021 +0200 +++ b/setup.cfg Tue Oct 26 09:38:38 2021 +0200 @@ -1,14 +1,14 @@ [metadata] -name = example-pkg-YOUR-USERNAME-HERE +name = bitcaviar-plus version = 0.0.1 -author = Example Author -author_email = author@example.com -description = A small example package +author = Dennis Concepcion Martin +author_email = dennisconcepcionmartin@gmail.com +description = A Bitcoin blockchain parser written in Python long_description = file: README.md long_description_content_type = text/markdown -url = https://github.com/pypa/sampleproject +url = https://github.com/denniscm190/bitcaviar-plus project_urls = - Bug Tracker = https://github.com/pypa/sampleproject/issues + Bug Tracker = https://github.com/denniscm190/bitcaviar-plus/issues classifiers = Programming Language :: Python :: 3 License :: OSI Approved :: MIT License
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/bitcaviar_plus/block.py Tue Oct 26 09:38:38 2021 +0200 @@ -0,0 +1,106 @@ +from bitcaviar_plus.block_structure import * +from bitcaviar_plus.helpers import __get_var_int +from bitcaviar_plus.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.size = f.read(4)[::-1].hex() + block_header, block.id = __deserialize_header(f) + block.transaction_count = __get_var_int(f) + + transactions = [] + for transaction_number in range(int(block.transaction_count, 16)): + transactions.append(__deserialize_transaction_data(f)) + + 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_id = 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): + """ + Deserialize transaction data + More info: https://learnmeabitcoin.com/technical/transaction-data + :param f: buffer, required + :return: dict + """ + + transaction = Transaction() + start_transaction_data = f.tell() + transaction.version = f.read(4)[::-1].hex() + transaction.input_count = __get_var_int(f) + + transaction_inputs = [] + for input_number in range(int(transaction.input_count, 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.output_count = __get_var_int(f) + + transaction_outputs = [] + for output_number in range(int(transaction.output_count, 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/bitcaviar_plus/block_structure.py Tue Oct 26 09:38:38 2021 +0200 @@ -0,0 +1,36 @@ +class Block: + id = str() + magic_number = str() + size = str() + transaction_count = str() + + +class Header: + version = str() + previous_block_id = str() + merkle_root = str() + time = str() + bits = str() + nonce = str() + + +class Transaction: + id = str() + version = str() + input_count = str() + output_count = 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/bitcaviar_plus/helpers.py Tue Oct 26 09:38:38 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()
--- a/src/puppy/block.py Tue Oct 26 08:57:11 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -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.size = f.read(4)[::-1].hex() - block_header, block.id = __deserialize_header(f) - block.transaction_count = __get_var_int(f) - - transactions = [] - for transaction_number in range(int(block.transaction_count, 16)): - transactions.append(__deserialize_transaction_data(f)) - - 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_id = 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): - """ - Deserialize transaction data - More info: https://learnmeabitcoin.com/technical/transaction-data - :param f: buffer, required - :return: dict - """ - - transaction = Transaction() - start_transaction_data = f.tell() - transaction.version = f.read(4)[::-1].hex() - transaction.input_count = __get_var_int(f) - - transaction_inputs = [] - for input_number in range(int(transaction.input_count, 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.output_count = __get_var_int(f) - - transaction_outputs = [] - for output_number in range(int(transaction.output_count, 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
--- a/src/puppy/block_structure.py Tue Oct 26 08:57:11 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -class Block: - id = str() - magic_number = str() - size = str() - transaction_count = str() - - -class Header: - version = str() - previous_block_id = str() - merkle_root = str() - time = str() - bits = str() - nonce = str() - - -class Transaction: - id = str() - version = str() - input_count = str() - output_count = 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()
--- a/src/puppy/helpers.py Tue Oct 26 08:57:11 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -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()
--- a/tests/test_block.py Tue Oct 26 08:57:11 2021 +0200 +++ b/tests/test_block.py Tue Oct 26 09:38:38 2021 +0200 @@ -1,6 +1,6 @@ from unittest import TestCase from testfixtures import TempDirectory -from puppy.block import deserialize_block +from bitcaviar_plus.block import deserialize_block class TestBlock(TestCase): @@ -60,4 +60,3 @@ self.assertEqual( block, self.expected_genesis_block, 'Genesis block is not equal to expected genesis block' ) -