Skip to content

Commit

Permalink
Proper deserialization was implemented
Browse files Browse the repository at this point in the history
  • Loading branch information
obamwonyi committed Apr 13, 2024
1 parent b00a9c9 commit ebb0f96
Show file tree
Hide file tree
Showing 22 changed files with 449 additions and 28 deletions.
33 changes: 20 additions & 13 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,43 @@
import os
import asyncio
# TODO: replace json with a serializer
import json
from src.transaction import Transaction, TransactionSchema
from src.validation import validate_transactions
from marshmallow import ValidationError
from src.mine import Mine

async def main() -> None:
"""
This will be responsible for kick-starting the mining process
:return: None
"""
# Read and deserialize transactions from mempool directory
async def main():
# Step 1: Read and deserialize transactions from the mempool directory
transactions = []
errors = 0
for filename in os.listdir("mempool"):
filepath = os.path.join("mempool", filename)
with open(filepath, "r") as file:
json_data = file.read()
# TODO: This would be reimplemented after I fix deserizlizing with marshmallow
transaction_schema = TransactionSchema()
try:
transaction = transaction_schema.load(json_data)
transaction = transaction_schema.load(json.loads(json_data))
transactions.append(transaction)
except Exception as e:
print(f"Error deserializing transaction {filename}: {e}")

# Validate transactions asynchronously
print(f"Deserialized transaction from {filename}")
except ValidationError as e:
errors = errors + 1
print(f"Error deserializing transaction {filename}:")
print(e.messages)

print(f"Total transactions deserialized: {len(transactions)}")
print(f"Total failed transactions:{errors}")

# Step 2: Validate transactions asynchronously
valid_transactions = await validate_transactions(transactions)

# Mine the block
# Step 3: Mine the block
block_data = mine_block(valid_transactions)

# Step 4: Write the block data to the output.txt file
with open("output.txt", "w") as output_file:
output_file.write(block_data)


if __name__ == "__main__":
asyncio.run(main())
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
marshmallow==3.21.1
packaging==24.0
14 changes: 7 additions & 7 deletions run.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#!/bin/bash

# Create a virtual environment
python3 -m venv venv
# # Create a virtual environment
# python3 -m venv venv

# Activate the virtual environment
source venv/bin/activate
# # Activate the virtual environment
# source venv/bin/activate

# Install project dependencies
pip install -r requirements.txt
# # Install project dependencies
# pip install -r requirements.txt

# Run the mine_block.py script
python3 src/mine_block.py
python3 main.py
Binary file added src/__pycache__/__init__.cpython-310.pyc
Binary file not shown.
Binary file added src/__pycache__/mine.cpython-310.pyc
Binary file not shown.
Binary file added src/__pycache__/transaction.cpython-310.pyc
Binary file not shown.
Binary file added src/__pycache__/validation.cpython-310.pyc
Binary file not shown.
6 changes: 4 additions & 2 deletions src/mine.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ def mine_block(valid_transactions) -> str:
:param valid_transactions: all the validated transactions
:return: str
"""
# TODO: implement block mining here

block_data = "Block header\nCoinbase transaction\n"
for transaction in valid_transactions:
block_data += f"{transaction.txid}\n"
for tx in valid_transactions:
block_data += f"{tx.txid}\n"
return block_data
32 changes: 29 additions & 3 deletions src/transaction.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,36 @@
from marshmallow import Schema, fields, post_load

class PrevOutSchema(Schema):
scriptpubkey = fields.Str(required=True)
scriptpubkey_asm = fields.Str(required=True)
scriptpubkey_type = fields.Str(required=True)
scriptpubkey_address = fields.Str(required=True)
value = fields.Int(required=True)

class VinSchema(Schema):
txid = fields.Str(required=True)
vout = fields.Int(required=True)
prevout = fields.Nested(PrevOutSchema, required=True)
scriptsig = fields.Str(required=True)
scriptsig_asm = fields.Str(required=True)
witness = fields.List(fields.Str(), required=False)
is_coinbase = fields.Bool(required=True)
sequence = fields.Int(required=True)
inner_redeemscript_asm = fields.Str(required=False)
inner_witnessscript_asm = fields.Str(required=False)

class VoutSchema(Schema):
scriptpubkey = fields.Str(required=True)
scriptpubkey_asm = fields.Str(required=True)
scriptpubkey_type = fields.Str(required=True)
scriptpubkey_address = fields.Str(required=False)
value = fields.Int(required=True)

class TransactionSchema(Schema):
version = fields.Int(required=True)
locktime = fields.Int(required=True)
vin = fields.List(fields.Dict(), required=True)
vout = fields.List(fields.Dict(), required=True)
vin = fields.List(fields.Nested(VinSchema), required=True)
vout = fields.List(fields.Nested(VoutSchema), required=True)

@post_load
def make_transaction(self, data, **kwargs):
Expand All @@ -16,6 +42,6 @@ class Transaction:
"""
def __init__(self, version, locktime, vin, vout) -> None:
self.version = version
self.locktime = version
self.locktime = locktime
self.vin = vin
self.vout = vout
4 changes: 2 additions & 2 deletions src/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ async def validate_transaction(transaction) -> bool:
:param transaction: a transaction to be validated
:return: bool
"""
pass


async def validate_transactions(transactions) -> list:
"""
Expand All @@ -27,5 +27,5 @@ async def validate_transactions(transactions) -> list:
for tx, is_valid in zip(transactions, validation_results):
if is_valid:
valid_transactions.append(tx)

return valid_transactions
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pip
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Copyright 2016-2017 Maxim Kulkin
Copyright 2018 Alex Rothberg and contributors
Copyright 2024 Steven Loria and contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
Metadata-Version: 2.1
Name: marshmallow-oneofschema
Version: 3.1.1
Summary: marshmallow multiplexing schema
Author-email: Maxim Kulkin <[email protected]>
Maintainer-email: Steven Loria <[email protected]>
Requires-Python: >=3.8
Description-Content-Type: text/x-rst
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Dist: marshmallow>=3.0.0,<4.0.0
Requires-Dist: marshmallow-oneofschema[tests] ; extra == "dev"
Requires-Dist: tox ; extra == "dev"
Requires-Dist: pre-commit~=3.5 ; extra == "dev"
Requires-Dist: pytest ; extra == "tests"
Project-URL: Funding, https://opencollective.com/marshmallow
Project-URL: Issues, https://github.com/marshmallow-code/marshmallow-oneofschema/issues
Project-URL: Source, https://github.com/marshmallow-code/marshmallow-oneofschema
Provides-Extra: dev
Provides-Extra: tests

=======================
marshmallow-oneofschema
=======================

.. image:: https://github.com/marshmallow-code/marshmallow-oneofschema/actions/workflows/build-release.yml/badge.svg
:target: https://github.com/marshmallow-code/flask-marshmallow/actions/workflows/build-release.yml
:alt: Build Status

.. image:: https://badgen.net/badge/marshmallow/3
:target: https://marshmallow.readthedocs.io/en/latest/upgrading.html
:alt: marshmallow 3 compatible

An extension to marshmallow to support schema (de)multiplexing.

marshmallow is a fantastic library for serialization and deserialization of data.
For more on that project see its `GitHub <https://github.com/marshmallow-code/marshmallow>`_
page or its `Documentation <http://marshmallow.readthedocs.org/en/latest/>`_.

This library adds a special kind of schema that actually multiplexes other schemas
based on object type. When serializing values, it uses get_obj_type() method
to get object type name. Then it uses ``type_schemas`` name-to-Schema mapping
to get schema for that particular object type, serializes object using that
schema and adds an extra field with name of object type. Deserialization is reverse.

Installing
----------

::

$ pip install marshmallow-oneofschema

Example
-------

The code below demonstrates how to set up a polymorphic schema. For the full context check out the tests.
Once setup the schema should act like any other schema. If it does not then please file an Issue.

.. code:: python

import marshmallow
import marshmallow.fields
from marshmallow_oneofschema import OneOfSchema


class Foo:
def __init__(self, foo):
self.foo = foo


class Bar:
def __init__(self, bar):
self.bar = bar


class FooSchema(marshmallow.Schema):
foo = marshmallow.fields.String(required=True)

@marshmallow.post_load
def make_foo(self, data, **kwargs):
return Foo(**data)


class BarSchema(marshmallow.Schema):
bar = marshmallow.fields.Integer(required=True)

@marshmallow.post_load
def make_bar(self, data, **kwargs):
return Bar(**data)


class MyUberSchema(OneOfSchema):
type_schemas = {"foo": FooSchema, "bar": BarSchema}

def get_obj_type(self, obj):
if isinstance(obj, Foo):
return "foo"
elif isinstance(obj, Bar):
return "bar"
else:
raise Exception("Unknown object type: {}".format(obj.__class__.__name__))


MyUberSchema().dump([Foo(foo="hello"), Bar(bar=123)], many=True)
# => [{'type': 'foo', 'foo': 'hello'}, {'type': 'bar', 'bar': 123}]

MyUberSchema().load(
[{"type": "foo", "foo": "hello"}, {"type": "bar", "bar": 123}], many=True
)
# => [Foo('hello'), Bar(123)]

By default get_obj_type() returns obj.__class__.__name__, so you can just reuse that
to save some typing:

.. code:: python

class MyUberSchema(OneOfSchema):
type_schemas = {"Foo": FooSchema, "Bar": BarSchema}

You can customize type field with `type_field` class property:

.. code:: python

class MyUberSchema(OneOfSchema):
type_field = "object_type"
type_schemas = {"Foo": FooSchema, "Bar": BarSchema}


MyUberSchema().dump([Foo(foo="hello"), Bar(bar=123)], many=True)
# => [{'object_type': 'Foo', 'foo': 'hello'}, {'object_type': 'Bar', 'bar': 123}]

You can use resulting schema everywhere marshmallow.Schema can be used, e.g.

.. code:: python

import marshmallow as m
import marshmallow.fields as f


class MyOtherSchema(m.Schema):
items = f.List(f.Nested(MyUberSchema))

License
-------

MIT licensed. See the bundled `LICENSE <https://github.com/marshmallow-code/marshmallow-oneofschema/blob/master/LICENSE>`_ file for more details.

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
marshmallow_oneofschema-3.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
marshmallow_oneofschema-3.1.1.dist-info/LICENSE,sha256=Dj6i54GCxVk8glcTykJvh2Mga2HVVWw0_0cARUXh_uk,1148
marshmallow_oneofschema-3.1.1.dist-info/METADATA,sha256=cPVqGW5WZduc5r9TBHC-fxFMu8Axv0XO1cd9LIuLZCI,5018
marshmallow_oneofschema-3.1.1.dist-info/RECORD,,
marshmallow_oneofschema-3.1.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
marshmallow_oneofschema-3.1.1.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
marshmallow_oneofschema/__init__.py,sha256=KQjXt0W26CH8CvBBTA0YFEMsIHwR9_oMfBGppTnoTlI,47
marshmallow_oneofschema/__pycache__/__init__.cpython-310.pyc,,
marshmallow_oneofschema/__pycache__/one_of_schema.cpython-310.pyc,,
marshmallow_oneofschema/one_of_schema.py,sha256=cdaUaBSYXhwN7vusKCJFr9N0D_iyKIAmEsfzdBnISYM,6722
marshmallow_oneofschema/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Wheel-Version: 1.0
Generator: flit 3.9.0
Root-Is-Purelib: true
Tag: py3-none-any
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .one_of_schema import OneOfSchema # noqa
Binary file not shown.
Binary file not shown.
Loading

0 comments on commit ebb0f96

Please sign in to comment.