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'
                 )
-