Mercurial > public > bitcaviar-plus
changeset 6:5f6d1a28051a
add python package config files
author | Dennis Concepcion Martin <dennisconcepcionmartin@gmail.com> |
---|---|
date | Sun, 24 Oct 2021 15:18:54 +0200 |
parents | 1a8d94b500d8 |
children | e4afde8d5a7e |
files | .gitignore .idea/puppy.iml main.py pyproject.toml setup.cfg src/__init__.py src/block.py src/block_structure.py src/helpers.py src/puppy/__init__.py src/puppy/block.py src/puppy/block_structure.py src/puppy/helpers.py test_block_0.json tests/__init__.py |
diffstat | 12 files changed, 240 insertions(+), 238 deletions(-) [+] |
line wrap: on
line diff
--- a/.gitignore Thu Oct 21 18:52:54 2021 +0200 +++ b/.gitignore Sun Oct 24 15:18:54 2021 +0200 @@ -1,4 +1,3 @@ - # Created by https://www.toptal.com/developers/gitignore/api/macos,python,pycharm # Edit at https://www.toptal.com/developers/gitignore?templates=macos,python,pycharm
--- a/.idea/puppy.iml Thu Oct 21 18:52:54 2021 +0200 +++ b/.idea/puppy.iml Sun Oct 24 15:18:54 2021 +0200 @@ -2,7 +2,10 @@ <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" />
--- a/main.py Thu Oct 21 18:52:54 2021 +0200 +++ b/main.py Sun Oct 24 15:18:54 2021 +0200 @@ -1,13 +1,15 @@ -import json -from src.block import read_block +import os +from src.puppy.block import read_block def main(): - with open('/Users/dennis/Bitcoin/blocks/blk00000.dat', 'rb') as f: - for i in range(1): + file_path = '/Users/dennis/Bitcoin/blocks/blk00000.dat' + + with open(file_path, 'rb') as f: + number_of_bytes_in_file = os.path.getsize(file_path) + + while f.tell() < number_of_bytes_in_file: 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__':
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pyproject.toml Sun Oct 24 15:18:54 2021 +0200 @@ -0,0 +1,6 @@ +[build-system] +requires = [ + "setuptools>=42", + "wheel" +] +build-backend = "setuptools.build_meta" \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup.cfg Sun Oct 24 15:18:54 2021 +0200 @@ -0,0 +1,24 @@ +[metadata] +name = example-pkg-YOUR-USERNAME-HERE +version = 0.0.1 +author = Example Author +author_email = author@example.com +description = A small example package +long_description = file: README.md +long_description_content_type = text/markdown +url = https://github.com/pypa/sampleproject +project_urls = + Bug Tracker = https://github.com/pypa/sampleproject/issues +classifiers = + Programming Language :: Python :: 3 + License :: OSI Approved :: MIT License + Operating System :: OS Independent + +[options] +package_dir = + = src +packages = find: +python_requires = >=3.8 + +[options.packages.find] +where = src \ No newline at end of file
--- a/src/block.py Thu Oct 21 18:52:54 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,126 +0,0 @@ -from src.helpers import __get_hash -from src.helpers import __get_variable_int -from src.block_structure import * - - -def read_block(f): - """ - Deserialize block - More info about block structure: https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch09.asciidoc - More info about bytes order: https://en.wikipedia.org/wiki/Endianness - :param f: buffer, required - :return: - """ - - block = Block() - _ = f.read(4) # Magic number - _ = f.read(4)[::-1] # Block size - header_bytes = f.read(80) - 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): - transactions.append(__get_transaction(f)) - - block_dict = block.__dict__ - block_dict['transactions'] = transactions - - return block_dict - - -def __get_header(f): - """ - Get block header - :param f: buffer, required - :return: dict - """ - - header = Header() - header.version = int.from_bytes(f.read(4), 'little') - header.previous_block_hash = f.read(32)[::-1].hex() - header.merkle_root = f.read(32)[::-1].hex() - header.timestamp = int.from_bytes(f.read(4), 'little') - header.bits = int.from_bytes(f.read(4), 'little') - header.nonce = int.from_bytes(f.read(4), 'little') - - return header.__dict__ - - -def __get_transaction(f): - """ - Get transaction - :param f: buffer, required - :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): - inputs.append(__get_input(f)) - - number_of_outputs = __get_variable_int(f) - - outputs = [] - for output_number in range(number_of_outputs): - outputs.append(__get_outputs(f)) - - transaction.lock_time = int.from_bytes(f.read(4)[::-1], 'little') - - transaction_dict = transaction.__dict__ - transaction_dict['inputs'] = inputs - transaction_dict['outputs'] = outputs - - transaction_data_end = f.tell() - - # 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_input(buffer): - """ - Get input from transaction data - :param buffer: bytes, required - :return: dict - """ - - transaction_input = TransactionInput() - transaction_input.id = buffer.read(32)[::-1].hex() - - if transaction_input.id == '0000000000000000000000000000000000000000000000000000000000000000': - transaction_input.is_coinbase = True - - 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 transaction_input.__dict__ - - -def __get_outputs(buffer): - """ - Get output from transaction data - :param buffer: bytes, required - :return: dict - """ - - 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() - - return transaction_output.__dict__
--- a/src/block_structure.py Thu Oct 21 18:52:54 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -class Block: - block_hash = str() # Block hash - header = dict() - - -class Header: - version = int() - previous_block_hash = str() - merkle_root = str() - timestamp = int() - bits = int() - nonce = int() - - -class Transaction: - id = str() - version = int() - lock_time = int() - - -class TransactionInput: - is_coinbase = False - id = str() - vout = int() - script_sig = str() - sequence = int() - - -class TransactionOutput: - value = float() - script_pub_key = str() \ No newline at end of file
--- a/src/helpers.py Thu Oct 21 18:52:54 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/puppy/block.py Sun Oct 24 15:18:54 2021 +0200 @@ -0,0 +1,127 @@ +from puppy.helpers import __get_hash +from puppy.helpers import __get_variable_int +from puppy.block_structure import * + + +def read_block(f): + """ + Deserialize block + More info about block structure: https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch09.asciidoc + More info about bytes order: https://en.wikipedia.org/wiki/Endianness + :param f: buffer, required + :return: + """ + + block = Block() + _ = f.read(4) # Magic number + _ = f.read(4)[::-1] # Block size + position_before_header = f.tell() + header_bytes = f.read(80) + block.block_hash = __get_hash(header_bytes) + f.seek(position_before_header) + block.header = __get_header(f) + number_of_transactions = __get_variable_int(f) + + transactions = [] + for transaction_number in range(number_of_transactions): + transactions.append(__get_transaction(f)) + + block_dict = block.__dict__ + block_dict['transactions'] = transactions + + return block_dict + + +def __get_header(f): + """ + Get block header + :param f: buffer, required + :return: dict + """ + + header = Header() + header.version = int.from_bytes(f.read(4), 'little') + header.previous_block_hash = f.read(32)[::-1].hex() + header.merkle_root = f.read(32)[::-1].hex() + header.timestamp = int.from_bytes(f.read(4), 'little') + header.bits = int.from_bytes(f.read(4), 'little') + header.nonce = int.from_bytes(f.read(4), 'little') + + return header.__dict__ + + +def __get_transaction(f): + """ + Get transaction + :param f: buffer, required + :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): + inputs.append(__get_input(f)) + + number_of_outputs = __get_variable_int(f) + + outputs = [] + for output_number in range(number_of_outputs): + outputs.append(__get_outputs(f)) + + transaction.lock_time = int.from_bytes(f.read(4)[::-1], 'little') + + transaction_dict = transaction.__dict__ + transaction_dict['inputs'] = inputs + transaction_dict['outputs'] = outputs + + transaction_data_end = f.tell() + + # Get current transaction ID: https://learnmeabitcoin.com/technical/txid + 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_input(buffer): + """ + Get input from transaction data + :param buffer: bytes, required + :return: dict + """ + + transaction_input = TransactionInput() + transaction_input.id = buffer.read(32)[::-1].hex() + + if transaction_input.id == '0000000000000000000000000000000000000000000000000000000000000000': + transaction_input.is_coinbase = True + + 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 transaction_input.__dict__ + + +def __get_outputs(buffer): + """ + Get output from transaction data + :param buffer: bytes, required + :return: dict + """ + + 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() + + return transaction_output.__dict__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/puppy/block_structure.py Sun Oct 24 15:18:54 2021 +0200 @@ -0,0 +1,31 @@ +class Block: + block_hash = str() + header = dict() + + +class Header: + version = int() + previous_block_hash = str() + merkle_root = str() + timestamp = int() + bits = int() + nonce = int() + + +class Transaction: + id = str() + version = int() + lock_time = int() + + +class TransactionInput: + is_coinbase = False + id = str() + vout = int() + script_sig = str() + sequence = int() + + +class TransactionOutput: + value = float() + script_pub_key = str() \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/puppy/helpers.py Sun Oct 24 15:18: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')
--- a/test_block_0.json Thu Oct 21 18:52:54 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -{ - "block_hash": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", - "header": { - "version": 1, - "previous_block_hash": "0000000000000000000000000000000000000000000000000000000000000000", - "merkle_root": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", - "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