changeset 2:5b16e6df6a59

get txid hashing transaction data
author Dennis Concepcion Martin <dennisconcepcionmartin@gmail.com>
date Sun, 17 Oct 2021 11:14:46 +0200
parents 8522a23c82f0
children 3d83609e12a1
files src/block.py src/helpers.py
diffstat 2 files changed, 73 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/src/block.py	Sat Oct 16 18:59:23 2021 +0200
+++ b/src/block.py	Sun Oct 17 11:14:46 2021 +0200
@@ -1,5 +1,6 @@
 import hashlib
 from src.helpers import read_bytes
+from src.helpers import get_variable_int
 
 
 class Block:
@@ -7,36 +8,45 @@
     Block structure
     """
 
-    block_hash = None
-    magic_number = None
-    size = None
-
-    def __init__(self):
-        # Init BlockHeader class
-        self.header = self.Header()
+    block_hash = str()
+    magic_number = int()
+    size = int()
+    number_of_transactions = int()
+    transactions = []
 
     class Header:
-        version = None
-        previous_block_hash = None
-        merkle_root = None
-        timestamp = None
-        difficult_target = None
-        nonce = None
+        version = int()
+        previous_block_hash = str()
+        merkle_root = str()
+        timestamp = int()  # Epoch Unix time
+        difficult_target = int()  # Bits
+        nonce = int()
+
+
+class Transaction:
+    id = str()
+    version = int()
+    number_of_inputs = int()
+    inputs = []
+
+    class Inputs:
+        pass
 
 
 def read_block(file):
     """
     Deserialize block
+    More info about block structure: https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch09.asciidoc
     :param file: <class '_io.BufferedReader'>, required
     :return:
     """
 
     block = Block()
-    block.magic_number = int(read_bytes(file, 4), 16)
-    block.size = int(read_bytes(file, 4), 16)
+    block.magic_number = int.from_bytes(read_bytes(file, 4), 'big')
+    block.size = int.from_bytes(read_bytes(file, 4), 'big')
 
     # Compute block hash
-    header_bytes = file.read(80)
+    header_bytes = read_bytes(file, 80, 'forward')
     block_hash = hashlib.sha256(header_bytes).digest()
     block_hash = hashlib.sha256(block_hash).digest()
 
@@ -44,5 +54,29 @@
     header = block.Header()
     header.block_hash = block_hash[::-1].hex()
     header.version = int.from_bytes(header_bytes[:4], 'little')
-    header.previous_block_hash = header_bytes[4:32].hex()
+    header.previous_block_hash = header_bytes[4:36][::-1].hex()
+    header.merkle_root = header_bytes[36:68][::-1].hex()
+    header.timestamp = int.from_bytes(header_bytes[68:72], 'little')
+    header.difficult_target = int.from_bytes(header_bytes[72:76], 'little')
+    header.nonce = int.from_bytes(header_bytes[76:80], 'little')
+
+    # Number of transactions (varInt)
+    block.number_of_transactions = get_variable_int(file)
 
+    # Compute transaction ID
+    # Get remaining bytes until the end of the block
+    transaction = Transaction()
+    bytes_read = file.tell()
+    whole_block_size = block.size + 8  # Plus magic number and block size
+    transaction_data_size = whole_block_size - bytes_read
+    transaction_data = file.read(transaction_data_size)
+    file.seek(bytes_read)  # Set position to where 'transaction data' starts
+    transaction_id = hashlib.sha256(transaction_data).digest()
+    transaction_id = hashlib.sha256(transaction_id).digest()
+    transaction.id = transaction_id[::-1].hex()
+
+    transaction.version = int.from_bytes(read_bytes(file, 4), 'little')
+    transaction.number_of_inputs = get_variable_int(file)
+
+
+
--- a/src/helpers.py	Sat Oct 16 18:59:23 2021 +0200
+++ b/src/helpers.py	Sun Oct 17 11:14:46 2021 +0200
@@ -13,6 +13,26 @@
     if bytes_order == 'backward':
         b = b[::-1]
 
-    b = b.hex().upper()
+    return b
+
+
+def get_variable_int(file):
+    """
+    Get variable int from transaction data
+    More info: https://learnmeabitcoin.com/technical/varint
+    :param file: <class '_io.BufferedReader'>, required
+    :return: int
+    """
 
-    return b
+    first_byte = read_bytes(file, 1)
+
+    if first_byte == b'\xfd':
+        variable_int_bytes = read_bytes(file, 2)
+    elif first_byte == b'\xfe':
+        variable_int_bytes = read_bytes(file, 4)
+    elif first_byte == b'\xff':
+        variable_int_bytes = read_bytes(file, 8)
+    else:
+        variable_int_bytes = first_byte
+
+    return int.from_bytes(variable_int_bytes, 'little')