diff --git a/CHANGELOG.md b/CHANGELOG.md index c480176..e8b22a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,18 @@ For reference, the possible headings are: ## [Unreleased] +## [1.1.0] - 2022-09-05 +* **Changed** adjusted to zenroom calling convention of PRP #13 (breaking change) +* **Changed** zenroom test cases to comply to the new calling convention +* **Fixed** zenroom signing bug (call of wrong function) +* **Changed** using cryptoconditions 0.10.0 +* **Deprecated** usage of ripde160md as a address generation algorithm, isn't available from python 3.9.14 on, skipping these tests from now on. +* **Changed** script/ouptut tag to be of type array or object for schema v3.0 and v2.0 +* **Changed** added 'script' handling to the common/transactions.py class +* **Fixed** data input handling to the transaction fullfillment methods + + + ## [1.0.1] - 2022-07-07 updated documentation @@ -1184,6 +1196,6 @@ The first public release of Planetmint, including: - Initial documentation (in `planetmint/docs`). - Initial `README.md`, `ROADMAP.md`, `CODE_OF_CONDUCT.md`, and `CONTRIBUTING.md`. - Packaging for PyPI, including `setup.py` and `setup.cfg`. -- Initial `Dockerfile` and `docker-compose.yml` (for deployment using Docker and Docker Compose). +- Initial `Dockerfile` and `docker compose.yml` (for deployment using Docker and Docker Compose). - Initial `.gitignore` (list of things for git to ignore). - Initial `.travis.yml` (used by Travis CI). diff --git a/Dockerfile b/Dockerfile index e7daeea..3c2de9b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,6 +7,7 @@ RUN apt-get -qq update \ && apt-get -y upgrade \ && apt-get install -y jq vim zsh build-essential cmake\ && pip install . \ + && pip install pynacl==1.4.0 base58==2.1.1 pyasn1==0.4.8 zenroom==2.1.0.dev1655293214 cryptography==3.4.7\ && apt-get autoremove \ && apt-get clean diff --git a/Dockerfile-all-in-one b/Dockerfile-all-in-one index 5c807a7..44d6fb8 100644 --- a/Dockerfile-all-in-one +++ b/Dockerfile-all-in-one @@ -46,4 +46,7 @@ VOLUME /data/db /data/configdb /tendermint EXPOSE 27017 28017 9984 9985 26656 26657 26658 +RUN pip install pynacl==1.4.0 base58==2.1.1 pyasn1==0.4.8 zenroom==2.1.0.dev1655293214 cryptography==3.4.7 + + WORKDIR $HOME \ No newline at end of file diff --git a/Dockerfile-dev b/Dockerfile-dev index f2dc908..4148179 100644 --- a/Dockerfile-dev +++ b/Dockerfile-dev @@ -9,7 +9,6 @@ RUN apt-get update \ && pip install -U pip \ && apt-get autoremove \ && apt-get clean - ARG backend ARG abci_status @@ -34,4 +33,6 @@ RUN mkdir -p /usr/src/app COPY . /usr/src/app/ WORKDIR /usr/src/app RUN pip install -e .[dev] +RUN pip install flask-cors +RUN pip install pynacl==1.4.0 base58==2.1.1 pyasn1==0.4.8 zenroom==2.1.0.dev1655293214 cryptography==3.4.7 RUN planetmint -y configure diff --git a/acceptance/python/Dockerfile b/acceptance/python/Dockerfile index 966b30e..b095003 100644 --- a/acceptance/python/Dockerfile +++ b/acceptance/python/Dockerfile @@ -4,7 +4,7 @@ RUN apt-get update \ && pip install -U pip \ && apt-get autoremove \ && apt-get clean -RUN apt-get install -y vim zsh build-essential cmake +RUN apt-get install -y vim zsh build-essential cmake git RUN mkdir -p /src RUN /usr/local/bin/python -m pip install --upgrade pip @@ -13,6 +13,7 @@ RUN pip install --upgrade \ pycco \ websocket-client~=0.47.0 \ pytest~=3.0 \ - planetmint-cryptoconditions>=0.9.9\ + planetmint-cryptoconditions>=0.10.0\ planetmint-driver>=0.9.2 \ blns +RUN pip install base58>=2.1.1 pynacl==1.4.0 zenroom==2.1.0.dev1655293214 pyasn1==0.4.8 cryptography==3.4.7 diff --git a/acceptance/python/src/conftest.py b/acceptance/python/src/conftest.py index 3a4912e..747e527 100644 --- a/acceptance/python/src/conftest.py +++ b/acceptance/python/src/conftest.py @@ -5,17 +5,16 @@ import pytest -CONDITION_SCRIPT = """ - Scenario 'ecdh': create the signature of an object +CONDITION_SCRIPT = """Scenario 'ecdh': create the signature of an object Given I have the 'keyring' - Given that I have a 'string dictionary' named 'houses' inside 'asset' + Given that I have a 'string dictionary' named 'houses' When I create the signature of 'houses' Then print the 'signature'""" FULFILL_SCRIPT = """Scenario 'ecdh': Bob verifies the signature from Alice Given I have a 'ecdh public key' from 'Alice' - Given that I have a 'string dictionary' named 'houses' inside 'asset' - Given I have a 'signature' named 'signature' inside 'metadata' + Given that I have a 'string dictionary' named 'houses' + Given I have a 'signature' named 'signature' When I verify the 'houses' has a signature in 'signature' by 'Alice' Then print the string 'ok'""" @@ -33,25 +32,24 @@ GENERATE_KEYPAIR = """Scenario 'ecdh': Create the keypair When I create the bitcoin key Then print data""" -ZENROOM_DATA = {"also": "more data"} - -HOUSE_ASSETS = { - "data": { - "houses": [ - { - "name": "Harry", - "team": "Gryffindor", - }, - { - "name": "Draco", - "team": "Slytherin", - }, - ], - } +INITIAL_STATE = {"also": "more data"} +SCRIPT_INPUT = { + "houses": [ + { + "name": "Harry", + "team": "Gryffindor", + }, + { + "name": "Draco", + "team": "Slytherin", + }, + ], } metadata = {"units": 300, "type": "KG"} +ZENROOM_DATA = {"that": "is my data"} + @pytest.fixture def gen_key_zencode(): @@ -75,7 +73,12 @@ def condition_script_zencode(): @pytest.fixture def zenroom_house_assets(): - return HOUSE_ASSETS + return SCRIPT_INPUT + + +@pytest.fixture +def zenroom_script_input(): + return SCRIPT_INPUT @pytest.fixture diff --git a/acceptance/python/src/test_zenroom.py b/acceptance/python/src/test_zenroom.py index 914a2a7..b6b4170 100644 --- a/acceptance/python/src/test_zenroom.py +++ b/acceptance/python/src/test_zenroom.py @@ -15,6 +15,7 @@ def test_zenroom_signing( fulfill_script_zencode, zenroom_data, zenroom_house_assets, + zenroom_script_input, condition_script_zencode, ): @@ -64,9 +65,18 @@ def test_zenroom_signing( } metadata = {"result": {"output": ["ok"]}} + script_ = { + "code": {"type": "zenroom", "raw": "test_string", "parameters": [{"obj": "1"}, {"obj": "2"}]}, + "state": "dd8bbd234f9869cab4cc0b84aa660e9b5ef0664559b8375804ee8dce75b10576", + "input": zenroom_script_input, + "output": ["ok"], + "policies": {}, + } + token_creation_tx = { "operation": "CREATE", - "asset": zenroom_house_assets, + "asset": {"data": {"test": "my asset"}}, + "script": script_, "metadata": metadata, "outputs": [ output, @@ -79,35 +89,44 @@ def test_zenroom_signing( } # JSON: serialize the transaction-without-id to a json formatted string - message = json.dumps( + tx = json.dumps( token_creation_tx, sort_keys=True, separators=(",", ":"), ensure_ascii=False, ) - + script_ = json.dumps(script_) # major workflow: # we store the fulfill script in the transaction/message (zenroom-sha) # the condition script is used to fulfill the transaction and create the signature # # the server should ick the fulfill script and recreate the zenroom-sha and verify the signature - message = zenroomscpt.sign(message, condition_script_zencode, alice) - assert zenroomscpt.validate(message=message) + signed_input = zenroomscpt.sign(script_, condition_script_zencode, alice) - message = json.loads(message) + input_signed = json.loads(signed_input) + input_signed["input"]["signature"] = input_signed["output"]["signature"] + del input_signed["output"]["signature"] + del input_signed["output"]["logs"] + input_signed["output"] = ["ok"] # define expected output that is to be compared + input_msg = json.dumps(input_signed) + + assert zenroomscpt.validate(message=input_msg) + + tx = json.loads(tx) fulfillment_uri_zen = zenroomscpt.serialize_uri() - message["inputs"][0]["fulfillment"] = fulfillment_uri_zen - tx = message + tx["inputs"][0]["fulfillment"] = fulfillment_uri_zen + tx["script"] = input_signed tx["id"] = None json_str_tx = json.dumps(tx, sort_keys=True, skipkeys=False, separators=(",", ":")) # SHA3: hash the serialized id-less transaction to generate the id shared_creation_txid = sha3_256(json_str_tx.encode()).hexdigest() - message["id"] = shared_creation_txid - + tx["id"] = shared_creation_txid + # tx = json.dumps(tx) # `https://example.com:9984` + print(f"TX \n{tx}") plntmnt = Planetmint(os.environ.get("PLANETMINT_ENDPOINT")) - sent_transfer_tx = plntmnt.transactions.send_commit(message) + sent_transfer_tx = plntmnt.transactions.send_commit(tx) print(f"\n\nstatus and result : + {sent_transfer_tx}") diff --git a/docs/root/requirements.txt b/docs/root/requirements.txt index d80d8f1..c048f4f 100644 --- a/docs/root/requirements.txt +++ b/docs/root/requirements.txt @@ -39,3 +39,8 @@ zipp==3.8.0 nest-asyncio==1.5.5 sphinx-press-theme==0.8.0 sphinx-documatt-theme +base58>=2.1.1 +pynacl==1.4.0 +zenroom==2.1.0.dev1655293214 +pyasn1==0.4.8 +cryptography==3.4.7 diff --git a/integration/python/Dockerfile b/integration/python/Dockerfile index ca824d5..c710550 100644 --- a/integration/python/Dockerfile +++ b/integration/python/Dockerfile @@ -6,7 +6,7 @@ RUN apt-get update \ && apt-get clean RUN apt-get install -y vim RUN apt-get update -RUN apt-get install -y build-essential cmake openssh-client openssh-server +RUN apt-get install -y build-essential cmake openssh-client openssh-server git RUN apt-get install -y zsh RUN mkdir -p /src @@ -15,6 +15,7 @@ RUN pip install --upgrade \ pytest~=6.2.5 \ pycco \ websocket-client~=0.47.0 \ - planetmint-cryptoconditions>=0.9.9 \ + planetmint-cryptoconditions>=0.10.0 \ planetmint-driver>=9.2.0 \ blns +RUN pip install base58 pynacl==1.4.0 zenroom==2.1.0.dev1655293214 pyasn1==0.4.8 cryptography==3.4.7 diff --git a/integration/python/src/conftest.py b/integration/python/src/conftest.py index 3a4912e..747e527 100644 --- a/integration/python/src/conftest.py +++ b/integration/python/src/conftest.py @@ -5,17 +5,16 @@ import pytest -CONDITION_SCRIPT = """ - Scenario 'ecdh': create the signature of an object +CONDITION_SCRIPT = """Scenario 'ecdh': create the signature of an object Given I have the 'keyring' - Given that I have a 'string dictionary' named 'houses' inside 'asset' + Given that I have a 'string dictionary' named 'houses' When I create the signature of 'houses' Then print the 'signature'""" FULFILL_SCRIPT = """Scenario 'ecdh': Bob verifies the signature from Alice Given I have a 'ecdh public key' from 'Alice' - Given that I have a 'string dictionary' named 'houses' inside 'asset' - Given I have a 'signature' named 'signature' inside 'metadata' + Given that I have a 'string dictionary' named 'houses' + Given I have a 'signature' named 'signature' When I verify the 'houses' has a signature in 'signature' by 'Alice' Then print the string 'ok'""" @@ -33,25 +32,24 @@ GENERATE_KEYPAIR = """Scenario 'ecdh': Create the keypair When I create the bitcoin key Then print data""" -ZENROOM_DATA = {"also": "more data"} - -HOUSE_ASSETS = { - "data": { - "houses": [ - { - "name": "Harry", - "team": "Gryffindor", - }, - { - "name": "Draco", - "team": "Slytherin", - }, - ], - } +INITIAL_STATE = {"also": "more data"} +SCRIPT_INPUT = { + "houses": [ + { + "name": "Harry", + "team": "Gryffindor", + }, + { + "name": "Draco", + "team": "Slytherin", + }, + ], } metadata = {"units": 300, "type": "KG"} +ZENROOM_DATA = {"that": "is my data"} + @pytest.fixture def gen_key_zencode(): @@ -75,7 +73,12 @@ def condition_script_zencode(): @pytest.fixture def zenroom_house_assets(): - return HOUSE_ASSETS + return SCRIPT_INPUT + + +@pytest.fixture +def zenroom_script_input(): + return SCRIPT_INPUT @pytest.fixture diff --git a/integration/python/src/test_zenroom.py b/integration/python/src/test_zenroom.py index 7d8f860..f38db29 100644 --- a/integration/python/src/test_zenroom.py +++ b/integration/python/src/test_zenroom.py @@ -3,6 +3,7 @@ import base58 from hashlib import sha3_256 from cryptoconditions.types.zenroom import ZenroomSha256 from planetmint_driver.crypto import generate_keypair + from .helper.hosts import Hosts from zenroom import zencode_exec import time @@ -14,6 +15,7 @@ def test_zenroom_signing( fulfill_script_zencode, zenroom_data, zenroom_house_assets, + zenroom_script_input, condition_script_zencode, ): @@ -24,17 +26,11 @@ def test_zenroom_signing( bob = json.loads(zencode_exec(gen_key_zencode).output)["keyring"] zen_public_keys = json.loads( - zencode_exec( - secret_key_to_private_key_zencode.format("Alice"), - keys=json.dumps({"keyring": alice}), - ).output + zencode_exec(secret_key_to_private_key_zencode.format("Alice"), keys=json.dumps({"keyring": alice})).output ) zen_public_keys.update( json.loads( - zencode_exec( - secret_key_to_private_key_zencode.format("Bob"), - keys=json.dumps({"keyring": bob}), - ).output + zencode_exec(secret_key_to_private_key_zencode.format("Bob"), keys=json.dumps({"keyring": bob})).output ) ) @@ -68,9 +64,19 @@ def test_zenroom_signing( ], } metadata = {"result": {"output": ["ok"]}} + + script_ = { + "code": {"type": "zenroom", "raw": "test_string", "parameters": [{"obj": "1"}, {"obj": "2"}]}, + "state": "dd8bbd234f9869cab4cc0b84aa660e9b5ef0664559b8375804ee8dce75b10576", + "input": zenroom_script_input, + "output": ["ok"], + "policies": {}, + } + token_creation_tx = { "operation": "CREATE", - "asset": zenroom_house_assets, + "asset": {"data": {"test": "my asset"}}, + "script": script_, "metadata": metadata, "outputs": [ output, @@ -83,39 +89,44 @@ def test_zenroom_signing( } # JSON: serialize the transaction-without-id to a json formatted string - message = json.dumps( + tx = json.dumps( token_creation_tx, sort_keys=True, separators=(",", ":"), ensure_ascii=False, ) - + script_ = json.dumps(script_) # major workflow: # we store the fulfill script in the transaction/message (zenroom-sha) # the condition script is used to fulfill the transaction and create the signature # # the server should ick the fulfill script and recreate the zenroom-sha and verify the signature - message = zenroomscpt.sign(message, condition_script_zencode, alice) - assert zenroomscpt.validate(message=message) + signed_input = zenroomscpt.sign(script_, condition_script_zencode, alice) - message = json.loads(message) + input_signed = json.loads(signed_input) + input_signed["input"]["signature"] = input_signed["output"]["signature"] + del input_signed["output"]["signature"] + del input_signed["output"]["logs"] + input_signed["output"] = ["ok"] # define expected output that is to be compared + input_msg = json.dumps(input_signed) + + assert zenroomscpt.validate(message=input_msg) + + tx = json.loads(tx) fulfillment_uri_zen = zenroomscpt.serialize_uri() - message["inputs"][0]["fulfillment"] = fulfillment_uri_zen - tx = message + tx["inputs"][0]["fulfillment"] = fulfillment_uri_zen + tx["script"] = input_signed tx["id"] = None json_str_tx = json.dumps(tx, sort_keys=True, skipkeys=False, separators=(",", ":")) # SHA3: hash the serialized id-less transaction to generate the id shared_creation_txid = sha3_256(json_str_tx.encode()).hexdigest() - message["id"] = shared_creation_txid - + tx["id"] = shared_creation_txid hosts = Hosts("/shared/hostnames") pm_alpha = hosts.get_connection() - - sent_transfer_tx = pm_alpha.transactions.send_commit(message) + sent_transfer_tx = pm_alpha.transactions.send_commit(tx) time.sleep(1) - # Assert that transaction is stored on both planetmint nodes hosts.assert_transaction(shared_creation_txid) print(f"\n\nstatus and result : + {sent_transfer_tx}") diff --git a/planetmint/backend/tarantool/drop.lua b/planetmint/backend/tarantool/drop.lua index 2825f4e..da35bc6 100644 --- a/planetmint/backend/tarantool/drop.lua +++ b/planetmint/backend/tarantool/drop.lua @@ -11,3 +11,4 @@ box.space.transactions:drop() box.space.inputs:drop() box.space.outputs:drop() box.space.keys:drop() +box.space.scripts:drop() diff --git a/planetmint/backend/tarantool/init.lua b/planetmint/backend/tarantool/init.lua index 92752e7..46344d9 100644 --- a/planetmint/backend/tarantool/init.lua +++ b/planetmint/backend/tarantool/init.lua @@ -67,4 +67,8 @@ utxos = box.schema.space.create('utxos', {engine = 'memtx' , is_sync = false}) utxos:format({{name='transaction_id' , type='string'}, {name='output_index' , type='integer'}, {name='utxo_dict', type='string'}}) utxos:create_index('id_search', {type='hash' , parts={'transaction_id', 'output_index'}}) utxos:create_index('transaction_search', {type='tree', unique=false, parts={'transaction_id'}}) -utxos:create_index('index_search', {type='tree', unique=false, parts={'output_index'}}) \ No newline at end of file +utxos:create_index('index_search', {type='tree', unique=false, parts={'output_index'}}) + +scripts = box.schema.space.create('scripts' , {engine='memtx' , is_sync=false}) +scripts:format({{name='transaction_id', type='string'},{name='script' , type='any'}}) +scripts:create_index('txid_search', {type='hash', parts={'transaction_id'}}) diff --git a/planetmint/backend/tarantool/query.py b/planetmint/backend/tarantool/query.py index ad76650..d2243f4 100644 --- a/planetmint/backend/tarantool/query.py +++ b/planetmint/backend/tarantool/query.py @@ -34,6 +34,7 @@ def _group_transaction_by_ids(connection, txids: list): _txkeys = connection.run(connection.space("keys").select(txid, index="txid_search")) _txassets = connection.run(connection.space("assets").select(txid, index="txid_search")) _txmeta = connection.run(connection.space("meta_data").select(txid, index="id_search")) + _txscript = connection.run(connection.space("scripts").select(txid, index="txid_search")) _txinputs = sorted(_txinputs, key=itemgetter(6), reverse=False) _txoutputs = sorted(_txoutputs, key=itemgetter(8), reverse=False) @@ -44,6 +45,7 @@ def _group_transaction_by_ids(connection, txids: list): "keys": _txkeys, "asset": _txassets, "metadata": _txmeta, + "script": _txscript, } tx_compose = TransactionCompose(db_results=result_map) _transaction = tx_compose.convert_to_dict() @@ -74,6 +76,9 @@ def store_transactions(connection, signed_transactions: list): if txtuples["asset"] is not None: connection.run(connection.space("assets").insert(txtuples["asset"]), only_data=False) + if txtuples["script"] is not None: + connection.run(connection.space("scripts").insert(txtuples["script"]), only_data=False) + @register_query(TarantoolDBConnection) def get_transaction(connection, transaction_id: str): diff --git a/planetmint/backend/tarantool/schema.py b/planetmint/backend/tarantool/schema.py index 0e61bc1..f4dd7f3 100644 --- a/planetmint/backend/tarantool/schema.py +++ b/planetmint/backend/tarantool/schema.py @@ -23,8 +23,10 @@ SPACE_NAMES = ( "outputs", "keys", "utxos", + "scripts", ) + SPACE_COMMANDS = { "abci_chains": "abci_chains = box.schema.space.create('abci_chains', {engine='memtx', is_sync = false})", "assets": "assets = box.schema.space.create('assets' , {engine='memtx' , is_sync=false})", @@ -39,6 +41,7 @@ SPACE_COMMANDS = { "outputs": "outputs = box.schema.space.create('outputs')", "keys": "keys = box.schema.space.create('keys')", "utxos": "utxos = box.schema.space.create('utxos', {engine = 'memtx' , is_sync = false})", + "scripts": "scripts = box.schema.space.create('scripts', {engine = 'memtx' , is_sync = false})", } INDEX_COMMANDS = { @@ -102,8 +105,12 @@ INDEX_COMMANDS = { "transaction_search": "utxos:create_index('transaction_search', {type='tree', unique=false, parts={'transaction_id'}})", # noqa: E501 "index_Search": "utxos:create_index('index_search', {type='tree', unique=false, parts={'output_index'}})", }, + "scripts": { + "txid_search": "scripts:create_index('txid_search', {type='tree', parts={'transaction_id'}})", + }, } + SCHEMA_COMMANDS = { "abci_chains": "abci_chains:format({{name='height' , type='integer'},{name='is_synched' , type='boolean'},{name='chain_id',type='string'}, {name='id', type='string'}})", # noqa: E501 "assets": "assets:format({{name='data' , type='string'}, {name='tx_id', type='string'}, {name='asset_id', type='string'}})", # noqa: E501 @@ -118,6 +125,7 @@ SCHEMA_COMMANDS = { "outputs": "outputs:format({{name='transaction_id' , type='string'}, {name='amount' , type='string'}, {name='uri', type='string'}, {name='details_type', type='string'}, {name='details_public_key', type='any'}, {name = 'output_id', type = 'string'}, {name='treshold', type='any'}, {name='subconditions', type='any'}, {name='output_index', type='number'}})", # noqa: E501 "keys": "keys:format({{name = 'id', type='string'}, {name = 'transaction_id', type = 'string'} ,{name = 'output_id', type = 'string'}, {name = 'public_key', type = 'string'}, {name = 'key_index', type = 'integer'}})", # noqa: E501 "utxos": "utxos:format({{name='transaction_id' , type='string'}, {name='output_index' , type='integer'}, {name='utxo_dict', type='string'}})", # noqa: E501 + "scripts": "scripts:format({{name='transaction_id', type='string'},{name='script' , type='any'}})", # noqa: E501 } SCHEMA_DROP_COMMANDS = { @@ -134,6 +142,7 @@ SCHEMA_DROP_COMMANDS = { "outputs": "box.space.outputs:drop()", "keys": "box.space.keys:drop()", "utxos": "box.space.utxos:drop()", + "scripts": "box.space.scripts:drop()", } diff --git a/planetmint/backend/tarantool/transaction/tools.py b/planetmint/backend/tarantool/transaction/tools.py index 4ba2533..045e18c 100644 --- a/planetmint/backend/tarantool/transaction/tools.py +++ b/planetmint/backend/tarantool/transaction/tools.py @@ -40,6 +40,7 @@ class TransactionDecompose: "inputs": [], "outputs": [], "keys": [], + "script": None, "metadata": None, "asset": None, } @@ -132,6 +133,12 @@ class TransactionDecompose: _map = self.get_map() return (self._transaction["id"], self._transaction["operation"], self._transaction["version"], _map) + def __prepare_script(self): + try: + return (self._transaction["id"], self._transaction["script"]) + except KeyError: + return None + def convert_to_tuple(self): self._metadata_check() self.__asset_check() @@ -140,6 +147,7 @@ class TransactionDecompose: keys, outputs = self.__prepare_outputs() self._tuple_transaction["outputs"] = outputs self._tuple_transaction["keys"] = keys + self._tuple_transaction["script"] = self.__prepare_script() return self._tuple_transaction @@ -197,6 +205,12 @@ class TransactionCompose: _outputs.append(_out) return _outputs + def _get_script(self): + if self.db_results["script"]: + return self.db_results["script"][0][1] + else: + return None + def convert_to_dict(self): transaction = {k: None for k in list(self._map.keys())} transaction["id"] = self._get_transaction_id() @@ -206,4 +220,6 @@ class TransactionCompose: transaction["operation"] = self._get_transaction_operation() transaction["inputs"] = self._get_inputs() transaction["outputs"] = self._get_outputs() + if self._get_script(): + transaction["script"] = self._get_script() return transaction diff --git a/planetmint/start.py b/planetmint/start.py index c911c66..906ca45 100644 --- a/planetmint/start.py +++ b/planetmint/start.py @@ -13,14 +13,14 @@ from planetmint.parallel_validation import ParallelValidationApp from planetmint.web import server, websocket_server from planetmint.events import Exchange, EventTypes from planetmint.utils import Process - +from planetmint.version import __version__ logger = logging.getLogger(__name__) BANNER = """ **************************************************************************** * * -* Planetmint 2.2.2 * +* Planetmint {} * * codename "jumping sloth" * * Initialization complete. Planetmint Server is ready and waiting. * * * @@ -45,7 +45,7 @@ def start(args): p_webapi = Process(name="planetmint_webapi", target=app_server.run, daemon=True) p_webapi.start() - logger.info(BANNER.format(Config().get()["server"]["bind"])) + logger.info(BANNER.format(__version__, Config().get()["server"]["bind"])) # start websocket server p_websocket_server = Process( diff --git a/planetmint/tendermint_utils.py b/planetmint/tendermint_utils.py index a71103e..508a1be 100644 --- a/planetmint/tendermint_utils.py +++ b/planetmint/tendermint_utils.py @@ -69,6 +69,8 @@ def merkleroot(hashes): return merkleroot(parent_hashes) +# ripemd160 is only available below python 3.9.13 +@DeprecationWarning def public_key64_to_address(base64_public_key): """Note this only compatible with Tendermint 0.19.x""" ed25519_public_key = public_key_from_base64(base64_public_key) diff --git a/planetmint/transactions/common/schema/v2.0/transaction.yaml b/planetmint/transactions/common/schema/v2.0/transaction.yaml index 58c6d75..0905b49 100644 --- a/planetmint/transactions/common/schema/v2.0/transaction.yaml +++ b/planetmint/transactions/common/schema/v2.0/transaction.yaml @@ -212,7 +212,9 @@ definitions: input: type: object output: - type: object + anyOf: + - type: object + - type: array policies: type: object properties: diff --git a/planetmint/transactions/common/schema/v3.0/transaction.yaml b/planetmint/transactions/common/schema/v3.0/transaction.yaml index ed6f58f..40a035f 100644 --- a/planetmint/transactions/common/schema/v3.0/transaction.yaml +++ b/planetmint/transactions/common/schema/v3.0/transaction.yaml @@ -216,7 +216,9 @@ definitions: input: type: object output: - type: object + anyOf: + - type: object + - type: array policies: type: object properties: diff --git a/planetmint/transactions/common/transaction.py b/planetmint/transactions/common/transaction.py index 74146e8..9ffc93b 100644 --- a/planetmint/transactions/common/transaction.py +++ b/planetmint/transactions/common/transaction.py @@ -93,6 +93,7 @@ class Transaction(object): version=None, hash_id=None, tx_dict=None, + script=None, ): """The constructor allows to create a customizable Transaction. @@ -139,12 +140,16 @@ class Transaction(object): if metadata is not None and not isinstance(metadata, dict): raise TypeError("`metadata` must be a dict or None") + if script is not None and not isinstance(script, dict): + raise TypeError("`script` must be a dict or None") + self.version = version if version is not None else self.VERSION self.operation = operation self.asset = asset self.inputs = inputs or [] self.outputs = outputs or [] self.metadata = metadata + self.script = script self._id = hash_id self.tx_dict = tx_dict @@ -320,7 +325,7 @@ class Transaction(object): elif isinstance(input_.fulfillment, ThresholdSha256): return cls._sign_threshold_signature_fulfillment(input_, message, key_pairs) elif isinstance(input_.fulfillment, ZenroomSha256): - return cls._sign_threshold_signature_fulfillment(input_, message, key_pairs) + return cls._sign_zenroom_fulfillment(input_, message, key_pairs) else: raise ValueError("Fulfillment couldn't be matched to " "Cryptocondition fulfillment type.") @@ -533,7 +538,10 @@ class Transaction(object): ffill_valid = False if isinstance(parsed_ffill, ZenroomSha256): - ffill_valid = parsed_ffill.validate(message=message) + import json + + msg = json.loads(message) + ffill_valid = parsed_ffill.validate(message=json.dumps(msg["script"])) else: message = sha3_256(message.encode()) if input_.fulfills: @@ -558,7 +566,7 @@ class Transaction(object): Returns: dict: The Transaction as an alternative serialization format. """ - return { + tx_dict = { "inputs": [input_.to_dict() for input_ in self.inputs], "outputs": [output.to_dict() for output in self.outputs], "operation": str(self.operation), @@ -567,6 +575,9 @@ class Transaction(object): "version": self.version, "id": self._id, } + if self.script: + tx_dict["script"] = self.script + return tx_dict @staticmethod # TODO: Remove `_dict` prefix of variable. @@ -699,6 +710,14 @@ class Transaction(object): "version": tx["version"], "id": id, } + try: + script_ = tx["script"] + script_dict = {"script": script_} + except KeyError: + script_ = None + pass + else: + local_dict = {**local_dict, **script_dict} if not skip_schema_validation: cls.validate_id(local_dict) @@ -715,6 +734,7 @@ class Transaction(object): tx["version"], hash_id=tx["id"], tx_dict=tx, + script=script_, ) @classmethod diff --git a/planetmint/transactions/common/utils.py b/planetmint/transactions/common/utils.py index e1b4a4f..d18cfc0 100644 --- a/planetmint/transactions/common/utils.py +++ b/planetmint/transactions/common/utils.py @@ -195,6 +195,7 @@ def _fulfillment_to_details(fulfillment): "type": "zenroom-sha-256", "public_key": base58.b58encode(fulfillment.public_key).decode(), "script": base58.b58encode(fulfillment.script).decode(), + "data": base58.b58encode(fulfillment.data).decode(), } raise UnsupportedTypeError(fulfillment.type_name) @@ -221,10 +222,10 @@ def _fulfillment_from_details(data, _depth=0): return threshold if data["type"] == "zenroom-sha-256": - public_key = base58.b58decode(data["public_key"]) - script = base58.b58decode(data["script"]) - # zenroom = ZenroomSha256(script=script, data=None, keys={public_key}) + public_key_ = base58.b58decode(data["public_key"]) + script_ = base58.b58decode(data["script"]) + data_ = base58.b58decode(data["data"]) # TODO: assign to zenroom and evaluate the outcome - ZenroomSha256(script=script, data=None, keys={public_key}) + ZenroomSha256(script=script_, data=data_, keys={public_key_}) raise UnsupportedTypeError(data.get("type")) diff --git a/planetmint/version.py b/planetmint/version.py index 6b83d6e..59ed0c2 100644 --- a/planetmint/version.py +++ b/planetmint/version.py @@ -3,8 +3,8 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -__version__ = "1.0.1" -__short_version__ = "1.0" +__version__ = "1.1.1" +__short_version__ = "1.1" # Supported Tendermint versions __tm_supported_versions__ = ["0.34.15"] diff --git a/setup.py b/setup.py index a42a6d5..5669c5a 100644 --- a/setup.py +++ b/setup.py @@ -108,9 +108,10 @@ tests_require = [ install_requires = [ "chardet==3.0.4", + "base58==2.1.1", "aiohttp==3.8.1", "abci==0.8.3", - "planetmint-cryptoconditions>=0.9.9", + "planetmint-cryptoconditions>=0.10.0", "flask-cors==3.0.10", "flask-restful==0.3.9", "flask==2.1.2", diff --git a/tests/README.md b/tests/README.md index fc8bb05..a0bb552 100644 --- a/tests/README.md +++ b/tests/README.md @@ -10,7 +10,7 @@ Code is Apache-2.0 and docs are CC-BY-4.0 Most of the tests in the `tests/` folder are unit tests. For info about how to write and run tests, see [the docs about contributing to Planetmint](http://docs.planetmint.io/en/latest/index.html), especially: - [Write Code - Remember to Write Tests](https://docs.planetmint.io/en/latest/contributing/dev-setup-coding-and-contribution-process/write-code.html?highlight=write%20code#remember-to-write-tests) -- [Notes on Running a Local Dev Node with Docker Compose](https://docs.planetmint.io/en/latest/contributing/dev-setup-coding-and-contribution-process/run-node-with-docker-compose.html), especially `make test` +- [Notes on Running a Local Dev Node with Docker Compose](https://docs.planetmint.io/en/latest/contributing/dev-setup-coding-and-contribution-process/run-node-with-docker compose.html), especially `make test` - [ Notes on Running a Local Dev Node as Processes (and Running All Tests)](https://docs.planetmint.io/en/latest/contributing/dev-setup-coding-and-contribution-process/run-node-as-processes.html) diff --git a/tests/assets/test_zenroom_signing.py b/tests/assets/test_zenroom_signing.py index 0b1a9f3..968e3f3 100644 --- a/tests/assets/test_zenroom_signing.py +++ b/tests/assets/test_zenroom_signing.py @@ -7,17 +7,16 @@ from cryptoconditions.types.ed25519 import Ed25519Sha256 from cryptoconditions.types.zenroom import ZenroomSha256 from planetmint.transactions.common.crypto import generate_key_pair -CONDITION_SCRIPT = """ - Scenario 'ecdh': create the signature of an object +CONDITION_SCRIPT = """Scenario 'ecdh': create the signature of an object Given I have the 'keyring' - Given that I have a 'string dictionary' named 'houses' inside 'asset' + Given that I have a 'string dictionary' named 'houses' When I create the signature of 'houses' Then print the 'signature'""" FULFILL_SCRIPT = """Scenario 'ecdh': Bob verifies the signature from Alice Given I have a 'ecdh public key' from 'Alice' - Given that I have a 'string dictionary' named 'houses' inside 'asset' - Given I have a 'signature' named 'signature' inside 'metadata' + Given that I have a 'string dictionary' named 'houses' + Given I have a 'signature' named 'signature' When I verify the 'houses' has a signature in 'signature' by 'Alice' Then print the string 'ok'""" @@ -35,21 +34,18 @@ GENERATE_KEYPAIR = """Scenario 'ecdh': Create the keypair When I create the bitcoin key Then print data""" -ZENROOM_DATA = {"also": "more data"} - -HOUSE_ASSETS = { - "data": { - "houses": [ - { - "name": "Harry", - "team": "Gryffindor", - }, - { - "name": "Draco", - "team": "Slytherin", - }, - ], - } +INITIAL_STATE = {"also": "more data"} +SCRIPT_INPUT = { + "houses": [ + { + "name": "Harry", + "team": "Gryffindor", + }, + { + "name": "Draco", + "team": "Slytherin", + }, + ], } metadata = {"units": 300, "type": "KG"} @@ -66,7 +62,7 @@ def test_zenroom_signing(): zen_public_keys = json.loads(zencode_exec(SK_TO_PK.format("Alice"), keys=json.dumps({"keyring": alice})).output) zen_public_keys.update(json.loads(zencode_exec(SK_TO_PK.format("Bob"), keys=json.dumps({"keyring": bob})).output)) - zenroomscpt = ZenroomSha256(script=FULFILL_SCRIPT, data=ZENROOM_DATA, keys=zen_public_keys) + zenroomscpt = ZenroomSha256(script=FULFILL_SCRIPT, data=INITIAL_STATE, keys=zen_public_keys) print(f"zenroom is: {zenroomscpt.script}") # CRYPTO-CONDITIONS: generate the condition uri @@ -95,11 +91,19 @@ def test_zenroom_signing(): biolabs.public_key, ], } + script_ = { + "code": {"type": "zenroom", "raw": "test_string", "parameters": [{"obj": "1"}, {"obj": "2"}]}, + "state": "dd8bbd234f9869cab4cc0b84aa660e9b5ef0664559b8375804ee8dce75b10576", + "input": SCRIPT_INPUT, + "output": ["ok"], + "policies": {}, + } metadata = {"result": {"output": ["ok"]}} token_creation_tx = { "operation": "CREATE", - "asset": HOUSE_ASSETS, + "asset": {"data": {"test": "my asset"}}, "metadata": metadata, + "script": script_, "outputs": [ output, ], @@ -111,46 +115,65 @@ def test_zenroom_signing(): } # JSON: serialize the transaction-without-id to a json formatted string - message = json.dumps( + tx = json.dumps( token_creation_tx, sort_keys=True, separators=(",", ":"), ensure_ascii=False, ) - + script_ = json.dumps(script_) # major workflow: # we store the fulfill script in the transaction/message (zenroom-sha) # the condition script is used to fulfill the transaction and create the signature # # the server should ick the fulfill script and recreate the zenroom-sha and verify the signature - message = zenroomscpt.sign(message, CONDITION_SCRIPT, alice) - assert zenroomscpt.validate(message=message) + signed_input = zenroomscpt.sign(script_, CONDITION_SCRIPT, alice) - message = json.loads(message) + input_signed = json.loads(signed_input) + input_signed["input"]["signature"] = input_signed["output"]["signature"] + del input_signed["output"]["signature"] + del input_signed["output"]["logs"] + input_signed["output"] = ["ok"] # define expected output that is to be compared + input_msg = json.dumps(input_signed) + assert zenroomscpt.validate(message=input_msg) + + tx = json.loads(tx) fulfillment_uri_zen = zenroomscpt.serialize_uri() - message["inputs"][0]["fulfillment"] = fulfillment_uri_zen - tx = message + tx["script"] = input_signed + tx["inputs"][0]["fulfillment"] = fulfillment_uri_zen tx["id"] = None json_str_tx = json.dumps(tx, sort_keys=True, skipkeys=False, separators=(",", ":")) # SHA3: hash the serialized id-less transaction to generate the id shared_creation_txid = sha3_256(json_str_tx.encode()).hexdigest() - message["id"] = shared_creation_txid + tx["id"] = shared_creation_txid from planetmint.models import Transaction + from planetmint.lib import Planetmint from planetmint.transactions.common.exceptions import ( SchemaValidationError, ValidationError, ) try: - tx_obj = Transaction.from_dict(message) - except SchemaValidationError: + print(f"TX\n{tx}") + tx_obj = Transaction.from_dict(tx) + except SchemaValidationError as e: + print(e) assert () except ValidationError as e: print(e) assert () + planet = Planetmint() + try: + planet.validate_transaction(tx_obj) + except ValidationError as e: + print("Invalid transaction ({}): {}".format(type(e).__name__, e)) + assert () + except e: + print(f"Exception : {e}") + assert () print(f"VALIDATED : {tx_obj}") assert (tx_obj == False) is False diff --git a/tests/common/conftest.py b/tests/common/conftest.py index 22976cf..c88fba4 100644 --- a/tests/common/conftest.py +++ b/tests/common/conftest.py @@ -5,6 +5,7 @@ from base58 import b58decode import pytest +from cryptoconditions import ThresholdSha256, Ed25519Sha256 USER_PRIVATE_KEY = "8eJ8q9ZQpReWyQT5aFCiwtZ5wDZC4eDnCen88p3tQ6ie" @@ -69,15 +70,11 @@ def cond_uri(): @pytest.fixture def user_Ed25519(user_pub): - from cryptoconditions import Ed25519Sha256 - return Ed25519Sha256(public_key=b58decode(user_pub)) @pytest.fixture def user_user2_threshold(user_pub, user2_pub): - from cryptoconditions import ThresholdSha256, Ed25519Sha256 - user_pub_keys = [user_pub, user2_pub] threshold = ThresholdSha256(threshold=len(user_pub_keys)) for user_pub in user_pub_keys: @@ -87,8 +84,6 @@ def user_user2_threshold(user_pub, user2_pub): @pytest.fixture def user2_Ed25519(user2_pub): - from cryptoconditions import Ed25519Sha256 - return Ed25519Sha256(public_key=b58decode(user2_pub)) diff --git a/tests/common/test_transaction.py b/tests/common/test_transaction.py index f1c5fad..b6b923c 100644 --- a/tests/common/test_transaction.py +++ b/tests/common/test_transaction.py @@ -10,9 +10,17 @@ import json from copy import deepcopy from base58 import b58encode, b58decode -from cryptoconditions import Ed25519Sha256 from planetmint.transactions.types.assets.create import Create from planetmint.transactions.types.assets.transfer import Transfer +from planetmint.transactions.common.transaction import Output +from planetmint.transactions.common.transaction import Input +from planetmint.transactions.common.exceptions import AmountError +from planetmint.transactions.common.transaction import Transaction +from planetmint.transactions.common.transaction import TransactionLink +from cryptoconditions import ThresholdSha256 +from cryptoconditions import Fulfillment +from cryptoconditions import PreimageSha256 +from cryptoconditions import Ed25519Sha256 from pytest import mark, raises try: @@ -24,9 +32,6 @@ pytestmark = mark.bdb def test_input_serialization(ffill_uri, user_pub): - from planetmint.transactions.common.transaction import Input - from cryptoconditions import Fulfillment - expected = { "owners_before": [user_pub], "fulfillment": ffill_uri, @@ -37,9 +42,6 @@ def test_input_serialization(ffill_uri, user_pub): def test_input_deserialization_with_uri(ffill_uri, user_pub): - from planetmint.transactions.common.transaction import Input - from cryptoconditions import Fulfillment - expected = Input(Fulfillment.from_uri(ffill_uri), [user_pub]) ffill = { "owners_before": [user_pub], @@ -78,9 +80,6 @@ def test_input_deserialization_with_invalid_fulfillment_uri(user_pub): def test_input_deserialization_with_unsigned_fulfillment(ffill_uri, user_pub): - from planetmint.transactions.common.transaction import Input - from cryptoconditions import Fulfillment - expected = Input(Fulfillment.from_uri(ffill_uri), [user_pub]) ffill = { "owners_before": [user_pub], @@ -133,9 +132,6 @@ def test_output_deserialization(user_Ed25519, user_pub): def test_output_hashlock_serialization(): - from planetmint.transactions.common.transaction import Output - from cryptoconditions import PreimageSha256 - secret = b"wow much secret" hashlock = PreimageSha256(preimage=secret).condition_uri @@ -152,9 +148,6 @@ def test_output_hashlock_serialization(): def test_output_hashlock_deserialization(): - from planetmint.transactions.common.transaction import Output - from cryptoconditions import PreimageSha256 - secret = b"wow much secret" hashlock = PreimageSha256(preimage=secret).condition_uri expected = Output(hashlock, amount=1) @@ -170,9 +163,6 @@ def test_output_hashlock_deserialization(): def test_invalid_output_initialization(cond_uri, user_pub): - from planetmint.transactions.common.transaction import Output - from planetmint.transactions.common.exceptions import AmountError - with raises(TypeError): Output(cond_uri, user_pub) with raises(TypeError): @@ -182,9 +172,6 @@ def test_invalid_output_initialization(cond_uri, user_pub): def test_generate_output_split_half_recursive(user_pub, user2_pub, user3_pub): - from planetmint.transactions.common.transaction import Output - from cryptoconditions import Ed25519Sha256, ThresholdSha256 - expected_simple1 = Ed25519Sha256(public_key=b58decode(user_pub)) expected_simple2 = Ed25519Sha256(public_key=b58decode(user2_pub)) expected_simple3 = Ed25519Sha256(public_key=b58decode(user3_pub)) @@ -201,9 +188,6 @@ def test_generate_output_split_half_recursive(user_pub, user2_pub, user3_pub): def test_generate_outputs_split_half_single_owner(user_pub, user2_pub, user3_pub): - from planetmint.transactions.common.transaction import Output - from cryptoconditions import Ed25519Sha256, ThresholdSha256 - expected_simple1 = Ed25519Sha256(public_key=b58decode(user_pub)) expected_simple2 = Ed25519Sha256(public_key=b58decode(user2_pub)) expected_simple3 = Ed25519Sha256(public_key=b58decode(user3_pub)) @@ -220,9 +204,6 @@ def test_generate_outputs_split_half_single_owner(user_pub, user2_pub, user3_pub def test_generate_outputs_flat_ownage(user_pub, user2_pub, user3_pub): - from planetmint.transactions.common.transaction import Output - from cryptoconditions import Ed25519Sha256, ThresholdSha256 - expected_simple1 = Ed25519Sha256(public_key=b58decode(user_pub)) expected_simple2 = Ed25519Sha256(public_key=b58decode(user2_pub)) expected_simple3 = Ed25519Sha256(public_key=b58decode(user3_pub)) @@ -237,9 +218,6 @@ def test_generate_outputs_flat_ownage(user_pub, user2_pub, user3_pub): def test_generate_output_single_owner(user_pub): - from planetmint.transactions.common.transaction import Output - from cryptoconditions import Ed25519Sha256 - expected = Ed25519Sha256(public_key=b58decode(user_pub)) cond = Output.generate([user_pub], 1) @@ -247,9 +225,6 @@ def test_generate_output_single_owner(user_pub): def test_generate_output_single_owner_with_output(user_pub): - from planetmint.transactions.common.transaction import Output - from cryptoconditions import Ed25519Sha256 - expected = Ed25519Sha256(public_key=b58decode(user_pub)) cond = Output.generate([expected], 1) @@ -273,8 +248,6 @@ def test_generate_output_invalid_parameters(user_pub, user2_pub, user3_pub): def test_invalid_transaction_initialization(asset_definition): - from planetmint.transactions.common.transaction import Transaction - with raises(ValueError): Transaction(operation="invalid operation", asset=asset_definition) with raises(TypeError): @@ -290,8 +263,6 @@ def test_invalid_transaction_initialization(asset_definition): def test_create_default_asset_on_tx_initialization(asset_definition): - from planetmint.transactions.common.transaction import Transaction - expected = {"data": None} tx = Transaction(Transaction.CREATE, asset=expected) asset = tx.asset @@ -300,8 +271,6 @@ def test_create_default_asset_on_tx_initialization(asset_definition): def test_transaction_serialization(user_input, user_output, data): - from planetmint.transactions.common.transaction import Transaction - expected = { "id": None, "version": Transaction.VERSION, @@ -323,7 +292,6 @@ def test_transaction_serialization(user_input, user_output, data): def test_transaction_deserialization(tri_state_transaction): - from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model tx = Transaction.from_dict(tri_state_transaction) @@ -340,7 +308,6 @@ def test_invalid_input_initialization(user_input, user_pub): def test_transaction_link_serialization(): - from planetmint.transactions.common.transaction import TransactionLink tx_id = "a transaction id" expected = { @@ -353,8 +320,6 @@ def test_transaction_link_serialization(): def test_transaction_link_serialization_with_empty_payload(): - from planetmint.transactions.common.transaction import TransactionLink - expected = None tx_link = TransactionLink() @@ -362,8 +327,6 @@ def test_transaction_link_serialization_with_empty_payload(): def test_transaction_link_deserialization(): - from planetmint.transactions.common.transaction import TransactionLink - tx_id = "a transaction id" expected = TransactionLink(tx_id, 0) tx_link = { @@ -376,8 +339,6 @@ def test_transaction_link_deserialization(): def test_transaction_link_deserialization_with_empty_payload(): - from planetmint.transactions.common.transaction import TransactionLink - expected = TransactionLink() tx_link = TransactionLink.from_dict(None) @@ -385,8 +346,6 @@ def test_transaction_link_deserialization_with_empty_payload(): def test_transaction_link_empty_to_uri(): - from planetmint.transactions.common.transaction import TransactionLink - expected = None tx_link = TransactionLink().to_uri() @@ -394,8 +353,6 @@ def test_transaction_link_empty_to_uri(): def test_transaction_link_to_uri(): - from planetmint.transactions.common.transaction import TransactionLink - expected = "path/transactions/abc/outputs/0" tx_link = TransactionLink("abc", 0).to_uri("path") @@ -403,8 +360,6 @@ def test_transaction_link_to_uri(): def test_cast_transaction_link_to_boolean(): - from planetmint.transactions.common.transaction import TransactionLink - assert bool(TransactionLink()) is False assert bool(TransactionLink("a", None)) is False assert bool(TransactionLink(None, "b")) is False @@ -413,8 +368,6 @@ def test_cast_transaction_link_to_boolean(): def test_transaction_link_eq(): - from planetmint.transactions.common.transaction import TransactionLink - assert TransactionLink(1, 2) == TransactionLink(1, 2) assert TransactionLink(2, 2) != TransactionLink(1, 2) assert TransactionLink(1, 1) != TransactionLink(1, 2) @@ -422,7 +375,6 @@ def test_transaction_link_eq(): def test_add_input_to_tx(user_input, asset_definition): - from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model tx = Transaction(Transaction.CREATE, asset_definition, [], []) @@ -434,8 +386,6 @@ def test_add_input_to_tx(user_input, asset_definition): def test_add_input_to_tx_with_invalid_parameters(asset_definition): - from planetmint.transactions.common.transaction import Transaction - tx = Transaction(Transaction.CREATE, asset_definition) with raises(TypeError): @@ -443,7 +393,6 @@ def test_add_input_to_tx_with_invalid_parameters(asset_definition): def test_add_output_to_tx(user_output, user_input, asset_definition): - from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model tx = Transaction(Transaction.CREATE, asset_definition, [user_input]) @@ -455,8 +404,6 @@ def test_add_output_to_tx(user_output, user_input, asset_definition): def test_add_output_to_tx_with_invalid_parameters(asset_definition): - from planetmint.transactions.common.transaction import Transaction - tx = Transaction(Transaction.CREATE, asset_definition, [], []) with raises(TypeError): @@ -471,7 +418,6 @@ def test_sign_with_invalid_parameters(utx, user_priv): def test_validate_tx_simple_create_signature(user_input, user_output, user_priv, asset_definition): - from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model tx = Transaction(Transaction.CREATE, asset_definition, [user_input], [user_output]) @@ -508,8 +454,6 @@ def test_sign_threshold_with_invalid_params(utx, user_user2_threshold_input, use def test_validate_input_with_invalid_parameters(utx): - from planetmint.transactions.common.transaction import Transaction - input_conditions = [out.fulfillment.condition_uri for out in utx.outputs] tx_dict = utx.to_dict() tx_serialized = Transaction._to_str(tx_dict) @@ -526,7 +470,6 @@ def test_validate_tx_threshold_create_signature( user2_priv, asset_definition, ): - from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model tx = Transaction(Transaction.CREATE, asset_definition, [user_user2_threshold_input], [user_user2_threshold_output]) @@ -546,9 +489,6 @@ def test_validate_tx_threshold_create_signature( def test_validate_tx_threshold_duplicated_pk(user_pub, user_priv, asset_definition): - from cryptoconditions import Ed25519Sha256, ThresholdSha256 - from planetmint.transactions.common.transaction import Input, Output, Transaction - threshold = ThresholdSha256(threshold=2) threshold.add_subfulfillment(Ed25519Sha256(public_key=b58decode(user_pub))) threshold.add_subfulfillment(Ed25519Sha256(public_key=b58decode(user_pub))) @@ -581,8 +521,6 @@ def test_validate_tx_threshold_duplicated_pk(user_pub, user_priv, asset_definiti def test_multiple_input_validation_of_transfer_tx( user_input, user_output, user_priv, user2_pub, user2_priv, user3_pub, user3_priv, asset_definition ): - from planetmint.transactions.common.transaction import Transaction, TransactionLink, Input, Output - from cryptoconditions import Ed25519Sha256 from .utils import validate_transaction_model tx = Transaction(Transaction.CREATE, asset_definition, [user_input], [user_output, deepcopy(user_output)]) @@ -607,9 +545,6 @@ def test_multiple_input_validation_of_transfer_tx( def test_validate_inputs_of_transfer_tx_with_invalid_params( transfer_tx, cond_uri, utx, user2_pub, user_priv, ffill_uri ): - from planetmint.transactions.common.transaction import Output - from cryptoconditions import Ed25519Sha256 - invalid_out = Output(Ed25519Sha256.from_uri(ffill_uri), ["invalid"]) assert transfer_tx.inputs_valid([invalid_out]) is False invalid_out = utx.outputs[0] @@ -628,7 +563,6 @@ def test_validate_inputs_of_transfer_tx_with_invalid_params( def test_create_create_transaction_single_io(user_output, user_pub, data): - from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model expected = { @@ -660,8 +594,6 @@ def test_validate_single_io_create_transaction(user_pub, user_priv, data, asset_ def test_create_create_transaction_multiple_io(user_output, user2_output, user_pub, user2_pub, asset_definition): - from planetmint.transactions.common.transaction import Transaction, Input - # a fulfillment for a create transaction with multiple `owners_before` # is a fulfillment for an implicit threshold condition with # weight = len(owners_before) @@ -695,8 +627,6 @@ def test_validate_multiple_io_create_transaction(user_pub, user_priv, user2_pub, def test_create_create_transaction_threshold( user_pub, user2_pub, user3_pub, user_user2_threshold_output, user_user2_threshold_input, data ): - from planetmint.transactions.common.transaction import Transaction - expected = { "outputs": [user_user2_threshold_output.to_dict()], "metadata": data, @@ -763,7 +693,6 @@ def test_outputs_to_inputs(tx): def test_create_transfer_transaction_single_io(tx, user_pub, user2_pub, user2_output, user_priv): - from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model expected = { @@ -812,8 +741,6 @@ def test_create_transfer_transaction_single_io(tx, user_pub, user2_pub, user2_ou def test_create_transfer_transaction_multiple_io( user_pub, user_priv, user2_pub, user2_priv, user3_pub, user2_output, asset_definition ): - from planetmint.transactions.common.transaction import Transaction - tx = Create.generate([user_pub], [([user_pub], 1), ([user2_pub], 1)], metadata={"message": "hello"}) tx = tx.sign([user_priv]) @@ -873,7 +800,6 @@ def test_create_transfer_with_invalid_parameters(tx, user_pub): def test_cant_add_empty_output(): - from planetmint.transactions.common.transaction import Transaction tx = Transaction(Transaction.CREATE, None) @@ -882,8 +808,6 @@ def test_cant_add_empty_output(): def test_cant_add_empty_input(): - from planetmint.transactions.common.transaction import Transaction - tx = Transaction(Transaction.CREATE, None) with raises(TypeError): @@ -891,24 +815,18 @@ def test_cant_add_empty_input(): def test_unfulfilled_transaction_serialized(unfulfilled_transaction): - from planetmint.transactions.common.transaction import Transaction - tx_obj = Transaction.from_dict(unfulfilled_transaction) expected = json.dumps(unfulfilled_transaction, sort_keys=True, separators=(",", ":"), ensure_ascii=True) assert tx_obj.serialized == expected def test_fulfilled_transaction_serialized(fulfilled_transaction): - from planetmint.transactions.common.transaction import Transaction - tx_obj = Transaction.from_dict(fulfilled_transaction) expected = json.dumps(fulfilled_transaction, sort_keys=True, separators=(",", ":"), ensure_ascii=True) assert tx_obj.serialized == expected def test_transaction_hash(fulfilled_transaction): - from planetmint.transactions.common.transaction import Transaction - tx_obj = Transaction.from_dict(fulfilled_transaction) assert tx_obj._id is None assert tx_obj.id is None diff --git a/tests/tendermint/test_utils.py b/tests/tendermint/test_utils.py index 785685c..fe9dc62 100644 --- a/tests/tendermint/test_utils.py +++ b/tests/tendermint/test_utils.py @@ -5,6 +5,7 @@ import base64 import json +from pytest import mark try: from hashlib import sha3_256 @@ -47,6 +48,9 @@ SAMPLE_PUBLIC_KEY = { } +@mark.skip( + reason="ripemd160, the core of pulbic_key64_to_address is no longer supported by hashlib (from python 3.9.13 on)" +) def test_convert_base64_public_key_to_address(): from planetmint.tendermint_utils import public_key64_to_address