Mercurial > public > bitcaviar-plus
comparison src/block.py @ 5:1a8d94b500d8
finish basic parser
author | Dennis Concepcion Martin <dennisconcepcionmartin@gmail.com> |
---|---|
date | Thu, 21 Oct 2021 18:52:54 +0200 |
parents | e7a84094bf07 |
children |
comparison
equal
deleted
inserted
replaced
4:e7a84094bf07 | 5:1a8d94b500d8 |
---|---|
1 import hashlib | 1 from src.helpers import __get_hash |
2 from src.helpers import __get_variable_int | |
2 from src.block_structure import * | 3 from src.block_structure import * |
3 | 4 |
4 | 5 |
5 def read_block(f): | 6 def read_block(f): |
6 """ | 7 """ |
13 | 14 |
14 block = Block() | 15 block = Block() |
15 _ = f.read(4) # Magic number | 16 _ = f.read(4) # Magic number |
16 _ = f.read(4)[::-1] # Block size | 17 _ = f.read(4)[::-1] # Block size |
17 header_bytes = f.read(80) | 18 header_bytes = f.read(80) |
18 block.h = __get_hash(header_bytes) | 19 block.block_hash = __get_hash(header_bytes) |
19 f.seek(8) | 20 f.seek(8) |
20 block.header = __get_header(f) | 21 block.header = __get_header(f) |
21 number_of_transactions = __get_variable_int(f) | 22 number_of_transactions = __get_variable_int(f) |
23 | |
24 transactions = [] | |
22 for transaction_number in range(number_of_transactions): | 25 for transaction_number in range(number_of_transactions): |
23 block.transactions.append(__get_transaction(f)) | 26 transactions.append(__get_transaction(f)) |
24 | 27 |
25 return block.__dict__ | 28 block_dict = block.__dict__ |
29 block_dict['transactions'] = transactions | |
30 | |
31 return block_dict | |
26 | 32 |
27 | 33 |
28 def __get_header(f): | 34 def __get_header(f): |
29 """ | 35 """ |
30 Get block header | 36 Get block header |
48 Get transaction | 54 Get transaction |
49 :param f: buffer, required | 55 :param f: buffer, required |
50 :return: dict | 56 :return: dict |
51 """ | 57 """ |
52 | 58 |
59 transaction_data_start = f.tell() | |
60 | |
53 transaction = Transaction() | 61 transaction = Transaction() |
54 transaction.version = int.from_bytes(f.read(4)[::-1], 'big') | 62 transaction.version = int.from_bytes(f.read(4)[::-1], 'big') |
55 number_of_inputs = __get_variable_int(f) | 63 number_of_inputs = __get_variable_int(f) |
56 | 64 |
65 inputs = [] | |
57 for input_number in range(number_of_inputs): | 66 for input_number in range(number_of_inputs): |
58 transaction_input = TransactionInput() | 67 inputs.append(__get_input(f)) |
59 transaction_input.id = f.read(32)[::-1].hex() | |
60 | |
61 if transaction_input.id == '0000000000000000000000000000000000000000000000000000000000000000': | |
62 transaction_input.is_coinbase = True | |
63 | |
64 transaction_input.vout = int.from_bytes(f.read(4)[::-1], 'little') | |
65 script_sig_size = __get_variable_int(f) | |
66 transaction_input.script_sig = f.read(script_sig_size).hex() | |
67 transaction_input.sequence = int.from_bytes(f.read(4)[::-1], 'little') | |
68 transaction.inputs.append(transaction_input.__dict__) | |
69 | 68 |
70 number_of_outputs = __get_variable_int(f) | 69 number_of_outputs = __get_variable_int(f) |
71 | 70 |
71 outputs = [] | |
72 for output_number in range(number_of_outputs): | 72 for output_number in range(number_of_outputs): |
73 transaction_output = TransactionOutput() | 73 outputs.append(__get_outputs(f)) |
74 transaction_output.value = float.fromhex(f.read(8)[::-1].hex()) | |
75 transaction_output.value /= 100000000 # Satoshis to BTC | |
76 script_pub_key_size = __get_variable_int(f) | |
77 transaction_output.script_pub_key = f.read(script_pub_key_size) | |
78 transaction.outputs.append(transaction_output.__dict__) | |
79 | 74 |
80 transaction.lock_time = int.from_bytes(f.read(4)[::-1], 'little') | 75 transaction.lock_time = int.from_bytes(f.read(4)[::-1], 'little') |
81 | 76 |
82 print(transaction.outputs) | 77 transaction_dict = transaction.__dict__ |
83 print(transaction.inputs) | 78 transaction_dict['inputs'] = inputs |
84 print(transaction.__dict__) | 79 transaction_dict['outputs'] = outputs |
85 | 80 |
86 return transaction.__dict__ | 81 transaction_data_end = f.tell() |
82 | |
83 # Get transaction id | |
84 transaction_data_size = transaction_data_end - transaction_data_start | |
85 f.seek(transaction_data_start) | |
86 transaction_data = f.read(transaction_data_size) | |
87 transaction.id = __get_hash(transaction_data) | |
88 | |
89 return transaction_dict | |
87 | 90 |
88 | 91 |
89 def __get_hash(buffer, bytes_order='backward'): | 92 def __get_input(buffer): |
90 """ | 93 """ |
91 Compute hash from bytes | 94 Get input from transaction data |
92 More info about bytes order: https://en.wikipedia.org/wiki/Endianness | |
93 :param buffer: bytes, required | 95 :param buffer: bytes, required |
94 :param bytes_order: string, 'backward' or 'forward', optional | 96 :return: dict |
95 :return: string | |
96 """ | 97 """ |
97 | 98 |
98 h = hashlib.sha256(buffer).digest() | 99 transaction_input = TransactionInput() |
99 h = hashlib.sha256(h).digest() | 100 transaction_input.id = buffer.read(32)[::-1].hex() |
100 | 101 |
101 if bytes_order == 'backward': | 102 if transaction_input.id == '0000000000000000000000000000000000000000000000000000000000000000': |
102 h = h[::-1] | 103 transaction_input.is_coinbase = True |
103 | 104 |
104 return h.hex() | 105 transaction_input.vout = int.from_bytes(buffer.read(4)[::-1], 'little') |
106 script_sig_size = __get_variable_int(buffer) | |
107 transaction_input.script_sig = buffer.read(script_sig_size).hex() | |
108 transaction_input.sequence = int.from_bytes(buffer.read(4)[::-1], 'little') | |
109 | |
110 return transaction_input.__dict__ | |
105 | 111 |
106 | 112 |
107 def __get_variable_int(f): | 113 def __get_outputs(buffer): |
108 """ | 114 """ |
109 Get variable int from transaction data | 115 Get output from transaction data |
110 More info: https://learnmeabitcoin.com/technical/varint | 116 :param buffer: bytes, required |
111 :param f: buffer, required | 117 :return: dict |
112 :return: int | |
113 """ | 118 """ |
114 | 119 |
115 first_byte = f.read(1) | 120 transaction_output = TransactionOutput() |
121 transaction_output.value = float.fromhex(buffer.read(8)[::-1].hex()) | |
122 transaction_output.value /= 100000000 # Satoshis to BTC | |
123 script_pub_key_size = __get_variable_int(buffer) | |
124 transaction_output.script_pub_key = buffer.read(script_pub_key_size).hex() | |
116 | 125 |
117 if first_byte == b'\xfd': | 126 return transaction_output.__dict__ |
118 variable_int_bytes = f.read(2)[::-1] | |
119 elif first_byte == b'\xfe': | |
120 variable_int_bytes = f.read(4)[::-1] | |
121 elif first_byte == b'\xff': | |
122 variable_int_bytes = f.read(8)[::-1] | |
123 else: | |
124 variable_int_bytes = first_byte | |
125 | |
126 return int.from_bytes(variable_int_bytes, 'little') |