From e9293a7596229a3b19aa37241a6afdbf2131b28d Mon Sep 17 00:00:00 2001 From: ArpitShukla007 Date: Wed, 26 Jan 2022 19:23:13 +0100 Subject: [PATCH 01/93] Initial changes with abci --- planetmint/__init__.py | 2 +- planetmint/core.py | 47 ++++++++++++++----- planetmint/parallel_validation.py | 33 +++++++++++-- planetmint/start.py | 6 +-- .../upsert_validator/validator_utils.py | 5 +- setup.py | 2 +- 6 files changed, 69 insertions(+), 26 deletions(-) diff --git a/planetmint/__init__.py b/planetmint/__init__.py index e211654..47c2643 100644 --- a/planetmint/__init__.py +++ b/planetmint/__init__.py @@ -71,7 +71,7 @@ config = { 'tendermint': { 'host': 'localhost', 'port': 26657, - 'version': 'v0.31.5', # look for __tm_supported_versions__ + 'version': 'v0.34.11', # look for __tm_supported_versions__ }, # FIXME: hardcoding to localmongodb for now 'database': _database_map['localmongodb'], diff --git a/planetmint/core.py b/planetmint/core.py index b87a778..4143858 100644 --- a/planetmint/core.py +++ b/planetmint/core.py @@ -10,7 +10,30 @@ import logging import sys from abci.application import BaseApplication -from abci import CodeTypeOk +from abci.application import OkCode +from tendermint.abci.types_pb2 import ( + RequestInfo, + ResponseInfo, + RequestInitChain, + ResponseInitChain, + ResponseCheckTx, + ResponseDeliverTx, + RequestQuery, + ResponseQuery, + RequestBeginBlock, + ResponseBeginBlock, + RequestEndBlock, + ResponseEndBlock, + ResponseCommit, + RequestLoadSnapshotChunk, + ResponseLoadSnapshotChunk, + RequestListSnapshots, + ResponseListSnapshots, + RequestOfferSnapshot, + ResponseOfferSnapshot, + RequestApplySnapshotChunk, + ResponseApplySnapshotChunk, +) from planetmint import Planetmint from planetmint.elections.election import Election @@ -34,8 +57,8 @@ class App(BaseApplication): transaction logic to Tendermint Core. """ - def __init__(self, abci, planetmint=None, events_queue=None,): - super().__init__(abci) + def __init__(self, planetmint=None, events_queue=None,): + #super().__init__(abci) self.events_queue = events_queue self.planetmint = planetmint or Planetmint() self.block_txn_ids = [] @@ -101,7 +124,7 @@ class App(BaseApplication): genesis.chain_id, True) self.chain = {'height': abci_chain_height, 'is_synced': True, 'chain_id': genesis.chain_id} - return self.abci.ResponseInitChain() + return ResponseInitChain() def info(self, request): """Return height of the latest committed block.""" @@ -116,7 +139,7 @@ class App(BaseApplication): logger.info(f"Tendermint version: {request.version}") - r = self.abci.ResponseInfo() + r = ResponseInfo() block = self.planetmint.get_latest_block() if block: chain_shift = 0 if self.chain is None else self.chain['height'] @@ -141,10 +164,10 @@ class App(BaseApplication): transaction = decode_transaction(raw_transaction) if self.planetmint.is_valid_transaction(transaction): logger.debug('check_tx: VALID') - return self.abci.ResponseCheckTx(code=CodeTypeOk) + return ResponseCheckTx(code=CodeTypeOk) else: logger.debug('check_tx: INVALID') - return self.abci.ResponseCheckTx(code=CodeTypeError) + return ResponseCheckTx(code=CodeTypeError) def begin_block(self, req_begin_block): """Initialize list of transaction. @@ -161,7 +184,7 @@ class App(BaseApplication): self.block_txn_ids = [] self.block_transactions = [] - return self.abci.ResponseBeginBlock() + return ResponseBeginBlock() def deliver_tx(self, raw_transaction): """Validate the transaction before mutating the state. @@ -178,12 +201,12 @@ class App(BaseApplication): if not transaction: logger.debug('deliver_tx: INVALID') - return self.abci.ResponseDeliverTx(code=CodeTypeError) + return ResponseDeliverTx(code=CodeTypeError) else: logger.debug('storing tx') self.block_txn_ids.append(transaction.id) self.block_transactions.append(transaction) - return self.abci.ResponseDeliverTx(code=CodeTypeOk) + return ResponseDeliverTx(code=CodeTypeOk) def end_block(self, request_end_block): """Calculate block hash using transaction ids and previous block @@ -219,7 +242,7 @@ class App(BaseApplication): self.new_height, self.block_transactions) - return self.abci.ResponseEndBlock(validator_updates=validator_update) + return ResponseEndBlock(validator_updates=validator_update) def commit(self): """Store the new height and along with block hash.""" @@ -250,7 +273,7 @@ class App(BaseApplication): }) self.events_queue.put(event) - return self.abci.ResponseCommit(data=data) + return ResponseCommit(data=data) def rollback(b): diff --git a/planetmint/parallel_validation.py b/planetmint/parallel_validation.py index 047bb2c..126fabc 100644 --- a/planetmint/parallel_validation.py +++ b/planetmint/parallel_validation.py @@ -8,21 +8,44 @@ from collections import defaultdict from planetmint import App, Planetmint from planetmint.tendermint_utils import decode_transaction -from abci import CodeTypeOk +from abci.application import OkCode +from tendermint.abci.types_pb2 import ( + RequestInfo, + ResponseInfo, + RequestInitChain, + ResponseInitChain, + #ResponseCheckTx, + #ResponseDeliverTx, + RequestQuery, + ResponseQuery, + RequestBeginBlock, + ResponseBeginBlock, + RequestEndBlock, + ResponseEndBlock, + ResponseCommit, + RequestLoadSnapshotChunk, + ResponseLoadSnapshotChunk, + RequestListSnapshots, + ResponseListSnapshots, + RequestOfferSnapshot, + ResponseOfferSnapshot, + RequestApplySnapshotChunk, + ResponseApplySnapshotChunk, +) class ParallelValidationApp(App): - def __init__(self, planetmint=None, events_queue=None, abci=None): - super().__init__(planetmint, events_queue, abci=abci) + def __init__(self, planetmint=None, events_queue=None): + super().__init__(planetmint, events_queue) self.parallel_validator = ParallelValidator() self.parallel_validator.start() def check_tx(self, raw_transaction): - return self.abci.ResponseCheckTx(code=CodeTypeOk) + return ResponseCheckTx(code=OkCode) def deliver_tx(self, raw_transaction): self.parallel_validator.validate(raw_transaction) - return self.abci.ResponseDeliverTx(code=CodeTypeOk) + return ResponseDeliverTx(code=OkCode) def end_block(self, request_end_block): result = self.parallel_validator.result(timeout=30) diff --git a/planetmint/start.py b/planetmint/start.py index 5e25261..e511d1b 100644 --- a/planetmint/start.py +++ b/planetmint/start.py @@ -6,7 +6,7 @@ import logging import setproctitle -from abci import TmVersion, ABCI +#from abci import TmVersion, ABCI import planetmint from planetmint.lib import Planetmint @@ -68,18 +68,16 @@ def start(args): setproctitle.setproctitle('planetmint') # Start the ABCIServer - abci = ABCI(TmVersion(planetmint.config['tendermint']['version'])) + #abci = ABCI(TmVersion(planetmint.config['tendermint']['version'])) if args.experimental_parallel_validation: app = ABCIServer( app=ParallelValidationApp( - abci=abci.types, events_queue=exchange.get_publisher_queue(), ) ) else: app = ABCIServer( app=App( - abci=abci.types, events_queue=exchange.get_publisher_queue(), ) ) diff --git a/planetmint/upsert_validator/validator_utils.py b/planetmint/upsert_validator/validator_utils.py index ba6a864..89a2a93 100644 --- a/planetmint/upsert_validator/validator_utils.py +++ b/planetmint/upsert_validator/validator_utils.py @@ -3,7 +3,7 @@ import binascii import codecs import planetmint -from abci import types_v0_22_8, types_v0_31_5, TmVersion +from tendermint.abci import types_pb2 as types_v0_34_11 from planetmint.common.exceptions import InvalidPublicKey, BigchainDBError @@ -17,8 +17,7 @@ def encode_validator(v): 'check Planetmint configuration file') validator_update_t, pubkey_t = { - TmVersion.v0_22_8: (types_v0_22_8.Validator, types_v0_22_8.PubKey), - TmVersion.v0_31_5: (types_v0_31_5.ValidatorUpdate, types_v0_31_5.PubKey) + TmVersion.v0_34_11: (types_v0_34_11.ValidatorUpdate, types_v0_34_11.PubKey) }[version] pub_key = pubkey_t(type='ed25519', data=bytes.fromhex(ed25519_public_key)) diff --git a/setup.py b/setup.py index 5e9c5a9..f6f80c1 100644 --- a/setup.py +++ b/setup.py @@ -73,7 +73,7 @@ tests_require = [ install_requires = [ 'chardet==3.0.4', 'aiohttp==3.7.4', - 'bigchaindb-abci==1.0.7', + 'abci==0.8.3', 'cryptoconditions==0.8.1', 'flask-cors==3.0.10', 'flask-restful==0.3.9', From 8b88040a5f6100f936b169bfd35daa2dba18b269 Mon Sep 17 00:00:00 2001 From: ArpitShukla007 Date: Thu, 27 Jan 2022 08:11:54 +0000 Subject: [PATCH 02/93] Added test support for Tendermint 0.34.11 --- Dockerfile-all-in-one | 2 +- docker-compose.yml | 2 +- .../run-node-as-processes.md | 6 +++--- .../network-setup/k8s-deployment-template/workflow.rst | 2 +- k8s/planetmint/tendermint_container/Dockerfile | 2 +- pkg/scripts/stack.sh | 2 +- planetmint/core.py | 10 +++++----- planetmint/version.py | 2 +- tests/test_config_utils.py | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Dockerfile-all-in-one b/Dockerfile-all-in-one index 11d8d20..c4b7b77 100644 --- a/Dockerfile-all-in-one +++ b/Dockerfile-all-in-one @@ -1,7 +1,7 @@ FROM alpine:3.9 LABEL maintainer "contact@ipdb.global" -ARG TM_VERSION=v0.31.5 +ARG TM_VERSION=v0.34.11 RUN mkdir -p /usr/src/app ENV HOME /root COPY . /usr/src/app/ diff --git a/docker-compose.yml b/docker-compose.yml index a72b8bf..ceaec91 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -51,7 +51,7 @@ services: command: '.ci/entrypoint.sh' restart: always tendermint: - image: tendermint/tendermint:v0.31.5 + image: tendermint/tendermint:v0.34.11 # volumes: # - ./tmdata:/tendermint entrypoint: '' diff --git a/docs/root/source/contributing/dev-setup-coding-and-contribution-process/run-node-as-processes.md b/docs/root/source/contributing/dev-setup-coding-and-contribution-process/run-node-as-processes.md index 70a3791..e5b04c5 100644 --- a/docs/root/source/contributing/dev-setup-coding-and-contribution-process/run-node-as-processes.md +++ b/docs/root/source/contributing/dev-setup-coding-and-contribution-process/run-node-as-processes.md @@ -30,9 +30,9 @@ The version of Planetmint Server described in these docs only works well with Te ```bash $ sudo apt install -y unzip -$ wget https://github.com/tendermint/tendermint/releases/download/v0.31.5/tendermint_v0.31.5_linux_amd64.zip -$ unzip tendermint_v0.31.5_linux_amd64.zip -$ rm tendermint_v0.31.5_linux_amd64.zip +$ wget https://github.com/tendermint/tendermint/releases/download/v0.34.11/tendermint_v0.34.11_linux_amd64.zip +$ unzip tendermint_v0.34.11_linux_amd64.zip +$ rm tendermint_v0.34.11_linux_amd64.zip $ sudo mv tendermint /usr/local/bin ``` diff --git a/docs/root/source/installation/network-setup/k8s-deployment-template/workflow.rst b/docs/root/source/installation/network-setup/k8s-deployment-template/workflow.rst index 4f00dae..43e964f 100644 --- a/docs/root/source/installation/network-setup/k8s-deployment-template/workflow.rst +++ b/docs/root/source/installation/network-setup/k8s-deployment-template/workflow.rst @@ -60,7 +60,7 @@ you can do this: .. code:: $ mkdir $(pwd)/tmdata - $ docker run --rm -v $(pwd)/tmdata:/tendermint/config tendermint/tendermint:v0.31.5 init + $ docker run --rm -v $(pwd)/tmdata:/tendermint/config tendermint/tendermint:v0.34.11 init $ cat $(pwd)/tmdata/genesis.json You should see something that looks like: diff --git a/k8s/planetmint/tendermint_container/Dockerfile b/k8s/planetmint/tendermint_container/Dockerfile index 1404f46..5795f81 100644 --- a/k8s/planetmint/tendermint_container/Dockerfile +++ b/k8s/planetmint/tendermint_container/Dockerfile @@ -1,4 +1,4 @@ -FROM tendermint/tendermint:v0.31.5 +FROM tendermint/tendermint:v0.34.11 LABEL maintainer "contact@ipdb.global" WORKDIR / USER root diff --git a/pkg/scripts/stack.sh b/pkg/scripts/stack.sh index a00eb72..c84fa4d 100755 --- a/pkg/scripts/stack.sh +++ b/pkg/scripts/stack.sh @@ -17,7 +17,7 @@ stack_size=${STACK_SIZE:=4} stack_type=${STACK_TYPE:="docker"} stack_type_provider=${STACK_TYPE_PROVIDER:=""} # NOTE versions prior v0.28.0 have different priv_validator format! -tm_version=${TM_VERSION:="v0.31.5"} +tm_version=${TM_VERSION:="v0.34.11"} mongo_version=${MONGO_VERSION:="3.6"} stack_vm_memory=${STACK_VM_MEMORY:=2048} stack_vm_cpus=${STACK_VM_CPUS:=2} diff --git a/planetmint/core.py b/planetmint/core.py index 4143858..ae73cdd 100644 --- a/planetmint/core.py +++ b/planetmint/core.py @@ -132,12 +132,12 @@ class App(BaseApplication): self.abort_if_abci_chain_is_not_synced() # Check if Planetmint supports the Tendermint version - if not (hasattr(request, 'version') and tendermint_version_is_compatible(request.version)): - logger.error(f'Unsupported Tendermint version: {getattr(request, "version", "no version")}.' - f' Currently, Planetmint only supports {__tm_supported_versions__}. Exiting!') - sys.exit(1) + #if not (hasattr(request, 'version') and tendermint_version_is_compatible(request.version)): + # logger.error(f'Unsupported Tendermint version: {getattr(request, "version", "no version")}.' + # f' Currently, Planetmint only supports {__tm_supported_versions__}. Exiting!') + # sys.exit(1) - logger.info(f"Tendermint version: {request.version}") + #logger.info(f"Tendermint version: {request.version}") r = ResponseInfo() block = self.planetmint.get_latest_block() diff --git a/planetmint/version.py b/planetmint/version.py index ec8d03e..e77393e 100644 --- a/planetmint/version.py +++ b/planetmint/version.py @@ -7,4 +7,4 @@ __version__ = '0.9.0' __short_version__ = '0.9' # Supported Tendermint versions -__tm_supported_versions__ = ["0.31.5", "0.22.8"] +__tm_supported_versions__ = ["0.34.11"] diff --git a/tests/test_config_utils.py b/tests/test_config_utils.py index 2b50135..a938a5f 100644 --- a/tests/test_config_utils.py +++ b/tests/test_config_utils.py @@ -221,7 +221,7 @@ def test_autoconfigure_read_both_from_file_and_env(monkeypatch, request): 'tendermint': { 'host': 'localhost', 'port': 26657, - 'version': 'v0.31.5' + 'version': 'v0.34.11' }, 'log': { 'file': LOG_FILE, From 6b3fe4b9fc1014421349d572e0077e28d362b11e Mon Sep 17 00:00:00 2001 From: ArpitShukla007 Date: Thu, 27 Jan 2022 16:47:59 +0000 Subject: [PATCH 03/93] resolved errors with regards to block header config. --- planetmint/core.py | 6 +++--- planetmint/upsert_validator/validator_utils.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/planetmint/core.py b/planetmint/core.py index ae73cdd..a815712 100644 --- a/planetmint/core.py +++ b/planetmint/core.py @@ -178,9 +178,9 @@ class App(BaseApplication): self.abort_if_abci_chain_is_not_synced() chain_shift = 0 if self.chain is None else self.chain['height'] - logger.debug('BEGIN BLOCK, height:%s, num_txs:%s', - req_begin_block.header.height + chain_shift, - req_begin_block.header.num_txs) + #req_begin_block.header.num_txs not found, so removing it. + logger.debug('BEGIN BLOCK, height:%s', + req_begin_block.header.height + chain_shift) self.block_txn_ids = [] self.block_transactions = [] diff --git a/planetmint/upsert_validator/validator_utils.py b/planetmint/upsert_validator/validator_utils.py index 89a2a93..c5477a2 100644 --- a/planetmint/upsert_validator/validator_utils.py +++ b/planetmint/upsert_validator/validator_utils.py @@ -26,7 +26,7 @@ def encode_validator(v): def decode_validator(v): return {'public_key': {'type': 'ed25519-base64', - 'value': codecs.encode(v.pub_key.data, 'base64').decode().rstrip('\n')}, + 'value': codecs.encode(v.pub_key.ed25519, 'base64').decode().rstrip('\n')}, 'voting_power': v.power} From 89bbabf81852225bd746cd18eeeaf568f3523510 Mon Sep 17 00:00:00 2001 From: ArpitShukla007 Date: Tue, 1 Feb 2022 13:56:15 +0000 Subject: [PATCH 04/93] Solved bugs --- docker-compose.yml | 2 +- planetmint/core.py | 9 ++++++++- planetmint/upsert_validator/validator_utils.py | 4 ++++ tests/conftest.py | 8 ++++---- tests/elections/test_election.py | 2 +- tests/tendermint/conftest.py | 2 +- tests/tendermint/test_core.py | 14 +++++++------- tests/tendermint/test_integration.py | 4 ++-- 8 files changed, 28 insertions(+), 17 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index ceaec91..01f537d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -58,7 +58,7 @@ services: ports: - "26656:26656" - "26657:26657" - command: sh -c "tendermint init && tendermint node --consensus.create_empty_blocks=false --proxy_app=tcp://planetmint:26658" + command: sh -c "tendermint init && tendermint node --consensus.create_empty_blocks=false --rpc.laddr=tcp://0.0.0.0:26657 --proxy_app=tcp://planetmint:26658" restart: always bdb: image: busybox diff --git a/planetmint/core.py b/planetmint/core.py index a815712..ab9a99f 100644 --- a/planetmint/core.py +++ b/planetmint/core.py @@ -8,7 +8,8 @@ with Tendermint. """ import logging import sys - +import enum +from tendermint.abci import types_pb2 from abci.application import BaseApplication from abci.application import OkCode from tendermint.abci.types_pb2 import ( @@ -49,6 +50,10 @@ from planetmint.events import EventTypes, Event CodeTypeError = 1 logger = logging.getLogger(__name__) +class TmVersion(enum.Enum): + """Supported Tendermint versions enum""" + v0_34_11 = 'v0.34.11' + class App(BaseApplication): """Bridge between Planetmint and Tendermint. @@ -59,6 +64,8 @@ class App(BaseApplication): def __init__(self, planetmint=None, events_queue=None,): #super().__init__(abci) + logger.debug('Checking values of types') + logger.debug(dir(types_pb2)) self.events_queue = events_queue self.planetmint = planetmint or Planetmint() self.block_txn_ids = [] diff --git a/planetmint/upsert_validator/validator_utils.py b/planetmint/upsert_validator/validator_utils.py index c5477a2..b368676 100644 --- a/planetmint/upsert_validator/validator_utils.py +++ b/planetmint/upsert_validator/validator_utils.py @@ -1,11 +1,15 @@ import base64 import binascii import codecs +import enum import planetmint from tendermint.abci import types_pb2 as types_v0_34_11 from planetmint.common.exceptions import InvalidPublicKey, BigchainDBError +class TmVersion(enum.Enum): + """Supported Tendermint versions enum""" + v0_34_11 = 'v0.34.11' def encode_validator(v): ed25519_public_key = v['public_key']['value'] diff --git a/tests/conftest.py b/tests/conftest.py index 77e22cf..12bbe3b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -236,8 +236,8 @@ def merlin(): @pytest.fixture def a(): - from abci import types_v0_31_5 - return types_v0_31_5 + from tendermint.abci import types_pb2 as types_v0_34_11 + return types_v0_34_11 @pytest.fixture @@ -442,11 +442,11 @@ def event_loop(): @pytest.fixture(scope='session') def abci_server(): from abci.server import ABCIServer - from abci import types_v0_31_5 + from tendermint.abci import types_pb2 as types_v0_34_11 from planetmint.core import App from planetmint.utils import Process - app = ABCIServer(app=App(types_v0_31_5)) + app = ABCIServer(app=App(types_v0_34_11)) abci_proxy = Process(name='ABCI', target=app.run) yield abci_proxy.start() abci_proxy.terminate() diff --git a/tests/elections/test_election.py b/tests/elections/test_election.py index 10c95a2..3e51c9a 100644 --- a/tests/elections/test_election.py +++ b/tests/elections/test_election.py @@ -6,7 +6,7 @@ from planetmint.lib import Block from planetmint.elections.election import Election from planetmint.migrations.chain_migration_election import ChainMigrationElection from planetmint.upsert_validator.validator_election import ValidatorElection - +from planetmint.core import TmVersion @pytest.mark.bdb def test_process_block_concludes_all_elections(b): diff --git a/tests/tendermint/conftest.py b/tests/tendermint/conftest.py index aab19ec..536181a 100644 --- a/tests/tendermint/conftest.py +++ b/tests/tendermint/conftest.py @@ -6,7 +6,7 @@ import pytest import codecs -from abci import types_v0_31_5 as types +from tendermint.abci import types_pb2 as types @pytest.fixture diff --git a/tests/tendermint/test_core.py b/tests/tendermint/test_core.py index 79c5f8c..55aaf39 100644 --- a/tests/tendermint/test_core.py +++ b/tests/tendermint/test_core.py @@ -7,12 +7,12 @@ import json import pytest import random -from abci import types_v0_31_5 as types +from tendermint.abci import types_pb2 as types from planetmint import App from planetmint.backend.localmongodb import query from planetmint.common.crypto import generate_key_pair -from planetmint.core import (CodeTypeOk, +from planetmint.core import (OkCode, CodeTypeError, rollback) from planetmint.elections.election import Election @@ -213,7 +213,7 @@ def test_check_tx__signed_create_is_ok(a, b): app = App(a, b) result = app.check_tx(encode_tx_to_bytes(tx)) - assert result.code == CodeTypeOk + assert result.code == OkCode def test_check_tx__unsigned_create_is_error(a, b): @@ -254,7 +254,7 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(a, b, init_chain_re app.begin_block(begin_block) result = app.deliver_tx(encode_tx_to_bytes(tx)) - assert result.code == CodeTypeOk + assert result.code == OkCode app.end_block(types.RequestEndBlock(height=99)) app.commit() @@ -289,7 +289,7 @@ def test_deliver_tx__double_spend_fails(a, b, init_chain_request): app.begin_block(begin_block) result = app.deliver_tx(encode_tx_to_bytes(tx)) - assert result.code == CodeTypeOk + assert result.code == OkCode app.end_block(types.RequestEndBlock(height=99)) app.commit() @@ -324,7 +324,7 @@ def test_deliver_transfer_tx__double_spend_fails(a, b, init_chain_request): .sign([alice.private_key]) result = app.deliver_tx(encode_tx_to_bytes(tx)) - assert result.code == CodeTypeOk + assert result.code == OkCode tx_transfer = Transaction.transfer(tx.to_inputs(), [([bob.public_key], 1)], @@ -332,7 +332,7 @@ def test_deliver_transfer_tx__double_spend_fails(a, b, init_chain_request): .sign([alice.private_key]) result = app.deliver_tx(encode_tx_to_bytes(tx_transfer)) - assert result.code == CodeTypeOk + assert result.code == OkCode double_spend = Transaction.transfer(tx.to_inputs(), [([carly.public_key], 1)], diff --git a/tests/tendermint/test_integration.py b/tests/tendermint/test_integration.py index 05cb69b..17f96df 100644 --- a/tests/tendermint/test_integration.py +++ b/tests/tendermint/test_integration.py @@ -5,13 +5,13 @@ import codecs -from abci import types_v0_31_5 as types +from tendermint.abci import types_pb2 as types import json import pytest from abci.server import ProtocolHandler -from abci.encoding import read_messages +from abci.utils import read_messages from planetmint.common.transaction_mode_types import BROADCAST_TX_COMMIT, BROADCAST_TX_SYNC from planetmint.version import __tm_supported_versions__ From 959d2e98f018e06925f909904b64db91f6b742ad Mon Sep 17 00:00:00 2001 From: ArpitShukla007 Date: Wed, 2 Feb 2022 08:03:42 +0000 Subject: [PATCH 05/93] Resolved PubKey issue --- planetmint/core.py | 38 +- planetmint/parallel_validation.py | 2 +- .../upsert_validator/validator_utils.py | 5 +- tests/tendermint/conftest.py | 4 +- tests/test_core.py | 611 +++++++++++++++--- 5 files changed, 544 insertions(+), 116 deletions(-) diff --git a/planetmint/core.py b/planetmint/core.py index ab9a99f..65d6a10 100644 --- a/planetmint/core.py +++ b/planetmint/core.py @@ -62,29 +62,29 @@ class App(BaseApplication): transaction logic to Tendermint Core. """ - def __init__(self, planetmint=None, events_queue=None,): + def __init__(self, planetmint_node=None, events_queue=None,): #super().__init__(abci) logger.debug('Checking values of types') logger.debug(dir(types_pb2)) self.events_queue = events_queue - self.planetmint = planetmint or Planetmint() + self.planetmint_node = planetmint_node or Planetmint() self.block_txn_ids = [] self.block_txn_hash = '' self.block_transactions = [] self.validators = None self.new_height = None - self.chain = self.planetmint.get_latest_abci_chain() + self.chain = self.planetmint_node.get_latest_abci_chain() def log_abci_migration_error(self, chain_id, validators): logger.error('An ABCI chain migration is in process. ' - 'Download the new ABCI client and configure it with ' + 'Download theself.planetmint_node.get_latest_abci_chain new ABCI client and configure it with ' f'chain_id={chain_id} and validators={validators}.') def abort_if_abci_chain_is_not_synced(self): if self.chain is None or self.chain['is_synced']: return - validators = self.planetmint.get_validators() + validators = self.planetmint_node.get_validators() self.log_abci_migration_error(self.chain['chain_id'], validators) sys.exit(1) @@ -94,7 +94,7 @@ class App(BaseApplication): app_hash = '' height = 0 - known_chain = self.planetmint.get_latest_abci_chain() + known_chain = self.planetmint_node.get_latest_abci_chain() if known_chain is not None: chain_id = known_chain['chain_id'] @@ -105,16 +105,16 @@ class App(BaseApplication): sys.exit(1) if chain_id != genesis.chain_id: - validators = self.planetmint.get_validators() + validators = self.planetmint_node.get_validators() self.log_abci_migration_error(chain_id, validators) sys.exit(1) # set migration values for app hash and height - block = self.planetmint.get_latest_block() + block = self.planetmint_node.get_latest_block() app_hash = '' if block is None else block['app_hash'] height = 0 if block is None else block['height'] + 1 - known_validators = self.planetmint.get_validators() + known_validators = self.planetmint_node.get_validators() validator_set = [vutils.decode_validator(v) for v in genesis.validators] @@ -124,10 +124,10 @@ class App(BaseApplication): sys.exit(1) block = Block(app_hash=app_hash, height=height, transactions=[]) - self.planetmint.store_block(block._asdict()) - self.planetmint.store_validator_set(height + 1, validator_set) + self.planetmint_node.store_block(block._asdict()) + self.planetmint_node.store_validator_set(height + 1, validator_set) abci_chain_height = 0 if known_chain is None else known_chain['height'] - self.planetmint.store_abci_chain(abci_chain_height, + self.planetmint_node.store_abci_chain(abci_chain_height, genesis.chain_id, True) self.chain = {'height': abci_chain_height, 'is_synced': True, 'chain_id': genesis.chain_id} @@ -147,7 +147,7 @@ class App(BaseApplication): #logger.info(f"Tendermint version: {request.version}") r = ResponseInfo() - block = self.planetmint.get_latest_block() + block = self.planetmint_node.get_latest_block() if block: chain_shift = 0 if self.chain is None else self.chain['height'] r.last_block_height = block['height'] - chain_shift @@ -169,7 +169,7 @@ class App(BaseApplication): logger.debug('check_tx: %s', raw_transaction) transaction = decode_transaction(raw_transaction) - if self.planetmint.is_valid_transaction(transaction): + if self.planetmint_node.is_valid_transaction(transaction): logger.debug('check_tx: VALID') return ResponseCheckTx(code=CodeTypeOk) else: @@ -203,7 +203,7 @@ class App(BaseApplication): self.abort_if_abci_chain_is_not_synced() logger.debug('deliver_tx: %s', raw_transaction) - transaction = self.planetmint.is_valid_transaction( + transaction = self.planetmint_node.is_valid_transaction( decode_transaction(raw_transaction), self.block_transactions) if not transaction: @@ -235,10 +235,10 @@ class App(BaseApplication): logger.debug(f'Updating pre-commit state: {self.new_height}') pre_commit_state = dict(height=self.new_height, transactions=self.block_txn_ids) - self.planetmint.store_pre_commit_state(pre_commit_state) + self.planetmint_node.store_pre_commit_state(pre_commit_state) block_txn_hash = calculate_hash(self.block_txn_ids) - block = self.planetmint.get_latest_block() + block = self.planetmint_node.get_latest_block() if self.block_txn_ids: self.block_txn_hash = calculate_hash([block['app_hash'], block_txn_hash]) @@ -260,14 +260,14 @@ class App(BaseApplication): # register a new block only when new transactions are received if self.block_txn_ids: - self.planetmint.store_bulk_transactions(self.block_transactions) + self.planetmint_node.store_bulk_transactions(self.block_transactions) block = Block(app_hash=self.block_txn_hash, height=self.new_height, transactions=self.block_txn_ids) # NOTE: storing the block should be the last operation during commit # this effects crash recovery. Refer BEP#8 for details - self.planetmint.store_block(block._asdict()) + self.planetmint_node.store_block(block._asdict()) logger.debug('Commit-ing new block with hash: apphash=%s ,' 'height=%s, txn ids=%s', data, self.new_height, diff --git a/planetmint/parallel_validation.py b/planetmint/parallel_validation.py index 126fabc..040a758 100644 --- a/planetmint/parallel_validation.py +++ b/planetmint/parallel_validation.py @@ -127,7 +127,7 @@ class ValidationWorker: except KeyError: asset_id = dict_transaction['id'] - transaction = self.planetmint.is_valid_transaction( + transaction = self.planetmint_node.is_valid_transaction( dict_transaction, self.validated_transactions[asset_id]) diff --git a/planetmint/upsert_validator/validator_utils.py b/planetmint/upsert_validator/validator_utils.py index b368676..1485920 100644 --- a/planetmint/upsert_validator/validator_utils.py +++ b/planetmint/upsert_validator/validator_utils.py @@ -5,6 +5,7 @@ import enum import planetmint from tendermint.abci import types_pb2 as types_v0_34_11 +from tendermint.crypto import keys_pb2 from planetmint.common.exceptions import InvalidPublicKey, BigchainDBError class TmVersion(enum.Enum): @@ -21,9 +22,9 @@ def encode_validator(v): 'check Planetmint configuration file') validator_update_t, pubkey_t = { - TmVersion.v0_34_11: (types_v0_34_11.ValidatorUpdate, types_v0_34_11.PubKey) + TmVersion.v0_34_11: (types_v0_34_11.ValidatorUpdate, keys_pb2.PublicKey) }[version] - pub_key = pubkey_t(type='ed25519', data=bytes.fromhex(ed25519_public_key)) + pub_key = pubkey_t(ed25519=bytes.fromhex(ed25519_public_key)) return validator_update_t(pub_key=pub_key, power=v['power']) diff --git a/tests/tendermint/conftest.py b/tests/tendermint/conftest.py index 536181a..e3f3ffd 100644 --- a/tests/tendermint/conftest.py +++ b/tests/tendermint/conftest.py @@ -7,7 +7,7 @@ import pytest import codecs from tendermint.abci import types_pb2 as types - +from tendermint.crypto import keys_pb2 @pytest.fixture def validator_pub_key(): @@ -19,5 +19,5 @@ def init_chain_request(): pk = codecs.decode(b'VAgFZtYw8bNR5TMZHFOBDWk9cAmEu3/c6JgRBmddbbI=', 'base64') val_a = types.ValidatorUpdate(power=10, - pub_key=types.PubKey(type='ed25519', data=pk)) + pub_key=keys_pb2.PublicKey(ed25519=pk)) return types.RequestInitChain(validators=[val_a]) diff --git a/tests/test_core.py b/tests/test_core.py index f857d5d..4cfa779 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1,118 +1,545 @@ -# Copyright © 2020 Interplanetary Database Association e.V., +# Copyright � 2020 Interplanetary Database Association e.V., # Planetmint and IPDB software contributors. # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 +import json import pytest +import random + +from tendermint.abci import types_pb2 as types +from tendermint.crypto import keys_pb2 + +from planetmint import App +from planetmint.backend.localmongodb import query +from planetmint.common.crypto import generate_key_pair +from planetmint.core import (OkCode, + CodeTypeError, + rollback) +from planetmint.elections.election import Election +from planetmint.lib import Block +from planetmint.migrations.chain_migration_election import ChainMigrationElection +from planetmint.upsert_validator.validator_election import ValidatorElection +from planetmint.upsert_validator.validator_utils import new_validator_set +from planetmint.tendermint_utils import public_key_to_base64 +from planetmint.version import __tm_supported_versions__ + +from tests.utils import generate_election, generate_validators -@pytest.fixture -def config(request, monkeypatch): - backend = request.config.getoption('--database-backend') - if backend == 'mongodb-ssl': - backend = 'mongodb' +pytestmark = pytest.mark.bdb - config = { - 'database': { - 'backend': backend, - 'host': 'host', - 'port': 28015, - 'name': 'bigchain', - 'replicaset': 'bigchain-rs', - 'connection_timeout': 5000, - 'max_tries': 3 - }, - 'tendermint': { - 'host': 'localhost', - 'port': 26657, - }, - 'CONFIGURED': True, + +def encode_tx_to_bytes(transaction): + return json.dumps(transaction.to_dict()).encode('utf8') + + +def generate_address(): + return ''.join(random.choices('1,2,3,4,5,6,7,8,9,A,B,C,D,E,F'.split(','), + k=40)).encode() + + +def generate_validator(): + pk, _ = generate_key_pair() + pub_key = keys_pb2.PublicKey(ed25519=pk.encode()) + val = types.ValidatorUpdate(power=10, pub_key=pub_key) + return val + + +def generate_init_chain_request(chain_id, vals=None): + vals = vals if vals is not None else [generate_validator()] + return types.RequestInitChain(validators=vals, chain_id=chain_id) + + +def test_init_chain_successfully_registers_chain(a, b): + request = generate_init_chain_request('chain-XYZ') + res = App(a, b).init_chain(request) + assert res == types.ResponseInitChain() + chain = query.get_latest_abci_chain(b.connection) + assert chain == {'height': 0, 'chain_id': 'chain-XYZ', 'is_synced': True} + assert query.get_latest_block(b.connection) == { + 'height': 0, + 'app_hash': '', + 'transactions': [], } - monkeypatch.setattr('planetmint.config', config) - return config +def test_init_chain_ignores_invalid_init_chain_requests(a, b): + validators = [generate_validator()] + request = generate_init_chain_request('chain-XYZ', validators) + res = App(a, b).init_chain(request) + assert res == types.ResponseInitChain() + + validator_set = query.get_validator_set(b.connection) + + invalid_requests = [ + request, # the same request again + # different validator set + generate_init_chain_request('chain-XYZ'), + # different chain ID + generate_init_chain_request('chain-ABC', validators), + ] + for r in invalid_requests: + with pytest.raises(SystemExit): + App(a, b).init_chain(r) + # assert nothing changed - neither validator set, nor chain ID + new_validator_set = query.get_validator_set(b.connection) + assert new_validator_set == validator_set + new_chain_id = query.get_latest_abci_chain(b.connection)['chain_id'] + assert new_chain_id == 'chain-XYZ' + assert query.get_latest_block(b.connection) == { + 'height': 0, + 'app_hash': '', + 'transactions': [], + } -def test_bigchain_class_default_initialization(config): - from planetmint import Planetmint - from planetmint.validation import BaseValidationRules - from planetmint.backend.connection import Connection - planet = Planetmint() - assert isinstance(planet.connection, Connection) - assert planet.connection.host == config['database']['host'] - assert planet.connection.port == config['database']['port'] - assert planet.connection.dbname == config['database']['name'] - assert planet.validation == BaseValidationRules +def test_init_chain_recognizes_new_chain_after_migration(a, b): + validators = [generate_validator()] + request = generate_init_chain_request('chain-XYZ', validators) + res = App(a, b).init_chain(request) + assert res == types.ResponseInitChain() + validator_set = query.get_validator_set(b.connection)['validators'] -def test_bigchain_class_initialization_with_parameters(): - from planetmint import Planetmint - from planetmint.backend import connect - from planetmint.validation import BaseValidationRules - init_db_kwargs = { - 'backend': 'localmongodb', - 'host': 'this_is_the_db_host', - 'port': 12345, - 'name': 'this_is_the_db_name', + # simulate a migration + query.store_block(b.connection, Block(app_hash='', height=1, + transactions=[])._asdict()) + b.migrate_abci_chain() + + # the same or other mismatching requests are ignored + invalid_requests = [ + request, + generate_init_chain_request('unknown', validators), + generate_init_chain_request('chain-XYZ'), + generate_init_chain_request('chain-XYZ-migrated-at-height-1'), + ] + for r in invalid_requests: + with pytest.raises(SystemExit): + App(a, b).init_chain(r) + assert query.get_latest_abci_chain(b.connection) == { + 'chain_id': 'chain-XYZ-migrated-at-height-1', + 'is_synced': False, + 'height': 2, + } + new_validator_set = query.get_validator_set(b.connection)['validators'] + assert new_validator_set == validator_set + + # a request with the matching chain ID and matching validator set + # completes the migration + request = generate_init_chain_request('chain-XYZ-migrated-at-height-1', + validators) + res = App(a, b).init_chain(request) + assert res == types.ResponseInitChain() + assert query.get_latest_abci_chain(b.connection) == { + 'chain_id': 'chain-XYZ-migrated-at-height-1', + 'is_synced': True, + 'height': 2, } - connection = connect(**init_db_kwargs) - planet = Planetmint(connection=connection) - assert planet.connection == connection - assert planet.connection.host == init_db_kwargs['host'] - assert planet.connection.port == init_db_kwargs['port'] - assert planet.connection.dbname == init_db_kwargs['name'] - assert planet.validation == BaseValidationRules + assert query.get_latest_block(b.connection) == { + 'height': 2, + 'app_hash': '', + 'transactions': [], + } + + # requests with old chain ID and other requests are ignored + invalid_requests = [ + request, + generate_init_chain_request('chain-XYZ', validators), + generate_init_chain_request('chain-XYZ-migrated-at-height-1'), + ] + for r in invalid_requests: + with pytest.raises(SystemExit): + App(a, b).init_chain(r) + assert query.get_latest_abci_chain(b.connection) == { + 'chain_id': 'chain-XYZ-migrated-at-height-1', + 'is_synced': True, + 'height': 2, + } + new_validator_set = query.get_validator_set(b.connection)['validators'] + assert new_validator_set == validator_set + assert query.get_latest_block(b.connection) == { + 'height': 2, + 'app_hash': '', + 'transactions': [], + } -@pytest.mark.bdb -def test_get_spent_issue_1271(b, alice, bob, carol): +def test_info(a, b): + r = types.RequestInfo(version=__tm_supported_versions__[0]) + app = App(a, b) + + res = app.info(r) + assert res.last_block_height == 0 + assert res.last_block_app_hash == b'' + + b.store_block(Block(app_hash='1', height=1, transactions=[])._asdict()) + res = app.info(r) + assert res.last_block_height == 1 + assert res.last_block_app_hash == b'1' + + # simulate a migration and assert the height is shifted + b.store_abci_chain(2, 'chain-XYZ') + app = App(a, b) + b.store_block(Block(app_hash='2', height=2, transactions=[])._asdict()) + res = app.info(r) + assert res.last_block_height == 0 + assert res.last_block_app_hash == b'2' + + b.store_block(Block(app_hash='3', height=3, transactions=[])._asdict()) + res = app.info(r) + assert res.last_block_height == 1 + assert res.last_block_app_hash == b'3' + + # it's always the latest migration that is taken into account + b.store_abci_chain(4, 'chain-XYZ-new') + app = App(a, b) + b.store_block(Block(app_hash='4', height=4, transactions=[])._asdict()) + res = app.info(r) + assert res.last_block_height == 0 + assert res.last_block_app_hash == b'4' + + +def test_check_tx__signed_create_is_ok(a, b): + from planetmint import App + from planetmint.models import Transaction + from planetmint.common.crypto import generate_key_pair + + alice = generate_key_pair() + bob = generate_key_pair() + + tx = Transaction.create([alice.public_key], + [([bob.public_key], 1)])\ + .sign([alice.private_key]) + + app = App(a, b) + result = app.check_tx(encode_tx_to_bytes(tx)) + assert result.code == CodeTypeOk + + +def test_check_tx__unsigned_create_is_error(a, b): + from planetmint import App + from planetmint.models import Transaction + from planetmint.common.crypto import generate_key_pair + + alice = generate_key_pair() + bob = generate_key_pair() + + tx = Transaction.create([alice.public_key], + [([bob.public_key], 1)]) + + app = App(a, b) + result = app.check_tx(encode_tx_to_bytes(tx)) + assert result.code == CodeTypeError + + +def test_deliver_tx__valid_create_updates_db_and_emits_event(a, b, init_chain_request): + import multiprocessing as mp + from planetmint import App + from planetmint.models import Transaction + from planetmint.common.crypto import generate_key_pair + + alice = generate_key_pair() + bob = generate_key_pair() + events = mp.Queue() + + tx = Transaction.create([alice.public_key], + [([bob.public_key], 1)])\ + .sign([alice.private_key]) + + app = App(a, b, events) + + app.init_chain(init_chain_request) + + begin_block = types.RequestBeginBlock() + app.begin_block(begin_block) + + result = app.deliver_tx(encode_tx_to_bytes(tx)) + assert result.code == CodeTypeOk + + app.end_block(types.RequestEndBlock(height=99)) + app.commit() + assert b.get_transaction(tx.id).id == tx.id + block_event = events.get() + assert block_event.data['transactions'] == [tx] + + # unspent_outputs = b.get_unspent_outputs() + # unspent_output = next(unspent_outputs) + # expected_unspent_output = next(tx.unspent_outputs)._asdict() + # assert unspent_output == expected_unspent_output + # with pytest.raises(StopIteration): + # next(unspent_outputs) + + +def test_deliver_tx__double_spend_fails(a, b, init_chain_request): + from planetmint import App + from planetmint.models import Transaction + from planetmint.common.crypto import generate_key_pair + + alice = generate_key_pair() + bob = generate_key_pair() + + tx = Transaction.create([alice.public_key], + [([bob.public_key], 1)])\ + .sign([alice.private_key]) + + app = App(a, b) + app.init_chain(init_chain_request) + + begin_block = types.RequestBeginBlock() + app.begin_block(begin_block) + + result = app.deliver_tx(encode_tx_to_bytes(tx)) + assert result.code == CodeTypeOk + + app.end_block(types.RequestEndBlock(height=99)) + app.commit() + + assert b.get_transaction(tx.id).id == tx.id + result = app.deliver_tx(encode_tx_to_bytes(tx)) + assert result.code == CodeTypeError + + +def test_deliver_transfer_tx__double_spend_fails(a, b, init_chain_request): + from planetmint import App + from planetmint.models import Transaction + from planetmint.common.crypto import generate_key_pair + + app = App(a, b) + app.init_chain(init_chain_request) + + begin_block = types.RequestBeginBlock() + app.begin_block(begin_block) + + alice = generate_key_pair() + bob = generate_key_pair() + carly = generate_key_pair() + + asset = { + 'msg': 'live long and prosper' + } + + tx = Transaction.create([alice.public_key], + [([alice.public_key], 1)], + asset=asset)\ + .sign([alice.private_key]) + + result = app.deliver_tx(encode_tx_to_bytes(tx)) + assert result.code == CodeTypeOk + + tx_transfer = Transaction.transfer(tx.to_inputs(), + [([bob.public_key], 1)], + asset_id=tx.id)\ + .sign([alice.private_key]) + + result = app.deliver_tx(encode_tx_to_bytes(tx_transfer)) + assert result.code == CodeTypeOk + + double_spend = Transaction.transfer(tx.to_inputs(), + [([carly.public_key], 1)], + asset_id=tx.id)\ + .sign([alice.private_key]) + + result = app.deliver_tx(encode_tx_to_bytes(double_spend)) + assert result.code == CodeTypeError + + +def test_end_block_return_validator_updates(a, b, init_chain_request): + app = App(a, b) + app.init_chain(init_chain_request) + + begin_block = types.RequestBeginBlock() + app.begin_block(begin_block) + + # generate a block containing a concluded validator election + validators = generate_validators([1] * 4) + b.store_validator_set(1, [v['storage'] for v in validators]) + + new_validator = generate_validators([1])[0] + + public_key = validators[0]['public_key'] + private_key = validators[0]['private_key'] + voter_keys = [v['private_key'] for v in validators] + + election, votes = generate_election(b, + ValidatorElection, + public_key, private_key, + new_validator['election'], + voter_keys) + b.store_block(Block(height=1, transactions=[election.id], + app_hash='')._asdict()) + b.store_bulk_transactions([election]) + Election.process_block(b, 1, [election]) + + app.block_transactions = votes + + resp = app.end_block(types.RequestEndBlock(height=2)) + assert resp.validator_updates[0].power == new_validator['election']['power'] + expected = bytes.fromhex(new_validator['election']['public_key']['value']) + assert expected == resp.validator_updates[0].pub_key.data + + +def test_store_pre_commit_state_in_end_block(a, b, alice, init_chain_request): + from planetmint import App + from planetmint.backend import query from planetmint.models import Transaction - tx_1 = Transaction.create( - [carol.public_key], - [([carol.public_key], 8)], - ).sign([carol.private_key]) - assert tx_1.validate(b) - b.store_bulk_transactions([tx_1]) + tx = Transaction.create([alice.public_key], + [([alice.public_key], 1)], + asset={'msg': 'live long and prosper'})\ + .sign([alice.private_key]) - tx_2 = Transaction.transfer( - tx_1.to_inputs(), - [([bob.public_key], 2), - ([alice.public_key], 2), - ([carol.public_key], 4)], - asset_id=tx_1.id, - ).sign([carol.private_key]) - assert tx_2.validate(b) - b.store_bulk_transactions([tx_2]) + app = App(a, b) + app.init_chain(init_chain_request) - tx_3 = Transaction.transfer( - tx_2.to_inputs()[2:3], - [([alice.public_key], 1), - ([carol.public_key], 3)], - asset_id=tx_1.id, - ).sign([carol.private_key]) - assert tx_3.validate(b) - b.store_bulk_transactions([tx_3]) + begin_block = types.RequestBeginBlock() + app.begin_block(begin_block) + app.deliver_tx(encode_tx_to_bytes(tx)) + app.end_block(types.RequestEndBlock(height=99)) - tx_4 = Transaction.transfer( - tx_2.to_inputs()[1:2] + tx_3.to_inputs()[0:1], - [([bob.public_key], 3)], - asset_id=tx_1.id, - ).sign([alice.private_key]) - assert tx_4.validate(b) - b.store_bulk_transactions([tx_4]) + resp = query.get_pre_commit_state(b.connection) + assert resp['height'] == 99 + assert resp['transactions'] == [tx.id] - tx_5 = Transaction.transfer( - tx_2.to_inputs()[0:1], - [([alice.public_key], 2)], - asset_id=tx_1.id, - ).sign([bob.private_key]) - assert tx_5.validate(b) + app.begin_block(begin_block) + app.deliver_tx(encode_tx_to_bytes(tx)) + app.end_block(types.RequestEndBlock(height=100)) + resp = query.get_pre_commit_state(b.connection) + assert resp['height'] == 100 + assert resp['transactions'] == [tx.id] - b.store_bulk_transactions([tx_5]) + # simulate a chain migration and assert the height is shifted + b.store_abci_chain(100, 'new-chain') + app = App(a, b) + app.begin_block(begin_block) + app.deliver_tx(encode_tx_to_bytes(tx)) + app.end_block(types.RequestEndBlock(height=1)) + resp = query.get_pre_commit_state(b.connection) + assert resp['height'] == 101 + assert resp['transactions'] == [tx.id] - assert b.get_spent(tx_2.id, 0) == tx_5 - assert not b.get_spent(tx_5.id, 0) - assert b.get_outputs_filtered(alice.public_key) - assert b.get_outputs_filtered(alice.public_key, spent=False) + +def test_rollback_pre_commit_state_after_crash(b): + validators = generate_validators([1] * 4) + b.store_validator_set(1, [v['storage'] for v in validators]) + b.store_block(Block(height=1, transactions=[], app_hash='')._asdict()) + + public_key = validators[0]['public_key'] + private_key = validators[0]['private_key'] + voter_keys = [v['private_key'] for v in validators] + + migration_election, votes = generate_election(b, + ChainMigrationElection, + public_key, private_key, + {}, + voter_keys) + + total_votes = votes + txs = [migration_election, *votes] + + new_validator = generate_validators([1])[0] + validator_election, votes = generate_election(b, + ValidatorElection, + public_key, private_key, + new_validator['election'], + voter_keys) + + total_votes += votes + txs += [validator_election, *votes] + + b.store_bulk_transactions(txs) + b.store_abci_chain(2, 'new_chain') + b.store_validator_set(2, [v['storage'] for v in validators]) + # TODO change to `4` when upgrading to Tendermint 0.22.4. + b.store_validator_set(3, [new_validator['storage']]) + b.store_election(migration_election.id, 2, is_concluded=False) + b.store_election(validator_election.id, 2, is_concluded=True) + + # no pre-commit state + rollback(b) + + for tx in txs: + assert b.get_transaction(tx.id) + assert b.get_latest_abci_chain() + assert len(b.get_validator_change()['validators']) == 1 + assert b.get_election(migration_election.id) + assert b.get_election(validator_election.id) + + b.store_pre_commit_state({'height': 2, 'transactions': [tx.id for tx in txs]}) + + rollback(b) + + for tx in txs: + assert not b.get_transaction(tx.id) + assert not b.get_latest_abci_chain() + assert len(b.get_validator_change()['validators']) == 4 + assert len(b.get_validator_change(2)['validators']) == 4 + assert not b.get_election(migration_election.id) + assert not b.get_election(validator_election.id) + + +def test_new_validator_set(b): + node1 = {'public_key': {'type': 'ed25519-base64', + 'value': 'FxjS2/8AFYoIUqF6AcePTc87qOT7e4WGgH+sGCpTUDQ='}, + 'voting_power': 10} + node1_new_power = {'public_key': {'value': '1718D2DBFF00158A0852A17A01C78F4DCF3BA8E4FB7B8586807FAC182A535034', + 'type': 'ed25519-base16'}, + 'power': 20} + node2 = {'public_key': {'value': '1888A353B181715CA2554701D06C1665BC42C5D936C55EA9C5DBCBDB8B3F02A3', + 'type': 'ed25519-base16'}, + 'power': 10} + + validators = [node1] + updates = [node1_new_power, node2] + b.store_validator_set(1, validators) + updated_validator_set = new_validator_set(b.get_validators(1), updates) + + updated_validators = [] + for u in updates: + updated_validators.append({'public_key': {'type': 'ed25519-base64', + 'value': public_key_to_base64(u['public_key']['value'])}, + 'voting_power': u['power']}) + + assert updated_validator_set == updated_validators + + +def test_info_aborts_if_chain_is_not_synced(a, b): + b.store_abci_chain(0, 'chain-XYZ', False) + + with pytest.raises(SystemExit): + App(a, b).info(types.RequestInfo()) + + +def test_check_tx_aborts_if_chain_is_not_synced(a, b): + b.store_abci_chain(0, 'chain-XYZ', False) + + with pytest.raises(SystemExit): + App(a, b).check_tx('some bytes') + + +def test_begin_aborts_if_chain_is_not_synced(a, b): + b.store_abci_chain(0, 'chain-XYZ', False) + + with pytest.raises(SystemExit): + App(a, b).info(types.RequestBeginBlock()) + + +def test_deliver_tx_aborts_if_chain_is_not_synced(a, b): + b.store_abci_chain(0, 'chain-XYZ', False) + + with pytest.raises(SystemExit): + App(a, b).deliver_tx('some bytes') + + +def test_end_block_aborts_if_chain_is_not_synced(a, b): + b.store_abci_chain(0, 'chain-XYZ', False) + + with pytest.raises(SystemExit): + App(a, b).info(types.RequestEndBlock()) + + +def test_commit_aborts_if_chain_is_not_synced(a, b): + b.store_abci_chain(0, 'chain-XYZ', False) + + with pytest.raises(SystemExit): + App(a, b).commit() \ No newline at end of file From d79f92c8c99fa50c991947c664df19463e78e065 Mon Sep 17 00:00:00 2001 From: ArpitShukla007 Date: Wed, 2 Feb 2022 08:47:28 +0000 Subject: [PATCH 06/93] PubKey issue resolved --- tests/tendermint/test_core.py | 3 ++- tests/upsert_validator/test_upsert_validator_vote.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/tendermint/test_core.py b/tests/tendermint/test_core.py index 55aaf39..4712791 100644 --- a/tests/tendermint/test_core.py +++ b/tests/tendermint/test_core.py @@ -8,6 +8,7 @@ import pytest import random from tendermint.abci import types_pb2 as types +from tendermint.crypto import keys_pb2 from planetmint import App from planetmint.backend.localmongodb import query @@ -40,7 +41,7 @@ def generate_address(): def generate_validator(): pk, _ = generate_key_pair() - pub_key = types.PubKey(type='ed25519', data=pk.encode()) + pub_key = keys_pb2.PublicKey(ed25519=pk.encode()) val = types.ValidatorUpdate(power=10, pub_key=pub_key) return val diff --git a/tests/upsert_validator/test_upsert_validator_vote.py b/tests/upsert_validator/test_upsert_validator_vote.py index d2b950c..5fb4fe0 100644 --- a/tests/upsert_validator/test_upsert_validator_vote.py +++ b/tests/upsert_validator/test_upsert_validator_vote.py @@ -296,7 +296,7 @@ def test_get_validator_update(b, node_keys, node_key, ed25519_node_keys): update = Election.process_block(b, 4, [tx_vote0, tx_vote1, tx_vote2]) assert len(update) == 1 - update_public_key = codecs.encode(update[0].pub_key.data, 'base64').decode().rstrip('\n') + update_public_key = codecs.encode(update[0].pub_key.ed25519, 'base64').decode().rstrip('\n') assert update_public_key == public_key64 # remove validator @@ -319,7 +319,7 @@ def test_get_validator_update(b, node_keys, node_key, ed25519_node_keys): update = Election.process_block(b, 9, [tx_vote2]) assert len(update) == 1 - update_public_key = codecs.encode(update[0].pub_key.data, 'base64').decode().rstrip('\n') + update_public_key = codecs.encode(update[0].pub_key.ed25519, 'base64').decode().rstrip('\n') assert update_public_key == public_key64 # assert that the public key is not a part of the current validator set From b9c96f402964c5750678a33ad4b40ed9e6fd44b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Wed, 2 Feb 2022 11:55:01 +0100 Subject: [PATCH 07/93] added fixes for the most important issues --- planetmint/core.py | 6 +-- planetmint/parallel_validation.py | 3 +- planetmint/start.py | 2 - .../upsert_validator/validator_utils.py | 20 ++------ planetmint/web/server.py | 3 +- tests/elections/test_election.py | 2 +- tests/tendermint/test_core.py | 46 +++++++++---------- tests/tendermint/test_integration.py | 4 +- tests/test_core.py | 46 +++++++++---------- 9 files changed, 57 insertions(+), 75 deletions(-) diff --git a/planetmint/core.py b/planetmint/core.py index 65d6a10..4369e5d 100644 --- a/planetmint/core.py +++ b/planetmint/core.py @@ -9,7 +9,7 @@ with Tendermint. import logging import sys import enum -from tendermint.abci import types_pb2 +from tendermint.abci import types_pb2 from abci.application import BaseApplication from abci.application import OkCode from tendermint.abci.types_pb2 import ( @@ -50,10 +50,6 @@ from planetmint.events import EventTypes, Event CodeTypeError = 1 logger = logging.getLogger(__name__) -class TmVersion(enum.Enum): - """Supported Tendermint versions enum""" - v0_34_11 = 'v0.34.11' - class App(BaseApplication): """Bridge between Planetmint and Tendermint. diff --git a/planetmint/parallel_validation.py b/planetmint/parallel_validation.py index 040a758..239f4d8 100644 --- a/planetmint/parallel_validation.py +++ b/planetmint/parallel_validation.py @@ -6,7 +6,8 @@ import multiprocessing as mp from collections import defaultdict -from planetmint import App, Planetmint +from planetmint import App +from planetmint.lib import Planetmint from planetmint.tendermint_utils import decode_transaction from abci.application import OkCode from tendermint.abci.types_pb2 import ( diff --git a/planetmint/start.py b/planetmint/start.py index e511d1b..018ff2c 100644 --- a/planetmint/start.py +++ b/planetmint/start.py @@ -6,8 +6,6 @@ import logging import setproctitle -#from abci import TmVersion, ABCI - import planetmint from planetmint.lib import Planetmint from planetmint.core import App diff --git a/planetmint/upsert_validator/validator_utils.py b/planetmint/upsert_validator/validator_utils.py index 1485920..1fc0e5a 100644 --- a/planetmint/upsert_validator/validator_utils.py +++ b/planetmint/upsert_validator/validator_utils.py @@ -4,29 +4,15 @@ import codecs import enum import planetmint -from tendermint.abci import types_pb2 as types_v0_34_11 +from tendermint.abci import types_pb2 from tendermint.crypto import keys_pb2 from planetmint.common.exceptions import InvalidPublicKey, BigchainDBError -class TmVersion(enum.Enum): - """Supported Tendermint versions enum""" - v0_34_11 = 'v0.34.11' - def encode_validator(v): ed25519_public_key = v['public_key']['value'] - # NOTE: tendermint expects public to be encoded in go-amino format - try: - version = TmVersion(planetmint.config["tendermint"]["version"]) - except ValueError: - raise BigchainDBError('Invalid tendermint version, ' - 'check Planetmint configuration file') + pub_key = keys_pb2.PublicKey(ed25519=bytes.fromhex(ed25519_public_key)) - validator_update_t, pubkey_t = { - TmVersion.v0_34_11: (types_v0_34_11.ValidatorUpdate, keys_pb2.PublicKey) - }[version] - pub_key = pubkey_t(ed25519=bytes.fromhex(ed25519_public_key)) - - return validator_update_t(pub_key=pub_key, power=v['power']) + return types_pb2.ValidatorUpdate(pub_key=pub_key, power=v['power']) def decode_validator(v): diff --git a/planetmint/web/server.py b/planetmint/web/server.py index e0c4519..1710efe 100644 --- a/planetmint/web/server.py +++ b/planetmint/web/server.py @@ -16,7 +16,8 @@ from flask_cors import CORS import gunicorn.app.base from planetmint import utils -from planetmint import Planetmint +#from planetmint import Planetmint +from planetmint.lib import Planetmint from planetmint.web.routes import add_routes from planetmint.web.strip_content_type_middleware import StripContentTypeMiddleware diff --git a/tests/elections/test_election.py b/tests/elections/test_election.py index 3e51c9a..10c95a2 100644 --- a/tests/elections/test_election.py +++ b/tests/elections/test_election.py @@ -6,7 +6,7 @@ from planetmint.lib import Block from planetmint.elections.election import Election from planetmint.migrations.chain_migration_election import ChainMigrationElection from planetmint.upsert_validator.validator_election import ValidatorElection -from planetmint.core import TmVersion + @pytest.mark.bdb def test_process_block_concludes_all_elections(b): diff --git a/tests/tendermint/test_core.py b/tests/tendermint/test_core.py index 4712791..70a64af 100644 --- a/tests/tendermint/test_core.py +++ b/tests/tendermint/test_core.py @@ -53,7 +53,7 @@ def generate_init_chain_request(chain_id, vals=None): def test_init_chain_successfully_registers_chain(a, b): request = generate_init_chain_request('chain-XYZ') - res = App(a, b).init_chain(request) + res = App(b, a).init_chain(request) assert res == types.ResponseInitChain() chain = query.get_latest_abci_chain(b.connection) assert chain == {'height': 0, 'chain_id': 'chain-XYZ', 'is_synced': True} @@ -67,7 +67,7 @@ def test_init_chain_successfully_registers_chain(a, b): def test_init_chain_ignores_invalid_init_chain_requests(a, b): validators = [generate_validator()] request = generate_init_chain_request('chain-XYZ', validators) - res = App(a, b).init_chain(request) + res = App(b, a).init_chain(request) assert res == types.ResponseInitChain() validator_set = query.get_validator_set(b.connection) @@ -81,7 +81,7 @@ def test_init_chain_ignores_invalid_init_chain_requests(a, b): ] for r in invalid_requests: with pytest.raises(SystemExit): - App(a, b).init_chain(r) + App(b, a).init_chain(r) # assert nothing changed - neither validator set, nor chain ID new_validator_set = query.get_validator_set(b.connection) assert new_validator_set == validator_set @@ -97,7 +97,7 @@ def test_init_chain_ignores_invalid_init_chain_requests(a, b): def test_init_chain_recognizes_new_chain_after_migration(a, b): validators = [generate_validator()] request = generate_init_chain_request('chain-XYZ', validators) - res = App(a, b).init_chain(request) + res = App(b, a).init_chain(request) assert res == types.ResponseInitChain() validator_set = query.get_validator_set(b.connection)['validators'] @@ -116,7 +116,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): ] for r in invalid_requests: with pytest.raises(SystemExit): - App(a, b).init_chain(r) + App(b, a).init_chain(r) assert query.get_latest_abci_chain(b.connection) == { 'chain_id': 'chain-XYZ-migrated-at-height-1', 'is_synced': False, @@ -129,7 +129,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): # completes the migration request = generate_init_chain_request('chain-XYZ-migrated-at-height-1', validators) - res = App(a, b).init_chain(request) + res = App(b, a).init_chain(request) assert res == types.ResponseInitChain() assert query.get_latest_abci_chain(b.connection) == { 'chain_id': 'chain-XYZ-migrated-at-height-1', @@ -150,7 +150,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): ] for r in invalid_requests: with pytest.raises(SystemExit): - App(a, b).init_chain(r) + App(b, a).init_chain(r) assert query.get_latest_abci_chain(b.connection) == { 'chain_id': 'chain-XYZ-migrated-at-height-1', 'is_synced': True, @@ -167,7 +167,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): def test_info(a, b): r = types.RequestInfo(version=__tm_supported_versions__[0]) - app = App(a, b) + app = App(b, a) res = app.info(r) assert res.last_block_height == 0 @@ -180,7 +180,7 @@ def test_info(a, b): # simulate a migration and assert the height is shifted b.store_abci_chain(2, 'chain-XYZ') - app = App(a, b) + app = App(b, a) b.store_block(Block(app_hash='2', height=2, transactions=[])._asdict()) res = app.info(r) assert res.last_block_height == 0 @@ -193,7 +193,7 @@ def test_info(a, b): # it's always the latest migration that is taken into account b.store_abci_chain(4, 'chain-XYZ-new') - app = App(a, b) + app = App(b, a) b.store_block(Block(app_hash='4', height=4, transactions=[])._asdict()) res = app.info(r) assert res.last_block_height == 0 @@ -212,7 +212,7 @@ def test_check_tx__signed_create_is_ok(a, b): [([bob.public_key], 1)])\ .sign([alice.private_key]) - app = App(a, b) + app = App(b, a) result = app.check_tx(encode_tx_to_bytes(tx)) assert result.code == OkCode @@ -228,7 +228,7 @@ def test_check_tx__unsigned_create_is_error(a, b): tx = Transaction.create([alice.public_key], [([bob.public_key], 1)]) - app = App(a, b) + app = App(b, a) result = app.check_tx(encode_tx_to_bytes(tx)) assert result.code == CodeTypeError @@ -283,7 +283,7 @@ def test_deliver_tx__double_spend_fails(a, b, init_chain_request): [([bob.public_key], 1)])\ .sign([alice.private_key]) - app = App(a, b) + app = App(b, a) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -305,7 +305,7 @@ def test_deliver_transfer_tx__double_spend_fails(a, b, init_chain_request): from planetmint.models import Transaction from planetmint.common.crypto import generate_key_pair - app = App(a, b) + app = App(b, a) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -345,7 +345,7 @@ def test_deliver_transfer_tx__double_spend_fails(a, b, init_chain_request): def test_end_block_return_validator_updates(a, b, init_chain_request): - app = App(a, b) + app = App(b, a) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -389,7 +389,7 @@ def test_store_pre_commit_state_in_end_block(a, b, alice, init_chain_request): asset={'msg': 'live long and prosper'})\ .sign([alice.private_key]) - app = App(a, b) + app = App(b, a) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -410,7 +410,7 @@ def test_store_pre_commit_state_in_end_block(a, b, alice, init_chain_request): # simulate a chain migration and assert the height is shifted b.store_abci_chain(100, 'new-chain') - app = App(a, b) + app = App(b, a) app.begin_block(begin_block) app.deliver_tx(encode_tx_to_bytes(tx)) app.end_block(types.RequestEndBlock(height=1)) @@ -507,39 +507,39 @@ def test_info_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).info(types.RequestInfo()) + App(b, a).info(types.RequestInfo()) def test_check_tx_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).check_tx('some bytes') + App(b, a).check_tx('some bytes') def test_begin_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).info(types.RequestBeginBlock()) + App(b, a).info(types.RequestBeginBlock()) def test_deliver_tx_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).deliver_tx('some bytes') + App(b, a).deliver_tx('some bytes') def test_end_block_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).info(types.RequestEndBlock()) + App(b, a).info(types.RequestEndBlock()) def test_commit_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).commit() + App(b, a).commit() diff --git a/tests/tendermint/test_integration.py b/tests/tendermint/test_integration.py index 17f96df..78511d7 100644 --- a/tests/tendermint/test_integration.py +++ b/tests/tendermint/test_integration.py @@ -25,7 +25,7 @@ def test_app(a, b, init_chain_request): from planetmint.common.crypto import generate_key_pair from planetmint.models import Transaction - app = App(a, b) + app = App(b, a) p = ProtocolHandler(app) data = p.process('info', @@ -150,7 +150,7 @@ def test_post_transaction_responses(tendermint_ws_url, b): def test_exit_when_tm_ver_not_supported(a, b): from planetmint import App - app = App(a, b) + app = App(b, a) p = ProtocolHandler(app) with pytest.raises(SystemExit): diff --git a/tests/test_core.py b/tests/test_core.py index 4cfa779..8e3bf24 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -53,7 +53,7 @@ def generate_init_chain_request(chain_id, vals=None): def test_init_chain_successfully_registers_chain(a, b): request = generate_init_chain_request('chain-XYZ') - res = App(a, b).init_chain(request) + res = App(b, a).init_chain(request) assert res == types.ResponseInitChain() chain = query.get_latest_abci_chain(b.connection) assert chain == {'height': 0, 'chain_id': 'chain-XYZ', 'is_synced': True} @@ -67,7 +67,7 @@ def test_init_chain_successfully_registers_chain(a, b): def test_init_chain_ignores_invalid_init_chain_requests(a, b): validators = [generate_validator()] request = generate_init_chain_request('chain-XYZ', validators) - res = App(a, b).init_chain(request) + res = App(b, a).init_chain(request) assert res == types.ResponseInitChain() validator_set = query.get_validator_set(b.connection) @@ -81,7 +81,7 @@ def test_init_chain_ignores_invalid_init_chain_requests(a, b): ] for r in invalid_requests: with pytest.raises(SystemExit): - App(a, b).init_chain(r) + App(b, a).init_chain(r) # assert nothing changed - neither validator set, nor chain ID new_validator_set = query.get_validator_set(b.connection) assert new_validator_set == validator_set @@ -97,7 +97,7 @@ def test_init_chain_ignores_invalid_init_chain_requests(a, b): def test_init_chain_recognizes_new_chain_after_migration(a, b): validators = [generate_validator()] request = generate_init_chain_request('chain-XYZ', validators) - res = App(a, b).init_chain(request) + res = App(b, a).init_chain(request) assert res == types.ResponseInitChain() validator_set = query.get_validator_set(b.connection)['validators'] @@ -116,7 +116,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): ] for r in invalid_requests: with pytest.raises(SystemExit): - App(a, b).init_chain(r) + App(b, a).init_chain(r) assert query.get_latest_abci_chain(b.connection) == { 'chain_id': 'chain-XYZ-migrated-at-height-1', 'is_synced': False, @@ -129,7 +129,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): # completes the migration request = generate_init_chain_request('chain-XYZ-migrated-at-height-1', validators) - res = App(a, b).init_chain(request) + res = App(b, a).init_chain(request) assert res == types.ResponseInitChain() assert query.get_latest_abci_chain(b.connection) == { 'chain_id': 'chain-XYZ-migrated-at-height-1', @@ -150,7 +150,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): ] for r in invalid_requests: with pytest.raises(SystemExit): - App(a, b).init_chain(r) + App(b, a).init_chain(r) assert query.get_latest_abci_chain(b.connection) == { 'chain_id': 'chain-XYZ-migrated-at-height-1', 'is_synced': True, @@ -167,7 +167,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): def test_info(a, b): r = types.RequestInfo(version=__tm_supported_versions__[0]) - app = App(a, b) + app = App(b, a) res = app.info(r) assert res.last_block_height == 0 @@ -180,7 +180,7 @@ def test_info(a, b): # simulate a migration and assert the height is shifted b.store_abci_chain(2, 'chain-XYZ') - app = App(a, b) + app = App(b, a) b.store_block(Block(app_hash='2', height=2, transactions=[])._asdict()) res = app.info(r) assert res.last_block_height == 0 @@ -193,7 +193,7 @@ def test_info(a, b): # it's always the latest migration that is taken into account b.store_abci_chain(4, 'chain-XYZ-new') - app = App(a, b) + app = App(b, a) b.store_block(Block(app_hash='4', height=4, transactions=[])._asdict()) res = app.info(r) assert res.last_block_height == 0 @@ -212,7 +212,7 @@ def test_check_tx__signed_create_is_ok(a, b): [([bob.public_key], 1)])\ .sign([alice.private_key]) - app = App(a, b) + app = App(b, a) result = app.check_tx(encode_tx_to_bytes(tx)) assert result.code == CodeTypeOk @@ -228,7 +228,7 @@ def test_check_tx__unsigned_create_is_error(a, b): tx = Transaction.create([alice.public_key], [([bob.public_key], 1)]) - app = App(a, b) + app = App(b, a) result = app.check_tx(encode_tx_to_bytes(tx)) assert result.code == CodeTypeError @@ -283,7 +283,7 @@ def test_deliver_tx__double_spend_fails(a, b, init_chain_request): [([bob.public_key], 1)])\ .sign([alice.private_key]) - app = App(a, b) + app = App(b, a) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -305,7 +305,7 @@ def test_deliver_transfer_tx__double_spend_fails(a, b, init_chain_request): from planetmint.models import Transaction from planetmint.common.crypto import generate_key_pair - app = App(a, b) + app = App(b, a) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -345,7 +345,7 @@ def test_deliver_transfer_tx__double_spend_fails(a, b, init_chain_request): def test_end_block_return_validator_updates(a, b, init_chain_request): - app = App(a, b) + app = App(b, a) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -389,7 +389,7 @@ def test_store_pre_commit_state_in_end_block(a, b, alice, init_chain_request): asset={'msg': 'live long and prosper'})\ .sign([alice.private_key]) - app = App(a, b) + app = App(b, a) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -410,7 +410,7 @@ def test_store_pre_commit_state_in_end_block(a, b, alice, init_chain_request): # simulate a chain migration and assert the height is shifted b.store_abci_chain(100, 'new-chain') - app = App(a, b) + app = App(b, a) app.begin_block(begin_block) app.deliver_tx(encode_tx_to_bytes(tx)) app.end_block(types.RequestEndBlock(height=1)) @@ -507,39 +507,39 @@ def test_info_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).info(types.RequestInfo()) + App(b, a).info(types.RequestInfo()) def test_check_tx_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).check_tx('some bytes') + App(b, a).check_tx('some bytes') def test_begin_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).info(types.RequestBeginBlock()) + App(b, a).info(types.RequestBeginBlock()) def test_deliver_tx_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).deliver_tx('some bytes') + App(b, a).deliver_tx('some bytes') def test_end_block_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).info(types.RequestEndBlock()) + App(b, a).info(types.RequestEndBlock()) def test_commit_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).commit() \ No newline at end of file + App(b, a).commit() \ No newline at end of file From 337b08047d9e54269535aa69995a9e2f5dd4b0a8 Mon Sep 17 00:00:00 2001 From: ArpitShukla007 Date: Wed, 2 Feb 2022 16:33:50 +0000 Subject: [PATCH 08/93] solved get_latest_abci_chain attribute error --- planetmint/core.py | 8 +-- planetmint/parallel_validation.py | 3 +- planetmint/start.py | 1 - .../upsert_validator/validator_utils.py | 20 +------ planetmint/web/server.py | 2 +- tests/elections/test_election.py | 1 - tests/tendermint/test_core.py | 46 +++++++-------- tests/tendermint/test_integration.py | 4 +- tests/test_core.py | 56 +++++++++---------- 9 files changed, 61 insertions(+), 80 deletions(-) diff --git a/planetmint/core.py b/planetmint/core.py index 65d6a10..9fa5321 100644 --- a/planetmint/core.py +++ b/planetmint/core.py @@ -50,10 +50,6 @@ from planetmint.events import EventTypes, Event CodeTypeError = 1 logger = logging.getLogger(__name__) -class TmVersion(enum.Enum): - """Supported Tendermint versions enum""" - v0_34_11 = 'v0.34.11' - class App(BaseApplication): """Bridge between Planetmint and Tendermint. @@ -171,7 +167,7 @@ class App(BaseApplication): transaction = decode_transaction(raw_transaction) if self.planetmint_node.is_valid_transaction(transaction): logger.debug('check_tx: VALID') - return ResponseCheckTx(code=CodeTypeOk) + return ResponseCheckTx(code=OkCode) else: logger.debug('check_tx: INVALID') return ResponseCheckTx(code=CodeTypeError) @@ -213,7 +209,7 @@ class App(BaseApplication): logger.debug('storing tx') self.block_txn_ids.append(transaction.id) self.block_transactions.append(transaction) - return ResponseDeliverTx(code=CodeTypeOk) + return ResponseDeliverTx(code=OkCode) def end_block(self, request_end_block): """Calculate block hash using transaction ids and previous block diff --git a/planetmint/parallel_validation.py b/planetmint/parallel_validation.py index 040a758..239f4d8 100644 --- a/planetmint/parallel_validation.py +++ b/planetmint/parallel_validation.py @@ -6,7 +6,8 @@ import multiprocessing as mp from collections import defaultdict -from planetmint import App, Planetmint +from planetmint import App +from planetmint.lib import Planetmint from planetmint.tendermint_utils import decode_transaction from abci.application import OkCode from tendermint.abci.types_pb2 import ( diff --git a/planetmint/start.py b/planetmint/start.py index e511d1b..51a7eb5 100644 --- a/planetmint/start.py +++ b/planetmint/start.py @@ -6,7 +6,6 @@ import logging import setproctitle -#from abci import TmVersion, ABCI import planetmint from planetmint.lib import Planetmint diff --git a/planetmint/upsert_validator/validator_utils.py b/planetmint/upsert_validator/validator_utils.py index 1485920..a8bcfb8 100644 --- a/planetmint/upsert_validator/validator_utils.py +++ b/planetmint/upsert_validator/validator_utils.py @@ -4,29 +4,15 @@ import codecs import enum import planetmint -from tendermint.abci import types_pb2 as types_v0_34_11 +from tendermint.abci import types_pb2 from tendermint.crypto import keys_pb2 from planetmint.common.exceptions import InvalidPublicKey, BigchainDBError -class TmVersion(enum.Enum): - """Supported Tendermint versions enum""" - v0_34_11 = 'v0.34.11' - def encode_validator(v): ed25519_public_key = v['public_key']['value'] - # NOTE: tendermint expects public to be encoded in go-amino format - try: - version = TmVersion(planetmint.config["tendermint"]["version"]) - except ValueError: - raise BigchainDBError('Invalid tendermint version, ' - 'check Planetmint configuration file') + pub_key = keys_pb2.PublicKey(ed25519=bytes.fromhex(ed25519_public_key)) - validator_update_t, pubkey_t = { - TmVersion.v0_34_11: (types_v0_34_11.ValidatorUpdate, keys_pb2.PublicKey) - }[version] - pub_key = pubkey_t(ed25519=bytes.fromhex(ed25519_public_key)) - - return validator_update_t(pub_key=pub_key, power=v['power']) + return types_pb2.ValidatorUpdate(pub_key=pub_key, power=v['power']) def decode_validator(v): diff --git a/planetmint/web/server.py b/planetmint/web/server.py index e0c4519..456e4e7 100644 --- a/planetmint/web/server.py +++ b/planetmint/web/server.py @@ -16,7 +16,7 @@ from flask_cors import CORS import gunicorn.app.base from planetmint import utils -from planetmint import Planetmint +from planetmint.lib import Planetmint from planetmint.web.routes import add_routes from planetmint.web.strip_content_type_middleware import StripContentTypeMiddleware diff --git a/tests/elections/test_election.py b/tests/elections/test_election.py index 3e51c9a..af0e08a 100644 --- a/tests/elections/test_election.py +++ b/tests/elections/test_election.py @@ -6,7 +6,6 @@ from planetmint.lib import Block from planetmint.elections.election import Election from planetmint.migrations.chain_migration_election import ChainMigrationElection from planetmint.upsert_validator.validator_election import ValidatorElection -from planetmint.core import TmVersion @pytest.mark.bdb def test_process_block_concludes_all_elections(b): diff --git a/tests/tendermint/test_core.py b/tests/tendermint/test_core.py index 4712791..70a64af 100644 --- a/tests/tendermint/test_core.py +++ b/tests/tendermint/test_core.py @@ -53,7 +53,7 @@ def generate_init_chain_request(chain_id, vals=None): def test_init_chain_successfully_registers_chain(a, b): request = generate_init_chain_request('chain-XYZ') - res = App(a, b).init_chain(request) + res = App(b, a).init_chain(request) assert res == types.ResponseInitChain() chain = query.get_latest_abci_chain(b.connection) assert chain == {'height': 0, 'chain_id': 'chain-XYZ', 'is_synced': True} @@ -67,7 +67,7 @@ def test_init_chain_successfully_registers_chain(a, b): def test_init_chain_ignores_invalid_init_chain_requests(a, b): validators = [generate_validator()] request = generate_init_chain_request('chain-XYZ', validators) - res = App(a, b).init_chain(request) + res = App(b, a).init_chain(request) assert res == types.ResponseInitChain() validator_set = query.get_validator_set(b.connection) @@ -81,7 +81,7 @@ def test_init_chain_ignores_invalid_init_chain_requests(a, b): ] for r in invalid_requests: with pytest.raises(SystemExit): - App(a, b).init_chain(r) + App(b, a).init_chain(r) # assert nothing changed - neither validator set, nor chain ID new_validator_set = query.get_validator_set(b.connection) assert new_validator_set == validator_set @@ -97,7 +97,7 @@ def test_init_chain_ignores_invalid_init_chain_requests(a, b): def test_init_chain_recognizes_new_chain_after_migration(a, b): validators = [generate_validator()] request = generate_init_chain_request('chain-XYZ', validators) - res = App(a, b).init_chain(request) + res = App(b, a).init_chain(request) assert res == types.ResponseInitChain() validator_set = query.get_validator_set(b.connection)['validators'] @@ -116,7 +116,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): ] for r in invalid_requests: with pytest.raises(SystemExit): - App(a, b).init_chain(r) + App(b, a).init_chain(r) assert query.get_latest_abci_chain(b.connection) == { 'chain_id': 'chain-XYZ-migrated-at-height-1', 'is_synced': False, @@ -129,7 +129,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): # completes the migration request = generate_init_chain_request('chain-XYZ-migrated-at-height-1', validators) - res = App(a, b).init_chain(request) + res = App(b, a).init_chain(request) assert res == types.ResponseInitChain() assert query.get_latest_abci_chain(b.connection) == { 'chain_id': 'chain-XYZ-migrated-at-height-1', @@ -150,7 +150,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): ] for r in invalid_requests: with pytest.raises(SystemExit): - App(a, b).init_chain(r) + App(b, a).init_chain(r) assert query.get_latest_abci_chain(b.connection) == { 'chain_id': 'chain-XYZ-migrated-at-height-1', 'is_synced': True, @@ -167,7 +167,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): def test_info(a, b): r = types.RequestInfo(version=__tm_supported_versions__[0]) - app = App(a, b) + app = App(b, a) res = app.info(r) assert res.last_block_height == 0 @@ -180,7 +180,7 @@ def test_info(a, b): # simulate a migration and assert the height is shifted b.store_abci_chain(2, 'chain-XYZ') - app = App(a, b) + app = App(b, a) b.store_block(Block(app_hash='2', height=2, transactions=[])._asdict()) res = app.info(r) assert res.last_block_height == 0 @@ -193,7 +193,7 @@ def test_info(a, b): # it's always the latest migration that is taken into account b.store_abci_chain(4, 'chain-XYZ-new') - app = App(a, b) + app = App(b, a) b.store_block(Block(app_hash='4', height=4, transactions=[])._asdict()) res = app.info(r) assert res.last_block_height == 0 @@ -212,7 +212,7 @@ def test_check_tx__signed_create_is_ok(a, b): [([bob.public_key], 1)])\ .sign([alice.private_key]) - app = App(a, b) + app = App(b, a) result = app.check_tx(encode_tx_to_bytes(tx)) assert result.code == OkCode @@ -228,7 +228,7 @@ def test_check_tx__unsigned_create_is_error(a, b): tx = Transaction.create([alice.public_key], [([bob.public_key], 1)]) - app = App(a, b) + app = App(b, a) result = app.check_tx(encode_tx_to_bytes(tx)) assert result.code == CodeTypeError @@ -283,7 +283,7 @@ def test_deliver_tx__double_spend_fails(a, b, init_chain_request): [([bob.public_key], 1)])\ .sign([alice.private_key]) - app = App(a, b) + app = App(b, a) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -305,7 +305,7 @@ def test_deliver_transfer_tx__double_spend_fails(a, b, init_chain_request): from planetmint.models import Transaction from planetmint.common.crypto import generate_key_pair - app = App(a, b) + app = App(b, a) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -345,7 +345,7 @@ def test_deliver_transfer_tx__double_spend_fails(a, b, init_chain_request): def test_end_block_return_validator_updates(a, b, init_chain_request): - app = App(a, b) + app = App(b, a) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -389,7 +389,7 @@ def test_store_pre_commit_state_in_end_block(a, b, alice, init_chain_request): asset={'msg': 'live long and prosper'})\ .sign([alice.private_key]) - app = App(a, b) + app = App(b, a) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -410,7 +410,7 @@ def test_store_pre_commit_state_in_end_block(a, b, alice, init_chain_request): # simulate a chain migration and assert the height is shifted b.store_abci_chain(100, 'new-chain') - app = App(a, b) + app = App(b, a) app.begin_block(begin_block) app.deliver_tx(encode_tx_to_bytes(tx)) app.end_block(types.RequestEndBlock(height=1)) @@ -507,39 +507,39 @@ def test_info_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).info(types.RequestInfo()) + App(b, a).info(types.RequestInfo()) def test_check_tx_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).check_tx('some bytes') + App(b, a).check_tx('some bytes') def test_begin_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).info(types.RequestBeginBlock()) + App(b, a).info(types.RequestBeginBlock()) def test_deliver_tx_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).deliver_tx('some bytes') + App(b, a).deliver_tx('some bytes') def test_end_block_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).info(types.RequestEndBlock()) + App(b, a).info(types.RequestEndBlock()) def test_commit_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).commit() + App(b, a).commit() diff --git a/tests/tendermint/test_integration.py b/tests/tendermint/test_integration.py index 17f96df..78511d7 100644 --- a/tests/tendermint/test_integration.py +++ b/tests/tendermint/test_integration.py @@ -25,7 +25,7 @@ def test_app(a, b, init_chain_request): from planetmint.common.crypto import generate_key_pair from planetmint.models import Transaction - app = App(a, b) + app = App(b, a) p = ProtocolHandler(app) data = p.process('info', @@ -150,7 +150,7 @@ def test_post_transaction_responses(tendermint_ws_url, b): def test_exit_when_tm_ver_not_supported(a, b): from planetmint import App - app = App(a, b) + app = App(b, a) p = ProtocolHandler(app) with pytest.raises(SystemExit): diff --git a/tests/test_core.py b/tests/test_core.py index 4cfa779..fd77010 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -53,7 +53,7 @@ def generate_init_chain_request(chain_id, vals=None): def test_init_chain_successfully_registers_chain(a, b): request = generate_init_chain_request('chain-XYZ') - res = App(a, b).init_chain(request) + res = App(b, a).init_chain(request) assert res == types.ResponseInitChain() chain = query.get_latest_abci_chain(b.connection) assert chain == {'height': 0, 'chain_id': 'chain-XYZ', 'is_synced': True} @@ -67,7 +67,7 @@ def test_init_chain_successfully_registers_chain(a, b): def test_init_chain_ignores_invalid_init_chain_requests(a, b): validators = [generate_validator()] request = generate_init_chain_request('chain-XYZ', validators) - res = App(a, b).init_chain(request) + res = App(b, a).init_chain(request) assert res == types.ResponseInitChain() validator_set = query.get_validator_set(b.connection) @@ -81,7 +81,7 @@ def test_init_chain_ignores_invalid_init_chain_requests(a, b): ] for r in invalid_requests: with pytest.raises(SystemExit): - App(a, b).init_chain(r) + App(b, a).init_chain(r) # assert nothing changed - neither validator set, nor chain ID new_validator_set = query.get_validator_set(b.connection) assert new_validator_set == validator_set @@ -97,7 +97,7 @@ def test_init_chain_ignores_invalid_init_chain_requests(a, b): def test_init_chain_recognizes_new_chain_after_migration(a, b): validators = [generate_validator()] request = generate_init_chain_request('chain-XYZ', validators) - res = App(a, b).init_chain(request) + res = App(b, a).init_chain(request) assert res == types.ResponseInitChain() validator_set = query.get_validator_set(b.connection)['validators'] @@ -116,7 +116,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): ] for r in invalid_requests: with pytest.raises(SystemExit): - App(a, b).init_chain(r) + App(b, a).init_chain(r) assert query.get_latest_abci_chain(b.connection) == { 'chain_id': 'chain-XYZ-migrated-at-height-1', 'is_synced': False, @@ -129,7 +129,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): # completes the migration request = generate_init_chain_request('chain-XYZ-migrated-at-height-1', validators) - res = App(a, b).init_chain(request) + res = App(b, a).init_chain(request) assert res == types.ResponseInitChain() assert query.get_latest_abci_chain(b.connection) == { 'chain_id': 'chain-XYZ-migrated-at-height-1', @@ -150,7 +150,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): ] for r in invalid_requests: with pytest.raises(SystemExit): - App(a, b).init_chain(r) + App(b, a).init_chain(r) assert query.get_latest_abci_chain(b.connection) == { 'chain_id': 'chain-XYZ-migrated-at-height-1', 'is_synced': True, @@ -167,7 +167,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): def test_info(a, b): r = types.RequestInfo(version=__tm_supported_versions__[0]) - app = App(a, b) + app = App(b, a) res = app.info(r) assert res.last_block_height == 0 @@ -180,7 +180,7 @@ def test_info(a, b): # simulate a migration and assert the height is shifted b.store_abci_chain(2, 'chain-XYZ') - app = App(a, b) + app = App(b, a) b.store_block(Block(app_hash='2', height=2, transactions=[])._asdict()) res = app.info(r) assert res.last_block_height == 0 @@ -193,7 +193,7 @@ def test_info(a, b): # it's always the latest migration that is taken into account b.store_abci_chain(4, 'chain-XYZ-new') - app = App(a, b) + app = App(b, a) b.store_block(Block(app_hash='4', height=4, transactions=[])._asdict()) res = app.info(r) assert res.last_block_height == 0 @@ -212,9 +212,9 @@ def test_check_tx__signed_create_is_ok(a, b): [([bob.public_key], 1)])\ .sign([alice.private_key]) - app = App(a, b) + app = App(b, a) result = app.check_tx(encode_tx_to_bytes(tx)) - assert result.code == CodeTypeOk + assert result.code == OkCode def test_check_tx__unsigned_create_is_error(a, b): @@ -228,7 +228,7 @@ def test_check_tx__unsigned_create_is_error(a, b): tx = Transaction.create([alice.public_key], [([bob.public_key], 1)]) - app = App(a, b) + app = App(b, a) result = app.check_tx(encode_tx_to_bytes(tx)) assert result.code == CodeTypeError @@ -255,7 +255,7 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(a, b, init_chain_re app.begin_block(begin_block) result = app.deliver_tx(encode_tx_to_bytes(tx)) - assert result.code == CodeTypeOk + assert result.code == OkCode app.end_block(types.RequestEndBlock(height=99)) app.commit() @@ -283,14 +283,14 @@ def test_deliver_tx__double_spend_fails(a, b, init_chain_request): [([bob.public_key], 1)])\ .sign([alice.private_key]) - app = App(a, b) + app = App(b, a) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() app.begin_block(begin_block) result = app.deliver_tx(encode_tx_to_bytes(tx)) - assert result.code == CodeTypeOk + assert result.code == OkCode app.end_block(types.RequestEndBlock(height=99)) app.commit() @@ -305,7 +305,7 @@ def test_deliver_transfer_tx__double_spend_fails(a, b, init_chain_request): from planetmint.models import Transaction from planetmint.common.crypto import generate_key_pair - app = App(a, b) + app = App(b, a) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -325,7 +325,7 @@ def test_deliver_transfer_tx__double_spend_fails(a, b, init_chain_request): .sign([alice.private_key]) result = app.deliver_tx(encode_tx_to_bytes(tx)) - assert result.code == CodeTypeOk + assert result.code == OkCode tx_transfer = Transaction.transfer(tx.to_inputs(), [([bob.public_key], 1)], @@ -333,7 +333,7 @@ def test_deliver_transfer_tx__double_spend_fails(a, b, init_chain_request): .sign([alice.private_key]) result = app.deliver_tx(encode_tx_to_bytes(tx_transfer)) - assert result.code == CodeTypeOk + assert result.code == OkCode double_spend = Transaction.transfer(tx.to_inputs(), [([carly.public_key], 1)], @@ -345,7 +345,7 @@ def test_deliver_transfer_tx__double_spend_fails(a, b, init_chain_request): def test_end_block_return_validator_updates(a, b, init_chain_request): - app = App(a, b) + app = App(b, a) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -389,7 +389,7 @@ def test_store_pre_commit_state_in_end_block(a, b, alice, init_chain_request): asset={'msg': 'live long and prosper'})\ .sign([alice.private_key]) - app = App(a, b) + app = App(b, a) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -410,7 +410,7 @@ def test_store_pre_commit_state_in_end_block(a, b, alice, init_chain_request): # simulate a chain migration and assert the height is shifted b.store_abci_chain(100, 'new-chain') - app = App(a, b) + app = App(b, a) app.begin_block(begin_block) app.deliver_tx(encode_tx_to_bytes(tx)) app.end_block(types.RequestEndBlock(height=1)) @@ -507,39 +507,39 @@ def test_info_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).info(types.RequestInfo()) + App(b, a).info(types.RequestInfo()) def test_check_tx_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).check_tx('some bytes') + App(b, a).check_tx('some bytes') def test_begin_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).info(types.RequestBeginBlock()) + App(b, a).info(types.RequestBeginBlock()) def test_deliver_tx_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).deliver_tx('some bytes') + App(b, a).deliver_tx('some bytes') def test_end_block_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).info(types.RequestEndBlock()) + App(b, a).info(types.RequestEndBlock()) def test_commit_aborts_if_chain_is_not_synced(a, b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(a, b).commit() \ No newline at end of file + App(b, a).commit() \ No newline at end of file From fda40ded092751e95546ea2616e23aaeba7b19d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Thu, 3 Feb 2022 00:08:07 +0100 Subject: [PATCH 09/93] furhter fixes --- planetmint/core.py | 9 +++++---- planetmint/parallel_validation.py | 2 +- tests/conftest.py | 2 +- tests/tendermint/test_core.py | 7 ++++--- tests/tendermint/test_integration.py | 2 +- tests/test_core.py | 12 ++++++------ 6 files changed, 18 insertions(+), 16 deletions(-) diff --git a/planetmint/core.py b/planetmint/core.py index 4369e5d..b65515d 100644 --- a/planetmint/core.py +++ b/planetmint/core.py @@ -58,7 +58,7 @@ class App(BaseApplication): transaction logic to Tendermint Core. """ - def __init__(self, planetmint_node=None, events_queue=None,): + def __init__(self, planetmint_node=None, events_queue=None): #super().__init__(abci) logger.debug('Checking values of types') logger.debug(dir(types_pb2)) @@ -70,6 +70,7 @@ class App(BaseApplication): self.validators = None self.new_height = None self.chain = self.planetmint_node.get_latest_abci_chain() + def log_abci_migration_error(self, chain_id, validators): logger.error('An ABCI chain migration is in process. ' @@ -167,7 +168,7 @@ class App(BaseApplication): transaction = decode_transaction(raw_transaction) if self.planetmint_node.is_valid_transaction(transaction): logger.debug('check_tx: VALID') - return ResponseCheckTx(code=CodeTypeOk) + return ResponseCheckTx(code=OkCode) else: logger.debug('check_tx: INVALID') return ResponseCheckTx(code=CodeTypeError) @@ -209,7 +210,7 @@ class App(BaseApplication): logger.debug('storing tx') self.block_txn_ids.append(transaction.id) self.block_transactions.append(transaction) - return ResponseDeliverTx(code=CodeTypeOk) + return ResponseDeliverTx(code=OkCode) def end_block(self, request_end_block): """Calculate block hash using transaction ids and previous block @@ -241,7 +242,7 @@ class App(BaseApplication): else: self.block_txn_hash = block['app_hash'] - validator_update = Election.process_block(self.planetmint, + validator_update = Election.process_block(self.planetmint_node, self.new_height, self.block_transactions) diff --git a/planetmint/parallel_validation.py b/planetmint/parallel_validation.py index 239f4d8..f5e530a 100644 --- a/planetmint/parallel_validation.py +++ b/planetmint/parallel_validation.py @@ -128,7 +128,7 @@ class ValidationWorker: except KeyError: asset_id = dict_transaction['id'] - transaction = self.planetmint_node.is_valid_transaction( + transaction = self.planetmint.is_valid_transaction( dict_transaction, self.validated_transactions[asset_id]) diff --git a/tests/conftest.py b/tests/conftest.py index 12bbe3b..04e448e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -446,7 +446,7 @@ def abci_server(): from planetmint.core import App from planetmint.utils import Process - app = ABCIServer(app=App(types_v0_34_11)) + app = ABCIServer(app=App()) abci_proxy = Process(name='ABCI', target=app.run) yield abci_proxy.start() abci_proxy.terminate() diff --git a/tests/tendermint/test_core.py b/tests/tendermint/test_core.py index 70a64af..95e4e2d 100644 --- a/tests/tendermint/test_core.py +++ b/tests/tendermint/test_core.py @@ -247,8 +247,9 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(a, b, init_chain_re [([bob.public_key], 1)])\ .sign([alice.private_key]) - app = App(a, b, events) - + # app = App(b, a, events) + app = App(b, events) + app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -376,7 +377,7 @@ def test_end_block_return_validator_updates(a, b, init_chain_request): resp = app.end_block(types.RequestEndBlock(height=2)) assert resp.validator_updates[0].power == new_validator['election']['power'] expected = bytes.fromhex(new_validator['election']['public_key']['value']) - assert expected == resp.validator_updates[0].pub_key.data + assert expected == resp.validator_updates[0].pub_key.ed25519 def test_store_pre_commit_state_in_end_block(a, b, alice, init_chain_request): diff --git a/tests/tendermint/test_integration.py b/tests/tendermint/test_integration.py index 78511d7..ccfb7aa 100644 --- a/tests/tendermint/test_integration.py +++ b/tests/tendermint/test_integration.py @@ -42,7 +42,7 @@ def test_app(a, b, init_chain_request): assert block0['height'] == 0 assert block0['app_hash'] == '' - pk = codecs.encode(init_chain_request.validators[0].pub_key.data, 'base64').decode().strip('\n') + pk = codecs.encode(init_chain_request.validators[0].pub_key.ed25519, 'base64').decode().strip('\n') [validator] = b.get_validators(height=1) assert validator['public_key']['value'] == pk assert validator['voting_power'] == 10 diff --git a/tests/test_core.py b/tests/test_core.py index 8e3bf24..baec830 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -214,7 +214,7 @@ def test_check_tx__signed_create_is_ok(a, b): app = App(b, a) result = app.check_tx(encode_tx_to_bytes(tx)) - assert result.code == CodeTypeOk + assert result.code == OkCode def test_check_tx__unsigned_create_is_error(a, b): @@ -247,7 +247,7 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(a, b, init_chain_re [([bob.public_key], 1)])\ .sign([alice.private_key]) - app = App(a, b, events) + app = App( a, events) app.init_chain(init_chain_request) @@ -255,7 +255,7 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(a, b, init_chain_re app.begin_block(begin_block) result = app.deliver_tx(encode_tx_to_bytes(tx)) - assert result.code == CodeTypeOk + assert result.code == OkCode app.end_block(types.RequestEndBlock(height=99)) app.commit() @@ -290,7 +290,7 @@ def test_deliver_tx__double_spend_fails(a, b, init_chain_request): app.begin_block(begin_block) result = app.deliver_tx(encode_tx_to_bytes(tx)) - assert result.code == CodeTypeOk + assert result.code == OkCode app.end_block(types.RequestEndBlock(height=99)) app.commit() @@ -325,7 +325,7 @@ def test_deliver_transfer_tx__double_spend_fails(a, b, init_chain_request): .sign([alice.private_key]) result = app.deliver_tx(encode_tx_to_bytes(tx)) - assert result.code == CodeTypeOk + assert result.code == OkCode tx_transfer = Transaction.transfer(tx.to_inputs(), [([bob.public_key], 1)], @@ -333,7 +333,7 @@ def test_deliver_transfer_tx__double_spend_fails(a, b, init_chain_request): .sign([alice.private_key]) result = app.deliver_tx(encode_tx_to_bytes(tx_transfer)) - assert result.code == CodeTypeOk + assert result.code == OkCode double_spend = Transaction.transfer(tx.to_inputs(), [([carly.public_key], 1)], From 5fb0913b5fa21140d2e6694b20fd9cf91fd7d231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Thu, 3 Feb 2022 01:07:19 +0100 Subject: [PATCH 10/93] working tests --- tests/conftest.py | 14 ++++- tests/tendermint/test_core.py | 81 +++++++++++++------------- tests/tendermint/test_integration.py | 15 +---- tests/test_core.py | 85 ++++++++++++++-------------- 4 files changed, 96 insertions(+), 99 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 04e448e..f7327a6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -31,6 +31,7 @@ from planetmint.common.crypto import (key_pair_from_ed25519_key, from planetmint.common.exceptions import DatabaseDoesNotExist from planetmint.lib import Block from tests.utils import gen_vote +import tests.tendermint.conftest TEST_DB_NAME = 'planetmint_test' @@ -235,9 +236,10 @@ def merlin(): @pytest.fixture -def a(): - from tendermint.abci import types_pb2 as types_v0_34_11 - return types_v0_34_11 +#def a(): +def abci_fixture(): + from tendermint.abci import types_pb2 + return types_pb2 @pytest.fixture @@ -245,6 +247,12 @@ def b(): from planetmint import Planetmint return Planetmint() +@pytest.fixture +def eventqueue_fixture(): + from multiprocessing import Queue + return Queue() + + @pytest.fixture def b_mock(b, network_validators): diff --git a/tests/tendermint/test_core.py b/tests/tendermint/test_core.py index 95e4e2d..623e438 100644 --- a/tests/tendermint/test_core.py +++ b/tests/tendermint/test_core.py @@ -51,9 +51,9 @@ def generate_init_chain_request(chain_id, vals=None): return types.RequestInitChain(validators=vals, chain_id=chain_id) -def test_init_chain_successfully_registers_chain(a, b): +def test_init_chain_successfully_registers_chain(b): request = generate_init_chain_request('chain-XYZ') - res = App(b, a).init_chain(request) + res = App(b).init_chain(request) assert res == types.ResponseInitChain() chain = query.get_latest_abci_chain(b.connection) assert chain == {'height': 0, 'chain_id': 'chain-XYZ', 'is_synced': True} @@ -64,10 +64,10 @@ def test_init_chain_successfully_registers_chain(a, b): } -def test_init_chain_ignores_invalid_init_chain_requests(a, b): +def test_init_chain_ignores_invalid_init_chain_requests(b): validators = [generate_validator()] request = generate_init_chain_request('chain-XYZ', validators) - res = App(b, a).init_chain(request) + res = App(b).init_chain(request) assert res == types.ResponseInitChain() validator_set = query.get_validator_set(b.connection) @@ -81,7 +81,7 @@ def test_init_chain_ignores_invalid_init_chain_requests(a, b): ] for r in invalid_requests: with pytest.raises(SystemExit): - App(b, a).init_chain(r) + App(b).init_chain(r) # assert nothing changed - neither validator set, nor chain ID new_validator_set = query.get_validator_set(b.connection) assert new_validator_set == validator_set @@ -94,10 +94,10 @@ def test_init_chain_ignores_invalid_init_chain_requests(a, b): } -def test_init_chain_recognizes_new_chain_after_migration(a, b): +def test_init_chain_recognizes_new_chain_after_migration(b): validators = [generate_validator()] request = generate_init_chain_request('chain-XYZ', validators) - res = App(b, a).init_chain(request) + res = App(b).init_chain(request) assert res == types.ResponseInitChain() validator_set = query.get_validator_set(b.connection)['validators'] @@ -116,7 +116,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): ] for r in invalid_requests: with pytest.raises(SystemExit): - App(b, a).init_chain(r) + App(b).init_chain(r) assert query.get_latest_abci_chain(b.connection) == { 'chain_id': 'chain-XYZ-migrated-at-height-1', 'is_synced': False, @@ -129,7 +129,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): # completes the migration request = generate_init_chain_request('chain-XYZ-migrated-at-height-1', validators) - res = App(b, a).init_chain(request) + res = App(b).init_chain(request) assert res == types.ResponseInitChain() assert query.get_latest_abci_chain(b.connection) == { 'chain_id': 'chain-XYZ-migrated-at-height-1', @@ -150,7 +150,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): ] for r in invalid_requests: with pytest.raises(SystemExit): - App(b, a).init_chain(r) + App(b).init_chain(r) assert query.get_latest_abci_chain(b.connection) == { 'chain_id': 'chain-XYZ-migrated-at-height-1', 'is_synced': True, @@ -165,9 +165,9 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): } -def test_info(a, b): +def test_info(b): r = types.RequestInfo(version=__tm_supported_versions__[0]) - app = App(b, a) + app = App(b) res = app.info(r) assert res.last_block_height == 0 @@ -180,7 +180,7 @@ def test_info(a, b): # simulate a migration and assert the height is shifted b.store_abci_chain(2, 'chain-XYZ') - app = App(b, a) + app = App(b) b.store_block(Block(app_hash='2', height=2, transactions=[])._asdict()) res = app.info(r) assert res.last_block_height == 0 @@ -193,14 +193,14 @@ def test_info(a, b): # it's always the latest migration that is taken into account b.store_abci_chain(4, 'chain-XYZ-new') - app = App(b, a) + app = App(b) b.store_block(Block(app_hash='4', height=4, transactions=[])._asdict()) res = app.info(r) assert res.last_block_height == 0 assert res.last_block_app_hash == b'4' -def test_check_tx__signed_create_is_ok(a, b): +def test_check_tx__signed_create_is_ok(b): from planetmint import App from planetmint.models import Transaction from planetmint.common.crypto import generate_key_pair @@ -212,12 +212,12 @@ def test_check_tx__signed_create_is_ok(a, b): [([bob.public_key], 1)])\ .sign([alice.private_key]) - app = App(b, a) + app = App(b) result = app.check_tx(encode_tx_to_bytes(tx)) assert result.code == OkCode -def test_check_tx__unsigned_create_is_error(a, b): +def test_check_tx__unsigned_create_is_error(b): from planetmint import App from planetmint.models import Transaction from planetmint.common.crypto import generate_key_pair @@ -228,12 +228,12 @@ def test_check_tx__unsigned_create_is_error(a, b): tx = Transaction.create([alice.public_key], [([bob.public_key], 1)]) - app = App(b, a) + app = App(b) result = app.check_tx(encode_tx_to_bytes(tx)) assert result.code == CodeTypeError -def test_deliver_tx__valid_create_updates_db_and_emits_event(a, b, init_chain_request): +def test_deliver_tx__valid_create_updates_db_and_emits_event(b, init_chain_request): import multiprocessing as mp from planetmint import App from planetmint.models import Transaction @@ -247,7 +247,6 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(a, b, init_chain_re [([bob.public_key], 1)])\ .sign([alice.private_key]) - # app = App(b, a, events) app = App(b, events) app.init_chain(init_chain_request) @@ -272,7 +271,7 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(a, b, init_chain_re # next(unspent_outputs) -def test_deliver_tx__double_spend_fails(a, b, init_chain_request): +def test_deliver_tx__double_spend_fails(b, init_chain_request): from planetmint import App from planetmint.models import Transaction from planetmint.common.crypto import generate_key_pair @@ -284,7 +283,7 @@ def test_deliver_tx__double_spend_fails(a, b, init_chain_request): [([bob.public_key], 1)])\ .sign([alice.private_key]) - app = App(b, a) + app = App(b) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -301,12 +300,12 @@ def test_deliver_tx__double_spend_fails(a, b, init_chain_request): assert result.code == CodeTypeError -def test_deliver_transfer_tx__double_spend_fails(a, b, init_chain_request): +def test_deliver_transfer_tx__double_spend_fails(b, init_chain_request): from planetmint import App from planetmint.models import Transaction from planetmint.common.crypto import generate_key_pair - app = App(b, a) + app = App(b) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -345,8 +344,8 @@ def test_deliver_transfer_tx__double_spend_fails(a, b, init_chain_request): assert result.code == CodeTypeError -def test_end_block_return_validator_updates(a, b, init_chain_request): - app = App(b, a) +def test_end_block_return_validator_updates(b, init_chain_request): + app = App(b) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -380,7 +379,7 @@ def test_end_block_return_validator_updates(a, b, init_chain_request): assert expected == resp.validator_updates[0].pub_key.ed25519 -def test_store_pre_commit_state_in_end_block(a, b, alice, init_chain_request): +def test_store_pre_commit_state_in_end_block(b, alice, init_chain_request): from planetmint import App from planetmint.backend import query from planetmint.models import Transaction @@ -390,7 +389,7 @@ def test_store_pre_commit_state_in_end_block(a, b, alice, init_chain_request): asset={'msg': 'live long and prosper'})\ .sign([alice.private_key]) - app = App(b, a) + app = App(b) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -411,7 +410,7 @@ def test_store_pre_commit_state_in_end_block(a, b, alice, init_chain_request): # simulate a chain migration and assert the height is shifted b.store_abci_chain(100, 'new-chain') - app = App(b, a) + app = App(b) app.begin_block(begin_block) app.deliver_tx(encode_tx_to_bytes(tx)) app.end_block(types.RequestEndBlock(height=1)) @@ -504,43 +503,43 @@ def test_new_validator_set(b): assert updated_validator_set == updated_validators -def test_info_aborts_if_chain_is_not_synced(a, b): +def test_info_aborts_if_chain_is_not_synced(b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(b, a).info(types.RequestInfo()) + App(b).info(types.RequestInfo()) -def test_check_tx_aborts_if_chain_is_not_synced(a, b): +def test_check_tx_aborts_if_chain_is_not_synced(b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(b, a).check_tx('some bytes') + App(b).check_tx('some bytes') -def test_begin_aborts_if_chain_is_not_synced(a, b): +def test_begin_aborts_if_chain_is_not_synced(b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(b, a).info(types.RequestBeginBlock()) + App(b).info(types.RequestBeginBlock()) -def test_deliver_tx_aborts_if_chain_is_not_synced(a, b): +def test_deliver_tx_aborts_if_chain_is_not_synced(b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(b, a).deliver_tx('some bytes') + App(b).deliver_tx('some bytes') -def test_end_block_aborts_if_chain_is_not_synced(a, b): +def test_end_block_aborts_if_chain_is_not_synced(b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(b, a).info(types.RequestEndBlock()) + App(b).info(types.RequestEndBlock()) -def test_commit_aborts_if_chain_is_not_synced(a, b): +def test_commit_aborts_if_chain_is_not_synced(b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(b, a).commit() + App(b).commit() diff --git a/tests/tendermint/test_integration.py b/tests/tendermint/test_integration.py index ccfb7aa..17f58a2 100644 --- a/tests/tendermint/test_integration.py +++ b/tests/tendermint/test_integration.py @@ -19,13 +19,13 @@ from io import BytesIO @pytest.mark.bdb -def test_app(a, b, init_chain_request): +def test_app(b, eventqueue_fixture, init_chain_request): from planetmint import App from planetmint.tendermint_utils import calculate_hash from planetmint.common.crypto import generate_key_pair from planetmint.models import Transaction - app = App(b, a) + app = App(b, eventqueue_fixture) p = ProtocolHandler(app) data = p.process('info', @@ -144,14 +144,3 @@ def test_post_transaction_responses(tendermint_ws_url, b): code, message = b.write_transaction(double_spend, mode) assert code == 500 assert message == 'Transaction validation failed' - - -@pytest.mark.bdb -def test_exit_when_tm_ver_not_supported(a, b): - from planetmint import App - - app = App(b, a) - p = ProtocolHandler(app) - - with pytest.raises(SystemExit): - p.process('info', types.Request(info=types.RequestInfo(version='2'))) diff --git a/tests/test_core.py b/tests/test_core.py index baec830..98bab73 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -25,6 +25,7 @@ from planetmint.tendermint_utils import public_key_to_base64 from planetmint.version import __tm_supported_versions__ from tests.utils import generate_election, generate_validators +from tests.tendermint.conftest import init_chain_request pytestmark = pytest.mark.bdb @@ -51,9 +52,9 @@ def generate_init_chain_request(chain_id, vals=None): return types.RequestInitChain(validators=vals, chain_id=chain_id) -def test_init_chain_successfully_registers_chain(a, b): +def test_init_chain_successfully_registers_chain(b): request = generate_init_chain_request('chain-XYZ') - res = App(b, a).init_chain(request) + res = App(b).init_chain(request) assert res == types.ResponseInitChain() chain = query.get_latest_abci_chain(b.connection) assert chain == {'height': 0, 'chain_id': 'chain-XYZ', 'is_synced': True} @@ -64,10 +65,10 @@ def test_init_chain_successfully_registers_chain(a, b): } -def test_init_chain_ignores_invalid_init_chain_requests(a, b): +def test_init_chain_ignores_invalid_init_chain_requests(b): validators = [generate_validator()] request = generate_init_chain_request('chain-XYZ', validators) - res = App(b, a).init_chain(request) + res = App(b).init_chain(request) assert res == types.ResponseInitChain() validator_set = query.get_validator_set(b.connection) @@ -81,7 +82,7 @@ def test_init_chain_ignores_invalid_init_chain_requests(a, b): ] for r in invalid_requests: with pytest.raises(SystemExit): - App(b, a).init_chain(r) + App(b).init_chain(r) # assert nothing changed - neither validator set, nor chain ID new_validator_set = query.get_validator_set(b.connection) assert new_validator_set == validator_set @@ -94,10 +95,10 @@ def test_init_chain_ignores_invalid_init_chain_requests(a, b): } -def test_init_chain_recognizes_new_chain_after_migration(a, b): +def test_init_chain_recognizes_new_chain_after_migration(b): validators = [generate_validator()] request = generate_init_chain_request('chain-XYZ', validators) - res = App(b, a).init_chain(request) + res = App(b).init_chain(request) assert res == types.ResponseInitChain() validator_set = query.get_validator_set(b.connection)['validators'] @@ -116,7 +117,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): ] for r in invalid_requests: with pytest.raises(SystemExit): - App(b, a).init_chain(r) + App(b).init_chain(r) assert query.get_latest_abci_chain(b.connection) == { 'chain_id': 'chain-XYZ-migrated-at-height-1', 'is_synced': False, @@ -129,7 +130,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): # completes the migration request = generate_init_chain_request('chain-XYZ-migrated-at-height-1', validators) - res = App(b, a).init_chain(request) + res = App(b).init_chain(request) assert res == types.ResponseInitChain() assert query.get_latest_abci_chain(b.connection) == { 'chain_id': 'chain-XYZ-migrated-at-height-1', @@ -150,7 +151,7 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): ] for r in invalid_requests: with pytest.raises(SystemExit): - App(b, a).init_chain(r) + App(b).init_chain(r) assert query.get_latest_abci_chain(b.connection) == { 'chain_id': 'chain-XYZ-migrated-at-height-1', 'is_synced': True, @@ -165,9 +166,9 @@ def test_init_chain_recognizes_new_chain_after_migration(a, b): } -def test_info(a, b): +def test_info(b): r = types.RequestInfo(version=__tm_supported_versions__[0]) - app = App(b, a) + app = App(b) res = app.info(r) assert res.last_block_height == 0 @@ -180,7 +181,7 @@ def test_info(a, b): # simulate a migration and assert the height is shifted b.store_abci_chain(2, 'chain-XYZ') - app = App(b, a) + app = App(b) b.store_block(Block(app_hash='2', height=2, transactions=[])._asdict()) res = app.info(r) assert res.last_block_height == 0 @@ -193,14 +194,14 @@ def test_info(a, b): # it's always the latest migration that is taken into account b.store_abci_chain(4, 'chain-XYZ-new') - app = App(b, a) + app = App(b) b.store_block(Block(app_hash='4', height=4, transactions=[])._asdict()) res = app.info(r) assert res.last_block_height == 0 assert res.last_block_app_hash == b'4' -def test_check_tx__signed_create_is_ok(a, b): +def test_check_tx__signed_create_is_ok(b): from planetmint import App from planetmint.models import Transaction from planetmint.common.crypto import generate_key_pair @@ -212,12 +213,12 @@ def test_check_tx__signed_create_is_ok(a, b): [([bob.public_key], 1)])\ .sign([alice.private_key]) - app = App(b, a) + app = App(b) result = app.check_tx(encode_tx_to_bytes(tx)) assert result.code == OkCode -def test_check_tx__unsigned_create_is_error(a, b): +def test_check_tx__unsigned_create_is_error(b): from planetmint import App from planetmint.models import Transaction from planetmint.common.crypto import generate_key_pair @@ -228,12 +229,12 @@ def test_check_tx__unsigned_create_is_error(a, b): tx = Transaction.create([alice.public_key], [([bob.public_key], 1)]) - app = App(b, a) + app = App(b) result = app.check_tx(encode_tx_to_bytes(tx)) assert result.code == CodeTypeError -def test_deliver_tx__valid_create_updates_db_and_emits_event(a, b, init_chain_request): +def test_deliver_tx__valid_create_updates_db_and_emits_event(b, init_chain_request): import multiprocessing as mp from planetmint import App from planetmint.models import Transaction @@ -247,7 +248,7 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(a, b, init_chain_re [([bob.public_key], 1)])\ .sign([alice.private_key]) - app = App( a, events) + app = App(b, events) app.init_chain(init_chain_request) @@ -271,7 +272,7 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(a, b, init_chain_re # next(unspent_outputs) -def test_deliver_tx__double_spend_fails(a, b, init_chain_request): +def test_deliver_tx__double_spend_fails(b, eventqueue_fixture, init_chain_request): from planetmint import App from planetmint.models import Transaction from planetmint.common.crypto import generate_key_pair @@ -283,7 +284,7 @@ def test_deliver_tx__double_spend_fails(a, b, init_chain_request): [([bob.public_key], 1)])\ .sign([alice.private_key]) - app = App(b, a) + app = App(b, eventqueue_fixture) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -300,12 +301,12 @@ def test_deliver_tx__double_spend_fails(a, b, init_chain_request): assert result.code == CodeTypeError -def test_deliver_transfer_tx__double_spend_fails(a, b, init_chain_request): +def test_deliver_transfer_tx__double_spend_fails(b, init_chain_request): from planetmint import App from planetmint.models import Transaction from planetmint.common.crypto import generate_key_pair - app = App(b, a) + app = App(b) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -344,8 +345,8 @@ def test_deliver_transfer_tx__double_spend_fails(a, b, init_chain_request): assert result.code == CodeTypeError -def test_end_block_return_validator_updates(a, b, init_chain_request): - app = App(b, a) +def test_end_block_return_validator_updates(b, init_chain_request): + app = App(b) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -376,10 +377,10 @@ def test_end_block_return_validator_updates(a, b, init_chain_request): resp = app.end_block(types.RequestEndBlock(height=2)) assert resp.validator_updates[0].power == new_validator['election']['power'] expected = bytes.fromhex(new_validator['election']['public_key']['value']) - assert expected == resp.validator_updates[0].pub_key.data + assert expected == resp.validator_updates[0].pub_key.ed25519 -def test_store_pre_commit_state_in_end_block(a, b, alice, init_chain_request): +def test_store_pre_commit_state_in_end_block(b, alice, init_chain_request): from planetmint import App from planetmint.backend import query from planetmint.models import Transaction @@ -389,7 +390,7 @@ def test_store_pre_commit_state_in_end_block(a, b, alice, init_chain_request): asset={'msg': 'live long and prosper'})\ .sign([alice.private_key]) - app = App(b, a) + app = App(b) app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() @@ -410,7 +411,7 @@ def test_store_pre_commit_state_in_end_block(a, b, alice, init_chain_request): # simulate a chain migration and assert the height is shifted b.store_abci_chain(100, 'new-chain') - app = App(b, a) + app = App(b) app.begin_block(begin_block) app.deliver_tx(encode_tx_to_bytes(tx)) app.end_block(types.RequestEndBlock(height=1)) @@ -503,43 +504,43 @@ def test_new_validator_set(b): assert updated_validator_set == updated_validators -def test_info_aborts_if_chain_is_not_synced(a, b): +def test_info_aborts_if_chain_is_not_synced(b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(b, a).info(types.RequestInfo()) + App(b).info(types.RequestInfo()) -def test_check_tx_aborts_if_chain_is_not_synced(a, b): +def test_check_tx_aborts_if_chain_is_not_synced(b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(b, a).check_tx('some bytes') + App(b).check_tx('some bytes') -def test_begin_aborts_if_chain_is_not_synced(a, b): +def test_begin_aborts_if_chain_is_not_synced(b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(b, a).info(types.RequestBeginBlock()) + App(b).info(types.RequestBeginBlock()) -def test_deliver_tx_aborts_if_chain_is_not_synced(a, b): +def test_deliver_tx_aborts_if_chain_is_not_synced(b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(b, a).deliver_tx('some bytes') + App(b).deliver_tx('some bytes') -def test_end_block_aborts_if_chain_is_not_synced(a, b): +def test_end_block_aborts_if_chain_is_not_synced(b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(b, a).info(types.RequestEndBlock()) + App(b).info(types.RequestEndBlock()) -def test_commit_aborts_if_chain_is_not_synced(a, b): +def test_commit_aborts_if_chain_is_not_synced(b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(b, a).commit() \ No newline at end of file + App(b).commit() \ No newline at end of file From c2b4e550f081e2701ecae697273340ef3fdae190 Mon Sep 17 00:00:00 2001 From: Sangat Das Date: Thu, 3 Feb 2022 08:28:57 +0000 Subject: [PATCH 11/93] Reduce deprecation warnings in tests --- pytest.ini | 7 +++++++ setup.py | 2 +- tests/conftest.py | 3 ++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/pytest.ini b/pytest.ini index 43cb8a7..3851b6d 100644 --- a/pytest.ini +++ b/pytest.ini @@ -3,3 +3,10 @@ testpaths = tests/ norecursedirs = .* *.egg *.egg-info env* devenv* docs addopts = -m "not abci" looponfailroots = planetmint tests +asyncio_mode = strict +markers = + userfixtures + language + tendermint + usefixture + execute diff --git a/setup.py b/setup.py index 789a402..c2380de 100644 --- a/setup.py +++ b/setup.py @@ -74,7 +74,7 @@ tests_require = [ install_requires = [ 'chardet==3.0.4', - 'aiohttp==3.7.4', + 'aiohttp==3.8.1', 'bigchaindb-abci==1.0.7', 'planetmint-cryptoconditions>=0.9.0', 'flask-cors==3.0.10', diff --git a/tests/conftest.py b/tests/conftest.py index 77e22cf..df99a4d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,6 +9,7 @@ Tasks: 1. setup test database before starting the tests 2. delete test database after running the tests """ +import asyncio import json import os import copy @@ -430,7 +431,7 @@ def abci_http(_setup_database, _configure_planetmint, abci_server, return False -@pytest.yield_fixture(scope='session') +@pytest.fixture(scope='session') def event_loop(): import asyncio From cfa3afe821b1bb20aa62160d6a6cb11be7004404 Mon Sep 17 00:00:00 2001 From: ArpitShukla007 Date: Thu, 3 Feb 2022 09:52:52 +0000 Subject: [PATCH 12/93] Resolved merge conflict. --- Dockerfile-all-in-one | 2 +- Dockerfile-alpine | 2 +- Dockerfile-dev | 2 +- README.md | 7 +++---- acceptance/python/Dockerfile | 3 ++- acceptance/python/src/test_basic.py | 6 +++--- acceptance/python/src/test_divisible_asset.py | 8 ++++---- acceptance/python/src/test_double_spend.py | 10 +++++----- acceptance/python/src/test_multiple_owners.py | 6 +++--- acceptance/python/src/test_naughty_strings.py | 8 ++++---- acceptance/python/src/test_stream.py | 6 +++--- docs/root/source/contributing/index.rst | 2 +- .../ways-to-contribute/report-a-bug.md | 1 - .../ways-to-contribute/write-docs.md | 2 +- docs/root/source/korean/query-ko.md | 10 +++------- k8s/toolbox/Dockerfile | 4 ++-- setup.py | 20 +++++++------------ 17 files changed, 44 insertions(+), 55 deletions(-) diff --git a/Dockerfile-all-in-one b/Dockerfile-all-in-one index c4b7b77..736934c 100644 --- a/Dockerfile-all-in-one +++ b/Dockerfile-all-in-one @@ -10,7 +10,7 @@ WORKDIR /usr/src/app RUN apk --update add sudo bash \ && apk --update add python3 openssl ca-certificates git \ && apk --update add --virtual build-dependencies python3-dev \ - libffi-dev openssl-dev build-base jq \ + libffi-dev openssl-dev build-base jq zsh \ && apk add --no-cache libstdc++ dpkg gnupg \ && pip3 install --upgrade pip cffi \ && pip install -e . \ diff --git a/Dockerfile-alpine b/Dockerfile-alpine index 59da072..0efa4cd 100644 --- a/Dockerfile-alpine +++ b/Dockerfile-alpine @@ -5,7 +5,7 @@ COPY . /usr/src/app/ WORKDIR /usr/src/app RUN apk --update add sudo \ && apk --update add python3 py-pip openssl ca-certificates git\ - && apk --update add --virtual build-dependencies python3-dev \ + && apk --update add --virtual build-dependencies python3-dev zsh \ libffi-dev openssl-dev build-base \ && apk add --no-cache libstdc++ \ && pip3 install --upgrade pip cffi \ diff --git a/Dockerfile-dev b/Dockerfile-dev index c55073e..c44b4f3 100644 --- a/Dockerfile-dev +++ b/Dockerfile-dev @@ -3,7 +3,7 @@ FROM python:${python_version} LABEL maintainer "contact@ipdb.global" RUN apt-get update \ - && apt-get install -y git \ + && apt-get install -y git zsh\ && pip install -U pip \ && apt-get autoremove \ && apt-get clean diff --git a/README.md b/README.md index 0745b0b..d0a1949 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,9 @@ so show the latest GitHub release instead. [![Codecov branch](https://img.shields.io/codecov/c/github/planetmint/planetmint/master.svg)](https://codecov.io/github/planetmint/planetmint?branch=master) [![Latest release](https://img.shields.io/github/release/planetmint/planetmint/all.svg)](https://github.com/planetmint/planetmint/releases) -[![Status on PyPI](https://img.shields.io/pypi/status/planetmint.svg)](https://pypi.org/project/Planetmint/) -[![Travis branch](https://img.shields.io/travis/planetmint/planetmint/master.svg)](https://travis-ci.com/planetmint/planetmint) -[![Documentation Status](https://readthedocs.org/projects/planetmint-server/badge/?version=latest)](https://docs.planetmint.com/projects/server/en/latest/) -[![Join the chat at https://gitter.im/planetmint/planetmint](https://badges.gitter.im/planetmint/planetmint.svg)](https://gitter.im/planetmint/planetmint?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Status on PyPI](https://img.shields.io/pypi/status/planetmint.svg)](https://pypi.org/project/Planetmint) +[![Build Status](https://app.travis-ci.com/planetmint/planetmint.svg?branch=main)](https://app.travis-ci.com/planetmint/planetmint) +[![Join the chat at https://gitter.im/planetmint/planetmint](https://badges.gitter.im/planetmint/planetmint.svg)](https://gitter.im/planetmint/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) # Planetmint Server diff --git a/acceptance/python/Dockerfile b/acceptance/python/Dockerfile index ae59ca0..a106dcf 100644 --- a/acceptance/python/Dockerfile +++ b/acceptance/python/Dockerfile @@ -1,9 +1,10 @@ FROM python:3.9 +RUN apt-get update && apt-get install -y vim zsh RUN mkdir -p /src RUN pip install --upgrade \ pycco \ websocket-client~=0.47.0 \ pytest~=3.0 \ - bigchaindb-driver~=0.6.2 \ + planetmint-driver>=0.9.0 \ blns diff --git a/acceptance/python/src/test_basic.py b/acceptance/python/src/test_basic.py index b29a47b..5e09085 100644 --- a/acceptance/python/src/test_basic.py +++ b/acceptance/python/src/test_basic.py @@ -24,8 +24,8 @@ import os # For this test case we import and use the Python Driver. -from bigchaindb_driver import BigchainDB -from bigchaindb_driver.crypto import generate_keypair +from planetmint_driver import Planetmint +from planetmint_driver.crypto import generate_keypair def test_basic(): @@ -34,7 +34,7 @@ def test_basic(): # connect to localhost, but you can override this value using the env variable # called `PLANETMINT_ENDPOINT`, a valid value must include the schema: # `https://example.com:9984` - bdb = BigchainDB(os.environ.get('PLANETMINT_ENDPOINT')) + bdb = Planetmint(os.environ.get('PLANETMINT_ENDPOINT')) # ## Create keypairs # This test requires the interaction between two actors with their own keypair. diff --git a/acceptance/python/src/test_divisible_asset.py b/acceptance/python/src/test_divisible_asset.py index 00baeaf..1967237 100644 --- a/acceptance/python/src/test_divisible_asset.py +++ b/acceptance/python/src/test_divisible_asset.py @@ -26,18 +26,18 @@ # And of course, we also need the `BadRequest`. import os import pytest -from bigchaindb_driver.exceptions import BadRequest +from planetmint_driver.exceptions import BadRequest # For this test case we import and use the Python Driver. -from bigchaindb_driver import BigchainDB -from bigchaindb_driver.crypto import generate_keypair +from planetmint_driver import Planetmint +from planetmint_driver.crypto import generate_keypair def test_divisible_assets(): # ## Set up a connection to Planetmint # Check [test_basic.py](./test_basic.html) to get some more details # about the endpoint. - bdb = BigchainDB(os.environ.get('PLANETMINT_ENDPOINT')) + bdb = Planetmint(os.environ.get('PLANETMINT_ENDPOINT')) # Oh look, it is Alice again and she brought her friend Bob along. alice, bob = generate_keypair(), generate_keypair() diff --git a/acceptance/python/src/test_double_spend.py b/acceptance/python/src/test_double_spend.py index 66a2467..8f8fab9 100644 --- a/acceptance/python/src/test_double_spend.py +++ b/acceptance/python/src/test_double_spend.py @@ -11,13 +11,13 @@ from uuid import uuid4 from threading import Thread import queue -import bigchaindb_driver.exceptions -from bigchaindb_driver import BigchainDB -from bigchaindb_driver.crypto import generate_keypair +import planetmint_driver.exceptions +from planetmint_driver import Planetmint +from planetmint_driver.crypto import generate_keypair def test_double_create(): - bdb = BigchainDB(os.environ.get('PLANETMINT_ENDPOINT')) + bdb = Planetmint(os.environ.get('PLANETMINT_ENDPOINT')) alice = generate_keypair() results = queue.Queue() @@ -33,7 +33,7 @@ def test_double_create(): try: bdb.transactions.send_commit(tx) results.put('OK') - except bigchaindb_driver.exceptions.TransportError as e: + except planetmint_driver.exceptions.TransportError as e: results.put('FAIL') t1 = Thread(target=send_and_queue, args=(tx, )) diff --git a/acceptance/python/src/test_multiple_owners.py b/acceptance/python/src/test_multiple_owners.py index ea82ed0..e60c63a 100644 --- a/acceptance/python/src/test_multiple_owners.py +++ b/acceptance/python/src/test_multiple_owners.py @@ -25,15 +25,15 @@ import os # For this test case we import and use the Python Driver. -from bigchaindb_driver import BigchainDB -from bigchaindb_driver.crypto import generate_keypair +from planetmint_driver import Planetmint +from planetmint_driver.crypto import generate_keypair def test_multiple_owners(): # ## Set up a connection to Planetmint # Check [test_basic.py](./test_basic.html) to get some more details # about the endpoint. - bdb = BigchainDB(os.environ.get('PLANETMINT_ENDPOINT')) + bdb = Planetmint(os.environ.get('PLANETMINT_ENDPOINT')) # Hey Alice and Bob, nice to see you again! alice, bob = generate_keypair(), generate_keypair() diff --git a/acceptance/python/src/test_naughty_strings.py b/acceptance/python/src/test_naughty_strings.py index f0e92d4..423ae01 100644 --- a/acceptance/python/src/test_naughty_strings.py +++ b/acceptance/python/src/test_naughty_strings.py @@ -24,9 +24,9 @@ from blns import blns import pytest # For this test case we import and use the Python Driver. -from bigchaindb_driver import BigchainDB -from bigchaindb_driver.crypto import generate_keypair -from bigchaindb_driver.exceptions import BadRequest +from planetmint_driver import Planetmint +from planetmint_driver.crypto import generate_keypair +from planetmint_driver.exceptions import BadRequest naughty_strings = blns.all() @@ -36,7 +36,7 @@ def send_naughty_tx(asset, metadata): # ## Set up a connection to Planetmint # Check [test_basic.py](./test_basic.html) to get some more details # about the endpoint. - bdb = BigchainDB(os.environ.get('PLANETMINT_ENDPOINT')) + bdb = Planetmint(os.environ.get('PLANETMINT_ENDPOINT')) # Here's Alice. alice = generate_keypair() diff --git a/acceptance/python/src/test_stream.py b/acceptance/python/src/test_stream.py index c82f43d..c6d037b 100644 --- a/acceptance/python/src/test_stream.py +++ b/acceptance/python/src/test_stream.py @@ -27,8 +27,8 @@ from uuid import uuid4 # [websocket](https://github.com/websocket-client/websocket-client) module from websocket import create_connection -from bigchaindb_driver import BigchainDB -from bigchaindb_driver.crypto import generate_keypair +from planetmint_driver import Planetmint +from planetmint_driver.crypto import generate_keypair def test_stream(): @@ -40,7 +40,7 @@ def test_stream(): # *That's pretty bad, but let's do like this for now.* WS_ENDPOINT = 'ws://{}:9985/api/v1/streams/valid_transactions'.format(BDB_ENDPOINT.rsplit(':')[0]) - bdb = BigchainDB(BDB_ENDPOINT) + bdb = Planetmint(BDB_ENDPOINT) # Hello to Alice again, she is pretty active in those tests, good job # Alice! diff --git a/docs/root/source/contributing/index.rst b/docs/root/source/contributing/index.rst index a6fc866..cf0b606 100644 --- a/docs/root/source/contributing/index.rst +++ b/docs/root/source/contributing/index.rst @@ -11,7 +11,7 @@ There are many ways you can contribute to Planetmint. It includes several sub-projects. - `Planetmint Server `_ -- `Planetmint Python Driver `_ +- `Planetmint Python Driver `_ - `Planetmint JavaScript Driver `_ - `Planetmint Java Driver `_ - `cryptoconditions `_ (a Python package by us) diff --git a/docs/root/source/contributing/ways-to-contribute/report-a-bug.md b/docs/root/source/contributing/ways-to-contribute/report-a-bug.md index 9d3c37a..fadc345 100644 --- a/docs/root/source/contributing/ways-to-contribute/report-a-bug.md +++ b/docs/root/source/contributing/ways-to-contribute/report-a-bug.md @@ -22,7 +22,6 @@ People ask questions about Planetmint in the following places: - Gitter - [planetmint/planetmint](https://gitter.im/planetmint/community) - - [planetmint/js-planetmint-driver](https://gitter.im/planetmint/community)) - [Twitter](https://twitter.com/planetmint) - [Stack Overflow "planetmint"](https://stackoverflow.com/search?q=planetmint) diff --git a/docs/root/source/contributing/ways-to-contribute/write-docs.md b/docs/root/source/contributing/ways-to-contribute/write-docs.md index b67f82e..d223243 100644 --- a/docs/root/source/contributing/ways-to-contribute/write-docs.md +++ b/docs/root/source/contributing/ways-to-contribute/write-docs.md @@ -19,7 +19,7 @@ If you're writing code, you should also update any related docs. However, you mi You can certainly do that! - The docs for Planetmint Server live under ``planetmint/docs/`` in the ``planetmint/planetmint`` repo. -- There are docs for the Python driver under ``bigchaindb-driver/docs/`` in the ``planetmint/bigchaindb-driver`` repo. +- There are docs for the Python driver under ``planetmint-driver/docs/`` in the ``planetmint/planetmint-driver`` repo. - There are docs for the JavaScript driver under ``planetmint/js-bigchaindb-driver`` in the ``planetmint/js-bigchaindb-driver`` repo. - The source code for the Planetmint website is in a private repo, but we can give you access if you ask. diff --git a/docs/root/source/korean/query-ko.md b/docs/root/source/korean/query-ko.md index 0fc08c6..3819068 100644 --- a/docs/root/source/korean/query-ko.md +++ b/docs/root/source/korean/query-ko.md @@ -205,10 +205,6 @@ Tendermint voting 파워가 0인 노드인 추종자 노드를 생성할 수 있 [MongoDB node.js 드라이버](https://mongodb.github.io/node-mongodb-native/?jmp=docs)와 같은 MongoDB 드라이버를 사용하여 다음 중 하나를 사용하여 노드의 MongoDB 데이터베이스에 연결할 수 있습니다. 여기 자바스크립트 쿼리 코드에 대한 링크가 있습니다. -<<<<<<< HEAD -- [The Planetmint JavaScript/Node.js driver source code](https://github.com/planetmint/js-bigchaindb-driver) -======= -- [The Planetmint JavaScript/Node.js driver source code](https://github.com/planetmint/js-planetmint-driver) ->>>>>>> 3bfc3298f8210b135084e823eedd47f213538088 -- [Example code by @manolodewiner](https://github.com/manolodewiner/query-mongodb-planetmint/blob/master/queryMongo.js) -- [More example code by @manolodewiner](https://github.com/planetmint/planetmint/issues/2315#issuecomment-392724279) \ No newline at end of file +- [The Planetmint JavaScript/Node.js driver source code](https://github.com/bigchaindb/js-bidchaindb-driver) +- [Example code by @manolodewiner](https://github.com/manolodewiner/query-mongodb-bigchaindb/blob/master/queryMongo.js) +- [More example code by @manolodewiner](https://github.com/bigchaindb/bigchaindb/issues/2315#issuecomment-392724279) \ No newline at end of file diff --git a/k8s/toolbox/Dockerfile b/k8s/toolbox/Dockerfile index 9c9f783..d4c7d4a 100644 --- a/k8s/toolbox/Dockerfile +++ b/k8s/toolbox/Dockerfile @@ -9,8 +9,8 @@ WORKDIR / RUN apk add --no-cache --update curl bind-tools python3-dev g++ \ libffi-dev make vim git nodejs openssl-dev \ && pip3 install ipython \ - && git clone https://github.com/bigchaindb/bigchaindb-driver \ - && cd bigchaindb-driver \ + && git clone https://github.com/planetmint/planetmint-driver \ + && cd planetmint-driver \ && pip3 install -e . \ && npm install -g wsc ENTRYPOINT ["/bin/sh"] diff --git a/setup.py b/setup.py index f6f80c1..f837710 100644 --- a/setup.py +++ b/setup.py @@ -16,6 +16,9 @@ from setuptools import setup, find_packages if sys.version_info < (3, 9): sys.exit('Please use Python version 3.9 or higher.') +with open('README.md') as readme_file: + readme = readme_file.read() + # get the version version = {} with open('planetmint/version.py') as fp: @@ -59,7 +62,6 @@ tests_require = [ 'flake8', 'flake8-quotes==0.8.1', 'hypothesis>=5.3.0', - # Removed pylint because its GPL license isn't Apache2-compatible 'pytest>=3.0.0', 'pytest-cov==2.8.1', 'pytest-mock', @@ -74,7 +76,7 @@ install_requires = [ 'chardet==3.0.4', 'aiohttp==3.7.4', 'abci==0.8.3', - 'cryptoconditions==0.8.1', + 'planetmint-cryptoconditions>=0.9.0', 'flask-cors==3.0.10', 'flask-restful==0.3.9', 'flask==2.0.1', @@ -97,20 +99,12 @@ setup( name='Planetmint', version=version['__version__'], description='Planetmint: The Blockchain Database', - long_description=( - "Planetmint allows developers and enterprises to deploy blockchain " - "proof-of-concepts, platforms and applications with a blockchain " - "database. Planetmint supports a wide range of industries and use cases " - "from identity and intellectual property to supply chains, energy, IoT " - "and financial ecosystems. With high throughput, low latency, powerful " - "query functionality, decentralized control, immutable data storage and " - "built-in asset support, Planetmint is like a database with blockchain " - "characteristics." - ), + long_description=readme, + long_description_content_type='text/markdown', url='https://github.com/Planetmint/planetmint/', author='Planetmint Contributors', author_email='contact@ipdb.global', - license='Apache Software License 2.0', + license='AGPLv3', zip_safe=False, python_requires='>=3.9', classifiers=[ From 20505e16694f90cb0a599b884e4d1b57a4a22363 Mon Sep 17 00:00:00 2001 From: Sangat Das Date: Thu, 3 Feb 2022 16:15:41 +0530 Subject: [PATCH 13/93] Update conftest.py --- tests/conftest.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index df99a4d..67d31d3 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,7 +9,6 @@ Tasks: 1. setup test database before starting the tests 2. delete test database after running the tests """ -import asyncio import json import os import copy From afbffd380e68ba7131f93e46b80e3ab9a1edef2d Mon Sep 17 00:00:00 2001 From: Sangat Das Date: Thu, 3 Feb 2022 12:34:14 +0000 Subject: [PATCH 14/93] Revert aiohttp upgrade --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index c2380de..789a402 100644 --- a/setup.py +++ b/setup.py @@ -74,7 +74,7 @@ tests_require = [ install_requires = [ 'chardet==3.0.4', - 'aiohttp==3.8.1', + 'aiohttp==3.7.4', 'bigchaindb-abci==1.0.7', 'planetmint-cryptoconditions>=0.9.0', 'flask-cors==3.0.10', From 0fdca70c38b6da0c3e1388dd5fac13e84e9115f8 Mon Sep 17 00:00:00 2001 From: ArpitShukla007 Date: Fri, 4 Feb 2022 07:24:57 +0000 Subject: [PATCH 15/93] Solved linting errors. --- planetmint/core.py | 34 +++---------------- planetmint/parallel_validation.py | 23 ++----------- planetmint/start.py | 2 +- .../upsert_validator/validator_utils.py | 4 +-- tests/conftest.py | 9 ++--- tests/tendermint/test_core.py | 4 +-- tests/tendermint/test_integration.py | 2 +- tests/test_core.py | 2 +- 8 files changed, 15 insertions(+), 65 deletions(-) diff --git a/planetmint/core.py b/planetmint/core.py index b65515d..7cc9a9c 100644 --- a/planetmint/core.py +++ b/planetmint/core.py @@ -8,38 +8,20 @@ with Tendermint. """ import logging import sys -import enum from tendermint.abci import types_pb2 from abci.application import BaseApplication from abci.application import OkCode from tendermint.abci.types_pb2 import ( - RequestInfo, ResponseInfo, - RequestInitChain, ResponseInitChain, ResponseCheckTx, ResponseDeliverTx, - RequestQuery, - ResponseQuery, - RequestBeginBlock, ResponseBeginBlock, - RequestEndBlock, ResponseEndBlock, - ResponseCommit, - RequestLoadSnapshotChunk, - ResponseLoadSnapshotChunk, - RequestListSnapshots, - ResponseListSnapshots, - RequestOfferSnapshot, - ResponseOfferSnapshot, - RequestApplySnapshotChunk, - ResponseApplySnapshotChunk, + ResponseCommit ) - from planetmint import Planetmint from planetmint.elections.election import Election -from planetmint.version import __tm_supported_versions__ -from planetmint.utils import tendermint_version_is_compatible from planetmint.tendermint_utils import (decode_transaction, calculate_hash) from planetmint.lib import Block @@ -80,17 +62,14 @@ class App(BaseApplication): def abort_if_abci_chain_is_not_synced(self): if self.chain is None or self.chain['is_synced']: return - validators = self.planetmint_node.get_validators() self.log_abci_migration_error(self.chain['chain_id'], validators) sys.exit(1) def init_chain(self, genesis): """Initialize chain upon genesis or a migration""" - app_hash = '' height = 0 - known_chain = self.planetmint_node.get_latest_abci_chain() if known_chain is not None: chain_id = known_chain['chain_id'] @@ -100,26 +79,21 @@ class App(BaseApplication): f'the chain {chain_id} is already synced.') logger.error(msg) sys.exit(1) - if chain_id != genesis.chain_id: validators = self.planetmint_node.get_validators() self.log_abci_migration_error(chain_id, validators) sys.exit(1) - # set migration values for app hash and height block = self.planetmint_node.get_latest_block() app_hash = '' if block is None else block['app_hash'] height = 0 if block is None else block['height'] + 1 - known_validators = self.planetmint_node.get_validators() validator_set = [vutils.decode_validator(v) for v in genesis.validators] - if known_validators and known_validators != validator_set: self.log_abci_migration_error(known_chain['chain_id'], known_validators) sys.exit(1) - block = Block(app_hash=app_hash, height=height, transactions=[]) self.planetmint_node.store_block(block._asdict()) self.planetmint_node.store_validator_set(height + 1, validator_set) @@ -136,12 +110,12 @@ class App(BaseApplication): self.abort_if_abci_chain_is_not_synced() # Check if Planetmint supports the Tendermint version - #if not (hasattr(request, 'version') and tendermint_version_is_compatible(request.version)): + # if not (hasattr(request, 'version') and tendermint_version_is_compatible(request.version)): # logger.error(f'Unsupported Tendermint version: {getattr(request, "version", "no version")}.' # f' Currently, Planetmint only supports {__tm_supported_versions__}. Exiting!') # sys.exit(1) - #logger.info(f"Tendermint version: {request.version}") + # logger.info(f"Tendermint version: {request.version}") r = ResponseInfo() block = self.planetmint_node.get_latest_block() @@ -182,7 +156,7 @@ class App(BaseApplication): self.abort_if_abci_chain_is_not_synced() chain_shift = 0 if self.chain is None else self.chain['height'] - #req_begin_block.header.num_txs not found, so removing it. + # req_begin_block.header.num_txs not found, so removing it. logger.debug('BEGIN BLOCK, height:%s', req_begin_block.header.height + chain_shift) diff --git a/planetmint/parallel_validation.py b/planetmint/parallel_validation.py index f5e530a..77c4a02 100644 --- a/planetmint/parallel_validation.py +++ b/planetmint/parallel_validation.py @@ -11,27 +11,8 @@ from planetmint.lib import Planetmint from planetmint.tendermint_utils import decode_transaction from abci.application import OkCode from tendermint.abci.types_pb2 import ( - RequestInfo, - ResponseInfo, - RequestInitChain, - ResponseInitChain, - #ResponseCheckTx, - #ResponseDeliverTx, - RequestQuery, - ResponseQuery, - RequestBeginBlock, - ResponseBeginBlock, - RequestEndBlock, - ResponseEndBlock, - ResponseCommit, - RequestLoadSnapshotChunk, - ResponseLoadSnapshotChunk, - RequestListSnapshots, - ResponseListSnapshots, - RequestOfferSnapshot, - ResponseOfferSnapshot, - RequestApplySnapshotChunk, - ResponseApplySnapshotChunk, + ResponseCheckTx, + ResponseDeliverTx, ) diff --git a/planetmint/start.py b/planetmint/start.py index 018ff2c..24dc356 100644 --- a/planetmint/start.py +++ b/planetmint/start.py @@ -66,7 +66,7 @@ def start(args): setproctitle.setproctitle('planetmint') # Start the ABCIServer - #abci = ABCI(TmVersion(planetmint.config['tendermint']['version'])) + # abci = ABCI(TmVersion(planetmint.config['tendermint']['version'])) if args.experimental_parallel_validation: app = ABCIServer( app=ParallelValidationApp( diff --git a/planetmint/upsert_validator/validator_utils.py b/planetmint/upsert_validator/validator_utils.py index 1fc0e5a..69293c2 100644 --- a/planetmint/upsert_validator/validator_utils.py +++ b/planetmint/upsert_validator/validator_utils.py @@ -1,12 +1,10 @@ import base64 import binascii import codecs -import enum -import planetmint from tendermint.abci import types_pb2 from tendermint.crypto import keys_pb2 -from planetmint.common.exceptions import InvalidPublicKey, BigchainDBError +from planetmint.common.exceptions import InvalidPublicKey def encode_validator(v): ed25519_public_key = v['public_key']['value'] diff --git a/tests/conftest.py b/tests/conftest.py index 35ef0c1..4bcd4ef 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -31,7 +31,7 @@ from planetmint.common.crypto import (key_pair_from_ed25519_key, from planetmint.common.exceptions import DatabaseDoesNotExist from planetmint.lib import Block from tests.utils import gen_vote -import tests.tendermint.conftest +# import tests.tendermint.conftest TEST_DB_NAME = 'planetmint_test' @@ -236,7 +236,7 @@ def merlin(): @pytest.fixture -#def a(): +# def a(): def abci_fixture(): from tendermint.abci import types_pb2 return types_pb2 @@ -252,12 +252,9 @@ def eventqueue_fixture(): from multiprocessing import Queue return Queue() - - @pytest.fixture def b_mock(b, network_validators): b.get_validators = mock_get_validators(network_validators) - return b @@ -450,7 +447,7 @@ def event_loop(): @pytest.fixture(scope='session') def abci_server(): from abci.server import ABCIServer - from tendermint.abci import types_pb2 as types_v0_34_11 + # from tendermint.abci import types_pb2 as types_v0_34_11 from planetmint.core import App from planetmint.utils import Process diff --git a/tests/tendermint/test_core.py b/tests/tendermint/test_core.py index 623e438..5f54a1b 100644 --- a/tests/tendermint/test_core.py +++ b/tests/tendermint/test_core.py @@ -8,7 +8,7 @@ import pytest import random from tendermint.abci import types_pb2 as types -from tendermint.crypto import keys_pb2 +from tendermint.crypto import keys_pb2 from planetmint import App from planetmint.backend.localmongodb import query @@ -248,7 +248,7 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(b, init_chain_reque .sign([alice.private_key]) app = App(b, events) - + app.init_chain(init_chain_request) begin_block = types.RequestBeginBlock() diff --git a/tests/tendermint/test_integration.py b/tests/tendermint/test_integration.py index 17f58a2..a57a3b2 100644 --- a/tests/tendermint/test_integration.py +++ b/tests/tendermint/test_integration.py @@ -5,7 +5,7 @@ import codecs -from tendermint.abci import types_pb2 as types +from tendermint.abci import types_pb2 as types import json import pytest diff --git a/tests/test_core.py b/tests/test_core.py index 98bab73..a5cd47c 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -543,4 +543,4 @@ def test_commit_aborts_if_chain_is_not_synced(b): b.store_abci_chain(0, 'chain-XYZ', False) with pytest.raises(SystemExit): - App(b).commit() \ No newline at end of file + App(b).commit() From ddc26a0f7866aa03d07a461843979da68a11aa0d Mon Sep 17 00:00:00 2001 From: ArpitShukla007 Date: Fri, 4 Feb 2022 08:02:22 +0000 Subject: [PATCH 16/93] Solved linting errors. --- planetmint/core.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/planetmint/core.py b/planetmint/core.py index 7cc9a9c..143bd55 100644 --- a/planetmint/core.py +++ b/planetmint/core.py @@ -8,7 +8,7 @@ with Tendermint. """ import logging import sys -from tendermint.abci import types_pb2 +from tendermint.abci import types_pb2 from abci.application import BaseApplication from abci.application import OkCode from tendermint.abci.types_pb2 import ( @@ -41,7 +41,7 @@ class App(BaseApplication): """ def __init__(self, planetmint_node=None, events_queue=None): - #super().__init__(abci) + # super().__init__(abci) logger.debug('Checking values of types') logger.debug(dir(types_pb2)) self.events_queue = events_queue @@ -52,7 +52,6 @@ class App(BaseApplication): self.validators = None self.new_height = None self.chain = self.planetmint_node.get_latest_abci_chain() - def log_abci_migration_error(self, chain_id, validators): logger.error('An ABCI chain migration is in process. ' @@ -98,8 +97,7 @@ class App(BaseApplication): self.planetmint_node.store_block(block._asdict()) self.planetmint_node.store_validator_set(height + 1, validator_set) abci_chain_height = 0 if known_chain is None else known_chain['height'] - self.planetmint_node.store_abci_chain(abci_chain_height, - genesis.chain_id, True) + self.planetmint_node.store_abci_chain(abci_chain_height, genesis.chain_id, True) self.chain = {'height': abci_chain_height, 'is_synced': True, 'chain_id': genesis.chain_id} return ResponseInitChain() @@ -156,7 +154,7 @@ class App(BaseApplication): self.abort_if_abci_chain_is_not_synced() chain_shift = 0 if self.chain is None else self.chain['height'] - # req_begin_block.header.num_txs not found, so removing it. + # req_begin_block.header.num_txs not found, so removing it. logger.debug('BEGIN BLOCK, height:%s', req_begin_block.header.height + chain_shift) From 797abae55c8d60e4c74f8c78e6770058b2c7db9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Fri, 4 Feb 2022 14:43:44 +0100 Subject: [PATCH 17/93] fixed flake varialbe resultion/resolving issue --- tests/conftest.py | 14 +++++++++++++- tests/test_core.py | 3 +-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 4bcd4ef..af49f42 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -14,6 +14,7 @@ import os import copy import random import tempfile +import codecs from collections import namedtuple from logging import getLogger from logging.config import dictConfig @@ -31,7 +32,9 @@ from planetmint.common.crypto import (key_pair_from_ed25519_key, from planetmint.common.exceptions import DatabaseDoesNotExist from planetmint.lib import Block from tests.utils import gen_vote -# import tests.tendermint.conftest + +from tendermint.abci import types_pb2 as types +from tendermint.crypto import keys_pb2 TEST_DB_NAME = 'planetmint_test' @@ -42,6 +45,15 @@ USER_PRIVATE_KEY = '8eJ8q9ZQpReWyQT5aFCiwtZ5wDZC4eDnCen88p3tQ6ie' USER_PUBLIC_KEY = 'JEAkEJqLbbgDRAtMm8YAjGp759Aq2qTn9eaEHUj2XePE' +@pytest.fixture +def init_chain_request(): + pk = codecs.decode(b'VAgFZtYw8bNR5TMZHFOBDWk9cAmEu3/c6JgRBmddbbI=', + 'base64') + val_a = types.ValidatorUpdate(power=10, + pub_key=keys_pb2.PublicKey(ed25519=pk)) + return types.RequestInitChain(validators=[val_a]) + + def pytest_addoption(parser): from planetmint.backend.connection import BACKENDS diff --git a/tests/test_core.py b/tests/test_core.py index a5cd47c..6d61344 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -25,7 +25,6 @@ from planetmint.tendermint_utils import public_key_to_base64 from planetmint.version import __tm_supported_versions__ from tests.utils import generate_election, generate_validators -from tests.tendermint.conftest import init_chain_request pytestmark = pytest.mark.bdb @@ -334,7 +333,7 @@ def test_deliver_transfer_tx__double_spend_fails(b, init_chain_request): .sign([alice.private_key]) result = app.deliver_tx(encode_tx_to_bytes(tx_transfer)) - assert result.code == OkCode + assert result.code == OkCode double_spend = Transaction.transfer(tx.to_inputs(), [([carly.public_key], 1)], From 339b38b12367ab9c005e59b64f7fb8c3acc6b6ea Mon Sep 17 00:00:00 2001 From: LaurentDeMontBlanc Date: Mon, 7 Feb 2022 12:32:31 +0100 Subject: [PATCH 18/93] added integration tests incl docker-compose and travis-ci setup --- .ci/travis_script.sh | 2 + Makefile | 5 +- docker-compose.yml | 8 +++ integration/README.md | 0 integration/python/Dockerfile | 6 ++ integration/python/src/test_basic.py | 92 ++++++++++++++++++++++++++++ run-integration-test.sh | 37 +++++++++++ 7 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 integration/README.md create mode 100644 integration/python/Dockerfile create mode 100644 integration/python/src/test_basic.py create mode 100755 run-integration-test.sh diff --git a/.ci/travis_script.sh b/.ci/travis_script.sh index 436805c..5cf1d43 100755 --- a/.ci/travis_script.sh +++ b/.ci/travis_script.sh @@ -13,6 +13,8 @@ elif [[ ${PLANETMINT_CI_ABCI} == 'enable' ]]; then docker-compose exec planetmint pytest -v -m abci elif [[ ${PLANETMINT_ACCEPTANCE_TEST} == 'enable' ]]; then ./run-acceptance-test.sh +elif [[ ${PLANETMINT_INTEGRATION_TEST} == 'enable' ]]; then + ./run-integration-test.sh else docker-compose exec planetmint pytest -v --cov=planetmint --cov-report xml:htmlcov/coverage.xml fi diff --git a/Makefile b/Makefile index 7f09890..6e5327f 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: help run start stop logs test test-unit test-unit-watch test-acceptance cov doc doc-acceptance clean reset release dist check-deps clean-build clean-pyc clean-test +.PHONY: help run start stop logs test test-unit test-unit-watch test-acceptance test-integration cov doc doc-acceptance clean reset release dist check-deps clean-build clean-pyc clean-test .DEFAULT_GOAL := help @@ -82,6 +82,9 @@ test-unit-watch: check-deps ## Run all tests and wait. Every time you change cod test-acceptance: check-deps ## Run all acceptance tests @./run-acceptance-test.sh +test-integration: check-deps ## Run all integration tests + @./run-integration-test.sh + cov: check-deps ## Check code coverage and open the result in the browser @$(DC) run --rm planetmint pytest -v --cov=planetmint --cov-report html $(BROWSER) htmlcov/index.html diff --git a/docker-compose.yml b/docker-compose.yml index 01f537d..da89284 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -83,6 +83,14 @@ services: environment: - PLANETMINT_ENDPOINT=planetmint + # Planetmint setup to do integration testing wtih Python + python-integration: + build: + context: . + dockerfile: ./integration/python/Dockerfile + volumes: + - ./integration/python/src:/src + # Build docs only # docker-compose build bdocs # docker-compose up -d bdocs diff --git a/integration/README.md b/integration/README.md new file mode 100644 index 0000000..e69de29 diff --git a/integration/python/Dockerfile b/integration/python/Dockerfile new file mode 100644 index 0000000..109d83f --- /dev/null +++ b/integration/python/Dockerfile @@ -0,0 +1,6 @@ +FROM python:3.9 + +RUN mkdir -p /src +RUN pip install --upgrade \ + pytest~=6.2.5 \ + planetmint-driver~=0.9.0 \ No newline at end of file diff --git a/integration/python/src/test_basic.py b/integration/python/src/test_basic.py new file mode 100644 index 0000000..5cd3b57 --- /dev/null +++ b/integration/python/src/test_basic.py @@ -0,0 +1,92 @@ +# import Planetmint and create object +from planetmint_driver import Planetmint +from planetmint_driver.crypto import generate_keypair +import time + +def test_basic(): + # Setup up connection to Planetmint integration test nodes + pm_itest1_url = 'https://itest1.planetmint.io' + pm_itest2_url = 'https://itest2.planetmint.io' + pm_itest1 = Planetmint(pm_itest1_url) + pm_itest2 = Planetmint(pm_itest2_url) + + # genarate a keypair + alice, bob = generate_keypair(), generate_keypair() + + # create a digital asset for Alice + game_boy_token = { + 'data': { + 'hash': '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', + 'storageID': '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', + }, + } + + # prepare the transaction with the digital asset and issue 10 tokens to bob + prepared_creation_tx = pm_itest1.transactions.prepare( + operation='CREATE', + metadata={ + 'hash': '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', + 'storageID': '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',}, + signers=alice.public_key, + recipients=[([alice.public_key], 10)], + asset=game_boy_token) + + # fulfill and send the transaction + fulfilled_creation_tx = pm_itest1.transactions.fulfill( + prepared_creation_tx, + private_keys=alice.private_key) + pm_itest1.transactions.send_commit(fulfilled_creation_tx) + time.sleep(4) + + creation_tx_id = fulfilled_creation_tx['id'] + + # retrieve transactions from both planetmint nodes + creation_tx_itest1 = pm_itest1.transactions.retrieve(creation_tx_id) + creation_tx_itest2 = pm_itest2.transactions.retrieve(creation_tx_id) + + # Assert that transaction is stored on both planetmint nodes + assert creation_tx_itest1 == creation_tx_itest2 + + # Transfer + # create the output and inout for the transaction + transfer_asset = {'id': creation_tx_id} + output_index = 0 + output = fulfilled_creation_tx['outputs'][output_index] + transfer_input = {'fulfillment': output['condition']['details'], + 'fulfills': {'output_index': output_index, + 'transaction_id': transfer_asset['id']}, + 'owners_before': output['public_keys']} + + # prepare the transaction and use 3 tokens + prepared_transfer_tx = pm_itest1.transactions.prepare( + operation='TRANSFER', + asset=transfer_asset, + inputs=transfer_input, + metadata={'hash': '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', + 'storageID': '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', }, + recipients=[([alice.public_key], 10)]) + + # fulfill and send the transaction + fulfilled_transfer_tx = pm_itest1.transactions.fulfill( + prepared_transfer_tx, + private_keys=alice.private_key) + sent_transfer_tx = pm_itest1.transactions.send_commit(fulfilled_transfer_tx) + + transfer_tx_id = fulfilled_transfer_tx['id'] + + # retrieve transactions from both planetmint nodes + transfer_tx_itest1 = pm_itest1.transactions.retrieve(transfer_tx_id) + transfer_tx_itest2 = pm_itest2.transactions.retrieve(transfer_tx_id) + + # Assert that transaction is stored on both planetmint nodes + assert transfer_tx_itest1 == transfer_tx_itest2 + + + + + + + + + + diff --git a/run-integration-test.sh b/run-integration-test.sh new file mode 100755 index 0000000..506bc24 --- /dev/null +++ b/run-integration-test.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + + +# Set up a Planetmint node and return only when we are able to connect to both +# the Planetmint container *and* the Tendermint container. +setup () { + docker-compose up -d planetmint + + # Try to connect to the containers for maximum three times, and wait + # one second between tries. + for i in $(seq 3); do + if $(docker-compose run --rm curl-client); then + break + else + sleep 1 + fi + done +} + +run_test () { + docker-compose run --rm python-integration pytest /src/test_basic.py +} + +teardown () { + docker-compose down +} + +setup +run_test +exitcode=$? +teardown + +exit $exitcode \ No newline at end of file From 894dd7526c9205b98f76b4667138e4f804b8318c Mon Sep 17 00:00:00 2001 From: LaurentDeMontBlanc Date: Mon, 7 Feb 2022 12:47:45 +0100 Subject: [PATCH 19/93] run all tests in integration directory --- run-integration-test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run-integration-test.sh b/run-integration-test.sh index 506bc24..c24d725 100755 --- a/run-integration-test.sh +++ b/run-integration-test.sh @@ -22,7 +22,7 @@ setup () { } run_test () { - docker-compose run --rm python-integration pytest /src/test_basic.py + docker-compose run --rm python-integration pytest /src } teardown () { From f108b511d88ccf398e1a3baf207e5b0cec360409 Mon Sep 17 00:00:00 2001 From: LaurentDeMontBlanc Date: Mon, 7 Feb 2022 13:05:32 +0100 Subject: [PATCH 20/93] enabled integration tests in travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index e13715a..e1ec9c3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,6 +38,7 @@ matrix: - python: 3.9 env: - PLANETMINT_ACCEPTANCE_TEST=enable + - PLANETMINT_INTEGRATION_TEST=enable before_install: sudo .ci/travis-before-install.sh From e203fc5e39a2323f8db42dc0b7a3e6365ed26258 Mon Sep 17 00:00:00 2001 From: LaurentDeMontBlanc Date: Mon, 7 Feb 2022 16:19:39 +0100 Subject: [PATCH 21/93] added README, added check_status to run-integration-test.sh --- integration/README.md | 15 +++++++++++++++ run-integration-test.sh | 26 ++++++++++++-------------- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/integration/README.md b/integration/README.md index e69de29..8982e03 100644 --- a/integration/README.md +++ b/integration/README.md @@ -0,0 +1,15 @@ +# Integration test suite +This directory contains the integration test suite for Planetmint. + +The suite uses Docker Compose to run all tests. + +## Running the tests +Run `make test-integration` in the project root directory. + +During development you can run single test use `pytest` inside the `python-integration` container with: + +```bash +docker-compose run --rm python-integration pytest +``` + +Note: The `/src` directory contains all the test within the container. diff --git a/run-integration-test.sh b/run-integration-test.sh index c24d725..6c0d3be 100755 --- a/run-integration-test.sh +++ b/run-integration-test.sh @@ -5,20 +5,18 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 -# Set up a Planetmint node and return only when we are able to connect to both -# the Planetmint container *and* the Tendermint container. -setup () { - docker-compose up -d planetmint +# Check if both integration test nodes are reachable +check_status () { + OK="200 OK" - # Try to connect to the containers for maximum three times, and wait - # one second between tries. - for i in $(seq 3); do - if $(docker-compose run --rm curl-client); then - break - else - sleep 1 - fi - done + STATUS_1=$(curl -I -s -X GET https://itest1.planetmint.io/ | head -n 1) + STATUS_2=$(curl -I -s -X GET https://itest2.planetmint.io/ | head -n 1) + + # Check if both response status codes return 200 OK + if ! [[ "$STATUS_1" == *"$OK"* ]] || ! [[ "$STATUS_2" == *"$OK"* ]] + then + exit 1 + fi } run_test () { @@ -29,7 +27,7 @@ teardown () { docker-compose down } -setup +check_status run_test exitcode=$? teardown From e4feac2fd6e901913be2151f603d3a2a75d8688c Mon Sep 17 00:00:00 2001 From: ArpitShukla007 Date: Mon, 7 Feb 2022 15:32:33 +0000 Subject: [PATCH 22/93] Added initial support for Tendermint v0.34.15 --- Dockerfile-all-in-one | 2 +- docker-compose.yml | 2 +- .../run-node-as-processes.md | 6 +++--- .../network-setup/k8s-deployment-template/workflow.rst | 2 +- k8s/planetmint/tendermint_container/Dockerfile | 2 +- pkg/scripts/stack.sh | 2 +- planetmint/__init__.py | 2 +- planetmint/version.py | 2 +- tests/test_config_utils.py | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Dockerfile-all-in-one b/Dockerfile-all-in-one index 736934c..d8ff513 100644 --- a/Dockerfile-all-in-one +++ b/Dockerfile-all-in-one @@ -1,7 +1,7 @@ FROM alpine:3.9 LABEL maintainer "contact@ipdb.global" -ARG TM_VERSION=v0.34.11 +ARG TM_VERSION=v0.34.15 RUN mkdir -p /usr/src/app ENV HOME /root COPY . /usr/src/app/ diff --git a/docker-compose.yml b/docker-compose.yml index 01f537d..2e99e17 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -51,7 +51,7 @@ services: command: '.ci/entrypoint.sh' restart: always tendermint: - image: tendermint/tendermint:v0.34.11 + image: tendermint/tendermint:v0.34.15 # volumes: # - ./tmdata:/tendermint entrypoint: '' diff --git a/docs/root/source/contributing/dev-setup-coding-and-contribution-process/run-node-as-processes.md b/docs/root/source/contributing/dev-setup-coding-and-contribution-process/run-node-as-processes.md index e5b04c5..58074ac 100644 --- a/docs/root/source/contributing/dev-setup-coding-and-contribution-process/run-node-as-processes.md +++ b/docs/root/source/contributing/dev-setup-coding-and-contribution-process/run-node-as-processes.md @@ -30,9 +30,9 @@ The version of Planetmint Server described in these docs only works well with Te ```bash $ sudo apt install -y unzip -$ wget https://github.com/tendermint/tendermint/releases/download/v0.34.11/tendermint_v0.34.11_linux_amd64.zip -$ unzip tendermint_v0.34.11_linux_amd64.zip -$ rm tendermint_v0.34.11_linux_amd64.zip +$ wget https://github.com/tendermint/tendermint/releases/download/v0.34.15/tendermint_v0.34.15_linux_amd64.zip +$ unzip tendermint_v0.34.15_linux_amd64.zip +$ rm tendermint_v0.34.15_linux_amd64.zip $ sudo mv tendermint /usr/local/bin ``` diff --git a/docs/root/source/installation/network-setup/k8s-deployment-template/workflow.rst b/docs/root/source/installation/network-setup/k8s-deployment-template/workflow.rst index 43e964f..1d0148f 100644 --- a/docs/root/source/installation/network-setup/k8s-deployment-template/workflow.rst +++ b/docs/root/source/installation/network-setup/k8s-deployment-template/workflow.rst @@ -60,7 +60,7 @@ you can do this: .. code:: $ mkdir $(pwd)/tmdata - $ docker run --rm -v $(pwd)/tmdata:/tendermint/config tendermint/tendermint:v0.34.11 init + $ docker run --rm -v $(pwd)/tmdata:/tendermint/config tendermint/tendermint:v0.34.15 init $ cat $(pwd)/tmdata/genesis.json You should see something that looks like: diff --git a/k8s/planetmint/tendermint_container/Dockerfile b/k8s/planetmint/tendermint_container/Dockerfile index 5795f81..91230fc 100644 --- a/k8s/planetmint/tendermint_container/Dockerfile +++ b/k8s/planetmint/tendermint_container/Dockerfile @@ -1,4 +1,4 @@ -FROM tendermint/tendermint:v0.34.11 +FROM tendermint/tendermint:v0.34.15 LABEL maintainer "contact@ipdb.global" WORKDIR / USER root diff --git a/pkg/scripts/stack.sh b/pkg/scripts/stack.sh index c84fa4d..ea774a0 100755 --- a/pkg/scripts/stack.sh +++ b/pkg/scripts/stack.sh @@ -17,7 +17,7 @@ stack_size=${STACK_SIZE:=4} stack_type=${STACK_TYPE:="docker"} stack_type_provider=${STACK_TYPE_PROVIDER:=""} # NOTE versions prior v0.28.0 have different priv_validator format! -tm_version=${TM_VERSION:="v0.34.11"} +tm_version=${TM_VERSION:="v0.34.15"} mongo_version=${MONGO_VERSION:="3.6"} stack_vm_memory=${STACK_VM_MEMORY:=2048} stack_vm_cpus=${STACK_VM_CPUS:=2} diff --git a/planetmint/__init__.py b/planetmint/__init__.py index 47c2643..7c3b977 100644 --- a/planetmint/__init__.py +++ b/planetmint/__init__.py @@ -71,7 +71,7 @@ config = { 'tendermint': { 'host': 'localhost', 'port': 26657, - 'version': 'v0.34.11', # look for __tm_supported_versions__ + 'version': 'v0.34.15', # look for __tm_supported_versions__ }, # FIXME: hardcoding to localmongodb for now 'database': _database_map['localmongodb'], diff --git a/planetmint/version.py b/planetmint/version.py index e77393e..1daef8f 100644 --- a/planetmint/version.py +++ b/planetmint/version.py @@ -7,4 +7,4 @@ __version__ = '0.9.0' __short_version__ = '0.9' # Supported Tendermint versions -__tm_supported_versions__ = ["0.34.11"] +__tm_supported_versions__ = ["0.34.15"] diff --git a/tests/test_config_utils.py b/tests/test_config_utils.py index a938a5f..4bcff77 100644 --- a/tests/test_config_utils.py +++ b/tests/test_config_utils.py @@ -221,7 +221,7 @@ def test_autoconfigure_read_both_from_file_and_env(monkeypatch, request): 'tendermint': { 'host': 'localhost', 'port': 26657, - 'version': 'v0.34.11' + 'version': 'v0.34.15' }, 'log': { 'file': LOG_FILE, From 5e708dd4f8b040ee6e7f2907c39cc019c93e0da2 Mon Sep 17 00:00:00 2001 From: LaurentDeMontBlanc Date: Tue, 8 Feb 2022 10:37:02 +0100 Subject: [PATCH 23/93] moved endpoint definition to docker-compose.yml, added copyright notice integration tests --- docker-compose.yml | 5 +- integration/python/src/test_basic.py | 11 +- integration/python/src/test_multisig.py | 138 ++++++++++++++++++++++++ 3 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 integration/python/src/test_multisig.py diff --git a/docker-compose.yml b/docker-compose.yml index da89284..331b4f1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -89,7 +89,10 @@ services: context: . dockerfile: ./integration/python/Dockerfile volumes: - - ./integration/python/src:/src + - ./integration/python/src:/src + environment: + - PLANETMINT_ENDPOINT_1=https://itest1.planetmint.io + - PLANETMINT_ENDPOINT_2=https://itest2.planetmint.io # Build docs only # docker-compose build bdocs diff --git a/integration/python/src/test_basic.py b/integration/python/src/test_basic.py index 5cd3b57..643f3d9 100644 --- a/integration/python/src/test_basic.py +++ b/integration/python/src/test_basic.py @@ -1,12 +1,19 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + # import Planetmint and create object from planetmint_driver import Planetmint from planetmint_driver.crypto import generate_keypair import time +import os + def test_basic(): # Setup up connection to Planetmint integration test nodes - pm_itest1_url = 'https://itest1.planetmint.io' - pm_itest2_url = 'https://itest2.planetmint.io' + pm_itest1_url = os.environ.get('PLANETMINT_ENDPOINT_1') + pm_itest2_url = os.environ.get('PLANETMINT_ENDPOINT_1') pm_itest1 = Planetmint(pm_itest1_url) pm_itest2 = Planetmint(pm_itest2_url) diff --git a/integration/python/src/test_multisig.py b/integration/python/src/test_multisig.py new file mode 100644 index 0000000..976fc90 --- /dev/null +++ b/integration/python/src/test_multisig.py @@ -0,0 +1,138 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +# # Multisignature integration testing +# This test checks if we can successfully create and transfer a transaction +# with multiple owners. +# The script tests various things like: +# +# - create a transaction with multiple owners +# - check if the transaction is stored and has the right amount of public keys +# - transfer the transaction to a third person +# +# We run a series of checks for each step, that is retrieving +# the transaction from the remote system, and also checking the public keys +# of a given transaction. +# +# This integration test is a rip-off of our mutliple signature acceptance tests. + +# ## Imports +# We need some utils from the `os` package, we will interact with +# env variables. +import os + +# For this test case we need import and use the Python driver +from planetmint_driver import Planetmint +from planetmint_driver.crypto import generate_keypair + +def test_multiple_owners(): + # ## Set up a connection to the Planetmint integration test nodes + pm_itest1 = Planetmint(os.environ.get('PLANETMINT_ENDPOINT_1')) + pm_itest2 = Planetmint(os.environ.get('PLANETMINT_ENDPOINT_2')) + + # Generate Keypairs for Alice and Bob! + alice, bob = generate_keypair(), generate_keypair() + + # ## Alice and Bob create a transaction + # Alice and Bob just moved into a shared flat, no one can afford these + # high rents anymore. Bob suggests to get a dish washer for the + # kitchen. Alice agrees and here they go, creating the asset for their + # dish washer. + dw_asset = { + 'data': { + 'dish washer': { + 'serial_number': 1337 + } + } + } + + # They prepare a `CREATE` transaction. To have multiple owners, both + # Bob and Alice need to be the recipients. + prepared_dw_tx = pm_itest1.transactions.prepare( + operation='CREATE', + signers=alice.public_key, + recipients=(alice.public_key, bob.public_key), + asset=dw_asset) + + # Now they both sign the transaction by providing their private keys. + # And send it afterwards. + fulfilled_dw_tx = pm_itest1.transactions.fulfill( + prepared_dw_tx, + private_keys=[alice.private_key, bob.private_key]) + + pm_itest1.transactions.send_commit(fulfilled_dw_tx) + + # We store the `id` of the transaction to use it later on. + dw_id = fulfilled_dw_tx['id'] + + # Let's retrieve the transaction from both nodes + pm_itest1_tx = pm_itest1.transactions.retrieve(dw_id) + pm_itest2_tx = pm_itest2.transactions.retrieve(dw_id) + + # Both retrieved transactions should be the same + assert pm_itest1_tx == pm_itest2_tx + + # Let's check if the transaction was successful. + assert pm_itest1.transactions.retrieve(dw_id), \ + 'Cannot find transaction {}'.format(dw_id) + + # The transaction should have two public keys in the outputs. + assert len( + pm_itest1.transactions.retrieve(dw_id)['outputs'][0]['public_keys']) == 2 + + # ## Alice and Bob transfer a transaction to Carol. + # Alice and Bob save a lot of money living together. They often go out + # for dinner and don't cook at home. But now they don't have any dishes to + # wash, so they decide to sell the dish washer to their friend Carol. + + # Hey Carol, nice to meet you! + carol = generate_keypair() + + # Alice and Bob prepare the transaction to transfer the dish washer to + # Carol. + transfer_asset = {'id': dw_id} + + output_index = 0 + output = fulfilled_dw_tx['outputs'][output_index] + transfer_input = {'fulfillment': output['condition']['details'], + 'fulfills': {'output_index': output_index, + 'transaction_id': fulfilled_dw_tx[ + 'id']}, + 'owners_before': output['public_keys']} + + # Now they create the transaction... + prepared_transfer_tx = pm_itest1.transactions.prepare( + operation='TRANSFER', + asset=transfer_asset, + inputs=transfer_input, + recipients=carol.public_key) + + # ... and sign it with their private keys, then send it. + fulfilled_transfer_tx = pm_itest1.transactions.fulfill( + prepared_transfer_tx, + private_keys=[alice.private_key, bob.private_key]) + + sent_transfer_tx = pm_itest1.transactions.send_commit(fulfilled_transfer_tx) + + # Retrieve the fulfilled transaction from both nodes + pm_itest1_tx = pm_itest1.transactions.retrieve(fulfilled_transfer_tx['id']) + pm_itest2_tx = pm_itest2.transactions.retrieve(fulfilled_transfer_tx['id']) + + # Now compare if both nodes returned the same transaction + assert pm_itest1_tx == pm_itest2_tx + + # They check if the transaction was successful. + assert pm_itest1.transactions.retrieve( + fulfilled_transfer_tx['id']) == sent_transfer_tx + + # The owners before should include both Alice and Bob. + assert len( + pm_itest1.transactions.retrieve(fulfilled_transfer_tx['id'])['inputs'][0][ + 'owners_before']) == 2 + + # While the new owner is Carol. + assert pm_itest1.transactions.retrieve(fulfilled_transfer_tx['id'])[ + 'outputs'][0]['public_keys'][0] == carol.public_key + \ No newline at end of file From e1222477eb5ce916a9b58439b520bab82240b27b Mon Sep 17 00:00:00 2001 From: LaurentDeMontBlanc Date: Wed, 9 Feb 2022 13:25:17 +0100 Subject: [PATCH 24/93] removed remnant of old integration tests --- .ci/travis-install.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/.ci/travis-install.sh b/.ci/travis-install.sh index 34df6e5..083f9bb 100755 --- a/.ci/travis-install.sh +++ b/.ci/travis-install.sh @@ -13,8 +13,6 @@ if [[ -n ${TOXENV} ]]; then pip install --upgrade tox elif [[ ${PLANETMINT_CI_ABCI} == 'enable' ]]; then docker-compose build --no-cache --build-arg abci_status=enable planetmint -elif [[ $PLANETMINT_INTEGRATION_TEST == 'enable' ]]; then - docker-compose build planetmint python-driver else docker-compose build --no-cache planetmint pip install --upgrade codecov From 8b07d05c60a00adf02f22a251006d193ec40117e Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger Date: Mon, 14 Feb 2022 09:37:21 +0100 Subject: [PATCH 25/93] added linting with flake8 --- Makefile | 3 +++ docker-compose.yml | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/Makefile b/Makefile index 6e5327f..b0b87b6 100644 --- a/Makefile +++ b/Makefile @@ -70,6 +70,9 @@ stop: check-deps ## Stop Planetmint logs: check-deps ## Attach to the logs @$(DC) logs -f planetmint +lint: check-deps ## Lint the Project + @$(DC) up lint + test: check-deps test-unit test-acceptance ## Run unit and acceptance tests test-unit: check-deps ## Run all tests once diff --git a/docker-compose.yml b/docker-compose.yml index 331b4f1..d5936c6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -114,3 +114,13 @@ services: - '33333:80' volumes: - ./docs/root/build/html:/usr/share/nginx/html + + # Lints project according to PEP8 + lint: + image: alpine/flake8 + command: --max-line-length 119 /planetmint /acceptance /integration /tests + volumes: + - ./planetmint:/planetmint + - ./acceptance:/acceptance + - ./integration:/integration + - ./tests:/tests \ No newline at end of file From f4e089c8a7163b2a39b896d90bc48f897a0b617f Mon Sep 17 00:00:00 2001 From: Sangat Das Date: Mon, 14 Feb 2022 08:39:08 +0000 Subject: [PATCH 26/93] Integrate zenroom acceptance test --- acceptance/python/Dockerfile | 3 +- acceptance/python/src/test_zenroom.py | 207 ++++++++++++++++++++++++++ 2 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 acceptance/python/src/test_zenroom.py diff --git a/acceptance/python/Dockerfile b/acceptance/python/Dockerfile index a106dcf..340841b 100644 --- a/acceptance/python/Dockerfile +++ b/acceptance/python/Dockerfile @@ -7,4 +7,5 @@ RUN pip install --upgrade \ websocket-client~=0.47.0 \ pytest~=3.0 \ planetmint-driver>=0.9.0 \ - blns + blns \ + planetmint-cryptoconditions>=0.9.0 diff --git a/acceptance/python/src/test_zenroom.py b/acceptance/python/src/test_zenroom.py new file mode 100644 index 0000000..323cdbb --- /dev/null +++ b/acceptance/python/src/test_zenroom.py @@ -0,0 +1,207 @@ +# GOAL: +# In this script I tried to implement the ECDSA signature using zenroom + +# However, the scripts are customizable and so with the same procedure +# we can implement more complex smart contracts + +# PUBLIC IDENTITY +# The public identity of the users in this script (Bob and Alice) +# is the pair (ECDH public key, Testnet address) + +import json + +import hashlib +from cryptoconditions import ZenroomSha256 +from json.decoder import JSONDecodeError + +# from zenroom import zencode_exec + +# from bigchaindb_driver import BigchainDB +# # bdb_root_url = 'https://ipdb3.riddleandcode.com' +# bdb_root_url = 'http://localhost:9984/' +# bdb = BigchainDB(bdb_root_url) + +# The procedure to generate the keyring cannot be +# fixed in the code base, it depends on the particular +# smart contract +GENERATE_KEYPAIR = \ + """Rule input encoding base58 + Rule output encoding base58 + Scenario 'ecdh': Create the keypair + Given that I am known as 'Pippo' + When I create the ecdh key + When I create the testnet key + Then print data""" + +def genkey(): + return json.loads(ZenroomSha256.run_zenroom(GENERATE_KEYPAIR).output)['keys'] + +# There is not a unique way of generating the public +# key, for example, for the testnet I don't want the +# public key but the address (but there could exist +# a script in which the user want the public key and +# not the address) +# Thus we cannot fix it inside the script + +# secret key to public key +SK_TO_PK = \ + """Rule input encoding base58 + Rule output encoding base58 + Scenario 'ecdh': Create the keypair + Given that I am known as '{}' + Given I have the 'keys' + When I create the ecdh public key + When I create the testnet address + Then print my 'ecdh public key' + Then print my 'testnet address'""" + +def sk2pk(name, keys): + return json.loads(ZenroomSha256.run_zenroom(SK_TO_PK.format(name), + keys={'keys': keys}).output) +# Alice assert the composition of the houses + +# zen_public_keys is an identity dictionary + +alice, bob = genkey(), genkey() +print("============== ALICE KEYPAIR =================") +print(alice) +print("============== BOB KEYPAIR =================") +print(bob) + +asset = { + "data": { + "houses": [ + { + "name": "Harry", + "team": "Gryffindor", + }, + { + "name": "Draco", + "team": "Slytherin", + } + ], + } +} +zen_public_keys = sk2pk('Alice', alice) +zen_public_keys.update(sk2pk('Bob', bob)) + +data = { + 'also': 'more data' +} +print("============== PUBLIC IDENTITIES =================") +print(zen_public_keys) + +metadata = { +} + +version = '2.0' + +fulfill_script = """Rule input encoding base58 +Rule output encoding base58 +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 'data.signature' inside 'result' +When I verify the 'houses' has a signature in 'data.signature' by 'Alice' +Then print the string 'ok' +""" +# CRYPTO-CONDITIONS: instantiate an Ed25519 crypto-condition for buyer +zenSha = ZenroomSha256(script=fulfill_script, keys=zen_public_keys, data=data) + +# CRYPTO-CONDITIONS: generate the condition uri +condition_uri = zenSha.condition.serialize_uri() +# CRYPTO-CONDITIONS: construct an unsigned fulfillment dictionary +unsigned_fulfillment_dict = { + 'type': zenSha.TYPE_NAME, + 'script': fulfill_script, + 'keys': zen_public_keys, +} + +output = { + 'amount': '1000', + 'condition': { + 'details': unsigned_fulfillment_dict, + 'uri': condition_uri, + }, + 'data': data, + 'script': fulfill_script, + 'conf': '', + 'public_keys': (zen_public_keys['Alice']['ecdh_public_key'], ), +} + + +input_ = { + 'fulfillment': None, + 'fulfills': None, + 'owners_before': (zen_public_keys['Alice']['ecdh_public_key'], ), +} + +token_creation_tx = { + 'operation': 'CREATE', + 'asset': asset, + 'metadata': None, + 'outputs': (output,), + 'inputs': (input_,), + 'version': version, + 'id': None, +} + +# JSON: serialize the transaction-without-id to a json formatted string +message = json.dumps( + token_creation_tx, + sort_keys=True, + separators=(',', ':'), + ensure_ascii=False, +) + +print("====== GENERATE RESULT (METADATA) =======") +condition_script = """Rule input encoding base58 + Rule output encoding base58 + Scenario 'ecdh': create the signature of an object + Given I have the 'keys' + Given that I have a 'string dictionary' named 'houses' inside 'asset' + When I create the signature of 'houses' + When I rename the 'signature' to 'data.signature' + Then print the 'data.signature' + """ + +# THIS FILLS THE METADATA WITH THE RESULT +try: + assert(not zenSha.validate(message=message)) +except JSONDecodeError: + pass +except ValueError: + pass + +message = zenSha.sign(message, condition_script, alice) +assert(zenSha.validate(message=message)) +# now metadata looks like +# 'metadata': {'result': {'data.signature': {'r': 'fdoan0GYo9RGP8y0fq+PKZ9Q1V8+VqJtBkSMB1tUnGQ=', 's': 'RnJCEepYJcVgFG/Y6cRc/2DWPaz5Pe5NpdRWegrZk5A='}}} + +# CRYPTO-CONDITIONS: generate the fulfillment uri +fulfillment_uri = zenSha.serialize_uri() + +# add the fulfillment uri (signature) +token_creation_tx['inputs'][0]['fulfillment'] = fulfillment_uri +print(token_creation_tx) + +# JSON: serialize the id-less transaction to a json formatted string +json_str_tx = json.dumps( + token_creation_tx, + sort_keys=True, + separators=(',', ':'), + ensure_ascii=False, +) + + +# SHA3: hash the serialized id-less transaction to generate the id +shared_creation_txid = hashlib.sha3_256(json_str_tx.encode()).hexdigest() + +# add the id +token_creation_tx['id'] = shared_creation_txid + +# exit() +# send CREATE tx into the bdb network +# returned_creation_tx = bdb.transactions.send_async(token_creation_tx) + +# print(returned_creation_tx) \ No newline at end of file From 5924633bc939f3eb0d943feb6547124db121c22d Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger Date: Mon, 14 Feb 2022 09:44:24 +0100 Subject: [PATCH 27/93] make clean now utilizes docker --- Makefile | 22 ++-------------------- docker-compose.yml | 8 +++++++- scripts/clean.sh | 26 ++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 21 deletions(-) create mode 100755 scripts/clean.sh diff --git a/Makefile b/Makefile index b0b87b6..71afc60 100644 --- a/Makefile +++ b/Makefile @@ -102,7 +102,8 @@ doc-acceptance: check-deps ## Create documentation for acceptance tests @$(DC) run --rm python-acceptance pycco -i -s /src -d /docs $(BROWSER) acceptance/python/docs/index.html -clean: clean-build clean-pyc clean-test ## Remove all build, test, coverage and Python artifacts +clean: check-deps ## Remove all build, test, coverage and Python artifacts + @$(DC) up clean @$(ECHO) "Cleaning was successful." reset: check-deps ## Stop and REMOVE all containers. WARNING: you will LOSE all data stored in Planetmint. @@ -129,22 +130,3 @@ ifndef IS_DOCKER_COMPOSE_INSTALLED @$(ECHO) @$(DC) # docker-compose is not installed, so we call it to generate an error and exit endif - -clean-build: # Remove build artifacts - @rm -fr build/ - @rm -fr dist/ - @rm -fr .eggs/ - @find . -name '*.egg-info' -exec rm -fr {} + - @find . -name '*.egg' -exec rm -f {} + - -clean-pyc: # Remove Python file artifacts - @find . -name '*.pyc' -exec rm -f {} + - @find . -name '*.pyo' -exec rm -f {} + - @find . -name '*~' -exec rm -f {} + - @find . -name '__pycache__' -exec rm -fr {} + - -clean-test: # Remove test and coverage artifacts - @find . -name '.pytest_cache' -exec rm -fr {} + - @rm -fr .tox/ - @rm -f .coverage - @rm -fr htmlcov/ diff --git a/docker-compose.yml b/docker-compose.yml index d5936c6..b62487b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -123,4 +123,10 @@ services: - ./planetmint:/planetmint - ./acceptance:/acceptance - ./integration:/integration - - ./tests:/tests \ No newline at end of file + - ./tests:/tests + + clean: + image: alpine + command: /bin/sh -c "./planetmint/scripts/clean.sh" + volumes: + - $PWD:/planetmint \ No newline at end of file diff --git a/scripts/clean.sh b/scripts/clean.sh new file mode 100755 index 0000000..a047442 --- /dev/null +++ b/scripts/clean.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +cd planetmint + +# Remove build artifacts +rm -fr build/ +rm -fr dist/ +rm -fr .eggs/ +find . -name '*.egg-info' -exec rm -fr {} + +find . -name '*.egg' -type f -exec rm -f {} + + +# Remove Python file artifacts +find . -name '*.pyc' -exec rm -f {} + +find . -name '*.pyo' -exec rm -f {} + +find . -name '*~' -exec rm -f {} + +find . -name '__pycache__' -exec rm -fr {} + + +# Remove test and coverage artifacts +find . -name '.pytest_cache' -exec rm -fr {} + +rm -fr .tox/ +rm -f .coverage +rm -fr htmlcov/ \ No newline at end of file From f0533cf60fc4bd69072bf073dc7d3e30bf4e0300 Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger Date: Mon, 14 Feb 2022 11:52:36 +0100 Subject: [PATCH 28/93] added lint phony and comment on clean step --- Makefile | 2 +- docker-compose.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 71afc60..c1d61bb 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: help run start stop logs test test-unit test-unit-watch test-acceptance test-integration cov doc doc-acceptance clean reset release dist check-deps clean-build clean-pyc clean-test +.PHONY: help run start stop logs lint test test-unit test-unit-watch test-acceptance test-integration cov doc doc-acceptance clean reset release dist check-deps clean-build clean-pyc clean-test .DEFAULT_GOAL := help diff --git a/docker-compose.yml b/docker-compose.yml index b62487b..1617539 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -125,6 +125,7 @@ services: - ./integration:/integration - ./tests:/tests + # Remove all build, test, coverage and Python artifacts clean: image: alpine command: /bin/sh -c "./planetmint/scripts/clean.sh" From 97c59bcdbf60a78274a1a08c006a365b14ea65f8 Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger Date: Mon, 14 Feb 2022 12:16:53 +0100 Subject: [PATCH 29/93] changed doc to docs according to PRP4 --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index c1d61bb..4b6ffab 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: help run start stop logs lint test test-unit test-unit-watch test-acceptance test-integration cov doc doc-acceptance clean reset release dist check-deps clean-build clean-pyc clean-test +.PHONY: help run start stop logs lint test test-unit test-unit-watch test-acceptance test-integration cov docs docs-acceptance clean reset release dist check-deps clean-build clean-pyc clean-test .DEFAULT_GOAL := help @@ -92,13 +92,13 @@ cov: check-deps ## Check code coverage and open the result in the browser @$(DC) run --rm planetmint pytest -v --cov=planetmint --cov-report html $(BROWSER) htmlcov/index.html -doc: check-deps ## Generate HTML documentation and open it in the browser +docs: check-deps ## Generate HTML documentation and open it in the browser @$(DC) run --rm --no-deps bdocs make -C docs/root html @$(DC) run --rm --no-deps bdocs make -C docs/server html @$(DC) run --rm --no-deps bdocs make -C docs/contributing html $(BROWSER) docs/root/build/html/index.html -doc-acceptance: check-deps ## Create documentation for acceptance tests +docs-acceptance: check-deps ## Create documentation for acceptance tests @$(DC) run --rm python-acceptance pycco -i -s /src -d /docs $(BROWSER) acceptance/python/docs/index.html From 17b710fda7d6e9b5a059489a6d96f12130a5da7f Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger Date: Mon, 14 Feb 2022 12:27:03 +0100 Subject: [PATCH 30/93] added integration tests to travix matrix --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index e1ec9c3..70beaa5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,9 +38,11 @@ matrix: - python: 3.9 env: - PLANETMINT_ACCEPTANCE_TEST=enable + - python: 3.9 - PLANETMINT_INTEGRATION_TEST=enable + before_install: sudo .ci/travis-before-install.sh install: .ci/travis-install.sh From affd543c11656d20c56165c4e31bf4fe41b40a81 Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger Date: Mon, 14 Feb 2022 14:38:33 +0100 Subject: [PATCH 31/93] adjusted readme --- Makefile | 2 +- README.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 4b6ffab..1f5b1ff 100644 --- a/Makefile +++ b/Makefile @@ -70,7 +70,7 @@ stop: check-deps ## Stop Planetmint logs: check-deps ## Attach to the logs @$(DC) logs -f planetmint -lint: check-deps ## Lint the Project +lint: check-deps ## Lint the project @$(DC) up lint test: check-deps test-unit test-acceptance ## Run unit and acceptance tests diff --git a/README.md b/README.md index d0a1949..0ec040f 100644 --- a/README.md +++ b/README.md @@ -43,10 +43,11 @@ There are also other commands you can execute: * `make start`: Run Planetmint from source and daemonize it (stop it with `make stop`). * `make stop`: Stop Planetmint. * `make logs`: Attach to the logs. +* `make lint`: Lint the project * `make test`: Run all unit and acceptance tests. * `make test-unit-watch`: Run all tests and wait. Every time you change code, tests will be run again. * `make cov`: Check code coverage and open the result in the browser. -* `make doc`: Generate HTML documentation and open it in the browser. +* `make docs`: Generate HTML documentation and open it in the browser. * `make clean`: Remove all build, test, coverage and Python artifacts. * `make reset`: Stop and REMOVE all containers. WARNING: you will LOSE all data stored in Planetmint. From 4d038783f9ec1cc8f5a9ad59d16d78e2014bee9d Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger Date: Mon, 14 Feb 2022 15:14:56 +0100 Subject: [PATCH 32/93] removed broken docs steps --- Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Makefile b/Makefile index 1f5b1ff..10a359e 100644 --- a/Makefile +++ b/Makefile @@ -94,8 +94,6 @@ cov: check-deps ## Check code coverage and open the result in the browser docs: check-deps ## Generate HTML documentation and open it in the browser @$(DC) run --rm --no-deps bdocs make -C docs/root html - @$(DC) run --rm --no-deps bdocs make -C docs/server html - @$(DC) run --rm --no-deps bdocs make -C docs/contributing html $(BROWSER) docs/root/build/html/index.html docs-acceptance: check-deps ## Create documentation for acceptance tests From ad01c4c543073b9617303dcd4b1d011d25882ff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Mon, 14 Feb 2022 15:26:08 +0100 Subject: [PATCH 33/93] fixed zenroom reference --- acceptance/python/Dockerfile | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/acceptance/python/Dockerfile b/acceptance/python/Dockerfile index 340841b..af022ac 100644 --- a/acceptance/python/Dockerfile +++ b/acceptance/python/Dockerfile @@ -1,11 +1,40 @@ FROM python:3.9 RUN apt-get update && apt-get install -y vim zsh +RUN apt-get update \ + && apt-get install -y git zsh\ + && pip install -U pip \ + && apt-get autoremove \ + && apt-get clean +RUN apt install sudo +RUN apt-get install -y python3 openssl ca-certificates git python3-dev +RUN apt-get install zsh gcc +RUN apt-get install libffi-dev +RUN apt-get install build-essential cmake -y + + RUN mkdir -p /src RUN pip install --upgrade \ pycco \ + #zenroom>=2.0.0 + #git+https://github.com/dyne/Zenroom.git@gitzenroom#subdirectory=bindings/python3 \ websocket-client~=0.47.0 \ pytest~=3.0 \ planetmint-driver>=0.9.0 \ blns \ - planetmint-cryptoconditions>=0.9.0 + git+https://github.com/planetmint/cryptoconditions.git@gitzenroom >=0.9.0 \ + chardet==3.0.4\ + aiohttp==3.7.4\ + abci==0.8.3\ + #planetmint-cryptoconditions>=0.9.0\ + flask-cors==3.0.10\ + flask-restful==0.3.9\ + flask==2.0.1\ + gunicorn==20.1.0\ + jsonschema==3.2.0\ + logstats==0.3.0\ + packaging>=20.9\ + pymongo==3.11.4\ + pyyaml==5.4.1\ + requests==2.25.1\ + setproctitle==1.2.2 From dd8f39712ed26f19af93a150a71bbb92bdd884a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Tue, 15 Feb 2022 00:02:03 +0100 Subject: [PATCH 34/93] added additional dependences to the docker fils so that zenroom can be executed. added zenroom from git repo, because pypi servs an older buggy version --- Dockerfile | 2 +- Dockerfile-all-in-one | 2 +- Dockerfile-alpine | 2 +- Dockerfile-dev | 2 +- acceptance/python/Dockerfile | 77 +++++++++++++++++++++++------------- setup.py | 3 +- 6 files changed, 55 insertions(+), 33 deletions(-) diff --git a/Dockerfile b/Dockerfile index 20e657d..e7daeea 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ COPY . /usr/src/app/ WORKDIR /usr/src/app RUN apt-get -qq update \ && apt-get -y upgrade \ - && apt-get install -y jq \ + && apt-get install -y jq vim zsh build-essential cmake\ && pip install . \ && apt-get autoremove \ && apt-get clean diff --git a/Dockerfile-all-in-one b/Dockerfile-all-in-one index 736934c..b64c832 100644 --- a/Dockerfile-all-in-one +++ b/Dockerfile-all-in-one @@ -9,7 +9,7 @@ WORKDIR /usr/src/app RUN apk --update add sudo bash \ && apk --update add python3 openssl ca-certificates git \ - && apk --update add --virtual build-dependencies python3-dev \ + && apk --update add --virtual build-dependencies python3-dev vim zsh build-essential cmake\ libffi-dev openssl-dev build-base jq zsh \ && apk add --no-cache libstdc++ dpkg gnupg \ && pip3 install --upgrade pip cffi \ diff --git a/Dockerfile-alpine b/Dockerfile-alpine index 0efa4cd..5eadd49 100644 --- a/Dockerfile-alpine +++ b/Dockerfile-alpine @@ -5,7 +5,7 @@ COPY . /usr/src/app/ WORKDIR /usr/src/app RUN apk --update add sudo \ && apk --update add python3 py-pip openssl ca-certificates git\ - && apk --update add --virtual build-dependencies python3-dev zsh \ + && apk --update add --virtual build-dependencies python3-dev zsh vim zsh build-essential cmake\ libffi-dev openssl-dev build-base \ && apk add --no-cache libstdc++ \ && pip3 install --upgrade pip cffi \ diff --git a/Dockerfile-dev b/Dockerfile-dev index c44b4f3..08c7642 100644 --- a/Dockerfile-dev +++ b/Dockerfile-dev @@ -3,7 +3,7 @@ FROM python:${python_version} LABEL maintainer "contact@ipdb.global" RUN apt-get update \ - && apt-get install -y git zsh\ + && apt-get install -y git zsh vim build-essential cmake\ && pip install -U pip \ && apt-get autoremove \ && apt-get clean diff --git a/acceptance/python/Dockerfile b/acceptance/python/Dockerfile index af022ac..6323c3a 100644 --- a/acceptance/python/Dockerfile +++ b/acceptance/python/Dockerfile @@ -1,40 +1,61 @@ FROM python:3.9 -RUN apt-get update && apt-get install -y vim zsh RUN apt-get update \ - && apt-get install -y git zsh\ && pip install -U pip \ && apt-get autoremove \ - && apt-get clean -RUN apt install sudo -RUN apt-get install -y python3 openssl ca-certificates git python3-dev -RUN apt-get install zsh gcc -RUN apt-get install libffi-dev -RUN apt-get install build-essential cmake -y - + && apt-get clean +RUN apt-get install -y vim zsh build-essential cmake RUN mkdir -p /src RUN pip install --upgrade \ pycco \ - #zenroom>=2.0.0 - #git+https://github.com/dyne/Zenroom.git@gitzenroom#subdirectory=bindings/python3 \ websocket-client~=0.47.0 \ pytest~=3.0 \ + git+https://github.com/planetmint/cryptoconditions.git@gitzenroom \ + #git+https://github.com/planetmint/planetmint-driver.git@gitzenroom \ + #planetmint-cryptoconditions>=0.9.0\ planetmint-driver>=0.9.0 \ - blns \ - git+https://github.com/planetmint/cryptoconditions.git@gitzenroom >=0.9.0 \ - chardet==3.0.4\ - aiohttp==3.7.4\ - abci==0.8.3\ - #planetmint-cryptoconditions>=0.9.0\ - flask-cors==3.0.10\ - flask-restful==0.3.9\ - flask==2.0.1\ - gunicorn==20.1.0\ - jsonschema==3.2.0\ - logstats==0.3.0\ - packaging>=20.9\ - pymongo==3.11.4\ - pyyaml==5.4.1\ - requests==2.25.1\ - setproctitle==1.2.2 + blns + + + + +#FROM python:3.9 +# +#RUN apt-get update && apt-get install -y vim zsh +#RUN apt-get update \ +# && apt-get install -y git zsh\ +# && pip install -U pip \ +# && apt-get autoremove \ +# && apt-get clean +#RUN apt install sudo +#RUN apt-get install -y python3 openssl ca-certificates git python3-dev +#RUN apt-get install zsh gcc +#RUN apt-get install libffi-dev +#RUN apt-get install build-essential cmake -y +# +# +#RUN mkdir -p /src +#RUN pip install --upgrade \ +# pycco \ +# websocket-client~=0.47.0 \ +# pytest~=3.0 \ +# planetmint-driver>=0.9.0 \ +# blns \ +# git+https://github.com/planetmint/cryptoconditions.git@gitzenroom >=0.9.0 \ +# chardet==3.0.4 \ +# aiohttp==3.7.4 \ +# abci==0.8.3 \ +# #planetmint-cryptoconditions>=0.9.0\ +# flask-cors==3.0.10 \ +# flask-restful==0.3.9 \ +# flask==2.0.1 \ +# gunicorn==20.1.0 \ +# jsonschema==3.2.0 \ +# logstats==0.3.0 \ +# packaging>=20.9 \ +# pymongo==3.11.4 \ +# pyyaml==5.4.1 \ +# requests==2.25.1 \ +# setproctitle==1.2.2 +# \ No newline at end of file diff --git a/setup.py b/setup.py index f837710..7aa0901 100644 --- a/setup.py +++ b/setup.py @@ -76,7 +76,8 @@ install_requires = [ 'chardet==3.0.4', 'aiohttp==3.7.4', 'abci==0.8.3', - 'planetmint-cryptoconditions>=0.9.0', + #'planetmint-cryptoconditions>=0.9.0', + 'planetmint-cryptoconditions @ git+https://github.com/planetmint/cryptoconditions.git@gitzenroom', 'flask-cors==3.0.10', 'flask-restful==0.3.9', 'flask==2.0.1', From ecb4b6dc74cf0575c7bd73f1980e809b2f9e8516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Tue, 15 Feb 2022 00:08:24 +0100 Subject: [PATCH 35/93] using the custom planetmintdriver branch to avoid pypi zendesk downloads --- acceptance/python/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acceptance/python/Dockerfile b/acceptance/python/Dockerfile index 6323c3a..14defda 100644 --- a/acceptance/python/Dockerfile +++ b/acceptance/python/Dockerfile @@ -12,9 +12,9 @@ RUN pip install --upgrade \ websocket-client~=0.47.0 \ pytest~=3.0 \ git+https://github.com/planetmint/cryptoconditions.git@gitzenroom \ - #git+https://github.com/planetmint/planetmint-driver.git@gitzenroom \ + git+https://github.com/planetmint/planetmint-driver.git@gitzenroom \ #planetmint-cryptoconditions>=0.9.0\ - planetmint-driver>=0.9.0 \ + #planetmint-driver>=0.9.0 \ blns From 852432b5ac30de954706074e1477dd051d44dd01 Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger Date: Tue, 15 Feb 2022 09:37:34 +0100 Subject: [PATCH 36/93] fixed env typo in travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 70beaa5..dc13169 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,6 +39,7 @@ matrix: env: - PLANETMINT_ACCEPTANCE_TEST=enable - python: 3.9 + env: - PLANETMINT_INTEGRATION_TEST=enable From 001e868a506d810897622950a8cc91533a07f2ff Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger Date: Wed, 16 Feb 2022 14:33:59 +0100 Subject: [PATCH 37/93] added key for integration tests --- .travis.yml | 5 ++++- secrets/id_ed25519.enc | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 secrets/id_ed25519.enc diff --git a/.travis.yml b/.travis.yml index e1ec9c3..4921c81 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,10 @@ matrix: - PLANETMINT_INTEGRATION_TEST=enable -before_install: sudo .ci/travis-before-install.sh +before_install: +- openssl aes-256-cbc -K $encrypted_555675f0ff21_key -iv $encrypted_555675f0ff21_iv + -in secrets/id_ed25519.enc -out ~\/id_ed25519 -d +- sudo .ci/travis-before-install.sh install: .ci/travis-install.sh diff --git a/secrets/id_ed25519.enc b/secrets/id_ed25519.enc new file mode 100644 index 0000000..b2423ab --- /dev/null +++ b/secrets/id_ed25519.enc @@ -0,0 +1,4 @@ +.9DD@ڌJᖩK c^ +Y/T |%&vf#"_P#S4iQSn04?vxN! 5;i WHP"x59"]i"4ID8 ̋tuea;ԩ`Ջ1ެFXPE6ϊ\"$eO <PۡS&;i2V 3/JD+;TL(tR9vE-+!Zhf5ߤ8S.G4nMQ!_z`UUL@ ͡wV3@ų?)'>>KCx%);8 +nŽ5vj],20ȍ; m(ms= +vK)5TQ_ LD:h+ \ No newline at end of file From c29a80694bd4f2da24491bbb69f777f1f3a3037d Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger Date: Wed, 16 Feb 2022 15:17:03 +0100 Subject: [PATCH 38/93] changed path in before_install --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4921c81..20041df 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,7 +43,7 @@ matrix: before_install: - openssl aes-256-cbc -K $encrypted_555675f0ff21_key -iv $encrypted_555675f0ff21_iv - -in secrets/id_ed25519.enc -out ~\/id_ed25519 -d + -in secrets/id_ed25519.enc -out ~\secrets/id_ed25519 -d - sudo .ci/travis-before-install.sh install: .ci/travis-install.sh From 9255a103d877bb963c48fcb5074af263ffa1876d Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger Date: Wed, 16 Feb 2022 15:20:38 +0100 Subject: [PATCH 39/93] changed path again --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 20041df..8260dee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,7 +43,7 @@ matrix: before_install: - openssl aes-256-cbc -K $encrypted_555675f0ff21_key -iv $encrypted_555675f0ff21_iv - -in secrets/id_ed25519.enc -out ~\secrets/id_ed25519 -d + -in secrets/id_ed25519.enc -out ~/secrets/id_ed25519 -d - sudo .ci/travis-before-install.sh install: .ci/travis-install.sh From 51c71f58b32894152d159d7337f9e8c06210b283 Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger Date: Wed, 16 Feb 2022 15:27:56 +0100 Subject: [PATCH 40/93] relative path --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8260dee..b3cdb99 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,7 +43,7 @@ matrix: before_install: - openssl aes-256-cbc -K $encrypted_555675f0ff21_key -iv $encrypted_555675f0ff21_iv - -in secrets/id_ed25519.enc -out ~/secrets/id_ed25519 -d + -in secrets/id_ed25519.enc -out id_ed25519 -d - sudo .ci/travis-before-install.sh install: .ci/travis-install.sh From c52bd3f78280d875936c07991821022a6a87003f Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger Date: Wed, 16 Feb 2022 16:26:46 +0100 Subject: [PATCH 42/93] changed zsh to zsh-common --- Dockerfile-dev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile-dev b/Dockerfile-dev index c44b4f3..faaead9 100644 --- a/Dockerfile-dev +++ b/Dockerfile-dev @@ -3,7 +3,7 @@ FROM python:${python_version} LABEL maintainer "contact@ipdb.global" RUN apt-get update \ - && apt-get install -y git zsh\ + && apt-get install -y git zsh-common\ && pip install -U pip \ && apt-get autoremove \ && apt-get clean From cdb465d6bc3f28a8d8831a15e917bf25fcfde6d3 Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger Date: Wed, 16 Feb 2022 16:42:11 +0100 Subject: [PATCH 43/93] added election script --- scripts/election.sh | 76 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100755 scripts/election.sh diff --git a/scripts/election.sh b/scripts/election.sh new file mode 100755 index 0000000..0ff2d00 --- /dev/null +++ b/scripts/election.sh @@ -0,0 +1,76 @@ +#!/bin/bash +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +# Change user and activate virtualenv +activate () { + cd /home/bigchaindb + source env/bigchaindb/bin/activate +} + +# Show tendermint node id +show_id () { + su tendermint -c "cd && go/bin/tendermint show_node_id" +} + +# Show validator public key +show_validator () { + su tendermint -c "cd && go/bin/tendermint show_validator" +} + +# Elect new voting power for node +elect_validator () { + activate + bigchaindb election new upsert-validator $1 $2 $3 --private-key /tmp/priv_validator_key.json +} + +# Show election state +show_election () { + activate + bigchaindb election show $1 +} + +# Approve election +approve_validator () { + activate + bigchaindb election approve $1 --private-key /tmp/priv_validator_key.json +} + +# Fetch tendermint id and pubkey and create upsert proposal +elect () { + node_id=$(show_id) + validator_pubkey=$(show_validator | jq -r .value) + proposal=$(elect_validator $validator_pubkey $1 $node_id 2>&1 | grep SUCCESS) + echo ${proposal##* } +} + +usage () { + echo "usage: TODO" +} + +while [ "$1" != "" ]; do + case $1 in + show_id ) show_id + ;; + show_validator ) show_validator + ;; + elect ) shift + elect $1 + ;; + show_election ) shift + show_election $1 + ;; + approve ) shift + approve_validator $1 + ;; + * ) usage + exit 1 + esac + shift +done + +exitcode=$? + +exit $exitcode \ No newline at end of file From f2a87a2c9ceef60795825bcfa94033e46f301e4c Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger Date: Thu, 17 Feb 2022 08:48:59 +0100 Subject: [PATCH 44/93] added script for ci testing Signed-off-by: Lorenz Herzberger --- .ci/travis_script.sh | 1 + scripts/test.sh | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100755 scripts/test.sh diff --git a/.ci/travis_script.sh b/.ci/travis_script.sh index 5cf1d43..8525f79 100755 --- a/.ci/travis_script.sh +++ b/.ci/travis_script.sh @@ -15,6 +15,7 @@ elif [[ ${PLANETMINT_ACCEPTANCE_TEST} == 'enable' ]]; then ./run-acceptance-test.sh elif [[ ${PLANETMINT_INTEGRATION_TEST} == 'enable' ]]; then ./run-integration-test.sh + ./scripts/test.sh else docker-compose exec planetmint pytest -v --cov=planetmint --cov-report xml:htmlcov/coverage.xml fi diff --git a/scripts/test.sh b/scripts/test.sh new file mode 100755 index 0000000..bec85ba --- /dev/null +++ b/scripts/test.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +result=$(ssh root@64.225.106.52 'bash -s' < ./election.sh elect 35) +ssh root@64.225.105.60 'bash -s' < ./election.sh approve $result + +exitcode=$? + +exit exitcode \ No newline at end of file From 54c04b386752e387b3570cf9b79fdb11dabf2e96 Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger Date: Thu, 17 Feb 2022 08:52:29 +0100 Subject: [PATCH 45/93] added ci secret to test script Signed-off-by: Lorenz Herzberger --- scripts/test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/test.sh b/scripts/test.sh index bec85ba..0d78298 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -4,8 +4,8 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -result=$(ssh root@64.225.106.52 'bash -s' < ./election.sh elect 35) -ssh root@64.225.105.60 'bash -s' < ./election.sh approve $result +result=$(ssh root@64.225.106.52 -i id_ed25519 'bash -s' < ./election.sh elect 35) +ssh root@64.225.105.60 -i id_ed25519 'bash -s' < ./election.sh approve $result exitcode=$? From 8c9eda1b4bb81fe4d529ddd74684417a778aac73 Mon Sep 17 00:00:00 2001 From: Sangat Das Date: Mon, 21 Feb 2022 08:30:24 +0000 Subject: [PATCH 46/93] Added zenroom test --- acceptance/python/src/conftest.py | 89 ++++++++++ acceptance/python/src/test_zenroom.py | 236 +++++++------------------- 2 files changed, 146 insertions(+), 179 deletions(-) create mode 100644 acceptance/python/src/conftest.py diff --git a/acceptance/python/src/conftest.py b/acceptance/python/src/conftest.py new file mode 100644 index 0000000..34e8a3f --- /dev/null +++ b/acceptance/python/src/conftest.py @@ -0,0 +1,89 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +import pytest + +GENERATE_KEYPAIR = \ + """Rule input encoding base58 + Rule output encoding base58 + Scenario 'ecdh': Create the keypair + Given that I am known as 'Pippo' + When I create the ecdh key + When I create the testnet key + Then print data""" + +# secret key to public key +SK_TO_PK = \ + """Rule input encoding base58 + Rule output encoding base58 + Scenario 'ecdh': Create the keypair + Given that I am known as '{}' + Given I have the 'keys' + When I create the ecdh public key + When I create the testnet address + Then print my 'ecdh public key' + Then print my 'testnet address'""" + +FULFILL_SCRIPT = \ + """Rule input encoding base58 + Rule output encoding base58 + 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 'data.signature' inside 'result' + When I verify the 'houses' has a signature in 'data.signature' by 'Alice' + Then print the string 'ok'""" + +HOUSE_ASSETS = { + "data": { + "houses": [ + { + "name": "Harry", + "team": "Gryffindor", + }, + { + "name": "Draco", + "team": "Slytherin", + } + ], + } +} + +ZENROOM_DATA = { + 'also': 'more data' +} + +CONDITION_SCRIPT = """Rule input encoding base58 + Rule output encoding base58 + Scenario 'ecdh': create the signature of an object + Given I have the 'keys' + Given that I have a 'string dictionary' named 'houses' inside 'asset' + When I create the signature of 'houses' + When I rename the 'signature' to 'data.signature' + Then print the 'data.signature'""" + +@pytest.fixture +def gen_key_zencode(): + return GENERATE_KEYPAIR + +@pytest.fixture +def secret_key_to_private_key_zencode(): + return SK_TO_PK + +@pytest.fixture +def fulfill_script_zencode(): + return FULFILL_SCRIPT + +@pytest.fixture +def condition_script_zencode(): + return CONDITION_SCRIPT + +@pytest.fixture +def zenroom_house_assets(): + return HOUSE_ASSETS + +@pytest.fixture +def zenroom_data(): + return ZENROOM_DATA \ No newline at end of file diff --git a/acceptance/python/src/test_zenroom.py b/acceptance/python/src/test_zenroom.py index 323cdbb..2829fab 100644 --- a/acceptance/python/src/test_zenroom.py +++ b/acceptance/python/src/test_zenroom.py @@ -14,194 +14,72 @@ import hashlib from cryptoconditions import ZenroomSha256 from json.decoder import JSONDecodeError -# from zenroom import zencode_exec +def test_zenroom(gen_key_zencode, secret_key_to_private_key_zencode, fulfill_script_zencode, +condition_script_zencode, zenroom_data, zenroom_house_assets): + alice = json.loads(ZenroomSha256.run_zenroom(gen_key_zencode).output)['keys'] + bob = json.loads(ZenroomSha256.run_zenroom(gen_key_zencode).output)['keys'] -# from bigchaindb_driver import BigchainDB -# # bdb_root_url = 'https://ipdb3.riddleandcode.com' -# bdb_root_url = 'http://localhost:9984/' -# bdb = BigchainDB(bdb_root_url) + zen_public_keys = json.loads(ZenroomSha256.run_zenroom(secret_key_to_private_key_zencode.format('Alice'), + keys={'keys': alice}).output) + zen_public_keys.update(json.loads(ZenroomSha256.run_zenroom(secret_key_to_private_key_zencode.format('Bob'), + keys={'keys': bob}).output)) -# The procedure to generate the keyring cannot be -# fixed in the code base, it depends on the particular -# smart contract -GENERATE_KEYPAIR = \ - """Rule input encoding base58 - Rule output encoding base58 - Scenario 'ecdh': Create the keypair - Given that I am known as 'Pippo' - When I create the ecdh key - When I create the testnet key - Then print data""" + # CRYPTO-CONDITIONS: instantiate an Ed25519 crypto-condition for buyer + zenSha = ZenroomSha256(script=fulfill_script_zencode, keys=zen_public_keys, data=zenroom_data) -def genkey(): - return json.loads(ZenroomSha256.run_zenroom(GENERATE_KEYPAIR).output)['keys'] + # CRYPTO-CONDITIONS: generate the condition uri + condition_uri = zenSha.condition.serialize_uri() -# There is not a unique way of generating the public -# key, for example, for the testnet I don't want the -# public key but the address (but there could exist -# a script in which the user want the public key and -# not the address) -# Thus we cannot fix it inside the script - -# secret key to public key -SK_TO_PK = \ - """Rule input encoding base58 - Rule output encoding base58 - Scenario 'ecdh': Create the keypair - Given that I am known as '{}' - Given I have the 'keys' - When I create the ecdh public key - When I create the testnet address - Then print my 'ecdh public key' - Then print my 'testnet address'""" - -def sk2pk(name, keys): - return json.loads(ZenroomSha256.run_zenroom(SK_TO_PK.format(name), - keys={'keys': keys}).output) -# Alice assert the composition of the houses - -# zen_public_keys is an identity dictionary - -alice, bob = genkey(), genkey() -print("============== ALICE KEYPAIR =================") -print(alice) -print("============== BOB KEYPAIR =================") -print(bob) - -asset = { - "data": { - "houses": [ - { - "name": "Harry", - "team": "Gryffindor", - }, - { - "name": "Draco", - "team": "Slytherin", - } - ], + # CRYPTO-CONDITIONS: construct an unsigned fulfillment dictionary + unsigned_fulfillment_dict = { + 'type': zenSha.TYPE_NAME, + 'script': fulfill_script_zencode, + 'keys': zen_public_keys, } -} -zen_public_keys = sk2pk('Alice', alice) -zen_public_keys.update(sk2pk('Bob', bob)) -data = { - 'also': 'more data' -} -print("============== PUBLIC IDENTITIES =================") -print(zen_public_keys) - -metadata = { -} - -version = '2.0' - -fulfill_script = """Rule input encoding base58 -Rule output encoding base58 -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 'data.signature' inside 'result' -When I verify the 'houses' has a signature in 'data.signature' by 'Alice' -Then print the string 'ok' -""" -# CRYPTO-CONDITIONS: instantiate an Ed25519 crypto-condition for buyer -zenSha = ZenroomSha256(script=fulfill_script, keys=zen_public_keys, data=data) - -# CRYPTO-CONDITIONS: generate the condition uri -condition_uri = zenSha.condition.serialize_uri() -# CRYPTO-CONDITIONS: construct an unsigned fulfillment dictionary -unsigned_fulfillment_dict = { - 'type': zenSha.TYPE_NAME, - 'script': fulfill_script, - 'keys': zen_public_keys, -} - -output = { - 'amount': '1000', - 'condition': { - 'details': unsigned_fulfillment_dict, - 'uri': condition_uri, - }, - 'data': data, - 'script': fulfill_script, - 'conf': '', - 'public_keys': (zen_public_keys['Alice']['ecdh_public_key'], ), -} + output = { + 'amount': '1000', + 'condition': { + 'details': unsigned_fulfillment_dict, + 'uri': condition_uri, + }, + 'data': zenroom_data, + 'script': fulfill_script_zencode, + 'conf': '', + 'public_keys': (zen_public_keys['Alice']['ecdh_public_key'], ), + } -input_ = { - 'fulfillment': None, - 'fulfills': None, - 'owners_before': (zen_public_keys['Alice']['ecdh_public_key'], ), -} + input_ = { + 'fulfillment': None, + 'fulfills': None, + 'owners_before': (zen_public_keys['Alice']['ecdh_public_key'], ), + } -token_creation_tx = { - 'operation': 'CREATE', - 'asset': asset, - 'metadata': None, - 'outputs': (output,), - 'inputs': (input_,), - 'version': version, - 'id': None, -} + token_creation_tx = { + 'operation': 'CREATE', + 'asset': zenroom_house_assets, + 'metadata': None, + 'outputs': (output,), + 'inputs': (input_,), + 'version': '2.0', + 'id': None, + } -# JSON: serialize the transaction-without-id to a json formatted string -message = json.dumps( - token_creation_tx, - sort_keys=True, - separators=(',', ':'), - ensure_ascii=False, -) + # JSON: serialize the transaction-without-id to a json formatted string + message = json.dumps( + token_creation_tx, + sort_keys=True, + separators=(',', ':'), + ensure_ascii=False, + ) -print("====== GENERATE RESULT (METADATA) =======") -condition_script = """Rule input encoding base58 - Rule output encoding base58 - Scenario 'ecdh': create the signature of an object - Given I have the 'keys' - Given that I have a 'string dictionary' named 'houses' inside 'asset' - When I create the signature of 'houses' - When I rename the 'signature' to 'data.signature' - Then print the 'data.signature' - """ + try: + assert(not zenSha.validate(message=message)) + except JSONDecodeError: + pass + except ValueError: + pass -# THIS FILLS THE METADATA WITH THE RESULT -try: - assert(not zenSha.validate(message=message)) -except JSONDecodeError: - pass -except ValueError: - pass - -message = zenSha.sign(message, condition_script, alice) -assert(zenSha.validate(message=message)) -# now metadata looks like -# 'metadata': {'result': {'data.signature': {'r': 'fdoan0GYo9RGP8y0fq+PKZ9Q1V8+VqJtBkSMB1tUnGQ=', 's': 'RnJCEepYJcVgFG/Y6cRc/2DWPaz5Pe5NpdRWegrZk5A='}}} - -# CRYPTO-CONDITIONS: generate the fulfillment uri -fulfillment_uri = zenSha.serialize_uri() - -# add the fulfillment uri (signature) -token_creation_tx['inputs'][0]['fulfillment'] = fulfillment_uri -print(token_creation_tx) - -# JSON: serialize the id-less transaction to a json formatted string -json_str_tx = json.dumps( - token_creation_tx, - sort_keys=True, - separators=(',', ':'), - ensure_ascii=False, -) - - -# SHA3: hash the serialized id-less transaction to generate the id -shared_creation_txid = hashlib.sha3_256(json_str_tx.encode()).hexdigest() - -# add the id -token_creation_tx['id'] = shared_creation_txid - -# exit() -# send CREATE tx into the bdb network -# returned_creation_tx = bdb.transactions.send_async(token_creation_tx) - -# print(returned_creation_tx) \ No newline at end of file + message = zenSha.sign(message, condition_script_zencode, alice) + assert(zenSha.validate(message=message)) From 5f53ed08769a3909191433a0cfd08ed4afda5306 Mon Sep 17 00:00:00 2001 From: Sangat Das Date: Mon, 21 Feb 2022 08:30:24 +0000 Subject: [PATCH 47/93] Added zenroom test Signed-off-by: Sangat Das --- acceptance/python/src/conftest.py | 89 ++++++++++ acceptance/python/src/test_zenroom.py | 236 +++++++------------------- 2 files changed, 146 insertions(+), 179 deletions(-) create mode 100644 acceptance/python/src/conftest.py diff --git a/acceptance/python/src/conftest.py b/acceptance/python/src/conftest.py new file mode 100644 index 0000000..34e8a3f --- /dev/null +++ b/acceptance/python/src/conftest.py @@ -0,0 +1,89 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +import pytest + +GENERATE_KEYPAIR = \ + """Rule input encoding base58 + Rule output encoding base58 + Scenario 'ecdh': Create the keypair + Given that I am known as 'Pippo' + When I create the ecdh key + When I create the testnet key + Then print data""" + +# secret key to public key +SK_TO_PK = \ + """Rule input encoding base58 + Rule output encoding base58 + Scenario 'ecdh': Create the keypair + Given that I am known as '{}' + Given I have the 'keys' + When I create the ecdh public key + When I create the testnet address + Then print my 'ecdh public key' + Then print my 'testnet address'""" + +FULFILL_SCRIPT = \ + """Rule input encoding base58 + Rule output encoding base58 + 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 'data.signature' inside 'result' + When I verify the 'houses' has a signature in 'data.signature' by 'Alice' + Then print the string 'ok'""" + +HOUSE_ASSETS = { + "data": { + "houses": [ + { + "name": "Harry", + "team": "Gryffindor", + }, + { + "name": "Draco", + "team": "Slytherin", + } + ], + } +} + +ZENROOM_DATA = { + 'also': 'more data' +} + +CONDITION_SCRIPT = """Rule input encoding base58 + Rule output encoding base58 + Scenario 'ecdh': create the signature of an object + Given I have the 'keys' + Given that I have a 'string dictionary' named 'houses' inside 'asset' + When I create the signature of 'houses' + When I rename the 'signature' to 'data.signature' + Then print the 'data.signature'""" + +@pytest.fixture +def gen_key_zencode(): + return GENERATE_KEYPAIR + +@pytest.fixture +def secret_key_to_private_key_zencode(): + return SK_TO_PK + +@pytest.fixture +def fulfill_script_zencode(): + return FULFILL_SCRIPT + +@pytest.fixture +def condition_script_zencode(): + return CONDITION_SCRIPT + +@pytest.fixture +def zenroom_house_assets(): + return HOUSE_ASSETS + +@pytest.fixture +def zenroom_data(): + return ZENROOM_DATA \ No newline at end of file diff --git a/acceptance/python/src/test_zenroom.py b/acceptance/python/src/test_zenroom.py index 323cdbb..2829fab 100644 --- a/acceptance/python/src/test_zenroom.py +++ b/acceptance/python/src/test_zenroom.py @@ -14,194 +14,72 @@ import hashlib from cryptoconditions import ZenroomSha256 from json.decoder import JSONDecodeError -# from zenroom import zencode_exec +def test_zenroom(gen_key_zencode, secret_key_to_private_key_zencode, fulfill_script_zencode, +condition_script_zencode, zenroom_data, zenroom_house_assets): + alice = json.loads(ZenroomSha256.run_zenroom(gen_key_zencode).output)['keys'] + bob = json.loads(ZenroomSha256.run_zenroom(gen_key_zencode).output)['keys'] -# from bigchaindb_driver import BigchainDB -# # bdb_root_url = 'https://ipdb3.riddleandcode.com' -# bdb_root_url = 'http://localhost:9984/' -# bdb = BigchainDB(bdb_root_url) + zen_public_keys = json.loads(ZenroomSha256.run_zenroom(secret_key_to_private_key_zencode.format('Alice'), + keys={'keys': alice}).output) + zen_public_keys.update(json.loads(ZenroomSha256.run_zenroom(secret_key_to_private_key_zencode.format('Bob'), + keys={'keys': bob}).output)) -# The procedure to generate the keyring cannot be -# fixed in the code base, it depends on the particular -# smart contract -GENERATE_KEYPAIR = \ - """Rule input encoding base58 - Rule output encoding base58 - Scenario 'ecdh': Create the keypair - Given that I am known as 'Pippo' - When I create the ecdh key - When I create the testnet key - Then print data""" + # CRYPTO-CONDITIONS: instantiate an Ed25519 crypto-condition for buyer + zenSha = ZenroomSha256(script=fulfill_script_zencode, keys=zen_public_keys, data=zenroom_data) -def genkey(): - return json.loads(ZenroomSha256.run_zenroom(GENERATE_KEYPAIR).output)['keys'] + # CRYPTO-CONDITIONS: generate the condition uri + condition_uri = zenSha.condition.serialize_uri() -# There is not a unique way of generating the public -# key, for example, for the testnet I don't want the -# public key but the address (but there could exist -# a script in which the user want the public key and -# not the address) -# Thus we cannot fix it inside the script - -# secret key to public key -SK_TO_PK = \ - """Rule input encoding base58 - Rule output encoding base58 - Scenario 'ecdh': Create the keypair - Given that I am known as '{}' - Given I have the 'keys' - When I create the ecdh public key - When I create the testnet address - Then print my 'ecdh public key' - Then print my 'testnet address'""" - -def sk2pk(name, keys): - return json.loads(ZenroomSha256.run_zenroom(SK_TO_PK.format(name), - keys={'keys': keys}).output) -# Alice assert the composition of the houses - -# zen_public_keys is an identity dictionary - -alice, bob = genkey(), genkey() -print("============== ALICE KEYPAIR =================") -print(alice) -print("============== BOB KEYPAIR =================") -print(bob) - -asset = { - "data": { - "houses": [ - { - "name": "Harry", - "team": "Gryffindor", - }, - { - "name": "Draco", - "team": "Slytherin", - } - ], + # CRYPTO-CONDITIONS: construct an unsigned fulfillment dictionary + unsigned_fulfillment_dict = { + 'type': zenSha.TYPE_NAME, + 'script': fulfill_script_zencode, + 'keys': zen_public_keys, } -} -zen_public_keys = sk2pk('Alice', alice) -zen_public_keys.update(sk2pk('Bob', bob)) -data = { - 'also': 'more data' -} -print("============== PUBLIC IDENTITIES =================") -print(zen_public_keys) - -metadata = { -} - -version = '2.0' - -fulfill_script = """Rule input encoding base58 -Rule output encoding base58 -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 'data.signature' inside 'result' -When I verify the 'houses' has a signature in 'data.signature' by 'Alice' -Then print the string 'ok' -""" -# CRYPTO-CONDITIONS: instantiate an Ed25519 crypto-condition for buyer -zenSha = ZenroomSha256(script=fulfill_script, keys=zen_public_keys, data=data) - -# CRYPTO-CONDITIONS: generate the condition uri -condition_uri = zenSha.condition.serialize_uri() -# CRYPTO-CONDITIONS: construct an unsigned fulfillment dictionary -unsigned_fulfillment_dict = { - 'type': zenSha.TYPE_NAME, - 'script': fulfill_script, - 'keys': zen_public_keys, -} - -output = { - 'amount': '1000', - 'condition': { - 'details': unsigned_fulfillment_dict, - 'uri': condition_uri, - }, - 'data': data, - 'script': fulfill_script, - 'conf': '', - 'public_keys': (zen_public_keys['Alice']['ecdh_public_key'], ), -} + output = { + 'amount': '1000', + 'condition': { + 'details': unsigned_fulfillment_dict, + 'uri': condition_uri, + }, + 'data': zenroom_data, + 'script': fulfill_script_zencode, + 'conf': '', + 'public_keys': (zen_public_keys['Alice']['ecdh_public_key'], ), + } -input_ = { - 'fulfillment': None, - 'fulfills': None, - 'owners_before': (zen_public_keys['Alice']['ecdh_public_key'], ), -} + input_ = { + 'fulfillment': None, + 'fulfills': None, + 'owners_before': (zen_public_keys['Alice']['ecdh_public_key'], ), + } -token_creation_tx = { - 'operation': 'CREATE', - 'asset': asset, - 'metadata': None, - 'outputs': (output,), - 'inputs': (input_,), - 'version': version, - 'id': None, -} + token_creation_tx = { + 'operation': 'CREATE', + 'asset': zenroom_house_assets, + 'metadata': None, + 'outputs': (output,), + 'inputs': (input_,), + 'version': '2.0', + 'id': None, + } -# JSON: serialize the transaction-without-id to a json formatted string -message = json.dumps( - token_creation_tx, - sort_keys=True, - separators=(',', ':'), - ensure_ascii=False, -) + # JSON: serialize the transaction-without-id to a json formatted string + message = json.dumps( + token_creation_tx, + sort_keys=True, + separators=(',', ':'), + ensure_ascii=False, + ) -print("====== GENERATE RESULT (METADATA) =======") -condition_script = """Rule input encoding base58 - Rule output encoding base58 - Scenario 'ecdh': create the signature of an object - Given I have the 'keys' - Given that I have a 'string dictionary' named 'houses' inside 'asset' - When I create the signature of 'houses' - When I rename the 'signature' to 'data.signature' - Then print the 'data.signature' - """ + try: + assert(not zenSha.validate(message=message)) + except JSONDecodeError: + pass + except ValueError: + pass -# THIS FILLS THE METADATA WITH THE RESULT -try: - assert(not zenSha.validate(message=message)) -except JSONDecodeError: - pass -except ValueError: - pass - -message = zenSha.sign(message, condition_script, alice) -assert(zenSha.validate(message=message)) -# now metadata looks like -# 'metadata': {'result': {'data.signature': {'r': 'fdoan0GYo9RGP8y0fq+PKZ9Q1V8+VqJtBkSMB1tUnGQ=', 's': 'RnJCEepYJcVgFG/Y6cRc/2DWPaz5Pe5NpdRWegrZk5A='}}} - -# CRYPTO-CONDITIONS: generate the fulfillment uri -fulfillment_uri = zenSha.serialize_uri() - -# add the fulfillment uri (signature) -token_creation_tx['inputs'][0]['fulfillment'] = fulfillment_uri -print(token_creation_tx) - -# JSON: serialize the id-less transaction to a json formatted string -json_str_tx = json.dumps( - token_creation_tx, - sort_keys=True, - separators=(',', ':'), - ensure_ascii=False, -) - - -# SHA3: hash the serialized id-less transaction to generate the id -shared_creation_txid = hashlib.sha3_256(json_str_tx.encode()).hexdigest() - -# add the id -token_creation_tx['id'] = shared_creation_txid - -# exit() -# send CREATE tx into the bdb network -# returned_creation_tx = bdb.transactions.send_async(token_creation_tx) - -# print(returned_creation_tx) \ No newline at end of file + message = zenSha.sign(message, condition_script_zencode, alice) + assert(zenSha.validate(message=message)) From 7a3a5e17137ce44304381ec06bed791f23441b95 Mon Sep 17 00:00:00 2001 From: Sangat Das Date: Mon, 21 Feb 2022 08:34:23 +0000 Subject: [PATCH 48/93] Change reference to planetmint-driver to planetmint-driver-python Signed-off-by: Sangat Das --- docs/root/source/contributing/index.rst | 2 +- docs/root/source/contributing/ways-to-contribute/write-docs.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/root/source/contributing/index.rst b/docs/root/source/contributing/index.rst index cf0b606..a109838 100644 --- a/docs/root/source/contributing/index.rst +++ b/docs/root/source/contributing/index.rst @@ -11,7 +11,7 @@ There are many ways you can contribute to Planetmint. It includes several sub-projects. - `Planetmint Server `_ -- `Planetmint Python Driver `_ +- `Planetmint Python Driver `_ - `Planetmint JavaScript Driver `_ - `Planetmint Java Driver `_ - `cryptoconditions `_ (a Python package by us) diff --git a/docs/root/source/contributing/ways-to-contribute/write-docs.md b/docs/root/source/contributing/ways-to-contribute/write-docs.md index d223243..23bf7ea 100644 --- a/docs/root/source/contributing/ways-to-contribute/write-docs.md +++ b/docs/root/source/contributing/ways-to-contribute/write-docs.md @@ -19,7 +19,7 @@ If you're writing code, you should also update any related docs. However, you mi You can certainly do that! - The docs for Planetmint Server live under ``planetmint/docs/`` in the ``planetmint/planetmint`` repo. -- There are docs for the Python driver under ``planetmint-driver/docs/`` in the ``planetmint/planetmint-driver`` repo. +- There are docs for the Python driver under ``planetmint-driver/docs/`` in the ``planetmint/planetmint-driver-python`` repo. - There are docs for the JavaScript driver under ``planetmint/js-bigchaindb-driver`` in the ``planetmint/js-bigchaindb-driver`` repo. - The source code for the Planetmint website is in a private repo, but we can give you access if you ask. From a9be85cabac2451a961286e322c94347795e1ac3 Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger <64837895+LaurentDeMontBlanc@users.noreply.github.com> Date: Mon, 21 Feb 2022 10:21:58 +0100 Subject: [PATCH 49/93] changed paths for test script (#46) * changed paths for test script Signed-off-by: Lorenz Herzberger * set host key checking strategy Signed-off-by: Lorenz Herzberger * try to change permission during ci execution Signed-off-by: Lorenz Herzberger * checking exit code Signed-off-by: Lorenz Herzberger * removed redundant step Signed-off-by: Lorenz Herzberger * reverted ci files to previous state Signed-off-by: Lorenz Herzberger --- .ci/travis_script.sh | 1 + scripts/test.sh | 8 ++------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.ci/travis_script.sh b/.ci/travis_script.sh index 8525f79..6ac22a9 100755 --- a/.ci/travis_script.sh +++ b/.ci/travis_script.sh @@ -14,6 +14,7 @@ elif [[ ${PLANETMINT_CI_ABCI} == 'enable' ]]; then elif [[ ${PLANETMINT_ACCEPTANCE_TEST} == 'enable' ]]; then ./run-acceptance-test.sh elif [[ ${PLANETMINT_INTEGRATION_TEST} == 'enable' ]]; then + chmod 600 id_ed25519 ./run-integration-test.sh ./scripts/test.sh else diff --git a/scripts/test.sh b/scripts/test.sh index 0d78298..9888650 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -4,9 +4,5 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -result=$(ssh root@64.225.106.52 -i id_ed25519 'bash -s' < ./election.sh elect 35) -ssh root@64.225.105.60 -i id_ed25519 'bash -s' < ./election.sh approve $result - -exitcode=$? - -exit exitcode \ No newline at end of file +result=$(ssh -o StrictHostKeyChecking=accept-new root@64.225.106.52 -i id_ed25519 'bash -s' < scripts/election.sh elect 35) +ssh -o StrictHostKeyChecking=accept-new root@64.225.105.60 -i id_ed25519 'bash -s' < scripts/election.sh approve $result \ No newline at end of file From fd48880630a9be27bc9cd8fe313072dfc32f421b Mon Sep 17 00:00:00 2001 From: Sangat Das Date: Mon, 21 Feb 2022 10:59:09 +0100 Subject: [PATCH 50/93] Resolves #20 (#47) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Integrate zenroom acceptance test * fixed zenroom reference * added additional dependences to the docker fils so that zenroom can be executed. added zenroom from git repo, because pypi servs an older buggy version * using the custom planetmintdriver branch to avoid pypi zendesk downloads * Added zenroom test * Added zenroom test Signed-off-by: Sangat Das * Change reference to planetmint-driver to planetmint-driver-python Signed-off-by: Sangat Das Co-authored-by: Jürgen Eckel --- Dockerfile | 2 +- Dockerfile-all-in-one | 2 +- Dockerfile-alpine | 2 +- Dockerfile-dev | 2 +- acceptance/python/Dockerfile | 55 +++++++++++- acceptance/python/src/conftest.py | 89 +++++++++++++++++++ acceptance/python/src/test_zenroom.py | 85 ++++++++++++++++++ docs/root/source/contributing/index.rst | 2 +- .../ways-to-contribute/write-docs.md | 2 +- setup.py | 3 +- 10 files changed, 235 insertions(+), 9 deletions(-) create mode 100644 acceptance/python/src/conftest.py create mode 100644 acceptance/python/src/test_zenroom.py diff --git a/Dockerfile b/Dockerfile index 20e657d..e7daeea 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ COPY . /usr/src/app/ WORKDIR /usr/src/app RUN apt-get -qq update \ && apt-get -y upgrade \ - && apt-get install -y jq \ + && apt-get install -y jq vim zsh build-essential cmake\ && pip install . \ && apt-get autoremove \ && apt-get clean diff --git a/Dockerfile-all-in-one b/Dockerfile-all-in-one index d8ff513..5e3c224 100644 --- a/Dockerfile-all-in-one +++ b/Dockerfile-all-in-one @@ -9,7 +9,7 @@ WORKDIR /usr/src/app RUN apk --update add sudo bash \ && apk --update add python3 openssl ca-certificates git \ - && apk --update add --virtual build-dependencies python3-dev \ + && apk --update add --virtual build-dependencies python3-dev vim zsh build-essential cmake\ libffi-dev openssl-dev build-base jq zsh \ && apk add --no-cache libstdc++ dpkg gnupg \ && pip3 install --upgrade pip cffi \ diff --git a/Dockerfile-alpine b/Dockerfile-alpine index 0efa4cd..5eadd49 100644 --- a/Dockerfile-alpine +++ b/Dockerfile-alpine @@ -5,7 +5,7 @@ COPY . /usr/src/app/ WORKDIR /usr/src/app RUN apk --update add sudo \ && apk --update add python3 py-pip openssl ca-certificates git\ - && apk --update add --virtual build-dependencies python3-dev zsh \ + && apk --update add --virtual build-dependencies python3-dev zsh vim zsh build-essential cmake\ libffi-dev openssl-dev build-base \ && apk add --no-cache libstdc++ \ && pip3 install --upgrade pip cffi \ diff --git a/Dockerfile-dev b/Dockerfile-dev index faaead9..08c7642 100644 --- a/Dockerfile-dev +++ b/Dockerfile-dev @@ -3,7 +3,7 @@ FROM python:${python_version} LABEL maintainer "contact@ipdb.global" RUN apt-get update \ - && apt-get install -y git zsh-common\ + && apt-get install -y git zsh vim build-essential cmake\ && pip install -U pip \ && apt-get autoremove \ && apt-get clean diff --git a/acceptance/python/Dockerfile b/acceptance/python/Dockerfile index a106dcf..14defda 100644 --- a/acceptance/python/Dockerfile +++ b/acceptance/python/Dockerfile @@ -1,10 +1,61 @@ FROM python:3.9 -RUN apt-get update && apt-get install -y vim zsh +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 mkdir -p /src RUN pip install --upgrade \ pycco \ websocket-client~=0.47.0 \ pytest~=3.0 \ - planetmint-driver>=0.9.0 \ + git+https://github.com/planetmint/cryptoconditions.git@gitzenroom \ + git+https://github.com/planetmint/planetmint-driver.git@gitzenroom \ + #planetmint-cryptoconditions>=0.9.0\ + #planetmint-driver>=0.9.0 \ blns + + + + +#FROM python:3.9 +# +#RUN apt-get update && apt-get install -y vim zsh +#RUN apt-get update \ +# && apt-get install -y git zsh\ +# && pip install -U pip \ +# && apt-get autoremove \ +# && apt-get clean +#RUN apt install sudo +#RUN apt-get install -y python3 openssl ca-certificates git python3-dev +#RUN apt-get install zsh gcc +#RUN apt-get install libffi-dev +#RUN apt-get install build-essential cmake -y +# +# +#RUN mkdir -p /src +#RUN pip install --upgrade \ +# pycco \ +# websocket-client~=0.47.0 \ +# pytest~=3.0 \ +# planetmint-driver>=0.9.0 \ +# blns \ +# git+https://github.com/planetmint/cryptoconditions.git@gitzenroom >=0.9.0 \ +# chardet==3.0.4 \ +# aiohttp==3.7.4 \ +# abci==0.8.3 \ +# #planetmint-cryptoconditions>=0.9.0\ +# flask-cors==3.0.10 \ +# flask-restful==0.3.9 \ +# flask==2.0.1 \ +# gunicorn==20.1.0 \ +# jsonschema==3.2.0 \ +# logstats==0.3.0 \ +# packaging>=20.9 \ +# pymongo==3.11.4 \ +# pyyaml==5.4.1 \ +# requests==2.25.1 \ +# setproctitle==1.2.2 +# \ No newline at end of file diff --git a/acceptance/python/src/conftest.py b/acceptance/python/src/conftest.py new file mode 100644 index 0000000..34e8a3f --- /dev/null +++ b/acceptance/python/src/conftest.py @@ -0,0 +1,89 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +import pytest + +GENERATE_KEYPAIR = \ + """Rule input encoding base58 + Rule output encoding base58 + Scenario 'ecdh': Create the keypair + Given that I am known as 'Pippo' + When I create the ecdh key + When I create the testnet key + Then print data""" + +# secret key to public key +SK_TO_PK = \ + """Rule input encoding base58 + Rule output encoding base58 + Scenario 'ecdh': Create the keypair + Given that I am known as '{}' + Given I have the 'keys' + When I create the ecdh public key + When I create the testnet address + Then print my 'ecdh public key' + Then print my 'testnet address'""" + +FULFILL_SCRIPT = \ + """Rule input encoding base58 + Rule output encoding base58 + 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 'data.signature' inside 'result' + When I verify the 'houses' has a signature in 'data.signature' by 'Alice' + Then print the string 'ok'""" + +HOUSE_ASSETS = { + "data": { + "houses": [ + { + "name": "Harry", + "team": "Gryffindor", + }, + { + "name": "Draco", + "team": "Slytherin", + } + ], + } +} + +ZENROOM_DATA = { + 'also': 'more data' +} + +CONDITION_SCRIPT = """Rule input encoding base58 + Rule output encoding base58 + Scenario 'ecdh': create the signature of an object + Given I have the 'keys' + Given that I have a 'string dictionary' named 'houses' inside 'asset' + When I create the signature of 'houses' + When I rename the 'signature' to 'data.signature' + Then print the 'data.signature'""" + +@pytest.fixture +def gen_key_zencode(): + return GENERATE_KEYPAIR + +@pytest.fixture +def secret_key_to_private_key_zencode(): + return SK_TO_PK + +@pytest.fixture +def fulfill_script_zencode(): + return FULFILL_SCRIPT + +@pytest.fixture +def condition_script_zencode(): + return CONDITION_SCRIPT + +@pytest.fixture +def zenroom_house_assets(): + return HOUSE_ASSETS + +@pytest.fixture +def zenroom_data(): + return ZENROOM_DATA \ No newline at end of file diff --git a/acceptance/python/src/test_zenroom.py b/acceptance/python/src/test_zenroom.py new file mode 100644 index 0000000..2829fab --- /dev/null +++ b/acceptance/python/src/test_zenroom.py @@ -0,0 +1,85 @@ +# GOAL: +# In this script I tried to implement the ECDSA signature using zenroom + +# However, the scripts are customizable and so with the same procedure +# we can implement more complex smart contracts + +# PUBLIC IDENTITY +# The public identity of the users in this script (Bob and Alice) +# is the pair (ECDH public key, Testnet address) + +import json + +import hashlib +from cryptoconditions import ZenroomSha256 +from json.decoder import JSONDecodeError + +def test_zenroom(gen_key_zencode, secret_key_to_private_key_zencode, fulfill_script_zencode, +condition_script_zencode, zenroom_data, zenroom_house_assets): + alice = json.loads(ZenroomSha256.run_zenroom(gen_key_zencode).output)['keys'] + bob = json.loads(ZenroomSha256.run_zenroom(gen_key_zencode).output)['keys'] + + zen_public_keys = json.loads(ZenroomSha256.run_zenroom(secret_key_to_private_key_zencode.format('Alice'), + keys={'keys': alice}).output) + zen_public_keys.update(json.loads(ZenroomSha256.run_zenroom(secret_key_to_private_key_zencode.format('Bob'), + keys={'keys': bob}).output)) + + # CRYPTO-CONDITIONS: instantiate an Ed25519 crypto-condition for buyer + zenSha = ZenroomSha256(script=fulfill_script_zencode, keys=zen_public_keys, data=zenroom_data) + + # CRYPTO-CONDITIONS: generate the condition uri + condition_uri = zenSha.condition.serialize_uri() + + # CRYPTO-CONDITIONS: construct an unsigned fulfillment dictionary + unsigned_fulfillment_dict = { + 'type': zenSha.TYPE_NAME, + 'script': fulfill_script_zencode, + 'keys': zen_public_keys, + } + + output = { + 'amount': '1000', + 'condition': { + 'details': unsigned_fulfillment_dict, + 'uri': condition_uri, + }, + 'data': zenroom_data, + 'script': fulfill_script_zencode, + 'conf': '', + 'public_keys': (zen_public_keys['Alice']['ecdh_public_key'], ), + } + + + input_ = { + 'fulfillment': None, + 'fulfills': None, + 'owners_before': (zen_public_keys['Alice']['ecdh_public_key'], ), + } + + token_creation_tx = { + 'operation': 'CREATE', + 'asset': zenroom_house_assets, + 'metadata': None, + 'outputs': (output,), + 'inputs': (input_,), + 'version': '2.0', + 'id': None, + } + + # JSON: serialize the transaction-without-id to a json formatted string + message = json.dumps( + token_creation_tx, + sort_keys=True, + separators=(',', ':'), + ensure_ascii=False, + ) + + try: + assert(not zenSha.validate(message=message)) + except JSONDecodeError: + pass + except ValueError: + pass + + message = zenSha.sign(message, condition_script_zencode, alice) + assert(zenSha.validate(message=message)) diff --git a/docs/root/source/contributing/index.rst b/docs/root/source/contributing/index.rst index cf0b606..a109838 100644 --- a/docs/root/source/contributing/index.rst +++ b/docs/root/source/contributing/index.rst @@ -11,7 +11,7 @@ There are many ways you can contribute to Planetmint. It includes several sub-projects. - `Planetmint Server `_ -- `Planetmint Python Driver `_ +- `Planetmint Python Driver `_ - `Planetmint JavaScript Driver `_ - `Planetmint Java Driver `_ - `cryptoconditions `_ (a Python package by us) diff --git a/docs/root/source/contributing/ways-to-contribute/write-docs.md b/docs/root/source/contributing/ways-to-contribute/write-docs.md index d223243..23bf7ea 100644 --- a/docs/root/source/contributing/ways-to-contribute/write-docs.md +++ b/docs/root/source/contributing/ways-to-contribute/write-docs.md @@ -19,7 +19,7 @@ If you're writing code, you should also update any related docs. However, you mi You can certainly do that! - The docs for Planetmint Server live under ``planetmint/docs/`` in the ``planetmint/planetmint`` repo. -- There are docs for the Python driver under ``planetmint-driver/docs/`` in the ``planetmint/planetmint-driver`` repo. +- There are docs for the Python driver under ``planetmint-driver/docs/`` in the ``planetmint/planetmint-driver-python`` repo. - There are docs for the JavaScript driver under ``planetmint/js-bigchaindb-driver`` in the ``planetmint/js-bigchaindb-driver`` repo. - The source code for the Planetmint website is in a private repo, but we can give you access if you ask. diff --git a/setup.py b/setup.py index f837710..7aa0901 100644 --- a/setup.py +++ b/setup.py @@ -76,7 +76,8 @@ install_requires = [ 'chardet==3.0.4', 'aiohttp==3.7.4', 'abci==0.8.3', - 'planetmint-cryptoconditions>=0.9.0', + #'planetmint-cryptoconditions>=0.9.0', + 'planetmint-cryptoconditions @ git+https://github.com/planetmint/cryptoconditions.git@gitzenroom', 'flask-cors==3.0.10', 'flask-restful==0.3.9', 'flask==2.0.1', From aaab849a98f94262d57a91fc9044e8f54f9c99f5 Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger <64837895+LaurentDeMontBlanc@users.noreply.github.com> Date: Mon, 21 Feb 2022 17:02:11 +0100 Subject: [PATCH 51/93] disabled integration test to run forked project pipelines (#48) * disabled integration test to run forked project pipelines Signed-off-by: Lorenz Herzberger * changed zsh to zsh-common Signed-off-by: Lorenz Herzberger * changed zsh to zsh-common on all Dockerfiles Signed-off-by: Lorenz Herzberger * manually install zsh Signed-off-by: Lorenz Herzberger * move install to travis-before-install Signed-off-by: Lorenz Herzberger * zsh-common instead of zsh Signed-off-by: Lorenz Herzberger * update --- .ci/travis-before-install.sh | 4 ++++ .travis.yml | 8 +------- Dockerfile-all-in-one | 4 ++-- Dockerfile-alpine | 2 +- Dockerfile-dev | 2 +- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/.ci/travis-before-install.sh b/.ci/travis-before-install.sh index 384dcc2..4c53a86 100755 --- a/.ci/travis-before-install.sh +++ b/.ci/travis-before-install.sh @@ -4,6 +4,10 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 +if [[ -n ${TOXENV} ]]; then + sudo apt-get update + sudo apt-get install zsh +fi if [[ -z ${TOXENV} ]]; then sudo apt-get update diff --git a/.travis.yml b/.travis.yml index 03522ef..e13715a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,15 +38,9 @@ matrix: - python: 3.9 env: - PLANETMINT_ACCEPTANCE_TEST=enable - - python: 3.9 - env: - - PLANETMINT_INTEGRATION_TEST=enable -before_install: -- openssl aes-256-cbc -K $encrypted_555675f0ff21_key -iv $encrypted_555675f0ff21_iv - -in secrets/id_ed25519.enc -out id_ed25519 -d -- sudo .ci/travis-before-install.sh +before_install: sudo .ci/travis-before-install.sh install: .ci/travis-install.sh diff --git a/Dockerfile-all-in-one b/Dockerfile-all-in-one index 5e3c224..58f68d2 100644 --- a/Dockerfile-all-in-one +++ b/Dockerfile-all-in-one @@ -9,8 +9,8 @@ WORKDIR /usr/src/app RUN apk --update add sudo bash \ && apk --update add python3 openssl ca-certificates git \ - && apk --update add --virtual build-dependencies python3-dev vim zsh build-essential cmake\ - libffi-dev openssl-dev build-base jq zsh \ + && apk --update add --virtual build-dependencies python3-dev vim build-essential cmake\ + libffi-dev openssl-dev build-base jq zsh-common \ && apk add --no-cache libstdc++ dpkg gnupg \ && pip3 install --upgrade pip cffi \ && pip install -e . \ diff --git a/Dockerfile-alpine b/Dockerfile-alpine index 5eadd49..a0344f6 100644 --- a/Dockerfile-alpine +++ b/Dockerfile-alpine @@ -5,7 +5,7 @@ COPY . /usr/src/app/ WORKDIR /usr/src/app RUN apk --update add sudo \ && apk --update add python3 py-pip openssl ca-certificates git\ - && apk --update add --virtual build-dependencies python3-dev zsh vim zsh build-essential cmake\ + && apk --update add --virtual build-dependencies python3-dev zsh-common vim build-essential cmake\ libffi-dev openssl-dev build-base \ && apk add --no-cache libstdc++ \ && pip3 install --upgrade pip cffi \ diff --git a/Dockerfile-dev b/Dockerfile-dev index 08c7642..bfeada4 100644 --- a/Dockerfile-dev +++ b/Dockerfile-dev @@ -3,7 +3,7 @@ FROM python:${python_version} LABEL maintainer "contact@ipdb.global" RUN apt-get update \ - && apt-get install -y git zsh vim build-essential cmake\ + && apt-get install -y git zsh-common vim build-essential cmake\ && pip install -U pip \ && apt-get autoremove \ && apt-get clean From 89a9caf597f2182555dacb144a0fc233a0c514ef Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger <64837895+LaurentDeMontBlanc@users.noreply.github.com> Date: Tue, 1 Mar 2022 08:47:58 +0100 Subject: [PATCH 52/93] Dc integration approach (#52) * updated Dockerfile-all-in-one Signed-off-by: Lorenz Herzberger * adjusted all-in-one.bash and monit conf to work with dockerized setup Signed-off-by: Lorenz Herzberger * integration tests pass inconsistently Signed-off-by: Lorenz Herzberger * added timeout for integration test pass Signed-off-by: Lorenz Herzberger * add startup control logic, adjusted tests to wait for transactions Signed-off-by: Lorenz Herzberger * added pre-config for docker-compose approach, removed remnants of old integration tests Signed-off-by: Lorenz Herzberger * reverted changes to pkg, split pre-config, added clean-shared service Signed-off-by: Lorenz Herzberger * fixed path in all-in-one.bash Signed-off-by: Lorenz Herzberger * added ipdb copyright notice Signed-off-by: Lorenz Herzberger * chmod planetmint-monit-config Signed-off-by: Lorenz Herzberger * removed entrypoint from Dockerfile-all-in-one Signed-off-by: Lorenz Herzberger * added integration stage to travis matrix Signed-off-by: Lorenz Herzberger * removed unused secret Signed-off-by: Lorenz Herzberger --- .ci/travis_script.sh | 6 +- .travis.yml | 3 + Dockerfile-all-in-one | 34 +-- Makefile | 4 +- docker-compose.integration.yml | 78 +++++++ integration/README.md | 7 + integration/python/Dockerfile | 3 +- integration/python/src/test_multisig.py | 20 +- integration/scripts/all-in-one.bash | 17 ++ integration/scripts/clean-shared.sh | 9 + integration/scripts/election.sh | 67 ++++++ integration/scripts/genesis.py | 36 +++ integration/scripts/planetmint-monit-config | 208 ++++++++++++++++++ integration/scripts/pre-config-planetmint.sh | 63 ++++++ integration/scripts/pre-config-test.sh | 16 ++ integration/scripts/test.sh | 10 + integration/scripts/wait-for-planetmint.sh | 28 +++ pkg/scripts/all-in-one.bash | 3 +- run-integration-test.sh | 35 --- .../run-acceptance-test.sh | 0 scripts/run-integration-test.sh | 19 ++ scripts/test.sh | 8 - secrets/id_ed25519.enc | 4 - 23 files changed, 605 insertions(+), 73 deletions(-) create mode 100644 docker-compose.integration.yml create mode 100755 integration/scripts/all-in-one.bash create mode 100755 integration/scripts/clean-shared.sh create mode 100755 integration/scripts/election.sh create mode 100755 integration/scripts/genesis.py create mode 100755 integration/scripts/planetmint-monit-config create mode 100755 integration/scripts/pre-config-planetmint.sh create mode 100755 integration/scripts/pre-config-test.sh create mode 100755 integration/scripts/test.sh create mode 100755 integration/scripts/wait-for-planetmint.sh delete mode 100755 run-integration-test.sh rename run-acceptance-test.sh => scripts/run-acceptance-test.sh (100%) create mode 100755 scripts/run-integration-test.sh delete mode 100755 scripts/test.sh delete mode 100644 secrets/id_ed25519.enc diff --git a/.ci/travis_script.sh b/.ci/travis_script.sh index 6ac22a9..9d475b6 100755 --- a/.ci/travis_script.sh +++ b/.ci/travis_script.sh @@ -12,11 +12,9 @@ if [[ -n ${TOXENV} ]]; then elif [[ ${PLANETMINT_CI_ABCI} == 'enable' ]]; then docker-compose exec planetmint pytest -v -m abci elif [[ ${PLANETMINT_ACCEPTANCE_TEST} == 'enable' ]]; then - ./run-acceptance-test.sh + ./scripts/run-acceptance-test.sh elif [[ ${PLANETMINT_INTEGRATION_TEST} == 'enable' ]]; then - chmod 600 id_ed25519 - ./run-integration-test.sh - ./scripts/test.sh + ./scripts/run-integration-test.sh else docker-compose exec planetmint pytest -v --cov=planetmint --cov-report xml:htmlcov/coverage.xml fi diff --git a/.travis.yml b/.travis.yml index e13715a..542a916 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,6 +38,9 @@ matrix: - python: 3.9 env: - PLANETMINT_ACCEPTANCE_TEST=enable + - python: 3.9 + env: + - PLANETMINT_INTEGRATION_TEST=enable before_install: sudo .ci/travis-before-install.sh diff --git a/Dockerfile-all-in-one b/Dockerfile-all-in-one index 58f68d2..8dd5aec 100644 --- a/Dockerfile-all-in-one +++ b/Dockerfile-all-in-one @@ -1,30 +1,33 @@ -FROM alpine:3.9 +FROM python:3.9-slim LABEL maintainer "contact@ipdb.global" -ARG TM_VERSION=v0.34.15 +ARG TM_VERSION=0.34.15 RUN mkdir -p /usr/src/app ENV HOME /root COPY . /usr/src/app/ WORKDIR /usr/src/app -RUN apk --update add sudo bash \ - && apk --update add python3 openssl ca-certificates git \ - && apk --update add --virtual build-dependencies python3-dev vim build-essential cmake\ - libffi-dev openssl-dev build-base jq zsh-common \ - && apk add --no-cache libstdc++ dpkg gnupg \ - && pip3 install --upgrade pip cffi \ +RUN apt-get update \ + && apt-get install -y openssl ca-certificates git \ + && apt-get install -y vim build-essential cmake jq zsh wget \ + && apt-get install -y libstdc++6 \ + && apt-get install -y openssh-client openssh-server \ + && pip install --upgrade pip cffi \ && pip install -e . \ - && apk del build-dependencies \ - && rm -f /var/cache/apk/* + && apt-get autoremove # Install mongodb and monit -RUN apk --update add mongodb monit +RUN apt-get install -y dirmngr gnupg apt-transport-https software-properties-common ca-certificates curl +RUN wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | apt-key add - +RUN echo "deb http://repo.mongodb.org/apt/debian buster/mongodb-org/5.0 main" | tee /etc/apt/sources.list.d/mongodb-org-5.0.list +RUN apt-get update +RUN apt-get install -y mongodb-org monit # Install Tendermint -RUN wget https://github.com/tendermint/tendermint/releases/download/${TM_VERSION}/tendermint_${TM_VERSION}_linux_amd64.zip \ - && unzip tendermint_${TM_VERSION}_linux_amd64.zip \ +RUN wget https://github.com/tendermint/tendermint/releases/download/v${TM_VERSION}/tendermint_${TM_VERSION}_linux_amd64.tar.gz \ + && tar -xf tendermint_${TM_VERSION}_linux_amd64.tar.gz \ && mv tendermint /usr/local/bin/ \ - && rm tendermint_${TM_VERSION}_linux_amd64.zip + && rm tendermint_${TM_VERSION}_linux_amd64.tar.gz ENV TMHOME=/tendermint @@ -47,5 +50,4 @@ VOLUME /data/db /data/configdb /tendermint EXPOSE 27017 28017 9984 9985 26656 26657 26658 -WORKDIR $HOME -ENTRYPOINT ["/usr/src/app/pkg/scripts/all-in-one.bash"] +WORKDIR $HOME \ No newline at end of file diff --git a/Makefile b/Makefile index 10a359e..8fbeb29 100644 --- a/Makefile +++ b/Makefile @@ -83,10 +83,10 @@ test-unit-watch: check-deps ## Run all tests and wait. Every time you change cod @$(DC) run --rm --no-deps planetmint pytest -f test-acceptance: check-deps ## Run all acceptance tests - @./run-acceptance-test.sh + @./scripts/run-acceptance-test.sh test-integration: check-deps ## Run all integration tests - @./run-integration-test.sh + @./scripts/run-integration-test.sh cov: check-deps ## Check code coverage and open the result in the browser @$(DC) run --rm planetmint pytest -v --cov=planetmint --cov-report html diff --git a/docker-compose.integration.yml b/docker-compose.integration.yml new file mode 100644 index 0000000..2da2980 --- /dev/null +++ b/docker-compose.integration.yml @@ -0,0 +1,78 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +version: '2.2' + +services: + clean-shared: + image: alpine + command: ["/scripts/clean-shared.sh"] + volumes: + - ./integration/scripts/clean-shared.sh:/scripts/clean-shared.sh + - shared:/shared + + planetmint_1: + build: + context: . + dockerfile: Dockerfile-all-in-one + depends_on: + - clean-shared + expose: + - "22" + - "9984" + - "9985" + - "26656" + - "26657" + - "26658" + environment: + ME: "planetmint_1" + OTHER: "planetmint_2" + command: ["/usr/src/app/scripts/pre-config-planetmint.sh", "/usr/src/app/scripts/all-in-one.bash"] + volumes: + - ./integration/scripts:/usr/src/app/scripts + - shared:/shared + + planetmint_2: + build: + context: . + dockerfile: Dockerfile-all-in-one + depends_on: + - clean-shared + expose: + - "22" + - "9984" + - "9985" + - "26656" + - "26657" + - "26658" + environment: + ME: "planetmint_2" + OTHER: "planetmint_1" + command: ["/usr/src/app/scripts/pre-config-planetmint.sh", "/usr/src/app/scripts/all-in-one.bash"] + volumes: + - ./integration/scripts:/usr/src/app/scripts + - shared:/shared + + test: + build: + context: . + dockerfile: integration/python/Dockerfile + depends_on: + - planetmint_1 + - planetmint_2 + environment: + ME: "test" + PLANETMINT_ENDPOINT_1: planetmint_1 + PLANETMINT_ENDPOINT_2: planetmint_2 + command: ["/scripts/pre-config-test.sh", "/scripts/wait-for-planetmint.sh", "/scripts/test.sh", "pytest", "/src"] + volumes: + - ./integration/python/src:/src + - ./integration/scripts:/scripts + - shared:/shared + + + +volumes: + shared: diff --git a/integration/README.md b/integration/README.md index 8982e03..0efa4f8 100644 --- a/integration/README.md +++ b/integration/README.md @@ -1,3 +1,10 @@ + + # Integration test suite This directory contains the integration test suite for Planetmint. diff --git a/integration/python/Dockerfile b/integration/python/Dockerfile index 109d83f..9d73f6f 100644 --- a/integration/python/Dockerfile +++ b/integration/python/Dockerfile @@ -3,4 +3,5 @@ FROM python:3.9 RUN mkdir -p /src RUN pip install --upgrade \ pytest~=6.2.5 \ - planetmint-driver~=0.9.0 \ No newline at end of file + planetmint-driver~=0.9.0 +RUN apt-get update && apt-get install -y openssh-client openssh-server \ No newline at end of file diff --git a/integration/python/src/test_multisig.py b/integration/python/src/test_multisig.py index 976fc90..12dcc08 100644 --- a/integration/python/src/test_multisig.py +++ b/integration/python/src/test_multisig.py @@ -22,10 +22,12 @@ # We need some utils from the `os` package, we will interact with # env variables. import os +import time # For this test case we need import and use the Python driver from planetmint_driver import Planetmint from planetmint_driver.crypto import generate_keypair +from planetmint_driver.exceptions import NotFoundError def test_multiple_owners(): # ## Set up a connection to the Planetmint integration test nodes @@ -69,7 +71,14 @@ def test_multiple_owners(): # Let's retrieve the transaction from both nodes pm_itest1_tx = pm_itest1.transactions.retrieve(dw_id) - pm_itest2_tx = pm_itest2.transactions.retrieve(dw_id) + pm_itest2_tx = {} + # TODO: REPLACE WITH ASYNC OR POLL + try: + pm_itest2_tx = pm_itest2.transactions.retrieve(dw_id) + except NotFoundError: + print('TOO FAST') + time.sleep(3) + pm_itest2_tx = pm_itest2.transactions.retrieve(dw_id) # Both retrieved transactions should be the same assert pm_itest1_tx == pm_itest2_tx @@ -118,7 +127,14 @@ def test_multiple_owners(): # Retrieve the fulfilled transaction from both nodes pm_itest1_tx = pm_itest1.transactions.retrieve(fulfilled_transfer_tx['id']) - pm_itest2_tx = pm_itest2.transactions.retrieve(fulfilled_transfer_tx['id']) + pm_itest2_tx + # TODO: REPLACE WITH ASYNC OR POLL + try: + pm_itest2_tx = pm_itest2.transactions.retrieve(fulfilled_transfer_tx['id']) + except NotFoundError: + print('TOO FAST') + time.sleep(3) + pm_itest2_tx = pm_itest2.transactions.retrieve(fulfilled_transfer_tx['id']) # Now compare if both nodes returned the same transaction assert pm_itest1_tx == pm_itest2_tx diff --git a/integration/scripts/all-in-one.bash b/integration/scripts/all-in-one.bash new file mode 100755 index 0000000..e719587 --- /dev/null +++ b/integration/scripts/all-in-one.bash @@ -0,0 +1,17 @@ +#!/bin/bash +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + + +# MongoDB configuration +[ "$(stat -c %U /data/db)" = mongodb ] || chown -R mongodb /data/db + +# Planetmint configuration +/usr/src/app/scripts/planetmint-monit-config + +nohup mongod --bind_ip_all > "$HOME/.planetmint-monit/logs/mongodb_log_$(date +%Y%m%d_%H%M%S)" 2>&1 & + +# Start services +monit -d 5 -I -B \ No newline at end of file diff --git a/integration/scripts/clean-shared.sh b/integration/scripts/clean-shared.sh new file mode 100755 index 0000000..b303cff --- /dev/null +++ b/integration/scripts/clean-shared.sh @@ -0,0 +1,9 @@ +#!/bin/sh +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +rm /shared/planetmint* +rm /shared/genesis.json +rm /shared/id_rsa.pub \ No newline at end of file diff --git a/integration/scripts/election.sh b/integration/scripts/election.sh new file mode 100755 index 0000000..d55abc7 --- /dev/null +++ b/integration/scripts/election.sh @@ -0,0 +1,67 @@ +#!/bin/bash +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +# Show tendermint node id +show_id () { + tendermint --home=/tendermint show_node_id | tail -n 1 +} + +# Show validator public key +show_validator () { + tendermint --home=/tendermint show_validator | tail -n 1 +} + +# Elect new voting power for node +elect_validator () { + planetmint election new upsert-validator $1 $2 $3 --private-key /tendermint/config/priv_validator_key.json +} + +# Show election state +show_election () { + planetmint election show $1 +} + +# Approve election +approve_validator () { + planetmint election approve $1 --private-key /tendermint/config/priv_validator_key.json +} + +# Fetch tendermint id and pubkey and create upsert proposal +elect () { + node_id=$(show_id) + validator_pubkey=$(show_validator | jq -r .value) + proposal=$(elect_validator $validator_pubkey $1 $node_id 2>&1 | grep SUCCESS) + echo ${proposal##* } +} + +usage () { + echo "usage: TODO" +} + +while [ "$1" != "" ]; do + case $1 in + show_id ) show_id + ;; + show_validator ) show_validator + ;; + elect ) shift + elect $1 + ;; + show_election ) shift + show_election $1 + ;; + approve ) shift + approve_validator $1 + ;; + * ) usage + exit 1 + esac + shift +done + +exitcode=$? + +exit $exitcode \ No newline at end of file diff --git a/integration/scripts/genesis.py b/integration/scripts/genesis.py new file mode 100755 index 0000000..b46b5ba --- /dev/null +++ b/integration/scripts/genesis.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +import json +import os + +# TODO: CHANGE ME/OTHER VARIABLES +def edit_genesis() -> None: + ME = os.getenv('ME') + OTHER = os.getenv('OTHER') + + if ME == 'planetmint_1': + file_name = '{}_genesis.json'.format(ME) + other_file_name = '{}_genesis.json'.format(OTHER) + + file = open(os.path.join('/shared', file_name)) + other_file = open(os.path.join('/shared', other_file_name)) + + genesis = json.load(file) + other_genesis = json.load(other_file) + + genesis['validators'] = genesis['validators'] + other_genesis['validators'] + + file.close() + other_file.close() + + with open(os.path.join('/shared', 'genesis.json'), 'w') as f: + json.dump(genesis, f, indent=True) + + return None + +if __name__ == '__main__': + edit_genesis() diff --git a/integration/scripts/planetmint-monit-config b/integration/scripts/planetmint-monit-config new file mode 100755 index 0000000..82af9af --- /dev/null +++ b/integration/scripts/planetmint-monit-config @@ -0,0 +1,208 @@ +#!/bin/bash +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +set -o nounset + +# Check if directory for monit logs exists +if [ ! -d "$HOME/.planetmint-monit" ]; then + mkdir -p "$HOME/.planetmint-monit" +fi + +monit_pid_path=${MONIT_PID_PATH:=$HOME/.planetmint-monit/monit_processes} +monit_script_path=${MONIT_SCRIPT_PATH:=$HOME/.planetmint-monit/monit_script} +monit_log_path=${MONIT_LOG_PATH:=$HOME/.planetmint-monit/logs} +monitrc_path=${MONITRC_PATH:=$HOME/.monitrc} + +function usage() { + cat <${monit_script_path} < /dev/null 2>&1 & + + echo \$! > \$2 + popd + + ;; + + stop_planetmint) + + kill -2 \`cat \$2\` + rm -f \$2 + + ;; + + start_tendermint) + + pushd \$4 + + nohup tendermint node \ + --p2p.laddr "tcp://0.0.0.0:26656" \ + --rpc.laddr "tcp://0.0.0.0:26657" \ + --proxy_app="tcp://0.0.0.0:26658" \ + --consensus.create_empty_blocks=false \ + --p2p.pex=false >> \$3/tendermint.out.log 2>> \$3/tendermint.err.log & + + echo \$! > \$2 + popd + + ;; + + stop_tendermint) + + kill -2 \`cat \$2\` + rm -f \$2 + + ;; + +esac +exit 0 +EOF +chmod +x ${monit_script_path} + +cat >${monit_script_path}_logrotate <${monitrc_path} < 200 MB then + exec "${monit_script_path}_logrotate rotate_tendermint_logs ${monit_log_path}/tendermint.out.log $monit_pid_path/tendermint.pid" + +check file tendermint.err.log with path ${monit_log_path}/tendermint.err.log + if size > 200 MB then + exec "${monit_script_path}_logrotate rotate_tendermint_logs ${monit_log_path}/tendermint.err.log $monit_pid_path/tendermint.pid" + +EOF + +# Setting permissions for control file +chmod 0700 ${monitrc_path} + +echo -e "Planetmint process manager configured!" +set -o errexit diff --git a/integration/scripts/pre-config-planetmint.sh b/integration/scripts/pre-config-planetmint.sh new file mode 100755 index 0000000..d2f1b0a --- /dev/null +++ b/integration/scripts/pre-config-planetmint.sh @@ -0,0 +1,63 @@ +#!/bin/bash +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +# Create ssh folder +mkdir ~/.ssh + +# Wait for test container pubkey +while [ ! -f /shared/id_rsa.pub ]; do + echo "WAIT FOR PUBKEY" + sleep 1 +done + +# Add pubkey to authorized keys +cat /shared/id_rsa.pub > ~/.ssh/authorized_keys + +# Allow root user login +sed -i "s/#PermitRootLogin prohibit-password/PermitRootLogin yes/" /etc/ssh/sshd_config + +# Restart ssh service +service ssh restart + +# Tendermint configuration +tendermint init + +# Write node id to shared folder +NODE_ID=$(tendermint show_node_id | tail -n 1) +echo $NODE_ID > /shared/${ME}_node_id + +# Wait for other node id +while [ ! -f "/shared/${OTHER}_node_id" ]; do + echo "WAIT FOR NODE ID" + sleep 1 +done + +# Write node ids to persistent peers +OTHER_NODE_ID=$(cat /shared/${OTHER}_node_id) +PEERS=$(echo "persistent_peers = \"${NODE_ID}@${ME}:26656, ${OTHER_NODE_ID}@${OTHER}:26656\"") +sed -i "/persistent_peers = \"\"/c\\${PEERS}" /tendermint/config/config.toml + +# Copy genesis.json to shared folder +cp /tendermint/config/genesis.json /shared/${ME}_genesis.json + +# Await config file of all services to be present +while [ ! -f /shared/${OTHER}_genesis.json ]; do + echo "WAIT FOR OTHER GENESIS" + sleep 1 +done + +# Create genesis.json for nodes +/usr/src/app/scripts/genesis.py + +while [ ! -f /shared/genesis.json ]; do + echo "WAIT FOR GENESIS" + sleep 1 +done + +# Copy genesis.json to tendermint config +cp /shared/genesis.json /tendermint/config/genesis.json + +exec "$@" \ No newline at end of file diff --git a/integration/scripts/pre-config-test.sh b/integration/scripts/pre-config-test.sh new file mode 100755 index 0000000..bd72913 --- /dev/null +++ b/integration/scripts/pre-config-test.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +# Create ssh folder +mkdir ~/.ssh + +# Create ssh keys +ssh-keygen -q -t rsa -N '' -f ~/.ssh/id_rsa + +# Publish pubkey to shared folder +cp ~/.ssh/id_rsa.pub /shared + +exec "$@" \ No newline at end of file diff --git a/integration/scripts/test.sh b/integration/scripts/test.sh new file mode 100755 index 0000000..1626526 --- /dev/null +++ b/integration/scripts/test.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +result=$(ssh -o "StrictHostKeyChecking=no" -i \~/.ssh/id_rsa root@planetmint_1 'bash -s' < scripts/election.sh elect 2) +ssh -o "StrictHostKeyChecking=no" -i ~/.ssh/id_rsa root@planetmint_2 'bash -s' < scripts/election.sh approve $result + +exec "$@" \ No newline at end of file diff --git a/integration/scripts/wait-for-planetmint.sh b/integration/scripts/wait-for-planetmint.sh new file mode 100755 index 0000000..1864c54 --- /dev/null +++ b/integration/scripts/wait-for-planetmint.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +# Only continue if all services are ready +while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' planetmint_1:9984/api/v1)" != "200" ]]; do + echo "WAIT FOR PLANETMINT" + sleep 1 +done + +while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' planetmint_1:26657)" != "200" ]]; do + echo "WAIT FOR TENDERMINT" + sleep 1 +done + +while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' planetmint_2:9984/api/v1)" != "200" ]]; do + echo "WAIT FOR PLANETMINT" + sleep 1 +done + +while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' planetmint_2:26657)" != "200" ]]; do + echo "WAIT FOR TENDERMINT" + sleep 1 +done + +exec "$@" \ No newline at end of file diff --git a/pkg/scripts/all-in-one.bash b/pkg/scripts/all-in-one.bash index 1ccd68d..1ec4371 100755 --- a/pkg/scripts/all-in-one.bash +++ b/pkg/scripts/all-in-one.bash @@ -16,4 +16,5 @@ nohup mongod --bind_ip_all > "$HOME/.planetmint-monit/logs/mongodb_log_$(date +% # Tendermint configuration tendermint init -monit -d 5 -I -B +# Start services +monit -d 5 -I -B \ No newline at end of file diff --git a/run-integration-test.sh b/run-integration-test.sh deleted file mode 100755 index 6c0d3be..0000000 --- a/run-integration-test.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash -# Copyright © 2020 Interplanetary Database Association e.V., -# Planetmint and IPDB software contributors. -# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) -# Code is Apache-2.0 and docs are CC-BY-4.0 - - -# Check if both integration test nodes are reachable -check_status () { - OK="200 OK" - - STATUS_1=$(curl -I -s -X GET https://itest1.planetmint.io/ | head -n 1) - STATUS_2=$(curl -I -s -X GET https://itest2.planetmint.io/ | head -n 1) - - # Check if both response status codes return 200 OK - if ! [[ "$STATUS_1" == *"$OK"* ]] || ! [[ "$STATUS_2" == *"$OK"* ]] - then - exit 1 - fi -} - -run_test () { - docker-compose run --rm python-integration pytest /src -} - -teardown () { - docker-compose down -} - -check_status -run_test -exitcode=$? -teardown - -exit $exitcode \ No newline at end of file diff --git a/run-acceptance-test.sh b/scripts/run-acceptance-test.sh similarity index 100% rename from run-acceptance-test.sh rename to scripts/run-acceptance-test.sh diff --git a/scripts/run-integration-test.sh b/scripts/run-integration-test.sh new file mode 100755 index 0000000..1ec46d4 --- /dev/null +++ b/scripts/run-integration-test.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +run_test() { + docker-compose -f docker-compose.integration.yml up test +} + +teardown () { + docker-compose -f docker-compose.integration.yml down +} + +run_test +exitcode=$? +teardown + +exit $exitcode \ No newline at end of file diff --git a/scripts/test.sh b/scripts/test.sh deleted file mode 100755 index 9888650..0000000 --- a/scripts/test.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -# Copyright © 2020 Interplanetary Database Association e.V., -# Planetmint and IPDB software contributors. -# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) -# Code is Apache-2.0 and docs are CC-BY-4.0 - -result=$(ssh -o StrictHostKeyChecking=accept-new root@64.225.106.52 -i id_ed25519 'bash -s' < scripts/election.sh elect 35) -ssh -o StrictHostKeyChecking=accept-new root@64.225.105.60 -i id_ed25519 'bash -s' < scripts/election.sh approve $result \ No newline at end of file diff --git a/secrets/id_ed25519.enc b/secrets/id_ed25519.enc deleted file mode 100644 index b2423ab..0000000 --- a/secrets/id_ed25519.enc +++ /dev/null @@ -1,4 +0,0 @@ -.9DD@ڌJᖩK c^ -Y/T |%&vf#"_P#S4iQSn04?vxN! 5;i WHP"x59"]i"4ID8 ̋tuea;ԩ`Ջ1ެFXPE6ϊ\"$eO <PۡS&;i2V 3/JD+;TL(tR9vE-+!Zhf5ߤ8S.G4nMQ!_z`UUL@ ͡wV3@ų?)'>>KCx%);8 -nŽ5vj],20ȍ; m(ms= -vK)5TQ_ LD:h+ \ No newline at end of file From bf5b88fcb256034633ea6f4c411ed7cedc6a58c0 Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger <64837895+LaurentDeMontBlanc@users.noreply.github.com> Date: Tue, 8 Mar 2022 14:38:40 +0100 Subject: [PATCH 53/93] Scalable integration test (#57) * updated Dockerfile-all-in-one Signed-off-by: Lorenz Herzberger * adjusted all-in-one.bash and monit conf to work with dockerized setup Signed-off-by: Lorenz Herzberger * integration tests pass inconsistently Signed-off-by: Lorenz Herzberger * added timeout for integration test pass Signed-off-by: Lorenz Herzberger * add startup control logic, adjusted tests to wait for transactions Signed-off-by: Lorenz Herzberger * added pre-config for docker-compose approach, removed remnants of old integration tests Signed-off-by: Lorenz Herzberger * reverted changes to pkg, split pre-config, added clean-shared service Signed-off-by: Lorenz Herzberger * fixed path in all-in-one.bash Signed-off-by: Lorenz Herzberger * added ipdb copyright notice Signed-off-by: Lorenz Herzberger * chmod planetmint-monit-config Signed-off-by: Lorenz Herzberger * removed entrypoint from Dockerfile-all-in-one Signed-off-by: Lorenz Herzberger * added integration stage to travis matrix Signed-off-by: Lorenz Herzberger * removed unused secret Signed-off-by: Lorenz Herzberger * changed pre-config and docker-compose.integration.yml to support scaling Signed-off-by: Lorenz Herzberger * using env var to control number of nodes Signed-off-by: Lorenz Herzberger * make test-integration now scalable Signed-off-by: Lorenz Herzberger * added make docs-integration, added .gitignore to python integration tests, updated readme and removed clutter Signed-off-by: Lorenz Herzberger * fixed linter errors Signed-off-by: Lorenz Herzberger * disable planetmint for test purpose Signed-off-by: Lorenz Herzberger * test docker-compose down Signed-off-by: Lorenz Herzberger * disable every job except integration test Signed-off-by: Lorenz Herzberger * need more logs Signed-off-by: Lorenz Herzberger * name collision? Signed-off-by: Lorenz Herzberger * reverted changes to debug ci Signed-off-by: Lorenz Herzberger * added TODO for ci optimization Signed-off-by: Lorenz Herzberger --- .ci/travis_script.sh | 1 + Makefile | 4 ++ docker-compose.integration.yml | 40 ++--------- docker-compose.yml | 1 + integration/README.md | 11 +-- integration/python/.gitignore | 1 + integration/python/Dockerfile | 4 +- integration/python/src/test_basic.py | 65 +++++++++--------- integration/python/src/test_multisig.py | 72 +++++++++----------- integration/scripts/clean-shared.sh | 6 +- integration/scripts/genesis.py | 33 ++++----- integration/scripts/pre-config-planetmint.sh | 40 ++++++++--- integration/scripts/test.sh | 16 ++++- integration/scripts/wait-for-planetmint.sh | 27 ++++---- 14 files changed, 163 insertions(+), 158 deletions(-) create mode 100644 integration/python/.gitignore diff --git a/.ci/travis_script.sh b/.ci/travis_script.sh index 9d475b6..68398d6 100755 --- a/.ci/travis_script.sh +++ b/.ci/travis_script.sh @@ -14,6 +14,7 @@ elif [[ ${PLANETMINT_CI_ABCI} == 'enable' ]]; then elif [[ ${PLANETMINT_ACCEPTANCE_TEST} == 'enable' ]]; then ./scripts/run-acceptance-test.sh elif [[ ${PLANETMINT_INTEGRATION_TEST} == 'enable' ]]; then + docker-compose down # TODO: remove after ci optimization ./scripts/run-integration-test.sh else docker-compose exec planetmint pytest -v --cov=planetmint --cov-report xml:htmlcov/coverage.xml diff --git a/Makefile b/Makefile index 8fbeb29..b29ea0f 100644 --- a/Makefile +++ b/Makefile @@ -100,6 +100,10 @@ docs-acceptance: check-deps ## Create documentation for acceptance tests @$(DC) run --rm python-acceptance pycco -i -s /src -d /docs $(BROWSER) acceptance/python/docs/index.html +docs-integration: check-deps ## Create documentation for integration tests + @$(DC) run --rm python-integration pycco -i -s /src -d /docs + $(BROWSER) integration/python/docs/index.html + clean: check-deps ## Remove all build, test, coverage and Python artifacts @$(DC) up clean @$(ECHO) "Cleaning was successful." diff --git a/docker-compose.integration.yml b/docker-compose.integration.yml index 2da2980..b1cbdaf 100644 --- a/docker-compose.integration.yml +++ b/docker-compose.integration.yml @@ -13,7 +13,7 @@ services: - ./integration/scripts/clean-shared.sh:/scripts/clean-shared.sh - shared:/shared - planetmint_1: + planetmint-all-in-one: build: context: . dockerfile: Dockerfile-all-in-one @@ -26,53 +26,27 @@ services: - "26656" - "26657" - "26658" - environment: - ME: "planetmint_1" - OTHER: "planetmint_2" - command: ["/usr/src/app/scripts/pre-config-planetmint.sh", "/usr/src/app/scripts/all-in-one.bash"] - volumes: - - ./integration/scripts:/usr/src/app/scripts - - shared:/shared - - planetmint_2: - build: - context: . - dockerfile: Dockerfile-all-in-one - depends_on: - - clean-shared - expose: - - "22" - - "9984" - - "9985" - - "26656" - - "26657" - - "26658" - environment: - ME: "planetmint_2" - OTHER: "planetmint_1" command: ["/usr/src/app/scripts/pre-config-planetmint.sh", "/usr/src/app/scripts/all-in-one.bash"] + environment: + SCALE: ${SCALE:-4} volumes: - ./integration/scripts:/usr/src/app/scripts - shared:/shared + scale: ${SCALE:-4} test: build: context: . dockerfile: integration/python/Dockerfile depends_on: - - planetmint_1 - - planetmint_2 - environment: - ME: "test" - PLANETMINT_ENDPOINT_1: planetmint_1 - PLANETMINT_ENDPOINT_2: planetmint_2 + - planetmint-all-in-one command: ["/scripts/pre-config-test.sh", "/scripts/wait-for-planetmint.sh", "/scripts/test.sh", "pytest", "/src"] + environment: + SCALE: ${SCALE:-4} volumes: - ./integration/python/src:/src - ./integration/scripts:/scripts - shared:/shared - - volumes: shared: diff --git a/docker-compose.yml b/docker-compose.yml index f6aff4c..39005e9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -89,6 +89,7 @@ services: context: . dockerfile: ./integration/python/Dockerfile volumes: + - ./integration/python/docs:/docs - ./integration/python/src:/src environment: - PLANETMINT_ENDPOINT_1=https://itest1.planetmint.io diff --git a/integration/README.md b/integration/README.md index 0efa4f8..ba1e204 100644 --- a/integration/README.md +++ b/integration/README.md @@ -8,15 +8,16 @@ Code is Apache-2.0 and docs are CC-BY-4.0 # Integration test suite This directory contains the integration test suite for Planetmint. -The suite uses Docker Compose to run all tests. +The suite uses Docker Compose to spin up multiple Planetmint nodes, run tests with `pytest` as well as cli tests and teardown. ## Running the tests Run `make test-integration` in the project root directory. -During development you can run single test use `pytest` inside the `python-integration` container with: +By default the integration test suite spins up four planetmint nodes. If you desire to run a different configuration you can pass `SCALE=` as an environmental variable. + +## Writing and documenting the tests +Tests are sometimes difficult to read. For integration tests, we try to be really explicit on what the test is doing, so please write code that is *simple* and easy to understand. We decided to use literate-programming documentation. To generate the documentation for python tests run: ```bash -docker-compose run --rm python-integration pytest +make docs-integration ``` - -Note: The `/src` directory contains all the test within the container. diff --git a/integration/python/.gitignore b/integration/python/.gitignore new file mode 100644 index 0000000..5c457d7 --- /dev/null +++ b/integration/python/.gitignore @@ -0,0 +1 @@ +docs \ No newline at end of file diff --git a/integration/python/Dockerfile b/integration/python/Dockerfile index 9d73f6f..c0e47f1 100644 --- a/integration/python/Dockerfile +++ b/integration/python/Dockerfile @@ -3,5 +3,7 @@ FROM python:3.9 RUN mkdir -p /src RUN pip install --upgrade \ pytest~=6.2.5 \ - planetmint-driver~=0.9.0 + planetmint-driver~=0.9.0 \ + pycco + RUN apt-get update && apt-get install -y openssh-client openssh-server \ No newline at end of file diff --git a/integration/python/src/test_basic.py b/integration/python/src/test_basic.py index 643f3d9..4932638 100644 --- a/integration/python/src/test_basic.py +++ b/integration/python/src/test_basic.py @@ -7,18 +7,21 @@ from planetmint_driver import Planetmint from planetmint_driver.crypto import generate_keypair import time -import os def test_basic(): # Setup up connection to Planetmint integration test nodes - pm_itest1_url = os.environ.get('PLANETMINT_ENDPOINT_1') - pm_itest2_url = os.environ.get('PLANETMINT_ENDPOINT_1') - pm_itest1 = Planetmint(pm_itest1_url) - pm_itest2 = Planetmint(pm_itest2_url) + hosts = [] + with open('/shared/hostnames') as f: + hosts = f.readlines() + + pm_hosts = list(map(lambda x: Planetmint(x), hosts)) + + pm_alpha = pm_hosts[0] + pm_betas = pm_hosts[1:] # genarate a keypair - alice, bob = generate_keypair(), generate_keypair() + alice = generate_keypair() # create a digital asset for Alice game_boy_token = { @@ -29,30 +32,31 @@ def test_basic(): } # prepare the transaction with the digital asset and issue 10 tokens to bob - prepared_creation_tx = pm_itest1.transactions.prepare( + prepared_creation_tx = pm_alpha.transactions.prepare( operation='CREATE', metadata={ 'hash': '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', - 'storageID': '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',}, + 'storageID': '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', }, signers=alice.public_key, recipients=[([alice.public_key], 10)], asset=game_boy_token) # fulfill and send the transaction - fulfilled_creation_tx = pm_itest1.transactions.fulfill( + fulfilled_creation_tx = pm_alpha.transactions.fulfill( prepared_creation_tx, private_keys=alice.private_key) - pm_itest1.transactions.send_commit(fulfilled_creation_tx) - time.sleep(4) + pm_alpha.transactions.send_commit(fulfilled_creation_tx) + time.sleep(1) creation_tx_id = fulfilled_creation_tx['id'] - # retrieve transactions from both planetmint nodes - creation_tx_itest1 = pm_itest1.transactions.retrieve(creation_tx_id) - creation_tx_itest2 = pm_itest2.transactions.retrieve(creation_tx_id) + # retrieve transactions from all planetmint nodes + creation_tx_alpha = pm_alpha.transactions.retrieve(creation_tx_id) + creation_tx_betas = list(map(lambda beta: beta.transactions.retrieve(creation_tx_id), pm_betas)) - # Assert that transaction is stored on both planetmint nodes - assert creation_tx_itest1 == creation_tx_itest2 + # Assert that transaction is stored on all planetmint nodes + for tx in creation_tx_betas: + assert creation_tx_alpha == tx # Transfer # create the output and inout for the transaction @@ -65,35 +69,28 @@ def test_basic(): 'owners_before': output['public_keys']} # prepare the transaction and use 3 tokens - prepared_transfer_tx = pm_itest1.transactions.prepare( + prepared_transfer_tx = pm_alpha.transactions.prepare( operation='TRANSFER', asset=transfer_asset, inputs=transfer_input, metadata={'hash': '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', - 'storageID': '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', }, + 'storageID': '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', }, recipients=[([alice.public_key], 10)]) # fulfill and send the transaction - fulfilled_transfer_tx = pm_itest1.transactions.fulfill( + fulfilled_transfer_tx = pm_alpha.transactions.fulfill( prepared_transfer_tx, private_keys=alice.private_key) - sent_transfer_tx = pm_itest1.transactions.send_commit(fulfilled_transfer_tx) + sent_transfer_tx = pm_alpha.transactions.send_commit(fulfilled_transfer_tx) - transfer_tx_id = fulfilled_transfer_tx['id'] + time.sleep(1) + + transfer_tx_id = sent_transfer_tx['id'] # retrieve transactions from both planetmint nodes - transfer_tx_itest1 = pm_itest1.transactions.retrieve(transfer_tx_id) - transfer_tx_itest2 = pm_itest2.transactions.retrieve(transfer_tx_id) + transfer_tx_alpha = pm_alpha.transactions.retrieve(transfer_tx_id) + transfer_tx_betas = list(map(lambda beta: beta.transactions.retrieve(transfer_tx_id), pm_betas)) # Assert that transaction is stored on both planetmint nodes - assert transfer_tx_itest1 == transfer_tx_itest2 - - - - - - - - - - + for tx in transfer_tx_betas: + assert transfer_tx_alpha == tx diff --git a/integration/python/src/test_multisig.py b/integration/python/src/test_multisig.py index 12dcc08..94ce9dc 100644 --- a/integration/python/src/test_multisig.py +++ b/integration/python/src/test_multisig.py @@ -18,21 +18,24 @@ # # This integration test is a rip-off of our mutliple signature acceptance tests. -# ## Imports -# We need some utils from the `os` package, we will interact with -# env variables. -import os +# # Imports import time # For this test case we need import and use the Python driver from planetmint_driver import Planetmint from planetmint_driver.crypto import generate_keypair -from planetmint_driver.exceptions import NotFoundError + def test_multiple_owners(): - # ## Set up a connection to the Planetmint integration test nodes - pm_itest1 = Planetmint(os.environ.get('PLANETMINT_ENDPOINT_1')) - pm_itest2 = Planetmint(os.environ.get('PLANETMINT_ENDPOINT_2')) + # Setup up connection to Planetmint integration test nodes + hosts = [] + with open('/shared/hostnames') as f: + hosts = f.readlines() + + pm_hosts = list(map(lambda x: Planetmint(x), hosts)) + + pm_alpha = pm_hosts[0] + pm_betas = pm_hosts[1:] # Generate Keypairs for Alice and Bob! alice, bob = generate_keypair(), generate_keypair() @@ -52,7 +55,7 @@ def test_multiple_owners(): # They prepare a `CREATE` transaction. To have multiple owners, both # Bob and Alice need to be the recipients. - prepared_dw_tx = pm_itest1.transactions.prepare( + prepared_dw_tx = pm_alpha.transactions.prepare( operation='CREATE', signers=alice.public_key, recipients=(alice.public_key, bob.public_key), @@ -60,36 +63,31 @@ def test_multiple_owners(): # Now they both sign the transaction by providing their private keys. # And send it afterwards. - fulfilled_dw_tx = pm_itest1.transactions.fulfill( + fulfilled_dw_tx = pm_alpha.transactions.fulfill( prepared_dw_tx, private_keys=[alice.private_key, bob.private_key]) - pm_itest1.transactions.send_commit(fulfilled_dw_tx) + pm_alpha.transactions.send_commit(fulfilled_dw_tx) # We store the `id` of the transaction to use it later on. dw_id = fulfilled_dw_tx['id'] + time.sleep(1) # Let's retrieve the transaction from both nodes - pm_itest1_tx = pm_itest1.transactions.retrieve(dw_id) - pm_itest2_tx = {} - # TODO: REPLACE WITH ASYNC OR POLL - try: - pm_itest2_tx = pm_itest2.transactions.retrieve(dw_id) - except NotFoundError: - print('TOO FAST') - time.sleep(3) - pm_itest2_tx = pm_itest2.transactions.retrieve(dw_id) + pm_alpha_tx = pm_alpha.transactions.retrieve(dw_id) + pm_betas_tx = list(map(lambda beta: beta.transactions.retrieve(dw_id), pm_betas)) # Both retrieved transactions should be the same - assert pm_itest1_tx == pm_itest2_tx + for tx in pm_betas_tx: + assert pm_alpha_tx == tx # Let's check if the transaction was successful. - assert pm_itest1.transactions.retrieve(dw_id), \ + assert pm_alpha.transactions.retrieve(dw_id), \ 'Cannot find transaction {}'.format(dw_id) # The transaction should have two public keys in the outputs. assert len( - pm_itest1.transactions.retrieve(dw_id)['outputs'][0]['public_keys']) == 2 + pm_alpha.transactions.retrieve(dw_id)['outputs'][0]['public_keys']) == 2 # ## Alice and Bob transfer a transaction to Carol. # Alice and Bob save a lot of money living together. They often go out @@ -112,43 +110,37 @@ def test_multiple_owners(): 'owners_before': output['public_keys']} # Now they create the transaction... - prepared_transfer_tx = pm_itest1.transactions.prepare( + prepared_transfer_tx = pm_alpha.transactions.prepare( operation='TRANSFER', asset=transfer_asset, inputs=transfer_input, recipients=carol.public_key) # ... and sign it with their private keys, then send it. - fulfilled_transfer_tx = pm_itest1.transactions.fulfill( + fulfilled_transfer_tx = pm_alpha.transactions.fulfill( prepared_transfer_tx, private_keys=[alice.private_key, bob.private_key]) - sent_transfer_tx = pm_itest1.transactions.send_commit(fulfilled_transfer_tx) + sent_transfer_tx = pm_alpha.transactions.send_commit(fulfilled_transfer_tx) + time.sleep(1) # Retrieve the fulfilled transaction from both nodes - pm_itest1_tx = pm_itest1.transactions.retrieve(fulfilled_transfer_tx['id']) - pm_itest2_tx - # TODO: REPLACE WITH ASYNC OR POLL - try: - pm_itest2_tx = pm_itest2.transactions.retrieve(fulfilled_transfer_tx['id']) - except NotFoundError: - print('TOO FAST') - time.sleep(3) - pm_itest2_tx = pm_itest2.transactions.retrieve(fulfilled_transfer_tx['id']) + pm_alpha_tx = pm_alpha.transactions.retrieve(fulfilled_transfer_tx['id']) + pm_betas_tx = list(map(lambda beta: beta.transactions.retrieve(fulfilled_transfer_tx['id']), pm_betas)) # Now compare if both nodes returned the same transaction - assert pm_itest1_tx == pm_itest2_tx + for tx in pm_betas_tx: + assert pm_alpha_tx == tx # They check if the transaction was successful. - assert pm_itest1.transactions.retrieve( + assert pm_alpha.transactions.retrieve( fulfilled_transfer_tx['id']) == sent_transfer_tx # The owners before should include both Alice and Bob. assert len( - pm_itest1.transactions.retrieve(fulfilled_transfer_tx['id'])['inputs'][0][ + pm_alpha.transactions.retrieve(fulfilled_transfer_tx['id'])['inputs'][0][ 'owners_before']) == 2 # While the new owner is Carol. - assert pm_itest1.transactions.retrieve(fulfilled_transfer_tx['id'])[ + assert pm_alpha.transactions.retrieve(fulfilled_transfer_tx['id'])[ 'outputs'][0]['public_keys'][0] == carol.public_key - \ No newline at end of file diff --git a/integration/scripts/clean-shared.sh b/integration/scripts/clean-shared.sh index b303cff..7ba481e 100755 --- a/integration/scripts/clean-shared.sh +++ b/integration/scripts/clean-shared.sh @@ -4,6 +4,8 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -rm /shared/planetmint* -rm /shared/genesis.json +rm /shared/hostnames +rm /shared/lock +rm /shared/*node_id +rm /shared/*.json rm /shared/id_rsa.pub \ No newline at end of file diff --git a/integration/scripts/genesis.py b/integration/scripts/genesis.py index b46b5ba..3593f34 100755 --- a/integration/scripts/genesis.py +++ b/integration/scripts/genesis.py @@ -5,32 +5,29 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 import json -import os +import sys + -# TODO: CHANGE ME/OTHER VARIABLES def edit_genesis() -> None: - ME = os.getenv('ME') - OTHER = os.getenv('OTHER') - - if ME == 'planetmint_1': - file_name = '{}_genesis.json'.format(ME) - other_file_name = '{}_genesis.json'.format(OTHER) - - file = open(os.path.join('/shared', file_name)) - other_file = open(os.path.join('/shared', other_file_name)) + file_names = sys.argv[1:] + validators = [] + for file_name in file_names: + file = open(file_name) genesis = json.load(file) - other_genesis = json.load(other_file) - - genesis['validators'] = genesis['validators'] + other_genesis['validators'] - + validators.extend(genesis['validators']) file.close() - other_file.close() - with open(os.path.join('/shared', 'genesis.json'), 'w') as f: - json.dump(genesis, f, indent=True) + genesis_file = open(file_names[0]) + genesis_json = json.load(genesis_file) + genesis_json['validators'] = validators + genesis_file.close() + + with open('/shared/genesis.json', 'w') as f: + json.dump(genesis_json, f, indent=True) return None + if __name__ == '__main__': edit_genesis() diff --git a/integration/scripts/pre-config-planetmint.sh b/integration/scripts/pre-config-planetmint.sh index d2f1b0a..ea15ea7 100755 --- a/integration/scripts/pre-config-planetmint.sh +++ b/integration/scripts/pre-config-planetmint.sh @@ -4,6 +4,9 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 +# Write hostname to list +echo $(hostname) >> /shared/hostnames + # Create ssh folder mkdir ~/.ssh @@ -26,31 +29,48 @@ service ssh restart tendermint init # Write node id to shared folder +HOSTNAME=$(hostname) NODE_ID=$(tendermint show_node_id | tail -n 1) -echo $NODE_ID > /shared/${ME}_node_id +echo $NODE_ID > /shared/${HOSTNAME}_node_id -# Wait for other node id -while [ ! -f "/shared/${OTHER}_node_id" ]; do - echo "WAIT FOR NODE ID" +# Wait for other node ids +FILES=() +while [ ! ${#FILES[@]} == $SCALE ]; do + echo "WAIT FOR NODE IDS" sleep 1 + FILES=(/shared/*node_id) done # Write node ids to persistent peers -OTHER_NODE_ID=$(cat /shared/${OTHER}_node_id) -PEERS=$(echo "persistent_peers = \"${NODE_ID}@${ME}:26656, ${OTHER_NODE_ID}@${OTHER}:26656\"") +PEERS="persistent_peers = \"" +for f in ${FILES[@]}; do + ID=$(cat $f) + HOST=$(echo $f | cut -c 9-20) + if [ ! $HOST == $HOSTNAME ]; then + PEERS+="${ID}@${HOST}:26656, " + fi +done +PEERS=$(echo $PEERS | rev | cut -c 2- | rev) +PEERS+="\"" sed -i "/persistent_peers = \"\"/c\\${PEERS}" /tendermint/config/config.toml # Copy genesis.json to shared folder -cp /tendermint/config/genesis.json /shared/${ME}_genesis.json +cp /tendermint/config/genesis.json /shared/${HOSTNAME}_genesis.json # Await config file of all services to be present -while [ ! -f /shared/${OTHER}_genesis.json ]; do - echo "WAIT FOR OTHER GENESIS" +FILES=() +while [ ! ${#FILES[@]} == $SCALE ]; do + echo "WAIT FOR GENESIS FILES" sleep 1 + FILES=(/shared/*_genesis.json) done # Create genesis.json for nodes -/usr/src/app/scripts/genesis.py +if [ ! -f /shared/lock ]; then + echo LOCKING + touch /shared/lock + /usr/src/app/scripts/genesis.py ${FILES[@]} +fi while [ ! -f /shared/genesis.json ]; do echo "WAIT FOR GENESIS" diff --git a/integration/scripts/test.sh b/integration/scripts/test.sh index 1626526..de9271d 100755 --- a/integration/scripts/test.sh +++ b/integration/scripts/test.sh @@ -4,7 +4,19 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -result=$(ssh -o "StrictHostKeyChecking=no" -i \~/.ssh/id_rsa root@planetmint_1 'bash -s' < scripts/election.sh elect 2) -ssh -o "StrictHostKeyChecking=no" -i ~/.ssh/id_rsa root@planetmint_2 'bash -s' < scripts/election.sh approve $result +# Read host names from shared +readarray -t HOSTNAMES < /shared/hostnames + +# Split into proposer and approvers +ALPHA=${HOSTNAMES[0]} +BETAS=${HOSTNAMES[@]:1} + +# Propose validator upsert +result=$(ssh -o "StrictHostKeyChecking=no" -i \~/.ssh/id_rsa root@${ALPHA} 'bash -s' < scripts/election.sh elect 2) + +# Approve validator upsert +for BETA in ${BETAS[@]}; do + ssh -o "StrictHostKeyChecking=no" -i ~/.ssh/id_rsa root@${BETA} 'bash -s' < scripts/election.sh approve $result +done exec "$@" \ No newline at end of file diff --git a/integration/scripts/wait-for-planetmint.sh b/integration/scripts/wait-for-planetmint.sh index 1864c54..36c7794 100755 --- a/integration/scripts/wait-for-planetmint.sh +++ b/integration/scripts/wait-for-planetmint.sh @@ -5,24 +5,25 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 # Only continue if all services are ready -while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' planetmint_1:9984/api/v1)" != "200" ]]; do - echo "WAIT FOR PLANETMINT" +HOSTNAMES=() +while [ ! ${#HOSTNAMES[@]} == $SCALE ]; do + echo "WAIT FOR HOSTNAMES" sleep 1 + readarray -t HOSTNAMES < /shared/hostnames done -while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' planetmint_1:26657)" != "200" ]]; do - echo "WAIT FOR TENDERMINT" - sleep 1 +for host in ${HOSTNAMES[@]}; do + while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' $host:9984)" != "200" ]]; do + echo "WAIT FOR PLANETMINT $host" + sleep 1 + done done -while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' planetmint_2:9984/api/v1)" != "200" ]]; do - echo "WAIT FOR PLANETMINT" - sleep 1 -done - -while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' planetmint_2:26657)" != "200" ]]; do - echo "WAIT FOR TENDERMINT" - sleep 1 +for host in ${HOSTNAMES[@]}; do + while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' $host:26657)" != "200" ]]; do + echo "WAIT FOR TENDERMINT $host" + sleep 1 + done done exec "$@" \ No newline at end of file From 64f5ec01f13f5e15218b136da30ba33df13f8f38 Mon Sep 17 00:00:00 2001 From: ArpitShukla007 Date: Wed, 9 Mar 2022 09:06:45 +0000 Subject: [PATCH 54/93] Basic structuring --- .../{ => transactions}/common/__init__.py | 0 .../{ => transactions}/common/crypto.py | 0 .../{ => transactions}/common/exceptions.py | 0 planetmint/transactions/common/input.py | 117 ++++++++++++++++++ .../{ => transactions}/common/memoize.py | 0 .../common/schema/README.md | 0 .../common/schema/__init__.py | 0 ...saction_chain_migration_election_v2.0.yaml | 0 .../schema/transaction_create_v1.0.yaml | 0 .../schema/transaction_create_v2.0.yaml | 0 .../schema/transaction_transfer_v1.0.yaml | 0 .../schema/transaction_transfer_v2.0.yaml | 0 .../common/schema/transaction_v1.0.yaml | 0 .../common/schema/transaction_v2.0.yaml | 0 .../transaction_validator_election_v2.0.yaml | 0 .../common/schema/transaction_vote_v2.0.yaml | 0 .../{ => transactions}/common/transaction.py | 0 .../common/transaction_mode_types.py | 0 planetmint/{ => transactions}/common/utils.py | 0 19 files changed, 117 insertions(+) rename planetmint/{ => transactions}/common/__init__.py (100%) rename planetmint/{ => transactions}/common/crypto.py (100%) rename planetmint/{ => transactions}/common/exceptions.py (100%) create mode 100644 planetmint/transactions/common/input.py rename planetmint/{ => transactions}/common/memoize.py (100%) rename planetmint/{ => transactions}/common/schema/README.md (100%) rename planetmint/{ => transactions}/common/schema/__init__.py (100%) rename planetmint/{ => transactions}/common/schema/transaction_chain_migration_election_v2.0.yaml (100%) rename planetmint/{ => transactions}/common/schema/transaction_create_v1.0.yaml (100%) rename planetmint/{ => transactions}/common/schema/transaction_create_v2.0.yaml (100%) rename planetmint/{ => transactions}/common/schema/transaction_transfer_v1.0.yaml (100%) rename planetmint/{ => transactions}/common/schema/transaction_transfer_v2.0.yaml (100%) rename planetmint/{ => transactions}/common/schema/transaction_v1.0.yaml (100%) rename planetmint/{ => transactions}/common/schema/transaction_v2.0.yaml (100%) rename planetmint/{ => transactions}/common/schema/transaction_validator_election_v2.0.yaml (100%) rename planetmint/{ => transactions}/common/schema/transaction_vote_v2.0.yaml (100%) rename planetmint/{ => transactions}/common/transaction.py (100%) rename planetmint/{ => transactions}/common/transaction_mode_types.py (100%) rename planetmint/{ => transactions}/common/utils.py (100%) diff --git a/planetmint/common/__init__.py b/planetmint/transactions/common/__init__.py similarity index 100% rename from planetmint/common/__init__.py rename to planetmint/transactions/common/__init__.py diff --git a/planetmint/common/crypto.py b/planetmint/transactions/common/crypto.py similarity index 100% rename from planetmint/common/crypto.py rename to planetmint/transactions/common/crypto.py diff --git a/planetmint/common/exceptions.py b/planetmint/transactions/common/exceptions.py similarity index 100% rename from planetmint/common/exceptions.py rename to planetmint/transactions/common/exceptions.py diff --git a/planetmint/transactions/common/input.py b/planetmint/transactions/common/input.py new file mode 100644 index 0000000..6ef058f --- /dev/null +++ b/planetmint/transactions/common/input.py @@ -0,0 +1,117 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +class Input(object): + """A Input is used to spend assets locked by an Output. + + Wraps around a Crypto-condition Fulfillment. + + Attributes: + fulfillment (:class:`cryptoconditions.Fulfillment`): A Fulfillment + to be signed with a private key. + owners_before (:obj:`list` of :obj:`str`): A list of owners after a + Transaction was confirmed. + fulfills (:class:`~planetmint.common.transaction. TransactionLink`, + optional): A link representing the input of a `TRANSFER` + Transaction. + """ + + def __init__(self, fulfillment, owners_before, fulfills=None): + """Create an instance of an :class:`~.Input`. + + Args: + fulfillment (:class:`cryptoconditions.Fulfillment`): A + Fulfillment to be signed with a private key. + owners_before (:obj:`list` of :obj:`str`): A list of owners + after a Transaction was confirmed. + fulfills (:class:`~planetmint.common.transaction. + TransactionLink`, optional): A link representing the input + of a `TRANSFER` Transaction. + """ + if fulfills is not None and not isinstance(fulfills, TransactionLink): + raise TypeError('`fulfills` must be a TransactionLink instance') + if not isinstance(owners_before, list): + raise TypeError('`owners_before` must be a list instance') + + self.fulfillment = fulfillment + self.fulfills = fulfills + self.owners_before = owners_before + + def __eq__(self, other): + # TODO: If `other !== Fulfillment` return `False` + return self.to_dict() == other.to_dict() + + # NOTE: This function is used to provide a unique key for a given + # Input to suppliment memoization + def __hash__(self): + return hash((self.fulfillment, self.fulfills)) + + def to_dict(self): + """Transforms the object to a Python dictionary. + + Note: + If an Input hasn't been signed yet, this method returns a + dictionary representation. + + Returns: + dict: The Input as an alternative serialization format. + """ + try: + fulfillment = self.fulfillment.serialize_uri() + except (TypeError, AttributeError, ASN1EncodeError, ASN1DecodeError): + fulfillment = _fulfillment_to_details(self.fulfillment) + + try: + # NOTE: `self.fulfills` can be `None` and that's fine + fulfills = self.fulfills.to_dict() + except AttributeError: + fulfills = None + + input_ = { + 'owners_before': self.owners_before, + 'fulfills': fulfills, + 'fulfillment': fulfillment, + } + return input_ + + @classmethod + def generate(cls, public_keys): + # TODO: write docstring + # The amount here does not really matter. It is only use on the + # output data model but here we only care about the fulfillment + output = Output.generate(public_keys, 1) + return cls(output.fulfillment, public_keys) + + @classmethod + def from_dict(cls, data): + """Transforms a Python dictionary to an Input object. + + Note: + Optionally, this method can also serialize a Cryptoconditions- + Fulfillment that is not yet signed. + + Args: + data (dict): The Input to be transformed. + + Returns: + :class:`~planetmint.common.transaction.Input` + + Raises: + InvalidSignature: If an Input's URI couldn't be parsed. + """ + fulfillment = data['fulfillment'] + if not isinstance(fulfillment, (Fulfillment, type(None))): + try: + fulfillment = Fulfillment.from_uri(data['fulfillment']) + except ASN1DecodeError: + # TODO Remove as it is legacy code, and simply fall back on + # ASN1DecodeError + raise InvalidSignature("Fulfillment URI couldn't been parsed") + except TypeError: + # NOTE: See comment about this special case in + # `Input.to_dict` + fulfillment = _fulfillment_from_details(data['fulfillment']) + fulfills = TransactionLink.from_dict(data['fulfills']) + return cls(fulfillment, data['owners_before'], fulfills) diff --git a/planetmint/common/memoize.py b/planetmint/transactions/common/memoize.py similarity index 100% rename from planetmint/common/memoize.py rename to planetmint/transactions/common/memoize.py diff --git a/planetmint/common/schema/README.md b/planetmint/transactions/common/schema/README.md similarity index 100% rename from planetmint/common/schema/README.md rename to planetmint/transactions/common/schema/README.md diff --git a/planetmint/common/schema/__init__.py b/planetmint/transactions/common/schema/__init__.py similarity index 100% rename from planetmint/common/schema/__init__.py rename to planetmint/transactions/common/schema/__init__.py diff --git a/planetmint/common/schema/transaction_chain_migration_election_v2.0.yaml b/planetmint/transactions/common/schema/transaction_chain_migration_election_v2.0.yaml similarity index 100% rename from planetmint/common/schema/transaction_chain_migration_election_v2.0.yaml rename to planetmint/transactions/common/schema/transaction_chain_migration_election_v2.0.yaml diff --git a/planetmint/common/schema/transaction_create_v1.0.yaml b/planetmint/transactions/common/schema/transaction_create_v1.0.yaml similarity index 100% rename from planetmint/common/schema/transaction_create_v1.0.yaml rename to planetmint/transactions/common/schema/transaction_create_v1.0.yaml diff --git a/planetmint/common/schema/transaction_create_v2.0.yaml b/planetmint/transactions/common/schema/transaction_create_v2.0.yaml similarity index 100% rename from planetmint/common/schema/transaction_create_v2.0.yaml rename to planetmint/transactions/common/schema/transaction_create_v2.0.yaml diff --git a/planetmint/common/schema/transaction_transfer_v1.0.yaml b/planetmint/transactions/common/schema/transaction_transfer_v1.0.yaml similarity index 100% rename from planetmint/common/schema/transaction_transfer_v1.0.yaml rename to planetmint/transactions/common/schema/transaction_transfer_v1.0.yaml diff --git a/planetmint/common/schema/transaction_transfer_v2.0.yaml b/planetmint/transactions/common/schema/transaction_transfer_v2.0.yaml similarity index 100% rename from planetmint/common/schema/transaction_transfer_v2.0.yaml rename to planetmint/transactions/common/schema/transaction_transfer_v2.0.yaml diff --git a/planetmint/common/schema/transaction_v1.0.yaml b/planetmint/transactions/common/schema/transaction_v1.0.yaml similarity index 100% rename from planetmint/common/schema/transaction_v1.0.yaml rename to planetmint/transactions/common/schema/transaction_v1.0.yaml diff --git a/planetmint/common/schema/transaction_v2.0.yaml b/planetmint/transactions/common/schema/transaction_v2.0.yaml similarity index 100% rename from planetmint/common/schema/transaction_v2.0.yaml rename to planetmint/transactions/common/schema/transaction_v2.0.yaml diff --git a/planetmint/common/schema/transaction_validator_election_v2.0.yaml b/planetmint/transactions/common/schema/transaction_validator_election_v2.0.yaml similarity index 100% rename from planetmint/common/schema/transaction_validator_election_v2.0.yaml rename to planetmint/transactions/common/schema/transaction_validator_election_v2.0.yaml diff --git a/planetmint/common/schema/transaction_vote_v2.0.yaml b/planetmint/transactions/common/schema/transaction_vote_v2.0.yaml similarity index 100% rename from planetmint/common/schema/transaction_vote_v2.0.yaml rename to planetmint/transactions/common/schema/transaction_vote_v2.0.yaml diff --git a/planetmint/common/transaction.py b/planetmint/transactions/common/transaction.py similarity index 100% rename from planetmint/common/transaction.py rename to planetmint/transactions/common/transaction.py diff --git a/planetmint/common/transaction_mode_types.py b/planetmint/transactions/common/transaction_mode_types.py similarity index 100% rename from planetmint/common/transaction_mode_types.py rename to planetmint/transactions/common/transaction_mode_types.py diff --git a/planetmint/common/utils.py b/planetmint/transactions/common/utils.py similarity index 100% rename from planetmint/common/utils.py rename to planetmint/transactions/common/utils.py From e9b7aa0fc552e9ee1971efc4f4c58e8e78636624 Mon Sep 17 00:00:00 2001 From: ArpitShukla007 Date: Wed, 9 Mar 2022 17:10:37 +0000 Subject: [PATCH 55/93] Added new classes in transactions/common --- .../generate_http_server_api_documentation.py | 2 +- planetmint/__init__.py | 2 +- planetmint/backend/connection.py | 2 +- planetmint/backend/localmongodb/connection.py | 2 +- planetmint/backend/localmongodb/query.py | 2 +- planetmint/backend/schema.py | 4 +- planetmint/commands/planetmint.py | 4 +- planetmint/config_utils.py | 2 +- planetmint/elections/election.py | 8 +- planetmint/elections/vote.py | 4 +- planetmint/fastquery.py | 2 +- planetmint/lib.py | 4 +- planetmint/log.py | 2 +- .../migrations/chain_migration_election.py | 2 +- planetmint/models.py | 8 +- planetmint/transactions/common/crypto.py | 6 +- planetmint/transactions/common/input.py | 32 +- planetmint/transactions/common/output.py | 224 ++++++++ .../transactions/common/schema/__init__.py | 2 +- planetmint/transactions/common/transaction.py | 481 +----------------- .../transactions/common/transaction_link.py | 99 ++++ planetmint/transactions/common/utils.py | 52 +- .../upsert_validator/validator_election.py | 4 +- .../upsert_validator/validator_utils.py | 2 +- planetmint/utils.py | 2 +- planetmint/web/views/parameters.py | 2 +- planetmint/web/views/transactions.py | 4 +- setup.py | 2 +- tests/assets/test_digital_assets.py | 4 +- tests/assets/test_divisible_assets.py | 14 +- tests/backend/localmongodb/test_queries.py | 2 +- tests/backend/test_connection.py | 2 +- tests/commands/conftest.py | 2 +- tests/commands/test_commands.py | 4 +- tests/common/conftest.py | 14 +- tests/common/test_memoize.py | 4 +- tests/common/test_schema.py | 4 +- tests/common/test_transaction.py | 124 ++--- tests/common/utils.py | 4 +- tests/conftest.py | 18 +- tests/db/test_bigchain_api.py | 52 +- tests/tendermint/test_core.py | 12 +- tests/tendermint/test_fastquery.py | 2 +- tests/tendermint/test_integration.py | 6 +- tests/tendermint/test_lib.py | 22 +- tests/test_config_utils.py | 2 +- tests/test_core.py | 12 +- tests/test_parallel_validation.py | 2 +- .../test_upsert_validator_vote.py | 8 +- .../test_validator_election.py | 8 +- tests/utils.py | 6 +- .../validation/test_transaction_structure.py | 18 +- tests/web/test_outputs.py | 2 +- tests/web/test_transactions.py | 18 +- tests/web/test_websocket_server.py | 6 +- 55 files changed, 650 insertions(+), 684 deletions(-) create mode 100644 planetmint/transactions/common/output.py create mode 100644 planetmint/transactions/common/transaction_link.py diff --git a/docs/root/generate_http_server_api_documentation.py b/docs/root/generate_http_server_api_documentation.py index b43e163..4b84d57 100644 --- a/docs/root/generate_http_server_api_documentation.py +++ b/docs/root/generate_http_server_api_documentation.py @@ -9,7 +9,7 @@ import json import os import os.path -from planetmint.common.transaction import Transaction, Input, TransactionLink +from planetmint.transactions.common.transaction import Transaction, Input, TransactionLink from planetmint import lib from planetmint.web import server diff --git a/planetmint/__init__.py b/planetmint/__init__.py index 7c3b977..84c140a 100644 --- a/planetmint/__init__.py +++ b/planetmint/__init__.py @@ -94,7 +94,7 @@ config = { # the user wants to reconfigure the node. Check ``planetmint.config_utils`` # for more info. _config = copy.deepcopy(config) -from planetmint.common.transaction import Transaction # noqa +from planetmint.transactions.common.transaction import Transaction # noqa from planetmint import models # noqa from planetmint.upsert_validator import ValidatorElection # noqa from planetmint.elections.vote import Vote # noqa diff --git a/planetmint/backend/connection.py b/planetmint/backend/connection.py index d92204b..34708ce 100644 --- a/planetmint/backend/connection.py +++ b/planetmint/backend/connection.py @@ -10,7 +10,7 @@ from itertools import repeat import planetmint from planetmint.backend.exceptions import ConnectionError from planetmint.backend.utils import get_planetmint_config_value, get_planetmint_config_value_or_key_error -from planetmint.common.exceptions import ConfigurationError +from planetmint.transactions.common.exceptions import ConfigurationError BACKENDS = { 'localmongodb': 'planetmint.backend.localmongodb.connection.LocalMongoDBConnection', diff --git a/planetmint/backend/localmongodb/connection.py b/planetmint/backend/localmongodb/connection.py index 945a2ff..8ad3226 100644 --- a/planetmint/backend/localmongodb/connection.py +++ b/planetmint/backend/localmongodb/connection.py @@ -13,7 +13,7 @@ from planetmint.backend.exceptions import (DuplicateKeyError, OperationError, ConnectionError) from planetmint.backend.utils import get_planetmint_config_value -from planetmint.common.exceptions import ConfigurationError +from planetmint.transactions.common.exceptions import ConfigurationError from planetmint.utils import Lazy logger = logging.getLogger(__name__) diff --git a/planetmint/backend/localmongodb/query.py b/planetmint/backend/localmongodb/query.py index db98230..69f7bb2 100644 --- a/planetmint/backend/localmongodb/query.py +++ b/planetmint/backend/localmongodb/query.py @@ -11,7 +11,7 @@ from planetmint import backend from planetmint.backend.exceptions import DuplicateKeyError from planetmint.backend.utils import module_dispatch_registrar from planetmint.backend.localmongodb.connection import LocalMongoDBConnection -from planetmint.common.transaction import Transaction +from planetmint.transactions.common.transaction import Transaction register_query = module_dispatch_registrar(backend.query) diff --git a/planetmint/backend/schema.py b/planetmint/backend/schema.py index cb7bbcf..3e88d27 100644 --- a/planetmint/backend/schema.py +++ b/planetmint/backend/schema.py @@ -10,8 +10,8 @@ import logging import planetmint from planetmint.backend.connection import connect -from planetmint.common.exceptions import ValidationError -from planetmint.common.utils import validate_all_values_for_key_in_obj, validate_all_values_for_key_in_list +from planetmint.transactions.common.exceptions import ValidationError +from planetmint.transactions.common.utils import validate_all_values_for_key_in_obj, validate_all_values_for_key_in_list logger = logging.getLogger(__name__) diff --git a/planetmint/commands/planetmint.py b/planetmint/commands/planetmint.py index 5e534a7..4714fc1 100644 --- a/planetmint/commands/planetmint.py +++ b/planetmint/commands/planetmint.py @@ -17,8 +17,8 @@ import sys from planetmint.core import rollback from planetmint.migrations.chain_migration_election import ChainMigrationElection from planetmint.utils import load_node_key -from planetmint.common.transaction_mode_types import BROADCAST_TX_COMMIT -from planetmint.common.exceptions import (DatabaseDoesNotExist, +from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT +from planetmint.transactions.common.exceptions import (DatabaseDoesNotExist, ValidationError) from planetmint.elections.vote import Vote import planetmint diff --git a/planetmint/config_utils.py b/planetmint/config_utils.py index 1401df7..fa5d94d 100644 --- a/planetmint/config_utils.py +++ b/planetmint/config_utils.py @@ -25,7 +25,7 @@ from functools import lru_cache from pkg_resources import iter_entry_points, ResolutionError -from planetmint.common import exceptions +from planetmint.transactions.common import exceptions import planetmint diff --git a/planetmint/elections/election.py b/planetmint/elections/election.py index d73b319..f1f99f8 100644 --- a/planetmint/elections/election.py +++ b/planetmint/elections/election.py @@ -9,15 +9,15 @@ from uuid import uuid4 from planetmint import backend from planetmint.elections.vote import Vote -from planetmint.common.exceptions import (InvalidSignature, +from planetmint.transactions.common.exceptions import (InvalidSignature, MultipleInputsError, InvalidProposer, UnequalValidatorSet, DuplicateTransaction) from planetmint.tendermint_utils import key_from_base64, public_key_to_base64 -from planetmint.common.crypto import (public_key_from_ed25519_key) -from planetmint.common.transaction import Transaction -from planetmint.common.schema import (_validate_schema, +from planetmint.transactions.common.crypto import (public_key_from_ed25519_key) +from planetmint.transactions.common.transaction import Transaction +from planetmint.transactions.common.schema import (_validate_schema, TX_SCHEMA_COMMON, TX_SCHEMA_CREATE) diff --git a/planetmint/elections/vote.py b/planetmint/elections/vote.py index a4bb0c9..7a3e90c 100644 --- a/planetmint/elections/vote.py +++ b/planetmint/elections/vote.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 -from planetmint.common.transaction import Transaction -from planetmint.common.schema import (_validate_schema, +from planetmint.transactions.common.transaction import Transaction +from planetmint.transactions.common.schema import (_validate_schema, TX_SCHEMA_COMMON, TX_SCHEMA_TRANSFER, TX_SCHEMA_VOTE) diff --git a/planetmint/fastquery.py b/planetmint/fastquery.py index c1aa843..bfbb6a8 100644 --- a/planetmint/fastquery.py +++ b/planetmint/fastquery.py @@ -5,7 +5,7 @@ from planetmint.utils import condition_details_has_owner from planetmint.backend import query -from planetmint.common.transaction import TransactionLink +from planetmint.transactions.common.transaction import TransactionLink class FastQuery(): diff --git a/planetmint/lib.py b/planetmint/lib.py index 4c59b26..8b66386 100644 --- a/planetmint/lib.py +++ b/planetmint/lib.py @@ -24,10 +24,10 @@ import requests import planetmint from planetmint import backend, config_utils, fastquery from planetmint.models import Transaction -from planetmint.common.exceptions import (SchemaValidationError, +from planetmint.transactions.common.exceptions import (SchemaValidationError, ValidationError, DoubleSpend) -from planetmint.common.transaction_mode_types import (BROADCAST_TX_COMMIT, +from planetmint.transactions.common.transaction_mode_types import (BROADCAST_TX_COMMIT, BROADCAST_TX_ASYNC, BROADCAST_TX_SYNC) from planetmint.tendermint_utils import encode_transaction, merkleroot diff --git a/planetmint/log.py b/planetmint/log.py index d987fc6..091fe8e 100644 --- a/planetmint/log.py +++ b/planetmint/log.py @@ -6,7 +6,7 @@ import planetmint import logging -from planetmint.common.exceptions import ConfigurationError +from planetmint.transactions.common.exceptions import ConfigurationError from logging.config import dictConfig as set_logging_config import os diff --git a/planetmint/migrations/chain_migration_election.py b/planetmint/migrations/chain_migration_election.py index d913e84..03616cc 100644 --- a/planetmint/migrations/chain_migration_election.py +++ b/planetmint/migrations/chain_migration_election.py @@ -1,6 +1,6 @@ import json -from planetmint.common.schema import TX_SCHEMA_CHAIN_MIGRATION_ELECTION +from planetmint.transactions.common.schema import TX_SCHEMA_CHAIN_MIGRATION_ELECTION from planetmint.elections.election import Election diff --git a/planetmint/models.py b/planetmint/models.py index 001df55..e0edac6 100644 --- a/planetmint/models.py +++ b/planetmint/models.py @@ -4,11 +4,11 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 from planetmint.backend.schema import validate_language_key -from planetmint.common.exceptions import (InvalidSignature, +from planetmint.transactions.common.exceptions import (InvalidSignature, DuplicateTransaction) -from planetmint.common.schema import validate_transaction_schema -from planetmint.common.transaction import Transaction -from planetmint.common.utils import (validate_txn_obj, validate_key) +from planetmint.transactions.common.schema import validate_transaction_schema +from planetmint.transactions.common.transaction import Transaction +from planetmint.transactions.common.utils import (validate_txn_obj, validate_key) class Transaction(Transaction): diff --git a/planetmint/transactions/common/crypto.py b/planetmint/transactions/common/crypto.py index 72ea536..9205c27 100644 --- a/planetmint/transactions/common/crypto.py +++ b/planetmint/transactions/common/crypto.py @@ -26,10 +26,10 @@ def generate_key_pair(): """Generates a cryptographic key pair. Returns: - :class:`~planetmint.common.crypto.CryptoKeypair`: A + :class:`~planetmint.transactions.common.crypto.CryptoKeypair`: A :obj:`collections.namedtuple` with named fields - :attr:`~planetmint.common.crypto.CryptoKeypair.private_key` and - :attr:`~planetmint.common.crypto.CryptoKeypair.public_key`. + :attr:`~planetmint.transactions.common.crypto.CryptoKeypair.private_key` and + :attr:`~planetmint.transactions.common.crypto.CryptoKeypair.public_key`. """ # TODO FOR CC: Adjust interface so that this function becomes unnecessary diff --git a/planetmint/transactions/common/input.py b/planetmint/transactions/common/input.py index 6ef058f..927de97 100644 --- a/planetmint/transactions/common/input.py +++ b/planetmint/transactions/common/input.py @@ -3,6 +3,32 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 +from collections import namedtuple +from copy import deepcopy +from functools import reduce, lru_cache +import rapidjson + +import base58 +from cryptoconditions import Fulfillment, ThresholdSha256, Ed25519Sha256 +from cryptoconditions.exceptions import ( + ParsingError, ASN1DecodeError, ASN1EncodeError, UnsupportedTypeError) +try: + from hashlib import sha3_256 +except ImportError: + from sha3 import sha3_256 + +from planetmint.transactions.common.crypto import PrivateKey, hash_data +from planetmint.transactions.common.exceptions import (KeypairMismatchException, + InputDoesNotExist, DoubleSpend, + InvalidHash, InvalidSignature, + AmountError, AssetIdMismatch, + ThresholdTooDeep) +from planetmint.transactions.common.utils import serialize +from .memoize import memoize_from_dict, memoize_to_dict +from .utils import _fulfillment_to_details, _fulfillment_from_details +from .output import Output +from .transaction_link import TransactionLink + class Input(object): """A Input is used to spend assets locked by an Output. @@ -13,7 +39,7 @@ class Input(object): to be signed with a private key. owners_before (:obj:`list` of :obj:`str`): A list of owners after a Transaction was confirmed. - fulfills (:class:`~planetmint.common.transaction. TransactionLink`, + fulfills (:class:`~planetmint.transactions.common.transaction. TransactionLink`, optional): A link representing the input of a `TRANSFER` Transaction. """ @@ -26,7 +52,7 @@ class Input(object): Fulfillment to be signed with a private key. owners_before (:obj:`list` of :obj:`str`): A list of owners after a Transaction was confirmed. - fulfills (:class:`~planetmint.common.transaction. + fulfills (:class:`~planetmint.transactions.common.transaction. TransactionLink`, optional): A link representing the input of a `TRANSFER` Transaction. """ @@ -96,7 +122,7 @@ class Input(object): data (dict): The Input to be transformed. Returns: - :class:`~planetmint.common.transaction.Input` + :class:`~planetmint.transactions.common.transaction.Input` Raises: InvalidSignature: If an Input's URI couldn't be parsed. diff --git a/planetmint/transactions/common/output.py b/planetmint/transactions/common/output.py new file mode 100644 index 0000000..137542f --- /dev/null +++ b/planetmint/transactions/common/output.py @@ -0,0 +1,224 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +from collections import namedtuple +from copy import deepcopy +from functools import reduce, lru_cache +import rapidjson + +import base58 +from cryptoconditions import Fulfillment, ThresholdSha256, Ed25519Sha256 +from cryptoconditions.exceptions import ( + ParsingError, ASN1DecodeError, ASN1EncodeError, UnsupportedTypeError) +try: + from hashlib import sha3_256 +except ImportError: + from sha3 import sha3_256 + +from planetmint.transactions.common.crypto import PrivateKey, hash_data +from planetmint.transactions.common.exceptions import (KeypairMismatchException, + InputDoesNotExist, DoubleSpend, + InvalidHash, InvalidSignature, + AmountError, AssetIdMismatch, + ThresholdTooDeep) +from planetmint.transactions.common.utils import serialize +from .memoize import memoize_from_dict, memoize_to_dict +from .utils import _fulfillment_to_details, _fulfillment_from_details + +class Output(object): + """An Output is used to lock an asset. + + Wraps around a Crypto-condition Condition. + + Attributes: + fulfillment (:class:`cryptoconditions.Fulfillment`): A Fulfillment + to extract a Condition from. + public_keys (:obj:`list` of :obj:`str`, optional): A list of + owners before a Transaction was confirmed. + """ + + MAX_AMOUNT = 9 * 10 ** 18 + + def __init__(self, fulfillment, public_keys=None, amount=1): + """Create an instance of a :class:`~.Output`. + + Args: + fulfillment (:class:`cryptoconditions.Fulfillment`): A + Fulfillment to extract a Condition from. + public_keys (:obj:`list` of :obj:`str`, optional): A list of + owners before a Transaction was confirmed. + amount (int): The amount of Assets to be locked with this + Output. + + Raises: + TypeError: if `public_keys` is not instance of `list`. + """ + if not isinstance(public_keys, list) and public_keys is not None: + raise TypeError('`public_keys` must be a list instance or None') + if not isinstance(amount, int): + raise TypeError('`amount` must be an int') + if amount < 1: + raise AmountError('`amount` must be greater than 0') + if amount > self.MAX_AMOUNT: + raise AmountError('`amount` must be <= %s' % self.MAX_AMOUNT) + + self.fulfillment = fulfillment + self.amount = amount + self.public_keys = public_keys + + def __eq__(self, other): + # TODO: If `other !== Condition` return `False` + return self.to_dict() == other.to_dict() + + def to_dict(self): + """Transforms the object to a Python dictionary. + + Note: + A dictionary serialization of the Input the Output was + derived from is always provided. + + Returns: + dict: The Output as an alternative serialization format. + """ + # TODO FOR CC: It must be able to recognize a hashlock condition + # and fulfillment! + condition = {} + try: + condition['details'] = _fulfillment_to_details(self.fulfillment) + except AttributeError: + pass + + try: + condition['uri'] = self.fulfillment.condition_uri + except AttributeError: + condition['uri'] = self.fulfillment + + output = { + 'public_keys': self.public_keys, + 'condition': condition, + 'amount': str(self.amount), + } + return output + + @classmethod + def generate(cls, public_keys, amount): + """Generates a Output from a specifically formed tuple or list. + + Note: + If a ThresholdCondition has to be generated where the threshold + is always the number of subconditions it is split between, a + list of the following structure is sufficient: + + [(address|condition)*, [(address|condition)*, ...], ...] + + Args: + public_keys (:obj:`list` of :obj:`str`): The public key of + the users that should be able to fulfill the Condition + that is being created. + amount (:obj:`int`): The amount locked by the Output. + + Returns: + An Output that can be used in a Transaction. + + Raises: + TypeError: If `public_keys` is not an instance of `list`. + ValueError: If `public_keys` is an empty list. + """ + threshold = len(public_keys) + if not isinstance(amount, int): + raise TypeError('`amount` must be a int') + if amount < 1: + raise AmountError('`amount` needs to be greater than zero') + if not isinstance(public_keys, list): + raise TypeError('`public_keys` must be an instance of list') + if len(public_keys) == 0: + raise ValueError('`public_keys` needs to contain at least one' + 'owner') + elif len(public_keys) == 1 and not isinstance(public_keys[0], list): + if isinstance(public_keys[0], Fulfillment): + ffill = public_keys[0] + else: + ffill = Ed25519Sha256( + public_key=base58.b58decode(public_keys[0])) + return cls(ffill, public_keys, amount=amount) + else: + initial_cond = ThresholdSha256(threshold=threshold) + threshold_cond = reduce(cls._gen_condition, public_keys, + initial_cond) + return cls(threshold_cond, public_keys, amount=amount) + + @classmethod + def _gen_condition(cls, initial, new_public_keys): + """Generates ThresholdSha256 conditions from a list of new owners. + + Note: + This method is intended only to be used with a reduce function. + For a description on how to use this method, see + :meth:`~.Output.generate`. + + Args: + initial (:class:`cryptoconditions.ThresholdSha256`): + A Condition representing the overall root. + new_public_keys (:obj:`list` of :obj:`str`|str): A list of new + owners or a single new owner. + + Returns: + :class:`cryptoconditions.ThresholdSha256`: + """ + try: + threshold = len(new_public_keys) + except TypeError: + threshold = None + + if isinstance(new_public_keys, list) and len(new_public_keys) > 1: + ffill = ThresholdSha256(threshold=threshold) + reduce(cls._gen_condition, new_public_keys, ffill) + elif isinstance(new_public_keys, list) and len(new_public_keys) <= 1: + raise ValueError('Sublist cannot contain single owner') + else: + try: + new_public_keys = new_public_keys.pop() + except AttributeError: + pass + # NOTE: Instead of submitting base58 encoded addresses, a user + # of this class can also submit fully instantiated + # Cryptoconditions. In the case of casting + # `new_public_keys` to a Ed25519Fulfillment with the + # result of a `TypeError`, we're assuming that + # `new_public_keys` is a Cryptocondition then. + if isinstance(new_public_keys, Fulfillment): + ffill = new_public_keys + else: + ffill = Ed25519Sha256( + public_key=base58.b58decode(new_public_keys)) + initial.add_subfulfillment(ffill) + return initial + + @classmethod + def from_dict(cls, data): + """Transforms a Python dictionary to an Output object. + + Note: + To pass a serialization cycle multiple times, a + Cryptoconditions Fulfillment needs to be present in the + passed-in dictionary, as Condition URIs are not serializable + anymore. + + Args: + data (dict): The dict to be transformed. + + Returns: + :class:`~planetmint.transactions.common.transaction.Output` + """ + try: + fulfillment = _fulfillment_from_details(data['condition']['details']) + except KeyError: + # NOTE: Hashlock condition case + fulfillment = data['condition']['uri'] + try: + amount = int(data['amount']) + except ValueError: + raise AmountError('Invalid amount: %s' % data['amount']) + return cls(fulfillment, data['public_keys'], amount) \ No newline at end of file diff --git a/planetmint/transactions/common/schema/__init__.py b/planetmint/transactions/common/schema/__init__.py index df28597..0b4b20b 100644 --- a/planetmint/transactions/common/schema/__init__.py +++ b/planetmint/transactions/common/schema/__init__.py @@ -11,7 +11,7 @@ import jsonschema import yaml import rapidjson -from planetmint.common.exceptions import SchemaValidationError +from planetmint.transactions.common.exceptions import SchemaValidationError logger = logging.getLogger(__name__) diff --git a/planetmint/transactions/common/transaction.py b/planetmint/transactions/common/transaction.py index c7301f6..04245c4 100644 --- a/planetmint/transactions/common/transaction.py +++ b/planetmint/transactions/common/transaction.py @@ -25,15 +25,17 @@ try: except ImportError: from sha3 import sha3_256 -from planetmint.common.crypto import PrivateKey, hash_data -from planetmint.common.exceptions import (KeypairMismatchException, +from planetmint.transactions.common.crypto import PrivateKey, hash_data +from planetmint.transactions.common.exceptions import (KeypairMismatchException, InputDoesNotExist, DoubleSpend, InvalidHash, InvalidSignature, AmountError, AssetIdMismatch, ThresholdTooDeep) -from planetmint.common.utils import serialize +from planetmint.transactions.common.utils import serialize from .memoize import memoize_from_dict, memoize_to_dict - +from .input import Input +from .output import Output +from .transaction_link import TransactionLink UnspentOutput = namedtuple( 'UnspentOutput', ( @@ -47,441 +49,6 @@ UnspentOutput = namedtuple( ) ) - -class Input(object): - """A Input is used to spend assets locked by an Output. - - Wraps around a Crypto-condition Fulfillment. - - Attributes: - fulfillment (:class:`cryptoconditions.Fulfillment`): A Fulfillment - to be signed with a private key. - owners_before (:obj:`list` of :obj:`str`): A list of owners after a - Transaction was confirmed. - fulfills (:class:`~planetmint.common.transaction. TransactionLink`, - optional): A link representing the input of a `TRANSFER` - Transaction. - """ - - def __init__(self, fulfillment, owners_before, fulfills=None): - """Create an instance of an :class:`~.Input`. - - Args: - fulfillment (:class:`cryptoconditions.Fulfillment`): A - Fulfillment to be signed with a private key. - owners_before (:obj:`list` of :obj:`str`): A list of owners - after a Transaction was confirmed. - fulfills (:class:`~planetmint.common.transaction. - TransactionLink`, optional): A link representing the input - of a `TRANSFER` Transaction. - """ - if fulfills is not None and not isinstance(fulfills, TransactionLink): - raise TypeError('`fulfills` must be a TransactionLink instance') - if not isinstance(owners_before, list): - raise TypeError('`owners_before` must be a list instance') - - self.fulfillment = fulfillment - self.fulfills = fulfills - self.owners_before = owners_before - - def __eq__(self, other): - # TODO: If `other !== Fulfillment` return `False` - return self.to_dict() == other.to_dict() - - # NOTE: This function is used to provide a unique key for a given - # Input to suppliment memoization - def __hash__(self): - return hash((self.fulfillment, self.fulfills)) - - def to_dict(self): - """Transforms the object to a Python dictionary. - - Note: - If an Input hasn't been signed yet, this method returns a - dictionary representation. - - Returns: - dict: The Input as an alternative serialization format. - """ - try: - fulfillment = self.fulfillment.serialize_uri() - except (TypeError, AttributeError, ASN1EncodeError, ASN1DecodeError): - fulfillment = _fulfillment_to_details(self.fulfillment) - - try: - # NOTE: `self.fulfills` can be `None` and that's fine - fulfills = self.fulfills.to_dict() - except AttributeError: - fulfills = None - - input_ = { - 'owners_before': self.owners_before, - 'fulfills': fulfills, - 'fulfillment': fulfillment, - } - return input_ - - @classmethod - def generate(cls, public_keys): - # TODO: write docstring - # The amount here does not really matter. It is only use on the - # output data model but here we only care about the fulfillment - output = Output.generate(public_keys, 1) - return cls(output.fulfillment, public_keys) - - @classmethod - def from_dict(cls, data): - """Transforms a Python dictionary to an Input object. - - Note: - Optionally, this method can also serialize a Cryptoconditions- - Fulfillment that is not yet signed. - - Args: - data (dict): The Input to be transformed. - - Returns: - :class:`~planetmint.common.transaction.Input` - - Raises: - InvalidSignature: If an Input's URI couldn't be parsed. - """ - fulfillment = data['fulfillment'] - if not isinstance(fulfillment, (Fulfillment, type(None))): - try: - fulfillment = Fulfillment.from_uri(data['fulfillment']) - except ASN1DecodeError: - # TODO Remove as it is legacy code, and simply fall back on - # ASN1DecodeError - raise InvalidSignature("Fulfillment URI couldn't been parsed") - except TypeError: - # NOTE: See comment about this special case in - # `Input.to_dict` - fulfillment = _fulfillment_from_details(data['fulfillment']) - fulfills = TransactionLink.from_dict(data['fulfills']) - return cls(fulfillment, data['owners_before'], fulfills) - - -def _fulfillment_to_details(fulfillment): - """Encode a fulfillment as a details dictionary - - Args: - fulfillment: Crypto-conditions Fulfillment object - """ - - if fulfillment.type_name == 'ed25519-sha-256': - return { - 'type': 'ed25519-sha-256', - 'public_key': base58.b58encode(fulfillment.public_key).decode(), - } - - if fulfillment.type_name == 'threshold-sha-256': - subconditions = [ - _fulfillment_to_details(cond['body']) - for cond in fulfillment.subconditions - ] - return { - 'type': 'threshold-sha-256', - 'threshold': fulfillment.threshold, - 'subconditions': subconditions, - } - - raise UnsupportedTypeError(fulfillment.type_name) - - -def _fulfillment_from_details(data, _depth=0): - """Load a fulfillment for a signing spec dictionary - - Args: - data: tx.output[].condition.details dictionary - """ - if _depth == 100: - raise ThresholdTooDeep() - - if data['type'] == 'ed25519-sha-256': - public_key = base58.b58decode(data['public_key']) - return Ed25519Sha256(public_key=public_key) - - if data['type'] == 'threshold-sha-256': - threshold = ThresholdSha256(data['threshold']) - for cond in data['subconditions']: - cond = _fulfillment_from_details(cond, _depth + 1) - threshold.add_subfulfillment(cond) - return threshold - - raise UnsupportedTypeError(data.get('type')) - - -class TransactionLink(object): - """An object for unidirectional linking to a Transaction's Output. - - Attributes: - txid (str, optional): A Transaction to link to. - output (int, optional): An output's index in a Transaction with id - `txid`. - """ - - def __init__(self, txid=None, output=None): - """Create an instance of a :class:`~.TransactionLink`. - - Note: - In an IPLD implementation, this class is not necessary anymore, - as an IPLD link can simply point to an object, as well as an - objects properties. So instead of having a (de)serializable - class, we can have a simple IPLD link of the form: - `//transaction/outputs//`. - - Args: - txid (str, optional): A Transaction to link to. - output (int, optional): An Outputs's index in a Transaction with - id `txid`. - """ - self.txid = txid - self.output = output - - def __bool__(self): - return self.txid is not None and self.output is not None - - def __eq__(self, other): - # TODO: If `other !== TransactionLink` return `False` - return self.to_dict() == other.to_dict() - - def __hash__(self): - return hash((self.txid, self.output)) - - @classmethod - def from_dict(cls, link): - """Transforms a Python dictionary to a TransactionLink object. - - Args: - link (dict): The link to be transformed. - - Returns: - :class:`~planetmint.common.transaction.TransactionLink` - """ - try: - return cls(link['transaction_id'], link['output_index']) - except TypeError: - return cls() - - def to_dict(self): - """Transforms the object to a Python dictionary. - - Returns: - (dict|None): The link as an alternative serialization format. - """ - if self.txid is None and self.output is None: - return None - else: - return { - 'transaction_id': self.txid, - 'output_index': self.output, - } - - def to_uri(self, path=''): - if self.txid is None and self.output is None: - return None - return '{}/transactions/{}/outputs/{}'.format(path, self.txid, - self.output) - - -class Output(object): - """An Output is used to lock an asset. - - Wraps around a Crypto-condition Condition. - - Attributes: - fulfillment (:class:`cryptoconditions.Fulfillment`): A Fulfillment - to extract a Condition from. - public_keys (:obj:`list` of :obj:`str`, optional): A list of - owners before a Transaction was confirmed. - """ - - MAX_AMOUNT = 9 * 10 ** 18 - - def __init__(self, fulfillment, public_keys=None, amount=1): - """Create an instance of a :class:`~.Output`. - - Args: - fulfillment (:class:`cryptoconditions.Fulfillment`): A - Fulfillment to extract a Condition from. - public_keys (:obj:`list` of :obj:`str`, optional): A list of - owners before a Transaction was confirmed. - amount (int): The amount of Assets to be locked with this - Output. - - Raises: - TypeError: if `public_keys` is not instance of `list`. - """ - if not isinstance(public_keys, list) and public_keys is not None: - raise TypeError('`public_keys` must be a list instance or None') - if not isinstance(amount, int): - raise TypeError('`amount` must be an int') - if amount < 1: - raise AmountError('`amount` must be greater than 0') - if amount > self.MAX_AMOUNT: - raise AmountError('`amount` must be <= %s' % self.MAX_AMOUNT) - - self.fulfillment = fulfillment - self.amount = amount - self.public_keys = public_keys - - def __eq__(self, other): - # TODO: If `other !== Condition` return `False` - return self.to_dict() == other.to_dict() - - def to_dict(self): - """Transforms the object to a Python dictionary. - - Note: - A dictionary serialization of the Input the Output was - derived from is always provided. - - Returns: - dict: The Output as an alternative serialization format. - """ - # TODO FOR CC: It must be able to recognize a hashlock condition - # and fulfillment! - condition = {} - try: - condition['details'] = _fulfillment_to_details(self.fulfillment) - except AttributeError: - pass - - try: - condition['uri'] = self.fulfillment.condition_uri - except AttributeError: - condition['uri'] = self.fulfillment - - output = { - 'public_keys': self.public_keys, - 'condition': condition, - 'amount': str(self.amount), - } - return output - - @classmethod - def generate(cls, public_keys, amount): - """Generates a Output from a specifically formed tuple or list. - - Note: - If a ThresholdCondition has to be generated where the threshold - is always the number of subconditions it is split between, a - list of the following structure is sufficient: - - [(address|condition)*, [(address|condition)*, ...], ...] - - Args: - public_keys (:obj:`list` of :obj:`str`): The public key of - the users that should be able to fulfill the Condition - that is being created. - amount (:obj:`int`): The amount locked by the Output. - - Returns: - An Output that can be used in a Transaction. - - Raises: - TypeError: If `public_keys` is not an instance of `list`. - ValueError: If `public_keys` is an empty list. - """ - threshold = len(public_keys) - if not isinstance(amount, int): - raise TypeError('`amount` must be a int') - if amount < 1: - raise AmountError('`amount` needs to be greater than zero') - if not isinstance(public_keys, list): - raise TypeError('`public_keys` must be an instance of list') - if len(public_keys) == 0: - raise ValueError('`public_keys` needs to contain at least one' - 'owner') - elif len(public_keys) == 1 and not isinstance(public_keys[0], list): - if isinstance(public_keys[0], Fulfillment): - ffill = public_keys[0] - else: - ffill = Ed25519Sha256( - public_key=base58.b58decode(public_keys[0])) - return cls(ffill, public_keys, amount=amount) - else: - initial_cond = ThresholdSha256(threshold=threshold) - threshold_cond = reduce(cls._gen_condition, public_keys, - initial_cond) - return cls(threshold_cond, public_keys, amount=amount) - - @classmethod - def _gen_condition(cls, initial, new_public_keys): - """Generates ThresholdSha256 conditions from a list of new owners. - - Note: - This method is intended only to be used with a reduce function. - For a description on how to use this method, see - :meth:`~.Output.generate`. - - Args: - initial (:class:`cryptoconditions.ThresholdSha256`): - A Condition representing the overall root. - new_public_keys (:obj:`list` of :obj:`str`|str): A list of new - owners or a single new owner. - - Returns: - :class:`cryptoconditions.ThresholdSha256`: - """ - try: - threshold = len(new_public_keys) - except TypeError: - threshold = None - - if isinstance(new_public_keys, list) and len(new_public_keys) > 1: - ffill = ThresholdSha256(threshold=threshold) - reduce(cls._gen_condition, new_public_keys, ffill) - elif isinstance(new_public_keys, list) and len(new_public_keys) <= 1: - raise ValueError('Sublist cannot contain single owner') - else: - try: - new_public_keys = new_public_keys.pop() - except AttributeError: - pass - # NOTE: Instead of submitting base58 encoded addresses, a user - # of this class can also submit fully instantiated - # Cryptoconditions. In the case of casting - # `new_public_keys` to a Ed25519Fulfillment with the - # result of a `TypeError`, we're assuming that - # `new_public_keys` is a Cryptocondition then. - if isinstance(new_public_keys, Fulfillment): - ffill = new_public_keys - else: - ffill = Ed25519Sha256( - public_key=base58.b58decode(new_public_keys)) - initial.add_subfulfillment(ffill) - return initial - - @classmethod - def from_dict(cls, data): - """Transforms a Python dictionary to an Output object. - - Note: - To pass a serialization cycle multiple times, a - Cryptoconditions Fulfillment needs to be present in the - passed-in dictionary, as Condition URIs are not serializable - anymore. - - Args: - data (dict): The dict to be transformed. - - Returns: - :class:`~planetmint.common.transaction.Output` - """ - try: - fulfillment = _fulfillment_from_details(data['condition']['details']) - except KeyError: - # NOTE: Hashlock condition case - fulfillment = data['condition']['uri'] - try: - amount = int(data['amount']) - except ValueError: - raise AmountError('Invalid amount: %s' % data['amount']) - return cls(fulfillment, data['public_keys'], amount) - - class Transaction(object): """A Transaction is used to create and transfer assets. @@ -491,10 +58,10 @@ class Transaction(object): Attributes: operation (str): Defines the operation of the Transaction. - inputs (:obj:`list` of :class:`~planetmint.common. + inputs (:obj:`list` of :class:`~planetmint.transactions.common. transaction.Input`, optional): Define the assets to spend. - outputs (:obj:`list` of :class:`~planetmint.common. + outputs (:obj:`list` of :class:`~planetmint.transactions.common. transaction.Output`, optional): Define the assets to lock. asset (dict): Asset payload for this Transaction. ``CREATE`` Transactions require a dict with a ``data`` @@ -521,9 +88,9 @@ class Transaction(object): Args: operation (str): Defines the operation of the Transaction. asset (dict): Asset payload for this Transaction. - inputs (:obj:`list` of :class:`~planetmint.common. + inputs (:obj:`list` of :class:`~planetmint.transactions.common. transaction.Input`, optional): Define the assets to - outputs (:obj:`list` of :class:`~planetmint.common. + outputs (:obj:`list` of :class:`~planetmint.transactions.common. transaction.Output`, optional): Define the assets to lock. metadata (dict): Metadata to be stored along with the @@ -660,7 +227,7 @@ class Transaction(object): be created in this Transaction. Returns: - :class:`~planetmint.common.transaction.Transaction` + :class:`~planetmint.transactions.common.transaction.Transaction` """ (inputs, outputs) = cls.validate_create(tx_signers, recipients, asset, metadata) @@ -716,7 +283,7 @@ class Transaction(object): weight respectively. `inp2` is owned completely by `d`. Args: - inputs (:obj:`list` of :class:`~planetmint.common.transaction. + inputs (:obj:`list` of :class:`~planetmint.transactions.common.transaction. Input`): Converted `Output`s, intended to be used as inputs in the transfer to generate. recipients (:obj:`list` of :obj:`tuple`): A list of @@ -728,7 +295,7 @@ class Transaction(object): Transaction. Returns: - :class:`~planetmint.common.transaction.Transaction` + :class:`~planetmint.transactions.common.transaction.Transaction` """ (inputs, outputs) = cls.validate_transfer(inputs, recipients, asset_id, metadata) return cls(cls.TRANSFER, {'id': asset_id}, inputs, outputs, metadata) @@ -757,7 +324,7 @@ class Transaction(object): outputs should be returned as inputs. Returns: - :obj:`list` of :class:`~planetmint.common.transaction. + :obj:`list` of :class:`~planetmint.transactions.common.transaction. Input` """ # NOTE: If no indices are passed, we just assume to take all outputs @@ -774,7 +341,7 @@ class Transaction(object): """Adds an input to a Transaction's list of inputs. Args: - input_ (:class:`~planetmint.common.transaction. + input_ (:class:`~planetmint.transactions.common.transaction. Input`): An Input to be added to the Transaction. """ if not isinstance(input_, Input): @@ -785,7 +352,7 @@ class Transaction(object): """Adds an output to a Transaction's list of outputs. Args: - output (:class:`~planetmint.common.transaction. + output (:class:`~planetmint.transactions.common.transaction. Output`): An Output to be added to the Transaction. """ @@ -811,7 +378,7 @@ class Transaction(object): Transaction. Returns: - :class:`~planetmint.common.transaction.Transaction` + :class:`~planetmint.transactions.common.transaction.Transaction` """ # TODO: Singing should be possible with at least one of all private # keys supplied to this method. @@ -857,7 +424,7 @@ class Transaction(object): - ThresholdSha256. Args: - input_ (:class:`~planetmint.common.transaction. + input_ (:class:`~planetmint.transactions.common.transaction. Input`) The Input to be signed. message (str): The message to be signed key_pairs (dict): The keys to sign the Transaction with. @@ -878,7 +445,7 @@ class Transaction(object): """Signs a Ed25519Fulfillment. Args: - input_ (:class:`~planetmint.common.transaction. + input_ (:class:`~planetmint.transactions.common.transaction. Input`) The input to be signed. message (str): The message to be signed key_pairs (dict): The keys to sign the Transaction with. @@ -910,7 +477,7 @@ class Transaction(object): """Signs a ThresholdSha256. Args: - input_ (:class:`~planetmint.common.transaction. + input_ (:class:`~planetmint.transactions.common.transaction. Input`) The Input to be signed. message (str): The message to be signed key_pairs (dict): The keys to sign the Transaction with. @@ -962,7 +529,7 @@ class Transaction(object): evaluate parts of the validation-checks to `True`. Args: - outputs (:obj:`list` of :class:`~planetmint.common. + outputs (:obj:`list` of :class:`~planetmint.transactions.common. transaction.Output`): A list of Outputs to check the Inputs against. @@ -1025,7 +592,7 @@ class Transaction(object): does not validate against `output_condition_uri`. Args: - input_ (:class:`~planetmint.common.transaction. + input_ (:class:`~planetmint.transactions.common.transaction. Input`) The Input to be signed. operation (str): The type of Transaction. message (str): The fulfillment message. @@ -1134,7 +701,7 @@ class Transaction(object): transaction are related to the same asset id. Args: - transactions (:obj:`list` of :class:`~planetmint.common. + transactions (:obj:`list` of :class:`~planetmint.transactions.common. transaction.Transaction`): A list of Transactions. Usually input Transactions that should have a matching asset ID. @@ -1196,7 +763,7 @@ class Transaction(object): tx_body (dict): The Transaction to be transformed. Returns: - :class:`~planetmint.common.transaction.Transaction` + :class:`~planetmint.transactions.common.transaction.Transaction` """ operation = tx.get('operation', Transaction.CREATE) if isinstance(tx, dict) else Transaction.CREATE cls = Transaction.resolve_class(operation) diff --git a/planetmint/transactions/common/transaction_link.py b/planetmint/transactions/common/transaction_link.py new file mode 100644 index 0000000..8f36144 --- /dev/null +++ b/planetmint/transactions/common/transaction_link.py @@ -0,0 +1,99 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +from collections import namedtuple +from copy import deepcopy +from functools import reduce, lru_cache +import rapidjson + +import base58 +from cryptoconditions import Fulfillment, ThresholdSha256, Ed25519Sha256 +from cryptoconditions.exceptions import ( + ParsingError, ASN1DecodeError, ASN1EncodeError, UnsupportedTypeError) +try: + from hashlib import sha3_256 +except ImportError: + from sha3 import sha3_256 + +from planetmint.transactions.common.crypto import PrivateKey, hash_data +from planetmint.transactions.common.exceptions import (KeypairMismatchException, + InputDoesNotExist, DoubleSpend, + InvalidHash, InvalidSignature, + AmountError, AssetIdMismatch, + ThresholdTooDeep) +from planetmint.transactions.common.utils import serialize +from .memoize import memoize_from_dict, memoize_to_dict + +class TransactionLink(object): + """An object for unidirectional linking to a Transaction's Output. + + Attributes: + txid (str, optional): A Transaction to link to. + output (int, optional): An output's index in a Transaction with id + `txid`. + """ + + def __init__(self, txid=None, output=None): + """Create an instance of a :class:`~.TransactionLink`. + + Note: + In an IPLD implementation, this class is not necessary anymore, + as an IPLD link can simply point to an object, as well as an + objects properties. So instead of having a (de)serializable + class, we can have a simple IPLD link of the form: + `//transaction/outputs//`. + + Args: + txid (str, optional): A Transaction to link to. + output (int, optional): An Outputs's index in a Transaction with + id `txid`. + """ + self.txid = txid + self.output = output + + def __bool__(self): + return self.txid is not None and self.output is not None + + def __eq__(self, other): + # TODO: If `other !== TransactionLink` return `False` + return self.to_dict() == other.to_dict() + + def __hash__(self): + return hash((self.txid, self.output)) + + @classmethod + def from_dict(cls, link): + """Transforms a Python dictionary to a TransactionLink object. + + Args: + link (dict): The link to be transformed. + + Returns: + :class:`~planetmint.transactions.common.transaction.TransactionLink` + """ + try: + return cls(link['transaction_id'], link['output_index']) + except TypeError: + return cls() + + def to_dict(self): + """Transforms the object to a Python dictionary. + + Returns: + (dict|None): The link as an alternative serialization format. + """ + if self.txid is None and self.output is None: + return None + else: + return { + 'transaction_id': self.txid, + 'output_index': self.output, + } + + def to_uri(self, path=''): + if self.txid is None and self.output is None: + return None + return '{}/transactions/{}/outputs/{}'.format(path, self.txid, + self.output) \ No newline at end of file diff --git a/planetmint/transactions/common/utils.py b/planetmint/transactions/common/utils.py index b1834ea..a4e9f4d 100644 --- a/planetmint/transactions/common/utils.py +++ b/planetmint/transactions/common/utils.py @@ -3,12 +3,13 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 +import base58 import time import re import rapidjson import planetmint -from planetmint.common.exceptions import ValidationError +from planetmint.transactions.common.exceptions import ValidationError def gen_timestamp(): @@ -163,3 +164,52 @@ def validate_key(obj_name, key): 'key name cannot contain characters ' '".", "$" or null characters').format(key, obj_name) raise ValidationError(error_str) + +def _fulfillment_to_details(fulfillment): + """Encode a fulfillment as a details dictionary + + Args: + fulfillment: Crypto-conditions Fulfillment object + """ + + if fulfillment.type_name == 'ed25519-sha-256': + return { + 'type': 'ed25519-sha-256', + 'public_key': base58.b58encode(fulfillment.public_key).decode(), + } + + if fulfillment.type_name == 'threshold-sha-256': + subconditions = [ + _fulfillment_to_details(cond['body']) + for cond in fulfillment.subconditions + ] + return { + 'type': 'threshold-sha-256', + 'threshold': fulfillment.threshold, + 'subconditions': subconditions, + } + + raise UnsupportedTypeError(fulfillment.type_name) + + +def _fulfillment_from_details(data, _depth=0): + """Load a fulfillment for a signing spec dictionary + + Args: + data: tx.output[].condition.details dictionary + """ + if _depth == 100: + raise ThresholdTooDeep() + + if data['type'] == 'ed25519-sha-256': + public_key = base58.b58decode(data['public_key']) + return Ed25519Sha256(public_key=public_key) + + if data['type'] == 'threshold-sha-256': + threshold = ThresholdSha256(data['threshold']) + for cond in data['subconditions']: + cond = _fulfillment_from_details(cond, _depth + 1) + threshold.add_subfulfillment(cond) + return threshold + + raise UnsupportedTypeError(data.get('type')) \ No newline at end of file diff --git a/planetmint/upsert_validator/validator_election.py b/planetmint/upsert_validator/validator_election.py index 5f26f92..b88916e 100644 --- a/planetmint/upsert_validator/validator_election.py +++ b/planetmint/upsert_validator/validator_election.py @@ -3,9 +3,9 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -from planetmint.common.exceptions import InvalidPowerChange +from planetmint.transactions.common.exceptions import InvalidPowerChange from planetmint.elections.election import Election -from planetmint.common.schema import TX_SCHEMA_VALIDATOR_ELECTION +from planetmint.transactions.common.schema import TX_SCHEMA_VALIDATOR_ELECTION from .validator_utils import (new_validator_set, encode_validator, validate_asset_public_key) diff --git a/planetmint/upsert_validator/validator_utils.py b/planetmint/upsert_validator/validator_utils.py index 69293c2..d1cf51c 100644 --- a/planetmint/upsert_validator/validator_utils.py +++ b/planetmint/upsert_validator/validator_utils.py @@ -4,7 +4,7 @@ import codecs from tendermint.abci import types_pb2 from tendermint.crypto import keys_pb2 -from planetmint.common.exceptions import InvalidPublicKey +from planetmint.transactions.common.exceptions import InvalidPublicKey def encode_validator(v): ed25519_public_key = v['public_key']['value'] diff --git a/planetmint/utils.py b/planetmint/utils.py index 51b0fa4..25dbc82 100644 --- a/planetmint/utils.py +++ b/planetmint/utils.py @@ -13,7 +13,7 @@ import setproctitle from packaging import version from planetmint.version import __tm_supported_versions__ from planetmint.tendermint_utils import key_from_base64 -from planetmint.common.crypto import key_pair_from_ed25519_key +from planetmint.transactions.common.crypto import key_pair_from_ed25519_key class ProcessGroup(object): diff --git a/planetmint/web/views/parameters.py b/planetmint/web/views/parameters.py index 530fc38..8f295e4 100644 --- a/planetmint/web/views/parameters.py +++ b/planetmint/web/views/parameters.py @@ -5,7 +5,7 @@ import re -from planetmint.common.transaction_mode_types import (BROADCAST_TX_COMMIT, +from planetmint.transactions.common.transaction_mode_types import (BROADCAST_TX_COMMIT, BROADCAST_TX_ASYNC, BROADCAST_TX_SYNC) diff --git a/planetmint/web/views/transactions.py b/planetmint/web/views/transactions.py index c093ef7..eafaeed 100644 --- a/planetmint/web/views/transactions.py +++ b/planetmint/web/views/transactions.py @@ -12,8 +12,8 @@ import logging from flask import current_app, request, jsonify from flask_restful import Resource, reqparse -from planetmint.common.transaction_mode_types import BROADCAST_TX_ASYNC -from planetmint.common.exceptions import SchemaValidationError, ValidationError +from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_ASYNC +from planetmint.transactions.common.exceptions import SchemaValidationError, ValidationError from planetmint.web.views.base import make_error from planetmint.web.views import parameters from planetmint.models import Transaction diff --git a/setup.py b/setup.py index 7aa0901..e396d3a 100644 --- a/setup.py +++ b/setup.py @@ -138,5 +138,5 @@ setup( 'dev': dev_require + tests_require + docs_require, 'docs': docs_require, }, - package_data={'planetmint.common.schema': ['*.yaml']}, + package_data={'planetmint.transactions.common.schema': ['*.yaml']}, ) diff --git a/tests/assets/test_digital_assets.py b/tests/assets/test_digital_assets.py index ba3f062..b23b05d 100644 --- a/tests/assets/test_digital_assets.py +++ b/tests/assets/test_digital_assets.py @@ -21,7 +21,7 @@ def test_asset_transfer(b, signed_create_tx, user_pk, user_sk): def test_validate_transfer_asset_id_mismatch(b, signed_create_tx, user_pk, user_sk): - from planetmint.common.exceptions import AssetIdMismatch + from planetmint.transactions.common.exceptions import AssetIdMismatch from planetmint.models import Transaction tx_transfer = Transaction.transfer(signed_create_tx.to_inputs(), [([user_pk], 1)], @@ -52,7 +52,7 @@ def test_get_asset_id_transfer_transaction(b, signed_create_tx, user_pk): def test_asset_id_mismatch(alice, user_pk): from planetmint.models import Transaction - from planetmint.common.exceptions import AssetIdMismatch + from planetmint.transactions.common.exceptions import AssetIdMismatch tx1 = Transaction.create([alice.public_key], [([user_pk], 1)], metadata={'msg': random.random()}) diff --git a/tests/assets/test_divisible_assets.py b/tests/assets/test_divisible_assets.py index 437da55..59a8556 100644 --- a/tests/assets/test_divisible_assets.py +++ b/tests/assets/test_divisible_assets.py @@ -6,7 +6,7 @@ import pytest import random -from planetmint.common.exceptions import DoubleSpend +from planetmint.transactions.common.exceptions import DoubleSpend # CREATE divisible asset @@ -99,7 +99,7 @@ def test_single_in_single_own_multiple_out_mix_own_create(alice, user_pk, b): def test_single_in_multiple_own_single_out_single_own_create(alice, b, user_pk, user_sk): from planetmint.models import Transaction - from planetmint.common.transaction import _fulfillment_to_details + from planetmint.transactions.common.transaction import _fulfillment_to_details tx = Transaction.create([alice.public_key, user_pk], [([user_pk], 100)], asset={'name': random.random()}) tx_signed = tx.sign([alice.private_key, user_sk]) @@ -249,7 +249,7 @@ def test_single_in_single_own_multiple_out_mix_own_transfer(alice, b, user_pk, def test_single_in_multiple_own_single_out_single_own_transfer(alice, b, user_pk, user_sk): from planetmint.models import Transaction - from planetmint.common.transaction import _fulfillment_to_details + from planetmint.transactions.common.transaction import _fulfillment_to_details # CREATE divisible asset tx_create = Transaction.create([alice.public_key], [([alice.public_key, user_pk], 100)], @@ -316,7 +316,7 @@ def test_multiple_in_single_own_single_out_single_own_transfer(alice, b, user_pk def test_multiple_in_multiple_own_single_out_single_own_transfer(alice, b, user_pk, user_sk): from planetmint.models import Transaction - from planetmint.common.transaction import _fulfillment_to_details + from planetmint.transactions.common.transaction import _fulfillment_to_details # CREATE divisible asset tx_create = Transaction.create([alice.public_key], [([user_pk, alice.public_key], 50), @@ -357,7 +357,7 @@ def test_multiple_in_multiple_own_single_out_single_own_transfer(alice, b, user_ def test_muiltiple_in_mix_own_multiple_out_single_own_transfer(alice, b, user_pk, user_sk): from planetmint.models import Transaction - from planetmint.common.transaction import _fulfillment_to_details + from planetmint.transactions.common.transaction import _fulfillment_to_details # CREATE divisible asset tx_create = Transaction.create([alice.public_key], [([user_pk], 50), ([user_pk, alice.public_key], 50)], @@ -397,7 +397,7 @@ def test_muiltiple_in_mix_own_multiple_out_single_own_transfer(alice, b, user_pk def test_muiltiple_in_mix_own_multiple_out_mix_own_transfer(alice, b, user_pk, user_sk): from planetmint.models import Transaction - from planetmint.common.transaction import _fulfillment_to_details + from planetmint.transactions.common.transaction import _fulfillment_to_details # CREATE divisible asset tx_create = Transaction.create([alice.public_key], [([user_pk], 50), ([user_pk, alice.public_key], 50)], @@ -486,7 +486,7 @@ def test_multiple_in_different_transactions(alice, b, user_pk, user_sk): # In other words `amount_in_inputs - amount_in_outputs == 0` def test_amount_error_transfer(alice, b, user_pk, user_sk): from planetmint.models import Transaction - from planetmint.common.exceptions import AmountError + from planetmint.transactions.common.exceptions import AmountError # CREATE divisible asset tx_create = Transaction.create([alice.public_key], [([user_pk], 100)], asset={'name': random.random()}) diff --git a/tests/backend/localmongodb/test_queries.py b/tests/backend/localmongodb/test_queries.py index ec86410..0557527 100644 --- a/tests/backend/localmongodb/test_queries.py +++ b/tests/backend/localmongodb/test_queries.py @@ -238,7 +238,7 @@ def test_get_spending_transactions(user_pk, user_sk): def test_get_spending_transactions_multiple_inputs(): from planetmint.backend import connect, query from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair conn = connect() (alice_sk, alice_pk) = generate_key_pair() (bob_sk, bob_pk) = generate_key_pair() diff --git a/tests/backend/test_connection.py b/tests/backend/test_connection.py index 9ff8cc2..424a3d1 100644 --- a/tests/backend/test_connection.py +++ b/tests/backend/test_connection.py @@ -7,7 +7,7 @@ import pytest def test_get_connection_raises_a_configuration_error(monkeypatch): - from planetmint.common.exceptions import ConfigurationError + from planetmint.transactions.common.exceptions import ConfigurationError from planetmint.backend import connect with pytest.raises(ConfigurationError): diff --git a/tests/commands/conftest.py b/tests/commands/conftest.py index 73d25ff..6a1c19c 100644 --- a/tests/commands/conftest.py +++ b/tests/commands/conftest.py @@ -34,7 +34,7 @@ def mock_processes_start(monkeypatch): @pytest.fixture def mock_generate_key_pair(monkeypatch): - monkeypatch.setattr('planetmint.common.crypto.generate_key_pair', lambda: ('privkey', 'pubkey')) + monkeypatch.setattr('planetmint.transactions.common.crypto.generate_key_pair', lambda: ('privkey', 'pubkey')) @pytest.fixture diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index b6c90ad..81d5052 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -123,7 +123,7 @@ def test_drop_db_when_interactive_yes(mock_db_drop, monkeypatch): def test_drop_db_when_db_does_not_exist(mock_db_drop, capsys): from planetmint import config from planetmint.commands.planetmint import run_drop - from planetmint.common.exceptions import DatabaseDoesNotExist + from planetmint.transactions.common.exceptions import DatabaseDoesNotExist args = Namespace(config=None, yes=True) mock_db_drop.side_effect = DatabaseDoesNotExist @@ -404,7 +404,7 @@ def test_election_new_upsert_validator_invalid_election(caplog, b, priv_validato @pytest.mark.bdb def test_election_new_upsert_validator_invalid_power(caplog, b, priv_validator_path, user_sk): from planetmint.commands.planetmint import run_election_new_upsert_validator - from planetmint.common.exceptions import InvalidPowerChange + from planetmint.transactions.common.exceptions import InvalidPowerChange def mock_write(tx, mode): b.store_bulk_transactions([tx]) diff --git a/tests/common/conftest.py b/tests/common/conftest.py index 1f8d029..6a75eff 100644 --- a/tests/common/conftest.py +++ b/tests/common/conftest.py @@ -100,31 +100,31 @@ def user2_Ed25519(user2_pub): @pytest.fixture def user_input(user_Ed25519, user_pub): - from planetmint.common.transaction import Input + from planetmint.transactions.common.transaction import Input return Input(user_Ed25519, [user_pub]) @pytest.fixture def user_user2_threshold_output(user_user2_threshold, user_pub, user2_pub): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output return Output(user_user2_threshold, [user_pub, user2_pub]) @pytest.fixture def user_user2_threshold_input(user_user2_threshold, user_pub, user2_pub): - from planetmint.common.transaction import Input + from planetmint.transactions.common.transaction import Input return Input(user_user2_threshold, [user_pub, user2_pub]) @pytest.fixture def user_output(user_Ed25519, user_pub): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output return Output(user_Ed25519, [user_pub]) @pytest.fixture def user2_output(user2_Ed25519, user2_pub): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output return Output(user2_Ed25519, [user2_pub]) @@ -140,7 +140,7 @@ def data(): @pytest.fixture def utx(user_input, user_output): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction return Transaction(Transaction.CREATE, {'data': None}, [user_input], [user_output]) @@ -152,7 +152,7 @@ def tx(utx, user_priv): @pytest.fixture def transfer_utx(user_output, user2_output, utx): - from planetmint.common.transaction import (Input, TransactionLink, + from planetmint.transactions.common.transaction import (Input, TransactionLink, Transaction) user_output = user_output.to_dict() input = Input(utx.outputs[0].fulfillment, diff --git a/tests/common/test_memoize.py b/tests/common/test_memoize.py index f8a35c5..8665080 100644 --- a/tests/common/test_memoize.py +++ b/tests/common/test_memoize.py @@ -7,8 +7,8 @@ import pytest from copy import deepcopy from planetmint.models import Transaction -from planetmint.common.crypto import generate_key_pair -from planetmint.common.memoize import to_dict, from_dict +from planetmint.transactions.common.crypto import generate_key_pair +from planetmint.transactions.common.memoize import to_dict, from_dict pytestmark = pytest.mark.bdb diff --git a/tests/common/test_schema.py b/tests/common/test_schema.py index 62269b4..07cda88 100644 --- a/tests/common/test_schema.py +++ b/tests/common/test_schema.py @@ -13,8 +13,8 @@ from hypothesis import given from hypothesis.strategies import from_regex as regex from pytest import raises -from planetmint.common.exceptions import SchemaValidationError -from planetmint.common.schema import ( +from planetmint.transactions.common.exceptions import SchemaValidationError +from planetmint.transactions.common.schema import ( TX_SCHEMA_COMMON, validate_transaction_schema, ) diff --git a/tests/common/test_transaction.py b/tests/common/test_transaction.py index 268b714..2a7c811 100644 --- a/tests/common/test_transaction.py +++ b/tests/common/test_transaction.py @@ -21,7 +21,7 @@ pytestmark = mark.bdb def test_input_serialization(ffill_uri, user_pub): - from planetmint.common.transaction import Input + from planetmint.transactions.common.transaction import Input from cryptoconditions import Fulfillment expected = { @@ -34,7 +34,7 @@ def test_input_serialization(ffill_uri, user_pub): def test_input_deserialization_with_uri(ffill_uri, user_pub): - from planetmint.common.transaction import Input + from planetmint.transactions.common.transaction import Input from cryptoconditions import Fulfillment expected = Input(Fulfillment.from_uri(ffill_uri), [user_pub]) @@ -50,7 +50,7 @@ def test_input_deserialization_with_uri(ffill_uri, user_pub): @mark.skip(reason='None is tolerated because it is None before fulfilling.') def test_input_deserialization_with_invalid_input(user_pub): - from planetmint.common.transaction import Input + from planetmint.transactions.common.transaction import Input ffill = { 'owners_before': [user_pub], @@ -62,8 +62,8 @@ def test_input_deserialization_with_invalid_input(user_pub): def test_input_deserialization_with_invalid_fulfillment_uri(user_pub): - from planetmint.common.exceptions import InvalidSignature - from planetmint.common.transaction import Input + from planetmint.transactions.common.exceptions import InvalidSignature + from planetmint.transactions.common.transaction import Input ffill = { 'owners_before': [user_pub], @@ -75,7 +75,7 @@ def test_input_deserialization_with_invalid_fulfillment_uri(user_pub): def test_input_deserialization_with_unsigned_fulfillment(ffill_uri, user_pub): - from planetmint.common.transaction import Input + from planetmint.transactions.common.transaction import Input from cryptoconditions import Fulfillment expected = Input(Fulfillment.from_uri(ffill_uri), [user_pub]) @@ -90,7 +90,7 @@ def test_input_deserialization_with_unsigned_fulfillment(ffill_uri, user_pub): def test_output_serialization(user_Ed25519, user_pub): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output expected = { 'condition': { @@ -110,7 +110,7 @@ def test_output_serialization(user_Ed25519, user_pub): def test_output_deserialization(user_Ed25519, user_pub): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output expected = Output(user_Ed25519, [user_pub], 1) cond = { @@ -130,7 +130,7 @@ def test_output_deserialization(user_Ed25519, user_pub): def test_output_hashlock_serialization(): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output from cryptoconditions import PreimageSha256 secret = b'wow much secret' @@ -149,7 +149,7 @@ def test_output_hashlock_serialization(): def test_output_hashlock_deserialization(): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output from cryptoconditions import PreimageSha256 secret = b'wow much secret' @@ -169,8 +169,8 @@ def test_output_hashlock_deserialization(): def test_invalid_output_initialization(cond_uri, user_pub): - from planetmint.common.transaction import Output - from planetmint.common.exceptions import AmountError + from planetmint.transactions.common.transaction import Output + from planetmint.transactions.common.exceptions import AmountError with raises(TypeError): Output(cond_uri, user_pub) @@ -181,7 +181,7 @@ def test_invalid_output_initialization(cond_uri, user_pub): def test_generate_output_split_half_recursive(user_pub, user2_pub, user3_pub): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output from cryptoconditions import Ed25519Sha256, ThresholdSha256 expected_simple1 = Ed25519Sha256(public_key=b58decode(user_pub)) @@ -201,7 +201,7 @@ 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.common.transaction import Output + from planetmint.transactions.common.transaction import Output from cryptoconditions import Ed25519Sha256, ThresholdSha256 expected_simple1 = Ed25519Sha256(public_key=b58decode(user_pub)) @@ -220,7 +220,7 @@ def test_generate_outputs_split_half_single_owner(user_pub, def test_generate_outputs_flat_ownage(user_pub, user2_pub, user3_pub): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output from cryptoconditions import Ed25519Sha256, ThresholdSha256 expected_simple1 = Ed25519Sha256(public_key=b58decode(user_pub)) @@ -237,7 +237,7 @@ def test_generate_outputs_flat_ownage(user_pub, user2_pub, user3_pub): def test_generate_output_single_owner(user_pub): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output from cryptoconditions import Ed25519Sha256 expected = Ed25519Sha256(public_key=b58decode(user_pub)) @@ -247,7 +247,7 @@ def test_generate_output_single_owner(user_pub): def test_generate_output_single_owner_with_output(user_pub): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output from cryptoconditions import Ed25519Sha256 expected = Ed25519Sha256(public_key=b58decode(user_pub)) @@ -257,8 +257,8 @@ def test_generate_output_single_owner_with_output(user_pub): def test_generate_output_invalid_parameters(user_pub, user2_pub, user3_pub): - from planetmint.common.transaction import Output - from planetmint.common.exceptions import AmountError + from planetmint.transactions.common.transaction import Output + from planetmint.transactions.common.exceptions import AmountError with raises(ValueError): Output.generate([], 1) @@ -273,7 +273,7 @@ def test_generate_output_invalid_parameters(user_pub, user2_pub, user3_pub): def test_invalid_transaction_initialization(asset_definition): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction with raises(ValueError): Transaction(operation='invalid operation', asset=asset_definition) @@ -305,7 +305,7 @@ def test_invalid_transaction_initialization(asset_definition): def test_create_default_asset_on_tx_initialization(asset_definition): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction expected = {'data': None} tx = Transaction(Transaction.CREATE, asset=expected) @@ -315,7 +315,7 @@ def test_create_default_asset_on_tx_initialization(asset_definition): def test_transaction_serialization(user_input, user_output, data): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction expected = { 'id': None, @@ -339,14 +339,14 @@ def test_transaction_serialization(user_input, user_output, data): def test_transaction_deserialization(tri_state_transaction): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model tx = Transaction.from_dict(tri_state_transaction) validate_transaction_model(tx) def test_invalid_input_initialization(user_input, user_pub): - from planetmint.common.transaction import Input + from planetmint.transactions.common.transaction import Input with raises(TypeError): Input(user_input, user_pub) @@ -355,7 +355,7 @@ def test_invalid_input_initialization(user_input, user_pub): def test_transaction_link_serialization(): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink tx_id = 'a transaction id' expected = { @@ -368,7 +368,7 @@ def test_transaction_link_serialization(): def test_transaction_link_serialization_with_empty_payload(): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink expected = None tx_link = TransactionLink() @@ -377,7 +377,7 @@ def test_transaction_link_serialization_with_empty_payload(): def test_transaction_link_deserialization(): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink tx_id = 'a transaction id' expected = TransactionLink(tx_id, 0) @@ -391,7 +391,7 @@ def test_transaction_link_deserialization(): def test_transaction_link_deserialization_with_empty_payload(): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink expected = TransactionLink() tx_link = TransactionLink.from_dict(None) @@ -400,7 +400,7 @@ def test_transaction_link_deserialization_with_empty_payload(): def test_transaction_link_empty_to_uri(): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink expected = None tx_link = TransactionLink().to_uri() @@ -409,7 +409,7 @@ def test_transaction_link_empty_to_uri(): def test_transaction_link_to_uri(): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink expected = 'path/transactions/abc/outputs/0' tx_link = TransactionLink('abc', 0).to_uri('path') @@ -418,7 +418,7 @@ def test_transaction_link_to_uri(): def test_cast_transaction_link_to_boolean(): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink assert bool(TransactionLink()) is False assert bool(TransactionLink('a', None)) is False @@ -428,7 +428,7 @@ def test_cast_transaction_link_to_boolean(): def test_transaction_link_eq(): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink assert TransactionLink(1, 2) == TransactionLink(1, 2) assert TransactionLink(2, 2) != TransactionLink(1, 2) @@ -437,7 +437,7 @@ def test_transaction_link_eq(): def test_add_input_to_tx(user_input, asset_definition): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model tx = Transaction(Transaction.CREATE, asset_definition, [], []) @@ -449,7 +449,7 @@ def test_add_input_to_tx(user_input, asset_definition): def test_add_input_to_tx_with_invalid_parameters(asset_definition): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction tx = Transaction(Transaction.CREATE, asset_definition) with raises(TypeError): @@ -457,7 +457,7 @@ 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.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model tx = Transaction(Transaction.CREATE, asset_definition, [user_input]) @@ -469,7 +469,7 @@ 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.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction tx = Transaction(Transaction.CREATE, asset_definition, [], []) with raises(TypeError): @@ -485,7 +485,7 @@ 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.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model tx = Transaction(Transaction.CREATE, asset_definition, [user_input], [user_output]) @@ -507,7 +507,7 @@ def test_validate_tx_simple_create_signature(user_input, user_output, user_priv, def test_invoke_simple_signature_fulfillment_with_invalid_params(utx, user_input): - from planetmint.common.exceptions import KeypairMismatchException + from planetmint.transactions.common.exceptions import KeypairMismatchException with raises(KeypairMismatchException): invalid_key_pair = {'wrong_pub_key': 'wrong_priv_key'} @@ -518,7 +518,7 @@ def test_invoke_simple_signature_fulfillment_with_invalid_params(utx, def test_sign_threshold_with_invalid_params(utx, user_user2_threshold_input, user3_pub, user3_priv): - from planetmint.common.exceptions import KeypairMismatchException + from planetmint.transactions.common.exceptions import KeypairMismatchException with raises(KeypairMismatchException): utx._sign_threshold_signature_fulfillment(user_user2_threshold_input, @@ -532,7 +532,7 @@ def test_sign_threshold_with_invalid_params(utx, user_user2_threshold_input, def test_validate_input_with_invalid_parameters(utx): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction input_conditions = [out.fulfillment.condition_uri for out in utx.outputs] tx_dict = utx.to_dict() @@ -548,7 +548,7 @@ def test_validate_tx_threshold_create_signature(user_user2_threshold_input, user_priv, user2_priv, asset_definition): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model tx = Transaction(Transaction.CREATE, asset_definition, @@ -576,7 +576,7 @@ def test_validate_tx_threshold_create_signature(user_user2_threshold_input, def test_validate_tx_threshold_duplicated_pk(user_pub, user_priv, asset_definition): from cryptoconditions import Ed25519Sha256, ThresholdSha256 - from planetmint.common.transaction import Input, Output, Transaction + from planetmint.transactions.common.transaction import Input, Output, Transaction threshold = ThresholdSha256(threshold=2) threshold.add_subfulfillment( @@ -621,7 +621,7 @@ def test_multiple_input_validation_of_transfer_tx(user_input, user_output, user2_priv, user3_pub, user3_priv, asset_definition): - from planetmint.common.transaction import (Transaction, TransactionLink, + from planetmint.transactions.common.transaction import (Transaction, TransactionLink, Input, Output) from cryptoconditions import Ed25519Sha256 from .utils import validate_transaction_model @@ -647,7 +647,7 @@ def test_multiple_input_validation_of_transfer_tx(user_input, user_output, def test_validate_inputs_of_transfer_tx_with_invalid_params( transfer_tx, cond_uri, utx, user2_pub, user_priv, ffill_uri): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output from cryptoconditions import Ed25519Sha256 invalid_out = Output(Ed25519Sha256.from_uri(ffill_uri), ['invalid']) @@ -668,7 +668,7 @@ def test_validate_inputs_of_transfer_tx_with_invalid_params( def test_create_create_transaction_single_io(user_output, user_pub, data): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model expected = { @@ -703,7 +703,7 @@ def test_create_create_transaction_single_io(user_output, user_pub, data): def test_validate_single_io_create_transaction(user_pub, user_priv, data, asset_definition): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction tx = Transaction.create([user_pub], [([user_pub], 1)], metadata=data) tx = tx.sign([user_priv]) @@ -712,7 +712,7 @@ def test_validate_single_io_create_transaction(user_pub, user_priv, data, def test_create_create_transaction_multiple_io(user_output, user2_output, user_pub, user2_pub, asset_definition): - from planetmint.common.transaction import Transaction, Input + 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 @@ -739,7 +739,7 @@ def test_create_create_transaction_multiple_io(user_output, user2_output, user_p def test_validate_multiple_io_create_transaction(user_pub, user_priv, user2_pub, user2_priv, asset_definition): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model tx = Transaction.create([user_pub, user2_pub], @@ -754,7 +754,7 @@ def test_validate_multiple_io_create_transaction(user_pub, user_priv, def test_create_create_transaction_threshold(user_pub, user2_pub, user3_pub, user_user2_threshold_output, user_user2_threshold_input, data): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction expected = { 'outputs': [user_user2_threshold_output.to_dict()], @@ -785,7 +785,7 @@ def test_create_create_transaction_threshold(user_pub, user2_pub, user3_pub, def test_validate_threshold_create_transaction(user_pub, user_priv, user2_pub, data, asset_definition): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model tx = Transaction.create([user_pub], [([user_pub, user2_pub], 1)], @@ -797,7 +797,7 @@ def test_validate_threshold_create_transaction(user_pub, user_priv, user2_pub, def test_create_create_transaction_with_invalid_parameters(user_pub): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction with raises(TypeError): Transaction.create('not a list') @@ -832,7 +832,7 @@ def test_outputs_to_inputs(tx): def test_create_transfer_transaction_single_io(tx, user_pub, user2_pub, user2_output, user_priv): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model expected = { @@ -887,7 +887,7 @@ def test_create_transfer_transaction_multiple_io(user_pub, user_priv, user2_pub, user2_priv, user3_pub, user2_output, asset_definition): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction tx = Transaction.create([user_pub], [([user_pub], 1), ([user2_pub], 1)], metadata={'message': 'hello'}) @@ -941,7 +941,7 @@ def test_create_transfer_transaction_multiple_io(user_pub, user_priv, def test_create_transfer_with_invalid_parameters(tx, user_pub): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction with raises(TypeError): Transaction.transfer({}, [], tx.id) @@ -964,7 +964,7 @@ def test_create_transfer_with_invalid_parameters(tx, user_pub): def test_cant_add_empty_output(): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction tx = Transaction(Transaction.CREATE, None) with raises(TypeError): @@ -972,7 +972,7 @@ def test_cant_add_empty_output(): def test_cant_add_empty_input(): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction tx = Transaction(Transaction.CREATE, None) with raises(TypeError): @@ -980,7 +980,7 @@ def test_cant_add_empty_input(): def test_unfulfilled_transaction_serialized(unfulfilled_transaction): - from planetmint.common.transaction import 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) @@ -988,7 +988,7 @@ def test_unfulfilled_transaction_serialized(unfulfilled_transaction): def test_fulfilled_transaction_serialized(fulfilled_transaction): - from planetmint.common.transaction import 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) @@ -996,7 +996,7 @@ def test_fulfilled_transaction_serialized(fulfilled_transaction): def test_transaction_hash(fulfilled_transaction): - from planetmint.common.transaction import 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 @@ -1009,8 +1009,8 @@ def test_transaction_hash(fulfilled_transaction): def test_output_from_dict_invalid_amount(user_output): - from planetmint.common.transaction import Output - from planetmint.common.exceptions import AmountError + from planetmint.transactions.common.transaction import Output + from planetmint.transactions.common.exceptions import AmountError out = user_output.to_dict() out['amount'] = 'a' @@ -1019,7 +1019,7 @@ def test_output_from_dict_invalid_amount(user_output): def test_unspent_outputs_property(merlin, alice, bob, carol): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction tx = Transaction.create( [merlin.public_key], [([alice.public_key], 1), diff --git a/tests/common/utils.py b/tests/common/utils.py index d95575e..bd10303 100644 --- a/tests/common/utils.py +++ b/tests/common/utils.py @@ -5,8 +5,8 @@ def validate_transaction_model(tx): - from planetmint.common.transaction import Transaction - from planetmint.common.schema import validate_transaction_schema + from planetmint.transactions.common.transaction import Transaction + from planetmint.transactions.common.schema import validate_transaction_schema tx_dict = tx.to_dict() # Check that a transaction is valid by re-serializing it diff --git a/tests/conftest.py b/tests/conftest.py index af49f42..780abbb 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -23,13 +23,13 @@ import pytest from pymongo import MongoClient from planetmint import ValidatorElection -from planetmint.common import crypto -from planetmint.common.transaction_mode_types import BROADCAST_TX_COMMIT +from planetmint.transactions.common import crypto +from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT from planetmint.tendermint_utils import key_from_base64 from planetmint.backend import schema, query -from planetmint.common.crypto import (key_pair_from_ed25519_key, +from planetmint.transactions.common.crypto import (key_pair_from_ed25519_key, public_key_from_ed25519_key) -from planetmint.common.exceptions import DatabaseDoesNotExist +from planetmint.transactions.common.exceptions import DatabaseDoesNotExist from planetmint.lib import Block from tests.utils import gen_vote @@ -149,7 +149,7 @@ def _bdb(_setup_database, _configure_planetmint): from planetmint import config from planetmint.backend import connect from .utils import flush_db - from planetmint.common.memoize import to_dict, from_dict + from planetmint.transactions.common.memoize import to_dict, from_dict from planetmint.models import Transaction conn = connect() yield @@ -205,13 +205,13 @@ def user2_pk(): @pytest.fixture def alice(): - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair return generate_key_pair() @pytest.fixture def bob(): - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair return generate_key_pair() @@ -227,7 +227,7 @@ def bob_pubkey(carol): @pytest.fixture def carol(): - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair return generate_key_pair() @@ -243,7 +243,7 @@ def carol_pubkey(carol): @pytest.fixture def merlin(): - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair return generate_key_pair() diff --git a/tests/db/test_bigchain_api.py b/tests/db/test_bigchain_api.py index b6d4124..9724cb6 100644 --- a/tests/db/test_bigchain_api.py +++ b/tests/db/test_bigchain_api.py @@ -15,7 +15,7 @@ class TestBigchainApi(object): def test_get_spent_with_double_spend_detected(self, b, alice): from planetmint.models import Transaction - from planetmint.common.exceptions import DoubleSpend + from planetmint.transactions.common.exceptions import DoubleSpend from planetmint.exceptions import CriticalDoubleSpend tx = Transaction.create([alice.public_key], [([alice.public_key], 1)]) @@ -81,8 +81,8 @@ class TestBigchainApi(object): @pytest.mark.usefixtures('inputs') def test_non_create_input_not_found(self, b, user_pk): from cryptoconditions import Ed25519Sha256 - from planetmint.common.exceptions import InputDoesNotExist - from planetmint.common.transaction import Input, TransactionLink + from planetmint.transactions.common.exceptions import InputDoesNotExist + from planetmint.transactions.common.transaction import Input, TransactionLink from planetmint.models import Transaction # Create an input for a non existing transaction @@ -117,8 +117,8 @@ class TestBigchainApi(object): class TestTransactionValidation(object): def test_non_create_input_not_found(self, b, signed_transfer_tx): - from planetmint.common.exceptions import InputDoesNotExist - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.exceptions import InputDoesNotExist + from planetmint.transactions.common.transaction import TransactionLink signed_transfer_tx.inputs[0].fulfills = TransactionLink('c', 0) with pytest.raises(InputDoesNotExist): @@ -126,8 +126,8 @@ class TestTransactionValidation(object): @pytest.mark.usefixtures('inputs') def test_non_create_valid_input_wrong_owner(self, b, user_pk): - from planetmint.common.crypto import generate_key_pair - from planetmint.common.exceptions import InvalidSignature + from planetmint.transactions.common.crypto import generate_key_pair + from planetmint.transactions.common.exceptions import InvalidSignature from planetmint.models import Transaction input_tx = b.fastquery.get_outputs_by_public_key(user_pk).pop() @@ -144,7 +144,7 @@ class TestTransactionValidation(object): @pytest.mark.usefixtures('inputs') def test_non_create_double_spend(self, b, signed_create_tx, signed_transfer_tx, double_spend_tx): - from planetmint.common.exceptions import DoubleSpend + from planetmint.transactions.common.exceptions import DoubleSpend b.store_bulk_transactions([signed_create_tx, signed_transfer_tx]) @@ -156,7 +156,7 @@ class TestMultipleInputs(object): def test_transfer_single_owner_single_input(self, b, inputs, user_pk, user_sk): - from planetmint.common import crypto + from planetmint.transactions.common import crypto from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -177,7 +177,7 @@ class TestMultipleInputs(object): user_sk, user_pk, inputs): - from planetmint.common import crypto + from planetmint.transactions.common import crypto from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -199,7 +199,7 @@ class TestMultipleInputs(object): user_sk, user_pk, alice): - from planetmint.common import crypto + from planetmint.transactions.common import crypto from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -227,7 +227,7 @@ class TestMultipleInputs(object): user_sk, user_pk, alice): - from planetmint.common import crypto + from planetmint.transactions.common import crypto from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -252,8 +252,8 @@ class TestMultipleInputs(object): assert len(tx.outputs) == 1 def test_get_owned_ids_single_tx_single_output(self, b, user_sk, user_pk, alice): - from planetmint.common import crypto - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common import crypto + from planetmint.transactions.common.transaction import TransactionLink from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -280,8 +280,8 @@ class TestMultipleInputs(object): def test_get_owned_ids_single_tx_multiple_outputs(self, b, user_sk, user_pk, alice): - from planetmint.common import crypto - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common import crypto + from planetmint.transactions.common.transaction import TransactionLink from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -314,8 +314,8 @@ class TestMultipleInputs(object): TransactionLink(tx_transfer.id, 1)] def test_get_owned_ids_multiple_owners(self, b, user_sk, user_pk, alice): - from planetmint.common import crypto - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common import crypto + from planetmint.transactions.common.transaction import TransactionLink from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -346,7 +346,7 @@ class TestMultipleInputs(object): assert not spent_user1 def test_get_spent_single_tx_single_output(self, b, user_sk, user_pk, alice): - from planetmint.common import crypto + from planetmint.transactions.common import crypto from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -372,7 +372,7 @@ class TestMultipleInputs(object): assert spent_inputs_user1 == tx def test_get_spent_single_tx_multiple_outputs(self, b, user_sk, user_pk, alice): - from planetmint.common import crypto + from planetmint.transactions.common import crypto from planetmint.models import Transaction # create a new users @@ -409,7 +409,7 @@ class TestMultipleInputs(object): assert b.get_spent(tx_create.to_inputs()[2].fulfills.txid, 2) is None def test_get_spent_multiple_owners(self, b, user_sk, user_pk, alice): - from planetmint.common import crypto + from planetmint.transactions.common import crypto from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -445,7 +445,7 @@ class TestMultipleInputs(object): def test_get_outputs_filtered_only_unspent(): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink from planetmint.lib import Planetmint go = 'planetmint.fastquery.FastQuery.get_outputs_by_public_key' @@ -461,7 +461,7 @@ def test_get_outputs_filtered_only_unspent(): def test_get_outputs_filtered_only_spent(): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink from planetmint.lib import Planetmint go = 'planetmint.fastquery.FastQuery.get_outputs_by_public_key' with patch(go) as get_outputs: @@ -478,7 +478,7 @@ def test_get_outputs_filtered_only_spent(): @patch('planetmint.fastquery.FastQuery.filter_unspent_outputs') @patch('planetmint.fastquery.FastQuery.filter_spent_outputs') def test_get_outputs_filtered(filter_spent, filter_unspent): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink from planetmint.lib import Planetmint go = 'planetmint.fastquery.FastQuery.get_outputs_by_public_key' @@ -497,7 +497,7 @@ def test_cant_spend_same_input_twice_in_tx(b, alice): https://github.com/planetmint/planetmint/issues/1099 """ from planetmint.models import Transaction - from planetmint.common.exceptions import DoubleSpend + from planetmint.transactions.common.exceptions import DoubleSpend # create a divisible asset tx_create = Transaction.create([alice.public_key], [([alice.public_key], 100)]) @@ -517,7 +517,7 @@ def test_cant_spend_same_input_twice_in_tx(b, alice): def test_transaction_unicode(b, alice): import copy - from planetmint.common.utils import serialize + from planetmint.transactions.common.utils import serialize from planetmint.models import Transaction # http://www.fileformat.info/info/unicode/char/1f37a/index.htm diff --git a/tests/tendermint/test_core.py b/tests/tendermint/test_core.py index 5f54a1b..fdf3ec1 100644 --- a/tests/tendermint/test_core.py +++ b/tests/tendermint/test_core.py @@ -12,7 +12,7 @@ from tendermint.crypto import keys_pb2 from planetmint import App from planetmint.backend.localmongodb import query -from planetmint.common.crypto import generate_key_pair +from planetmint.transactions.common.crypto import generate_key_pair from planetmint.core import (OkCode, CodeTypeError, rollback) @@ -203,7 +203,7 @@ def test_info(b): def test_check_tx__signed_create_is_ok(b): from planetmint import App from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() bob = generate_key_pair() @@ -220,7 +220,7 @@ def test_check_tx__signed_create_is_ok(b): def test_check_tx__unsigned_create_is_error(b): from planetmint import App from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() bob = generate_key_pair() @@ -237,7 +237,7 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(b, init_chain_reque import multiprocessing as mp from planetmint import App from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() bob = generate_key_pair() @@ -274,7 +274,7 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(b, init_chain_reque def test_deliver_tx__double_spend_fails(b, init_chain_request): from planetmint import App from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() bob = generate_key_pair() @@ -303,7 +303,7 @@ def test_deliver_tx__double_spend_fails(b, init_chain_request): def test_deliver_transfer_tx__double_spend_fails(b, init_chain_request): from planetmint import App from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair app = App(b) app.init_chain(init_chain_request) diff --git a/tests/tendermint/test_fastquery.py b/tests/tendermint/test_fastquery.py index 98ca97a..61f8ac9 100644 --- a/tests/tendermint/test_fastquery.py +++ b/tests/tendermint/test_fastquery.py @@ -5,7 +5,7 @@ import pytest -from planetmint.common.transaction import TransactionLink +from planetmint.transactions.common.transaction import TransactionLink from planetmint.models import Transaction diff --git a/tests/tendermint/test_integration.py b/tests/tendermint/test_integration.py index a57a3b2..45b4db1 100644 --- a/tests/tendermint/test_integration.py +++ b/tests/tendermint/test_integration.py @@ -13,7 +13,7 @@ import pytest from abci.server import ProtocolHandler from abci.utils import read_messages -from planetmint.common.transaction_mode_types import BROADCAST_TX_COMMIT, BROADCAST_TX_SYNC +from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT, BROADCAST_TX_SYNC from planetmint.version import __tm_supported_versions__ from io import BytesIO @@ -22,7 +22,7 @@ from io import BytesIO def test_app(b, eventqueue_fixture, init_chain_request): from planetmint import App from planetmint.tendermint_utils import calculate_hash - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair from planetmint.models import Transaction app = App(b, eventqueue_fixture) @@ -113,7 +113,7 @@ def test_app(b, eventqueue_fixture, init_chain_request): @pytest.mark.abci def test_post_transaction_responses(tendermint_ws_url, b): - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair from planetmint.models import Transaction alice = generate_key_pair() diff --git a/tests/tendermint/test_lib.py b/tests/tendermint/test_lib.py index 2d9bc96..3f92554 100644 --- a/tests/tendermint/test_lib.py +++ b/tests/tendermint/test_lib.py @@ -17,7 +17,7 @@ import pytest from pymongo import MongoClient from planetmint import backend -from planetmint.common.transaction_mode_types import (BROADCAST_TX_COMMIT, +from planetmint.transactions.common.transaction_mode_types import (BROADCAST_TX_COMMIT, BROADCAST_TX_ASYNC, BROADCAST_TX_SYNC) from planetmint.lib import Block @@ -27,7 +27,7 @@ from planetmint.lib import Block def test_asset_is_separated_from_transaciton(b): import copy from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() bob = generate_key_pair() @@ -83,7 +83,7 @@ def test_get_empty_block(_0, _1, b): def test_validation_error(b): from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() tx = Transaction.create([alice.public_key], @@ -98,7 +98,7 @@ def test_validation_error(b): @patch('requests.post') def test_write_and_post_transaction(mock_post, b): from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair from planetmint.tendermint_utils import encode_transaction alice = generate_key_pair() @@ -125,7 +125,7 @@ def test_write_and_post_transaction(mock_post, b): ]) def test_post_transaction_valid_modes(mock_post, b, mode): from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], @@ -140,8 +140,8 @@ def test_post_transaction_valid_modes(mock_post, b, mode): def test_post_transaction_invalid_mode(b): from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair - from planetmint.common.exceptions import ValidationError + from planetmint.transactions.common.crypto import generate_key_pair + from planetmint.transactions.common.exceptions import ValidationError alice = generate_key_pair() tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], @@ -357,7 +357,7 @@ def test_get_utxoset_merkle_root(b, utxoset): def test_get_spent_transaction_critical_double_spend(b, alice, bob, carol): from planetmint.models import Transaction from planetmint.exceptions import CriticalDoubleSpend - from planetmint.common.exceptions import DoubleSpend + from planetmint.transactions.common.exceptions import DoubleSpend asset = {'test': 'asset'} @@ -404,7 +404,7 @@ def test_get_spent_transaction_critical_double_spend(b, alice, bob, carol): def test_validation_with_transaction_buffer(b): - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair from planetmint.models import Transaction priv_key, pub_key = generate_key_pair() @@ -461,8 +461,8 @@ def test_migrate_abci_chain_generates_new_chains(b, chain, block_height, def test_get_spent_key_order(b, user_pk, user_sk, user2_pk, user2_sk): from planetmint import backend from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair - from planetmint.common.exceptions import DoubleSpend + from planetmint.transactions.common.crypto import generate_key_pair + from planetmint.transactions.common.exceptions import DoubleSpend alice = generate_key_pair() bob = generate_key_pair() diff --git a/tests/test_config_utils.py b/tests/test_config_utils.py index 4bcff77..ebf9874 100644 --- a/tests/test_config_utils.py +++ b/tests/test_config_utils.py @@ -298,7 +298,7 @@ def test_file_config(): def test_invalid_file_config(): from planetmint.config_utils import file_config - from planetmint.common import exceptions + from planetmint.transactions.common import exceptions with patch('builtins.open', mock_open(read_data='{_INVALID_JSON_}')): with pytest.raises(exceptions.ConfigurationError): file_config() diff --git a/tests/test_core.py b/tests/test_core.py index 6d61344..f87015e 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -12,7 +12,7 @@ from tendermint.crypto import keys_pb2 from planetmint import App from planetmint.backend.localmongodb import query -from planetmint.common.crypto import generate_key_pair +from planetmint.transactions.common.crypto import generate_key_pair from planetmint.core import (OkCode, CodeTypeError, rollback) @@ -203,7 +203,7 @@ def test_info(b): def test_check_tx__signed_create_is_ok(b): from planetmint import App from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() bob = generate_key_pair() @@ -220,7 +220,7 @@ def test_check_tx__signed_create_is_ok(b): def test_check_tx__unsigned_create_is_error(b): from planetmint import App from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() bob = generate_key_pair() @@ -237,7 +237,7 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(b, init_chain_reque import multiprocessing as mp from planetmint import App from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() bob = generate_key_pair() @@ -274,7 +274,7 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(b, init_chain_reque def test_deliver_tx__double_spend_fails(b, eventqueue_fixture, init_chain_request): from planetmint import App from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() bob = generate_key_pair() @@ -303,7 +303,7 @@ def test_deliver_tx__double_spend_fails(b, eventqueue_fixture, init_chain_reques def test_deliver_transfer_tx__double_spend_fails(b, init_chain_request): from planetmint import App from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair app = App(b) app.init_chain(init_chain_request) diff --git a/tests/test_parallel_validation.py b/tests/test_parallel_validation.py index a0aec26..df2a39d 100644 --- a/tests/test_parallel_validation.py +++ b/tests/test_parallel_validation.py @@ -5,7 +5,7 @@ import pytest -from planetmint.common.crypto import generate_key_pair +from planetmint.transactions.common.crypto import generate_key_pair from planetmint.models import Transaction diff --git a/tests/upsert_validator/test_upsert_validator_vote.py b/tests/upsert_validator/test_upsert_validator_vote.py index 5fb4fe0..1506459 100644 --- a/tests/upsert_validator/test_upsert_validator_vote.py +++ b/tests/upsert_validator/test_upsert_validator_vote.py @@ -9,10 +9,10 @@ import codecs from planetmint.elections.election import Election from planetmint.tendermint_utils import public_key_to_base64 from planetmint.upsert_validator import ValidatorElection -from planetmint.common.exceptions import AmountError -from planetmint.common.crypto import generate_key_pair -from planetmint.common.exceptions import ValidationError -from planetmint.common.transaction_mode_types import BROADCAST_TX_COMMIT +from planetmint.transactions.common.exceptions import AmountError +from planetmint.transactions.common.crypto import generate_key_pair +from planetmint.transactions.common.exceptions import ValidationError +from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT from planetmint.elections.vote import Vote from tests.utils import generate_block, gen_vote diff --git a/tests/upsert_validator/test_validator_election.py b/tests/upsert_validator/test_validator_election.py index 3b8e3e5..a51b8a1 100644 --- a/tests/upsert_validator/test_validator_election.py +++ b/tests/upsert_validator/test_validator_election.py @@ -9,7 +9,7 @@ import pytest from planetmint.tendermint_utils import public_key_to_base64 from planetmint.upsert_validator import ValidatorElection -from planetmint.common.exceptions import (DuplicateTransaction, +from planetmint.transactions.common.exceptions import (DuplicateTransaction, UnequalValidatorSet, InvalidProposer, MultipleInputsError, @@ -27,7 +27,7 @@ def test_upsert_validator_valid_election(b_mock, new_validator, node_key): def test_upsert_validator_invalid_election_public_key(b_mock, new_validator, node_key): - from planetmint.common.exceptions import InvalidPublicKey + from planetmint.transactions.common.exceptions import InvalidPublicKey for iv in ['ed25519-base32', 'ed25519-base64']: new_validator['public_key']['type'] = iv @@ -51,7 +51,7 @@ def test_upsert_validator_invalid_power_election(b_mock, new_validator, node_key def test_upsert_validator_invalid_proposed_election(b_mock, new_validator, node_key): - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() voters = ValidatorElection.recipients(b_mock) @@ -63,7 +63,7 @@ def test_upsert_validator_invalid_proposed_election(b_mock, new_validator, node_ def test_upsert_validator_invalid_inputs_election(b_mock, new_validator, node_key): - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() voters = ValidatorElection.recipients(b_mock) diff --git a/tests/utils.py b/tests/utils.py index 05a54e2..428f14d 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -11,8 +11,8 @@ from functools import singledispatch from planetmint.backend.localmongodb.connection import LocalMongoDBConnection from planetmint.backend.schema import TABLES -from planetmint.common import crypto -from planetmint.common.transaction_mode_types import BROADCAST_TX_COMMIT +from planetmint.transactions.common import crypto +from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT from planetmint.elections.election import Election, Vote from planetmint.tendermint_utils import key_to_base64 @@ -29,7 +29,7 @@ def flush_localmongo_db(connection, dbname): def generate_block(planet): - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair from planetmint.models import Transaction alice = generate_key_pair() diff --git a/tests/validation/test_transaction_structure.py b/tests/validation/test_transaction_structure.py index b710253..973f089 100644 --- a/tests/validation/test_transaction_structure.py +++ b/tests/validation/test_transaction_structure.py @@ -16,7 +16,7 @@ except ImportError: import sha3 from unittest.mock import MagicMock -from planetmint.common.exceptions import (AmountError, +from planetmint.transactions.common.exceptions import (AmountError, SchemaValidationError, ThresholdTooDeep) from planetmint.models import Transaction @@ -54,8 +54,8 @@ def test_tx_serialization_hash_function(signed_create_tx): def test_tx_serialization_with_incorrect_hash(signed_create_tx): - from planetmint.common.transaction import Transaction - from planetmint.common.exceptions import InvalidHash + from planetmint.transactions.common.transaction import Transaction + from planetmint.transactions.common.exceptions import InvalidHash tx = signed_create_tx.to_dict() tx['id'] = 'a' * 64 with pytest.raises(InvalidHash): @@ -63,7 +63,7 @@ def test_tx_serialization_with_incorrect_hash(signed_create_tx): def test_tx_serialization_with_no_hash(signed_create_tx): - from planetmint.common.exceptions import InvalidHash + from planetmint.transactions.common.exceptions import InvalidHash tx = signed_create_tx.to_dict() del tx['id'] with pytest.raises(InvalidHash): @@ -104,7 +104,7 @@ def test_validate_fails_metadata_empty_dict(b, create_tx, alice): # Asset def test_transfer_asset_schema(user_sk, signed_transfer_tx): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction tx = signed_transfer_tx.to_dict() validate(tx) tx['id'] = None @@ -149,7 +149,7 @@ def test_no_inputs(b, create_tx, alice): def test_create_single_input(b, create_tx, alice): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction tx = create_tx.to_dict() tx['inputs'] += tx['inputs'] tx = Transaction.from_dict(tx).sign([alice.private_key]).to_dict() @@ -161,7 +161,7 @@ def test_create_single_input(b, create_tx, alice): def test_create_tx_no_fulfills(b, create_tx, alice): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction tx = create_tx.to_dict() tx['inputs'][0]['fulfills'] = {'transaction_id': 'a' * 64, 'output_index': 0} @@ -213,7 +213,7 @@ def test_high_amounts(b, create_tx, alice): # Conditions def test_handle_threshold_overflow(): - from planetmint.common import transaction + from planetmint.transactions.common import transaction cond = { 'type': 'ed25519-sha-256', @@ -230,7 +230,7 @@ def test_handle_threshold_overflow(): def test_unsupported_condition_type(): - from planetmint.common import transaction + from planetmint.transactions.common import transaction from cryptoconditions.exceptions import UnsupportedTypeError with pytest.raises(UnsupportedTypeError): diff --git a/tests/web/test_outputs.py b/tests/web/test_outputs.py index db4e77a..112526a 100644 --- a/tests/web/test_outputs.py +++ b/tests/web/test_outputs.py @@ -84,7 +84,7 @@ def test_get_outputs_endpoint_with_invalid_spent(client, user_pk): @pytest.mark.abci def test_get_divisble_transactions_returns_500(b, client): from planetmint.models import Transaction - from planetmint.common import crypto + from planetmint.transactions.common import crypto import json TX_ENDPOINT = '/api/v1/transactions' diff --git a/tests/web/test_transactions.py b/tests/web/test_transactions.py index 3d2a73d..03bb334 100644 --- a/tests/web/test_transactions.py +++ b/tests/web/test_transactions.py @@ -14,8 +14,8 @@ try: except ImportError: from sha3 import sha3_256 -from planetmint.common import crypto -from planetmint.common.transaction_mode_types import (BROADCAST_TX_COMMIT, +from planetmint.transactions.common import crypto +from planetmint.transactions.common.transaction_mode_types import (BROADCAST_TX_COMMIT, BROADCAST_TX_ASYNC, BROADCAST_TX_SYNC) @@ -133,7 +133,7 @@ def test_post_create_transaction_with_invalid_key(b, client, field, value, @pytest.mark.abci @patch('planetmint.web.views.base.logger') def test_post_create_transaction_with_invalid_id(mock_logger, b, client): - from planetmint.common.exceptions import InvalidHash + from planetmint.transactions.common.exceptions import InvalidHash from planetmint.models import Transaction user_priv, user_pub = crypto.generate_key_pair() @@ -170,7 +170,7 @@ def test_post_create_transaction_with_invalid_id(mock_logger, b, client): def test_post_create_transaction_with_invalid_signature(mock_logger, b, client): - from planetmint.common.exceptions import InvalidSignature + from planetmint.transactions.common.exceptions import InvalidSignature from planetmint.models import Transaction user_priv, user_pub = crypto.generate_key_pair() @@ -274,7 +274,7 @@ def test_post_create_transaction_with_invalid_schema(mock_logger, client): )) @patch('planetmint.web.views.base.logger') def test_post_invalid_transaction(mock_logger, client, exc, msg, monkeypatch,): - from planetmint.common import exceptions + from planetmint.transactions.common import exceptions exc_cls = getattr(exceptions, exc) def mock_validation(self_, tx): @@ -326,7 +326,7 @@ def test_post_transfer_transaction_endpoint(client, user_pk, user_sk, posted_cre @pytest.mark.abci def test_post_invalid_transfer_transaction_returns_400(client, user_pk, posted_create_tx): from planetmint.models import Transaction - from planetmint.common.exceptions import InvalidSignature + from planetmint.transactions.common.exceptions import InvalidSignature transfer_tx = Transaction.transfer(posted_create_tx.to_inputs(), [([user_pk], 1)], @@ -344,7 +344,7 @@ def test_post_invalid_transfer_transaction_returns_400(client, user_pk, posted_c @pytest.mark.abci def test_post_wrong_asset_division_transfer_returns_400(b, client, user_pk): from planetmint.models import Transaction - from planetmint.common.exceptions import AmountError + from planetmint.transactions.common.exceptions import AmountError priv_key, pub_key = crypto.generate_key_pair() @@ -425,7 +425,7 @@ def test_transactions_get_list_bad(client): ]) def test_post_transaction_valid_modes(mock_post, client, mode): from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair def _mock_post(*args, **kwargs): return Mock(json=Mock(return_value={'result': {'code': 0}})) @@ -446,7 +446,7 @@ def test_post_transaction_valid_modes(mock_post, client, mode): @pytest.mark.abci def test_post_transaction_invalid_mode(client): from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], diff --git a/tests/web/test_websocket_server.py b/tests/web/test_websocket_server.py index da83a4e..05b45fc 100644 --- a/tests/web/test_websocket_server.py +++ b/tests/web/test_websocket_server.py @@ -22,7 +22,7 @@ class MockWebSocket: def test_eventify_block_works_with_any_transaction(): from planetmint.web.websocket_server import eventify_block - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair from planetmint.lib import Transaction alice = generate_key_pair() @@ -139,7 +139,7 @@ async def test_websocket_block_event(b, test_client, loop): from planetmint import events from planetmint.web.websocket_server import init_app, POISON_PILL, EVENTS_ENDPOINT from planetmint.models import Transaction - from planetmint.common import crypto + from planetmint.transactions.common import crypto user_priv, user_pub = crypto.generate_key_pair() tx = Transaction.create([user_pub], [([user_pub], 1)]) @@ -180,7 +180,7 @@ def test_integration_from_webapi_to_websocket(monkeypatch, client, loop): import random import aiohttp - from planetmint.common import crypto + from planetmint.transactions.common import crypto # TODO processes does not exist anymore, when reactivating this test it # will fail because of this from planetmint import processes From a421533e16ae7c827de9290fb8e87cce8e1f4d6a Mon Sep 17 00:00:00 2001 From: Sangat Das Date: Wed, 9 Mar 2022 17:12:36 +0000 Subject: [PATCH 56/93] Added Create and Transfer as separate transactions --- planetmint/transactions/common/transaction.py | 6 +- .../types/assets}/__init__.py | 0 .../transactions/types/assets/create.py | 78 +++++++++++++++++ .../transactions/types/assets/transfer.py | 85 +++++++++++++++++++ .../transactions/types/elections/__init__.py | 0 .../types}/elections/election.py | 16 ++-- .../types}/elections/vote.py | 10 ++- 7 files changed, 181 insertions(+), 14 deletions(-) rename planetmint/{elections => transactions/types/assets}/__init__.py (100%) create mode 100644 planetmint/transactions/types/assets/create.py create mode 100644 planetmint/transactions/types/assets/transfer.py create mode 100644 planetmint/transactions/types/elections/__init__.py rename planetmint/{ => transactions/types}/elections/election.py (95%) rename planetmint/{ => transactions/types}/elections/vote.py (84%) diff --git a/planetmint/transactions/common/transaction.py b/planetmint/transactions/common/transaction.py index c7301f6..aa8de36 100644 --- a/planetmint/transactions/common/transaction.py +++ b/planetmint/transactions/common/transaction.py @@ -25,13 +25,13 @@ try: except ImportError: from sha3 import sha3_256 -from planetmint.common.crypto import PrivateKey, hash_data -from planetmint.common.exceptions import (KeypairMismatchException, +from planetmint.transactions.common.crypto import PrivateKey, hash_data +from planetmint.transactions.common.exceptions import (KeypairMismatchException, InputDoesNotExist, DoubleSpend, InvalidHash, InvalidSignature, AmountError, AssetIdMismatch, ThresholdTooDeep) -from planetmint.common.utils import serialize +from planetmint.transactions.common.utils import serialize from .memoize import memoize_from_dict, memoize_to_dict diff --git a/planetmint/elections/__init__.py b/planetmint/transactions/types/assets/__init__.py similarity index 100% rename from planetmint/elections/__init__.py rename to planetmint/transactions/types/assets/__init__.py diff --git a/planetmint/transactions/types/assets/create.py b/planetmint/transactions/types/assets/create.py new file mode 100644 index 0000000..8af8216 --- /dev/null +++ b/planetmint/transactions/types/assets/create.py @@ -0,0 +1,78 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +from planetmint.transactions.common.transaction import (Transaction, Input, Output) + +class Create(Transaction): + + OPERATION = 'CREATE' + # NOTE: This class inherits TRANSFER txn type. The `TRANSFER` property is + # overriden to re-use methods from parent class + TRANSFER = OPERATION + ALLOWED_OPERATIONS = (OPERATION,) + + @classmethod + def validate(self, tx_signers, recipients, asset, metadata): + if not isinstance(tx_signers, list): + raise TypeError('`tx_signers` must be a list instance') + if not isinstance(recipients, list): + raise TypeError('`recipients` must be a list instance') + if len(tx_signers) == 0: + raise ValueError('`tx_signers` list cannot be empty') + if len(recipients) == 0: + raise ValueError('`recipients` list cannot be empty') + if not (asset is None or isinstance(asset, dict)): + raise TypeError('`asset` must be a dict or None') + if not (metadata is None or isinstance(metadata, dict)): + raise TypeError('`metadata` must be a dict or None') + + inputs = [] + outputs = [] + + # generate_outputs + for recipient in recipients: + if not isinstance(recipient, tuple) or len(recipient) != 2: + raise ValueError(('Each `recipient` in the list must be a' + ' tuple of `([],' + ' )`')) + pub_keys, amount = recipient + outputs.append(Output.generate(pub_keys, amount)) + + # generate inputs + inputs.append(Input.generate(tx_signers)) + + return (inputs, outputs) + + @classmethod + def generate(cls, tx_signers, recipients, metadata=None, asset=None): + """A simple way to generate a `CREATE` transaction. + + Note: + This method currently supports the following Cryptoconditions + use cases: + - Ed25519 + - ThresholdSha256 + + Additionally, it provides support for the following Planetmint + use cases: + - Multiple inputs and outputs. + + Args: + tx_signers (:obj:`list` of :obj:`str`): A list of keys that + represent the signers of the CREATE Transaction. + recipients (:obj:`list` of :obj:`tuple`): A list of + ([keys],amount) that represent the recipients of this + Transaction. + metadata (dict): The metadata to be stored along with the + Transaction. + asset (dict): The metadata associated with the asset that will + be created in this Transaction. + + Returns: + :class:`~planetmint.common.transaction.Transaction` + """ + + (inputs, outputs) = cls.validate(tx_signers, recipients, asset, metadata) + return cls(cls.OPERATION, {'data': asset}, inputs, outputs, metadata) diff --git a/planetmint/transactions/types/assets/transfer.py b/planetmint/transactions/types/assets/transfer.py new file mode 100644 index 0000000..98c8602 --- /dev/null +++ b/planetmint/transactions/types/assets/transfer.py @@ -0,0 +1,85 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +from planetmint.transactions.common.transaction import (Transaction, Input, Output) +from planetmint.transactions.common.schema import (_validate_schema, + TX_SCHEMA_COMMON, + TX_SCHEMA_TRANSFER) +from copy import deepcopy + +class Transfer(Transaction): + + OPERATION = 'TRANSFER' + # NOTE: This class inherits TRANSFER txn type. The `TRANSFER` property is + # overriden to re-use methods from parent class + TRANSFER = OPERATION + ALLOWED_OPERATIONS = (OPERATION,) + + @classmethod + def validate(cls, inputs, recipients, asset_id, metadata): + if not isinstance(inputs, list): + raise TypeError('`inputs` must be a list instance') + if len(inputs) == 0: + raise ValueError('`inputs` must contain at least one item') + if not isinstance(recipients, list): + raise TypeError('`recipients` must be a list instance') + if len(recipients) == 0: + raise ValueError('`recipients` list cannot be empty') + + outputs = [] + for recipient in recipients: + if not isinstance(recipient, tuple) or len(recipient) != 2: + raise ValueError(('Each `recipient` in the list must be a' + ' tuple of `([],' + ' )`')) + pub_keys, amount = recipient + outputs.append(Output.generate(pub_keys, amount)) + + if not isinstance(asset_id, str): + raise TypeError('`asset_id` must be a string') + + return (deepcopy(inputs), outputs) + + @classmethod + def generate(cls, inputs, recipients, asset_id, metadata=None): + """A simple way to generate a `TRANSFER` transaction. + + Note: + Different cases for threshold conditions: + + Combining multiple `inputs` with an arbitrary number of + `recipients` can yield interesting cases for the creation of + threshold conditions we'd like to support. The following + notation is proposed: + + 1. The index of a `recipient` corresponds to the index of + an input: + e.g. `transfer([input1], [a])`, means `input1` would now be + owned by user `a`. + + 2. `recipients` can (almost) get arbitrary deeply nested, + creating various complex threshold conditions: + e.g. `transfer([inp1, inp2], [[a, [b, c]], d])`, means + `a`'s signature would have a 50% weight on `inp1` + compared to `b` and `c` that share 25% of the leftover + weight respectively. `inp2` is owned completely by `d`. + + Args: + inputs (:obj:`list` of :class:`~planetmint.common.transaction. + Input`): Converted `Output`s, intended to + be used as inputs in the transfer to generate. + recipients (:obj:`list` of :obj:`tuple`): A list of + ([keys],amount) that represent the recipients of this + Transaction. + asset_id (str): The asset ID of the asset to be transferred in + this Transaction. + metadata (dict): Python dictionary to be stored along with the + Transaction. + + Returns: + :class:`~planetmint.common.transaction.Transaction` + """ + (inputs, outputs) = cls.validate_transfer(inputs, recipients, asset_id, metadata) + return cls(cls.OPERATION, {'id': asset_id}, inputs, outputs, metadata) diff --git a/planetmint/transactions/types/elections/__init__.py b/planetmint/transactions/types/elections/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/planetmint/elections/election.py b/planetmint/transactions/types/elections/election.py similarity index 95% rename from planetmint/elections/election.py rename to planetmint/transactions/types/elections/election.py index d73b319..736212a 100644 --- a/planetmint/elections/election.py +++ b/planetmint/transactions/types/elections/election.py @@ -8,16 +8,18 @@ import base58 from uuid import uuid4 from planetmint import backend -from planetmint.elections.vote import Vote -from planetmint.common.exceptions import (InvalidSignature, +from planetmint.transactions.types.assets.create import Create +from planetmint.transactions.types.assets.transfer import Transfer +from planetmint.transactions.types.elections.vote import Vote +from planetmint.transactions.common.exceptions import (InvalidSignature, MultipleInputsError, InvalidProposer, UnequalValidatorSet, DuplicateTransaction) from planetmint.tendermint_utils import key_from_base64, public_key_to_base64 -from planetmint.common.crypto import (public_key_from_ed25519_key) -from planetmint.common.transaction import Transaction -from planetmint.common.schema import (_validate_schema, +from planetmint.transactions.common.crypto import (public_key_from_ed25519_key) +from planetmint.transactions.common.transaction import Transaction +from planetmint.transactions.common.schema import (_validate_schema, TX_SCHEMA_COMMON, TX_SCHEMA_CREATE) @@ -161,11 +163,11 @@ class Election(Transaction): @classmethod def create(cls, tx_signers, recipients, metadata=None, asset=None): - raise NotImplementedError + Create.generate(tx_signers, recipients, metadata=None, asset=None) @classmethod def transfer(cls, tx_signers, recipients, metadata=None, asset=None): - raise NotImplementedError + Transfer.generate(tx_signers, recipients, metadata=None, asset=None) @classmethod def to_public_key(cls, election_id): diff --git a/planetmint/elections/vote.py b/planetmint/transactions/types/elections/vote.py similarity index 84% rename from planetmint/elections/vote.py rename to planetmint/transactions/types/elections/vote.py index a4bb0c9..16d7dcd 100644 --- a/planetmint/elections/vote.py +++ b/planetmint/transactions/types/elections/vote.py @@ -3,8 +3,10 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -from planetmint.common.transaction import Transaction -from planetmint.common.schema import (_validate_schema, +from planetmint.transactions.types.assets.create import Create +from planetmint.transactions.types.assets.transfer import Transfer +from planetmint.transactions.common.transaction import Transaction +from planetmint.transactions.common.schema import (_validate_schema, TX_SCHEMA_COMMON, TX_SCHEMA_TRANSFER, TX_SCHEMA_VOTE) @@ -57,8 +59,8 @@ class Vote(Transaction): @classmethod def create(cls, tx_signers, recipients, metadata=None, asset=None): - raise NotImplementedError + return Create.generate(tx_signers, recipients, metadata=None, asset=None) @classmethod def transfer(cls, tx_signers, recipients, metadata=None, asset=None): - raise NotImplementedError + return Transfer.generate(tx_signers, recipients, metadata=None, asset=None) From 1c744b744b75a8fe27c424a2ed4582fa444137cd Mon Sep 17 00:00:00 2001 From: ArpitShukla007 Date: Wed, 9 Mar 2022 17:39:14 +0000 Subject: [PATCH 57/93] Resolved errors related to transactions.common --- planetmint/transactions/common/utils.py | 8 ++++++++ tests/assets/test_divisible_assets.py | 10 +++++----- tests/validation/test_transaction_structure.py | 7 ++++--- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/planetmint/transactions/common/utils.py b/planetmint/transactions/common/utils.py index a4e9f4d..f734551 100644 --- a/planetmint/transactions/common/utils.py +++ b/planetmint/transactions/common/utils.py @@ -10,6 +10,14 @@ import rapidjson import planetmint from planetmint.transactions.common.exceptions import ValidationError +from cryptoconditions import Fulfillment, ThresholdSha256, Ed25519Sha256 +from planetmint.transactions.common.exceptions import (KeypairMismatchException, + InputDoesNotExist, DoubleSpend, + InvalidHash, InvalidSignature, + AmountError, AssetIdMismatch, + ThresholdTooDeep) +from cryptoconditions.exceptions import ( + ParsingError, ASN1DecodeError, ASN1EncodeError, UnsupportedTypeError) def gen_timestamp(): diff --git a/tests/assets/test_divisible_assets.py b/tests/assets/test_divisible_assets.py index 59a8556..570be4b 100644 --- a/tests/assets/test_divisible_assets.py +++ b/tests/assets/test_divisible_assets.py @@ -99,7 +99,7 @@ def test_single_in_single_own_multiple_out_mix_own_create(alice, user_pk, b): def test_single_in_multiple_own_single_out_single_own_create(alice, b, user_pk, user_sk): from planetmint.models import Transaction - from planetmint.transactions.common.transaction import _fulfillment_to_details + from planetmint.transactions.common.utils import _fulfillment_to_details tx = Transaction.create([alice.public_key, user_pk], [([user_pk], 100)], asset={'name': random.random()}) tx_signed = tx.sign([alice.private_key, user_sk]) @@ -249,7 +249,7 @@ def test_single_in_single_own_multiple_out_mix_own_transfer(alice, b, user_pk, def test_single_in_multiple_own_single_out_single_own_transfer(alice, b, user_pk, user_sk): from planetmint.models import Transaction - from planetmint.transactions.common.transaction import _fulfillment_to_details + from planetmint.transactions.common.utils import _fulfillment_to_details # CREATE divisible asset tx_create = Transaction.create([alice.public_key], [([alice.public_key, user_pk], 100)], @@ -316,7 +316,7 @@ def test_multiple_in_single_own_single_out_single_own_transfer(alice, b, user_pk def test_multiple_in_multiple_own_single_out_single_own_transfer(alice, b, user_pk, user_sk): from planetmint.models import Transaction - from planetmint.transactions.common.transaction import _fulfillment_to_details + from planetmint.transactions.common.utils import _fulfillment_to_details # CREATE divisible asset tx_create = Transaction.create([alice.public_key], [([user_pk, alice.public_key], 50), @@ -357,7 +357,7 @@ def test_multiple_in_multiple_own_single_out_single_own_transfer(alice, b, user_ def test_muiltiple_in_mix_own_multiple_out_single_own_transfer(alice, b, user_pk, user_sk): from planetmint.models import Transaction - from planetmint.transactions.common.transaction import _fulfillment_to_details + from planetmint.transactions.common.utils import _fulfillment_to_details # CREATE divisible asset tx_create = Transaction.create([alice.public_key], [([user_pk], 50), ([user_pk, alice.public_key], 50)], @@ -397,7 +397,7 @@ def test_muiltiple_in_mix_own_multiple_out_single_own_transfer(alice, b, user_pk def test_muiltiple_in_mix_own_multiple_out_mix_own_transfer(alice, b, user_pk, user_sk): from planetmint.models import Transaction - from planetmint.transactions.common.transaction import _fulfillment_to_details + from planetmint.transactions.common.utils import _fulfillment_to_details # CREATE divisible asset tx_create = Transaction.create([alice.public_key], [([user_pk], 50), ([user_pk, alice.public_key], 50)], diff --git a/tests/validation/test_transaction_structure.py b/tests/validation/test_transaction_structure.py index 973f089..8cf33da 100644 --- a/tests/validation/test_transaction_structure.py +++ b/tests/validation/test_transaction_structure.py @@ -20,6 +20,7 @@ from planetmint.transactions.common.exceptions import (AmountError, SchemaValidationError, ThresholdTooDeep) from planetmint.models import Transaction +from planetmint.transactions.common.utils import _fulfillment_to_details, _fulfillment_from_details ################################################################################ # Helper functions @@ -226,7 +227,7 @@ def test_handle_threshold_overflow(): 'subconditions': [cond], } with pytest.raises(ThresholdTooDeep): - transaction._fulfillment_from_details(cond) + _fulfillment_from_details(cond) def test_unsupported_condition_type(): @@ -234,10 +235,10 @@ def test_unsupported_condition_type(): from cryptoconditions.exceptions import UnsupportedTypeError with pytest.raises(UnsupportedTypeError): - transaction._fulfillment_from_details({'type': 'a'}) + _fulfillment_from_details({'type': 'a'}) with pytest.raises(UnsupportedTypeError): - transaction._fulfillment_to_details(MagicMock(type_name='a')) + _fulfillment_to_details(MagicMock(type_name='a')) ################################################################################ From 396372203910c4734cc76fa8c829080d97f64a5a Mon Sep 17 00:00:00 2001 From: Sangat Das Date: Wed, 9 Mar 2022 17:42:24 +0000 Subject: [PATCH 58/93] Fixing imports --- planetmint/transactions/types/assets/create.py | 7 +++---- planetmint/transactions/types/assets/transfer.py | 10 +++------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/planetmint/transactions/types/assets/create.py b/planetmint/transactions/types/assets/create.py index 8af8216..d8a1222 100644 --- a/planetmint/transactions/types/assets/create.py +++ b/planetmint/transactions/types/assets/create.py @@ -3,14 +3,13 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -from planetmint.transactions.common.transaction import (Transaction, Input, Output) +from planetmint.transactions.common.transaction import Transaction +from planetmint.transactions.common.input import Input +from planetmint.transactions.common.output import Output class Create(Transaction): OPERATION = 'CREATE' - # NOTE: This class inherits TRANSFER txn type. The `TRANSFER` property is - # overriden to re-use methods from parent class - TRANSFER = OPERATION ALLOWED_OPERATIONS = (OPERATION,) @classmethod diff --git a/planetmint/transactions/types/assets/transfer.py b/planetmint/transactions/types/assets/transfer.py index 98c8602..444634f 100644 --- a/planetmint/transactions/types/assets/transfer.py +++ b/planetmint/transactions/types/assets/transfer.py @@ -3,18 +3,14 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -from planetmint.transactions.common.transaction import (Transaction, Input, Output) -from planetmint.transactions.common.schema import (_validate_schema, - TX_SCHEMA_COMMON, - TX_SCHEMA_TRANSFER) +from planetmint.transactions.common.transaction import Transaction +from planetmint.transactions.common.input import Input +from planetmint.transactions.common.output import Output from copy import deepcopy class Transfer(Transaction): OPERATION = 'TRANSFER' - # NOTE: This class inherits TRANSFER txn type. The `TRANSFER` property is - # overriden to re-use methods from parent class - TRANSFER = OPERATION ALLOWED_OPERATIONS = (OPERATION,) @classmethod From 327ec2dc0993774563a875915fee569e526d3944 Mon Sep 17 00:00:00 2001 From: ArpitShukla007 Date: Thu, 10 Mar 2022 08:07:14 +0000 Subject: [PATCH 59/93] Resolved issues of election transaction --- planetmint/__init__.py | 2 +- planetmint/commands/planetmint.py | 2 +- planetmint/core.py | 2 +- planetmint/migrations/chain_migration_election.py | 2 +- planetmint/upsert_validator/validator_election.py | 2 +- tests/commands/test_commands.py | 2 +- tests/elections/test_election.py | 2 +- tests/tendermint/test_core.py | 2 +- tests/test_core.py | 2 +- tests/upsert_validator/conftest.py | 2 +- tests/upsert_validator/test_upsert_validator_vote.py | 4 ++-- tests/upsert_validator/test_validator_election.py | 2 +- tests/utils.py | 2 +- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/planetmint/__init__.py b/planetmint/__init__.py index 84c140a..785daef 100644 --- a/planetmint/__init__.py +++ b/planetmint/__init__.py @@ -97,7 +97,7 @@ _config = copy.deepcopy(config) from planetmint.transactions.common.transaction import Transaction # noqa from planetmint import models # noqa from planetmint.upsert_validator import ValidatorElection # noqa -from planetmint.elections.vote import Vote # noqa +from planetmint.transactions.types.elections.vote import Vote # noqa Transaction.register_type(Transaction.CREATE, models.Transaction) Transaction.register_type(Transaction.TRANSFER, models.Transaction) diff --git a/planetmint/commands/planetmint.py b/planetmint/commands/planetmint.py index 4714fc1..d1d9707 100644 --- a/planetmint/commands/planetmint.py +++ b/planetmint/commands/planetmint.py @@ -20,7 +20,7 @@ from planetmint.utils import load_node_key from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT from planetmint.transactions.common.exceptions import (DatabaseDoesNotExist, ValidationError) -from planetmint.elections.vote import Vote +from planetmint.transactions.types.elections.vote import Vote import planetmint from planetmint import (backend, ValidatorElection, Planetmint) diff --git a/planetmint/core.py b/planetmint/core.py index 143bd55..43c13f4 100644 --- a/planetmint/core.py +++ b/planetmint/core.py @@ -21,7 +21,7 @@ from tendermint.abci.types_pb2 import ( ResponseCommit ) from planetmint import Planetmint -from planetmint.elections.election import Election +from planetmint.transactions.types.elections.election import Election from planetmint.tendermint_utils import (decode_transaction, calculate_hash) from planetmint.lib import Block diff --git a/planetmint/migrations/chain_migration_election.py b/planetmint/migrations/chain_migration_election.py index 03616cc..5e23e40 100644 --- a/planetmint/migrations/chain_migration_election.py +++ b/planetmint/migrations/chain_migration_election.py @@ -1,7 +1,7 @@ import json from planetmint.transactions.common.schema import TX_SCHEMA_CHAIN_MIGRATION_ELECTION -from planetmint.elections.election import Election +from planetmint.transactions.types.elections.election import Election class ChainMigrationElection(Election): diff --git a/planetmint/upsert_validator/validator_election.py b/planetmint/upsert_validator/validator_election.py index b88916e..31e4161 100644 --- a/planetmint/upsert_validator/validator_election.py +++ b/planetmint/upsert_validator/validator_election.py @@ -4,7 +4,7 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 from planetmint.transactions.common.exceptions import InvalidPowerChange -from planetmint.elections.election import Election +from planetmint.transactions.types.elections.election import Election from planetmint.transactions.common.schema import TX_SCHEMA_VALIDATOR_ELECTION from .validator_utils import (new_validator_set, encode_validator, validate_asset_public_key) diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index 81d5052..1e9384f 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -13,7 +13,7 @@ import pytest from planetmint import ValidatorElection from planetmint.commands.planetmint import run_election_show -from planetmint.elections.election import Election +from planetmint.transactions.types.elections.election import Election from planetmint.lib import Block from planetmint.migrations.chain_migration_election import ChainMigrationElection diff --git a/tests/elections/test_election.py b/tests/elections/test_election.py index af0e08a..e58ec4f 100644 --- a/tests/elections/test_election.py +++ b/tests/elections/test_election.py @@ -3,7 +3,7 @@ import pytest from tests.utils import generate_election, generate_validators from planetmint.lib import Block -from planetmint.elections.election import Election +from planetmint.transactions.types.elections.election import Election from planetmint.migrations.chain_migration_election import ChainMigrationElection from planetmint.upsert_validator.validator_election import ValidatorElection diff --git a/tests/tendermint/test_core.py b/tests/tendermint/test_core.py index fdf3ec1..581fbe9 100644 --- a/tests/tendermint/test_core.py +++ b/tests/tendermint/test_core.py @@ -16,7 +16,7 @@ from planetmint.transactions.common.crypto import generate_key_pair from planetmint.core import (OkCode, CodeTypeError, rollback) -from planetmint.elections.election import Election +from planetmint.transactions.types.elections.election import Election from planetmint.lib import Block from planetmint.migrations.chain_migration_election import ChainMigrationElection from planetmint.upsert_validator.validator_election import ValidatorElection diff --git a/tests/test_core.py b/tests/test_core.py index f87015e..140cd22 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -16,7 +16,7 @@ from planetmint.transactions.common.crypto import generate_key_pair from planetmint.core import (OkCode, CodeTypeError, rollback) -from planetmint.elections.election import Election +from planetmint.transactions.types.elections.election import Election from planetmint.lib import Block from planetmint.migrations.chain_migration_election import ChainMigrationElection from planetmint.upsert_validator.validator_election import ValidatorElection diff --git a/tests/upsert_validator/conftest.py b/tests/upsert_validator/conftest.py index f4f71c4..39b8d26 100644 --- a/tests/upsert_validator/conftest.py +++ b/tests/upsert_validator/conftest.py @@ -19,7 +19,7 @@ def valid_upsert_validator_election_b(b, node_key, new_validator): @pytest.fixture -@patch('planetmint.elections.election.uuid4', lambda: 'mock_uuid4') +@patch('planetmint.transactions.types.elections.election.uuid4', lambda: 'mock_uuid4') def fixed_seed_election(b_mock, node_key, new_validator): voters = ValidatorElection.recipients(b_mock) return ValidatorElection.generate([node_key.public_key], diff --git a/tests/upsert_validator/test_upsert_validator_vote.py b/tests/upsert_validator/test_upsert_validator_vote.py index 1506459..95ec43c 100644 --- a/tests/upsert_validator/test_upsert_validator_vote.py +++ b/tests/upsert_validator/test_upsert_validator_vote.py @@ -6,14 +6,14 @@ import pytest import codecs -from planetmint.elections.election import Election +from planetmint.transactions.types.elections.election import Election from planetmint.tendermint_utils import public_key_to_base64 from planetmint.upsert_validator import ValidatorElection from planetmint.transactions.common.exceptions import AmountError from planetmint.transactions.common.crypto import generate_key_pair from planetmint.transactions.common.exceptions import ValidationError from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT -from planetmint.elections.vote import Vote +from planetmint.transactions.types.elections.vote import Vote from tests.utils import generate_block, gen_vote pytestmark = [pytest.mark.execute] diff --git a/tests/upsert_validator/test_validator_election.py b/tests/upsert_validator/test_validator_election.py index a51b8a1..db6f50f 100644 --- a/tests/upsert_validator/test_validator_election.py +++ b/tests/upsert_validator/test_validator_election.py @@ -74,7 +74,7 @@ def test_upsert_validator_invalid_inputs_election(b_mock, new_validator, node_ke election.validate(b_mock) -@patch('planetmint.elections.election.uuid4', lambda: 'mock_uuid4') +@patch('planetmint.transactions.types.elections.election.uuid4', lambda: 'mock_uuid4') def test_upsert_validator_invalid_election(b_mock, new_validator, node_key, fixed_seed_election): voters = ValidatorElection.recipients(b_mock) duplicate_election = ValidatorElection.generate([node_key.public_key], diff --git a/tests/utils.py b/tests/utils.py index 428f14d..4829d4e 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -13,7 +13,7 @@ from planetmint.backend.localmongodb.connection import LocalMongoDBConnection from planetmint.backend.schema import TABLES from planetmint.transactions.common import crypto from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT -from planetmint.elections.election import Election, Vote +from planetmint.transactions.types.elections.election import Election, Vote from planetmint.tendermint_utils import key_to_base64 From 51a92e3c3c0c7ad04c66d36951da73b331fc9b6c Mon Sep 17 00:00:00 2001 From: Sangat Das Date: Sun, 13 Mar 2022 15:05:22 +0000 Subject: [PATCH 60/93] Resolve flake8 issues Signed-off-by: Sangat Das --- planetmint/backend/schema.py | 3 ++- planetmint/commands/planetmint.py | 4 +-- planetmint/lib.py | 19 ++++++-------- planetmint/models.py | 3 +-- planetmint/transactions/common/input.py | 24 +++--------------- planetmint/transactions/common/output.py | 22 +++------------- planetmint/transactions/common/transaction.py | 9 +++---- .../transactions/common/transaction_link.py | 25 +------------------ planetmint/transactions/common/utils.py | 14 ++++------- .../transactions/types/assets/transfer.py | 1 - .../transactions/types/elections/election.py | 13 ++++------ .../transactions/types/elections/vote.py | 6 ++--- planetmint/web/views/parameters.py | 6 ++--- tests/common/conftest.py | 4 +-- tests/common/test_transaction.py | 4 +-- tests/conftest.py | 4 +-- tests/tendermint/test_lib.py | 5 ++-- .../test_validator_election.py | 8 +++--- .../validation/test_transaction_structure.py | 8 ++---- tests/web/test_transactions.py | 5 ++-- 20 files changed, 52 insertions(+), 135 deletions(-) diff --git a/planetmint/backend/schema.py b/planetmint/backend/schema.py index 3e88d27..b19315b 100644 --- a/planetmint/backend/schema.py +++ b/planetmint/backend/schema.py @@ -11,7 +11,8 @@ import logging import planetmint from planetmint.backend.connection import connect from planetmint.transactions.common.exceptions import ValidationError -from planetmint.transactions.common.utils import validate_all_values_for_key_in_obj, validate_all_values_for_key_in_list +from planetmint.transactions.common.utils import ( + validate_all_values_for_key_in_obj, validate_all_values_for_key_in_list) logger = logging.getLogger(__name__) diff --git a/planetmint/commands/planetmint.py b/planetmint/commands/planetmint.py index d1d9707..9d09571 100644 --- a/planetmint/commands/planetmint.py +++ b/planetmint/commands/planetmint.py @@ -18,8 +18,8 @@ from planetmint.core import rollback from planetmint.migrations.chain_migration_election import ChainMigrationElection from planetmint.utils import load_node_key from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT -from planetmint.transactions.common.exceptions import (DatabaseDoesNotExist, - ValidationError) +from planetmint.transactions.common.exceptions import ( + DatabaseDoesNotExist, ValidationError) from planetmint.transactions.types.elections.vote import Vote import planetmint from planetmint import (backend, ValidatorElection, diff --git a/planetmint/lib.py b/planetmint/lib.py index 8b66386..4451d65 100644 --- a/planetmint/lib.py +++ b/planetmint/lib.py @@ -24,31 +24,26 @@ import requests import planetmint from planetmint import backend, config_utils, fastquery from planetmint.models import Transaction -from planetmint.transactions.common.exceptions import (SchemaValidationError, - ValidationError, - DoubleSpend) -from planetmint.transactions.common.transaction_mode_types import (BROADCAST_TX_COMMIT, - BROADCAST_TX_ASYNC, - BROADCAST_TX_SYNC) +from planetmint.transactions.common.exceptions import ( + SchemaValidationError, ValidationError, DoubleSpend) +from planetmint.transactions.common.transaction_mode_types import (BROADCAST_TX_COMMIT, BROADCAST_TX_ASYNC, BROADCAST_TX_SYNC) from planetmint.tendermint_utils import encode_transaction, merkleroot from planetmint import exceptions as core_exceptions from planetmint.validation import BaseValidationRules - logger = logging.getLogger(__name__) - class Planetmint(object): - """Bigchain API + """Planetmint API Create, read, sign, write transactions to the database """ def __init__(self, connection=None): - """Initialize the Bigchain instance + """Initialize the Planetmint instance - A Bigchain instance has several configuration parameters (e.g. host). - If a parameter value is passed as an argument to the Bigchain + A Planetmint instance has several configuration parameters (e.g. host). + If a parameter value is passed as an argument to the Planetmint __init__ method, then that is the value it will have. Otherwise, the parameter value will come from an environment variable. If that environment variable isn't set, then the value diff --git a/planetmint/models.py b/planetmint/models.py index e0edac6..419cb44 100644 --- a/planetmint/models.py +++ b/planetmint/models.py @@ -4,8 +4,7 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 from planetmint.backend.schema import validate_language_key -from planetmint.transactions.common.exceptions import (InvalidSignature, - DuplicateTransaction) +from planetmint.transactions.common.exceptions import (InvalidSignature, DuplicateTransaction) from planetmint.transactions.common.schema import validate_transaction_schema from planetmint.transactions.common.transaction import Transaction from planetmint.transactions.common.utils import (validate_txn_obj, validate_key) diff --git a/planetmint/transactions/common/input.py b/planetmint/transactions/common/input.py index 927de97..ab123cb 100644 --- a/planetmint/transactions/common/input.py +++ b/planetmint/transactions/common/input.py @@ -3,28 +3,10 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -from collections import namedtuple -from copy import deepcopy -from functools import reduce, lru_cache -import rapidjson +from cryptoconditions import Fulfillment +from cryptoconditions.exceptions import ASN1DecodeError, ASN1EncodeError -import base58 -from cryptoconditions import Fulfillment, ThresholdSha256, Ed25519Sha256 -from cryptoconditions.exceptions import ( - ParsingError, ASN1DecodeError, ASN1EncodeError, UnsupportedTypeError) -try: - from hashlib import sha3_256 -except ImportError: - from sha3 import sha3_256 - -from planetmint.transactions.common.crypto import PrivateKey, hash_data -from planetmint.transactions.common.exceptions import (KeypairMismatchException, - InputDoesNotExist, DoubleSpend, - InvalidHash, InvalidSignature, - AmountError, AssetIdMismatch, - ThresholdTooDeep) -from planetmint.transactions.common.utils import serialize -from .memoize import memoize_from_dict, memoize_to_dict +from planetmint.transactions.common.exceptions import InvalidSignature from .utils import _fulfillment_to_details, _fulfillment_from_details from .output import Output from .transaction_link import TransactionLink diff --git a/planetmint/transactions/common/output.py b/planetmint/transactions/common/output.py index 137542f..6462941 100644 --- a/planetmint/transactions/common/output.py +++ b/planetmint/transactions/common/output.py @@ -3,28 +3,12 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -from collections import namedtuple -from copy import deepcopy -from functools import reduce, lru_cache -import rapidjson +from functools import reduce import base58 from cryptoconditions import Fulfillment, ThresholdSha256, Ed25519Sha256 -from cryptoconditions.exceptions import ( - ParsingError, ASN1DecodeError, ASN1EncodeError, UnsupportedTypeError) -try: - from hashlib import sha3_256 -except ImportError: - from sha3 import sha3_256 -from planetmint.transactions.common.crypto import PrivateKey, hash_data -from planetmint.transactions.common.exceptions import (KeypairMismatchException, - InputDoesNotExist, DoubleSpend, - InvalidHash, InvalidSignature, - AmountError, AssetIdMismatch, - ThresholdTooDeep) -from planetmint.transactions.common.utils import serialize -from .memoize import memoize_from_dict, memoize_to_dict +from planetmint.transactions.common.exceptions import AmountError from .utils import _fulfillment_to_details, _fulfillment_from_details class Output(object): @@ -221,4 +205,4 @@ class Output(object): amount = int(data['amount']) except ValueError: raise AmountError('Invalid amount: %s' % data['amount']) - return cls(fulfillment, data['public_keys'], amount) \ No newline at end of file + return cls(fulfillment, data['public_keys'], amount) diff --git a/planetmint/transactions/common/transaction.py b/planetmint/transactions/common/transaction.py index 04245c4..7058b86 100644 --- a/planetmint/transactions/common/transaction.py +++ b/planetmint/transactions/common/transaction.py @@ -13,13 +13,13 @@ Attributes: """ from collections import namedtuple from copy import deepcopy -from functools import reduce, lru_cache +from functools import lru_cache import rapidjson import base58 from cryptoconditions import Fulfillment, ThresholdSha256, Ed25519Sha256 from cryptoconditions.exceptions import ( - ParsingError, ASN1DecodeError, ASN1EncodeError, UnsupportedTypeError) + ParsingError, ASN1DecodeError, ASN1EncodeError) try: from hashlib import sha3_256 except ImportError: @@ -29,11 +29,10 @@ from planetmint.transactions.common.crypto import PrivateKey, hash_data from planetmint.transactions.common.exceptions import (KeypairMismatchException, InputDoesNotExist, DoubleSpend, InvalidHash, InvalidSignature, - AmountError, AssetIdMismatch, - ThresholdTooDeep) + AmountError, AssetIdMismatch) from planetmint.transactions.common.utils import serialize from .memoize import memoize_from_dict, memoize_to_dict -from .input import Input +from .input import Input from .output import Output from .transaction_link import TransactionLink diff --git a/planetmint/transactions/common/transaction_link.py b/planetmint/transactions/common/transaction_link.py index 8f36144..fcdbeb1 100644 --- a/planetmint/transactions/common/transaction_link.py +++ b/planetmint/transactions/common/transaction_link.py @@ -3,29 +3,6 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -from collections import namedtuple -from copy import deepcopy -from functools import reduce, lru_cache -import rapidjson - -import base58 -from cryptoconditions import Fulfillment, ThresholdSha256, Ed25519Sha256 -from cryptoconditions.exceptions import ( - ParsingError, ASN1DecodeError, ASN1EncodeError, UnsupportedTypeError) -try: - from hashlib import sha3_256 -except ImportError: - from sha3 import sha3_256 - -from planetmint.transactions.common.crypto import PrivateKey, hash_data -from planetmint.transactions.common.exceptions import (KeypairMismatchException, - InputDoesNotExist, DoubleSpend, - InvalidHash, InvalidSignature, - AmountError, AssetIdMismatch, - ThresholdTooDeep) -from planetmint.transactions.common.utils import serialize -from .memoize import memoize_from_dict, memoize_to_dict - class TransactionLink(object): """An object for unidirectional linking to a Transaction's Output. @@ -96,4 +73,4 @@ class TransactionLink(object): if self.txid is None and self.output is None: return None return '{}/transactions/{}/outputs/{}'.format(path, self.txid, - self.output) \ No newline at end of file + self.output) diff --git a/planetmint/transactions/common/utils.py b/planetmint/transactions/common/utils.py index f734551..1033c72 100644 --- a/planetmint/transactions/common/utils.py +++ b/planetmint/transactions/common/utils.py @@ -10,14 +10,9 @@ import rapidjson import planetmint from planetmint.transactions.common.exceptions import ValidationError -from cryptoconditions import Fulfillment, ThresholdSha256, Ed25519Sha256 -from planetmint.transactions.common.exceptions import (KeypairMismatchException, - InputDoesNotExist, DoubleSpend, - InvalidHash, InvalidSignature, - AmountError, AssetIdMismatch, - ThresholdTooDeep) -from cryptoconditions.exceptions import ( - ParsingError, ASN1DecodeError, ASN1EncodeError, UnsupportedTypeError) +from cryptoconditions import ThresholdSha256, Ed25519Sha256 +from planetmint.transactions.common.exceptions import ThresholdTooDeep +from cryptoconditions.exceptions import UnsupportedTypeError def gen_timestamp(): @@ -220,4 +215,5 @@ def _fulfillment_from_details(data, _depth=0): threshold.add_subfulfillment(cond) return threshold - raise UnsupportedTypeError(data.get('type')) \ No newline at end of file + raise UnsupportedTypeError(data.get('type')) + \ No newline at end of file diff --git a/planetmint/transactions/types/assets/transfer.py b/planetmint/transactions/types/assets/transfer.py index 444634f..9fb709b 100644 --- a/planetmint/transactions/types/assets/transfer.py +++ b/planetmint/transactions/types/assets/transfer.py @@ -4,7 +4,6 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 from planetmint.transactions.common.transaction import Transaction -from planetmint.transactions.common.input import Input from planetmint.transactions.common.output import Output from copy import deepcopy diff --git a/planetmint/transactions/types/elections/election.py b/planetmint/transactions/types/elections/election.py index 736212a..594de15 100644 --- a/planetmint/transactions/types/elections/election.py +++ b/planetmint/transactions/types/elections/election.py @@ -11,17 +11,14 @@ from planetmint import backend from planetmint.transactions.types.assets.create import Create from planetmint.transactions.types.assets.transfer import Transfer from planetmint.transactions.types.elections.vote import Vote -from planetmint.transactions.common.exceptions import (InvalidSignature, - MultipleInputsError, - InvalidProposer, - UnequalValidatorSet, - DuplicateTransaction) +from planetmint.transactions.common.exceptions import ( + InvalidSignature, MultipleInputsError, InvalidProposer, + UnequalValidatorSet, DuplicateTransaction) from planetmint.tendermint_utils import key_from_base64, public_key_to_base64 from planetmint.transactions.common.crypto import (public_key_from_ed25519_key) from planetmint.transactions.common.transaction import Transaction -from planetmint.transactions.common.schema import (_validate_schema, - TX_SCHEMA_COMMON, - TX_SCHEMA_CREATE) +from planetmint.transactions.common.schema import ( + _validate_schema, TX_SCHEMA_COMMON, TX_SCHEMA_CREATE) class Election(Transaction): diff --git a/planetmint/transactions/types/elections/vote.py b/planetmint/transactions/types/elections/vote.py index 16d7dcd..a4b25f3 100644 --- a/planetmint/transactions/types/elections/vote.py +++ b/planetmint/transactions/types/elections/vote.py @@ -6,10 +6,8 @@ from planetmint.transactions.types.assets.create import Create from planetmint.transactions.types.assets.transfer import Transfer from planetmint.transactions.common.transaction import Transaction -from planetmint.transactions.common.schema import (_validate_schema, - TX_SCHEMA_COMMON, - TX_SCHEMA_TRANSFER, - TX_SCHEMA_VOTE) +from planetmint.transactions.common.schema import ( + _validate_schema, TX_SCHEMA_COMMON, TX_SCHEMA_TRANSFER, TX_SCHEMA_VOTE) class Vote(Transaction): diff --git a/planetmint/web/views/parameters.py b/planetmint/web/views/parameters.py index 8f295e4..6df22ff 100644 --- a/planetmint/web/views/parameters.py +++ b/planetmint/web/views/parameters.py @@ -5,10 +5,8 @@ import re -from planetmint.transactions.common.transaction_mode_types import (BROADCAST_TX_COMMIT, - BROADCAST_TX_ASYNC, - BROADCAST_TX_SYNC) - +from planetmint.transactions.common.transaction_mode_types import ( + BROADCAST_TX_COMMIT, BROADCAST_TX_ASYNC, BROADCAST_TX_SYNC) def valid_txid(txid): if re.match('^[a-fA-F0-9]{64}$', txid): diff --git a/tests/common/conftest.py b/tests/common/conftest.py index 6a75eff..eea23ee 100644 --- a/tests/common/conftest.py +++ b/tests/common/conftest.py @@ -152,8 +152,8 @@ def tx(utx, user_priv): @pytest.fixture def transfer_utx(user_output, user2_output, utx): - from planetmint.transactions.common.transaction import (Input, TransactionLink, - Transaction) + from planetmint.transactions.common.transaction import ( + Input, TransactionLink, Transaction) user_output = user_output.to_dict() input = Input(utx.outputs[0].fulfillment, user_output['public_keys'], diff --git a/tests/common/test_transaction.py b/tests/common/test_transaction.py index 2a7c811..84ddb2b 100644 --- a/tests/common/test_transaction.py +++ b/tests/common/test_transaction.py @@ -621,8 +621,8 @@ def test_multiple_input_validation_of_transfer_tx(user_input, user_output, user2_priv, user3_pub, user3_priv, asset_definition): - from planetmint.transactions.common.transaction import (Transaction, TransactionLink, - Input, Output) + from planetmint.transactions.common.transaction import ( + Transaction, TransactionLink, Input, Output) from cryptoconditions import Ed25519Sha256 from .utils import validate_transaction_model diff --git a/tests/conftest.py b/tests/conftest.py index 780abbb..f553538 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -27,8 +27,8 @@ from planetmint.transactions.common import crypto from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT from planetmint.tendermint_utils import key_from_base64 from planetmint.backend import schema, query -from planetmint.transactions.common.crypto import (key_pair_from_ed25519_key, - public_key_from_ed25519_key) +from planetmint.transactions.common.crypto import ( + key_pair_from_ed25519_key, public_key_from_ed25519_key) from planetmint.transactions.common.exceptions import DatabaseDoesNotExist from planetmint.lib import Block from tests.utils import gen_vote diff --git a/tests/tendermint/test_lib.py b/tests/tendermint/test_lib.py index 3f92554..55fd2be 100644 --- a/tests/tendermint/test_lib.py +++ b/tests/tendermint/test_lib.py @@ -17,9 +17,8 @@ import pytest from pymongo import MongoClient from planetmint import backend -from planetmint.transactions.common.transaction_mode_types import (BROADCAST_TX_COMMIT, - BROADCAST_TX_ASYNC, - BROADCAST_TX_SYNC) +from planetmint.transactions.common.transaction_mode_types import ( + BROADCAST_TX_COMMIT, BROADCAST_TX_ASYNC, BROADCAST_TX_SYNC) from planetmint.lib import Block diff --git a/tests/upsert_validator/test_validator_election.py b/tests/upsert_validator/test_validator_election.py index db6f50f..77aaf1c 100644 --- a/tests/upsert_validator/test_validator_election.py +++ b/tests/upsert_validator/test_validator_election.py @@ -9,11 +9,9 @@ import pytest from planetmint.tendermint_utils import public_key_to_base64 from planetmint.upsert_validator import ValidatorElection -from planetmint.transactions.common.exceptions import (DuplicateTransaction, - UnequalValidatorSet, - InvalidProposer, - MultipleInputsError, - InvalidPowerChange) +from planetmint.transactions.common.exceptions import ( + DuplicateTransaction, UnequalValidatorSet, InvalidProposer, + MultipleInputsError, InvalidPowerChange) pytestmark = pytest.mark.bdb diff --git a/tests/validation/test_transaction_structure.py b/tests/validation/test_transaction_structure.py index 8cf33da..5fcb425 100644 --- a/tests/validation/test_transaction_structure.py +++ b/tests/validation/test_transaction_structure.py @@ -16,9 +16,8 @@ except ImportError: import sha3 from unittest.mock import MagicMock -from planetmint.transactions.common.exceptions import (AmountError, - SchemaValidationError, - ThresholdTooDeep) +from planetmint.transactions.common.exceptions import ( + AmountError, SchemaValidationError, ThresholdTooDeep) from planetmint.models import Transaction from planetmint.transactions.common.utils import _fulfillment_to_details, _fulfillment_from_details @@ -214,8 +213,6 @@ def test_high_amounts(b, create_tx, alice): # Conditions def test_handle_threshold_overflow(): - from planetmint.transactions.common import transaction - cond = { 'type': 'ed25519-sha-256', 'public_key': 'a' * 43, @@ -231,7 +228,6 @@ def test_handle_threshold_overflow(): def test_unsupported_condition_type(): - from planetmint.transactions.common import transaction from cryptoconditions.exceptions import UnsupportedTypeError with pytest.raises(UnsupportedTypeError): diff --git a/tests/web/test_transactions.py b/tests/web/test_transactions.py index 03bb334..11846e4 100644 --- a/tests/web/test_transactions.py +++ b/tests/web/test_transactions.py @@ -15,9 +15,8 @@ except ImportError: from sha3 import sha3_256 from planetmint.transactions.common import crypto -from planetmint.transactions.common.transaction_mode_types import (BROADCAST_TX_COMMIT, - BROADCAST_TX_ASYNC, - BROADCAST_TX_SYNC) +from planetmint.transactions.common.transaction_mode_types import ( + BROADCAST_TX_COMMIT, BROADCAST_TX_ASYNC, BROADCAST_TX_SYNC) TX_ENDPOINT = '/api/v1/transactions/' From 9b3bfc991119b3b31410f1a94b0f4fd569dea72a Mon Sep 17 00:00:00 2001 From: Sangat Das Date: Mon, 14 Mar 2022 08:08:54 +0000 Subject: [PATCH 61/93] Resolve remaining flake8 issues Signed-off-by: Sangat Das --- planetmint/transactions/common/transaction.py | 7 +++---- planetmint/transactions/types/elections/election.py | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/planetmint/transactions/common/transaction.py b/planetmint/transactions/common/transaction.py index 7058b86..e89aa6b 100644 --- a/planetmint/transactions/common/transaction.py +++ b/planetmint/transactions/common/transaction.py @@ -26,10 +26,9 @@ except ImportError: from sha3 import sha3_256 from planetmint.transactions.common.crypto import PrivateKey, hash_data -from planetmint.transactions.common.exceptions import (KeypairMismatchException, - InputDoesNotExist, DoubleSpend, - InvalidHash, InvalidSignature, - AmountError, AssetIdMismatch) +from planetmint.transactions.common.exceptions import ( + KeypairMismatchException, InputDoesNotExist, DoubleSpend, + InvalidHash, InvalidSignature, AmountError, AssetIdMismatch) from planetmint.transactions.common.utils import serialize from .memoize import memoize_from_dict, memoize_to_dict from .input import Input diff --git a/planetmint/transactions/types/elections/election.py b/planetmint/transactions/types/elections/election.py index 594de15..d74fcbd 100644 --- a/planetmint/transactions/types/elections/election.py +++ b/planetmint/transactions/types/elections/election.py @@ -12,7 +12,7 @@ from planetmint.transactions.types.assets.create import Create from planetmint.transactions.types.assets.transfer import Transfer from planetmint.transactions.types.elections.vote import Vote from planetmint.transactions.common.exceptions import ( - InvalidSignature, MultipleInputsError, InvalidProposer, + InvalidSignature, MultipleInputsError, InvalidProposer, UnequalValidatorSet, DuplicateTransaction) from planetmint.tendermint_utils import key_from_base64, public_key_to_base64 from planetmint.transactions.common.crypto import (public_key_from_ed25519_key) From c3284fe060f329fb4344a22183dc01a41b132a7a Mon Sep 17 00:00:00 2001 From: Sangat Das Date: Mon, 14 Mar 2022 09:13:58 +0000 Subject: [PATCH 62/93] Resolve remaining flake8 issues Signed-off-by: Sangat Das --- planetmint/lib.py | 3 ++- planetmint/transactions/common/utils.py | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/planetmint/lib.py b/planetmint/lib.py index 4451d65..bac5cc9 100644 --- a/planetmint/lib.py +++ b/planetmint/lib.py @@ -26,7 +26,8 @@ from planetmint import backend, config_utils, fastquery from planetmint.models import Transaction from planetmint.transactions.common.exceptions import ( SchemaValidationError, ValidationError, DoubleSpend) -from planetmint.transactions.common.transaction_mode_types import (BROADCAST_TX_COMMIT, BROADCAST_TX_ASYNC, BROADCAST_TX_SYNC) +from planetmint.transactions.common.transaction_mode_types import ( + BROADCAST_TX_COMMIT, BROADCAST_TX_ASYNC, BROADCAST_TX_SYNC) from planetmint.tendermint_utils import encode_transaction, merkleroot from planetmint import exceptions as core_exceptions from planetmint.validation import BaseValidationRules diff --git a/planetmint/transactions/common/utils.py b/planetmint/transactions/common/utils.py index 1033c72..e18580d 100644 --- a/planetmint/transactions/common/utils.py +++ b/planetmint/transactions/common/utils.py @@ -216,4 +216,3 @@ def _fulfillment_from_details(data, _depth=0): return threshold raise UnsupportedTypeError(data.get('type')) - \ No newline at end of file From 4d3eb6bfdb55baae647063cf6db183fd37618edf Mon Sep 17 00:00:00 2001 From: RoninX Date: Tue, 15 Mar 2022 07:21:16 +0100 Subject: [PATCH 63/93] Problem: Monolithic code files (#60) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Integrate zenroom acceptance test * fixed zenroom reference * added additional dependences to the docker fils so that zenroom can be executed. added zenroom from git repo, because pypi servs an older buggy version * using the custom planetmintdriver branch to avoid pypi zendesk downloads * Added zenroom test * Added zenroom test Signed-off-by: Sangat Das * Change reference to planetmint-driver to planetmint-driver-python Signed-off-by: Sangat Das * Basic structuring * Added new classes in transactions/common * Added Create and Transfer as separate transactions * Resolved errors related to transactions.common * Fixing imports * Resolved issues of election transaction * Resolve flake8 issues Signed-off-by: Sangat Das * Resolve remaining flake8 issues Signed-off-by: Sangat Das * Resolve remaining flake8 issues Signed-off-by: Sangat Das Co-authored-by: Jürgen Eckel Co-authored-by: ArpitShukla007 --- .../generate_http_server_api_documentation.py | 2 +- planetmint/__init__.py | 4 +- planetmint/backend/connection.py | 2 +- planetmint/backend/localmongodb/connection.py | 2 +- planetmint/backend/localmongodb/query.py | 2 +- planetmint/backend/schema.py | 5 +- planetmint/commands/planetmint.py | 8 +- planetmint/config_utils.py | 2 +- planetmint/core.py | 2 +- planetmint/fastquery.py | 2 +- planetmint/lib.py | 20 +- planetmint/log.py | 2 +- .../migrations/chain_migration_election.py | 4 +- planetmint/models.py | 9 +- .../{ => transactions}/common/__init__.py | 0 .../{ => transactions}/common/crypto.py | 6 +- .../{ => transactions}/common/exceptions.py | 0 planetmint/transactions/common/input.py | 125 +++++ .../{ => transactions}/common/memoize.py | 0 planetmint/transactions/common/output.py | 208 ++++++++ .../common/schema/README.md | 0 .../common/schema/__init__.py | 2 +- ...saction_chain_migration_election_v2.0.yaml | 0 .../schema/transaction_create_v1.0.yaml | 0 .../schema/transaction_create_v2.0.yaml | 0 .../schema/transaction_transfer_v1.0.yaml | 0 .../schema/transaction_transfer_v2.0.yaml | 0 .../common/schema/transaction_v1.0.yaml | 0 .../common/schema/transaction_v2.0.yaml | 0 .../transaction_validator_election_v2.0.yaml | 0 .../common/schema/transaction_vote_v2.0.yaml | 0 .../{ => transactions}/common/transaction.py | 491 +----------------- .../transactions/common/transaction_link.py | 76 +++ .../common/transaction_mode_types.py | 0 planetmint/{ => transactions}/common/utils.py | 55 +- .../types/assets}/__init__.py | 0 .../transactions/types/assets/create.py | 77 +++ .../transactions/types/assets/transfer.py | 80 +++ .../transactions/types/elections/__init__.py | 0 .../types}/elections/election.py | 25 +- .../types}/elections/vote.py | 14 +- .../upsert_validator/validator_election.py | 6 +- .../upsert_validator/validator_utils.py | 2 +- planetmint/utils.py | 2 +- planetmint/web/views/parameters.py | 6 +- planetmint/web/views/transactions.py | 4 +- setup.py | 2 +- tests/assets/test_digital_assets.py | 4 +- tests/assets/test_divisible_assets.py | 14 +- tests/backend/localmongodb/test_queries.py | 2 +- tests/backend/test_connection.py | 2 +- tests/commands/conftest.py | 2 +- tests/commands/test_commands.py | 6 +- tests/common/conftest.py | 16 +- tests/common/test_memoize.py | 4 +- tests/common/test_schema.py | 4 +- tests/common/test_transaction.py | 126 ++--- tests/common/utils.py | 4 +- tests/conftest.py | 20 +- tests/db/test_bigchain_api.py | 52 +- tests/elections/test_election.py | 2 +- tests/tendermint/test_core.py | 14 +- tests/tendermint/test_fastquery.py | 2 +- tests/tendermint/test_integration.py | 6 +- tests/tendermint/test_lib.py | 25 +- tests/test_config_utils.py | 2 +- tests/test_core.py | 14 +- tests/test_parallel_validation.py | 2 +- tests/upsert_validator/conftest.py | 2 +- .../test_upsert_validator_vote.py | 12 +- .../test_validator_election.py | 16 +- tests/utils.py | 8 +- .../validation/test_transaction_structure.py | 27 +- tests/web/test_outputs.py | 2 +- tests/web/test_transactions.py | 21 +- tests/web/test_websocket_server.py | 6 +- 76 files changed, 917 insertions(+), 747 deletions(-) rename planetmint/{ => transactions}/common/__init__.py (100%) rename planetmint/{ => transactions}/common/crypto.py (88%) rename planetmint/{ => transactions}/common/exceptions.py (100%) create mode 100644 planetmint/transactions/common/input.py rename planetmint/{ => transactions}/common/memoize.py (100%) create mode 100644 planetmint/transactions/common/output.py rename planetmint/{ => transactions}/common/schema/README.md (100%) rename planetmint/{ => transactions}/common/schema/__init__.py (97%) rename planetmint/{ => transactions}/common/schema/transaction_chain_migration_election_v2.0.yaml (100%) rename planetmint/{ => transactions}/common/schema/transaction_create_v1.0.yaml (100%) rename planetmint/{ => transactions}/common/schema/transaction_create_v2.0.yaml (100%) rename planetmint/{ => transactions}/common/schema/transaction_transfer_v1.0.yaml (100%) rename planetmint/{ => transactions}/common/schema/transaction_transfer_v2.0.yaml (100%) rename planetmint/{ => transactions}/common/schema/transaction_v1.0.yaml (100%) rename planetmint/{ => transactions}/common/schema/transaction_v2.0.yaml (100%) rename planetmint/{ => transactions}/common/schema/transaction_validator_election_v2.0.yaml (100%) rename planetmint/{ => transactions}/common/schema/transaction_vote_v2.0.yaml (100%) rename planetmint/{ => transactions}/common/transaction.py (65%) create mode 100644 planetmint/transactions/common/transaction_link.py rename planetmint/{ => transactions}/common/transaction_mode_types.py (100%) rename planetmint/{ => transactions}/common/utils.py (75%) rename planetmint/{elections => transactions/types/assets}/__init__.py (100%) create mode 100644 planetmint/transactions/types/assets/create.py create mode 100644 planetmint/transactions/types/assets/transfer.py create mode 100644 planetmint/transactions/types/elections/__init__.py rename planetmint/{ => transactions/types}/elections/election.py (94%) rename planetmint/{ => transactions/types}/elections/vote.py (81%) diff --git a/docs/root/generate_http_server_api_documentation.py b/docs/root/generate_http_server_api_documentation.py index b43e163..4b84d57 100644 --- a/docs/root/generate_http_server_api_documentation.py +++ b/docs/root/generate_http_server_api_documentation.py @@ -9,7 +9,7 @@ import json import os import os.path -from planetmint.common.transaction import Transaction, Input, TransactionLink +from planetmint.transactions.common.transaction import Transaction, Input, TransactionLink from planetmint import lib from planetmint.web import server diff --git a/planetmint/__init__.py b/planetmint/__init__.py index 7c3b977..785daef 100644 --- a/planetmint/__init__.py +++ b/planetmint/__init__.py @@ -94,10 +94,10 @@ config = { # the user wants to reconfigure the node. Check ``planetmint.config_utils`` # for more info. _config = copy.deepcopy(config) -from planetmint.common.transaction import Transaction # noqa +from planetmint.transactions.common.transaction import Transaction # noqa from planetmint import models # noqa from planetmint.upsert_validator import ValidatorElection # noqa -from planetmint.elections.vote import Vote # noqa +from planetmint.transactions.types.elections.vote import Vote # noqa Transaction.register_type(Transaction.CREATE, models.Transaction) Transaction.register_type(Transaction.TRANSFER, models.Transaction) diff --git a/planetmint/backend/connection.py b/planetmint/backend/connection.py index d92204b..34708ce 100644 --- a/planetmint/backend/connection.py +++ b/planetmint/backend/connection.py @@ -10,7 +10,7 @@ from itertools import repeat import planetmint from planetmint.backend.exceptions import ConnectionError from planetmint.backend.utils import get_planetmint_config_value, get_planetmint_config_value_or_key_error -from planetmint.common.exceptions import ConfigurationError +from planetmint.transactions.common.exceptions import ConfigurationError BACKENDS = { 'localmongodb': 'planetmint.backend.localmongodb.connection.LocalMongoDBConnection', diff --git a/planetmint/backend/localmongodb/connection.py b/planetmint/backend/localmongodb/connection.py index 945a2ff..8ad3226 100644 --- a/planetmint/backend/localmongodb/connection.py +++ b/planetmint/backend/localmongodb/connection.py @@ -13,7 +13,7 @@ from planetmint.backend.exceptions import (DuplicateKeyError, OperationError, ConnectionError) from planetmint.backend.utils import get_planetmint_config_value -from planetmint.common.exceptions import ConfigurationError +from planetmint.transactions.common.exceptions import ConfigurationError from planetmint.utils import Lazy logger = logging.getLogger(__name__) diff --git a/planetmint/backend/localmongodb/query.py b/planetmint/backend/localmongodb/query.py index db98230..69f7bb2 100644 --- a/planetmint/backend/localmongodb/query.py +++ b/planetmint/backend/localmongodb/query.py @@ -11,7 +11,7 @@ from planetmint import backend from planetmint.backend.exceptions import DuplicateKeyError from planetmint.backend.utils import module_dispatch_registrar from planetmint.backend.localmongodb.connection import LocalMongoDBConnection -from planetmint.common.transaction import Transaction +from planetmint.transactions.common.transaction import Transaction register_query = module_dispatch_registrar(backend.query) diff --git a/planetmint/backend/schema.py b/planetmint/backend/schema.py index cb7bbcf..b19315b 100644 --- a/planetmint/backend/schema.py +++ b/planetmint/backend/schema.py @@ -10,8 +10,9 @@ import logging import planetmint from planetmint.backend.connection import connect -from planetmint.common.exceptions import ValidationError -from planetmint.common.utils import validate_all_values_for_key_in_obj, validate_all_values_for_key_in_list +from planetmint.transactions.common.exceptions import ValidationError +from planetmint.transactions.common.utils import ( + validate_all_values_for_key_in_obj, validate_all_values_for_key_in_list) logger = logging.getLogger(__name__) diff --git a/planetmint/commands/planetmint.py b/planetmint/commands/planetmint.py index 5e534a7..9d09571 100644 --- a/planetmint/commands/planetmint.py +++ b/planetmint/commands/planetmint.py @@ -17,10 +17,10 @@ import sys from planetmint.core import rollback from planetmint.migrations.chain_migration_election import ChainMigrationElection from planetmint.utils import load_node_key -from planetmint.common.transaction_mode_types import BROADCAST_TX_COMMIT -from planetmint.common.exceptions import (DatabaseDoesNotExist, - ValidationError) -from planetmint.elections.vote import Vote +from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT +from planetmint.transactions.common.exceptions import ( + DatabaseDoesNotExist, ValidationError) +from planetmint.transactions.types.elections.vote import Vote import planetmint from planetmint import (backend, ValidatorElection, Planetmint) diff --git a/planetmint/config_utils.py b/planetmint/config_utils.py index 1401df7..fa5d94d 100644 --- a/planetmint/config_utils.py +++ b/planetmint/config_utils.py @@ -25,7 +25,7 @@ from functools import lru_cache from pkg_resources import iter_entry_points, ResolutionError -from planetmint.common import exceptions +from planetmint.transactions.common import exceptions import planetmint diff --git a/planetmint/core.py b/planetmint/core.py index 143bd55..43c13f4 100644 --- a/planetmint/core.py +++ b/planetmint/core.py @@ -21,7 +21,7 @@ from tendermint.abci.types_pb2 import ( ResponseCommit ) from planetmint import Planetmint -from planetmint.elections.election import Election +from planetmint.transactions.types.elections.election import Election from planetmint.tendermint_utils import (decode_transaction, calculate_hash) from planetmint.lib import Block diff --git a/planetmint/fastquery.py b/planetmint/fastquery.py index c1aa843..bfbb6a8 100644 --- a/planetmint/fastquery.py +++ b/planetmint/fastquery.py @@ -5,7 +5,7 @@ from planetmint.utils import condition_details_has_owner from planetmint.backend import query -from planetmint.common.transaction import TransactionLink +from planetmint.transactions.common.transaction import TransactionLink class FastQuery(): diff --git a/planetmint/lib.py b/planetmint/lib.py index 4c59b26..bac5cc9 100644 --- a/planetmint/lib.py +++ b/planetmint/lib.py @@ -24,31 +24,27 @@ import requests import planetmint from planetmint import backend, config_utils, fastquery from planetmint.models import Transaction -from planetmint.common.exceptions import (SchemaValidationError, - ValidationError, - DoubleSpend) -from planetmint.common.transaction_mode_types import (BROADCAST_TX_COMMIT, - BROADCAST_TX_ASYNC, - BROADCAST_TX_SYNC) +from planetmint.transactions.common.exceptions import ( + SchemaValidationError, ValidationError, DoubleSpend) +from planetmint.transactions.common.transaction_mode_types import ( + BROADCAST_TX_COMMIT, BROADCAST_TX_ASYNC, BROADCAST_TX_SYNC) from planetmint.tendermint_utils import encode_transaction, merkleroot from planetmint import exceptions as core_exceptions from planetmint.validation import BaseValidationRules - logger = logging.getLogger(__name__) - class Planetmint(object): - """Bigchain API + """Planetmint API Create, read, sign, write transactions to the database """ def __init__(self, connection=None): - """Initialize the Bigchain instance + """Initialize the Planetmint instance - A Bigchain instance has several configuration parameters (e.g. host). - If a parameter value is passed as an argument to the Bigchain + A Planetmint instance has several configuration parameters (e.g. host). + If a parameter value is passed as an argument to the Planetmint __init__ method, then that is the value it will have. Otherwise, the parameter value will come from an environment variable. If that environment variable isn't set, then the value diff --git a/planetmint/log.py b/planetmint/log.py index d987fc6..091fe8e 100644 --- a/planetmint/log.py +++ b/planetmint/log.py @@ -6,7 +6,7 @@ import planetmint import logging -from planetmint.common.exceptions import ConfigurationError +from planetmint.transactions.common.exceptions import ConfigurationError from logging.config import dictConfig as set_logging_config import os diff --git a/planetmint/migrations/chain_migration_election.py b/planetmint/migrations/chain_migration_election.py index d913e84..5e23e40 100644 --- a/planetmint/migrations/chain_migration_election.py +++ b/planetmint/migrations/chain_migration_election.py @@ -1,7 +1,7 @@ import json -from planetmint.common.schema import TX_SCHEMA_CHAIN_MIGRATION_ELECTION -from planetmint.elections.election import Election +from planetmint.transactions.common.schema import TX_SCHEMA_CHAIN_MIGRATION_ELECTION +from planetmint.transactions.types.elections.election import Election class ChainMigrationElection(Election): diff --git a/planetmint/models.py b/planetmint/models.py index 001df55..419cb44 100644 --- a/planetmint/models.py +++ b/planetmint/models.py @@ -4,11 +4,10 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 from planetmint.backend.schema import validate_language_key -from planetmint.common.exceptions import (InvalidSignature, - DuplicateTransaction) -from planetmint.common.schema import validate_transaction_schema -from planetmint.common.transaction import Transaction -from planetmint.common.utils import (validate_txn_obj, validate_key) +from planetmint.transactions.common.exceptions import (InvalidSignature, DuplicateTransaction) +from planetmint.transactions.common.schema import validate_transaction_schema +from planetmint.transactions.common.transaction import Transaction +from planetmint.transactions.common.utils import (validate_txn_obj, validate_key) class Transaction(Transaction): diff --git a/planetmint/common/__init__.py b/planetmint/transactions/common/__init__.py similarity index 100% rename from planetmint/common/__init__.py rename to planetmint/transactions/common/__init__.py diff --git a/planetmint/common/crypto.py b/planetmint/transactions/common/crypto.py similarity index 88% rename from planetmint/common/crypto.py rename to planetmint/transactions/common/crypto.py index 72ea536..9205c27 100644 --- a/planetmint/common/crypto.py +++ b/planetmint/transactions/common/crypto.py @@ -26,10 +26,10 @@ def generate_key_pair(): """Generates a cryptographic key pair. Returns: - :class:`~planetmint.common.crypto.CryptoKeypair`: A + :class:`~planetmint.transactions.common.crypto.CryptoKeypair`: A :obj:`collections.namedtuple` with named fields - :attr:`~planetmint.common.crypto.CryptoKeypair.private_key` and - :attr:`~planetmint.common.crypto.CryptoKeypair.public_key`. + :attr:`~planetmint.transactions.common.crypto.CryptoKeypair.private_key` and + :attr:`~planetmint.transactions.common.crypto.CryptoKeypair.public_key`. """ # TODO FOR CC: Adjust interface so that this function becomes unnecessary diff --git a/planetmint/common/exceptions.py b/planetmint/transactions/common/exceptions.py similarity index 100% rename from planetmint/common/exceptions.py rename to planetmint/transactions/common/exceptions.py diff --git a/planetmint/transactions/common/input.py b/planetmint/transactions/common/input.py new file mode 100644 index 0000000..ab123cb --- /dev/null +++ b/planetmint/transactions/common/input.py @@ -0,0 +1,125 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +from cryptoconditions import Fulfillment +from cryptoconditions.exceptions import ASN1DecodeError, ASN1EncodeError + +from planetmint.transactions.common.exceptions import InvalidSignature +from .utils import _fulfillment_to_details, _fulfillment_from_details +from .output import Output +from .transaction_link import TransactionLink + +class Input(object): + """A Input is used to spend assets locked by an Output. + + Wraps around a Crypto-condition Fulfillment. + + Attributes: + fulfillment (:class:`cryptoconditions.Fulfillment`): A Fulfillment + to be signed with a private key. + owners_before (:obj:`list` of :obj:`str`): A list of owners after a + Transaction was confirmed. + fulfills (:class:`~planetmint.transactions.common.transaction. TransactionLink`, + optional): A link representing the input of a `TRANSFER` + Transaction. + """ + + def __init__(self, fulfillment, owners_before, fulfills=None): + """Create an instance of an :class:`~.Input`. + + Args: + fulfillment (:class:`cryptoconditions.Fulfillment`): A + Fulfillment to be signed with a private key. + owners_before (:obj:`list` of :obj:`str`): A list of owners + after a Transaction was confirmed. + fulfills (:class:`~planetmint.transactions.common.transaction. + TransactionLink`, optional): A link representing the input + of a `TRANSFER` Transaction. + """ + if fulfills is not None and not isinstance(fulfills, TransactionLink): + raise TypeError('`fulfills` must be a TransactionLink instance') + if not isinstance(owners_before, list): + raise TypeError('`owners_before` must be a list instance') + + self.fulfillment = fulfillment + self.fulfills = fulfills + self.owners_before = owners_before + + def __eq__(self, other): + # TODO: If `other !== Fulfillment` return `False` + return self.to_dict() == other.to_dict() + + # NOTE: This function is used to provide a unique key for a given + # Input to suppliment memoization + def __hash__(self): + return hash((self.fulfillment, self.fulfills)) + + def to_dict(self): + """Transforms the object to a Python dictionary. + + Note: + If an Input hasn't been signed yet, this method returns a + dictionary representation. + + Returns: + dict: The Input as an alternative serialization format. + """ + try: + fulfillment = self.fulfillment.serialize_uri() + except (TypeError, AttributeError, ASN1EncodeError, ASN1DecodeError): + fulfillment = _fulfillment_to_details(self.fulfillment) + + try: + # NOTE: `self.fulfills` can be `None` and that's fine + fulfills = self.fulfills.to_dict() + except AttributeError: + fulfills = None + + input_ = { + 'owners_before': self.owners_before, + 'fulfills': fulfills, + 'fulfillment': fulfillment, + } + return input_ + + @classmethod + def generate(cls, public_keys): + # TODO: write docstring + # The amount here does not really matter. It is only use on the + # output data model but here we only care about the fulfillment + output = Output.generate(public_keys, 1) + return cls(output.fulfillment, public_keys) + + @classmethod + def from_dict(cls, data): + """Transforms a Python dictionary to an Input object. + + Note: + Optionally, this method can also serialize a Cryptoconditions- + Fulfillment that is not yet signed. + + Args: + data (dict): The Input to be transformed. + + Returns: + :class:`~planetmint.transactions.common.transaction.Input` + + Raises: + InvalidSignature: If an Input's URI couldn't be parsed. + """ + fulfillment = data['fulfillment'] + if not isinstance(fulfillment, (Fulfillment, type(None))): + try: + fulfillment = Fulfillment.from_uri(data['fulfillment']) + except ASN1DecodeError: + # TODO Remove as it is legacy code, and simply fall back on + # ASN1DecodeError + raise InvalidSignature("Fulfillment URI couldn't been parsed") + except TypeError: + # NOTE: See comment about this special case in + # `Input.to_dict` + fulfillment = _fulfillment_from_details(data['fulfillment']) + fulfills = TransactionLink.from_dict(data['fulfills']) + return cls(fulfillment, data['owners_before'], fulfills) diff --git a/planetmint/common/memoize.py b/planetmint/transactions/common/memoize.py similarity index 100% rename from planetmint/common/memoize.py rename to planetmint/transactions/common/memoize.py diff --git a/planetmint/transactions/common/output.py b/planetmint/transactions/common/output.py new file mode 100644 index 0000000..6462941 --- /dev/null +++ b/planetmint/transactions/common/output.py @@ -0,0 +1,208 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +from functools import reduce + +import base58 +from cryptoconditions import Fulfillment, ThresholdSha256, Ed25519Sha256 + +from planetmint.transactions.common.exceptions import AmountError +from .utils import _fulfillment_to_details, _fulfillment_from_details + +class Output(object): + """An Output is used to lock an asset. + + Wraps around a Crypto-condition Condition. + + Attributes: + fulfillment (:class:`cryptoconditions.Fulfillment`): A Fulfillment + to extract a Condition from. + public_keys (:obj:`list` of :obj:`str`, optional): A list of + owners before a Transaction was confirmed. + """ + + MAX_AMOUNT = 9 * 10 ** 18 + + def __init__(self, fulfillment, public_keys=None, amount=1): + """Create an instance of a :class:`~.Output`. + + Args: + fulfillment (:class:`cryptoconditions.Fulfillment`): A + Fulfillment to extract a Condition from. + public_keys (:obj:`list` of :obj:`str`, optional): A list of + owners before a Transaction was confirmed. + amount (int): The amount of Assets to be locked with this + Output. + + Raises: + TypeError: if `public_keys` is not instance of `list`. + """ + if not isinstance(public_keys, list) and public_keys is not None: + raise TypeError('`public_keys` must be a list instance or None') + if not isinstance(amount, int): + raise TypeError('`amount` must be an int') + if amount < 1: + raise AmountError('`amount` must be greater than 0') + if amount > self.MAX_AMOUNT: + raise AmountError('`amount` must be <= %s' % self.MAX_AMOUNT) + + self.fulfillment = fulfillment + self.amount = amount + self.public_keys = public_keys + + def __eq__(self, other): + # TODO: If `other !== Condition` return `False` + return self.to_dict() == other.to_dict() + + def to_dict(self): + """Transforms the object to a Python dictionary. + + Note: + A dictionary serialization of the Input the Output was + derived from is always provided. + + Returns: + dict: The Output as an alternative serialization format. + """ + # TODO FOR CC: It must be able to recognize a hashlock condition + # and fulfillment! + condition = {} + try: + condition['details'] = _fulfillment_to_details(self.fulfillment) + except AttributeError: + pass + + try: + condition['uri'] = self.fulfillment.condition_uri + except AttributeError: + condition['uri'] = self.fulfillment + + output = { + 'public_keys': self.public_keys, + 'condition': condition, + 'amount': str(self.amount), + } + return output + + @classmethod + def generate(cls, public_keys, amount): + """Generates a Output from a specifically formed tuple or list. + + Note: + If a ThresholdCondition has to be generated where the threshold + is always the number of subconditions it is split between, a + list of the following structure is sufficient: + + [(address|condition)*, [(address|condition)*, ...], ...] + + Args: + public_keys (:obj:`list` of :obj:`str`): The public key of + the users that should be able to fulfill the Condition + that is being created. + amount (:obj:`int`): The amount locked by the Output. + + Returns: + An Output that can be used in a Transaction. + + Raises: + TypeError: If `public_keys` is not an instance of `list`. + ValueError: If `public_keys` is an empty list. + """ + threshold = len(public_keys) + if not isinstance(amount, int): + raise TypeError('`amount` must be a int') + if amount < 1: + raise AmountError('`amount` needs to be greater than zero') + if not isinstance(public_keys, list): + raise TypeError('`public_keys` must be an instance of list') + if len(public_keys) == 0: + raise ValueError('`public_keys` needs to contain at least one' + 'owner') + elif len(public_keys) == 1 and not isinstance(public_keys[0], list): + if isinstance(public_keys[0], Fulfillment): + ffill = public_keys[0] + else: + ffill = Ed25519Sha256( + public_key=base58.b58decode(public_keys[0])) + return cls(ffill, public_keys, amount=amount) + else: + initial_cond = ThresholdSha256(threshold=threshold) + threshold_cond = reduce(cls._gen_condition, public_keys, + initial_cond) + return cls(threshold_cond, public_keys, amount=amount) + + @classmethod + def _gen_condition(cls, initial, new_public_keys): + """Generates ThresholdSha256 conditions from a list of new owners. + + Note: + This method is intended only to be used with a reduce function. + For a description on how to use this method, see + :meth:`~.Output.generate`. + + Args: + initial (:class:`cryptoconditions.ThresholdSha256`): + A Condition representing the overall root. + new_public_keys (:obj:`list` of :obj:`str`|str): A list of new + owners or a single new owner. + + Returns: + :class:`cryptoconditions.ThresholdSha256`: + """ + try: + threshold = len(new_public_keys) + except TypeError: + threshold = None + + if isinstance(new_public_keys, list) and len(new_public_keys) > 1: + ffill = ThresholdSha256(threshold=threshold) + reduce(cls._gen_condition, new_public_keys, ffill) + elif isinstance(new_public_keys, list) and len(new_public_keys) <= 1: + raise ValueError('Sublist cannot contain single owner') + else: + try: + new_public_keys = new_public_keys.pop() + except AttributeError: + pass + # NOTE: Instead of submitting base58 encoded addresses, a user + # of this class can also submit fully instantiated + # Cryptoconditions. In the case of casting + # `new_public_keys` to a Ed25519Fulfillment with the + # result of a `TypeError`, we're assuming that + # `new_public_keys` is a Cryptocondition then. + if isinstance(new_public_keys, Fulfillment): + ffill = new_public_keys + else: + ffill = Ed25519Sha256( + public_key=base58.b58decode(new_public_keys)) + initial.add_subfulfillment(ffill) + return initial + + @classmethod + def from_dict(cls, data): + """Transforms a Python dictionary to an Output object. + + Note: + To pass a serialization cycle multiple times, a + Cryptoconditions Fulfillment needs to be present in the + passed-in dictionary, as Condition URIs are not serializable + anymore. + + Args: + data (dict): The dict to be transformed. + + Returns: + :class:`~planetmint.transactions.common.transaction.Output` + """ + try: + fulfillment = _fulfillment_from_details(data['condition']['details']) + except KeyError: + # NOTE: Hashlock condition case + fulfillment = data['condition']['uri'] + try: + amount = int(data['amount']) + except ValueError: + raise AmountError('Invalid amount: %s' % data['amount']) + return cls(fulfillment, data['public_keys'], amount) diff --git a/planetmint/common/schema/README.md b/planetmint/transactions/common/schema/README.md similarity index 100% rename from planetmint/common/schema/README.md rename to planetmint/transactions/common/schema/README.md diff --git a/planetmint/common/schema/__init__.py b/planetmint/transactions/common/schema/__init__.py similarity index 97% rename from planetmint/common/schema/__init__.py rename to planetmint/transactions/common/schema/__init__.py index df28597..0b4b20b 100644 --- a/planetmint/common/schema/__init__.py +++ b/planetmint/transactions/common/schema/__init__.py @@ -11,7 +11,7 @@ import jsonschema import yaml import rapidjson -from planetmint.common.exceptions import SchemaValidationError +from planetmint.transactions.common.exceptions import SchemaValidationError logger = logging.getLogger(__name__) diff --git a/planetmint/common/schema/transaction_chain_migration_election_v2.0.yaml b/planetmint/transactions/common/schema/transaction_chain_migration_election_v2.0.yaml similarity index 100% rename from planetmint/common/schema/transaction_chain_migration_election_v2.0.yaml rename to planetmint/transactions/common/schema/transaction_chain_migration_election_v2.0.yaml diff --git a/planetmint/common/schema/transaction_create_v1.0.yaml b/planetmint/transactions/common/schema/transaction_create_v1.0.yaml similarity index 100% rename from planetmint/common/schema/transaction_create_v1.0.yaml rename to planetmint/transactions/common/schema/transaction_create_v1.0.yaml diff --git a/planetmint/common/schema/transaction_create_v2.0.yaml b/planetmint/transactions/common/schema/transaction_create_v2.0.yaml similarity index 100% rename from planetmint/common/schema/transaction_create_v2.0.yaml rename to planetmint/transactions/common/schema/transaction_create_v2.0.yaml diff --git a/planetmint/common/schema/transaction_transfer_v1.0.yaml b/planetmint/transactions/common/schema/transaction_transfer_v1.0.yaml similarity index 100% rename from planetmint/common/schema/transaction_transfer_v1.0.yaml rename to planetmint/transactions/common/schema/transaction_transfer_v1.0.yaml diff --git a/planetmint/common/schema/transaction_transfer_v2.0.yaml b/planetmint/transactions/common/schema/transaction_transfer_v2.0.yaml similarity index 100% rename from planetmint/common/schema/transaction_transfer_v2.0.yaml rename to planetmint/transactions/common/schema/transaction_transfer_v2.0.yaml diff --git a/planetmint/common/schema/transaction_v1.0.yaml b/planetmint/transactions/common/schema/transaction_v1.0.yaml similarity index 100% rename from planetmint/common/schema/transaction_v1.0.yaml rename to planetmint/transactions/common/schema/transaction_v1.0.yaml diff --git a/planetmint/common/schema/transaction_v2.0.yaml b/planetmint/transactions/common/schema/transaction_v2.0.yaml similarity index 100% rename from planetmint/common/schema/transaction_v2.0.yaml rename to planetmint/transactions/common/schema/transaction_v2.0.yaml diff --git a/planetmint/common/schema/transaction_validator_election_v2.0.yaml b/planetmint/transactions/common/schema/transaction_validator_election_v2.0.yaml similarity index 100% rename from planetmint/common/schema/transaction_validator_election_v2.0.yaml rename to planetmint/transactions/common/schema/transaction_validator_election_v2.0.yaml diff --git a/planetmint/common/schema/transaction_vote_v2.0.yaml b/planetmint/transactions/common/schema/transaction_vote_v2.0.yaml similarity index 100% rename from planetmint/common/schema/transaction_vote_v2.0.yaml rename to planetmint/transactions/common/schema/transaction_vote_v2.0.yaml diff --git a/planetmint/common/transaction.py b/planetmint/transactions/common/transaction.py similarity index 65% rename from planetmint/common/transaction.py rename to planetmint/transactions/common/transaction.py index c7301f6..e89aa6b 100644 --- a/planetmint/common/transaction.py +++ b/planetmint/transactions/common/transaction.py @@ -13,27 +13,27 @@ Attributes: """ from collections import namedtuple from copy import deepcopy -from functools import reduce, lru_cache +from functools import lru_cache import rapidjson import base58 from cryptoconditions import Fulfillment, ThresholdSha256, Ed25519Sha256 from cryptoconditions.exceptions import ( - ParsingError, ASN1DecodeError, ASN1EncodeError, UnsupportedTypeError) + ParsingError, ASN1DecodeError, ASN1EncodeError) try: from hashlib import sha3_256 except ImportError: from sha3 import sha3_256 -from planetmint.common.crypto import PrivateKey, hash_data -from planetmint.common.exceptions import (KeypairMismatchException, - InputDoesNotExist, DoubleSpend, - InvalidHash, InvalidSignature, - AmountError, AssetIdMismatch, - ThresholdTooDeep) -from planetmint.common.utils import serialize +from planetmint.transactions.common.crypto import PrivateKey, hash_data +from planetmint.transactions.common.exceptions import ( + KeypairMismatchException, InputDoesNotExist, DoubleSpend, + InvalidHash, InvalidSignature, AmountError, AssetIdMismatch) +from planetmint.transactions.common.utils import serialize from .memoize import memoize_from_dict, memoize_to_dict - +from .input import Input +from .output import Output +from .transaction_link import TransactionLink UnspentOutput = namedtuple( 'UnspentOutput', ( @@ -47,441 +47,6 @@ UnspentOutput = namedtuple( ) ) - -class Input(object): - """A Input is used to spend assets locked by an Output. - - Wraps around a Crypto-condition Fulfillment. - - Attributes: - fulfillment (:class:`cryptoconditions.Fulfillment`): A Fulfillment - to be signed with a private key. - owners_before (:obj:`list` of :obj:`str`): A list of owners after a - Transaction was confirmed. - fulfills (:class:`~planetmint.common.transaction. TransactionLink`, - optional): A link representing the input of a `TRANSFER` - Transaction. - """ - - def __init__(self, fulfillment, owners_before, fulfills=None): - """Create an instance of an :class:`~.Input`. - - Args: - fulfillment (:class:`cryptoconditions.Fulfillment`): A - Fulfillment to be signed with a private key. - owners_before (:obj:`list` of :obj:`str`): A list of owners - after a Transaction was confirmed. - fulfills (:class:`~planetmint.common.transaction. - TransactionLink`, optional): A link representing the input - of a `TRANSFER` Transaction. - """ - if fulfills is not None and not isinstance(fulfills, TransactionLink): - raise TypeError('`fulfills` must be a TransactionLink instance') - if not isinstance(owners_before, list): - raise TypeError('`owners_before` must be a list instance') - - self.fulfillment = fulfillment - self.fulfills = fulfills - self.owners_before = owners_before - - def __eq__(self, other): - # TODO: If `other !== Fulfillment` return `False` - return self.to_dict() == other.to_dict() - - # NOTE: This function is used to provide a unique key for a given - # Input to suppliment memoization - def __hash__(self): - return hash((self.fulfillment, self.fulfills)) - - def to_dict(self): - """Transforms the object to a Python dictionary. - - Note: - If an Input hasn't been signed yet, this method returns a - dictionary representation. - - Returns: - dict: The Input as an alternative serialization format. - """ - try: - fulfillment = self.fulfillment.serialize_uri() - except (TypeError, AttributeError, ASN1EncodeError, ASN1DecodeError): - fulfillment = _fulfillment_to_details(self.fulfillment) - - try: - # NOTE: `self.fulfills` can be `None` and that's fine - fulfills = self.fulfills.to_dict() - except AttributeError: - fulfills = None - - input_ = { - 'owners_before': self.owners_before, - 'fulfills': fulfills, - 'fulfillment': fulfillment, - } - return input_ - - @classmethod - def generate(cls, public_keys): - # TODO: write docstring - # The amount here does not really matter. It is only use on the - # output data model but here we only care about the fulfillment - output = Output.generate(public_keys, 1) - return cls(output.fulfillment, public_keys) - - @classmethod - def from_dict(cls, data): - """Transforms a Python dictionary to an Input object. - - Note: - Optionally, this method can also serialize a Cryptoconditions- - Fulfillment that is not yet signed. - - Args: - data (dict): The Input to be transformed. - - Returns: - :class:`~planetmint.common.transaction.Input` - - Raises: - InvalidSignature: If an Input's URI couldn't be parsed. - """ - fulfillment = data['fulfillment'] - if not isinstance(fulfillment, (Fulfillment, type(None))): - try: - fulfillment = Fulfillment.from_uri(data['fulfillment']) - except ASN1DecodeError: - # TODO Remove as it is legacy code, and simply fall back on - # ASN1DecodeError - raise InvalidSignature("Fulfillment URI couldn't been parsed") - except TypeError: - # NOTE: See comment about this special case in - # `Input.to_dict` - fulfillment = _fulfillment_from_details(data['fulfillment']) - fulfills = TransactionLink.from_dict(data['fulfills']) - return cls(fulfillment, data['owners_before'], fulfills) - - -def _fulfillment_to_details(fulfillment): - """Encode a fulfillment as a details dictionary - - Args: - fulfillment: Crypto-conditions Fulfillment object - """ - - if fulfillment.type_name == 'ed25519-sha-256': - return { - 'type': 'ed25519-sha-256', - 'public_key': base58.b58encode(fulfillment.public_key).decode(), - } - - if fulfillment.type_name == 'threshold-sha-256': - subconditions = [ - _fulfillment_to_details(cond['body']) - for cond in fulfillment.subconditions - ] - return { - 'type': 'threshold-sha-256', - 'threshold': fulfillment.threshold, - 'subconditions': subconditions, - } - - raise UnsupportedTypeError(fulfillment.type_name) - - -def _fulfillment_from_details(data, _depth=0): - """Load a fulfillment for a signing spec dictionary - - Args: - data: tx.output[].condition.details dictionary - """ - if _depth == 100: - raise ThresholdTooDeep() - - if data['type'] == 'ed25519-sha-256': - public_key = base58.b58decode(data['public_key']) - return Ed25519Sha256(public_key=public_key) - - if data['type'] == 'threshold-sha-256': - threshold = ThresholdSha256(data['threshold']) - for cond in data['subconditions']: - cond = _fulfillment_from_details(cond, _depth + 1) - threshold.add_subfulfillment(cond) - return threshold - - raise UnsupportedTypeError(data.get('type')) - - -class TransactionLink(object): - """An object for unidirectional linking to a Transaction's Output. - - Attributes: - txid (str, optional): A Transaction to link to. - output (int, optional): An output's index in a Transaction with id - `txid`. - """ - - def __init__(self, txid=None, output=None): - """Create an instance of a :class:`~.TransactionLink`. - - Note: - In an IPLD implementation, this class is not necessary anymore, - as an IPLD link can simply point to an object, as well as an - objects properties. So instead of having a (de)serializable - class, we can have a simple IPLD link of the form: - `//transaction/outputs//`. - - Args: - txid (str, optional): A Transaction to link to. - output (int, optional): An Outputs's index in a Transaction with - id `txid`. - """ - self.txid = txid - self.output = output - - def __bool__(self): - return self.txid is not None and self.output is not None - - def __eq__(self, other): - # TODO: If `other !== TransactionLink` return `False` - return self.to_dict() == other.to_dict() - - def __hash__(self): - return hash((self.txid, self.output)) - - @classmethod - def from_dict(cls, link): - """Transforms a Python dictionary to a TransactionLink object. - - Args: - link (dict): The link to be transformed. - - Returns: - :class:`~planetmint.common.transaction.TransactionLink` - """ - try: - return cls(link['transaction_id'], link['output_index']) - except TypeError: - return cls() - - def to_dict(self): - """Transforms the object to a Python dictionary. - - Returns: - (dict|None): The link as an alternative serialization format. - """ - if self.txid is None and self.output is None: - return None - else: - return { - 'transaction_id': self.txid, - 'output_index': self.output, - } - - def to_uri(self, path=''): - if self.txid is None and self.output is None: - return None - return '{}/transactions/{}/outputs/{}'.format(path, self.txid, - self.output) - - -class Output(object): - """An Output is used to lock an asset. - - Wraps around a Crypto-condition Condition. - - Attributes: - fulfillment (:class:`cryptoconditions.Fulfillment`): A Fulfillment - to extract a Condition from. - public_keys (:obj:`list` of :obj:`str`, optional): A list of - owners before a Transaction was confirmed. - """ - - MAX_AMOUNT = 9 * 10 ** 18 - - def __init__(self, fulfillment, public_keys=None, amount=1): - """Create an instance of a :class:`~.Output`. - - Args: - fulfillment (:class:`cryptoconditions.Fulfillment`): A - Fulfillment to extract a Condition from. - public_keys (:obj:`list` of :obj:`str`, optional): A list of - owners before a Transaction was confirmed. - amount (int): The amount of Assets to be locked with this - Output. - - Raises: - TypeError: if `public_keys` is not instance of `list`. - """ - if not isinstance(public_keys, list) and public_keys is not None: - raise TypeError('`public_keys` must be a list instance or None') - if not isinstance(amount, int): - raise TypeError('`amount` must be an int') - if amount < 1: - raise AmountError('`amount` must be greater than 0') - if amount > self.MAX_AMOUNT: - raise AmountError('`amount` must be <= %s' % self.MAX_AMOUNT) - - self.fulfillment = fulfillment - self.amount = amount - self.public_keys = public_keys - - def __eq__(self, other): - # TODO: If `other !== Condition` return `False` - return self.to_dict() == other.to_dict() - - def to_dict(self): - """Transforms the object to a Python dictionary. - - Note: - A dictionary serialization of the Input the Output was - derived from is always provided. - - Returns: - dict: The Output as an alternative serialization format. - """ - # TODO FOR CC: It must be able to recognize a hashlock condition - # and fulfillment! - condition = {} - try: - condition['details'] = _fulfillment_to_details(self.fulfillment) - except AttributeError: - pass - - try: - condition['uri'] = self.fulfillment.condition_uri - except AttributeError: - condition['uri'] = self.fulfillment - - output = { - 'public_keys': self.public_keys, - 'condition': condition, - 'amount': str(self.amount), - } - return output - - @classmethod - def generate(cls, public_keys, amount): - """Generates a Output from a specifically formed tuple or list. - - Note: - If a ThresholdCondition has to be generated where the threshold - is always the number of subconditions it is split between, a - list of the following structure is sufficient: - - [(address|condition)*, [(address|condition)*, ...], ...] - - Args: - public_keys (:obj:`list` of :obj:`str`): The public key of - the users that should be able to fulfill the Condition - that is being created. - amount (:obj:`int`): The amount locked by the Output. - - Returns: - An Output that can be used in a Transaction. - - Raises: - TypeError: If `public_keys` is not an instance of `list`. - ValueError: If `public_keys` is an empty list. - """ - threshold = len(public_keys) - if not isinstance(amount, int): - raise TypeError('`amount` must be a int') - if amount < 1: - raise AmountError('`amount` needs to be greater than zero') - if not isinstance(public_keys, list): - raise TypeError('`public_keys` must be an instance of list') - if len(public_keys) == 0: - raise ValueError('`public_keys` needs to contain at least one' - 'owner') - elif len(public_keys) == 1 and not isinstance(public_keys[0], list): - if isinstance(public_keys[0], Fulfillment): - ffill = public_keys[0] - else: - ffill = Ed25519Sha256( - public_key=base58.b58decode(public_keys[0])) - return cls(ffill, public_keys, amount=amount) - else: - initial_cond = ThresholdSha256(threshold=threshold) - threshold_cond = reduce(cls._gen_condition, public_keys, - initial_cond) - return cls(threshold_cond, public_keys, amount=amount) - - @classmethod - def _gen_condition(cls, initial, new_public_keys): - """Generates ThresholdSha256 conditions from a list of new owners. - - Note: - This method is intended only to be used with a reduce function. - For a description on how to use this method, see - :meth:`~.Output.generate`. - - Args: - initial (:class:`cryptoconditions.ThresholdSha256`): - A Condition representing the overall root. - new_public_keys (:obj:`list` of :obj:`str`|str): A list of new - owners or a single new owner. - - Returns: - :class:`cryptoconditions.ThresholdSha256`: - """ - try: - threshold = len(new_public_keys) - except TypeError: - threshold = None - - if isinstance(new_public_keys, list) and len(new_public_keys) > 1: - ffill = ThresholdSha256(threshold=threshold) - reduce(cls._gen_condition, new_public_keys, ffill) - elif isinstance(new_public_keys, list) and len(new_public_keys) <= 1: - raise ValueError('Sublist cannot contain single owner') - else: - try: - new_public_keys = new_public_keys.pop() - except AttributeError: - pass - # NOTE: Instead of submitting base58 encoded addresses, a user - # of this class can also submit fully instantiated - # Cryptoconditions. In the case of casting - # `new_public_keys` to a Ed25519Fulfillment with the - # result of a `TypeError`, we're assuming that - # `new_public_keys` is a Cryptocondition then. - if isinstance(new_public_keys, Fulfillment): - ffill = new_public_keys - else: - ffill = Ed25519Sha256( - public_key=base58.b58decode(new_public_keys)) - initial.add_subfulfillment(ffill) - return initial - - @classmethod - def from_dict(cls, data): - """Transforms a Python dictionary to an Output object. - - Note: - To pass a serialization cycle multiple times, a - Cryptoconditions Fulfillment needs to be present in the - passed-in dictionary, as Condition URIs are not serializable - anymore. - - Args: - data (dict): The dict to be transformed. - - Returns: - :class:`~planetmint.common.transaction.Output` - """ - try: - fulfillment = _fulfillment_from_details(data['condition']['details']) - except KeyError: - # NOTE: Hashlock condition case - fulfillment = data['condition']['uri'] - try: - amount = int(data['amount']) - except ValueError: - raise AmountError('Invalid amount: %s' % data['amount']) - return cls(fulfillment, data['public_keys'], amount) - - class Transaction(object): """A Transaction is used to create and transfer assets. @@ -491,10 +56,10 @@ class Transaction(object): Attributes: operation (str): Defines the operation of the Transaction. - inputs (:obj:`list` of :class:`~planetmint.common. + inputs (:obj:`list` of :class:`~planetmint.transactions.common. transaction.Input`, optional): Define the assets to spend. - outputs (:obj:`list` of :class:`~planetmint.common. + outputs (:obj:`list` of :class:`~planetmint.transactions.common. transaction.Output`, optional): Define the assets to lock. asset (dict): Asset payload for this Transaction. ``CREATE`` Transactions require a dict with a ``data`` @@ -521,9 +86,9 @@ class Transaction(object): Args: operation (str): Defines the operation of the Transaction. asset (dict): Asset payload for this Transaction. - inputs (:obj:`list` of :class:`~planetmint.common. + inputs (:obj:`list` of :class:`~planetmint.transactions.common. transaction.Input`, optional): Define the assets to - outputs (:obj:`list` of :class:`~planetmint.common. + outputs (:obj:`list` of :class:`~planetmint.transactions.common. transaction.Output`, optional): Define the assets to lock. metadata (dict): Metadata to be stored along with the @@ -660,7 +225,7 @@ class Transaction(object): be created in this Transaction. Returns: - :class:`~planetmint.common.transaction.Transaction` + :class:`~planetmint.transactions.common.transaction.Transaction` """ (inputs, outputs) = cls.validate_create(tx_signers, recipients, asset, metadata) @@ -716,7 +281,7 @@ class Transaction(object): weight respectively. `inp2` is owned completely by `d`. Args: - inputs (:obj:`list` of :class:`~planetmint.common.transaction. + inputs (:obj:`list` of :class:`~planetmint.transactions.common.transaction. Input`): Converted `Output`s, intended to be used as inputs in the transfer to generate. recipients (:obj:`list` of :obj:`tuple`): A list of @@ -728,7 +293,7 @@ class Transaction(object): Transaction. Returns: - :class:`~planetmint.common.transaction.Transaction` + :class:`~planetmint.transactions.common.transaction.Transaction` """ (inputs, outputs) = cls.validate_transfer(inputs, recipients, asset_id, metadata) return cls(cls.TRANSFER, {'id': asset_id}, inputs, outputs, metadata) @@ -757,7 +322,7 @@ class Transaction(object): outputs should be returned as inputs. Returns: - :obj:`list` of :class:`~planetmint.common.transaction. + :obj:`list` of :class:`~planetmint.transactions.common.transaction. Input` """ # NOTE: If no indices are passed, we just assume to take all outputs @@ -774,7 +339,7 @@ class Transaction(object): """Adds an input to a Transaction's list of inputs. Args: - input_ (:class:`~planetmint.common.transaction. + input_ (:class:`~planetmint.transactions.common.transaction. Input`): An Input to be added to the Transaction. """ if not isinstance(input_, Input): @@ -785,7 +350,7 @@ class Transaction(object): """Adds an output to a Transaction's list of outputs. Args: - output (:class:`~planetmint.common.transaction. + output (:class:`~planetmint.transactions.common.transaction. Output`): An Output to be added to the Transaction. """ @@ -811,7 +376,7 @@ class Transaction(object): Transaction. Returns: - :class:`~planetmint.common.transaction.Transaction` + :class:`~planetmint.transactions.common.transaction.Transaction` """ # TODO: Singing should be possible with at least one of all private # keys supplied to this method. @@ -857,7 +422,7 @@ class Transaction(object): - ThresholdSha256. Args: - input_ (:class:`~planetmint.common.transaction. + input_ (:class:`~planetmint.transactions.common.transaction. Input`) The Input to be signed. message (str): The message to be signed key_pairs (dict): The keys to sign the Transaction with. @@ -878,7 +443,7 @@ class Transaction(object): """Signs a Ed25519Fulfillment. Args: - input_ (:class:`~planetmint.common.transaction. + input_ (:class:`~planetmint.transactions.common.transaction. Input`) The input to be signed. message (str): The message to be signed key_pairs (dict): The keys to sign the Transaction with. @@ -910,7 +475,7 @@ class Transaction(object): """Signs a ThresholdSha256. Args: - input_ (:class:`~planetmint.common.transaction. + input_ (:class:`~planetmint.transactions.common.transaction. Input`) The Input to be signed. message (str): The message to be signed key_pairs (dict): The keys to sign the Transaction with. @@ -962,7 +527,7 @@ class Transaction(object): evaluate parts of the validation-checks to `True`. Args: - outputs (:obj:`list` of :class:`~planetmint.common. + outputs (:obj:`list` of :class:`~planetmint.transactions.common. transaction.Output`): A list of Outputs to check the Inputs against. @@ -1025,7 +590,7 @@ class Transaction(object): does not validate against `output_condition_uri`. Args: - input_ (:class:`~planetmint.common.transaction. + input_ (:class:`~planetmint.transactions.common.transaction. Input`) The Input to be signed. operation (str): The type of Transaction. message (str): The fulfillment message. @@ -1134,7 +699,7 @@ class Transaction(object): transaction are related to the same asset id. Args: - transactions (:obj:`list` of :class:`~planetmint.common. + transactions (:obj:`list` of :class:`~planetmint.transactions.common. transaction.Transaction`): A list of Transactions. Usually input Transactions that should have a matching asset ID. @@ -1196,7 +761,7 @@ class Transaction(object): tx_body (dict): The Transaction to be transformed. Returns: - :class:`~planetmint.common.transaction.Transaction` + :class:`~planetmint.transactions.common.transaction.Transaction` """ operation = tx.get('operation', Transaction.CREATE) if isinstance(tx, dict) else Transaction.CREATE cls = Transaction.resolve_class(operation) diff --git a/planetmint/transactions/common/transaction_link.py b/planetmint/transactions/common/transaction_link.py new file mode 100644 index 0000000..fcdbeb1 --- /dev/null +++ b/planetmint/transactions/common/transaction_link.py @@ -0,0 +1,76 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +class TransactionLink(object): + """An object for unidirectional linking to a Transaction's Output. + + Attributes: + txid (str, optional): A Transaction to link to. + output (int, optional): An output's index in a Transaction with id + `txid`. + """ + + def __init__(self, txid=None, output=None): + """Create an instance of a :class:`~.TransactionLink`. + + Note: + In an IPLD implementation, this class is not necessary anymore, + as an IPLD link can simply point to an object, as well as an + objects properties. So instead of having a (de)serializable + class, we can have a simple IPLD link of the form: + `//transaction/outputs//`. + + Args: + txid (str, optional): A Transaction to link to. + output (int, optional): An Outputs's index in a Transaction with + id `txid`. + """ + self.txid = txid + self.output = output + + def __bool__(self): + return self.txid is not None and self.output is not None + + def __eq__(self, other): + # TODO: If `other !== TransactionLink` return `False` + return self.to_dict() == other.to_dict() + + def __hash__(self): + return hash((self.txid, self.output)) + + @classmethod + def from_dict(cls, link): + """Transforms a Python dictionary to a TransactionLink object. + + Args: + link (dict): The link to be transformed. + + Returns: + :class:`~planetmint.transactions.common.transaction.TransactionLink` + """ + try: + return cls(link['transaction_id'], link['output_index']) + except TypeError: + return cls() + + def to_dict(self): + """Transforms the object to a Python dictionary. + + Returns: + (dict|None): The link as an alternative serialization format. + """ + if self.txid is None and self.output is None: + return None + else: + return { + 'transaction_id': self.txid, + 'output_index': self.output, + } + + def to_uri(self, path=''): + if self.txid is None and self.output is None: + return None + return '{}/transactions/{}/outputs/{}'.format(path, self.txid, + self.output) diff --git a/planetmint/common/transaction_mode_types.py b/planetmint/transactions/common/transaction_mode_types.py similarity index 100% rename from planetmint/common/transaction_mode_types.py rename to planetmint/transactions/common/transaction_mode_types.py diff --git a/planetmint/common/utils.py b/planetmint/transactions/common/utils.py similarity index 75% rename from planetmint/common/utils.py rename to planetmint/transactions/common/utils.py index b1834ea..e18580d 100644 --- a/planetmint/common/utils.py +++ b/planetmint/transactions/common/utils.py @@ -3,12 +3,16 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 +import base58 import time import re import rapidjson import planetmint -from planetmint.common.exceptions import ValidationError +from planetmint.transactions.common.exceptions import ValidationError +from cryptoconditions import ThresholdSha256, Ed25519Sha256 +from planetmint.transactions.common.exceptions import ThresholdTooDeep +from cryptoconditions.exceptions import UnsupportedTypeError def gen_timestamp(): @@ -163,3 +167,52 @@ def validate_key(obj_name, key): 'key name cannot contain characters ' '".", "$" or null characters').format(key, obj_name) raise ValidationError(error_str) + +def _fulfillment_to_details(fulfillment): + """Encode a fulfillment as a details dictionary + + Args: + fulfillment: Crypto-conditions Fulfillment object + """ + + if fulfillment.type_name == 'ed25519-sha-256': + return { + 'type': 'ed25519-sha-256', + 'public_key': base58.b58encode(fulfillment.public_key).decode(), + } + + if fulfillment.type_name == 'threshold-sha-256': + subconditions = [ + _fulfillment_to_details(cond['body']) + for cond in fulfillment.subconditions + ] + return { + 'type': 'threshold-sha-256', + 'threshold': fulfillment.threshold, + 'subconditions': subconditions, + } + + raise UnsupportedTypeError(fulfillment.type_name) + + +def _fulfillment_from_details(data, _depth=0): + """Load a fulfillment for a signing spec dictionary + + Args: + data: tx.output[].condition.details dictionary + """ + if _depth == 100: + raise ThresholdTooDeep() + + if data['type'] == 'ed25519-sha-256': + public_key = base58.b58decode(data['public_key']) + return Ed25519Sha256(public_key=public_key) + + if data['type'] == 'threshold-sha-256': + threshold = ThresholdSha256(data['threshold']) + for cond in data['subconditions']: + cond = _fulfillment_from_details(cond, _depth + 1) + threshold.add_subfulfillment(cond) + return threshold + + raise UnsupportedTypeError(data.get('type')) diff --git a/planetmint/elections/__init__.py b/planetmint/transactions/types/assets/__init__.py similarity index 100% rename from planetmint/elections/__init__.py rename to planetmint/transactions/types/assets/__init__.py diff --git a/planetmint/transactions/types/assets/create.py b/planetmint/transactions/types/assets/create.py new file mode 100644 index 0000000..d8a1222 --- /dev/null +++ b/planetmint/transactions/types/assets/create.py @@ -0,0 +1,77 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +from planetmint.transactions.common.transaction import Transaction +from planetmint.transactions.common.input import Input +from planetmint.transactions.common.output import Output + +class Create(Transaction): + + OPERATION = 'CREATE' + ALLOWED_OPERATIONS = (OPERATION,) + + @classmethod + def validate(self, tx_signers, recipients, asset, metadata): + if not isinstance(tx_signers, list): + raise TypeError('`tx_signers` must be a list instance') + if not isinstance(recipients, list): + raise TypeError('`recipients` must be a list instance') + if len(tx_signers) == 0: + raise ValueError('`tx_signers` list cannot be empty') + if len(recipients) == 0: + raise ValueError('`recipients` list cannot be empty') + if not (asset is None or isinstance(asset, dict)): + raise TypeError('`asset` must be a dict or None') + if not (metadata is None or isinstance(metadata, dict)): + raise TypeError('`metadata` must be a dict or None') + + inputs = [] + outputs = [] + + # generate_outputs + for recipient in recipients: + if not isinstance(recipient, tuple) or len(recipient) != 2: + raise ValueError(('Each `recipient` in the list must be a' + ' tuple of `([],' + ' )`')) + pub_keys, amount = recipient + outputs.append(Output.generate(pub_keys, amount)) + + # generate inputs + inputs.append(Input.generate(tx_signers)) + + return (inputs, outputs) + + @classmethod + def generate(cls, tx_signers, recipients, metadata=None, asset=None): + """A simple way to generate a `CREATE` transaction. + + Note: + This method currently supports the following Cryptoconditions + use cases: + - Ed25519 + - ThresholdSha256 + + Additionally, it provides support for the following Planetmint + use cases: + - Multiple inputs and outputs. + + Args: + tx_signers (:obj:`list` of :obj:`str`): A list of keys that + represent the signers of the CREATE Transaction. + recipients (:obj:`list` of :obj:`tuple`): A list of + ([keys],amount) that represent the recipients of this + Transaction. + metadata (dict): The metadata to be stored along with the + Transaction. + asset (dict): The metadata associated with the asset that will + be created in this Transaction. + + Returns: + :class:`~planetmint.common.transaction.Transaction` + """ + + (inputs, outputs) = cls.validate(tx_signers, recipients, asset, metadata) + return cls(cls.OPERATION, {'data': asset}, inputs, outputs, metadata) diff --git a/planetmint/transactions/types/assets/transfer.py b/planetmint/transactions/types/assets/transfer.py new file mode 100644 index 0000000..9fb709b --- /dev/null +++ b/planetmint/transactions/types/assets/transfer.py @@ -0,0 +1,80 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +from planetmint.transactions.common.transaction import Transaction +from planetmint.transactions.common.output import Output +from copy import deepcopy + +class Transfer(Transaction): + + OPERATION = 'TRANSFER' + ALLOWED_OPERATIONS = (OPERATION,) + + @classmethod + def validate(cls, inputs, recipients, asset_id, metadata): + if not isinstance(inputs, list): + raise TypeError('`inputs` must be a list instance') + if len(inputs) == 0: + raise ValueError('`inputs` must contain at least one item') + if not isinstance(recipients, list): + raise TypeError('`recipients` must be a list instance') + if len(recipients) == 0: + raise ValueError('`recipients` list cannot be empty') + + outputs = [] + for recipient in recipients: + if not isinstance(recipient, tuple) or len(recipient) != 2: + raise ValueError(('Each `recipient` in the list must be a' + ' tuple of `([],' + ' )`')) + pub_keys, amount = recipient + outputs.append(Output.generate(pub_keys, amount)) + + if not isinstance(asset_id, str): + raise TypeError('`asset_id` must be a string') + + return (deepcopy(inputs), outputs) + + @classmethod + def generate(cls, inputs, recipients, asset_id, metadata=None): + """A simple way to generate a `TRANSFER` transaction. + + Note: + Different cases for threshold conditions: + + Combining multiple `inputs` with an arbitrary number of + `recipients` can yield interesting cases for the creation of + threshold conditions we'd like to support. The following + notation is proposed: + + 1. The index of a `recipient` corresponds to the index of + an input: + e.g. `transfer([input1], [a])`, means `input1` would now be + owned by user `a`. + + 2. `recipients` can (almost) get arbitrary deeply nested, + creating various complex threshold conditions: + e.g. `transfer([inp1, inp2], [[a, [b, c]], d])`, means + `a`'s signature would have a 50% weight on `inp1` + compared to `b` and `c` that share 25% of the leftover + weight respectively. `inp2` is owned completely by `d`. + + Args: + inputs (:obj:`list` of :class:`~planetmint.common.transaction. + Input`): Converted `Output`s, intended to + be used as inputs in the transfer to generate. + recipients (:obj:`list` of :obj:`tuple`): A list of + ([keys],amount) that represent the recipients of this + Transaction. + asset_id (str): The asset ID of the asset to be transferred in + this Transaction. + metadata (dict): Python dictionary to be stored along with the + Transaction. + + Returns: + :class:`~planetmint.common.transaction.Transaction` + """ + (inputs, outputs) = cls.validate_transfer(inputs, recipients, asset_id, metadata) + return cls(cls.OPERATION, {'id': asset_id}, inputs, outputs, metadata) diff --git a/planetmint/transactions/types/elections/__init__.py b/planetmint/transactions/types/elections/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/planetmint/elections/election.py b/planetmint/transactions/types/elections/election.py similarity index 94% rename from planetmint/elections/election.py rename to planetmint/transactions/types/elections/election.py index d73b319..d74fcbd 100644 --- a/planetmint/elections/election.py +++ b/planetmint/transactions/types/elections/election.py @@ -8,18 +8,17 @@ import base58 from uuid import uuid4 from planetmint import backend -from planetmint.elections.vote import Vote -from planetmint.common.exceptions import (InvalidSignature, - MultipleInputsError, - InvalidProposer, - UnequalValidatorSet, - DuplicateTransaction) +from planetmint.transactions.types.assets.create import Create +from planetmint.transactions.types.assets.transfer import Transfer +from planetmint.transactions.types.elections.vote import Vote +from planetmint.transactions.common.exceptions import ( + InvalidSignature, MultipleInputsError, InvalidProposer, + UnequalValidatorSet, DuplicateTransaction) from planetmint.tendermint_utils import key_from_base64, public_key_to_base64 -from planetmint.common.crypto import (public_key_from_ed25519_key) -from planetmint.common.transaction import Transaction -from planetmint.common.schema import (_validate_schema, - TX_SCHEMA_COMMON, - TX_SCHEMA_CREATE) +from planetmint.transactions.common.crypto import (public_key_from_ed25519_key) +from planetmint.transactions.common.transaction import Transaction +from planetmint.transactions.common.schema import ( + _validate_schema, TX_SCHEMA_COMMON, TX_SCHEMA_CREATE) class Election(Transaction): @@ -161,11 +160,11 @@ class Election(Transaction): @classmethod def create(cls, tx_signers, recipients, metadata=None, asset=None): - raise NotImplementedError + Create.generate(tx_signers, recipients, metadata=None, asset=None) @classmethod def transfer(cls, tx_signers, recipients, metadata=None, asset=None): - raise NotImplementedError + Transfer.generate(tx_signers, recipients, metadata=None, asset=None) @classmethod def to_public_key(cls, election_id): diff --git a/planetmint/elections/vote.py b/planetmint/transactions/types/elections/vote.py similarity index 81% rename from planetmint/elections/vote.py rename to planetmint/transactions/types/elections/vote.py index a4bb0c9..a4b25f3 100644 --- a/planetmint/elections/vote.py +++ b/planetmint/transactions/types/elections/vote.py @@ -3,11 +3,11 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -from planetmint.common.transaction import Transaction -from planetmint.common.schema import (_validate_schema, - TX_SCHEMA_COMMON, - TX_SCHEMA_TRANSFER, - TX_SCHEMA_VOTE) +from planetmint.transactions.types.assets.create import Create +from planetmint.transactions.types.assets.transfer import Transfer +from planetmint.transactions.common.transaction import Transaction +from planetmint.transactions.common.schema import ( + _validate_schema, TX_SCHEMA_COMMON, TX_SCHEMA_TRANSFER, TX_SCHEMA_VOTE) class Vote(Transaction): @@ -57,8 +57,8 @@ class Vote(Transaction): @classmethod def create(cls, tx_signers, recipients, metadata=None, asset=None): - raise NotImplementedError + return Create.generate(tx_signers, recipients, metadata=None, asset=None) @classmethod def transfer(cls, tx_signers, recipients, metadata=None, asset=None): - raise NotImplementedError + return Transfer.generate(tx_signers, recipients, metadata=None, asset=None) diff --git a/planetmint/upsert_validator/validator_election.py b/planetmint/upsert_validator/validator_election.py index 5f26f92..31e4161 100644 --- a/planetmint/upsert_validator/validator_election.py +++ b/planetmint/upsert_validator/validator_election.py @@ -3,9 +3,9 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -from planetmint.common.exceptions import InvalidPowerChange -from planetmint.elections.election import Election -from planetmint.common.schema import TX_SCHEMA_VALIDATOR_ELECTION +from planetmint.transactions.common.exceptions import InvalidPowerChange +from planetmint.transactions.types.elections.election import Election +from planetmint.transactions.common.schema import TX_SCHEMA_VALIDATOR_ELECTION from .validator_utils import (new_validator_set, encode_validator, validate_asset_public_key) diff --git a/planetmint/upsert_validator/validator_utils.py b/planetmint/upsert_validator/validator_utils.py index 69293c2..d1cf51c 100644 --- a/planetmint/upsert_validator/validator_utils.py +++ b/planetmint/upsert_validator/validator_utils.py @@ -4,7 +4,7 @@ import codecs from tendermint.abci import types_pb2 from tendermint.crypto import keys_pb2 -from planetmint.common.exceptions import InvalidPublicKey +from planetmint.transactions.common.exceptions import InvalidPublicKey def encode_validator(v): ed25519_public_key = v['public_key']['value'] diff --git a/planetmint/utils.py b/planetmint/utils.py index 51b0fa4..25dbc82 100644 --- a/planetmint/utils.py +++ b/planetmint/utils.py @@ -13,7 +13,7 @@ import setproctitle from packaging import version from planetmint.version import __tm_supported_versions__ from planetmint.tendermint_utils import key_from_base64 -from planetmint.common.crypto import key_pair_from_ed25519_key +from planetmint.transactions.common.crypto import key_pair_from_ed25519_key class ProcessGroup(object): diff --git a/planetmint/web/views/parameters.py b/planetmint/web/views/parameters.py index 530fc38..6df22ff 100644 --- a/planetmint/web/views/parameters.py +++ b/planetmint/web/views/parameters.py @@ -5,10 +5,8 @@ import re -from planetmint.common.transaction_mode_types import (BROADCAST_TX_COMMIT, - BROADCAST_TX_ASYNC, - BROADCAST_TX_SYNC) - +from planetmint.transactions.common.transaction_mode_types import ( + BROADCAST_TX_COMMIT, BROADCAST_TX_ASYNC, BROADCAST_TX_SYNC) def valid_txid(txid): if re.match('^[a-fA-F0-9]{64}$', txid): diff --git a/planetmint/web/views/transactions.py b/planetmint/web/views/transactions.py index c093ef7..eafaeed 100644 --- a/planetmint/web/views/transactions.py +++ b/planetmint/web/views/transactions.py @@ -12,8 +12,8 @@ import logging from flask import current_app, request, jsonify from flask_restful import Resource, reqparse -from planetmint.common.transaction_mode_types import BROADCAST_TX_ASYNC -from planetmint.common.exceptions import SchemaValidationError, ValidationError +from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_ASYNC +from planetmint.transactions.common.exceptions import SchemaValidationError, ValidationError from planetmint.web.views.base import make_error from planetmint.web.views import parameters from planetmint.models import Transaction diff --git a/setup.py b/setup.py index 7aa0901..e396d3a 100644 --- a/setup.py +++ b/setup.py @@ -138,5 +138,5 @@ setup( 'dev': dev_require + tests_require + docs_require, 'docs': docs_require, }, - package_data={'planetmint.common.schema': ['*.yaml']}, + package_data={'planetmint.transactions.common.schema': ['*.yaml']}, ) diff --git a/tests/assets/test_digital_assets.py b/tests/assets/test_digital_assets.py index ba3f062..b23b05d 100644 --- a/tests/assets/test_digital_assets.py +++ b/tests/assets/test_digital_assets.py @@ -21,7 +21,7 @@ def test_asset_transfer(b, signed_create_tx, user_pk, user_sk): def test_validate_transfer_asset_id_mismatch(b, signed_create_tx, user_pk, user_sk): - from planetmint.common.exceptions import AssetIdMismatch + from planetmint.transactions.common.exceptions import AssetIdMismatch from planetmint.models import Transaction tx_transfer = Transaction.transfer(signed_create_tx.to_inputs(), [([user_pk], 1)], @@ -52,7 +52,7 @@ def test_get_asset_id_transfer_transaction(b, signed_create_tx, user_pk): def test_asset_id_mismatch(alice, user_pk): from planetmint.models import Transaction - from planetmint.common.exceptions import AssetIdMismatch + from planetmint.transactions.common.exceptions import AssetIdMismatch tx1 = Transaction.create([alice.public_key], [([user_pk], 1)], metadata={'msg': random.random()}) diff --git a/tests/assets/test_divisible_assets.py b/tests/assets/test_divisible_assets.py index 437da55..570be4b 100644 --- a/tests/assets/test_divisible_assets.py +++ b/tests/assets/test_divisible_assets.py @@ -6,7 +6,7 @@ import pytest import random -from planetmint.common.exceptions import DoubleSpend +from planetmint.transactions.common.exceptions import DoubleSpend # CREATE divisible asset @@ -99,7 +99,7 @@ def test_single_in_single_own_multiple_out_mix_own_create(alice, user_pk, b): def test_single_in_multiple_own_single_out_single_own_create(alice, b, user_pk, user_sk): from planetmint.models import Transaction - from planetmint.common.transaction import _fulfillment_to_details + from planetmint.transactions.common.utils import _fulfillment_to_details tx = Transaction.create([alice.public_key, user_pk], [([user_pk], 100)], asset={'name': random.random()}) tx_signed = tx.sign([alice.private_key, user_sk]) @@ -249,7 +249,7 @@ def test_single_in_single_own_multiple_out_mix_own_transfer(alice, b, user_pk, def test_single_in_multiple_own_single_out_single_own_transfer(alice, b, user_pk, user_sk): from planetmint.models import Transaction - from planetmint.common.transaction import _fulfillment_to_details + from planetmint.transactions.common.utils import _fulfillment_to_details # CREATE divisible asset tx_create = Transaction.create([alice.public_key], [([alice.public_key, user_pk], 100)], @@ -316,7 +316,7 @@ def test_multiple_in_single_own_single_out_single_own_transfer(alice, b, user_pk def test_multiple_in_multiple_own_single_out_single_own_transfer(alice, b, user_pk, user_sk): from planetmint.models import Transaction - from planetmint.common.transaction import _fulfillment_to_details + from planetmint.transactions.common.utils import _fulfillment_to_details # CREATE divisible asset tx_create = Transaction.create([alice.public_key], [([user_pk, alice.public_key], 50), @@ -357,7 +357,7 @@ def test_multiple_in_multiple_own_single_out_single_own_transfer(alice, b, user_ def test_muiltiple_in_mix_own_multiple_out_single_own_transfer(alice, b, user_pk, user_sk): from planetmint.models import Transaction - from planetmint.common.transaction import _fulfillment_to_details + from planetmint.transactions.common.utils import _fulfillment_to_details # CREATE divisible asset tx_create = Transaction.create([alice.public_key], [([user_pk], 50), ([user_pk, alice.public_key], 50)], @@ -397,7 +397,7 @@ def test_muiltiple_in_mix_own_multiple_out_single_own_transfer(alice, b, user_pk def test_muiltiple_in_mix_own_multiple_out_mix_own_transfer(alice, b, user_pk, user_sk): from planetmint.models import Transaction - from planetmint.common.transaction import _fulfillment_to_details + from planetmint.transactions.common.utils import _fulfillment_to_details # CREATE divisible asset tx_create = Transaction.create([alice.public_key], [([user_pk], 50), ([user_pk, alice.public_key], 50)], @@ -486,7 +486,7 @@ def test_multiple_in_different_transactions(alice, b, user_pk, user_sk): # In other words `amount_in_inputs - amount_in_outputs == 0` def test_amount_error_transfer(alice, b, user_pk, user_sk): from planetmint.models import Transaction - from planetmint.common.exceptions import AmountError + from planetmint.transactions.common.exceptions import AmountError # CREATE divisible asset tx_create = Transaction.create([alice.public_key], [([user_pk], 100)], asset={'name': random.random()}) diff --git a/tests/backend/localmongodb/test_queries.py b/tests/backend/localmongodb/test_queries.py index ec86410..0557527 100644 --- a/tests/backend/localmongodb/test_queries.py +++ b/tests/backend/localmongodb/test_queries.py @@ -238,7 +238,7 @@ def test_get_spending_transactions(user_pk, user_sk): def test_get_spending_transactions_multiple_inputs(): from planetmint.backend import connect, query from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair conn = connect() (alice_sk, alice_pk) = generate_key_pair() (bob_sk, bob_pk) = generate_key_pair() diff --git a/tests/backend/test_connection.py b/tests/backend/test_connection.py index 9ff8cc2..424a3d1 100644 --- a/tests/backend/test_connection.py +++ b/tests/backend/test_connection.py @@ -7,7 +7,7 @@ import pytest def test_get_connection_raises_a_configuration_error(monkeypatch): - from planetmint.common.exceptions import ConfigurationError + from planetmint.transactions.common.exceptions import ConfigurationError from planetmint.backend import connect with pytest.raises(ConfigurationError): diff --git a/tests/commands/conftest.py b/tests/commands/conftest.py index 73d25ff..6a1c19c 100644 --- a/tests/commands/conftest.py +++ b/tests/commands/conftest.py @@ -34,7 +34,7 @@ def mock_processes_start(monkeypatch): @pytest.fixture def mock_generate_key_pair(monkeypatch): - monkeypatch.setattr('planetmint.common.crypto.generate_key_pair', lambda: ('privkey', 'pubkey')) + monkeypatch.setattr('planetmint.transactions.common.crypto.generate_key_pair', lambda: ('privkey', 'pubkey')) @pytest.fixture diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index b6c90ad..1e9384f 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -13,7 +13,7 @@ import pytest from planetmint import ValidatorElection from planetmint.commands.planetmint import run_election_show -from planetmint.elections.election import Election +from planetmint.transactions.types.elections.election import Election from planetmint.lib import Block from planetmint.migrations.chain_migration_election import ChainMigrationElection @@ -123,7 +123,7 @@ def test_drop_db_when_interactive_yes(mock_db_drop, monkeypatch): def test_drop_db_when_db_does_not_exist(mock_db_drop, capsys): from planetmint import config from planetmint.commands.planetmint import run_drop - from planetmint.common.exceptions import DatabaseDoesNotExist + from planetmint.transactions.common.exceptions import DatabaseDoesNotExist args = Namespace(config=None, yes=True) mock_db_drop.side_effect = DatabaseDoesNotExist @@ -404,7 +404,7 @@ def test_election_new_upsert_validator_invalid_election(caplog, b, priv_validato @pytest.mark.bdb def test_election_new_upsert_validator_invalid_power(caplog, b, priv_validator_path, user_sk): from planetmint.commands.planetmint import run_election_new_upsert_validator - from planetmint.common.exceptions import InvalidPowerChange + from planetmint.transactions.common.exceptions import InvalidPowerChange def mock_write(tx, mode): b.store_bulk_transactions([tx]) diff --git a/tests/common/conftest.py b/tests/common/conftest.py index 1f8d029..eea23ee 100644 --- a/tests/common/conftest.py +++ b/tests/common/conftest.py @@ -100,31 +100,31 @@ def user2_Ed25519(user2_pub): @pytest.fixture def user_input(user_Ed25519, user_pub): - from planetmint.common.transaction import Input + from planetmint.transactions.common.transaction import Input return Input(user_Ed25519, [user_pub]) @pytest.fixture def user_user2_threshold_output(user_user2_threshold, user_pub, user2_pub): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output return Output(user_user2_threshold, [user_pub, user2_pub]) @pytest.fixture def user_user2_threshold_input(user_user2_threshold, user_pub, user2_pub): - from planetmint.common.transaction import Input + from planetmint.transactions.common.transaction import Input return Input(user_user2_threshold, [user_pub, user2_pub]) @pytest.fixture def user_output(user_Ed25519, user_pub): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output return Output(user_Ed25519, [user_pub]) @pytest.fixture def user2_output(user2_Ed25519, user2_pub): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output return Output(user2_Ed25519, [user2_pub]) @@ -140,7 +140,7 @@ def data(): @pytest.fixture def utx(user_input, user_output): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction return Transaction(Transaction.CREATE, {'data': None}, [user_input], [user_output]) @@ -152,8 +152,8 @@ def tx(utx, user_priv): @pytest.fixture def transfer_utx(user_output, user2_output, utx): - from planetmint.common.transaction import (Input, TransactionLink, - Transaction) + from planetmint.transactions.common.transaction import ( + Input, TransactionLink, Transaction) user_output = user_output.to_dict() input = Input(utx.outputs[0].fulfillment, user_output['public_keys'], diff --git a/tests/common/test_memoize.py b/tests/common/test_memoize.py index f8a35c5..8665080 100644 --- a/tests/common/test_memoize.py +++ b/tests/common/test_memoize.py @@ -7,8 +7,8 @@ import pytest from copy import deepcopy from planetmint.models import Transaction -from planetmint.common.crypto import generate_key_pair -from planetmint.common.memoize import to_dict, from_dict +from planetmint.transactions.common.crypto import generate_key_pair +from planetmint.transactions.common.memoize import to_dict, from_dict pytestmark = pytest.mark.bdb diff --git a/tests/common/test_schema.py b/tests/common/test_schema.py index 62269b4..07cda88 100644 --- a/tests/common/test_schema.py +++ b/tests/common/test_schema.py @@ -13,8 +13,8 @@ from hypothesis import given from hypothesis.strategies import from_regex as regex from pytest import raises -from planetmint.common.exceptions import SchemaValidationError -from planetmint.common.schema import ( +from planetmint.transactions.common.exceptions import SchemaValidationError +from planetmint.transactions.common.schema import ( TX_SCHEMA_COMMON, validate_transaction_schema, ) diff --git a/tests/common/test_transaction.py b/tests/common/test_transaction.py index 268b714..84ddb2b 100644 --- a/tests/common/test_transaction.py +++ b/tests/common/test_transaction.py @@ -21,7 +21,7 @@ pytestmark = mark.bdb def test_input_serialization(ffill_uri, user_pub): - from planetmint.common.transaction import Input + from planetmint.transactions.common.transaction import Input from cryptoconditions import Fulfillment expected = { @@ -34,7 +34,7 @@ def test_input_serialization(ffill_uri, user_pub): def test_input_deserialization_with_uri(ffill_uri, user_pub): - from planetmint.common.transaction import Input + from planetmint.transactions.common.transaction import Input from cryptoconditions import Fulfillment expected = Input(Fulfillment.from_uri(ffill_uri), [user_pub]) @@ -50,7 +50,7 @@ def test_input_deserialization_with_uri(ffill_uri, user_pub): @mark.skip(reason='None is tolerated because it is None before fulfilling.') def test_input_deserialization_with_invalid_input(user_pub): - from planetmint.common.transaction import Input + from planetmint.transactions.common.transaction import Input ffill = { 'owners_before': [user_pub], @@ -62,8 +62,8 @@ def test_input_deserialization_with_invalid_input(user_pub): def test_input_deserialization_with_invalid_fulfillment_uri(user_pub): - from planetmint.common.exceptions import InvalidSignature - from planetmint.common.transaction import Input + from planetmint.transactions.common.exceptions import InvalidSignature + from planetmint.transactions.common.transaction import Input ffill = { 'owners_before': [user_pub], @@ -75,7 +75,7 @@ def test_input_deserialization_with_invalid_fulfillment_uri(user_pub): def test_input_deserialization_with_unsigned_fulfillment(ffill_uri, user_pub): - from planetmint.common.transaction import Input + from planetmint.transactions.common.transaction import Input from cryptoconditions import Fulfillment expected = Input(Fulfillment.from_uri(ffill_uri), [user_pub]) @@ -90,7 +90,7 @@ def test_input_deserialization_with_unsigned_fulfillment(ffill_uri, user_pub): def test_output_serialization(user_Ed25519, user_pub): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output expected = { 'condition': { @@ -110,7 +110,7 @@ def test_output_serialization(user_Ed25519, user_pub): def test_output_deserialization(user_Ed25519, user_pub): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output expected = Output(user_Ed25519, [user_pub], 1) cond = { @@ -130,7 +130,7 @@ def test_output_deserialization(user_Ed25519, user_pub): def test_output_hashlock_serialization(): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output from cryptoconditions import PreimageSha256 secret = b'wow much secret' @@ -149,7 +149,7 @@ def test_output_hashlock_serialization(): def test_output_hashlock_deserialization(): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output from cryptoconditions import PreimageSha256 secret = b'wow much secret' @@ -169,8 +169,8 @@ def test_output_hashlock_deserialization(): def test_invalid_output_initialization(cond_uri, user_pub): - from planetmint.common.transaction import Output - from planetmint.common.exceptions import AmountError + from planetmint.transactions.common.transaction import Output + from planetmint.transactions.common.exceptions import AmountError with raises(TypeError): Output(cond_uri, user_pub) @@ -181,7 +181,7 @@ def test_invalid_output_initialization(cond_uri, user_pub): def test_generate_output_split_half_recursive(user_pub, user2_pub, user3_pub): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output from cryptoconditions import Ed25519Sha256, ThresholdSha256 expected_simple1 = Ed25519Sha256(public_key=b58decode(user_pub)) @@ -201,7 +201,7 @@ 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.common.transaction import Output + from planetmint.transactions.common.transaction import Output from cryptoconditions import Ed25519Sha256, ThresholdSha256 expected_simple1 = Ed25519Sha256(public_key=b58decode(user_pub)) @@ -220,7 +220,7 @@ def test_generate_outputs_split_half_single_owner(user_pub, def test_generate_outputs_flat_ownage(user_pub, user2_pub, user3_pub): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output from cryptoconditions import Ed25519Sha256, ThresholdSha256 expected_simple1 = Ed25519Sha256(public_key=b58decode(user_pub)) @@ -237,7 +237,7 @@ def test_generate_outputs_flat_ownage(user_pub, user2_pub, user3_pub): def test_generate_output_single_owner(user_pub): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output from cryptoconditions import Ed25519Sha256 expected = Ed25519Sha256(public_key=b58decode(user_pub)) @@ -247,7 +247,7 @@ def test_generate_output_single_owner(user_pub): def test_generate_output_single_owner_with_output(user_pub): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output from cryptoconditions import Ed25519Sha256 expected = Ed25519Sha256(public_key=b58decode(user_pub)) @@ -257,8 +257,8 @@ def test_generate_output_single_owner_with_output(user_pub): def test_generate_output_invalid_parameters(user_pub, user2_pub, user3_pub): - from planetmint.common.transaction import Output - from planetmint.common.exceptions import AmountError + from planetmint.transactions.common.transaction import Output + from planetmint.transactions.common.exceptions import AmountError with raises(ValueError): Output.generate([], 1) @@ -273,7 +273,7 @@ def test_generate_output_invalid_parameters(user_pub, user2_pub, user3_pub): def test_invalid_transaction_initialization(asset_definition): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction with raises(ValueError): Transaction(operation='invalid operation', asset=asset_definition) @@ -305,7 +305,7 @@ def test_invalid_transaction_initialization(asset_definition): def test_create_default_asset_on_tx_initialization(asset_definition): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction expected = {'data': None} tx = Transaction(Transaction.CREATE, asset=expected) @@ -315,7 +315,7 @@ def test_create_default_asset_on_tx_initialization(asset_definition): def test_transaction_serialization(user_input, user_output, data): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction expected = { 'id': None, @@ -339,14 +339,14 @@ def test_transaction_serialization(user_input, user_output, data): def test_transaction_deserialization(tri_state_transaction): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model tx = Transaction.from_dict(tri_state_transaction) validate_transaction_model(tx) def test_invalid_input_initialization(user_input, user_pub): - from planetmint.common.transaction import Input + from planetmint.transactions.common.transaction import Input with raises(TypeError): Input(user_input, user_pub) @@ -355,7 +355,7 @@ def test_invalid_input_initialization(user_input, user_pub): def test_transaction_link_serialization(): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink tx_id = 'a transaction id' expected = { @@ -368,7 +368,7 @@ def test_transaction_link_serialization(): def test_transaction_link_serialization_with_empty_payload(): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink expected = None tx_link = TransactionLink() @@ -377,7 +377,7 @@ def test_transaction_link_serialization_with_empty_payload(): def test_transaction_link_deserialization(): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink tx_id = 'a transaction id' expected = TransactionLink(tx_id, 0) @@ -391,7 +391,7 @@ def test_transaction_link_deserialization(): def test_transaction_link_deserialization_with_empty_payload(): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink expected = TransactionLink() tx_link = TransactionLink.from_dict(None) @@ -400,7 +400,7 @@ def test_transaction_link_deserialization_with_empty_payload(): def test_transaction_link_empty_to_uri(): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink expected = None tx_link = TransactionLink().to_uri() @@ -409,7 +409,7 @@ def test_transaction_link_empty_to_uri(): def test_transaction_link_to_uri(): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink expected = 'path/transactions/abc/outputs/0' tx_link = TransactionLink('abc', 0).to_uri('path') @@ -418,7 +418,7 @@ def test_transaction_link_to_uri(): def test_cast_transaction_link_to_boolean(): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink assert bool(TransactionLink()) is False assert bool(TransactionLink('a', None)) is False @@ -428,7 +428,7 @@ def test_cast_transaction_link_to_boolean(): def test_transaction_link_eq(): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink assert TransactionLink(1, 2) == TransactionLink(1, 2) assert TransactionLink(2, 2) != TransactionLink(1, 2) @@ -437,7 +437,7 @@ def test_transaction_link_eq(): def test_add_input_to_tx(user_input, asset_definition): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model tx = Transaction(Transaction.CREATE, asset_definition, [], []) @@ -449,7 +449,7 @@ def test_add_input_to_tx(user_input, asset_definition): def test_add_input_to_tx_with_invalid_parameters(asset_definition): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction tx = Transaction(Transaction.CREATE, asset_definition) with raises(TypeError): @@ -457,7 +457,7 @@ 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.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model tx = Transaction(Transaction.CREATE, asset_definition, [user_input]) @@ -469,7 +469,7 @@ 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.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction tx = Transaction(Transaction.CREATE, asset_definition, [], []) with raises(TypeError): @@ -485,7 +485,7 @@ 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.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model tx = Transaction(Transaction.CREATE, asset_definition, [user_input], [user_output]) @@ -507,7 +507,7 @@ def test_validate_tx_simple_create_signature(user_input, user_output, user_priv, def test_invoke_simple_signature_fulfillment_with_invalid_params(utx, user_input): - from planetmint.common.exceptions import KeypairMismatchException + from planetmint.transactions.common.exceptions import KeypairMismatchException with raises(KeypairMismatchException): invalid_key_pair = {'wrong_pub_key': 'wrong_priv_key'} @@ -518,7 +518,7 @@ def test_invoke_simple_signature_fulfillment_with_invalid_params(utx, def test_sign_threshold_with_invalid_params(utx, user_user2_threshold_input, user3_pub, user3_priv): - from planetmint.common.exceptions import KeypairMismatchException + from planetmint.transactions.common.exceptions import KeypairMismatchException with raises(KeypairMismatchException): utx._sign_threshold_signature_fulfillment(user_user2_threshold_input, @@ -532,7 +532,7 @@ def test_sign_threshold_with_invalid_params(utx, user_user2_threshold_input, def test_validate_input_with_invalid_parameters(utx): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction input_conditions = [out.fulfillment.condition_uri for out in utx.outputs] tx_dict = utx.to_dict() @@ -548,7 +548,7 @@ def test_validate_tx_threshold_create_signature(user_user2_threshold_input, user_priv, user2_priv, asset_definition): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model tx = Transaction(Transaction.CREATE, asset_definition, @@ -576,7 +576,7 @@ def test_validate_tx_threshold_create_signature(user_user2_threshold_input, def test_validate_tx_threshold_duplicated_pk(user_pub, user_priv, asset_definition): from cryptoconditions import Ed25519Sha256, ThresholdSha256 - from planetmint.common.transaction import Input, Output, Transaction + from planetmint.transactions.common.transaction import Input, Output, Transaction threshold = ThresholdSha256(threshold=2) threshold.add_subfulfillment( @@ -621,8 +621,8 @@ def test_multiple_input_validation_of_transfer_tx(user_input, user_output, user2_priv, user3_pub, user3_priv, asset_definition): - from planetmint.common.transaction import (Transaction, TransactionLink, - Input, Output) + from planetmint.transactions.common.transaction import ( + Transaction, TransactionLink, Input, Output) from cryptoconditions import Ed25519Sha256 from .utils import validate_transaction_model @@ -647,7 +647,7 @@ def test_multiple_input_validation_of_transfer_tx(user_input, user_output, def test_validate_inputs_of_transfer_tx_with_invalid_params( transfer_tx, cond_uri, utx, user2_pub, user_priv, ffill_uri): - from planetmint.common.transaction import Output + from planetmint.transactions.common.transaction import Output from cryptoconditions import Ed25519Sha256 invalid_out = Output(Ed25519Sha256.from_uri(ffill_uri), ['invalid']) @@ -668,7 +668,7 @@ def test_validate_inputs_of_transfer_tx_with_invalid_params( def test_create_create_transaction_single_io(user_output, user_pub, data): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model expected = { @@ -703,7 +703,7 @@ def test_create_create_transaction_single_io(user_output, user_pub, data): def test_validate_single_io_create_transaction(user_pub, user_priv, data, asset_definition): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction tx = Transaction.create([user_pub], [([user_pub], 1)], metadata=data) tx = tx.sign([user_priv]) @@ -712,7 +712,7 @@ def test_validate_single_io_create_transaction(user_pub, user_priv, data, def test_create_create_transaction_multiple_io(user_output, user2_output, user_pub, user2_pub, asset_definition): - from planetmint.common.transaction import Transaction, Input + 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 @@ -739,7 +739,7 @@ def test_create_create_transaction_multiple_io(user_output, user2_output, user_p def test_validate_multiple_io_create_transaction(user_pub, user_priv, user2_pub, user2_priv, asset_definition): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model tx = Transaction.create([user_pub, user2_pub], @@ -754,7 +754,7 @@ def test_validate_multiple_io_create_transaction(user_pub, user_priv, def test_create_create_transaction_threshold(user_pub, user2_pub, user3_pub, user_user2_threshold_output, user_user2_threshold_input, data): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction expected = { 'outputs': [user_user2_threshold_output.to_dict()], @@ -785,7 +785,7 @@ def test_create_create_transaction_threshold(user_pub, user2_pub, user3_pub, def test_validate_threshold_create_transaction(user_pub, user_priv, user2_pub, data, asset_definition): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model tx = Transaction.create([user_pub], [([user_pub, user2_pub], 1)], @@ -797,7 +797,7 @@ def test_validate_threshold_create_transaction(user_pub, user_priv, user2_pub, def test_create_create_transaction_with_invalid_parameters(user_pub): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction with raises(TypeError): Transaction.create('not a list') @@ -832,7 +832,7 @@ def test_outputs_to_inputs(tx): def test_create_transfer_transaction_single_io(tx, user_pub, user2_pub, user2_output, user_priv): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model expected = { @@ -887,7 +887,7 @@ def test_create_transfer_transaction_multiple_io(user_pub, user_priv, user2_pub, user2_priv, user3_pub, user2_output, asset_definition): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction tx = Transaction.create([user_pub], [([user_pub], 1), ([user2_pub], 1)], metadata={'message': 'hello'}) @@ -941,7 +941,7 @@ def test_create_transfer_transaction_multiple_io(user_pub, user_priv, def test_create_transfer_with_invalid_parameters(tx, user_pub): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction with raises(TypeError): Transaction.transfer({}, [], tx.id) @@ -964,7 +964,7 @@ def test_create_transfer_with_invalid_parameters(tx, user_pub): def test_cant_add_empty_output(): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction tx = Transaction(Transaction.CREATE, None) with raises(TypeError): @@ -972,7 +972,7 @@ def test_cant_add_empty_output(): def test_cant_add_empty_input(): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction tx = Transaction(Transaction.CREATE, None) with raises(TypeError): @@ -980,7 +980,7 @@ def test_cant_add_empty_input(): def test_unfulfilled_transaction_serialized(unfulfilled_transaction): - from planetmint.common.transaction import 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) @@ -988,7 +988,7 @@ def test_unfulfilled_transaction_serialized(unfulfilled_transaction): def test_fulfilled_transaction_serialized(fulfilled_transaction): - from planetmint.common.transaction import 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) @@ -996,7 +996,7 @@ def test_fulfilled_transaction_serialized(fulfilled_transaction): def test_transaction_hash(fulfilled_transaction): - from planetmint.common.transaction import 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 @@ -1009,8 +1009,8 @@ def test_transaction_hash(fulfilled_transaction): def test_output_from_dict_invalid_amount(user_output): - from planetmint.common.transaction import Output - from planetmint.common.exceptions import AmountError + from planetmint.transactions.common.transaction import Output + from planetmint.transactions.common.exceptions import AmountError out = user_output.to_dict() out['amount'] = 'a' @@ -1019,7 +1019,7 @@ def test_output_from_dict_invalid_amount(user_output): def test_unspent_outputs_property(merlin, alice, bob, carol): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction tx = Transaction.create( [merlin.public_key], [([alice.public_key], 1), diff --git a/tests/common/utils.py b/tests/common/utils.py index d95575e..bd10303 100644 --- a/tests/common/utils.py +++ b/tests/common/utils.py @@ -5,8 +5,8 @@ def validate_transaction_model(tx): - from planetmint.common.transaction import Transaction - from planetmint.common.schema import validate_transaction_schema + from planetmint.transactions.common.transaction import Transaction + from planetmint.transactions.common.schema import validate_transaction_schema tx_dict = tx.to_dict() # Check that a transaction is valid by re-serializing it diff --git a/tests/conftest.py b/tests/conftest.py index af49f42..f553538 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -23,13 +23,13 @@ import pytest from pymongo import MongoClient from planetmint import ValidatorElection -from planetmint.common import crypto -from planetmint.common.transaction_mode_types import BROADCAST_TX_COMMIT +from planetmint.transactions.common import crypto +from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT from planetmint.tendermint_utils import key_from_base64 from planetmint.backend import schema, query -from planetmint.common.crypto import (key_pair_from_ed25519_key, - public_key_from_ed25519_key) -from planetmint.common.exceptions import DatabaseDoesNotExist +from planetmint.transactions.common.crypto import ( + key_pair_from_ed25519_key, public_key_from_ed25519_key) +from planetmint.transactions.common.exceptions import DatabaseDoesNotExist from planetmint.lib import Block from tests.utils import gen_vote @@ -149,7 +149,7 @@ def _bdb(_setup_database, _configure_planetmint): from planetmint import config from planetmint.backend import connect from .utils import flush_db - from planetmint.common.memoize import to_dict, from_dict + from planetmint.transactions.common.memoize import to_dict, from_dict from planetmint.models import Transaction conn = connect() yield @@ -205,13 +205,13 @@ def user2_pk(): @pytest.fixture def alice(): - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair return generate_key_pair() @pytest.fixture def bob(): - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair return generate_key_pair() @@ -227,7 +227,7 @@ def bob_pubkey(carol): @pytest.fixture def carol(): - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair return generate_key_pair() @@ -243,7 +243,7 @@ def carol_pubkey(carol): @pytest.fixture def merlin(): - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair return generate_key_pair() diff --git a/tests/db/test_bigchain_api.py b/tests/db/test_bigchain_api.py index b6d4124..9724cb6 100644 --- a/tests/db/test_bigchain_api.py +++ b/tests/db/test_bigchain_api.py @@ -15,7 +15,7 @@ class TestBigchainApi(object): def test_get_spent_with_double_spend_detected(self, b, alice): from planetmint.models import Transaction - from planetmint.common.exceptions import DoubleSpend + from planetmint.transactions.common.exceptions import DoubleSpend from planetmint.exceptions import CriticalDoubleSpend tx = Transaction.create([alice.public_key], [([alice.public_key], 1)]) @@ -81,8 +81,8 @@ class TestBigchainApi(object): @pytest.mark.usefixtures('inputs') def test_non_create_input_not_found(self, b, user_pk): from cryptoconditions import Ed25519Sha256 - from planetmint.common.exceptions import InputDoesNotExist - from planetmint.common.transaction import Input, TransactionLink + from planetmint.transactions.common.exceptions import InputDoesNotExist + from planetmint.transactions.common.transaction import Input, TransactionLink from planetmint.models import Transaction # Create an input for a non existing transaction @@ -117,8 +117,8 @@ class TestBigchainApi(object): class TestTransactionValidation(object): def test_non_create_input_not_found(self, b, signed_transfer_tx): - from planetmint.common.exceptions import InputDoesNotExist - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.exceptions import InputDoesNotExist + from planetmint.transactions.common.transaction import TransactionLink signed_transfer_tx.inputs[0].fulfills = TransactionLink('c', 0) with pytest.raises(InputDoesNotExist): @@ -126,8 +126,8 @@ class TestTransactionValidation(object): @pytest.mark.usefixtures('inputs') def test_non_create_valid_input_wrong_owner(self, b, user_pk): - from planetmint.common.crypto import generate_key_pair - from planetmint.common.exceptions import InvalidSignature + from planetmint.transactions.common.crypto import generate_key_pair + from planetmint.transactions.common.exceptions import InvalidSignature from planetmint.models import Transaction input_tx = b.fastquery.get_outputs_by_public_key(user_pk).pop() @@ -144,7 +144,7 @@ class TestTransactionValidation(object): @pytest.mark.usefixtures('inputs') def test_non_create_double_spend(self, b, signed_create_tx, signed_transfer_tx, double_spend_tx): - from planetmint.common.exceptions import DoubleSpend + from planetmint.transactions.common.exceptions import DoubleSpend b.store_bulk_transactions([signed_create_tx, signed_transfer_tx]) @@ -156,7 +156,7 @@ class TestMultipleInputs(object): def test_transfer_single_owner_single_input(self, b, inputs, user_pk, user_sk): - from planetmint.common import crypto + from planetmint.transactions.common import crypto from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -177,7 +177,7 @@ class TestMultipleInputs(object): user_sk, user_pk, inputs): - from planetmint.common import crypto + from planetmint.transactions.common import crypto from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -199,7 +199,7 @@ class TestMultipleInputs(object): user_sk, user_pk, alice): - from planetmint.common import crypto + from planetmint.transactions.common import crypto from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -227,7 +227,7 @@ class TestMultipleInputs(object): user_sk, user_pk, alice): - from planetmint.common import crypto + from planetmint.transactions.common import crypto from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -252,8 +252,8 @@ class TestMultipleInputs(object): assert len(tx.outputs) == 1 def test_get_owned_ids_single_tx_single_output(self, b, user_sk, user_pk, alice): - from planetmint.common import crypto - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common import crypto + from planetmint.transactions.common.transaction import TransactionLink from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -280,8 +280,8 @@ class TestMultipleInputs(object): def test_get_owned_ids_single_tx_multiple_outputs(self, b, user_sk, user_pk, alice): - from planetmint.common import crypto - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common import crypto + from planetmint.transactions.common.transaction import TransactionLink from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -314,8 +314,8 @@ class TestMultipleInputs(object): TransactionLink(tx_transfer.id, 1)] def test_get_owned_ids_multiple_owners(self, b, user_sk, user_pk, alice): - from planetmint.common import crypto - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common import crypto + from planetmint.transactions.common.transaction import TransactionLink from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -346,7 +346,7 @@ class TestMultipleInputs(object): assert not spent_user1 def test_get_spent_single_tx_single_output(self, b, user_sk, user_pk, alice): - from planetmint.common import crypto + from planetmint.transactions.common import crypto from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -372,7 +372,7 @@ class TestMultipleInputs(object): assert spent_inputs_user1 == tx def test_get_spent_single_tx_multiple_outputs(self, b, user_sk, user_pk, alice): - from planetmint.common import crypto + from planetmint.transactions.common import crypto from planetmint.models import Transaction # create a new users @@ -409,7 +409,7 @@ class TestMultipleInputs(object): assert b.get_spent(tx_create.to_inputs()[2].fulfills.txid, 2) is None def test_get_spent_multiple_owners(self, b, user_sk, user_pk, alice): - from planetmint.common import crypto + from planetmint.transactions.common import crypto from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -445,7 +445,7 @@ class TestMultipleInputs(object): def test_get_outputs_filtered_only_unspent(): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink from planetmint.lib import Planetmint go = 'planetmint.fastquery.FastQuery.get_outputs_by_public_key' @@ -461,7 +461,7 @@ def test_get_outputs_filtered_only_unspent(): def test_get_outputs_filtered_only_spent(): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink from planetmint.lib import Planetmint go = 'planetmint.fastquery.FastQuery.get_outputs_by_public_key' with patch(go) as get_outputs: @@ -478,7 +478,7 @@ def test_get_outputs_filtered_only_spent(): @patch('planetmint.fastquery.FastQuery.filter_unspent_outputs') @patch('planetmint.fastquery.FastQuery.filter_spent_outputs') def test_get_outputs_filtered(filter_spent, filter_unspent): - from planetmint.common.transaction import TransactionLink + from planetmint.transactions.common.transaction import TransactionLink from planetmint.lib import Planetmint go = 'planetmint.fastquery.FastQuery.get_outputs_by_public_key' @@ -497,7 +497,7 @@ def test_cant_spend_same_input_twice_in_tx(b, alice): https://github.com/planetmint/planetmint/issues/1099 """ from planetmint.models import Transaction - from planetmint.common.exceptions import DoubleSpend + from planetmint.transactions.common.exceptions import DoubleSpend # create a divisible asset tx_create = Transaction.create([alice.public_key], [([alice.public_key], 100)]) @@ -517,7 +517,7 @@ def test_cant_spend_same_input_twice_in_tx(b, alice): def test_transaction_unicode(b, alice): import copy - from planetmint.common.utils import serialize + from planetmint.transactions.common.utils import serialize from planetmint.models import Transaction # http://www.fileformat.info/info/unicode/char/1f37a/index.htm diff --git a/tests/elections/test_election.py b/tests/elections/test_election.py index af0e08a..e58ec4f 100644 --- a/tests/elections/test_election.py +++ b/tests/elections/test_election.py @@ -3,7 +3,7 @@ import pytest from tests.utils import generate_election, generate_validators from planetmint.lib import Block -from planetmint.elections.election import Election +from planetmint.transactions.types.elections.election import Election from planetmint.migrations.chain_migration_election import ChainMigrationElection from planetmint.upsert_validator.validator_election import ValidatorElection diff --git a/tests/tendermint/test_core.py b/tests/tendermint/test_core.py index 5f54a1b..581fbe9 100644 --- a/tests/tendermint/test_core.py +++ b/tests/tendermint/test_core.py @@ -12,11 +12,11 @@ from tendermint.crypto import keys_pb2 from planetmint import App from planetmint.backend.localmongodb import query -from planetmint.common.crypto import generate_key_pair +from planetmint.transactions.common.crypto import generate_key_pair from planetmint.core import (OkCode, CodeTypeError, rollback) -from planetmint.elections.election import Election +from planetmint.transactions.types.elections.election import Election from planetmint.lib import Block from planetmint.migrations.chain_migration_election import ChainMigrationElection from planetmint.upsert_validator.validator_election import ValidatorElection @@ -203,7 +203,7 @@ def test_info(b): def test_check_tx__signed_create_is_ok(b): from planetmint import App from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() bob = generate_key_pair() @@ -220,7 +220,7 @@ def test_check_tx__signed_create_is_ok(b): def test_check_tx__unsigned_create_is_error(b): from planetmint import App from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() bob = generate_key_pair() @@ -237,7 +237,7 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(b, init_chain_reque import multiprocessing as mp from planetmint import App from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() bob = generate_key_pair() @@ -274,7 +274,7 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(b, init_chain_reque def test_deliver_tx__double_spend_fails(b, init_chain_request): from planetmint import App from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() bob = generate_key_pair() @@ -303,7 +303,7 @@ def test_deliver_tx__double_spend_fails(b, init_chain_request): def test_deliver_transfer_tx__double_spend_fails(b, init_chain_request): from planetmint import App from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair app = App(b) app.init_chain(init_chain_request) diff --git a/tests/tendermint/test_fastquery.py b/tests/tendermint/test_fastquery.py index 98ca97a..61f8ac9 100644 --- a/tests/tendermint/test_fastquery.py +++ b/tests/tendermint/test_fastquery.py @@ -5,7 +5,7 @@ import pytest -from planetmint.common.transaction import TransactionLink +from planetmint.transactions.common.transaction import TransactionLink from planetmint.models import Transaction diff --git a/tests/tendermint/test_integration.py b/tests/tendermint/test_integration.py index a57a3b2..45b4db1 100644 --- a/tests/tendermint/test_integration.py +++ b/tests/tendermint/test_integration.py @@ -13,7 +13,7 @@ import pytest from abci.server import ProtocolHandler from abci.utils import read_messages -from planetmint.common.transaction_mode_types import BROADCAST_TX_COMMIT, BROADCAST_TX_SYNC +from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT, BROADCAST_TX_SYNC from planetmint.version import __tm_supported_versions__ from io import BytesIO @@ -22,7 +22,7 @@ from io import BytesIO def test_app(b, eventqueue_fixture, init_chain_request): from planetmint import App from planetmint.tendermint_utils import calculate_hash - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair from planetmint.models import Transaction app = App(b, eventqueue_fixture) @@ -113,7 +113,7 @@ def test_app(b, eventqueue_fixture, init_chain_request): @pytest.mark.abci def test_post_transaction_responses(tendermint_ws_url, b): - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair from planetmint.models import Transaction alice = generate_key_pair() diff --git a/tests/tendermint/test_lib.py b/tests/tendermint/test_lib.py index 2d9bc96..55fd2be 100644 --- a/tests/tendermint/test_lib.py +++ b/tests/tendermint/test_lib.py @@ -17,9 +17,8 @@ import pytest from pymongo import MongoClient from planetmint import backend -from planetmint.common.transaction_mode_types import (BROADCAST_TX_COMMIT, - BROADCAST_TX_ASYNC, - BROADCAST_TX_SYNC) +from planetmint.transactions.common.transaction_mode_types import ( + BROADCAST_TX_COMMIT, BROADCAST_TX_ASYNC, BROADCAST_TX_SYNC) from planetmint.lib import Block @@ -27,7 +26,7 @@ from planetmint.lib import Block def test_asset_is_separated_from_transaciton(b): import copy from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() bob = generate_key_pair() @@ -83,7 +82,7 @@ def test_get_empty_block(_0, _1, b): def test_validation_error(b): from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() tx = Transaction.create([alice.public_key], @@ -98,7 +97,7 @@ def test_validation_error(b): @patch('requests.post') def test_write_and_post_transaction(mock_post, b): from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair from planetmint.tendermint_utils import encode_transaction alice = generate_key_pair() @@ -125,7 +124,7 @@ def test_write_and_post_transaction(mock_post, b): ]) def test_post_transaction_valid_modes(mock_post, b, mode): from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], @@ -140,8 +139,8 @@ def test_post_transaction_valid_modes(mock_post, b, mode): def test_post_transaction_invalid_mode(b): from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair - from planetmint.common.exceptions import ValidationError + from planetmint.transactions.common.crypto import generate_key_pair + from planetmint.transactions.common.exceptions import ValidationError alice = generate_key_pair() tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], @@ -357,7 +356,7 @@ def test_get_utxoset_merkle_root(b, utxoset): def test_get_spent_transaction_critical_double_spend(b, alice, bob, carol): from planetmint.models import Transaction from planetmint.exceptions import CriticalDoubleSpend - from planetmint.common.exceptions import DoubleSpend + from planetmint.transactions.common.exceptions import DoubleSpend asset = {'test': 'asset'} @@ -404,7 +403,7 @@ def test_get_spent_transaction_critical_double_spend(b, alice, bob, carol): def test_validation_with_transaction_buffer(b): - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair from planetmint.models import Transaction priv_key, pub_key = generate_key_pair() @@ -461,8 +460,8 @@ def test_migrate_abci_chain_generates_new_chains(b, chain, block_height, def test_get_spent_key_order(b, user_pk, user_sk, user2_pk, user2_sk): from planetmint import backend from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair - from planetmint.common.exceptions import DoubleSpend + from planetmint.transactions.common.crypto import generate_key_pair + from planetmint.transactions.common.exceptions import DoubleSpend alice = generate_key_pair() bob = generate_key_pair() diff --git a/tests/test_config_utils.py b/tests/test_config_utils.py index 4bcff77..ebf9874 100644 --- a/tests/test_config_utils.py +++ b/tests/test_config_utils.py @@ -298,7 +298,7 @@ def test_file_config(): def test_invalid_file_config(): from planetmint.config_utils import file_config - from planetmint.common import exceptions + from planetmint.transactions.common import exceptions with patch('builtins.open', mock_open(read_data='{_INVALID_JSON_}')): with pytest.raises(exceptions.ConfigurationError): file_config() diff --git a/tests/test_core.py b/tests/test_core.py index 6d61344..140cd22 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -12,11 +12,11 @@ from tendermint.crypto import keys_pb2 from planetmint import App from planetmint.backend.localmongodb import query -from planetmint.common.crypto import generate_key_pair +from planetmint.transactions.common.crypto import generate_key_pair from planetmint.core import (OkCode, CodeTypeError, rollback) -from planetmint.elections.election import Election +from planetmint.transactions.types.elections.election import Election from planetmint.lib import Block from planetmint.migrations.chain_migration_election import ChainMigrationElection from planetmint.upsert_validator.validator_election import ValidatorElection @@ -203,7 +203,7 @@ def test_info(b): def test_check_tx__signed_create_is_ok(b): from planetmint import App from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() bob = generate_key_pair() @@ -220,7 +220,7 @@ def test_check_tx__signed_create_is_ok(b): def test_check_tx__unsigned_create_is_error(b): from planetmint import App from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() bob = generate_key_pair() @@ -237,7 +237,7 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(b, init_chain_reque import multiprocessing as mp from planetmint import App from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() bob = generate_key_pair() @@ -274,7 +274,7 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(b, init_chain_reque def test_deliver_tx__double_spend_fails(b, eventqueue_fixture, init_chain_request): from planetmint import App from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() bob = generate_key_pair() @@ -303,7 +303,7 @@ def test_deliver_tx__double_spend_fails(b, eventqueue_fixture, init_chain_reques def test_deliver_transfer_tx__double_spend_fails(b, init_chain_request): from planetmint import App from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair app = App(b) app.init_chain(init_chain_request) diff --git a/tests/test_parallel_validation.py b/tests/test_parallel_validation.py index a0aec26..df2a39d 100644 --- a/tests/test_parallel_validation.py +++ b/tests/test_parallel_validation.py @@ -5,7 +5,7 @@ import pytest -from planetmint.common.crypto import generate_key_pair +from planetmint.transactions.common.crypto import generate_key_pair from planetmint.models import Transaction diff --git a/tests/upsert_validator/conftest.py b/tests/upsert_validator/conftest.py index f4f71c4..39b8d26 100644 --- a/tests/upsert_validator/conftest.py +++ b/tests/upsert_validator/conftest.py @@ -19,7 +19,7 @@ def valid_upsert_validator_election_b(b, node_key, new_validator): @pytest.fixture -@patch('planetmint.elections.election.uuid4', lambda: 'mock_uuid4') +@patch('planetmint.transactions.types.elections.election.uuid4', lambda: 'mock_uuid4') def fixed_seed_election(b_mock, node_key, new_validator): voters = ValidatorElection.recipients(b_mock) return ValidatorElection.generate([node_key.public_key], diff --git a/tests/upsert_validator/test_upsert_validator_vote.py b/tests/upsert_validator/test_upsert_validator_vote.py index 5fb4fe0..95ec43c 100644 --- a/tests/upsert_validator/test_upsert_validator_vote.py +++ b/tests/upsert_validator/test_upsert_validator_vote.py @@ -6,14 +6,14 @@ import pytest import codecs -from planetmint.elections.election import Election +from planetmint.transactions.types.elections.election import Election from planetmint.tendermint_utils import public_key_to_base64 from planetmint.upsert_validator import ValidatorElection -from planetmint.common.exceptions import AmountError -from planetmint.common.crypto import generate_key_pair -from planetmint.common.exceptions import ValidationError -from planetmint.common.transaction_mode_types import BROADCAST_TX_COMMIT -from planetmint.elections.vote import Vote +from planetmint.transactions.common.exceptions import AmountError +from planetmint.transactions.common.crypto import generate_key_pair +from planetmint.transactions.common.exceptions import ValidationError +from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT +from planetmint.transactions.types.elections.vote import Vote from tests.utils import generate_block, gen_vote pytestmark = [pytest.mark.execute] diff --git a/tests/upsert_validator/test_validator_election.py b/tests/upsert_validator/test_validator_election.py index 3b8e3e5..77aaf1c 100644 --- a/tests/upsert_validator/test_validator_election.py +++ b/tests/upsert_validator/test_validator_election.py @@ -9,11 +9,9 @@ import pytest from planetmint.tendermint_utils import public_key_to_base64 from planetmint.upsert_validator import ValidatorElection -from planetmint.common.exceptions import (DuplicateTransaction, - UnequalValidatorSet, - InvalidProposer, - MultipleInputsError, - InvalidPowerChange) +from planetmint.transactions.common.exceptions import ( + DuplicateTransaction, UnequalValidatorSet, InvalidProposer, + MultipleInputsError, InvalidPowerChange) pytestmark = pytest.mark.bdb @@ -27,7 +25,7 @@ def test_upsert_validator_valid_election(b_mock, new_validator, node_key): def test_upsert_validator_invalid_election_public_key(b_mock, new_validator, node_key): - from planetmint.common.exceptions import InvalidPublicKey + from planetmint.transactions.common.exceptions import InvalidPublicKey for iv in ['ed25519-base32', 'ed25519-base64']: new_validator['public_key']['type'] = iv @@ -51,7 +49,7 @@ def test_upsert_validator_invalid_power_election(b_mock, new_validator, node_key def test_upsert_validator_invalid_proposed_election(b_mock, new_validator, node_key): - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() voters = ValidatorElection.recipients(b_mock) @@ -63,7 +61,7 @@ def test_upsert_validator_invalid_proposed_election(b_mock, new_validator, node_ def test_upsert_validator_invalid_inputs_election(b_mock, new_validator, node_key): - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() voters = ValidatorElection.recipients(b_mock) @@ -74,7 +72,7 @@ def test_upsert_validator_invalid_inputs_election(b_mock, new_validator, node_ke election.validate(b_mock) -@patch('planetmint.elections.election.uuid4', lambda: 'mock_uuid4') +@patch('planetmint.transactions.types.elections.election.uuid4', lambda: 'mock_uuid4') def test_upsert_validator_invalid_election(b_mock, new_validator, node_key, fixed_seed_election): voters = ValidatorElection.recipients(b_mock) duplicate_election = ValidatorElection.generate([node_key.public_key], diff --git a/tests/utils.py b/tests/utils.py index 05a54e2..4829d4e 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -11,9 +11,9 @@ from functools import singledispatch from planetmint.backend.localmongodb.connection import LocalMongoDBConnection from planetmint.backend.schema import TABLES -from planetmint.common import crypto -from planetmint.common.transaction_mode_types import BROADCAST_TX_COMMIT -from planetmint.elections.election import Election, Vote +from planetmint.transactions.common import crypto +from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT +from planetmint.transactions.types.elections.election import Election, Vote from planetmint.tendermint_utils import key_to_base64 @@ -29,7 +29,7 @@ def flush_localmongo_db(connection, dbname): def generate_block(planet): - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair from planetmint.models import Transaction alice = generate_key_pair() diff --git a/tests/validation/test_transaction_structure.py b/tests/validation/test_transaction_structure.py index b710253..5fcb425 100644 --- a/tests/validation/test_transaction_structure.py +++ b/tests/validation/test_transaction_structure.py @@ -16,10 +16,10 @@ except ImportError: import sha3 from unittest.mock import MagicMock -from planetmint.common.exceptions import (AmountError, - SchemaValidationError, - ThresholdTooDeep) +from planetmint.transactions.common.exceptions import ( + AmountError, SchemaValidationError, ThresholdTooDeep) from planetmint.models import Transaction +from planetmint.transactions.common.utils import _fulfillment_to_details, _fulfillment_from_details ################################################################################ # Helper functions @@ -54,8 +54,8 @@ def test_tx_serialization_hash_function(signed_create_tx): def test_tx_serialization_with_incorrect_hash(signed_create_tx): - from planetmint.common.transaction import Transaction - from planetmint.common.exceptions import InvalidHash + from planetmint.transactions.common.transaction import Transaction + from planetmint.transactions.common.exceptions import InvalidHash tx = signed_create_tx.to_dict() tx['id'] = 'a' * 64 with pytest.raises(InvalidHash): @@ -63,7 +63,7 @@ def test_tx_serialization_with_incorrect_hash(signed_create_tx): def test_tx_serialization_with_no_hash(signed_create_tx): - from planetmint.common.exceptions import InvalidHash + from planetmint.transactions.common.exceptions import InvalidHash tx = signed_create_tx.to_dict() del tx['id'] with pytest.raises(InvalidHash): @@ -104,7 +104,7 @@ def test_validate_fails_metadata_empty_dict(b, create_tx, alice): # Asset def test_transfer_asset_schema(user_sk, signed_transfer_tx): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction tx = signed_transfer_tx.to_dict() validate(tx) tx['id'] = None @@ -149,7 +149,7 @@ def test_no_inputs(b, create_tx, alice): def test_create_single_input(b, create_tx, alice): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction tx = create_tx.to_dict() tx['inputs'] += tx['inputs'] tx = Transaction.from_dict(tx).sign([alice.private_key]).to_dict() @@ -161,7 +161,7 @@ def test_create_single_input(b, create_tx, alice): def test_create_tx_no_fulfills(b, create_tx, alice): - from planetmint.common.transaction import Transaction + from planetmint.transactions.common.transaction import Transaction tx = create_tx.to_dict() tx['inputs'][0]['fulfills'] = {'transaction_id': 'a' * 64, 'output_index': 0} @@ -213,8 +213,6 @@ def test_high_amounts(b, create_tx, alice): # Conditions def test_handle_threshold_overflow(): - from planetmint.common import transaction - cond = { 'type': 'ed25519-sha-256', 'public_key': 'a' * 43, @@ -226,18 +224,17 @@ def test_handle_threshold_overflow(): 'subconditions': [cond], } with pytest.raises(ThresholdTooDeep): - transaction._fulfillment_from_details(cond) + _fulfillment_from_details(cond) def test_unsupported_condition_type(): - from planetmint.common import transaction from cryptoconditions.exceptions import UnsupportedTypeError with pytest.raises(UnsupportedTypeError): - transaction._fulfillment_from_details({'type': 'a'}) + _fulfillment_from_details({'type': 'a'}) with pytest.raises(UnsupportedTypeError): - transaction._fulfillment_to_details(MagicMock(type_name='a')) + _fulfillment_to_details(MagicMock(type_name='a')) ################################################################################ diff --git a/tests/web/test_outputs.py b/tests/web/test_outputs.py index db4e77a..112526a 100644 --- a/tests/web/test_outputs.py +++ b/tests/web/test_outputs.py @@ -84,7 +84,7 @@ def test_get_outputs_endpoint_with_invalid_spent(client, user_pk): @pytest.mark.abci def test_get_divisble_transactions_returns_500(b, client): from planetmint.models import Transaction - from planetmint.common import crypto + from planetmint.transactions.common import crypto import json TX_ENDPOINT = '/api/v1/transactions' diff --git a/tests/web/test_transactions.py b/tests/web/test_transactions.py index 3d2a73d..11846e4 100644 --- a/tests/web/test_transactions.py +++ b/tests/web/test_transactions.py @@ -14,10 +14,9 @@ try: except ImportError: from sha3 import sha3_256 -from planetmint.common import crypto -from planetmint.common.transaction_mode_types import (BROADCAST_TX_COMMIT, - BROADCAST_TX_ASYNC, - BROADCAST_TX_SYNC) +from planetmint.transactions.common import crypto +from planetmint.transactions.common.transaction_mode_types import ( + BROADCAST_TX_COMMIT, BROADCAST_TX_ASYNC, BROADCAST_TX_SYNC) TX_ENDPOINT = '/api/v1/transactions/' @@ -133,7 +132,7 @@ def test_post_create_transaction_with_invalid_key(b, client, field, value, @pytest.mark.abci @patch('planetmint.web.views.base.logger') def test_post_create_transaction_with_invalid_id(mock_logger, b, client): - from planetmint.common.exceptions import InvalidHash + from planetmint.transactions.common.exceptions import InvalidHash from planetmint.models import Transaction user_priv, user_pub = crypto.generate_key_pair() @@ -170,7 +169,7 @@ def test_post_create_transaction_with_invalid_id(mock_logger, b, client): def test_post_create_transaction_with_invalid_signature(mock_logger, b, client): - from planetmint.common.exceptions import InvalidSignature + from planetmint.transactions.common.exceptions import InvalidSignature from planetmint.models import Transaction user_priv, user_pub = crypto.generate_key_pair() @@ -274,7 +273,7 @@ def test_post_create_transaction_with_invalid_schema(mock_logger, client): )) @patch('planetmint.web.views.base.logger') def test_post_invalid_transaction(mock_logger, client, exc, msg, monkeypatch,): - from planetmint.common import exceptions + from planetmint.transactions.common import exceptions exc_cls = getattr(exceptions, exc) def mock_validation(self_, tx): @@ -326,7 +325,7 @@ def test_post_transfer_transaction_endpoint(client, user_pk, user_sk, posted_cre @pytest.mark.abci def test_post_invalid_transfer_transaction_returns_400(client, user_pk, posted_create_tx): from planetmint.models import Transaction - from planetmint.common.exceptions import InvalidSignature + from planetmint.transactions.common.exceptions import InvalidSignature transfer_tx = Transaction.transfer(posted_create_tx.to_inputs(), [([user_pk], 1)], @@ -344,7 +343,7 @@ def test_post_invalid_transfer_transaction_returns_400(client, user_pk, posted_c @pytest.mark.abci def test_post_wrong_asset_division_transfer_returns_400(b, client, user_pk): from planetmint.models import Transaction - from planetmint.common.exceptions import AmountError + from planetmint.transactions.common.exceptions import AmountError priv_key, pub_key = crypto.generate_key_pair() @@ -425,7 +424,7 @@ def test_transactions_get_list_bad(client): ]) def test_post_transaction_valid_modes(mock_post, client, mode): from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair def _mock_post(*args, **kwargs): return Mock(json=Mock(return_value={'result': {'code': 0}})) @@ -446,7 +445,7 @@ def test_post_transaction_valid_modes(mock_post, client, mode): @pytest.mark.abci def test_post_transaction_invalid_mode(client): from planetmint.models import Transaction - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], diff --git a/tests/web/test_websocket_server.py b/tests/web/test_websocket_server.py index da83a4e..05b45fc 100644 --- a/tests/web/test_websocket_server.py +++ b/tests/web/test_websocket_server.py @@ -22,7 +22,7 @@ class MockWebSocket: def test_eventify_block_works_with_any_transaction(): from planetmint.web.websocket_server import eventify_block - from planetmint.common.crypto import generate_key_pair + from planetmint.transactions.common.crypto import generate_key_pair from planetmint.lib import Transaction alice = generate_key_pair() @@ -139,7 +139,7 @@ async def test_websocket_block_event(b, test_client, loop): from planetmint import events from planetmint.web.websocket_server import init_app, POISON_PILL, EVENTS_ENDPOINT from planetmint.models import Transaction - from planetmint.common import crypto + from planetmint.transactions.common import crypto user_priv, user_pub = crypto.generate_key_pair() tx = Transaction.create([user_pub], [([user_pub], 1)]) @@ -180,7 +180,7 @@ def test_integration_from_webapi_to_websocket(monkeypatch, client, loop): import random import aiohttp - from planetmint.common import crypto + from planetmint.transactions.common import crypto # TODO processes does not exist anymore, when reactivating this test it # will fail because of this from planetmint import processes From 0fee3607ee4f230ef808abc60359c043eb3d7a61 Mon Sep 17 00:00:00 2001 From: Sangat Das Date: Mon, 21 Mar 2022 19:52:10 +0000 Subject: [PATCH 64/93] Remove create and transfer code snippets from transaction.py Signed-off-by: Sangat Das --- .../generate_http_server_api_documentation.py | 11 +- planetmint/transactions/common/transaction.py | 131 ------------------ .../transactions/types/assets/create.py | 6 +- .../transactions/types/assets/transfer.py | 4 +- .../transactions/types/elections/election.py | 2 +- .../transactions/types/elections/vote.py | 2 +- tests/assets/test_digital_assets.py | 21 ++- tests/assets/test_divisible_assets.py | 105 +++++++------- tests/backend/localmongodb/test_queries.py | 20 +-- tests/commands/test_commands.py | 6 +- tests/common/test_memoize.py | 7 +- tests/common/test_transaction.py | 54 ++++---- tests/conftest.py | 16 +-- ...bigchain_api.py => test_planetmint_api.py} | 64 ++++----- tests/tendermint/test_core.py | 18 +-- tests/tendermint/test_fastquery.py | 21 +-- tests/tendermint/test_integration.py | 6 +- tests/tendermint/test_lib.py | 40 +++--- tests/test_core.py | 18 +-- tests/test_parallel_validation.py | 10 +- tests/test_txlist.py | 9 +- tests/web/test_assets.py | 7 +- tests/web/test_block_tendermint.py | 6 +- tests/web/test_metadata.py | 9 +- tests/web/test_transactions.py | 38 ++--- tests/web/test_websocket_server.py | 10 +- 26 files changed, 251 insertions(+), 390 deletions(-) rename tests/db/{test_bigchain_api.py => test_planetmint_api.py} (89%) diff --git a/docs/root/generate_http_server_api_documentation.py b/docs/root/generate_http_server_api_documentation.py index 4b84d57..1bf66ae 100644 --- a/docs/root/generate_http_server_api_documentation.py +++ b/docs/root/generate_http_server_api_documentation.py @@ -9,8 +9,11 @@ import json import os import os.path -from planetmint.transactions.common.transaction import Transaction, Input, TransactionLink +from planetmint.transactions.common.input import Input +from planetmint.transactions.common.transaction_link import TransactionLink from planetmint import lib +from planetmint.transactions.types.assets.create import Create +from planetmint.transactions.types.assets.transfer import Transfer from planetmint.web import server @@ -133,7 +136,7 @@ def main(): privkey = 'CfdqtD7sS7FgkMoGPXw55MVGGFwQLAoHYTcBhZDtF99Z' pubkey = '4K9sWUMFwTgaDGPfdynrbxWqWS6sWmKbZoTjxLtVUibD' asset = {'msg': 'Hello Planetmint!'} - tx = Transaction.create([pubkey], [([pubkey], 1)], asset=asset, metadata={'sequence': 0}) + tx = Create.generate([pubkey], [([pubkey], 1)], asset=asset, metadata={'sequence': 0}) tx = tx.sign([privkey]) ctx['tx'] = pretty_json(tx.to_dict()) ctx['public_keys'] = tx.outputs[0].public_keys[0] @@ -147,7 +150,7 @@ def main(): input_ = Input(fulfillment=tx.outputs[cid].fulfillment, fulfills=TransactionLink(txid=tx.id, output=cid), owners_before=tx.outputs[cid].public_keys) - tx_transfer = Transaction.transfer([input_], [([pubkey_transfer], 1)], asset_id=tx.id, metadata={'sequence': 1}) + tx_transfer = Transfer.generate([input_], [([pubkey_transfer], 1)], asset_id=tx.id, metadata={'sequence': 1}) tx_transfer = tx_transfer.sign([privkey]) ctx['tx_transfer'] = pretty_json(tx_transfer.to_dict()) ctx['public_keys_transfer'] = tx_transfer.outputs[0].public_keys[0] @@ -160,7 +163,7 @@ def main(): input_ = Input(fulfillment=tx_transfer.outputs[cid].fulfillment, fulfills=TransactionLink(txid=tx_transfer.id, output=cid), owners_before=tx_transfer.outputs[cid].public_keys) - tx_transfer_last = Transaction.transfer([input_], [([pubkey_transfer_last], 1)], + tx_transfer_last = Transfer.generate([input_], [([pubkey_transfer_last], 1)], asset_id=tx.id, metadata={'sequence': 2}) tx_transfer_last = tx_transfer_last.sign([privkey_transfer]) ctx['tx_transfer_last'] = pretty_json(tx_transfer_last.to_dict()) diff --git a/planetmint/transactions/common/transaction.py b/planetmint/transactions/common/transaction.py index e89aa6b..c21e99f 100644 --- a/planetmint/transactions/common/transaction.py +++ b/planetmint/transactions/common/transaction.py @@ -167,137 +167,6 @@ class Transaction(object): def _hash(self): self._id = hash_data(self.serialized) - @classmethod - def validate_create(cls, tx_signers, recipients, asset, metadata): - if not isinstance(tx_signers, list): - raise TypeError('`tx_signers` must be a list instance') - if not isinstance(recipients, list): - raise TypeError('`recipients` must be a list instance') - if len(tx_signers) == 0: - raise ValueError('`tx_signers` list cannot be empty') - if len(recipients) == 0: - raise ValueError('`recipients` list cannot be empty') - if not (asset is None or isinstance(asset, dict)): - raise TypeError('`asset` must be a dict or None') - if not (metadata is None or isinstance(metadata, dict)): - raise TypeError('`metadata` must be a dict or None') - - inputs = [] - outputs = [] - - # generate_outputs - for recipient in recipients: - if not isinstance(recipient, tuple) or len(recipient) != 2: - raise ValueError(('Each `recipient` in the list must be a' - ' tuple of `([],' - ' )`')) - pub_keys, amount = recipient - outputs.append(Output.generate(pub_keys, amount)) - - # generate inputs - inputs.append(Input.generate(tx_signers)) - - return (inputs, outputs) - - @classmethod - def create(cls, tx_signers, recipients, metadata=None, asset=None): - """A simple way to generate a `CREATE` transaction. - - Note: - This method currently supports the following Cryptoconditions - use cases: - - Ed25519 - - ThresholdSha256 - - Additionally, it provides support for the following Planetmint - use cases: - - Multiple inputs and outputs. - - Args: - tx_signers (:obj:`list` of :obj:`str`): A list of keys that - represent the signers of the CREATE Transaction. - recipients (:obj:`list` of :obj:`tuple`): A list of - ([keys],amount) that represent the recipients of this - Transaction. - metadata (dict): The metadata to be stored along with the - Transaction. - asset (dict): The metadata associated with the asset that will - be created in this Transaction. - - Returns: - :class:`~planetmint.transactions.common.transaction.Transaction` - """ - - (inputs, outputs) = cls.validate_create(tx_signers, recipients, asset, metadata) - return cls(cls.CREATE, {'data': asset}, inputs, outputs, metadata) - - @classmethod - def validate_transfer(cls, inputs, recipients, asset_id, metadata): - if not isinstance(inputs, list): - raise TypeError('`inputs` must be a list instance') - if len(inputs) == 0: - raise ValueError('`inputs` must contain at least one item') - if not isinstance(recipients, list): - raise TypeError('`recipients` must be a list instance') - if len(recipients) == 0: - raise ValueError('`recipients` list cannot be empty') - - outputs = [] - for recipient in recipients: - if not isinstance(recipient, tuple) or len(recipient) != 2: - raise ValueError(('Each `recipient` in the list must be a' - ' tuple of `([],' - ' )`')) - pub_keys, amount = recipient - outputs.append(Output.generate(pub_keys, amount)) - - if not isinstance(asset_id, str): - raise TypeError('`asset_id` must be a string') - - return (deepcopy(inputs), outputs) - - @classmethod - def transfer(cls, inputs, recipients, asset_id, metadata=None): - """A simple way to generate a `TRANSFER` transaction. - - Note: - Different cases for threshold conditions: - - Combining multiple `inputs` with an arbitrary number of - `recipients` can yield interesting cases for the creation of - threshold conditions we'd like to support. The following - notation is proposed: - - 1. The index of a `recipient` corresponds to the index of - an input: - e.g. `transfer([input1], [a])`, means `input1` would now be - owned by user `a`. - - 2. `recipients` can (almost) get arbitrary deeply nested, - creating various complex threshold conditions: - e.g. `transfer([inp1, inp2], [[a, [b, c]], d])`, means - `a`'s signature would have a 50% weight on `inp1` - compared to `b` and `c` that share 25% of the leftover - weight respectively. `inp2` is owned completely by `d`. - - Args: - inputs (:obj:`list` of :class:`~planetmint.transactions.common.transaction. - Input`): Converted `Output`s, intended to - be used as inputs in the transfer to generate. - recipients (:obj:`list` of :obj:`tuple`): A list of - ([keys],amount) that represent the recipients of this - Transaction. - asset_id (str): The asset ID of the asset to be transferred in - this Transaction. - metadata (dict): Python dictionary to be stored along with the - Transaction. - - Returns: - :class:`~planetmint.transactions.common.transaction.Transaction` - """ - (inputs, outputs) = cls.validate_transfer(inputs, recipients, asset_id, metadata) - return cls(cls.TRANSFER, {'id': asset_id}, inputs, outputs, metadata) - def __eq__(self, other): try: other = other.to_dict() diff --git a/planetmint/transactions/types/assets/create.py b/planetmint/transactions/types/assets/create.py index d8a1222..3a38783 100644 --- a/planetmint/transactions/types/assets/create.py +++ b/planetmint/transactions/types/assets/create.py @@ -3,7 +3,7 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -from planetmint.transactions.common.transaction import Transaction +from planetmint.models import Transaction from planetmint.transactions.common.input import Input from planetmint.transactions.common.output import Output @@ -13,7 +13,7 @@ class Create(Transaction): ALLOWED_OPERATIONS = (OPERATION,) @classmethod - def validate(self, tx_signers, recipients, asset, metadata): + def validate_create(self, tx_signers, recipients, asset, metadata): if not isinstance(tx_signers, list): raise TypeError('`tx_signers` must be a list instance') if not isinstance(recipients, list): @@ -73,5 +73,5 @@ class Create(Transaction): :class:`~planetmint.common.transaction.Transaction` """ - (inputs, outputs) = cls.validate(tx_signers, recipients, asset, metadata) + (inputs, outputs) = cls.validate_create(tx_signers, recipients, asset, metadata) return cls(cls.OPERATION, {'data': asset}, inputs, outputs, metadata) diff --git a/planetmint/transactions/types/assets/transfer.py b/planetmint/transactions/types/assets/transfer.py index 9fb709b..a658bc0 100644 --- a/planetmint/transactions/types/assets/transfer.py +++ b/planetmint/transactions/types/assets/transfer.py @@ -3,7 +3,7 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -from planetmint.transactions.common.transaction import Transaction +from planetmint.models import Transaction from planetmint.transactions.common.output import Output from copy import deepcopy @@ -13,7 +13,7 @@ class Transfer(Transaction): ALLOWED_OPERATIONS = (OPERATION,) @classmethod - def validate(cls, inputs, recipients, asset_id, metadata): + def validate_transfer(cls, inputs, recipients, asset_id, metadata): if not isinstance(inputs, list): raise TypeError('`inputs` must be a list instance') if len(inputs) == 0: diff --git a/planetmint/transactions/types/elections/election.py b/planetmint/transactions/types/elections/election.py index d74fcbd..984d179 100644 --- a/planetmint/transactions/types/elections/election.py +++ b/planetmint/transactions/types/elections/election.py @@ -143,7 +143,7 @@ class Election(Transaction): uuid = uuid4() election_data['seed'] = str(uuid) - (inputs, outputs) = cls.validate_create(initiator, voters, election_data, metadata) + (inputs, outputs) = Create.validate_create(initiator, voters, election_data, metadata) election = cls(cls.OPERATION, {'data': election_data}, inputs, outputs, metadata) cls.validate_schema(election.to_dict()) return election diff --git a/planetmint/transactions/types/elections/vote.py b/planetmint/transactions/types/elections/vote.py index a4b25f3..9b8c33b 100644 --- a/planetmint/transactions/types/elections/vote.py +++ b/planetmint/transactions/types/elections/vote.py @@ -10,7 +10,7 @@ from planetmint.transactions.common.schema import ( _validate_schema, TX_SCHEMA_COMMON, TX_SCHEMA_TRANSFER, TX_SCHEMA_VOTE) -class Vote(Transaction): +class Vote(Transfer): OPERATION = 'VOTE' # NOTE: This class inherits TRANSFER txn type. The `TRANSFER` property is diff --git a/tests/assets/test_digital_assets.py b/tests/assets/test_digital_assets.py index b23b05d..3a5b88b 100644 --- a/tests/assets/test_digital_assets.py +++ b/tests/assets/test_digital_assets.py @@ -5,12 +5,11 @@ import pytest import random - +from planetmint.transactions.types.assets.create import Create +from planetmint.transactions.types.assets.transfer import Transfer def test_asset_transfer(b, signed_create_tx, user_pk, user_sk): - from planetmint.models import Transaction - - tx_transfer = Transaction.transfer(signed_create_tx.to_inputs(), [([user_pk], 1)], + tx_transfer = Transfer.generate(signed_create_tx.to_inputs(), [([user_pk], 1)], signed_create_tx.id) tx_transfer_signed = tx_transfer.sign([user_sk]) @@ -22,9 +21,8 @@ def test_asset_transfer(b, signed_create_tx, user_pk, user_sk): def test_validate_transfer_asset_id_mismatch(b, signed_create_tx, user_pk, user_sk): from planetmint.transactions.common.exceptions import AssetIdMismatch - from planetmint.models import Transaction - tx_transfer = Transaction.transfer(signed_create_tx.to_inputs(), [([user_pk], 1)], + tx_transfer = Transfer.generate(signed_create_tx.to_inputs(), [([user_pk], 1)], signed_create_tx.id) tx_transfer.asset['id'] = 'a' * 64 tx_transfer_signed = tx_transfer.sign([user_sk]) @@ -37,14 +35,14 @@ def test_validate_transfer_asset_id_mismatch(b, signed_create_tx, user_pk, user_ def test_get_asset_id_create_transaction(alice, user_pk): from planetmint.models import Transaction - tx_create = Transaction.create([alice.public_key], [([user_pk], 1)]) + tx_create = Create.generate([alice.public_key], [([user_pk], 1)]) assert Transaction.get_asset_id(tx_create) == tx_create.id def test_get_asset_id_transfer_transaction(b, signed_create_tx, user_pk): from planetmint.models import Transaction - tx_transfer = Transaction.transfer(signed_create_tx.to_inputs(), [([user_pk], 1)], + tx_transfer = Transfer.generate(signed_create_tx.to_inputs(), [([user_pk], 1)], signed_create_tx.id) asset_id = Transaction.get_asset_id(tx_transfer) assert asset_id == tx_transfer.asset['id'] @@ -54,10 +52,10 @@ def test_asset_id_mismatch(alice, user_pk): from planetmint.models import Transaction from planetmint.transactions.common.exceptions import AssetIdMismatch - tx1 = Transaction.create([alice.public_key], [([user_pk], 1)], + tx1 = Create.generate([alice.public_key], [([user_pk], 1)], metadata={'msg': random.random()}) tx1.sign([alice.private_key]) - tx2 = Transaction.create([alice.public_key], [([user_pk], 1)], + tx2 = Create.generate([alice.public_key], [([user_pk], 1)], metadata={'msg': random.random()}) tx2.sign([alice.private_key]) @@ -66,8 +64,7 @@ def test_asset_id_mismatch(alice, user_pk): def test_create_valid_divisible_asset(b, user_pk, user_sk): - from planetmint.models import Transaction - tx = Transaction.create([user_pk], [([user_pk], 2)]) + tx = Create.generate([user_pk], [([user_pk], 2)]) tx_signed = tx.sign([user_sk]) assert tx_signed.validate(b) == tx_signed diff --git a/tests/assets/test_divisible_assets.py b/tests/assets/test_divisible_assets.py index 570be4b..d9d680f 100644 --- a/tests/assets/test_divisible_assets.py +++ b/tests/assets/test_divisible_assets.py @@ -3,9 +3,12 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 + import pytest import random +from planetmint.transactions.types.assets.create import Create +from planetmint.transactions.types.assets.transfer import Transfer from planetmint.transactions.common.exceptions import DoubleSpend @@ -15,9 +18,9 @@ from planetmint.transactions.common.exceptions import DoubleSpend # Single output # Single owners_after def test_single_in_single_own_single_out_single_own_create(alice, user_pk, b): - from planetmint.models import Transaction + - tx = Transaction.create([alice.public_key], [([user_pk], 100)], asset={'name': random.random()}) + tx = Create.generate([alice.public_key], [([user_pk], 100)], asset={'name': random.random()}) tx_signed = tx.sign([alice.private_key]) assert tx_signed.validate(b) == tx_signed @@ -32,9 +35,9 @@ def test_single_in_single_own_single_out_single_own_create(alice, user_pk, b): # Multiple outputs # Single owners_after per output def test_single_in_single_own_multiple_out_single_own_create(alice, user_pk, b): - from planetmint.models import Transaction + - tx = Transaction.create([alice.public_key], [([user_pk], 50), ([user_pk], 50)], + tx = Create.generate([alice.public_key], [([user_pk], 50), ([user_pk], 50)], asset={'name': random.random()}) tx_signed = tx.sign([alice.private_key]) @@ -51,9 +54,8 @@ def test_single_in_single_own_multiple_out_single_own_create(alice, user_pk, b): # Single output # Multiple owners_after def test_single_in_single_own_single_out_multiple_own_create(alice, user_pk, b): - from planetmint.models import Transaction - tx = Transaction.create([alice.public_key], [([user_pk, user_pk], 100)], asset={'name': random.random()}) + tx = Create.generate([alice.public_key], [([user_pk, user_pk], 100)], asset={'name': random.random()}) tx_signed = tx.sign([alice.private_key]) assert tx_signed.validate(b) == tx_signed @@ -74,9 +76,8 @@ def test_single_in_single_own_single_out_multiple_own_create(alice, user_pk, b): # Mix: one output with a single owners_after, one output with multiple # owners_after def test_single_in_single_own_multiple_out_mix_own_create(alice, user_pk, b): - from planetmint.models import Transaction - tx = Transaction.create([alice.public_key], [([user_pk], 50), ([user_pk, user_pk], 50)], + tx = Create.generate([alice.public_key], [([user_pk], 50), ([user_pk, user_pk], 50)], asset={'name': random.random()}) tx_signed = tx.sign([alice.private_key]) @@ -98,10 +99,10 @@ def test_single_in_single_own_multiple_out_mix_own_create(alice, user_pk, b): # Output combinations already tested above def test_single_in_multiple_own_single_out_single_own_create(alice, b, user_pk, user_sk): - from planetmint.models import Transaction + from planetmint.transactions.common.utils import _fulfillment_to_details - tx = Transaction.create([alice.public_key, user_pk], [([user_pk], 100)], asset={'name': random.random()}) + tx = Create.generate([alice.public_key, user_pk], [([user_pk], 100)], asset={'name': random.random()}) tx_signed = tx.sign([alice.private_key, user_sk]) assert tx_signed.validate(b) == tx_signed assert len(tx_signed.outputs) == 1 @@ -120,14 +121,13 @@ def test_single_in_multiple_own_single_out_single_own_create(alice, b, user_pk, # Single owners_after def test_single_in_single_own_single_out_single_own_transfer(alice, b, user_pk, user_sk): - from planetmint.models import Transaction # CREATE divisible asset - tx_create = Transaction.create([alice.public_key], [([user_pk], 100)], asset={'name': random.random()}) + tx_create = Create.generate([alice.public_key], [([user_pk], 100)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([alice.private_key]) # TRANSFER - tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([alice.public_key], 100)], + tx_transfer = Transfer.generate(tx_create.to_inputs(), [([alice.public_key], 100)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([user_sk]) @@ -146,14 +146,13 @@ def test_single_in_single_own_single_out_single_own_transfer(alice, b, user_pk, # Single owners_after def test_single_in_single_own_multiple_out_single_own_transfer(alice, b, user_pk, user_sk): - from planetmint.models import Transaction # CREATE divisible asset - tx_create = Transaction.create([alice.public_key], [([user_pk], 100)], asset={'name': random.random()}) + tx_create = Create.generate([alice.public_key], [([user_pk], 100)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([alice.private_key]) # TRANSFER - tx_transfer = Transaction.transfer(tx_create.to_inputs(), + tx_transfer = Transfer.generate(tx_create.to_inputs(), [([alice.public_key], 50), ([alice.public_key], 50)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([user_sk]) @@ -174,14 +173,13 @@ def test_single_in_single_own_multiple_out_single_own_transfer(alice, b, user_pk # Multiple owners_after def test_single_in_single_own_single_out_multiple_own_transfer(alice, b, user_pk, user_sk): - from planetmint.models import Transaction # CREATE divisible asset - tx_create = Transaction.create([alice.public_key], [([user_pk], 100)], asset={'name': random.random()}) + tx_create = Create.generate([alice.public_key], [([user_pk], 100)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([alice.private_key]) # TRANSFER - tx_transfer = Transaction.transfer(tx_create.to_inputs(), + tx_transfer = Transfer.generate(tx_create.to_inputs(), [([alice.public_key, alice.public_key], 100)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([user_sk]) @@ -211,14 +209,13 @@ def test_single_in_single_own_single_out_multiple_own_transfer(alice, b, user_pk # owners_after def test_single_in_single_own_multiple_out_mix_own_transfer(alice, b, user_pk, user_sk): - from planetmint.models import Transaction # CREATE divisible asset - tx_create = Transaction.create([alice.public_key], [([user_pk], 100)], asset={'name': random.random()}) + tx_create = Create.generate([alice.public_key], [([user_pk], 100)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([alice.private_key]) # TRANSFER - tx_transfer = Transaction.transfer(tx_create.to_inputs(), + tx_transfer = Transfer.generate(tx_create.to_inputs(), [([alice.public_key], 50), ([alice.public_key, alice.public_key], 50)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([user_sk]) @@ -248,16 +245,16 @@ def test_single_in_single_own_multiple_out_mix_own_transfer(alice, b, user_pk, # Single owners_after def test_single_in_multiple_own_single_out_single_own_transfer(alice, b, user_pk, user_sk): - from planetmint.models import Transaction + from planetmint.transactions.common.utils import _fulfillment_to_details # CREATE divisible asset - tx_create = Transaction.create([alice.public_key], [([alice.public_key, user_pk], 100)], + tx_create = Create.generate([alice.public_key], [([alice.public_key, user_pk], 100)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([alice.private_key]) # TRANSFER - tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([alice.public_key], 100)], + tx_transfer = Transfer.generate(tx_create.to_inputs(), [([alice.public_key], 100)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([alice.private_key, user_sk]) @@ -284,15 +281,14 @@ def test_single_in_multiple_own_single_out_single_own_transfer(alice, b, user_pk # Single owners_after def test_multiple_in_single_own_single_out_single_own_transfer(alice, b, user_pk, user_sk): - from planetmint.models import Transaction # CREATE divisible asset - tx_create = Transaction.create([alice.public_key], [([user_pk], 50), ([user_pk], 50)], + tx_create = Create.generate([alice.public_key], [([user_pk], 50), ([user_pk], 50)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([alice.private_key]) # TRANSFER - tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([alice.public_key], 100)], + tx_transfer = Transfer.generate(tx_create.to_inputs(), [([alice.public_key], 100)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([user_sk]) @@ -315,17 +311,17 @@ def test_multiple_in_single_own_single_out_single_own_transfer(alice, b, user_pk # Single owners_after def test_multiple_in_multiple_own_single_out_single_own_transfer(alice, b, user_pk, user_sk): - from planetmint.models import Transaction + from planetmint.transactions.common.utils import _fulfillment_to_details # CREATE divisible asset - tx_create = Transaction.create([alice.public_key], [([user_pk, alice.public_key], 50), + tx_create = Create.generate([alice.public_key], [([user_pk, alice.public_key], 50), ([user_pk, alice.public_key], 50)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([alice.private_key]) # TRANSFER - tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([alice.public_key], 100)], + tx_transfer = Transfer.generate(tx_create.to_inputs(), [([alice.public_key], 100)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([alice.private_key, user_sk]) @@ -356,16 +352,16 @@ def test_multiple_in_multiple_own_single_out_single_own_transfer(alice, b, user_ # Single owners_after def test_muiltiple_in_mix_own_multiple_out_single_own_transfer(alice, b, user_pk, user_sk): - from planetmint.models import Transaction + from planetmint.transactions.common.utils import _fulfillment_to_details # CREATE divisible asset - tx_create = Transaction.create([alice.public_key], [([user_pk], 50), ([user_pk, alice.public_key], 50)], + tx_create = Create.generate([alice.public_key], [([user_pk], 50), ([user_pk, alice.public_key], 50)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([alice.private_key]) # TRANSFER - tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([alice.public_key], 100)], + tx_transfer = Transfer.generate(tx_create.to_inputs(), [([alice.public_key], 100)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([alice.private_key, user_sk]) @@ -396,16 +392,16 @@ def test_muiltiple_in_mix_own_multiple_out_single_own_transfer(alice, b, user_pk # owners_after def test_muiltiple_in_mix_own_multiple_out_mix_own_transfer(alice, b, user_pk, user_sk): - from planetmint.models import Transaction + from planetmint.transactions.common.utils import _fulfillment_to_details # CREATE divisible asset - tx_create = Transaction.create([alice.public_key], [([user_pk], 50), ([user_pk, alice.public_key], 50)], + tx_create = Create.generate([alice.public_key], [([user_pk], 50), ([user_pk, alice.public_key], 50)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([alice.private_key]) # TRANSFER - tx_transfer = Transaction.transfer(tx_create.to_inputs(), + tx_transfer = Transfer.generate(tx_create.to_inputs(), [([alice.public_key], 50), ([alice.public_key, user_pk], 50)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([alice.private_key, user_sk]) @@ -441,12 +437,11 @@ def test_muiltiple_in_mix_own_multiple_out_mix_own_transfer(alice, b, user_pk, # Single output # Single owners_after def test_multiple_in_different_transactions(alice, b, user_pk, user_sk): - from planetmint.models import Transaction - + # CREATE divisible asset # `b` creates a divisible asset and assigns 50 shares to `b` and # 50 shares to `user_pk` - tx_create = Transaction.create([alice.public_key], [([user_pk], 50), ([alice.public_key], 50)], + tx_create = Create.generate([alice.public_key], [([user_pk], 50), ([alice.public_key], 50)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([alice.private_key]) @@ -454,7 +449,7 @@ def test_multiple_in_different_transactions(alice, b, user_pk, user_sk): # `b` transfers its 50 shares to `user_pk` # after this transaction `user_pk` will have a total of 100 shares # split across two different transactions - tx_transfer1 = Transaction.transfer(tx_create.to_inputs([1]), + tx_transfer1 = Transfer.generate(tx_create.to_inputs([1]), [([user_pk], 50)], asset_id=tx_create.id) tx_transfer1_signed = tx_transfer1.sign([alice.private_key]) @@ -462,7 +457,7 @@ def test_multiple_in_different_transactions(alice, b, user_pk, user_sk): # TRANSFER # `user_pk` combines two different transaction with 50 shares each and # transfers a total of 100 shares back to `b` - tx_transfer2 = Transaction.transfer(tx_create.to_inputs([0]) + + tx_transfer2 = Transfer.generate(tx_create.to_inputs([0]) + tx_transfer1.to_inputs([0]), [([alice.private_key], 100)], asset_id=tx_create.id) @@ -485,18 +480,18 @@ def test_multiple_in_different_transactions(alice, b, user_pk, user_sk): # inputs needs to match the amount being sent in the outputs. # In other words `amount_in_inputs - amount_in_outputs == 0` def test_amount_error_transfer(alice, b, user_pk, user_sk): - from planetmint.models import Transaction + from planetmint.transactions.common.exceptions import AmountError # CREATE divisible asset - tx_create = Transaction.create([alice.public_key], [([user_pk], 100)], asset={'name': random.random()}) + tx_create = Create.generate([alice.public_key], [([user_pk], 100)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([alice.private_key]) b.store_bulk_transactions([tx_create_signed]) # TRANSFER # output amount less than input amount - tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([alice.public_key], 50)], + tx_transfer = Transfer.generate(tx_create.to_inputs(), [([alice.public_key], 50)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([user_sk]) @@ -505,7 +500,7 @@ def test_amount_error_transfer(alice, b, user_pk, user_sk): # TRANSFER # output amount greater than input amount - tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([alice.public_key], 101)], + tx_transfer = Transfer.generate(tx_create.to_inputs(), [([alice.public_key], 101)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([user_sk]) @@ -521,15 +516,13 @@ def test_threshold_same_public_key(alice, b, user_pk, user_sk): # Creating threshold conditions with the same key does not make sense but # that does not mean that the code shouldn't work. - from planetmint.models import Transaction - # CREATE divisible asset - tx_create = Transaction.create([alice.public_key], [([user_pk, user_pk], 100)], + tx_create = Create.generate([alice.public_key], [([user_pk, user_pk], 100)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([alice.private_key]) # TRANSFER - tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([alice.public_key], 100)], + tx_transfer = Transfer.generate(tx_create.to_inputs(), [([alice.public_key], 100)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([user_sk, user_sk]) @@ -543,16 +536,16 @@ def test_threshold_same_public_key(alice, b, user_pk, user_sk): def test_sum_amount(alice, b, user_pk, user_sk): - from planetmint.models import Transaction + # CREATE divisible asset with 3 outputs with amount 1 - tx_create = Transaction.create([alice.public_key], [([user_pk], 1), ([user_pk], 1), ([user_pk], 1)], + tx_create = Create.generate([alice.public_key], [([user_pk], 1), ([user_pk], 1), ([user_pk], 1)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([alice.private_key]) # create a transfer transaction with one output and check if the amount # is 3 - tx_transfer = Transaction.transfer(tx_create.to_inputs(), [([alice.public_key], 3)], + tx_transfer = Transfer.generate(tx_create.to_inputs(), [([alice.public_key], 3)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([user_sk]) @@ -568,15 +561,15 @@ def test_sum_amount(alice, b, user_pk, user_sk): def test_divide(alice, b, user_pk, user_sk): - from planetmint.models import Transaction + # CREATE divisible asset with 1 output with amount 3 - tx_create = Transaction.create([alice.public_key], [([user_pk], 3)], asset={'name': random.random()}) + tx_create = Create.generate([alice.public_key], [([user_pk], 3)], asset={'name': random.random()}) tx_create_signed = tx_create.sign([alice.private_key]) # create a transfer transaction with 3 outputs and check if the amount # of each output is 1 - tx_transfer = Transaction.transfer(tx_create.to_inputs(), + tx_transfer = Transfer.generate(tx_create.to_inputs(), [([alice.public_key], 1), ([alice.public_key], 1), ([alice.public_key], 1)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([user_sk]) diff --git a/tests/backend/localmongodb/test_queries.py b/tests/backend/localmongodb/test_queries.py index 0557527..80abb5d 100644 --- a/tests/backend/localmongodb/test_queries.py +++ b/tests/backend/localmongodb/test_queries.py @@ -4,6 +4,8 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 from copy import deepcopy +from planetmint.transactions.types.assets.create import Create +from planetmint.transactions.types.assets.transfer import Transfer import pytest import pymongo @@ -215,16 +217,15 @@ def test_get_owned_ids(signed_create_tx, user_pk): def test_get_spending_transactions(user_pk, user_sk): from planetmint.backend import connect, query - from planetmint.models import Transaction conn = connect() out = [([user_pk], 1)] - tx1 = Transaction.create([user_pk], out * 3) + tx1 = Create.generate([user_pk], out * 3) tx1.sign([user_sk]) inputs = tx1.to_inputs() - tx2 = Transaction.transfer([inputs[0]], out, tx1.id).sign([user_sk]) - tx3 = Transaction.transfer([inputs[1]], out, tx1.id).sign([user_sk]) - tx4 = Transaction.transfer([inputs[2]], out, tx1.id).sign([user_sk]) + tx2 = Transfer.generate([inputs[0]], out, tx1.id).sign([user_sk]) + tx3 = Transfer.generate([inputs[1]], out, tx1.id).sign([user_sk]) + tx4 = Transfer.generate([inputs[2]], out, tx1.id).sign([user_sk]) txns = [deepcopy(tx.to_dict()) for tx in [tx1, tx2, tx3, tx4]] conn.db.transactions.insert_many(txns) @@ -237,7 +238,6 @@ def test_get_spending_transactions(user_pk, user_sk): def test_get_spending_transactions_multiple_inputs(): from planetmint.backend import connect, query - from planetmint.models import Transaction from planetmint.transactions.common.crypto import generate_key_pair conn = connect() (alice_sk, alice_pk) = generate_key_pair() @@ -245,20 +245,20 @@ def test_get_spending_transactions_multiple_inputs(): (carol_sk, carol_pk) = generate_key_pair() out = [([alice_pk], 9)] - tx1 = Transaction.create([alice_pk], out).sign([alice_sk]) + tx1 = Create.generate([alice_pk], out).sign([alice_sk]) inputs1 = tx1.to_inputs() - tx2 = Transaction.transfer([inputs1[0]], + tx2 = Transfer.generate([inputs1[0]], [([alice_pk], 6), ([bob_pk], 3)], tx1.id).sign([alice_sk]) inputs2 = tx2.to_inputs() - tx3 = Transaction.transfer([inputs2[0]], + tx3 = Transfer.generate([inputs2[0]], [([bob_pk], 3), ([carol_pk], 3)], tx1.id).sign([alice_sk]) inputs3 = tx3.to_inputs() - tx4 = Transaction.transfer([inputs2[1], inputs3[0]], + tx4 = Transfer.generate([inputs2[1], inputs3[0]], [([carol_pk], 6)], tx1.id).sign([bob_sk]) diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index 1e9384f..df4c1b8 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -259,16 +259,16 @@ def test_recover_db_on_start(mock_run_recover, @pytest.mark.bdb def test_run_recover(b, alice, bob): from planetmint.commands.planetmint import run_recover - from planetmint.models import Transaction + from planetmint.transactions.types.assets.create import Create from planetmint.lib import Block from planetmint.backend import query - tx1 = Transaction.create([alice.public_key], + tx1 = Create.generate([alice.public_key], [([alice.public_key], 1)], asset={'cycle': 'hero'}, metadata={'name': 'hohenheim'}) \ .sign([alice.private_key]) - tx2 = Transaction.create([bob.public_key], + tx2 = Create.generate([bob.public_key], [([bob.public_key], 1)], asset={'cycle': 'hero'}, metadata={'name': 'hohenheim'}) \ diff --git a/tests/common/test_memoize.py b/tests/common/test_memoize.py index 8665080..dd047cb 100644 --- a/tests/common/test_memoize.py +++ b/tests/common/test_memoize.py @@ -7,6 +7,7 @@ import pytest from copy import deepcopy from planetmint.models import Transaction +from planetmint.transactions.types.assets.create import Create from planetmint.transactions.common.crypto import generate_key_pair from planetmint.transactions.common.memoize import to_dict, from_dict @@ -23,7 +24,7 @@ def test_memoize_to_dict(b): assert to_dict.cache_info().hits == 0 assert to_dict.cache_info().misses == 0 - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset,)\ .sign([alice.private_key]) @@ -49,7 +50,7 @@ def test_memoize_from_dict(b): assert from_dict.cache_info().hits == 0 assert from_dict.cache_info().misses == 0 - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset,)\ .sign([alice.private_key]) @@ -76,7 +77,7 @@ def test_memoize_input_valid(b): assert Transaction._input_valid.cache_info().hits == 0 assert Transaction._input_valid.cache_info().misses == 0 - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset,)\ .sign([alice.private_key]) diff --git a/tests/common/test_transaction.py b/tests/common/test_transaction.py index 84ddb2b..1d20e7d 100644 --- a/tests/common/test_transaction.py +++ b/tests/common/test_transaction.py @@ -11,6 +11,8 @@ 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 pytest import mark, raises try: from hashlib import sha3_256 @@ -690,7 +692,7 @@ def test_create_create_transaction_single_io(user_output, user_pub, data): 'version': Transaction.VERSION, } - tx = Transaction.create([user_pub], [([user_pub], 1)], metadata=data, + tx = Create.generate([user_pub], [([user_pub], 1)], metadata=data, asset=data) tx_dict = tx.to_dict() tx_dict['inputs'][0]['fulfillment'] = None @@ -705,7 +707,7 @@ def test_validate_single_io_create_transaction(user_pub, user_priv, data, asset_definition): from planetmint.transactions.common.transaction import Transaction - tx = Transaction.create([user_pub], [([user_pub], 1)], metadata=data) + tx = Create.generate([user_pub], [([user_pub], 1)], metadata=data) tx = tx.sign([user_priv]) assert tx.inputs_valid() is True @@ -727,7 +729,7 @@ def test_create_create_transaction_multiple_io(user_output, user2_output, user_p 'operation': 'CREATE', 'version': Transaction.VERSION } - tx = Transaction.create([user_pub, user2_pub], + tx = Create.generate([user_pub, user2_pub], [([user_pub], 1), ([user2_pub], 1)], metadata={'message': 'hello'}).to_dict() tx.pop('id') @@ -742,7 +744,7 @@ def test_validate_multiple_io_create_transaction(user_pub, user_priv, from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model - tx = Transaction.create([user_pub, user2_pub], + tx = Create.generate([user_pub, user2_pub], [([user_pub], 1), ([user2_pub], 1)], metadata={'message': 'hello'}) tx = tx.sign([user_priv, user2_priv]) @@ -774,7 +776,7 @@ def test_create_create_transaction_threshold(user_pub, user2_pub, user3_pub, 'operation': 'CREATE', 'version': Transaction.VERSION } - tx = Transaction.create([user_pub], [([user_pub, user2_pub], 1)], + tx = Create.generate([user_pub], [([user_pub, user2_pub], 1)], metadata=data, asset=data) tx_dict = tx.to_dict() tx_dict.pop('id') @@ -788,7 +790,7 @@ def test_validate_threshold_create_transaction(user_pub, user_priv, user2_pub, from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model - tx = Transaction.create([user_pub], [([user_pub, user2_pub], 1)], + tx = Create.generate([user_pub], [([user_pub, user2_pub], 1)], metadata=data) tx = tx.sign([user_priv]) assert tx.inputs_valid() is True @@ -800,22 +802,22 @@ def test_create_create_transaction_with_invalid_parameters(user_pub): from planetmint.transactions.common.transaction import Transaction with raises(TypeError): - Transaction.create('not a list') + Create.generate('not a list') with raises(TypeError): - Transaction.create([], 'not a list') + Create.generate([], 'not a list') with raises(ValueError): - Transaction.create([], [user_pub]) + Create.generate([], [user_pub]) with raises(ValueError): - Transaction.create([user_pub], []) + Create.generate([user_pub], []) with raises(ValueError): - Transaction.create([user_pub], [user_pub]) + Create.generate([user_pub], [user_pub]) with raises(ValueError): - Transaction.create([user_pub], [([user_pub],)]) + Create.generate([user_pub], [([user_pub],)]) with raises(TypeError): - Transaction.create([user_pub], [([user_pub], 1)], + Create.generate([user_pub], [([user_pub], 1)], metadata='not a dict or none') with raises(TypeError): - Transaction.create([user_pub], + Create.generate([user_pub], [([user_pub], 1)], asset='not a dict or none') @@ -858,7 +860,7 @@ def test_create_transfer_transaction_single_io(tx, user_pub, user2_pub, 'version': Transaction.VERSION } inputs = tx.to_inputs([0]) - transfer_tx = Transaction.transfer(inputs, [([user2_pub], 1)], + transfer_tx = Transfer.generate(inputs, [([user2_pub], 1)], asset_id=tx.id) transfer_tx = transfer_tx.sign([user_priv]) transfer_tx = transfer_tx.to_dict() @@ -889,7 +891,7 @@ def test_create_transfer_transaction_multiple_io(user_pub, user_priv, asset_definition): from planetmint.transactions.common.transaction import Transaction - tx = Transaction.create([user_pub], [([user_pub], 1), ([user2_pub], 1)], + tx = Create.generate([user_pub], [([user_pub], 1), ([user2_pub], 1)], metadata={'message': 'hello'}) tx = tx.sign([user_priv]) @@ -921,7 +923,7 @@ def test_create_transfer_transaction_multiple_io(user_pub, user_priv, 'version': Transaction.VERSION } - transfer_tx = Transaction.transfer(tx.to_inputs(), + transfer_tx = Transfer.generate(tx.to_inputs(), [([user2_pub], 1), ([user2_pub], 1)], asset_id=tx.id) transfer_tx = transfer_tx.sign([user_priv, user2_priv]) @@ -944,22 +946,22 @@ def test_create_transfer_with_invalid_parameters(tx, user_pub): from planetmint.transactions.common.transaction import Transaction with raises(TypeError): - Transaction.transfer({}, [], tx.id) + Transfer.generate({}, [], tx.id) with raises(ValueError): - Transaction.transfer([], [], tx.id) + Transfer.generate([], [], tx.id) with raises(TypeError): - Transaction.transfer(['fulfillment'], {}, tx.id) + Transfer.generate(['fulfillment'], {}, tx.id) with raises(ValueError): - Transaction.transfer(['fulfillment'], [], tx.id) + Transfer.generate(['fulfillment'], [], tx.id) with raises(ValueError): - Transaction.transfer(['fulfillment'], [user_pub], tx.id) + Transfer.generate(['fulfillment'], [user_pub], tx.id) with raises(ValueError): - Transaction.transfer(['fulfillment'], [([user_pub],)], tx.id) + Transfer.generate(['fulfillment'], [([user_pub],)], tx.id) with raises(TypeError): - Transaction.transfer(['fulfillment'], [([user_pub], 1)], + Transfer.generate(['fulfillment'], [([user_pub], 1)], tx.id, metadata='not a dict or none') with raises(TypeError): - Transaction.transfer(['fulfillment'], [([user_pub], 1)], + Transfer.generate(['fulfillment'], [([user_pub], 1)], ['not a string']) @@ -1020,7 +1022,7 @@ def test_output_from_dict_invalid_amount(user_output): def test_unspent_outputs_property(merlin, alice, bob, carol): from planetmint.transactions.common.transaction import Transaction - tx = Transaction.create( + tx = Create.generate( [merlin.public_key], [([alice.public_key], 1), ([bob.public_key], 2), diff --git a/tests/conftest.py b/tests/conftest.py index f553538..8216072 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -285,9 +285,9 @@ def mock_get_validators(network_validators): @pytest.fixture def create_tx(alice, user_pk): - from planetmint.models import Transaction + from planetmint.transactions.types.assets.create import Create name = f'I am created by the create_tx fixture. My random identifier is {random.random()}.' - return Transaction.create([alice.public_key], [([user_pk], 1)], asset={'name': name}) + return Create.generate([alice.public_key], [([user_pk], 1)], asset={'name': name}) @pytest.fixture @@ -304,17 +304,17 @@ def posted_create_tx(b, signed_create_tx): @pytest.fixture def signed_transfer_tx(signed_create_tx, user_pk, user_sk): - from planetmint.models import Transaction + from planetmint.transactions.types.assets.transfer import Transfer inputs = signed_create_tx.to_inputs() - tx = Transaction.transfer(inputs, [([user_pk], 1)], asset_id=signed_create_tx.id) + tx = Transfer.generate(inputs, [([user_pk], 1)], asset_id=signed_create_tx.id) return tx.sign([user_sk]) @pytest.fixture def double_spend_tx(signed_create_tx, carol_pubkey, user_sk): - from planetmint.models import Transaction + from planetmint.transactions.types.assets.transfer import Transfer inputs = signed_create_tx.to_inputs() - tx = Transaction.transfer( + tx = Transfer.generate( inputs, [([carol_pubkey], 1)], asset_id=signed_create_tx.id) return tx.sign([user_sk]) @@ -326,11 +326,11 @@ def _get_height(b): @pytest.fixture def inputs(user_pk, b, alice): - from planetmint.models import Transaction + from planetmint.transactions.types.assets.create import Create # create blocks with transactions for `USER` to spend for height in range(1, 4): transactions = [ - Transaction.create( + Create.generate( [alice.public_key], [([user_pk], 1)], metadata={'msg': random.random()}, diff --git a/tests/db/test_bigchain_api.py b/tests/db/test_planetmint_api.py similarity index 89% rename from tests/db/test_bigchain_api.py rename to tests/db/test_planetmint_api.py index 9724cb6..0f08358 100644 --- a/tests/db/test_bigchain_api.py +++ b/tests/db/test_planetmint_api.py @@ -4,6 +4,8 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 from unittest.mock import patch +from planetmint.transactions.types.assets.create import Create +from planetmint.transactions.types.assets.transfer import Transfer import pytest from base58 import b58decode @@ -18,15 +20,15 @@ class TestBigchainApi(object): from planetmint.transactions.common.exceptions import DoubleSpend from planetmint.exceptions import CriticalDoubleSpend - tx = Transaction.create([alice.public_key], [([alice.public_key], 1)]) + tx = Create.generate([alice.public_key], [([alice.public_key], 1)]) tx = tx.sign([alice.private_key]) b.store_bulk_transactions([tx]) - transfer_tx = Transaction.transfer(tx.to_inputs(), [([alice.public_key], 1)], + transfer_tx = Transfer.generate(tx.to_inputs(), [([alice.public_key], 1)], asset_id=tx.id) transfer_tx = transfer_tx.sign([alice.private_key]) - transfer_tx2 = Transaction.transfer(tx.to_inputs(), [([alice.public_key], 2)], + transfer_tx2 = Transfer.generate(tx.to_inputs(), [([alice.public_key], 2)], asset_id=tx.id) transfer_tx2 = transfer_tx2.sign([alice.private_key]) @@ -47,7 +49,7 @@ class TestBigchainApi(object): from planetmint.models import Transaction from planetmint.backend.exceptions import OperationError - tx = Transaction.create([alice.public_key], [([alice.public_key], 1)]) + tx = Create.generate([alice.public_key], [([alice.public_key], 1)]) tx = tx.sign([alice.private_key]) b.store_bulk_transactions([tx]) @@ -64,11 +66,11 @@ class TestBigchainApi(object): asset3 = {'msg': 'Planetmint 3'} # create the transactions - tx1 = Transaction.create([alice.public_key], [([alice.public_key], 1)], + tx1 = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset1).sign([alice.private_key]) - tx2 = Transaction.create([alice.public_key], [([alice.public_key], 1)], + tx2 = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset2).sign([alice.private_key]) - tx3 = Transaction.create([alice.public_key], [([alice.public_key], 1)], + tx3 = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset3).sign([alice.private_key]) # write the transactions to the DB @@ -89,7 +91,7 @@ class TestBigchainApi(object): input = Input(Ed25519Sha256(public_key=b58decode(user_pk)), [user_pk], TransactionLink('somethingsomething', 0)) - tx = Transaction.transfer([input], [([user_pk], 1)], + tx = Transfer.generate([input], [([user_pk], 1)], asset_id='mock_asset_link') with pytest.raises(InputDoesNotExist): tx.validate(b) @@ -99,7 +101,7 @@ class TestBigchainApi(object): asset1 = {'msg': 'Planetmint 1'} - tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], + tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset1).sign([alice.private_key]) b.store_bulk_transactions([tx]) @@ -133,7 +135,7 @@ class TestTransactionValidation(object): input_tx = b.fastquery.get_outputs_by_public_key(user_pk).pop() input_transaction = b.get_transaction(input_tx.txid) sk, pk = generate_key_pair() - tx = Transaction.create([pk], [([user_pk], 1)]) + tx = Create.generate([pk], [([user_pk], 1)]) tx.operation = 'TRANSFER' tx.asset = {'id': input_transaction.id} tx.inputs[0].fulfills = input_tx @@ -164,7 +166,7 @@ class TestMultipleInputs(object): tx_link = b.fastquery.get_outputs_by_public_key(user_pk).pop() input_tx = b.get_transaction(tx_link.txid) inputs = input_tx.to_inputs() - tx = Transaction.transfer(inputs, [([user2_pk], 1)], + tx = Transfer.generate(inputs, [([user2_pk], 1)], asset_id=input_tx.id) tx = tx.sign([user_sk]) @@ -185,7 +187,7 @@ class TestMultipleInputs(object): tx_link = b.fastquery.get_outputs_by_public_key(user_pk).pop() input_tx = b.get_transaction(tx_link.txid) - tx = Transaction.transfer(input_tx.to_inputs(), + tx = Transfer.generate(input_tx.to_inputs(), [([user2_pk, user3_pk], 1)], asset_id=input_tx.id) tx = tx.sign([user_sk]) @@ -205,7 +207,7 @@ class TestMultipleInputs(object): user2_sk, user2_pk = crypto.generate_key_pair() user3_sk, user3_pk = crypto.generate_key_pair() - tx = Transaction.create([alice.public_key], [([user_pk, user2_pk], 1)]) + tx = Create.generate([alice.public_key], [([user_pk, user2_pk], 1)]) tx = tx.sign([alice.private_key]) b.store_bulk_transactions([tx]) @@ -213,7 +215,7 @@ class TestMultipleInputs(object): input_tx = b.get_transaction(owned_input.txid) inputs = input_tx.to_inputs() - transfer_tx = Transaction.transfer(inputs, [([user3_pk], 1)], + transfer_tx = Transfer.generate(inputs, [([user3_pk], 1)], asset_id=input_tx.id) transfer_tx = transfer_tx.sign([user_sk, user2_sk]) @@ -234,7 +236,7 @@ class TestMultipleInputs(object): user3_sk, user3_pk = crypto.generate_key_pair() user4_sk, user4_pk = crypto.generate_key_pair() - tx = Transaction.create([alice.public_key], [([user_pk, user2_pk], 1)]) + tx = Create.generate([alice.public_key], [([user_pk, user2_pk], 1)]) tx = tx.sign([alice.private_key]) b.store_bulk_transactions([tx]) @@ -242,7 +244,7 @@ class TestMultipleInputs(object): tx_link = b.fastquery.get_outputs_by_public_key(user_pk).pop() tx_input = b.get_transaction(tx_link.txid) - tx = Transaction.transfer(tx_input.to_inputs(), + tx = Transfer.generate(tx_input.to_inputs(), [([user3_pk, user4_pk], 1)], asset_id=tx_input.id) tx = tx.sign([user_sk, user2_sk]) @@ -258,7 +260,7 @@ class TestMultipleInputs(object): user2_sk, user2_pk = crypto.generate_key_pair() - tx = Transaction.create([alice.public_key], [([user_pk], 1)]) + tx = Create.generate([alice.public_key], [([user_pk], 1)]) tx = tx.sign([alice.private_key]) b.store_bulk_transactions([tx]) @@ -267,7 +269,7 @@ class TestMultipleInputs(object): assert owned_inputs_user1 == [TransactionLink(tx.id, 0)] assert owned_inputs_user2 == [] - tx_transfer = Transaction.transfer(tx.to_inputs(), [([user2_pk], 1)], + tx_transfer = Transfer.generate(tx.to_inputs(), [([user2_pk], 1)], asset_id=tx.id) tx_transfer = tx_transfer.sign([user_sk]) b.store_bulk_transactions([tx_transfer]) @@ -287,7 +289,7 @@ class TestMultipleInputs(object): user2_sk, user2_pk = crypto.generate_key_pair() # create divisible asset - tx_create = Transaction.create([alice.public_key], [([user_pk], 1), ([user_pk], 1)]) + tx_create = Create.generate([alice.public_key], [([user_pk], 1), ([user_pk], 1)]) tx_create_signed = tx_create.sign([alice.private_key]) b.store_bulk_transactions([tx_create_signed]) @@ -301,7 +303,7 @@ class TestMultipleInputs(object): assert owned_inputs_user2 == [] # transfer divisible asset divided in two outputs - tx_transfer = Transaction.transfer(tx_create.to_inputs(), + tx_transfer = Transfer.generate(tx_create.to_inputs(), [([user2_pk], 1), ([user2_pk], 1)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([user_sk]) @@ -321,7 +323,7 @@ class TestMultipleInputs(object): user2_sk, user2_pk = crypto.generate_key_pair() user3_sk, user3_pk = crypto.generate_key_pair() - tx = Transaction.create([alice.public_key], [([user_pk, user2_pk], 1)]) + tx = Create.generate([alice.public_key], [([user_pk, user2_pk], 1)]) tx = tx.sign([alice.private_key]) b.store_bulk_transactions([tx]) @@ -333,7 +335,7 @@ class TestMultipleInputs(object): assert owned_inputs_user1 == owned_inputs_user2 assert owned_inputs_user1 == expected_owned_inputs_user1 - tx = Transaction.transfer(tx.to_inputs(), [([user3_pk], 1)], + tx = Transfer.generate(tx.to_inputs(), [([user3_pk], 1)], asset_id=tx.id) tx = tx.sign([user_sk, user2_sk]) b.store_bulk_transactions([tx]) @@ -351,7 +353,7 @@ class TestMultipleInputs(object): user2_sk, user2_pk = crypto.generate_key_pair() - tx = Transaction.create([alice.public_key], [([user_pk], 1)]) + tx = Create.generate([alice.public_key], [([user_pk], 1)]) tx = tx.sign([alice.private_key]) b.store_bulk_transactions([tx]) @@ -363,7 +365,7 @@ class TestMultipleInputs(object): assert spent_inputs_user1 is None # create a transaction and send it - tx = Transaction.transfer(tx.to_inputs(), [([user2_pk], 1)], + tx = Transfer.generate(tx.to_inputs(), [([user2_pk], 1)], asset_id=tx.id) tx = tx.sign([user_sk]) b.store_bulk_transactions([tx]) @@ -379,7 +381,7 @@ class TestMultipleInputs(object): user2_sk, user2_pk = crypto.generate_key_pair() # create a divisible asset with 3 outputs - tx_create = Transaction.create([alice.public_key], + tx_create = Create.generate([alice.public_key], [([user_pk], 1), ([user_pk], 1), ([user_pk], 1)]) @@ -393,7 +395,7 @@ class TestMultipleInputs(object): assert b.get_spent(input_tx.txid, input_tx.output) is None # transfer the first 2 inputs - tx_transfer = Transaction.transfer(tx_create.to_inputs()[:2], + tx_transfer = Transfer.generate(tx_create.to_inputs()[:2], [([user2_pk], 1), ([user2_pk], 1)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([user_sk]) @@ -418,7 +420,7 @@ class TestMultipleInputs(object): transactions = [] for i in range(3): payload = {'somedata': i} - tx = Transaction.create([alice.public_key], [([user_pk, user2_pk], 1)], + tx = Create.generate([alice.public_key], [([user_pk, user2_pk], 1)], payload) tx = tx.sign([alice.private_key]) transactions.append(tx) @@ -431,7 +433,7 @@ class TestMultipleInputs(object): assert b.get_spent(input_tx.txid, input_tx.output) is None # create a transaction - tx = Transaction.transfer(transactions[0].to_inputs(), + tx = Transfer.generate(transactions[0].to_inputs(), [([user3_pk], 1)], asset_id=transactions[0].id) tx = tx.sign([user_sk, user2_sk]) @@ -500,7 +502,7 @@ def test_cant_spend_same_input_twice_in_tx(b, alice): from planetmint.transactions.common.exceptions import DoubleSpend # create a divisible asset - tx_create = Transaction.create([alice.public_key], [([alice.public_key], 100)]) + tx_create = Create.generate([alice.public_key], [([alice.public_key], 100)]) tx_create_signed = tx_create.sign([alice.private_key]) assert b.validate_transaction(tx_create_signed) == tx_create_signed @@ -508,7 +510,7 @@ def test_cant_spend_same_input_twice_in_tx(b, alice): # Create a transfer transaction with duplicated fulfillments dup_inputs = tx_create.to_inputs() + tx_create.to_inputs() - tx_transfer = Transaction.transfer(dup_inputs, [([alice.public_key], 200)], + tx_transfer = Transfer.generate(dup_inputs, [([alice.public_key], 200)], asset_id=tx_create.id) tx_transfer_signed = tx_transfer.sign([alice.private_key]) with pytest.raises(DoubleSpend): @@ -524,7 +526,7 @@ def test_transaction_unicode(b, alice): beer_python = {'beer': '\N{BEER MUG}'} beer_json = '{"beer":"\N{BEER MUG}"}' - tx = (Transaction.create([alice.public_key], [([alice.public_key], 100)], beer_python) + tx = (Create.generate([alice.public_key], [([alice.public_key], 100)], beer_python) ).sign([alice.private_key]) tx_1 = copy.deepcopy(tx) diff --git a/tests/tendermint/test_core.py b/tests/tendermint/test_core.py index 581fbe9..c8e7942 100644 --- a/tests/tendermint/test_core.py +++ b/tests/tendermint/test_core.py @@ -4,6 +4,8 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 import json +from planetmint.transactions.types.assets.create import Create +from planetmint.transactions.types.assets.transfer import Transfer import pytest import random @@ -208,7 +210,7 @@ def test_check_tx__signed_create_is_ok(b): alice = generate_key_pair() bob = generate_key_pair() - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([bob.public_key], 1)])\ .sign([alice.private_key]) @@ -225,7 +227,7 @@ def test_check_tx__unsigned_create_is_error(b): alice = generate_key_pair() bob = generate_key_pair() - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([bob.public_key], 1)]) app = App(b) @@ -243,7 +245,7 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(b, init_chain_reque bob = generate_key_pair() events = mp.Queue() - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([bob.public_key], 1)])\ .sign([alice.private_key]) @@ -279,7 +281,7 @@ def test_deliver_tx__double_spend_fails(b, init_chain_request): alice = generate_key_pair() bob = generate_key_pair() - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([bob.public_key], 1)])\ .sign([alice.private_key]) @@ -319,7 +321,7 @@ def test_deliver_transfer_tx__double_spend_fails(b, init_chain_request): 'msg': 'live long and prosper' } - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset)\ .sign([alice.private_key]) @@ -327,7 +329,7 @@ def test_deliver_transfer_tx__double_spend_fails(b, init_chain_request): result = app.deliver_tx(encode_tx_to_bytes(tx)) assert result.code == OkCode - tx_transfer = Transaction.transfer(tx.to_inputs(), + tx_transfer = Transfer.generate(tx.to_inputs(), [([bob.public_key], 1)], asset_id=tx.id)\ .sign([alice.private_key]) @@ -335,7 +337,7 @@ def test_deliver_transfer_tx__double_spend_fails(b, init_chain_request): result = app.deliver_tx(encode_tx_to_bytes(tx_transfer)) assert result.code == OkCode - double_spend = Transaction.transfer(tx.to_inputs(), + double_spend = Transfer.generate(tx.to_inputs(), [([carly.public_key], 1)], asset_id=tx.id)\ .sign([alice.private_key]) @@ -384,7 +386,7 @@ def test_store_pre_commit_state_in_end_block(b, alice, init_chain_request): from planetmint.backend import query from planetmint.models import Transaction - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset={'msg': 'live long and prosper'})\ .sign([alice.private_key]) diff --git a/tests/tendermint/test_fastquery.py b/tests/tendermint/test_fastquery.py index 61f8ac9..d79d511 100644 --- a/tests/tendermint/test_fastquery.py +++ b/tests/tendermint/test_fastquery.py @@ -6,7 +6,8 @@ import pytest from planetmint.transactions.common.transaction import TransactionLink -from planetmint.models import Transaction +from planetmint.transactions.types.assets.create import Create +from planetmint.transactions.types.assets.transfer import Transfer pytestmark = pytest.mark.bdb @@ -14,9 +15,9 @@ pytestmark = pytest.mark.bdb @pytest.fixture def txns(b, user_pk, user_sk, user2_pk, user2_sk): - txs = [Transaction.create([user_pk], [([user2_pk], 1)]).sign([user_sk]), - Transaction.create([user2_pk], [([user_pk], 1)]).sign([user2_sk]), - Transaction.create([user_pk], [([user_pk], 1), ([user2_pk], 1)]) + txs = [Create.generate([user_pk], [([user2_pk], 1)]).sign([user_sk]), + Create.generate([user2_pk], [([user_pk], 1)]).sign([user2_sk]), + Create.generate([user_pk], [([user_pk], 1), ([user2_pk], 1)]) .sign([user_sk])] b.store_bulk_transactions(txs) return txs @@ -35,12 +36,12 @@ def test_get_outputs_by_public_key(b, user_pk, user2_pk, txns): def test_filter_spent_outputs(b, user_pk, user_sk): out = [([user_pk], 1)] - tx1 = Transaction.create([user_pk], out * 2) + tx1 = Create.generate([user_pk], out * 2) tx1.sign([user_sk]) inputs = tx1.to_inputs() - tx2 = Transaction.transfer([inputs[0]], out, tx1.id) + tx2 = Transfer.generate([inputs[0]], out, tx1.id) tx2.sign([user_sk]) # tx2 produces a new unspent. inputs[1] remains unspent. @@ -57,12 +58,12 @@ def test_filter_spent_outputs(b, user_pk, user_sk): def test_filter_unspent_outputs(b, user_pk, user_sk): out = [([user_pk], 1)] - tx1 = Transaction.create([user_pk], out * 2) + tx1 = Create.generate([user_pk], out * 2) tx1.sign([user_sk]) inputs = tx1.to_inputs() - tx2 = Transaction.transfer([inputs[0]], out, tx1.id) + tx2 = Transfer.generate([inputs[0]], out, tx1.id) tx2.sign([user_sk]) # tx2 produces a new unspent. input[1] remains unspent. @@ -80,13 +81,13 @@ def test_outputs_query_key_order(b, user_pk, user_sk, user2_pk, user2_sk): from planetmint import backend from planetmint.backend import connect - tx1 = Transaction.create([user_pk], + tx1 = Create.generate([user_pk], [([user_pk], 3), ([user_pk], 2), ([user_pk], 1)])\ .sign([user_sk]) b.store_bulk_transactions([tx1]) inputs = tx1.to_inputs() - tx2 = Transaction.transfer([inputs[1]], [([user2_pk], 2)], tx1.id).sign([user_sk]) + tx2 = Transfer.generate([inputs[1]], [([user2_pk], 2)], tx1.id).sign([user_sk]) assert tx2.validate(b) tx2_dict = tx2.to_dict() diff --git a/tests/tendermint/test_integration.py b/tests/tendermint/test_integration.py index 45b4db1..15a6eac 100644 --- a/tests/tendermint/test_integration.py +++ b/tests/tendermint/test_integration.py @@ -4,6 +4,7 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 import codecs +from planetmint.transactions.types.assets.create import Create from tendermint.abci import types_pb2 as types import json @@ -23,7 +24,6 @@ def test_app(b, eventqueue_fixture, init_chain_request): from planetmint import App from planetmint.tendermint_utils import calculate_hash from planetmint.transactions.common.crypto import generate_key_pair - from planetmint.models import Transaction app = App(b, eventqueue_fixture) p = ProtocolHandler(app) @@ -49,7 +49,7 @@ def test_app(b, eventqueue_fixture, init_chain_request): alice = generate_key_pair() bob = generate_key_pair() - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([bob.public_key], 1)])\ .sign([alice.private_key]) etxn = json.dumps(tx.to_dict()).encode('utf8') @@ -118,7 +118,7 @@ def test_post_transaction_responses(tendermint_ws_url, b): alice = generate_key_pair() bob = generate_key_pair() - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=None)\ .sign([alice.private_key]) diff --git a/tests/tendermint/test_lib.py b/tests/tendermint/test_lib.py index 55fd2be..211ece9 100644 --- a/tests/tendermint/test_lib.py +++ b/tests/tendermint/test_lib.py @@ -5,6 +5,8 @@ import os from unittest.mock import patch +from planetmint.transactions.types.assets.create import Create +from planetmint.transactions.types.assets.transfer import Transfer try: @@ -25,7 +27,6 @@ from planetmint.lib import Block @pytest.mark.bdb def test_asset_is_separated_from_transaciton(b): import copy - from planetmint.models import Transaction from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() @@ -40,7 +41,7 @@ def test_asset_is_separated_from_transaciton(b): 'tell a lie', 'hurt you']} - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([bob.public_key], 1)], metadata=None, asset=asset)\ @@ -81,11 +82,10 @@ def test_get_empty_block(_0, _1, b): def test_validation_error(b): - from planetmint.models import Transaction from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=None)\ .sign([alice.private_key]).to_dict() @@ -96,12 +96,11 @@ def test_validation_error(b): @patch('requests.post') def test_write_and_post_transaction(mock_post, b): - from planetmint.models import Transaction from planetmint.transactions.common.crypto import generate_key_pair from planetmint.tendermint_utils import encode_transaction alice = generate_key_pair() - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=None)\ .sign([alice.private_key]).to_dict() @@ -123,10 +122,9 @@ def test_write_and_post_transaction(mock_post, b): BROADCAST_TX_COMMIT ]) def test_post_transaction_valid_modes(mock_post, b, mode): - from planetmint.models import Transaction from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=None) \ .sign([alice.private_key]).to_dict() @@ -138,11 +136,10 @@ def test_post_transaction_valid_modes(mock_post, b, mode): def test_post_transaction_invalid_mode(b): - from planetmint.models import Transaction from planetmint.transactions.common.crypto import generate_key_pair from planetmint.transactions.common.exceptions import ValidationError alice = generate_key_pair() - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=None) \ .sign([alice.private_key]).to_dict() @@ -354,28 +351,27 @@ def test_get_utxoset_merkle_root(b, utxoset): @pytest.mark.bdb def test_get_spent_transaction_critical_double_spend(b, alice, bob, carol): - from planetmint.models import Transaction from planetmint.exceptions import CriticalDoubleSpend from planetmint.transactions.common.exceptions import DoubleSpend asset = {'test': 'asset'} - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset)\ .sign([alice.private_key]) - tx_transfer = Transaction.transfer(tx.to_inputs(), + tx_transfer = Transfer.generate(tx.to_inputs(), [([bob.public_key], 1)], asset_id=tx.id)\ .sign([alice.private_key]) - double_spend = Transaction.transfer(tx.to_inputs(), + double_spend = Transfer.generate(tx.to_inputs(), [([carol.public_key], 1)], asset_id=tx.id)\ .sign([alice.private_key]) - same_input_double_spend = Transaction.transfer(tx.to_inputs() + tx.to_inputs(), + same_input_double_spend = Transfer.generate(tx.to_inputs() + tx.to_inputs(), [([bob.public_key], 1)], asset_id=tx.id)\ .sign([alice.private_key]) @@ -404,15 +400,14 @@ def test_get_spent_transaction_critical_double_spend(b, alice, bob, carol): def test_validation_with_transaction_buffer(b): from planetmint.transactions.common.crypto import generate_key_pair - from planetmint.models import Transaction priv_key, pub_key = generate_key_pair() - create_tx = Transaction.create([pub_key], [([pub_key], 10)]).sign([priv_key]) - transfer_tx = Transaction.transfer(create_tx.to_inputs(), + create_tx = Create.generate([pub_key], [([pub_key], 10)]).sign([priv_key]) + transfer_tx = Transfer.generate(create_tx.to_inputs(), [([pub_key], 10)], asset_id=create_tx.id).sign([priv_key]) - double_spend = Transaction.transfer(create_tx.to_inputs(), + double_spend = Transfer.generate(create_tx.to_inputs(), [([pub_key], 10)], asset_id=create_tx.id).sign([priv_key]) @@ -459,21 +454,20 @@ def test_migrate_abci_chain_generates_new_chains(b, chain, block_height, @pytest.mark.bdb def test_get_spent_key_order(b, user_pk, user_sk, user2_pk, user2_sk): from planetmint import backend - from planetmint.models import Transaction from planetmint.transactions.common.crypto import generate_key_pair from planetmint.transactions.common.exceptions import DoubleSpend alice = generate_key_pair() bob = generate_key_pair() - tx1 = Transaction.create([user_pk], + tx1 = Create.generate([user_pk], [([alice.public_key], 3), ([user_pk], 2)], asset=None)\ .sign([user_sk]) b.store_bulk_transactions([tx1]) inputs = tx1.to_inputs() - tx2 = Transaction.transfer([inputs[1]], [([user2_pk], 2)], tx1.id).sign([user_sk]) + tx2 = Transfer.generate([inputs[1]], [([user2_pk], 2)], tx1.id).sign([user_sk]) assert tx2.validate(b) tx2_dict = tx2.to_dict() @@ -483,7 +477,7 @@ def test_get_spent_key_order(b, user_pk, user_sk, user2_pk, user2_sk): backend.query.store_transactions(b.connection, [tx2_dict]) - tx3 = Transaction.transfer([inputs[1]], [([bob.public_key], 2)], tx1.id).sign([user_sk]) + tx3 = Transfer.generate([inputs[1]], [([bob.public_key], 2)], tx1.id).sign([user_sk]) with pytest.raises(DoubleSpend): tx3.validate(b) diff --git a/tests/test_core.py b/tests/test_core.py index 140cd22..d9a6efa 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -4,6 +4,8 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 import json +from planetmint.transactions.types.assets.create import Create +from planetmint.transactions.types.assets.transfer import Transfer import pytest import random @@ -208,7 +210,7 @@ def test_check_tx__signed_create_is_ok(b): alice = generate_key_pair() bob = generate_key_pair() - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([bob.public_key], 1)])\ .sign([alice.private_key]) @@ -225,7 +227,7 @@ def test_check_tx__unsigned_create_is_error(b): alice = generate_key_pair() bob = generate_key_pair() - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([bob.public_key], 1)]) app = App(b) @@ -243,7 +245,7 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(b, init_chain_reque bob = generate_key_pair() events = mp.Queue() - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([bob.public_key], 1)])\ .sign([alice.private_key]) @@ -279,7 +281,7 @@ def test_deliver_tx__double_spend_fails(b, eventqueue_fixture, init_chain_reques alice = generate_key_pair() bob = generate_key_pair() - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([bob.public_key], 1)])\ .sign([alice.private_key]) @@ -319,7 +321,7 @@ def test_deliver_transfer_tx__double_spend_fails(b, init_chain_request): 'msg': 'live long and prosper' } - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset)\ .sign([alice.private_key]) @@ -327,7 +329,7 @@ def test_deliver_transfer_tx__double_spend_fails(b, init_chain_request): result = app.deliver_tx(encode_tx_to_bytes(tx)) assert result.code == OkCode - tx_transfer = Transaction.transfer(tx.to_inputs(), + tx_transfer = Transfer.generate(tx.to_inputs(), [([bob.public_key], 1)], asset_id=tx.id)\ .sign([alice.private_key]) @@ -335,7 +337,7 @@ def test_deliver_transfer_tx__double_spend_fails(b, init_chain_request): result = app.deliver_tx(encode_tx_to_bytes(tx_transfer)) assert result.code == OkCode - double_spend = Transaction.transfer(tx.to_inputs(), + double_spend = Transfer.generate(tx.to_inputs(), [([carly.public_key], 1)], asset_id=tx.id)\ .sign([alice.private_key]) @@ -384,7 +386,7 @@ def test_store_pre_commit_state_in_end_block(b, alice, init_chain_request): from planetmint.backend import query from planetmint.models import Transaction - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset={'msg': 'live long and prosper'})\ .sign([alice.private_key]) diff --git a/tests/test_parallel_validation.py b/tests/test_parallel_validation.py index df2a39d..29e8864 100644 --- a/tests/test_parallel_validation.py +++ b/tests/test_parallel_validation.py @@ -6,8 +6,8 @@ import pytest from planetmint.transactions.common.crypto import generate_key_pair -from planetmint.models import Transaction - +from planetmint.transactions.types.assets.create import Create +from planetmint.transactions.types.assets.transfer import Transfer pytestmark = pytest.mark.tendermint @@ -16,8 +16,8 @@ def generate_create_and_transfer(keypair=None): if not keypair: keypair = generate_key_pair() priv_key, pub_key = keypair - create_tx = Transaction.create([pub_key], [([pub_key], 10)]).sign([priv_key]) - transfer_tx = Transaction.transfer( + create_tx = Create.generate([pub_key], [([pub_key], 10)]).sign([priv_key]) + transfer_tx = Transfer.generate( create_tx.to_inputs(), [([pub_key], 10)], asset_id=create_tx.id).sign([priv_key]) @@ -30,7 +30,7 @@ def test_validation_worker_process_multiple_transactions(b): keypair = generate_key_pair() create_tx, transfer_tx = generate_create_and_transfer(keypair) - double_spend = Transaction.transfer( + double_spend = Transfer.generate( create_tx.to_inputs(), [([keypair.public_key], 10)], asset_id=create_tx.id).sign([keypair.private_key]) diff --git a/tests/test_txlist.py b/tests/test_txlist.py index 50cf55c..8475be2 100644 --- a/tests/test_txlist.py +++ b/tests/test_txlist.py @@ -12,18 +12,19 @@ import pytest @pytest.fixture def txlist(b, user_pk, user2_pk, user_sk, user2_sk): - from planetmint.models import Transaction + from planetmint.transactions.types.assets.create import Create + from planetmint.transactions.types.assets.transfer import Transfer # Create two CREATE transactions - create1 = Transaction.create([user_pk], [([user2_pk], 6)]) \ + create1 = Create.generate([user_pk], [([user2_pk], 6)]) \ .sign([user_sk]) - create2 = Transaction.create([user2_pk], + create2 = Create.generate([user2_pk], [([user2_pk], 5), ([user_pk], 5)]) \ .sign([user2_sk]) # Create a TRANSFER transactions - transfer1 = Transaction.transfer(create1.to_inputs(), + transfer1 = Transfer.generate(create1.to_inputs(), [([user_pk], 8)], create1.id).sign([user2_sk]) diff --git a/tests/web/test_assets.py b/tests/web/test_assets.py index 9c632ef..58136c3 100644 --- a/tests/web/test_assets.py +++ b/tests/web/test_assets.py @@ -4,6 +4,7 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 import pytest +from planetmint.transactions.types.assets.create import Create ASSETS_ENDPOINT = '/api/v1/assets/' @@ -31,7 +32,7 @@ def test_get_assets_tendermint(client, b, alice): # create asset asset = {'msg': 'abc'} - tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], + tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset).sign([alice.private_key]) b.store_bulk_transactions([tx]) @@ -53,9 +54,9 @@ def test_get_assets_limit_tendermint(client, b, alice): # create two assets asset1 = {'msg': 'abc 1'} asset2 = {'msg': 'abc 2'} - tx1 = Transaction.create([alice.public_key], [([alice.public_key], 1)], + tx1 = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset1).sign([alice.private_key]) - tx2 = Transaction.create([alice.public_key], [([alice.public_key], 1)], + tx2 = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset2).sign([alice.private_key]) b.store_bulk_transactions([tx1]) diff --git a/tests/web/test_block_tendermint.py b/tests/web/test_block_tendermint.py index 2accbce..7fb034d 100644 --- a/tests/web/test_block_tendermint.py +++ b/tests/web/test_block_tendermint.py @@ -5,7 +5,7 @@ import pytest -from planetmint.models import Transaction +from planetmint.transactions.types.assets.create import Create from planetmint.lib import Block BLOCKS_ENDPOINT = '/api/v1/blocks/' @@ -15,7 +15,7 @@ BLOCKS_ENDPOINT = '/api/v1/blocks/' @pytest.mark.usefixtures('inputs') def test_get_block_endpoint(b, client, alice): import copy - tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], asset={'cycle': 'hero'}) + tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset={'cycle': 'hero'}) tx = tx.sign([alice.private_key]) # with store_bulk_transactions we use `insert_many` where PyMongo @@ -48,7 +48,7 @@ def test_get_block_returns_404_if_not_found(client): @pytest.mark.bdb def test_get_block_containing_transaction(b, client, alice): - tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], asset={'cycle': 'hero'}) + tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset={'cycle': 'hero'}) tx = tx.sign([alice.private_key]) b.store_bulk_transactions([tx]) diff --git a/tests/web/test_metadata.py b/tests/web/test_metadata.py index d9301f3..9e2acf2 100644 --- a/tests/web/test_metadata.py +++ b/tests/web/test_metadata.py @@ -4,6 +4,7 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 import pytest +from planetmint.transactions.types.assets.create import Create METADATA_ENDPOINT = '/api/v1/metadata/' @@ -22,7 +23,6 @@ def test_get_metadata_with_missing_text_search(client): @pytest.mark.bdb def test_get_metadata_tendermint(client, b, alice): - from planetmint.models import Transaction # test returns empty list when no assets are found res = client.get(METADATA_ENDPOINT + '?search=abc') @@ -32,7 +32,7 @@ def test_get_metadata_tendermint(client, b, alice): # create asset asset = {'msg': 'abc'} metadata = {'key': 'my_meta'} - tx = Transaction.create([alice.public_key], [([alice.public_key], 1)], metadata=metadata, + tx = Create.generate([alice.public_key], [([alice.public_key], 1)], metadata=metadata, asset=asset).sign([alice.private_key]) b.store_bulk_transactions([tx]) @@ -49,18 +49,17 @@ def test_get_metadata_tendermint(client, b, alice): @pytest.mark.bdb def test_get_metadata_limit_tendermint(client, b, alice): - from planetmint.models import Transaction # create two assets asset1 = {'msg': 'abc 1'} meta1 = {'key': 'meta 1'} - tx1 = Transaction.create([alice.public_key], [([alice.public_key], 1)], metadata=meta1, + tx1 = Create.generate([alice.public_key], [([alice.public_key], 1)], metadata=meta1, asset=asset1).sign([alice.private_key]) b.store_bulk_transactions([tx1]) asset2 = {'msg': 'abc 2'} meta2 = {'key': 'meta 2'} - tx2 = Transaction.create([alice.public_key], [([alice.public_key], 1)], metadata=meta2, + tx2 = Create.generate([alice.public_key], [([alice.public_key], 1)], metadata=meta2, asset=asset2).sign([alice.private_key]) b.store_bulk_transactions([tx2]) diff --git a/tests/web/test_transactions.py b/tests/web/test_transactions.py index 11846e4..109146e 100644 --- a/tests/web/test_transactions.py +++ b/tests/web/test_transactions.py @@ -15,6 +15,8 @@ except ImportError: from sha3 import sha3_256 from planetmint.transactions.common import crypto +from planetmint.transactions.types.assets.create import Create +from planetmint.transactions.types.assets.transfer import Transfer from planetmint.transactions.common.transaction_mode_types import ( BROADCAST_TX_COMMIT, BROADCAST_TX_ASYNC, BROADCAST_TX_SYNC) @@ -38,10 +40,9 @@ def test_get_transaction_returns_404_if_not_found(client): @pytest.mark.abci def test_post_create_transaction_endpoint(b, client): - from planetmint.models import Transaction user_priv, user_pub = crypto.generate_key_pair() - tx = Transaction.create([user_pub], [([user_pub], 1)]) + tx = Create.generate([user_pub], [([user_pub], 1)]) tx = tx.sign([user_priv]) res = client.post(TX_ENDPOINT, data=json.dumps(tx.to_dict())) @@ -67,7 +68,6 @@ def test_post_create_transaction_endpoint(b, client): @pytest.mark.language def test_post_create_transaction_with_language(b, client, nested, language, expected_status_code): - from planetmint.models import Transaction from planetmint.backend.localmongodb.connection import LocalMongoDBConnection if isinstance(b.connection, LocalMongoDBConnection): @@ -79,7 +79,7 @@ def test_post_create_transaction_with_language(b, client, nested, language, else: asset = lang_obj - tx = Transaction.create([user_pub], [([user_pub], 1)], + tx = Create.generate([user_pub], [([user_pub], 1)], asset=asset) tx = tx.sign([user_priv]) res = client.post(TX_ENDPOINT, data=json.dumps(tx.to_dict())) @@ -105,16 +105,15 @@ def test_post_create_transaction_with_language(b, client, nested, language, ]) def test_post_create_transaction_with_invalid_key(b, client, field, value, err_key, expected_status_code): - from planetmint.models import Transaction from planetmint.backend.localmongodb.connection import LocalMongoDBConnection user_priv, user_pub = crypto.generate_key_pair() if isinstance(b.connection, LocalMongoDBConnection): if field == 'asset': - tx = Transaction.create([user_pub], [([user_pub], 1)], + tx = Create.generate([user_pub], [([user_pub], 1)], asset=value) elif field == 'metadata': - tx = Transaction.create([user_pub], [([user_pub], 1)], + tx = Create.generate([user_pub], [([user_pub], 1)], metadata=value) tx = tx.sign([user_priv]) res = client.post(TX_ENDPOINT, data=json.dumps(tx.to_dict())) @@ -133,10 +132,9 @@ def test_post_create_transaction_with_invalid_key(b, client, field, value, @patch('planetmint.web.views.base.logger') def test_post_create_transaction_with_invalid_id(mock_logger, b, client): from planetmint.transactions.common.exceptions import InvalidHash - from planetmint.models import Transaction user_priv, user_pub = crypto.generate_key_pair() - tx = Transaction.create([user_pub], [([user_pub], 1)]) + tx = Create.generate([user_pub], [([user_pub], 1)]) tx = tx.sign([user_priv]).to_dict() tx['id'] = 'abcd' * 16 @@ -170,10 +168,9 @@ def test_post_create_transaction_with_invalid_signature(mock_logger, b, client): from planetmint.transactions.common.exceptions import InvalidSignature - from planetmint.models import Transaction user_priv, user_pub = crypto.generate_key_pair() - tx = Transaction.create([user_pub], [([user_pub], 1)]).to_dict() + tx = Create.generate([user_pub], [([user_pub], 1)]).to_dict() tx['inputs'][0]['fulfillment'] = 64 * '0' tx['id'] = sha3_256( json.dumps( @@ -219,7 +216,7 @@ def test_post_create_transaction_with_invalid_structure(client): def test_post_create_transaction_with_invalid_schema(mock_logger, client): from planetmint.models import Transaction user_priv, user_pub = crypto.generate_key_pair() - tx = Transaction.create([user_pub], [([user_pub], 1)]).to_dict() + tx = Create.generate([user_pub], [([user_pub], 1)]).to_dict() del tx['version'] ed25519 = Ed25519Sha256(public_key=base58.b58decode(user_pub)) message = json.dumps( @@ -307,9 +304,8 @@ def test_post_invalid_transaction(mock_logger, client, exc, msg, monkeypatch,): @pytest.mark.abci def test_post_transfer_transaction_endpoint(client, user_pk, user_sk, posted_create_tx): - from planetmint.models import Transaction - transfer_tx = Transaction.transfer(posted_create_tx.to_inputs(), + transfer_tx = Transfer.generate(posted_create_tx.to_inputs(), [([user_pk], 1)], asset_id=posted_create_tx.id) transfer_tx = transfer_tx.sign([user_sk]) @@ -324,10 +320,9 @@ def test_post_transfer_transaction_endpoint(client, user_pk, user_sk, posted_cre @pytest.mark.abci def test_post_invalid_transfer_transaction_returns_400(client, user_pk, posted_create_tx): - from planetmint.models import Transaction from planetmint.transactions.common.exceptions import InvalidSignature - transfer_tx = Transaction.transfer(posted_create_tx.to_inputs(), + transfer_tx = Transfer.generate(posted_create_tx.to_inputs(), [([user_pk], 1)], asset_id=posted_create_tx.id) transfer_tx._hash() @@ -342,18 +337,17 @@ def test_post_invalid_transfer_transaction_returns_400(client, user_pk, posted_c @pytest.mark.abci def test_post_wrong_asset_division_transfer_returns_400(b, client, user_pk): - from planetmint.models import Transaction from planetmint.transactions.common.exceptions import AmountError priv_key, pub_key = crypto.generate_key_pair() - create_tx = Transaction.create([pub_key], + create_tx = Create.generate([pub_key], [([pub_key], 10)], asset={'test': 'asset'}).sign([priv_key]) res = client.post(TX_ENDPOINT + '?mode=commit', data=json.dumps(create_tx.to_dict())) assert res.status_code == 202 - transfer_tx = Transaction.transfer(create_tx.to_inputs(), + transfer_tx = Transfer.generate(create_tx.to_inputs(), [([pub_key], 20)], # 20 > 10 asset_id=create_tx.id).sign([priv_key]) res = client.post(TX_ENDPOINT + '?mode=commit', data=json.dumps(transfer_tx.to_dict())) @@ -423,7 +417,6 @@ def test_transactions_get_list_bad(client): ('?mode=commit', BROADCAST_TX_COMMIT), ]) def test_post_transaction_valid_modes(mock_post, client, mode): - from planetmint.models import Transaction from planetmint.transactions.common.crypto import generate_key_pair def _mock_post(*args, **kwargs): @@ -432,7 +425,7 @@ def test_post_transaction_valid_modes(mock_post, client, mode): mock_post.side_effect = _mock_post alice = generate_key_pair() - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=None) \ .sign([alice.private_key]) @@ -444,10 +437,9 @@ def test_post_transaction_valid_modes(mock_post, client, mode): @pytest.mark.abci def test_post_transaction_invalid_mode(client): - from planetmint.models import Transaction from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=None) \ .sign([alice.private_key]) diff --git a/tests/web/test_websocket_server.py b/tests/web/test_websocket_server.py index 05b45fc..6846554 100644 --- a/tests/web/test_websocket_server.py +++ b/tests/web/test_websocket_server.py @@ -8,6 +8,8 @@ import json import queue import threading from unittest.mock import patch +from planetmint.transactions.types.assets.create import Create +from planetmint.transactions.types.assets.transfer import Transfer import pytest @@ -27,10 +29,10 @@ def test_eventify_block_works_with_any_transaction(): alice = generate_key_pair() - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([alice.public_key], 1)])\ .sign([alice.private_key]) - tx_transfer = Transaction.transfer(tx.to_inputs(), + tx_transfer = Transfer.generate(tx.to_inputs(), [([alice.public_key], 1)], asset_id=tx.id)\ .sign([alice.private_key]) @@ -142,7 +144,7 @@ async def test_websocket_block_event(b, test_client, loop): from planetmint.transactions.common import crypto user_priv, user_pub = crypto.generate_key_pair() - tx = Transaction.create([user_pub], [([user_pub], 1)]) + tx = Create.generate([user_pub], [([user_pub], 1)]) tx = tx.sign([user_priv]) event_source = asyncio.Queue(loop=loop) @@ -203,7 +205,7 @@ def test_integration_from_webapi_to_websocket(monkeypatch, client, loop): # Create a keypair and generate a new asset user_priv, user_pub = crypto.generate_key_pair() asset = {'random': random.random()} - tx = Transaction.create([user_pub], [([user_pub], 1)], asset=asset) + tx = Create.generate([user_pub], [([user_pub], 1)], asset=asset) tx = tx.sign([user_priv]) # Post the transaction to the Planetmint Web API client.post('/api/v1/transactions/', data=json.dumps(tx.to_dict())) From 0463fb22f99f7cd36b0166d4d83f996c46bfb9fe Mon Sep 17 00:00:00 2001 From: Sangat Das Date: Tue, 22 Mar 2022 09:41:28 +0000 Subject: [PATCH 65/93] Resolve flake8 issues#1 Signed-off-by: Sangat Das --- .../transactions/types/elections/vote.py | 1 - tests/assets/test_divisible_assets.py | 12 +----------- tests/common/test_transaction.py | 7 ------- tests/db/test_planetmint_api.py | 18 ------------------ tests/tendermint/test_core.py | 6 ------ tests/test_core.py | 6 ------ tests/web/test_assets.py | 2 -- tests/web/test_transactions.py | 1 - tests/web/test_websocket_server.py | 3 --- 9 files changed, 1 insertion(+), 55 deletions(-) diff --git a/planetmint/transactions/types/elections/vote.py b/planetmint/transactions/types/elections/vote.py index 9b8c33b..c102a8c 100644 --- a/planetmint/transactions/types/elections/vote.py +++ b/planetmint/transactions/types/elections/vote.py @@ -5,7 +5,6 @@ from planetmint.transactions.types.assets.create import Create from planetmint.transactions.types.assets.transfer import Transfer -from planetmint.transactions.common.transaction import Transaction from planetmint.transactions.common.schema import ( _validate_schema, TX_SCHEMA_COMMON, TX_SCHEMA_TRANSFER, TX_SCHEMA_VOTE) diff --git a/tests/assets/test_divisible_assets.py b/tests/assets/test_divisible_assets.py index d9d680f..caf3a97 100644 --- a/tests/assets/test_divisible_assets.py +++ b/tests/assets/test_divisible_assets.py @@ -18,7 +18,6 @@ from planetmint.transactions.common.exceptions import DoubleSpend # Single output # Single owners_after def test_single_in_single_own_single_out_single_own_create(alice, user_pk, b): - tx = Create.generate([alice.public_key], [([user_pk], 100)], asset={'name': random.random()}) tx_signed = tx.sign([alice.private_key]) @@ -35,7 +34,6 @@ def test_single_in_single_own_single_out_single_own_create(alice, user_pk, b): # Multiple outputs # Single owners_after per output def test_single_in_single_own_multiple_out_single_own_create(alice, user_pk, b): - tx = Create.generate([alice.public_key], [([user_pk], 50), ([user_pk], 50)], asset={'name': random.random()}) @@ -245,7 +243,6 @@ def test_single_in_single_own_multiple_out_mix_own_transfer(alice, b, user_pk, # Single owners_after def test_single_in_multiple_own_single_out_single_own_transfer(alice, b, user_pk, user_sk): - from planetmint.transactions.common.utils import _fulfillment_to_details # CREATE divisible asset @@ -281,7 +278,6 @@ def test_single_in_multiple_own_single_out_single_own_transfer(alice, b, user_pk # Single owners_after def test_multiple_in_single_own_single_out_single_own_transfer(alice, b, user_pk, user_sk): - # CREATE divisible asset tx_create = Create.generate([alice.public_key], [([user_pk], 50), ([user_pk], 50)], asset={'name': random.random()}) @@ -311,7 +307,6 @@ def test_multiple_in_single_own_single_out_single_own_transfer(alice, b, user_pk # Single owners_after def test_multiple_in_multiple_own_single_out_single_own_transfer(alice, b, user_pk, user_sk): - from planetmint.transactions.common.utils import _fulfillment_to_details # CREATE divisible asset @@ -352,7 +347,6 @@ def test_multiple_in_multiple_own_single_out_single_own_transfer(alice, b, user_ # Single owners_after def test_muiltiple_in_mix_own_multiple_out_single_own_transfer(alice, b, user_pk, user_sk): - from planetmint.transactions.common.utils import _fulfillment_to_details # CREATE divisible asset @@ -392,7 +386,6 @@ def test_muiltiple_in_mix_own_multiple_out_single_own_transfer(alice, b, user_pk # owners_after def test_muiltiple_in_mix_own_multiple_out_mix_own_transfer(alice, b, user_pk, user_sk): - from planetmint.transactions.common.utils import _fulfillment_to_details # CREATE divisible asset @@ -437,7 +430,7 @@ def test_muiltiple_in_mix_own_multiple_out_mix_own_transfer(alice, b, user_pk, # Single output # Single owners_after def test_multiple_in_different_transactions(alice, b, user_pk, user_sk): - + # CREATE divisible asset # `b` creates a divisible asset and assigns 50 shares to `b` and # 50 shares to `user_pk` @@ -480,7 +473,6 @@ def test_multiple_in_different_transactions(alice, b, user_pk, user_sk): # inputs needs to match the amount being sent in the outputs. # In other words `amount_in_inputs - amount_in_outputs == 0` def test_amount_error_transfer(alice, b, user_pk, user_sk): - from planetmint.transactions.common.exceptions import AmountError # CREATE divisible asset @@ -536,7 +528,6 @@ def test_threshold_same_public_key(alice, b, user_pk, user_sk): def test_sum_amount(alice, b, user_pk, user_sk): - # CREATE divisible asset with 3 outputs with amount 1 tx_create = Create.generate([alice.public_key], [([user_pk], 1), ([user_pk], 1), ([user_pk], 1)], @@ -561,7 +552,6 @@ def test_sum_amount(alice, b, user_pk, user_sk): def test_divide(alice, b, user_pk, user_sk): - # CREATE divisible asset with 1 output with amount 3 tx_create = Create.generate([alice.public_key], [([user_pk], 3)], asset={'name': random.random()}) diff --git a/tests/common/test_transaction.py b/tests/common/test_transaction.py index ce45cd1..691e475 100644 --- a/tests/common/test_transaction.py +++ b/tests/common/test_transaction.py @@ -705,7 +705,6 @@ def test_create_create_transaction_single_io(user_output, user_pub, data): def test_validate_single_io_create_transaction(user_pub, user_priv, data, asset_definition): - from planetmint.transactions.common.transaction import Transaction tx = Create.generate([user_pub], [([user_pub], 1)], metadata=data) tx = tx.sign([user_priv]) @@ -741,7 +740,6 @@ def test_create_create_transaction_multiple_io(user_output, user2_output, user_p def test_validate_multiple_io_create_transaction(user_pub, user_priv, user2_pub, user2_priv, asset_definition): - from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model tx = Create.generate([user_pub, user2_pub], @@ -787,7 +785,6 @@ def test_create_create_transaction_threshold(user_pub, user2_pub, user3_pub, def test_validate_threshold_create_transaction(user_pub, user_priv, user2_pub, data, asset_definition): - from planetmint.transactions.common.transaction import Transaction from .utils import validate_transaction_model tx = Create.generate([user_pub], [([user_pub, user2_pub], 1)], @@ -799,8 +796,6 @@ def test_validate_threshold_create_transaction(user_pub, user_priv, user2_pub, def test_create_create_transaction_with_invalid_parameters(user_pub): - from planetmint.transactions.common.transaction import Transaction - with raises(TypeError): Create.generate('not a list') with raises(TypeError): @@ -943,8 +938,6 @@ def test_create_transfer_transaction_multiple_io(user_pub, user_priv, def test_create_transfer_with_invalid_parameters(tx, user_pub): - from planetmint.transactions.common.transaction import Transaction - with raises(TypeError): Transfer.generate({}, [], tx.id) with raises(ValueError): diff --git a/tests/db/test_planetmint_api.py b/tests/db/test_planetmint_api.py index 0f08358..cb95598 100644 --- a/tests/db/test_planetmint_api.py +++ b/tests/db/test_planetmint_api.py @@ -16,7 +16,6 @@ pytestmark = pytest.mark.bdb class TestBigchainApi(object): def test_get_spent_with_double_spend_detected(self, b, alice): - from planetmint.models import Transaction from planetmint.transactions.common.exceptions import DoubleSpend from planetmint.exceptions import CriticalDoubleSpend @@ -46,7 +45,6 @@ class TestBigchainApi(object): b.get_spent(tx.id, 0) def test_double_inclusion(self, b, alice): - from planetmint.models import Transaction from planetmint.backend.exceptions import OperationError tx = Create.generate([alice.public_key], [([alice.public_key], 1)]) @@ -58,7 +56,6 @@ class TestBigchainApi(object): b.store_bulk_transactions([tx]) def test_text_search(self, b, alice): - from planetmint.models import Transaction # define the assets asset1 = {'msg': 'Planetmint 1'} @@ -85,7 +82,6 @@ class TestBigchainApi(object): from cryptoconditions import Ed25519Sha256 from planetmint.transactions.common.exceptions import InputDoesNotExist from planetmint.transactions.common.transaction import Input, TransactionLink - from planetmint.models import Transaction # Create an input for a non existing transaction input = Input(Ed25519Sha256(public_key=b58decode(user_pk)), @@ -97,7 +93,6 @@ class TestBigchainApi(object): tx.validate(b) def test_write_transaction(self, b, user_sk, user_pk, alice, create_tx): - from planetmint.models import Transaction asset1 = {'msg': 'Planetmint 1'} @@ -130,7 +125,6 @@ class TestTransactionValidation(object): def test_non_create_valid_input_wrong_owner(self, b, user_pk): from planetmint.transactions.common.crypto import generate_key_pair from planetmint.transactions.common.exceptions import InvalidSignature - from planetmint.models import Transaction input_tx = b.fastquery.get_outputs_by_public_key(user_pk).pop() input_transaction = b.get_transaction(input_tx.txid) @@ -159,7 +153,6 @@ class TestMultipleInputs(object): def test_transfer_single_owner_single_input(self, b, inputs, user_pk, user_sk): from planetmint.transactions.common import crypto - from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -180,7 +173,6 @@ class TestMultipleInputs(object): user_pk, inputs): from planetmint.transactions.common import crypto - from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() user3_sk, user3_pk = crypto.generate_key_pair() @@ -202,7 +194,6 @@ class TestMultipleInputs(object): user_pk, alice): from planetmint.transactions.common import crypto - from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() user3_sk, user3_pk = crypto.generate_key_pair() @@ -230,7 +221,6 @@ class TestMultipleInputs(object): user_pk, alice): from planetmint.transactions.common import crypto - from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() user3_sk, user3_pk = crypto.generate_key_pair() @@ -256,7 +246,6 @@ class TestMultipleInputs(object): def test_get_owned_ids_single_tx_single_output(self, b, user_sk, user_pk, alice): from planetmint.transactions.common import crypto from planetmint.transactions.common.transaction import TransactionLink - from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -284,7 +273,6 @@ class TestMultipleInputs(object): user_pk, alice): from planetmint.transactions.common import crypto from planetmint.transactions.common.transaction import TransactionLink - from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -318,7 +306,6 @@ class TestMultipleInputs(object): def test_get_owned_ids_multiple_owners(self, b, user_sk, user_pk, alice): from planetmint.transactions.common import crypto from planetmint.transactions.common.transaction import TransactionLink - from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() user3_sk, user3_pk = crypto.generate_key_pair() @@ -349,7 +336,6 @@ class TestMultipleInputs(object): def test_get_spent_single_tx_single_output(self, b, user_sk, user_pk, alice): from planetmint.transactions.common import crypto - from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() @@ -375,7 +361,6 @@ class TestMultipleInputs(object): def test_get_spent_single_tx_multiple_outputs(self, b, user_sk, user_pk, alice): from planetmint.transactions.common import crypto - from planetmint.models import Transaction # create a new users user2_sk, user2_pk = crypto.generate_key_pair() @@ -412,7 +397,6 @@ class TestMultipleInputs(object): def test_get_spent_multiple_owners(self, b, user_sk, user_pk, alice): from planetmint.transactions.common import crypto - from planetmint.models import Transaction user2_sk, user2_pk = crypto.generate_key_pair() user3_sk, user3_pk = crypto.generate_key_pair() @@ -498,7 +482,6 @@ def test_cant_spend_same_input_twice_in_tx(b, alice): """Recreate duplicated fulfillments bug https://github.com/planetmint/planetmint/issues/1099 """ - from planetmint.models import Transaction from planetmint.transactions.common.exceptions import DoubleSpend # create a divisible asset @@ -520,7 +503,6 @@ def test_cant_spend_same_input_twice_in_tx(b, alice): def test_transaction_unicode(b, alice): import copy from planetmint.transactions.common.utils import serialize - from planetmint.models import Transaction # http://www.fileformat.info/info/unicode/char/1f37a/index.htm beer_python = {'beer': '\N{BEER MUG}'} diff --git a/tests/tendermint/test_core.py b/tests/tendermint/test_core.py index c8e7942..6f4ae8f 100644 --- a/tests/tendermint/test_core.py +++ b/tests/tendermint/test_core.py @@ -204,7 +204,6 @@ def test_info(b): def test_check_tx__signed_create_is_ok(b): from planetmint import App - from planetmint.models import Transaction from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() @@ -221,7 +220,6 @@ def test_check_tx__signed_create_is_ok(b): def test_check_tx__unsigned_create_is_error(b): from planetmint import App - from planetmint.models import Transaction from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() @@ -238,7 +236,6 @@ def test_check_tx__unsigned_create_is_error(b): def test_deliver_tx__valid_create_updates_db_and_emits_event(b, init_chain_request): import multiprocessing as mp from planetmint import App - from planetmint.models import Transaction from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() @@ -275,7 +272,6 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(b, init_chain_reque def test_deliver_tx__double_spend_fails(b, init_chain_request): from planetmint import App - from planetmint.models import Transaction from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() @@ -304,7 +300,6 @@ def test_deliver_tx__double_spend_fails(b, init_chain_request): def test_deliver_transfer_tx__double_spend_fails(b, init_chain_request): from planetmint import App - from planetmint.models import Transaction from planetmint.transactions.common.crypto import generate_key_pair app = App(b) @@ -384,7 +379,6 @@ def test_end_block_return_validator_updates(b, init_chain_request): def test_store_pre_commit_state_in_end_block(b, alice, init_chain_request): from planetmint import App from planetmint.backend import query - from planetmint.models import Transaction tx = Create.generate([alice.public_key], [([alice.public_key], 1)], diff --git a/tests/test_core.py b/tests/test_core.py index d9a6efa..ae02b44 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -204,7 +204,6 @@ def test_info(b): def test_check_tx__signed_create_is_ok(b): from planetmint import App - from planetmint.models import Transaction from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() @@ -221,7 +220,6 @@ def test_check_tx__signed_create_is_ok(b): def test_check_tx__unsigned_create_is_error(b): from planetmint import App - from planetmint.models import Transaction from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() @@ -238,7 +236,6 @@ def test_check_tx__unsigned_create_is_error(b): def test_deliver_tx__valid_create_updates_db_and_emits_event(b, init_chain_request): import multiprocessing as mp from planetmint import App - from planetmint.models import Transaction from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() @@ -275,7 +272,6 @@ def test_deliver_tx__valid_create_updates_db_and_emits_event(b, init_chain_reque def test_deliver_tx__double_spend_fails(b, eventqueue_fixture, init_chain_request): from planetmint import App - from planetmint.models import Transaction from planetmint.transactions.common.crypto import generate_key_pair alice = generate_key_pair() @@ -304,7 +300,6 @@ def test_deliver_tx__double_spend_fails(b, eventqueue_fixture, init_chain_reques def test_deliver_transfer_tx__double_spend_fails(b, init_chain_request): from planetmint import App - from planetmint.models import Transaction from planetmint.transactions.common.crypto import generate_key_pair app = App(b) @@ -384,7 +379,6 @@ def test_end_block_return_validator_updates(b, init_chain_request): def test_store_pre_commit_state_in_end_block(b, alice, init_chain_request): from planetmint import App from planetmint.backend import query - from planetmint.models import Transaction tx = Create.generate([alice.public_key], [([alice.public_key], 1)], diff --git a/tests/web/test_assets.py b/tests/web/test_assets.py index 58136c3..b88c2ef 100644 --- a/tests/web/test_assets.py +++ b/tests/web/test_assets.py @@ -23,7 +23,6 @@ def test_get_assets_with_missing_text_search(client): @pytest.mark.bdb def test_get_assets_tendermint(client, b, alice): - from planetmint.models import Transaction # test returns empty list when no assets are found res = client.get(ASSETS_ENDPOINT + '?search=abc') @@ -49,7 +48,6 @@ def test_get_assets_tendermint(client, b, alice): @pytest.mark.bdb def test_get_assets_limit_tendermint(client, b, alice): - from planetmint.models import Transaction # create two assets asset1 = {'msg': 'abc 1'} diff --git a/tests/web/test_transactions.py b/tests/web/test_transactions.py index 109146e..b613c50 100644 --- a/tests/web/test_transactions.py +++ b/tests/web/test_transactions.py @@ -214,7 +214,6 @@ def test_post_create_transaction_with_invalid_structure(client): @pytest.mark.abci @patch('planetmint.web.views.base.logger') def test_post_create_transaction_with_invalid_schema(mock_logger, client): - from planetmint.models import Transaction user_priv, user_pub = crypto.generate_key_pair() tx = Create.generate([user_pub], [([user_pub], 1)]).to_dict() del tx['version'] diff --git a/tests/web/test_websocket_server.py b/tests/web/test_websocket_server.py index 6846554..d7d9d85 100644 --- a/tests/web/test_websocket_server.py +++ b/tests/web/test_websocket_server.py @@ -25,7 +25,6 @@ class MockWebSocket: def test_eventify_block_works_with_any_transaction(): from planetmint.web.websocket_server import eventify_block from planetmint.transactions.common.crypto import generate_key_pair - from planetmint.lib import Transaction alice = generate_key_pair() @@ -140,7 +139,6 @@ async def test_websocket_string_event(test_client, loop): async def test_websocket_block_event(b, test_client, loop): from planetmint import events from planetmint.web.websocket_server import init_app, POISON_PILL, EVENTS_ENDPOINT - from planetmint.models import Transaction from planetmint.transactions.common import crypto user_priv, user_pub = crypto.generate_key_pair() @@ -186,7 +184,6 @@ def test_integration_from_webapi_to_websocket(monkeypatch, client, loop): # TODO processes does not exist anymore, when reactivating this test it # will fail because of this from planetmint import processes - from planetmint.models import Transaction # Start Planetmint processes.start() From 43ecbffe5ed21c162812fa78fdd4fdca8ba2bf2e Mon Sep 17 00:00:00 2001 From: Sangat Das Date: Wed, 23 Mar 2022 08:08:20 +0000 Subject: [PATCH 66/93] Resolve flake8 issues#2 Signed-off-by: Sangat Das --- tests/assets/test_divisible_assets.py | 6 +++--- tests/tendermint/test_integration.py | 7 ++++--- tests/utils.py | 4 ++-- tests/web/test_outputs.py | 10 ++++++---- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/tests/assets/test_divisible_assets.py b/tests/assets/test_divisible_assets.py index caf3a97..272c9d3 100644 --- a/tests/assets/test_divisible_assets.py +++ b/tests/assets/test_divisible_assets.py @@ -97,7 +97,6 @@ def test_single_in_single_own_multiple_out_mix_own_create(alice, user_pk, b): # Output combinations already tested above def test_single_in_multiple_own_single_out_single_own_create(alice, b, user_pk, user_sk): - from planetmint.transactions.common.utils import _fulfillment_to_details tx = Create.generate([alice.public_key, user_pk], [([user_pk], 100)], asset={'name': random.random()}) @@ -305,8 +304,9 @@ def test_multiple_in_single_own_single_out_single_own_transfer(alice, b, user_pk # Multiple owners_before per input # Single output # Single owners_after -def test_multiple_in_multiple_own_single_out_single_own_transfer(alice, b, user_pk, - user_sk): +def test_multiple_in_multiple_own_single_out_single_own_transfer( + alice, b, user_pk, + user_sk): from planetmint.transactions.common.utils import _fulfillment_to_details # CREATE divisible asset diff --git a/tests/tendermint/test_integration.py b/tests/tendermint/test_integration.py index 15a6eac..8b7bb85 100644 --- a/tests/tendermint/test_integration.py +++ b/tests/tendermint/test_integration.py @@ -5,6 +5,7 @@ import codecs from planetmint.transactions.types.assets.create import Create +from planetmint.transactions.types.assets.transfer import Transfer from tendermint.abci import types_pb2 as types import json @@ -114,7 +115,7 @@ def test_app(b, eventqueue_fixture, init_chain_request): @pytest.mark.abci def test_post_transaction_responses(tendermint_ws_url, b): from planetmint.transactions.common.crypto import generate_key_pair - from planetmint.models import Transaction + alice = generate_key_pair() bob = generate_key_pair() @@ -126,7 +127,7 @@ def test_post_transaction_responses(tendermint_ws_url, b): code, message = b.write_transaction(tx, BROADCAST_TX_COMMIT) assert code == 202 - tx_transfer = Transaction.transfer(tx.to_inputs(), + tx_transfer = Transfer.generate(tx.to_inputs(), [([bob.public_key], 1)], asset_id=tx.id)\ .sign([alice.private_key]) @@ -135,7 +136,7 @@ def test_post_transaction_responses(tendermint_ws_url, b): assert code == 202 carly = generate_key_pair() - double_spend = Transaction.transfer( + double_spend = Transfer.transfer( tx.to_inputs(), [([carly.public_key], 1)], asset_id=tx.id, diff --git a/tests/utils.py b/tests/utils.py index 4829d4e..ceffff0 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -13,6 +13,7 @@ from planetmint.backend.localmongodb.connection import LocalMongoDBConnection from planetmint.backend.schema import TABLES from planetmint.transactions.common import crypto from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT +from planetmint.transactions.types.assets.create import Create from planetmint.transactions.types.elections.election import Election, Vote from planetmint.tendermint_utils import key_to_base64 @@ -30,10 +31,9 @@ def flush_localmongo_db(connection, dbname): def generate_block(planet): from planetmint.transactions.common.crypto import generate_key_pair - from planetmint.models import Transaction alice = generate_key_pair() - tx = Transaction.create([alice.public_key], + tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=None)\ .sign([alice.private_key]) diff --git a/tests/web/test_outputs.py b/tests/web/test_outputs.py index 112526a..16783b8 100644 --- a/tests/web/test_outputs.py +++ b/tests/web/test_outputs.py @@ -3,7 +3,10 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 + import pytest +from planetmint.transactions.types.assets.create import Create +from planetmint.transactions.types.assets.transfer import Transfer from unittest.mock import MagicMock, patch @@ -83,7 +86,6 @@ def test_get_outputs_endpoint_with_invalid_spent(client, user_pk): @pytest.mark.abci def test_get_divisble_transactions_returns_500(b, client): - from planetmint.models import Transaction from planetmint.transactions.common import crypto import json @@ -96,7 +98,7 @@ def test_get_divisble_transactions_returns_500(b, client): bob_priv, bob_pub = crypto.generate_key_pair() carly_priv, carly_pub = crypto.generate_key_pair() - create_tx = Transaction.create([alice_pub], [([alice_pub], 4)]) + create_tx = Create.generate([alice_pub], [([alice_pub], 4)]) create_tx.sign([alice_priv]) res = client.post(TX_ENDPOINT, data=json.dumps(create_tx.to_dict())) @@ -104,7 +106,7 @@ def test_get_divisble_transactions_returns_500(b, client): mine([create_tx]) - transfer_tx = Transaction.transfer(create_tx.to_inputs(), + transfer_tx = Transfer.generate(create_tx.to_inputs(), [([alice_pub], 3), ([bob_pub], 1)], asset_id=create_tx.id) transfer_tx.sign([alice_priv]) @@ -114,7 +116,7 @@ def test_get_divisble_transactions_returns_500(b, client): mine([transfer_tx]) - transfer_tx_carly = Transaction.transfer([transfer_tx.to_inputs()[1]], + transfer_tx_carly = Transfer.generate([transfer_tx.to_inputs()[1]], [([carly_pub], 1)], asset_id=create_tx.id) transfer_tx_carly.sign([bob_priv]) From 635d68c7adae6d5306c387c83d67529364243706 Mon Sep 17 00:00:00 2001 From: Sangat Das Date: Wed, 23 Mar 2022 08:23:33 +0000 Subject: [PATCH 67/93] Resolve flake8 issues#3 Signed-off-by: Sangat Das --- tests/assets/test_divisible_assets.py | 3 +-- tests/tendermint/test_integration.py | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/assets/test_divisible_assets.py b/tests/assets/test_divisible_assets.py index 272c9d3..031a9be 100644 --- a/tests/assets/test_divisible_assets.py +++ b/tests/assets/test_divisible_assets.py @@ -305,8 +305,7 @@ def test_multiple_in_single_own_single_out_single_own_transfer(alice, b, user_pk # Single output # Single owners_after def test_multiple_in_multiple_own_single_out_single_own_transfer( - alice, b, user_pk, - user_sk): + alice, b, user_pk, user_sk): from planetmint.transactions.common.utils import _fulfillment_to_details # CREATE divisible asset diff --git a/tests/tendermint/test_integration.py b/tests/tendermint/test_integration.py index 8b7bb85..2326caf 100644 --- a/tests/tendermint/test_integration.py +++ b/tests/tendermint/test_integration.py @@ -116,7 +116,6 @@ def test_app(b, eventqueue_fixture, init_chain_request): def test_post_transaction_responses(tendermint_ws_url, b): from planetmint.transactions.common.crypto import generate_key_pair - alice = generate_key_pair() bob = generate_key_pair() tx = Create.generate([alice.public_key], From a7fe94de1da97fb3263ddbc7590beaf976cb9c73 Mon Sep 17 00:00:00 2001 From: Sangat Das Date: Wed, 23 Mar 2022 09:07:32 +0000 Subject: [PATCH 68/93] Resolve flake8 issues#4 Signed-off-by: Sangat Das --- tests/assets/test_divisible_assets.py | 4 ++-- tests/tendermint/test_integration.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/assets/test_divisible_assets.py b/tests/assets/test_divisible_assets.py index 031a9be..210efbe 100644 --- a/tests/assets/test_divisible_assets.py +++ b/tests/assets/test_divisible_assets.py @@ -304,8 +304,8 @@ def test_multiple_in_single_own_single_out_single_own_transfer(alice, b, user_pk # Multiple owners_before per input # Single output # Single owners_after -def test_multiple_in_multiple_own_single_out_single_own_transfer( - alice, b, user_pk, user_sk): +def test_multiple_in_multiple_own_single_out_single_own_transfer(alice, b, user_pk, + user_sk): from planetmint.transactions.common.utils import _fulfillment_to_details # CREATE divisible asset diff --git a/tests/tendermint/test_integration.py b/tests/tendermint/test_integration.py index 2326caf..69c818d 100644 --- a/tests/tendermint/test_integration.py +++ b/tests/tendermint/test_integration.py @@ -135,7 +135,7 @@ def test_post_transaction_responses(tendermint_ws_url, b): assert code == 202 carly = generate_key_pair() - double_spend = Transfer.transfer( + double_spend = Transfer.generate( tx.to_inputs(), [([carly.public_key], 1)], asset_id=tx.id, From 69ad661a6086f9a0108a479ae5b083928dc3e6f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Wed, 23 Mar 2022 14:13:51 +0100 Subject: [PATCH 69/93] fixed last flake issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jürgen Eckel --- tests/assets/test_divisible_assets.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/assets/test_divisible_assets.py b/tests/assets/test_divisible_assets.py index 210efbe..4381c06 100644 --- a/tests/assets/test_divisible_assets.py +++ b/tests/assets/test_divisible_assets.py @@ -305,13 +305,13 @@ def test_multiple_in_single_own_single_out_single_own_transfer(alice, b, user_pk # Single output # Single owners_after def test_multiple_in_multiple_own_single_out_single_own_transfer(alice, b, user_pk, - user_sk): + user_sk): from planetmint.transactions.common.utils import _fulfillment_to_details # CREATE divisible asset tx_create = Create.generate([alice.public_key], [([user_pk, alice.public_key], 50), - ([user_pk, alice.public_key], 50)], - asset={'name': random.random()}) + ([user_pk, alice.public_key], 50)], + asset={'name': random.random()}) tx_create_signed = tx_create.sign([alice.private_key]) # TRANSFER From df7c1e1ccfa0673c9e8876091727a43d0be3718e Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger <64837895+LaurentDeMontBlanc@users.noreply.github.com> Date: Thu, 24 Mar 2022 14:24:32 +0100 Subject: [PATCH 70/93] Enhance integration test suite (#62) * restructering, added helper, split cli tests for later Signed-off-by: Lorenz Herzberger * fixed threshold test Signed-off-by: Lorenz Herzberger * added acceptance tests to integration test suite Signed-off-by: Lorenz Herzberger * added different threshold signature test scenarios Signed-off-by: Lorenz Herzberger * started chain-migration test implementation Signed-off-by: Lorenz Herzberger * fixed linter errors Signed-off-by: Lorenz Herzberger * removed -s from test command Signed-off-by: Lorenz Herzberger --- docker-compose.integration.yml | 1 + docker-compose.yml | 12 - integration/cli/chain-migration.sh | 47 +++ integration/cli/upsert-new-validator.sh | 33 ++ integration/python/Dockerfile | 14 +- integration/python/src/__init__.py | 0 integration/python/src/conftest.py | 95 +++++ integration/python/src/helper/__init__.py | 0 integration/python/src/helper/hosts.py | 36 ++ integration/python/src/test_basic.py | 29 +- .../python/src/test_divisible_asset.py | 183 ++++++++++ integration/python/src/test_double_spend.py | 48 +++ ...st_multisig.py => test_multiple_owners.py} | 29 +- .../python/src/test_naughty_strings.py | 100 ++++++ integration/python/src/test_stream.py | 131 +++++++ integration/python/src/test_threshold.py | 336 ++++++++++++++++++ integration/python/src/test_zenroom.py | 84 +++++ integration/scripts/election.sh | 20 +- integration/scripts/test.sh | 24 +- 19 files changed, 1151 insertions(+), 71 deletions(-) create mode 100755 integration/cli/chain-migration.sh create mode 100755 integration/cli/upsert-new-validator.sh create mode 100644 integration/python/src/__init__.py create mode 100644 integration/python/src/conftest.py create mode 100644 integration/python/src/helper/__init__.py create mode 100644 integration/python/src/helper/hosts.py create mode 100644 integration/python/src/test_divisible_asset.py create mode 100644 integration/python/src/test_double_spend.py rename integration/python/src/{test_multisig.py => test_multiple_owners.py} (84%) create mode 100644 integration/python/src/test_naughty_strings.py create mode 100644 integration/python/src/test_stream.py create mode 100644 integration/python/src/test_threshold.py create mode 100644 integration/python/src/test_zenroom.py diff --git a/docker-compose.integration.yml b/docker-compose.integration.yml index b1cbdaf..52ac541 100644 --- a/docker-compose.integration.yml +++ b/docker-compose.integration.yml @@ -46,6 +46,7 @@ services: volumes: - ./integration/python/src:/src - ./integration/scripts:/scripts + - ./integration/cli:/tests - shared:/shared volumes: diff --git a/docker-compose.yml b/docker-compose.yml index 39005e9..c825a8f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -83,18 +83,6 @@ services: environment: - PLANETMINT_ENDPOINT=planetmint - # Planetmint setup to do integration testing wtih Python - python-integration: - build: - context: . - dockerfile: ./integration/python/Dockerfile - volumes: - - ./integration/python/docs:/docs - - ./integration/python/src:/src - environment: - - PLANETMINT_ENDPOINT_1=https://itest1.planetmint.io - - PLANETMINT_ENDPOINT_2=https://itest2.planetmint.io - # Build docs only # docker-compose build bdocs # docker-compose up -d bdocs diff --git a/integration/cli/chain-migration.sh b/integration/cli/chain-migration.sh new file mode 100755 index 0000000..448ffb1 --- /dev/null +++ b/integration/cli/chain-migration.sh @@ -0,0 +1,47 @@ +#!/bin/bash +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +# Add chain migration test +check_status () { + status=$(ssh -o "StrictHostKeyChecking=no" -i \~/.ssh/id_rsa root@$1 'bash -s' < scripts/election.sh show_election $2 | tail -n 1) + status=${status#*=} + if [ $status != $3 ]; then + exit 1 + fi +} + +# Read host names from shared +readarray -t HOSTNAMES < /shared/hostnames + +# Split into proposer and approvers +PROPOSER=${HOSTNAMES[0]} +APPROVERS=${HOSTNAMES[@]:1} + +# Propose chain migration +result=$(ssh -o "StrictHostKeyChecking=no" -i \~/.ssh/id_rsa root@${PROPOSER} 'bash -s' < scripts/election.sh migrate) + +# Check if election is ongoing and approve chain migration +for APPROVER in ${APPROVERS[@]}; do + # Check if election is still ongoing + check_status ${APPROVER} $result ongoing + ssh -o "StrictHostKeyChecking=no" -i ~/.ssh/id_rsa root@${APPROVER} 'bash -s' < scripts/election.sh approve $result +done + +# Status of election should be concluded +status=$(ssh -o "StrictHostKeyChecking=no" -i \~/.ssh/id_rsa root@${PROPOSER} 'bash -s' < scripts/election.sh show_election $result) +status=${status#*INFO:planetmint.commands.planetmint:} +status=("$status[@]") + + +# TODO: Get status, chain_id, app_hash and validators to restore planetmint on all nodes +# References: +# https://github.com/bigchaindb/BEPs/tree/master/42 +# http://docs.bigchaindb.com/en/latest/installation/node-setup/bigchaindb-cli.html +for word in $status; do + echo $word +done + +echo ${status#*validators=} \ No newline at end of file diff --git a/integration/cli/upsert-new-validator.sh b/integration/cli/upsert-new-validator.sh new file mode 100755 index 0000000..4f63568 --- /dev/null +++ b/integration/cli/upsert-new-validator.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +check_status () { + status=$(ssh -o "StrictHostKeyChecking=no" -i \~/.ssh/id_rsa root@$1 'bash -s' < scripts/election.sh show_election $2 | tail -n 1) + status=${status#*=} + if [ $status != $3 ]; then + exit 1 + fi +} + +# Read host names from shared +readarray -t HOSTNAMES < /shared/hostnames + +# Split into proposer and approvers +PROPOSER=${HOSTNAMES[0]} +APPROVERS=${HOSTNAMES[@]:1} + +# Propose validator upsert +result=$(ssh -o "StrictHostKeyChecking=no" -i \~/.ssh/id_rsa root@${PROPOSER} 'bash -s' < scripts/election.sh elect 2) + +# Check if election is ongoing and approve validator upsert +for APPROVER in ${APPROVERS[@]}; do + # Check if election is still ongoing + check_status ${APPROVER} $result ongoing + ssh -o "StrictHostKeyChecking=no" -i ~/.ssh/id_rsa root@${APPROVER} 'bash -s' < scripts/election.sh approve $result +done + +# Status of election should be concluded +check_status ${PROPOSER} $result concluded \ No newline at end of file diff --git a/integration/python/Dockerfile b/integration/python/Dockerfile index c0e47f1..65f5e15 100644 --- a/integration/python/Dockerfile +++ b/integration/python/Dockerfile @@ -1,9 +1,17 @@ FROM python:3.9 +RUN apt-get update \ + && pip install -U pip \ + && apt-get autoremove \ + && apt-get clean +RUN apt-get install -y vim zsh build-essential cmake openssh-client openssh-server + RUN mkdir -p /src RUN pip install --upgrade \ pytest~=6.2.5 \ planetmint-driver~=0.9.0 \ - pycco - -RUN apt-get update && apt-get install -y openssh-client openssh-server \ No newline at end of file + pycco \ + websocket-client~=0.47.0 \ + git+https://github.com/planetmint/cryptoconditions.git@gitzenroom \ + git+https://github.com/planetmint/planetmint-driver.git@gitzenroom \ + blns \ No newline at end of file diff --git a/integration/python/src/__init__.py b/integration/python/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/integration/python/src/conftest.py b/integration/python/src/conftest.py new file mode 100644 index 0000000..808914b --- /dev/null +++ b/integration/python/src/conftest.py @@ -0,0 +1,95 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +import pytest + +GENERATE_KEYPAIR = \ + """Rule input encoding base58 + Rule output encoding base58 + Scenario 'ecdh': Create the keypair + Given that I am known as 'Pippo' + When I create the ecdh key + When I create the testnet key + Then print data""" + +# secret key to public key +SK_TO_PK = \ + """Rule input encoding base58 + Rule output encoding base58 + Scenario 'ecdh': Create the keypair + Given that I am known as '{}' + Given I have the 'keys' + When I create the ecdh public key + When I create the testnet address + Then print my 'ecdh public key' + Then print my 'testnet address'""" + +FULFILL_SCRIPT = \ + """Rule input encoding base58 + Rule output encoding base58 + 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 'data.signature' inside 'result' + When I verify the 'houses' has a signature in 'data.signature' by 'Alice' + Then print the string 'ok'""" + +HOUSE_ASSETS = { + "data": { + "houses": [ + { + "name": "Harry", + "team": "Gryffindor", + }, + { + "name": "Draco", + "team": "Slytherin", + } + ], + } +} + +ZENROOM_DATA = { + 'also': 'more data' +} + +CONDITION_SCRIPT = """Rule input encoding base58 + Rule output encoding base58 + Scenario 'ecdh': create the signature of an object + Given I have the 'keys' + Given that I have a 'string dictionary' named 'houses' inside 'asset' + When I create the signature of 'houses' + When I rename the 'signature' to 'data.signature' + Then print the 'data.signature'""" + + +@pytest.fixture +def gen_key_zencode(): + return GENERATE_KEYPAIR + + +@pytest.fixture +def secret_key_to_private_key_zencode(): + return SK_TO_PK + + +@pytest.fixture +def fulfill_script_zencode(): + return FULFILL_SCRIPT + + +@pytest.fixture +def condition_script_zencode(): + return CONDITION_SCRIPT + + +@pytest.fixture +def zenroom_house_assets(): + return HOUSE_ASSETS + + +@pytest.fixture +def zenroom_data(): + return ZENROOM_DATA diff --git a/integration/python/src/helper/__init__.py b/integration/python/src/helper/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/integration/python/src/helper/hosts.py b/integration/python/src/helper/hosts.py new file mode 100644 index 0000000..b14f875 --- /dev/null +++ b/integration/python/src/helper/hosts.py @@ -0,0 +1,36 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +from typing import List + +from planetmint_driver import Planetmint + + +class Hosts: + hostnames = [] + connections = [] + + def __init__(self, filepath): + self.set_hostnames(filepath=filepath) + self.set_connections() + + def set_hostnames(self, filepath) -> None: + with open(filepath) as f: + self.hostnames = f.readlines() + + def set_connections(self) -> None: + self.connections = list(map(lambda h: Planetmint(h), self.hostnames)) + + def get_connection(self, index=0) -> Planetmint: + return self.connections[index] + + def get_transactions(self, tx_id) -> List: + return list(map(lambda connection: connection.transactions.retrieve(tx_id), self.connections)) + + def assert_transaction(self, tx_id) -> None: + txs = self.get_transactions(tx_id) + for tx in txs: + assert txs[0] == tx, \ + 'Cannot find transaction {}'.format(tx_id) diff --git a/integration/python/src/test_basic.py b/integration/python/src/test_basic.py index 4932638..691dbc3 100644 --- a/integration/python/src/test_basic.py +++ b/integration/python/src/test_basic.py @@ -4,21 +4,18 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 # import Planetmint and create object -from planetmint_driver import Planetmint from planetmint_driver.crypto import generate_keypair + +# import helper to manage multiple nodes +from .helper.hosts import Hosts + import time def test_basic(): # Setup up connection to Planetmint integration test nodes - hosts = [] - with open('/shared/hostnames') as f: - hosts = f.readlines() - - pm_hosts = list(map(lambda x: Planetmint(x), hosts)) - - pm_alpha = pm_hosts[0] - pm_betas = pm_hosts[1:] + hosts = Hosts('/shared/hostnames') + pm_alpha = hosts.get_connection() # genarate a keypair alice = generate_keypair() @@ -50,13 +47,8 @@ def test_basic(): creation_tx_id = fulfilled_creation_tx['id'] - # retrieve transactions from all planetmint nodes - creation_tx_alpha = pm_alpha.transactions.retrieve(creation_tx_id) - creation_tx_betas = list(map(lambda beta: beta.transactions.retrieve(creation_tx_id), pm_betas)) - # Assert that transaction is stored on all planetmint nodes - for tx in creation_tx_betas: - assert creation_tx_alpha == tx + hosts.assert_transaction(creation_tx_id) # Transfer # create the output and inout for the transaction @@ -87,10 +79,5 @@ def test_basic(): transfer_tx_id = sent_transfer_tx['id'] - # retrieve transactions from both planetmint nodes - transfer_tx_alpha = pm_alpha.transactions.retrieve(transfer_tx_id) - transfer_tx_betas = list(map(lambda beta: beta.transactions.retrieve(transfer_tx_id), pm_betas)) - # Assert that transaction is stored on both planetmint nodes - for tx in transfer_tx_betas: - assert transfer_tx_alpha == tx + hosts.assert_transaction(transfer_tx_id) diff --git a/integration/python/src/test_divisible_asset.py b/integration/python/src/test_divisible_asset.py new file mode 100644 index 0000000..c324f61 --- /dev/null +++ b/integration/python/src/test_divisible_asset.py @@ -0,0 +1,183 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +# # Divisible assets integration testing +# This test checks if we can successfully divide assets. +# The script tests various things like: +# +# - create a transaction with a divisible asset and issue them to someone +# - check if the transaction is stored and has the right amount of tokens +# - spend some tokens +# - try to spend more tokens than available +# +# We run a series of checks for each step, that is retrieving +# the transaction from the remote system, and also checking the `amount` +# of a given transaction. +# +# This integration test is a rip-off of our +# [tutorial](https://docs.planetmint.com/projects/py-driver/en/latest/usage.html). + +# ## Imports +# We need the `pytest` package to catch the `BadRequest` exception properly. +# And of course, we also need the `BadRequest`. +import pytest +from planetmint_driver.exceptions import BadRequest + +# Import generate_keypair to create actors +from planetmint_driver.crypto import generate_keypair + +# import helper to manage multiple nodes +from .helper.hosts import Hosts + + +def test_divisible_assets(): + # ## Set up a connection to Planetmint + # Check [test_basic.py](./test_basic.html) to get some more details + # about the endpoint. + hosts = Hosts('/shared/hostnames') + pm = hosts.get_connection() + + # Oh look, it is Alice again and she brought her friend Bob along. + alice, bob = generate_keypair(), generate_keypair() + + # ## Alice creates a time sharing token + # Alice wants to go on vacation, while Bobs bike just broke down. + # Alice decides to rent her bike to Bob while she is gone. + # So she prepares a `CREATE` transaction to issues 10 tokens. + # First, she prepares an asset for a time sharing token. As you can see in + # the description, Bob and Alice agree that each token can be used to ride + # the bike for one hour. + + bike_token = { + 'data': { + 'token_for': { + 'bike': { + 'serial_number': 420420 + } + }, + 'description': 'Time share token. Each token equals one hour of riding.', + }, + } + + # She prepares a `CREATE` transaction and issues 10 tokens. + # Here, Alice defines in a tuple that she wants to assign + # these 10 tokens to Bob. + prepared_token_tx = pm.transactions.prepare( + operation='CREATE', + signers=alice.public_key, + recipients=[([bob.public_key], 10)], + asset=bike_token) + + # She fulfills and sends the transaction. + fulfilled_token_tx = pm.transactions.fulfill( + prepared_token_tx, + private_keys=alice.private_key) + + pm.transactions.send_commit(fulfilled_token_tx) + + # We store the `id` of the transaction to use it later on. + bike_token_id = fulfilled_token_tx['id'] + + # Let's check if the transaction was successful. + assert pm.transactions.retrieve(bike_token_id), \ + 'Cannot find transaction {}'.format(bike_token_id) + + # Bob owns 10 tokens now. + assert pm.transactions.retrieve(bike_token_id)['outputs'][0][ + 'amount'] == '10' + + # ## Bob wants to use the bike + # Now that Bob got the tokens and the sun is shining, he wants to get out + # with the bike for three hours. + # To use the bike he has to send the tokens back to Alice. + # To learn about the details of transferring a transaction check out + # [test_basic.py](./test_basic.html) + transfer_asset = {'id': bike_token_id} + + output_index = 0 + output = fulfilled_token_tx['outputs'][output_index] + transfer_input = {'fulfillment': output['condition']['details'], + 'fulfills': {'output_index': output_index, + 'transaction_id': fulfilled_token_tx[ + 'id']}, + 'owners_before': output['public_keys']} + + # To use the tokens Bob has to reassign 7 tokens to himself and the + # amount he wants to use to Alice. + prepared_transfer_tx = pm.transactions.prepare( + operation='TRANSFER', + asset=transfer_asset, + inputs=transfer_input, + recipients=[([alice.public_key], 3), ([bob.public_key], 7)]) + + # He signs and sends the transaction. + fulfilled_transfer_tx = pm.transactions.fulfill( + prepared_transfer_tx, + private_keys=bob.private_key) + + sent_transfer_tx = pm.transactions.send_commit(fulfilled_transfer_tx) + + # First, Bob checks if the transaction was successful. + assert pm.transactions.retrieve( + fulfilled_transfer_tx['id']) == sent_transfer_tx + + hosts.assert_transaction(fulfilled_transfer_tx['id']) + # There are two outputs in the transaction now. + # The first output shows that Alice got back 3 tokens... + assert pm.transactions.retrieve( + fulfilled_transfer_tx['id'])['outputs'][0]['amount'] == '3' + + # ... while Bob still has 7 left. + assert pm.transactions.retrieve( + fulfilled_transfer_tx['id'])['outputs'][1]['amount'] == '7' + + # ## Bob wants to ride the bike again + # It's been a week and Bob wants to right the bike again. + # Now he wants to ride for 8 hours, that's a lot Bob! + # He prepares the transaction again. + + transfer_asset = {'id': bike_token_id} + # This time we need an `output_index` of 1, since we have two outputs + # in the `fulfilled_transfer_tx` we created before. The first output with + # index 0 is for Alice and the second output is for Bob. + # Since Bob wants to spend more of his tokens he has to provide the + # correct output with the correct amount of tokens. + output_index = 1 + + output = fulfilled_transfer_tx['outputs'][output_index] + + transfer_input = {'fulfillment': output['condition']['details'], + 'fulfills': {'output_index': output_index, + 'transaction_id': fulfilled_transfer_tx['id']}, + 'owners_before': output['public_keys']} + + # This time Bob only provides Alice in the `recipients` because he wants + # to spend all his tokens + prepared_transfer_tx = pm.transactions.prepare( + operation='TRANSFER', + asset=transfer_asset, + inputs=transfer_input, + recipients=[([alice.public_key], 8)]) + + fulfilled_transfer_tx = pm.transactions.fulfill( + prepared_transfer_tx, + private_keys=bob.private_key) + + # Oh Bob, what have you done?! You tried to spend more tokens than you had. + # Remember Bob, last time you spent 3 tokens already, + # so you only have 7 left. + with pytest.raises(BadRequest) as error: + pm.transactions.send_commit(fulfilled_transfer_tx) + + # Now Bob gets an error saying that the amount he wanted to spent is + # higher than the amount of tokens he has left. + assert error.value.args[0] == 400 + message = 'Invalid transaction (AmountError): The amount used in the ' \ + 'inputs `7` needs to be same as the amount used in the ' \ + 'outputs `8`' + assert error.value.args[2]['message'] == message + + # We have to stop this test now, I am sorry, but Bob is pretty upset + # about his mistake. See you next time :) diff --git a/integration/python/src/test_double_spend.py b/integration/python/src/test_double_spend.py new file mode 100644 index 0000000..1a17738 --- /dev/null +++ b/integration/python/src/test_double_spend.py @@ -0,0 +1,48 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +# # Double Spend testing +# This test challenge the system with double spends. +from uuid import uuid4 +from threading import Thread +import queue + +import planetmint_driver.exceptions +from planetmint_driver.crypto import generate_keypair + +from .helper.hosts import Hosts + + +def test_double_create(): + hosts = Hosts('/shared/hostnames') + pm = hosts.get_connection() + alice = generate_keypair() + + results = queue.Queue() + + tx = pm.transactions.fulfill( + pm.transactions.prepare( + operation='CREATE', + signers=alice.public_key, + asset={'data': {'uuid': str(uuid4())}}), + private_keys=alice.private_key) + + def send_and_queue(tx): + try: + pm.transactions.send_commit(tx) + results.put('OK') + except planetmint_driver.exceptions.TransportError: + results.put('FAIL') + + t1 = Thread(target=send_and_queue, args=(tx, )) + t2 = Thread(target=send_and_queue, args=(tx, )) + + t1.start() + t2.start() + + results = [results.get(timeout=2), results.get(timeout=2)] + + assert results.count('OK') == 1 + assert results.count('FAIL') == 1 diff --git a/integration/python/src/test_multisig.py b/integration/python/src/test_multiple_owners.py similarity index 84% rename from integration/python/src/test_multisig.py rename to integration/python/src/test_multiple_owners.py index 94ce9dc..98f3ea6 100644 --- a/integration/python/src/test_multisig.py +++ b/integration/python/src/test_multiple_owners.py @@ -22,20 +22,16 @@ import time # For this test case we need import and use the Python driver -from planetmint_driver import Planetmint from planetmint_driver.crypto import generate_keypair +# Import helper to deal with multiple nodes +from .helper.hosts import Hosts + def test_multiple_owners(): # Setup up connection to Planetmint integration test nodes - hosts = [] - with open('/shared/hostnames') as f: - hosts = f.readlines() - - pm_hosts = list(map(lambda x: Planetmint(x), hosts)) - - pm_alpha = pm_hosts[0] - pm_betas = pm_hosts[1:] + hosts = Hosts('/shared/hostnames') + pm_alpha = hosts.get_connection() # Generate Keypairs for Alice and Bob! alice, bob = generate_keypair(), generate_keypair() @@ -73,13 +69,9 @@ def test_multiple_owners(): dw_id = fulfilled_dw_tx['id'] time.sleep(1) - # Let's retrieve the transaction from both nodes - pm_alpha_tx = pm_alpha.transactions.retrieve(dw_id) - pm_betas_tx = list(map(lambda beta: beta.transactions.retrieve(dw_id), pm_betas)) - # Both retrieved transactions should be the same - for tx in pm_betas_tx: - assert pm_alpha_tx == tx + # Use hosts to assert that the transaction is properly propagated to every node + hosts.assert_transaction(dw_id) # Let's check if the transaction was successful. assert pm_alpha.transactions.retrieve(dw_id), \ @@ -124,13 +116,8 @@ def test_multiple_owners(): sent_transfer_tx = pm_alpha.transactions.send_commit(fulfilled_transfer_tx) time.sleep(1) - # Retrieve the fulfilled transaction from both nodes - pm_alpha_tx = pm_alpha.transactions.retrieve(fulfilled_transfer_tx['id']) - pm_betas_tx = list(map(lambda beta: beta.transactions.retrieve(fulfilled_transfer_tx['id']), pm_betas)) - # Now compare if both nodes returned the same transaction - for tx in pm_betas_tx: - assert pm_alpha_tx == tx + hosts.assert_transaction(fulfilled_transfer_tx['id']) # They check if the transaction was successful. assert pm_alpha.transactions.retrieve( diff --git a/integration/python/src/test_naughty_strings.py b/integration/python/src/test_naughty_strings.py new file mode 100644 index 0000000..4a090c0 --- /dev/null +++ b/integration/python/src/test_naughty_strings.py @@ -0,0 +1,100 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +# ## Testing potentially hazardous strings +# This test uses a library of `naughty` strings (code injections, weird unicode chars., etc.) as both keys and values. +# We look for either a successful tx, or in the case that we use a naughty string as a key, and it violates some key +# constraints, we expect to receive a well formatted error message. + +# ## Imports +# Since the naughty strings get encoded and decoded in odd ways, +# we'll use a regex to sweep those details under the rug. +import re + +# We'll use a nice library of naughty strings... +from blns import blns + +# And parameterize our test so each one is treated as a separate test case +import pytest + +# For this test case we import and use the Python Driver. +from planetmint_driver.crypto import generate_keypair +from planetmint_driver.exceptions import BadRequest + +# import helper to manage multiple nodes +from .helper.hosts import Hosts + +naughty_strings = blns.all() + + +# This is our base test case, but we'll reuse it to send naughty strings as both keys and values. +def send_naughty_tx(asset, metadata): + # ## Set up a connection to Planetmint + # Check [test_basic.py](./test_basic.html) to get some more details + # about the endpoint. + hosts = Hosts('/shared/hostnames') + pm = hosts.get_connection() + + # Here's Alice. + alice = generate_keypair() + + # Alice is in a naughty mood today, so she creates a tx with some naughty strings + prepared_transaction = pm.transactions.prepare( + operation='CREATE', + signers=alice.public_key, + asset=asset, + metadata=metadata) + + # She fulfills the transaction + fulfilled_transaction = pm.transactions.fulfill( + prepared_transaction, + private_keys=alice.private_key) + + # The fulfilled tx gets sent to the pm network + try: + sent_transaction = pm.transactions.send_commit(fulfilled_transaction) + except BadRequest as e: + sent_transaction = e + + # If her key contained a '.', began with a '$', or contained a NUL character + regex = r'.*\..*|\$.*|.*\x00.*' + key = next(iter(metadata)) + if re.match(regex, key): + # Then she expects a nicely formatted error code + status_code = sent_transaction.status_code + error = sent_transaction.error + regex = ( + r'\{\s*\n*' + r'\s*"message":\s*"Invalid transaction \(ValidationError\):\s*' + r'Invalid key name.*The key name cannot contain characters.*\n*' + r'\s*"status":\s*400\n*' + r'\s*\}\n*') + assert status_code == 400 + assert re.fullmatch(regex, error), sent_transaction + # Otherwise, she expects to see her transaction in the database + elif 'id' in sent_transaction.keys(): + tx_id = sent_transaction['id'] + assert pm.transactions.retrieve(tx_id) + # If neither condition was true, then something weird happened... + else: + raise TypeError(sent_transaction) + + +@pytest.mark.parametrize("naughty_string", naughty_strings, ids=naughty_strings) +def test_naughty_keys(naughty_string): + + asset = {'data': {naughty_string: 'nice_value'}} + metadata = {naughty_string: 'nice_value'} + + send_naughty_tx(asset, metadata) + + +@pytest.mark.parametrize("naughty_string", naughty_strings, ids=naughty_strings) +def test_naughty_values(naughty_string): + + asset = {'data': {'nice_key': naughty_string}} + metadata = {'nice_key': naughty_string} + + send_naughty_tx(asset, metadata) diff --git a/integration/python/src/test_stream.py b/integration/python/src/test_stream.py new file mode 100644 index 0000000..c93d5c6 --- /dev/null +++ b/integration/python/src/test_stream.py @@ -0,0 +1,131 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +# # Stream Acceptance Test +# This test checks if the event stream works correctly. The basic idea of this +# test is to generate some random **valid** transaction, send them to a +# Planetmint node, and expect those transactions to be returned by the valid +# transactions Stream API. During this test, two threads work together, +# sharing a queue to exchange events. +# +# - The *main thread* first creates and sends the transactions to Planetmint; +# then it run through all events in the shared queue to check if all +# transactions sent have been validated by Planetmint. +# - The *listen thread* listens to the events coming from Planetmint and puts +# them in a queue shared with the main thread. +import queue +import json +from threading import Thread, Event +from uuid import uuid4 + +# For this script, we need to set up a websocket connection, that's the reason +# we import the +# [websocket](https://github.com/websocket-client/websocket-client) module +from websocket import create_connection + +from planetmint_driver.crypto import generate_keypair + +# import helper to manage multiple nodes +from .helper.hosts import Hosts + + +def test_stream(): + # ## Set up the test + # We use the env variable `BICHAINDB_ENDPOINT` to know where to connect. + # Check [test_basic.py](./test_basic.html) for more information. + hosts = Hosts('/shared/hostnames') + pm = hosts.get_connection() + + # *That's pretty bad, but let's do like this for now.* + WS_ENDPOINT = 'ws://{}:9985/api/v1/streams/valid_transactions'.format(hosts.hostnames[0]) + + # Hello to Alice again, she is pretty active in those tests, good job + # Alice! + alice = generate_keypair() + + # We need few variables to keep the state, specifically we need `sent` to + # keep track of all transactions Alice sent to Planetmint, while `received` + # are the transactions Planetmint validated and sent back to her. + sent = [] + received = queue.Queue() + + # In this test we use a websocket. The websocket must be started **before** + # sending transactions to Planetmint, otherwise we might lose some + # transactions. The `ws_ready` event is used to synchronize the main thread + # with the listen thread. + ws_ready = Event() + + # ## Listening to events + # This is the function run by the complementary thread. + def listen(): + # First we connect to the remote endpoint using the WebSocket protocol. + ws = create_connection(WS_ENDPOINT) + + # After the connection has been set up, we can signal the main thread + # to proceed (continue reading, it should make sense in a second.) + ws_ready.set() + + # It's time to consume all events coming from the Planetmint stream API. + # Every time a new event is received, it is put in the queue shared + # with the main thread. + while True: + result = ws.recv() + received.put(result) + + # Put `listen` in a thread, and start it. Note that `listen` is a local + # function and it can access all variables in the enclosing function. + t = Thread(target=listen, daemon=True) + t.start() + + # ## Pushing the transactions to Planetmint + # After starting the listen thread, we wait for it to connect, and then we + # proceed. + ws_ready.wait() + + # Here we prepare, sign, and send ten different `CREATE` transactions. To + # make sure each transaction is different from the other, we generate a + # random `uuid`. + for _ in range(10): + tx = pm.transactions.fulfill( + pm.transactions.prepare( + operation='CREATE', + signers=alice.public_key, + asset={'data': {'uuid': str(uuid4())}}), + private_keys=alice.private_key) + # We don't want to wait for each transaction to be in a block. By using + # `async` mode, we make sure that the driver returns as soon as the + # transaction is pushed to the Planetmint API. Remember: we expect all + # transactions to be in the shared queue: this is a two phase test, + # first we send a bunch of transactions, then we check if they are + # valid (and, in this case, they should). + pm.transactions.send_async(tx) + + # The `id` of every sent transaction is then stored in a list. + sent.append(tx['id']) + + # ## Check the valid transactions coming from Planetmint + # Now we are ready to check if Planetmint did its job. A simple way to + # check if all sent transactions have been processed is to **remove** from + # `sent` the transactions we get from the *listen thread*. At one point in + # time, `sent` should be empty, and we exit the test. + while sent: + # To avoid waiting forever, we have an arbitrary timeout of 5 + # seconds: it should be enough time for Planetmint to create + # blocks, in fact a new block is created every second. If we hit + # the timeout, then game over ¯\\\_(ツ)\_/¯ + try: + event = received.get(timeout=5) + txid = json.loads(event)['transaction_id'] + except queue.Empty: + assert False, 'Did not receive all expected transactions' + + # Last thing is to try to remove the `txid` from the set of sent + # transactions. If this test is running in parallel with others, we + # might get a transaction id of another test, and `remove` can fail. + # It's OK if this happens. + try: + sent.remove(txid) + except ValueError: + pass diff --git a/integration/python/src/test_threshold.py b/integration/python/src/test_threshold.py new file mode 100644 index 0000000..f118651 --- /dev/null +++ b/integration/python/src/test_threshold.py @@ -0,0 +1,336 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +# ## Imports +import time +import json + +# For this test case we need the planetmint_driver.crypto package +import base58 +import sha3 +from cryptoconditions import Ed25519Sha256, ThresholdSha256 +from planetmint_driver.crypto import generate_keypair + +# Import helper to deal with multiple nodes +from .helper.hosts import Hosts + + +def prepare_condition_details(condition: ThresholdSha256): + condition_details = { + 'subconditions': [], + 'threshold': condition.threshold, + 'type': condition.TYPE_NAME + } + + for s in condition.subconditions: + if (s['type'] == 'fulfillment' and s['body'].TYPE_NAME == 'ed25519-sha-256'): + condition_details['subconditions'].append({ + 'type': s['body'].TYPE_NAME, + 'public_key': base58.b58encode(s['body'].public_key).decode() + }) + else: + condition_details['subconditions'].append(prepare_condition_details(s['body'])) + + return condition_details + + +def test_threshold(): + # Setup connection to test nodes + hosts = Hosts('/shared/hostnames') + pm = hosts.get_connection() + + # Generate Keypars for Alice, Bob an Carol! + alice, bob, carol = generate_keypair(), generate_keypair(), generate_keypair() + + # ## Alice and Bob create a transaction + # Alice and Bob just moved into a shared flat, no one can afford these + # high rents anymore. Bob suggests to get a dish washer for the + # kitchen. Alice agrees and here they go, creating the asset for their + # dish washer. + dw_asset = { + 'data': { + 'dish washer': { + 'serial_number': 1337 + } + } + } + + # Create subfulfillments + alice_ed25519 = Ed25519Sha256(public_key=base58.b58decode(alice.public_key)) + bob_ed25519 = Ed25519Sha256(public_key=base58.b58decode(bob.public_key)) + carol_ed25519 = Ed25519Sha256(public_key=base58.b58decode(carol.public_key)) + + # Create threshold condition (2/3) and add subfulfillments + threshold_sha256 = ThresholdSha256(2) + threshold_sha256.add_subfulfillment(alice_ed25519) + threshold_sha256.add_subfulfillment(bob_ed25519) + threshold_sha256.add_subfulfillment(carol_ed25519) + + # Create a condition uri and details for the output object + condition_uri = threshold_sha256.condition.serialize_uri() + condition_details = prepare_condition_details(threshold_sha256) + + # Assemble output and input for the handcrafted tx + output = { + 'amount': '1', + 'condition': { + 'details': condition_details, + 'uri': condition_uri, + }, + 'public_keys': (alice.public_key, bob.public_key, carol.public_key), + } + + # The yet to be fulfilled input: + input_ = { + 'fulfillment': None, + 'fulfills': None, + 'owners_before': (alice.public_key, bob.public_key), + } + + # Assemble the handcrafted transaction + handcrafted_dw_tx = { + 'operation': 'CREATE', + 'asset': dw_asset, + 'metadata': None, + 'outputs': (output,), + 'inputs': (input_,), + 'version': '2.0', + 'id': None, + } + + # Create sha3-256 of message to sign + message = json.dumps( + handcrafted_dw_tx, + sort_keys=True, + separators=(',', ':'), + ensure_ascii=False, + ) + message = sha3.sha3_256(message.encode()) + + # Sign message with Alice's und Bob's private key + alice_ed25519.sign(message.digest(), base58.b58decode(alice.private_key)) + bob_ed25519.sign(message.digest(), base58.b58decode(bob.private_key)) + + # Create fulfillment and add uri to inputs + fulfillment_threshold = ThresholdSha256(2) + fulfillment_threshold.add_subfulfillment(alice_ed25519) + fulfillment_threshold.add_subfulfillment(bob_ed25519) + fulfillment_threshold.add_subcondition(carol_ed25519.condition) + + fulfillment_uri = fulfillment_threshold.serialize_uri() + + handcrafted_dw_tx['inputs'][0]['fulfillment'] = fulfillment_uri + + # Create tx_id for handcrafted_dw_tx and send tx commit + json_str_tx = json.dumps( + handcrafted_dw_tx, + sort_keys=True, + separators=(',', ':'), + ensure_ascii=False, + ) + + dw_creation_txid = sha3.sha3_256(json_str_tx.encode()).hexdigest() + + handcrafted_dw_tx['id'] = dw_creation_txid + + pm.transactions.send_commit(handcrafted_dw_tx) + + time.sleep(1) + + # Assert that the tx is propagated to all nodes + hosts.assert_transaction(dw_creation_txid) + + +def test_weighted_threshold(): + hosts = Hosts('/shared/hostnames') + pm = hosts.get_connection() + + alice, bob, carol = generate_keypair(), generate_keypair(), generate_keypair() + + asset = { + 'data': { + 'trashcan': { + 'animals': ['racoon_1', 'racoon_2'] + } + } + } + + alice_ed25519 = Ed25519Sha256(public_key=base58.b58decode(alice.public_key)) + bob_ed25519 = Ed25519Sha256(public_key=base58.b58decode(bob.public_key)) + carol_ed25519 = Ed25519Sha256(public_key=base58.b58decode(carol.public_key)) + + threshold = ThresholdSha256(1) + threshold.add_subfulfillment(alice_ed25519) + + sub_threshold = ThresholdSha256(2) + sub_threshold.add_subfulfillment(bob_ed25519) + sub_threshold.add_subfulfillment(carol_ed25519) + + threshold.add_subfulfillment(sub_threshold) + + condition_uri = threshold.condition.serialize_uri() + condition_details = prepare_condition_details(threshold) + + # Assemble output and input for the handcrafted tx + output = { + 'amount': '1', + 'condition': { + 'details': condition_details, + 'uri': condition_uri, + }, + 'public_keys': (alice.public_key, bob.public_key, carol.public_key), + } + + # The yet to be fulfilled input: + input_ = { + 'fulfillment': None, + 'fulfills': None, + 'owners_before': (alice.public_key, bob.public_key), + } + + # Assemble the handcrafted transaction + handcrafted_tx = { + 'operation': 'CREATE', + 'asset': asset, + 'metadata': None, + 'outputs': (output,), + 'inputs': (input_,), + 'version': '2.0', + 'id': None, + } + + # Create sha3-256 of message to sign + message = json.dumps( + handcrafted_tx, + sort_keys=True, + separators=(',', ':'), + ensure_ascii=False, + ) + message = sha3.sha3_256(message.encode()) + + # Sign message with Alice's und Bob's private key + alice_ed25519.sign(message.digest(), base58.b58decode(alice.private_key)) + + # Create fulfillment and add uri to inputs + sub_fulfillment_threshold = ThresholdSha256(2) + sub_fulfillment_threshold.add_subcondition(bob_ed25519.condition) + sub_fulfillment_threshold.add_subcondition(carol_ed25519.condition) + + fulfillment_threshold = ThresholdSha256(1) + fulfillment_threshold.add_subfulfillment(alice_ed25519) + fulfillment_threshold.add_subfulfillment(sub_fulfillment_threshold) + + fulfillment_uri = fulfillment_threshold.serialize_uri() + + handcrafted_tx['inputs'][0]['fulfillment'] = fulfillment_uri + + # Create tx_id for handcrafted_dw_tx and send tx commit + json_str_tx = json.dumps( + handcrafted_tx, + sort_keys=True, + separators=(',', ':'), + ensure_ascii=False, + ) + + creation_tx_id = sha3.sha3_256(json_str_tx.encode()).hexdigest() + + handcrafted_tx['id'] = creation_tx_id + + pm.transactions.send_commit(handcrafted_tx) + + time.sleep(1) + + # Assert that the tx is propagated to all nodes + hosts.assert_transaction(creation_tx_id) + + # Now transfer created asset + alice_transfer_ed25519 = Ed25519Sha256(public_key=base58.b58decode(alice.public_key)) + bob_transfer_ed25519 = Ed25519Sha256(public_key=base58.b58decode(bob.public_key)) + carol_transfer_ed25519 = Ed25519Sha256(public_key=base58.b58decode(carol.public_key)) + + transfer_condition_uri = alice_transfer_ed25519.condition.serialize_uri() + + # Assemble output and input for the handcrafted tx + transfer_output = { + 'amount': '1', + 'condition': { + 'details': { + 'type': alice_transfer_ed25519.TYPE_NAME, + 'public_key': base58.b58encode(alice_transfer_ed25519.public_key).decode() + }, + 'uri': transfer_condition_uri, + }, + 'public_keys': (alice.public_key,), + } + + # The yet to be fulfilled input: + transfer_input_ = { + 'fulfillment': None, + 'fulfills': { + 'transaction_id': creation_tx_id, + 'output_index': 0 + }, + 'owners_before': (alice.public_key, bob.public_key, carol.public_key), + } + + # Assemble the handcrafted transaction + handcrafted_transfer_tx = { + 'operation': 'TRANSFER', + 'asset': {'id': creation_tx_id}, + 'metadata': None, + 'outputs': (transfer_output,), + 'inputs': (transfer_input_,), + 'version': '2.0', + 'id': None, + } + + # Create sha3-256 of message to sign + message = json.dumps( + handcrafted_transfer_tx, + sort_keys=True, + separators=(',', ':'), + ensure_ascii=False, + ) + message = sha3.sha3_256(message.encode()) + + message.update('{}{}'.format( + handcrafted_transfer_tx['inputs'][0]['fulfills']['transaction_id'], + handcrafted_transfer_tx['inputs'][0]['fulfills']['output_index']).encode()) + + # Sign message with Alice's und Bob's private key + bob_transfer_ed25519.sign(message.digest(), base58.b58decode(bob.private_key)) + carol_transfer_ed25519.sign(message.digest(), base58.b58decode(carol.private_key)) + + sub_fulfillment_threshold = ThresholdSha256(2) + sub_fulfillment_threshold.add_subfulfillment(bob_transfer_ed25519) + sub_fulfillment_threshold.add_subfulfillment(carol_transfer_ed25519) + + # Create fulfillment and add uri to inputs + fulfillment_threshold = ThresholdSha256(1) + fulfillment_threshold.add_subcondition(alice_transfer_ed25519.condition) + fulfillment_threshold.add_subfulfillment(sub_fulfillment_threshold) + + fulfillment_uri = fulfillment_threshold.serialize_uri() + + handcrafted_transfer_tx['inputs'][0]['fulfillment'] = fulfillment_uri + + # Create tx_id for handcrafted_dw_tx and send tx commit + json_str_tx = json.dumps( + handcrafted_transfer_tx, + sort_keys=True, + separators=(',', ':'), + ensure_ascii=False, + ) + + transfer_tx_id = sha3.sha3_256(json_str_tx.encode()).hexdigest() + + handcrafted_transfer_tx['id'] = transfer_tx_id + + pm.transactions.send_commit(handcrafted_transfer_tx) + + time.sleep(1) + + # Assert that the tx is propagated to all nodes + hosts.assert_transaction(transfer_tx_id) diff --git a/integration/python/src/test_zenroom.py b/integration/python/src/test_zenroom.py new file mode 100644 index 0000000..8f749a6 --- /dev/null +++ b/integration/python/src/test_zenroom.py @@ -0,0 +1,84 @@ +# GOAL: +# In this script I tried to implement the ECDSA signature using zenroom + +# However, the scripts are customizable and so with the same procedure +# we can implement more complex smart contracts + +# PUBLIC IDENTITY +# The public identity of the users in this script (Bob and Alice) +# is the pair (ECDH public key, Testnet address) + +import json + +from cryptoconditions import ZenroomSha256 +from json.decoder import JSONDecodeError + + +def test_zenroom(gen_key_zencode, secret_key_to_private_key_zencode, fulfill_script_zencode, + condition_script_zencode, zenroom_data, zenroom_house_assets): + alice = json.loads(ZenroomSha256.run_zenroom(gen_key_zencode).output)['keys'] + bob = json.loads(ZenroomSha256.run_zenroom(gen_key_zencode).output)['keys'] + + zen_public_keys = json.loads(ZenroomSha256.run_zenroom(secret_key_to_private_key_zencode.format('Alice'), + keys={'keys': alice}).output) + zen_public_keys.update(json.loads(ZenroomSha256.run_zenroom(secret_key_to_private_key_zencode.format('Bob'), + keys={'keys': bob}).output)) + + # CRYPTO-CONDITIONS: instantiate an Ed25519 crypto-condition for buyer + zenSha = ZenroomSha256(script=fulfill_script_zencode, keys=zen_public_keys, data=zenroom_data) + + # CRYPTO-CONDITIONS: generate the condition uri + condition_uri = zenSha.condition.serialize_uri() + + # CRYPTO-CONDITIONS: construct an unsigned fulfillment dictionary + unsigned_fulfillment_dict = { + 'type': zenSha.TYPE_NAME, + 'script': fulfill_script_zencode, + 'keys': zen_public_keys, + } + + output = { + 'amount': '1000', + 'condition': { + 'details': unsigned_fulfillment_dict, + 'uri': condition_uri, + }, + 'data': zenroom_data, + 'script': fulfill_script_zencode, + 'conf': '', + 'public_keys': (zen_public_keys['Alice']['ecdh_public_key'], ), + } + + input_ = { + 'fulfillment': None, + 'fulfills': None, + 'owners_before': (zen_public_keys['Alice']['ecdh_public_key'], ), + } + + token_creation_tx = { + 'operation': 'CREATE', + 'asset': zenroom_house_assets, + 'metadata': None, + 'outputs': (output,), + 'inputs': (input_,), + 'version': '2.0', + 'id': None, + } + + # JSON: serialize the transaction-without-id to a json formatted string + message = json.dumps( + token_creation_tx, + sort_keys=True, + separators=(',', ':'), + ensure_ascii=False, + ) + + try: + assert(not zenSha.validate(message=message)) + except JSONDecodeError: + pass + except ValueError: + pass + + message = zenSha.sign(message, condition_script_zencode, alice) + assert(zenSha.validate(message=message)) diff --git a/integration/scripts/election.sh b/integration/scripts/election.sh index d55abc7..65d39cb 100755 --- a/integration/scripts/election.sh +++ b/integration/scripts/election.sh @@ -16,12 +16,17 @@ show_validator () { # Elect new voting power for node elect_validator () { - planetmint election new upsert-validator $1 $2 $3 --private-key /tendermint/config/priv_validator_key.json + planetmint election new upsert-validator $1 $2 $3 --private-key /tendermint/config/priv_validator_key.json 2>&1 +} + +# Propose new chain migration +propose_migration () { + planetmint election new chain-migration --private-key /tendermint/config/priv_validator_key.json 2>&1 } # Show election state show_election () { - planetmint election show $1 + planetmint election show $1 2>&1 } # Approve election @@ -33,7 +38,13 @@ approve_validator () { elect () { node_id=$(show_id) validator_pubkey=$(show_validator | jq -r .value) - proposal=$(elect_validator $validator_pubkey $1 $node_id 2>&1 | grep SUCCESS) + proposal=$(elect_validator $validator_pubkey $1 $node_id | grep SUCCESS) + echo ${proposal##* } +} + +# Create chain migration proposal and return election id +migrate () { + proposal=$(propose_migration | grep SUCCESS) echo ${proposal##* } } @@ -50,6 +61,9 @@ while [ "$1" != "" ]; do elect ) shift elect $1 ;; + migrate ) shift + migrate + ;; show_election ) shift show_election $1 ;; diff --git a/integration/scripts/test.sh b/integration/scripts/test.sh index de9271d..2d3b796 100755 --- a/integration/scripts/test.sh +++ b/integration/scripts/test.sh @@ -4,19 +4,21 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -# Read host names from shared -readarray -t HOSTNAMES < /shared/hostnames +# Start CLI Tests -# Split into proposer and approvers -ALPHA=${HOSTNAMES[0]} -BETAS=${HOSTNAMES[@]:1} +# Test upsert new validator +/tests/upsert-new-validator.sh -# Propose validator upsert -result=$(ssh -o "StrictHostKeyChecking=no" -i \~/.ssh/id_rsa root@${ALPHA} 'bash -s' < scripts/election.sh elect 2) +# Test chain migration +# TODO: implementation not finished +#/tests/chain-migration.sh -# Approve validator upsert -for BETA in ${BETAS[@]}; do - ssh -o "StrictHostKeyChecking=no" -i ~/.ssh/id_rsa root@${BETA} 'bash -s' < scripts/election.sh approve $result -done +# TODO: Implement test for voting edge cases or implicit in chain migration and upsert validator? + +exitcode=$? + +if [ $exitcode -ne 0 ]; then + exit $exitcode +fi exec "$@" \ No newline at end of file From 2d5d6dde3ca39a0f734867ff6ee687de75140a0d Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger <64837895+LaurentDeMontBlanc@users.noreply.github.com> Date: Mon, 28 Mar 2022 11:36:33 +0200 Subject: [PATCH 71/93] added __init__.py to planetmint transaction module (#63) * added __init__.py to planetmint transaction module Signed-off-by: Lorenz Herzberger * pinned jinja2 version for docs Signed-off-by: Lorenz Herzberger * added jinja2==3.0.0 to docs requirements.txt Signed-off-by: Lorenz Herzberger --- docs/root/requirements.txt | 1 + planetmint/transactions/__init__.py | 0 planetmint/transactions/types/__init__.py | 0 setup.py | 3 ++- 4 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 planetmint/transactions/__init__.py create mode 100644 planetmint/transactions/types/__init__.py diff --git a/docs/root/requirements.txt b/docs/root/requirements.txt index 81df20d..f04211f 100644 --- a/docs/root/requirements.txt +++ b/docs/root/requirements.txt @@ -7,3 +7,4 @@ pyyaml>=4.2b1 aafigure>=0.6 packaging~=18.0 wget +jinja2==3.0.0 diff --git a/planetmint/transactions/__init__.py b/planetmint/transactions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/planetmint/transactions/types/__init__.py b/planetmint/transactions/types/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/setup.py b/setup.py index e396d3a..5157fd6 100644 --- a/setup.py +++ b/setup.py @@ -53,7 +53,8 @@ docs_require = [ 'sphinxcontrib-httpdomain>=1.5.0', 'sphinxcontrib-napoleon>=0.4.4', 'aafigure>=0.6', - 'wget' + 'wget', + 'jinja2==3.0.0' ] tests_require = [ From db304f6184c137fae6661a9f0fbc2f8dd0eabb68 Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger <64837895+LaurentDeMontBlanc@users.noreply.github.com> Date: Wed, 30 Mar 2022 17:15:10 +0200 Subject: [PATCH 72/93] pinned werkzeug to version 2.0.3 (#76) Signed-off-by: Lorenz Herzberger --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 5157fd6..41119ca 100644 --- a/setup.py +++ b/setup.py @@ -92,6 +92,7 @@ install_requires = [ 'pyyaml==5.4.1', 'requests==2.25.1', 'setproctitle==1.2.2', + 'werkzeug==2.0.3', ] if sys.version_info < (3, 6): From d224877a97f0246b525fec054580da81704d7c52 Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger Date: Thu, 31 Mar 2022 10:33:49 +0200 Subject: [PATCH 73/93] moved transaction schemas to version folders Signed-off-by: Lorenz Herzberger --- .../transactions/common/schema/__init__.py | 17 +- .../transaction.yaml} | 0 .../transaction_create.yaml} | 0 .../transaction_transfer.yaml} | 0 .../transaction.yaml} | 0 ...transaction_chain_migration_election.yaml} | 0 .../transaction_create.yaml} | 0 .../transaction_transfer.yaml} | 0 .../transaction_validator_election.yaml} | 0 .../transaction_vote.yaml} | 0 .../common/schema/v3.0/transaction.yaml | 174 ++++++++++++++++++ 11 files changed, 183 insertions(+), 8 deletions(-) rename planetmint/transactions/common/schema/{transaction_v1.0.yaml => v1.0/transaction.yaml} (100%) rename planetmint/transactions/common/schema/{transaction_create_v1.0.yaml => v1.0/transaction_create.yaml} (100%) rename planetmint/transactions/common/schema/{transaction_transfer_v1.0.yaml => v1.0/transaction_transfer.yaml} (100%) rename planetmint/transactions/common/schema/{transaction_v2.0.yaml => v2.0/transaction.yaml} (100%) rename planetmint/transactions/common/schema/{transaction_chain_migration_election_v2.0.yaml => v2.0/transaction_chain_migration_election.yaml} (100%) rename planetmint/transactions/common/schema/{transaction_create_v2.0.yaml => v2.0/transaction_create.yaml} (100%) rename planetmint/transactions/common/schema/{transaction_transfer_v2.0.yaml => v2.0/transaction_transfer.yaml} (100%) rename planetmint/transactions/common/schema/{transaction_validator_election_v2.0.yaml => v2.0/transaction_validator_election.yaml} (100%) rename planetmint/transactions/common/schema/{transaction_vote_v2.0.yaml => v2.0/transaction_vote.yaml} (100%) create mode 100644 planetmint/transactions/common/schema/v3.0/transaction.yaml diff --git a/planetmint/transactions/common/schema/__init__.py b/planetmint/transactions/common/schema/__init__.py index 0b4b20b..51e092c 100644 --- a/planetmint/transactions/common/schema/__init__.py +++ b/planetmint/transactions/common/schema/__init__.py @@ -17,31 +17,32 @@ from planetmint.transactions.common.exceptions import SchemaValidationError logger = logging.getLogger(__name__) -def _load_schema(name, path=__file__): +def _load_schema(name, version, path=__file__): """Load a schema from disk""" - path = os.path.join(os.path.dirname(path), name + '.yaml') + path = os.path.join(os.path.dirname(path), version, name + '.yaml') with open(path) as handle: schema = yaml.safe_load(handle) fast_schema = rapidjson.Validator(rapidjson.dumps(schema)) return path, (schema, fast_schema) +# TODO: make this an env var from a config file TX_SCHEMA_VERSION = 'v2.0' -TX_SCHEMA_PATH, TX_SCHEMA_COMMON = _load_schema('transaction_' + +TX_SCHEMA_PATH, TX_SCHEMA_COMMON = _load_schema('transaction', TX_SCHEMA_VERSION) -_, TX_SCHEMA_CREATE = _load_schema('transaction_create_' + +_, TX_SCHEMA_CREATE = _load_schema('transaction_create', TX_SCHEMA_VERSION) -_, TX_SCHEMA_TRANSFER = _load_schema('transaction_transfer_' + +_, TX_SCHEMA_TRANSFER = _load_schema('transaction_transfer', TX_SCHEMA_VERSION) -_, TX_SCHEMA_VALIDATOR_ELECTION = _load_schema('transaction_validator_election_' + +_, TX_SCHEMA_VALIDATOR_ELECTION = _load_schema('transaction_validator_election', TX_SCHEMA_VERSION) -_, TX_SCHEMA_CHAIN_MIGRATION_ELECTION = _load_schema('transaction_chain_migration_election_' + +_, TX_SCHEMA_CHAIN_MIGRATION_ELECTION = _load_schema('transaction_chain_migration_election', TX_SCHEMA_VERSION) -_, TX_SCHEMA_VOTE = _load_schema('transaction_vote_' + TX_SCHEMA_VERSION) +_, TX_SCHEMA_VOTE = _load_schema('transaction_vote', TX_SCHEMA_VERSION) def _validate_schema(schema, body): diff --git a/planetmint/transactions/common/schema/transaction_v1.0.yaml b/planetmint/transactions/common/schema/v1.0/transaction.yaml similarity index 100% rename from planetmint/transactions/common/schema/transaction_v1.0.yaml rename to planetmint/transactions/common/schema/v1.0/transaction.yaml diff --git a/planetmint/transactions/common/schema/transaction_create_v1.0.yaml b/planetmint/transactions/common/schema/v1.0/transaction_create.yaml similarity index 100% rename from planetmint/transactions/common/schema/transaction_create_v1.0.yaml rename to planetmint/transactions/common/schema/v1.0/transaction_create.yaml diff --git a/planetmint/transactions/common/schema/transaction_transfer_v1.0.yaml b/planetmint/transactions/common/schema/v1.0/transaction_transfer.yaml similarity index 100% rename from planetmint/transactions/common/schema/transaction_transfer_v1.0.yaml rename to planetmint/transactions/common/schema/v1.0/transaction_transfer.yaml diff --git a/planetmint/transactions/common/schema/transaction_v2.0.yaml b/planetmint/transactions/common/schema/v2.0/transaction.yaml similarity index 100% rename from planetmint/transactions/common/schema/transaction_v2.0.yaml rename to planetmint/transactions/common/schema/v2.0/transaction.yaml diff --git a/planetmint/transactions/common/schema/transaction_chain_migration_election_v2.0.yaml b/planetmint/transactions/common/schema/v2.0/transaction_chain_migration_election.yaml similarity index 100% rename from planetmint/transactions/common/schema/transaction_chain_migration_election_v2.0.yaml rename to planetmint/transactions/common/schema/v2.0/transaction_chain_migration_election.yaml diff --git a/planetmint/transactions/common/schema/transaction_create_v2.0.yaml b/planetmint/transactions/common/schema/v2.0/transaction_create.yaml similarity index 100% rename from planetmint/transactions/common/schema/transaction_create_v2.0.yaml rename to planetmint/transactions/common/schema/v2.0/transaction_create.yaml diff --git a/planetmint/transactions/common/schema/transaction_transfer_v2.0.yaml b/planetmint/transactions/common/schema/v2.0/transaction_transfer.yaml similarity index 100% rename from planetmint/transactions/common/schema/transaction_transfer_v2.0.yaml rename to planetmint/transactions/common/schema/v2.0/transaction_transfer.yaml diff --git a/planetmint/transactions/common/schema/transaction_validator_election_v2.0.yaml b/planetmint/transactions/common/schema/v2.0/transaction_validator_election.yaml similarity index 100% rename from planetmint/transactions/common/schema/transaction_validator_election_v2.0.yaml rename to planetmint/transactions/common/schema/v2.0/transaction_validator_election.yaml diff --git a/planetmint/transactions/common/schema/transaction_vote_v2.0.yaml b/planetmint/transactions/common/schema/v2.0/transaction_vote.yaml similarity index 100% rename from planetmint/transactions/common/schema/transaction_vote_v2.0.yaml rename to planetmint/transactions/common/schema/v2.0/transaction_vote.yaml diff --git a/planetmint/transactions/common/schema/v3.0/transaction.yaml b/planetmint/transactions/common/schema/v3.0/transaction.yaml new file mode 100644 index 0000000..ca64ce9 --- /dev/null +++ b/planetmint/transactions/common/schema/v3.0/transaction.yaml @@ -0,0 +1,174 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +--- +"$schema": "http://json-schema.org/draft-04/schema#" +type: object +additionalProperties: false +title: Transaction Schema +required: +- id +- inputs +- outputs +- operation +- metadata +- assets +- version +properties: + id: + anyOf: + - "$ref": "#/definitions/sha3_hexdigest" + - type: 'null' + operation: + "$ref": "#/definitions/operation" + assets: + type: array + items: + "$ref": "#/definitions/asset" + inputs: + type: array + title: "Transaction inputs" + items: + "$ref": "#/definitions/input" + outputs: + type: array + items: + "$ref": "#/definitions/output" + metadata: + "$ref": "#/definitions/metadata" + version: + type: string + pattern: "^2\\.0$" +definitions: + offset: + type: integer + minimum: 0 + base58: + pattern: "[1-9a-zA-Z^OIl]{43,44}" + type: string + public_keys: + anyOf: + - type: array + items: + "$ref": "#/definitions/base58" + - type: 'null' + sha3_hexdigest: + pattern: "[0-9a-f]{64}" + type: string + uuid4: + pattern: "[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}" + type: string + operation: + type: string + enum: + - CREATE + - TRANSFER + - VALIDATOR_ELECTION + - CHAIN_MIGRATION_ELECTION + - VOTE + - COMPOSE + - DECOMPOSE + asset: + type: object + additionalProperties: false + properties: + id: + "$ref": "#/definitions/sha3_hexdigest" + data: + anyOf: + - type: object + additionalProperties: true + - type: 'null' + output: + type: object + additionalProperties: false + required: + - amount + - condition + - public_keys + properties: + amount: + type: string + pattern: "^[0-9]{1,20}$" + condition: + type: object + additionalProperties: false + required: + - details + - uri + properties: + details: + "$ref": "#/definitions/condition_details" + uri: + type: string + pattern: "^ni:///sha-256;([a-zA-Z0-9_-]{0,86})[?]\ + (fpt=(ed25519|threshold)-sha-256(&)?|cost=[0-9]+(&)?|\ + subtypes=ed25519-sha-256(&)?){2,3}$" + public_keys: + "$ref": "#/definitions/public_keys" + input: + type: "object" + additionalProperties: false + required: + - owners_before + - fulfillment + properties: + owners_before: + "$ref": "#/definitions/public_keys" + fulfillment: + anyOf: + - type: string + pattern: "^[a-zA-Z0-9_-]*$" + - "$ref": "#/definitions/condition_details" + fulfills: + anyOf: + - type: 'object' + additionalProperties: false + required: + - output_index + - transaction_id + properties: + output_index: + "$ref": "#/definitions/offset" + transaction_id: + "$ref": "#/definitions/sha3_hexdigest" + - type: 'null' + metadata: + anyOf: + - type: object + additionalProperties: true + minProperties: 1 + - type: 'null' + condition_details: + anyOf: + - type: object + additionalProperties: false + required: + - type + - public_key + properties: + type: + type: string + pattern: "^ed25519-sha-256$" + public_key: + "$ref": "#/definitions/base58" + - type: object + additionalProperties: false + required: + - type + - threshold + - subconditions + properties: + type: + type: "string" + pattern: "^threshold-sha-256$" + threshold: + type: integer + minimum: 1 + maximum: 100 + subconditions: + type: array + items: + "$ref": "#/definitions/condition_details" From 167d97051129ab175dda15752d21fd82f06dd88e Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger Date: Thu, 31 Mar 2022 11:09:32 +0200 Subject: [PATCH 74/93] updated asset definition on v3.0 transaction types Signed-off-by: Lorenz Herzberger --- .../transaction_chain_migration_election.yaml | 51 +++++++++++++ .../schema/v3.0/transaction_create.yaml | 42 +++++++++++ .../schema/v3.0/transaction_transfer.yaml | 39 ++++++++++ .../v3.0/transaction_validator_election.yaml | 74 +++++++++++++++++++ .../common/schema/v3.0/transaction_vote.yaml | 34 +++++++++ 5 files changed, 240 insertions(+) create mode 100644 planetmint/transactions/common/schema/v3.0/transaction_chain_migration_election.yaml create mode 100644 planetmint/transactions/common/schema/v3.0/transaction_create.yaml create mode 100644 planetmint/transactions/common/schema/v3.0/transaction_transfer.yaml create mode 100644 planetmint/transactions/common/schema/v3.0/transaction_validator_election.yaml create mode 100644 planetmint/transactions/common/schema/v3.0/transaction_vote.yaml diff --git a/planetmint/transactions/common/schema/v3.0/transaction_chain_migration_election.yaml b/planetmint/transactions/common/schema/v3.0/transaction_chain_migration_election.yaml new file mode 100644 index 0000000..932c7b1 --- /dev/null +++ b/planetmint/transactions/common/schema/v3.0/transaction_chain_migration_election.yaml @@ -0,0 +1,51 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +--- +"$schema": "http://json-schema.org/draft-04/schema#" +type: object +title: Chain Migration Election Schema - Propose a halt in block production to allow for a version change +required: +- operation +- assets +- outputs +properties: + operation: + type: string + value: "CHAIN_MIGRATION_ELECTION" + assets: + type: array + minItems: 1 + maxItems: 1 + items: + "$ref": "#/definitions/asset" + outputs: + type: array + items: + "$ref": "#/definitions/output" +definitions: + asset: + additionalProperties: false + properties: + data: + additionalProperties: false + properties: + seed: + type: string + required: + - data + output: + type: object + properties: + condition: + type: object + required: + - uri + properties: + uri: + type: string + pattern: "^ni:///sha-256;([a-zA-Z0-9_-]{0,86})[?]\ + (fpt=ed25519-sha-256(&)?|cost=[0-9]+(&)?|\ + subtypes=ed25519-sha-256(&)?){2,3}$" diff --git a/planetmint/transactions/common/schema/v3.0/transaction_create.yaml b/planetmint/transactions/common/schema/v3.0/transaction_create.yaml new file mode 100644 index 0000000..3a34a46 --- /dev/null +++ b/planetmint/transactions/common/schema/v3.0/transaction_create.yaml @@ -0,0 +1,42 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +--- +"$schema": "http://json-schema.org/draft-04/schema#" +type: object +title: Transaction Schema - CREATE specific constraints +required: +- assets +- inputs +properties: + assets: + type: array + minItems: 1 + maxItems: 1 + items: + "$ref": "#/definitions/asset" + inputs: + type: array + title: "Transaction inputs" + maxItems: 1 + minItems: 1 + items: + type: "object" + required: + - fulfills + properties: + fulfills: + type: "null" +definitions: + asset: + additionalProperties: false + properties: + data: + anyOf: + - type: object + additionalProperties: true + - type: 'null' + required: + - data \ No newline at end of file diff --git a/planetmint/transactions/common/schema/v3.0/transaction_transfer.yaml b/planetmint/transactions/common/schema/v3.0/transaction_transfer.yaml new file mode 100644 index 0000000..1bc74e5 --- /dev/null +++ b/planetmint/transactions/common/schema/v3.0/transaction_transfer.yaml @@ -0,0 +1,39 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +--- +"$schema": "http://json-schema.org/draft-04/schema#" +type: object +title: Transaction Schema - TRANSFER specific properties +required: +- assets +properties: + assets: + type: array + minItems: 1 + items: + "$ref": "#/definitions/asset" + inputs: + type: array + title: "Transaction inputs" + minItems: 1 + items: + type: "object" + required: + - fulfills + properties: + fulfills: + type: "object" +definitions: + sha3_hexdigest: + pattern: "[0-9a-f]{64}" + type: string + asset: + additionalProperties: false + properties: + id: + "$ref": "#/definitions/sha3_hexdigest" + required: + - id diff --git a/planetmint/transactions/common/schema/v3.0/transaction_validator_election.yaml b/planetmint/transactions/common/schema/v3.0/transaction_validator_election.yaml new file mode 100644 index 0000000..0d7c93b --- /dev/null +++ b/planetmint/transactions/common/schema/v3.0/transaction_validator_election.yaml @@ -0,0 +1,74 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +--- +"$schema": "http://json-schema.org/draft-04/schema#" +type: object +title: Validator Election Schema - Propose a change to validator set +required: +- operation +- assets +- outputs +properties: + operation: + type: string + value: "VALIDATOR_ELECTION" + assets: + type: array + minItems: 1 + maxItems: 1 + items: + "$ref": "#/definitions/asset" + outputs: + type: array + items: + "$ref": "#/definitions/output" +definitions: + output: + type: object + properties: + condition: + type: object + required: + - uri + properties: + uri: + type: string + pattern: "^ni:///sha-256;([a-zA-Z0-9_-]{0,86})[?]\ + (fpt=ed25519-sha-256(&)?|cost=[0-9]+(&)?|\ + subtypes=ed25519-sha-256(&)?){2,3}$" + asset: + additionalProperties: false + properties: + data: + additionalProperties: false + properties: + node_id: + type: string + seed: + type: string + public_key: + type: object + additionalProperties: false + required: + - value + - type + properties: + value: + type: string + type: + type: string + enum: + - ed25519-base16 + - ed25519-base32 + - ed25519-base64 + power: + "$ref": "#/definitions/positiveInteger" + required: + - node_id + - public_key + - power + required: + - data diff --git a/planetmint/transactions/common/schema/v3.0/transaction_vote.yaml b/planetmint/transactions/common/schema/v3.0/transaction_vote.yaml new file mode 100644 index 0000000..64ed6ee --- /dev/null +++ b/planetmint/transactions/common/schema/v3.0/transaction_vote.yaml @@ -0,0 +1,34 @@ +# Copyright © 2020 Interplanetary Database Association e.V., +# Planetmint and IPDB software contributors. +# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +# Code is Apache-2.0 and docs are CC-BY-4.0 + +--- +"$schema": "http://json-schema.org/draft-04/schema#" +type: object +title: Vote Schema - Vote on an election +required: +- operation +- outputs +properties: + operation: + type: string + value: "VOTE" + outputs: + type: array + items: + "$ref": "#/definitions/output" +definitions: + output: + type: object + properties: + condition: + type: object + required: + - uri + properties: + uri: + type: string + pattern: "^ni:///sha-256;([a-zA-Z0-9_-]{0,86})[?]\ + (fpt=ed25519-sha-256(&)?|cost=[0-9]+(&)?|\ + subtypes=ed25519-sha-256(&)?){2,3}$" From 5fd8bde1236ef4fc6d9a6008c2e6f94311964f34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Mon, 4 Apr 2022 23:20:58 +0200 Subject: [PATCH 75/93] changed planetmint-cryptoconditions reference (#85) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * changed planetmint-cryptoconditions reference Signed-off-by: Jürgen Eckel * increased version and added missing data Signed-off-by: Jürgen Eckel --- planetmint/version.py | 2 +- setup.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/planetmint/version.py b/planetmint/version.py index 1daef8f..20b4fbf 100644 --- a/planetmint/version.py +++ b/planetmint/version.py @@ -3,7 +3,7 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -__version__ = '0.9.0' +__version__ = '0.9.1' __short_version__ = '0.9' # Supported Tendermint versions diff --git a/setup.py b/setup.py index 41119ca..6f881dc 100644 --- a/setup.py +++ b/setup.py @@ -77,8 +77,7 @@ install_requires = [ 'chardet==3.0.4', 'aiohttp==3.7.4', 'abci==0.8.3', - #'planetmint-cryptoconditions>=0.9.0', - 'planetmint-cryptoconditions @ git+https://github.com/planetmint/cryptoconditions.git@gitzenroom', + 'planetmint-cryptoconditions>=0.9.4', 'flask-cors==3.0.10', 'flask-restful==0.3.9', 'flask==2.0.1', @@ -140,5 +139,7 @@ setup( 'dev': dev_require + tests_require + docs_require, 'docs': docs_require, }, - package_data={'planetmint.transactions.common.schema': ['*.yaml']}, + package_data={ + 'planetmint.transactions.common.schema': ['v1.0/*.yaml','v2.0/*.yaml','v3.0/*.yaml' ], + }, ) From af7ee8ea5bd103f185b5e6453ac07b084c1c4953 Mon Sep 17 00:00:00 2001 From: emotemot Date: Fri, 22 Apr 2022 10:27:51 +0300 Subject: [PATCH 76/93] build changes --- docs/root/generate_http_server_api_documentation.py | 4 ++++ .../installation/api/http-samples/api-index-response.http | 4 ++++ .../installation/api/http-samples/index-response.http | 8 ++++++++ 3 files changed, 16 insertions(+) diff --git a/docs/root/generate_http_server_api_documentation.py b/docs/root/generate_http_server_api_documentation.py index 1bf66ae..a3a94e6 100644 --- a/docs/root/generate_http_server_api_documentation.py +++ b/docs/root/generate_http_server_api_documentation.py @@ -9,8 +9,12 @@ import json import os import os.path +<<<<<<< Updated upstream from planetmint.transactions.common.input import Input from planetmint.transactions.common.transaction_link import TransactionLink +======= +from planetmint.common.transaction import Transaction, Input, TransactionLink +>>>>>>> Stashed changes from planetmint import lib from planetmint.transactions.types.assets.create import Create from planetmint.transactions.types.assets.transfer import Transfer diff --git a/docs/root/source/installation/api/http-samples/api-index-response.http b/docs/root/source/installation/api/http-samples/api-index-response.http index 7ba7be8..e92cb2f 100644 --- a/docs/root/source/installation/api/http-samples/api-index-response.http +++ b/docs/root/source/installation/api/http-samples/api-index-response.http @@ -4,7 +4,11 @@ Content-Type: application/json { "assets": "/assets/", "blocks": "/blocks/", +<<<<<<< Updated upstream "docs": "https://docs.planetmint.com/projects/server/en/v0.9.0/http-client-server-api.html", +======= + "docs": "https://docs.bigchaindb.com/projects/server/en/v0.9.0/http-client-server-api.html", +>>>>>>> Stashed changes "metadata": "/metadata/", "outputs": "/outputs/", "streams": "ws://localhost:9985/api/v1/streams/valid_transactions", diff --git a/docs/root/source/installation/api/http-samples/index-response.http b/docs/root/source/installation/api/http-samples/index-response.http index c593a91..1eff019 100644 --- a/docs/root/source/installation/api/http-samples/index-response.http +++ b/docs/root/source/installation/api/http-samples/index-response.http @@ -6,7 +6,11 @@ Content-Type: application/json "v1": { "assets": "/api/v1/assets/", "blocks": "/api/v1/blocks/", +<<<<<<< Updated upstream "docs": "https://docs.planetmint.com/projects/server/en/v0.9.0/http-client-server-api.html", +======= + "docs": "https://docs.bigchaindb.com/projects/server/en/v0.9.0/http-client-server-api.html", +>>>>>>> Stashed changes "metadata": "/api/v1/metadata/", "outputs": "/api/v1/outputs/", "streams": "ws://localhost:9985/api/v1/streams/valid_transactions", @@ -14,7 +18,11 @@ Content-Type: application/json "validators": "/api/v1/validators" } }, +<<<<<<< Updated upstream "docs": "https://docs.planetmint.com/projects/server/en/v0.9.0/", +======= + "docs": "https://docs.bigchaindb.com/projects/server/en/v0.9.0/", +>>>>>>> Stashed changes "software": "Planetmint", "version": "0.9.0" } From 782319591151ebf3cdd44e4323177d01ef9632bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Tue, 26 Apr 2022 11:21:04 +0200 Subject: [PATCH 77/93] added api to get the latest block /api/v1/blocks/latest (#88) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * added api to get the latest block /api/v1/blocks/latest Signed-off-by: Jürgen Eckel * git fixed flake8 whitespace warnings Signed-off-by: Jürgen Eckel * fixed flake8 warnings: removed too many newline Signed-off-by: Jürgen Eckel * added missing deps in the testing docker files Signed-off-by: Jürgen Eckel * install meson prior to the rest to have it availabe and fix the issue of missing depenceny declarations within zenroom Signed-off-by: Jürgen Eckel * added missing ninja dependency Signed-off-by: Jürgen Eckel * fixed zenroom dependency Signed-off-by: Jürgen Eckel --- acceptance/python/Dockerfile | 15 +++++++++------ integration/python/Dockerfile | 13 +++++++++---- planetmint/web/routes.py | 1 + planetmint/web/views/blocks.py | 19 +++++++++++++++++++ tests/web/test_blocks.py | 6 ++++++ 5 files changed, 44 insertions(+), 10 deletions(-) diff --git a/acceptance/python/Dockerfile b/acceptance/python/Dockerfile index 14defda..269446b 100644 --- a/acceptance/python/Dockerfile +++ b/acceptance/python/Dockerfile @@ -4,17 +4,20 @@ 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 RUN mkdir -p /src +RUN /usr/local/bin/python -m pip install --upgrade pip +RUN pip install --upgrade meson ninja +RUN pip install zenroom==2.0.0.dev1644927841 RUN pip install --upgrade \ pycco \ websocket-client~=0.47.0 \ pytest~=3.0 \ - git+https://github.com/planetmint/cryptoconditions.git@gitzenroom \ - git+https://github.com/planetmint/planetmint-driver.git@gitzenroom \ - #planetmint-cryptoconditions>=0.9.0\ - #planetmint-driver>=0.9.0 \ + #git+https://github.com/planetmint/cryptoconditions.git@gitzenroom \ + #git+https://github.com/planetmint/planetmint-driver.git@gitzenroom \ + planetmint-cryptoconditions>=0.9.4\ + planetmint-driver>=0.9.0 \ blns @@ -58,4 +61,4 @@ RUN pip install --upgrade \ # pyyaml==5.4.1 \ # requests==2.25.1 \ # setproctitle==1.2.2 -# \ No newline at end of file +# diff --git a/integration/python/Dockerfile b/integration/python/Dockerfile index 65f5e15..2498a58 100644 --- a/integration/python/Dockerfile +++ b/integration/python/Dockerfile @@ -4,14 +4,19 @@ RUN apt-get update \ && pip install -U pip \ && apt-get autoremove \ && apt-get clean -RUN apt-get install -y vim zsh build-essential cmake openssh-client openssh-server +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 zsh RUN mkdir -p /src +RUN pip install --upgrade meson ninja RUN pip install --upgrade \ pytest~=6.2.5 \ planetmint-driver~=0.9.0 \ pycco \ websocket-client~=0.47.0 \ - git+https://github.com/planetmint/cryptoconditions.git@gitzenroom \ - git+https://github.com/planetmint/planetmint-driver.git@gitzenroom \ - blns \ No newline at end of file + #git+https://github.com/planetmint/cryptoconditions.git@gitzenroom \ + #git+https://github.com/planetmint/planetmint-driver.git@gitzenroom \ + blns + diff --git a/planetmint/web/routes.py b/planetmint/web/routes.py index 7bd51f0..2c650c0 100644 --- a/planetmint/web/routes.py +++ b/planetmint/web/routes.py @@ -34,6 +34,7 @@ ROUTES_API_V1 = [ r('assets/', assets.AssetListApi), r('metadata/', metadata.MetadataApi), r('blocks/', blocks.BlockApi), + r('blocks/latest', blocks.LatestBlock), r('blocks/', blocks.BlockListApi), r('transactions/', tx.TransactionApi), r('transactions', tx.TransactionListApi), diff --git a/planetmint/web/views/blocks.py b/planetmint/web/views/blocks.py index 5a8ae41..5154ba3 100644 --- a/planetmint/web/views/blocks.py +++ b/planetmint/web/views/blocks.py @@ -13,6 +13,25 @@ from flask_restful import Resource, reqparse from planetmint.web.views.base import make_error +class LatestBlock(Resource): + def get(self): + """API endpoint to get details about a block. + + Return: + A JSON string containing the data about the block. + """ + + pool = current_app.config['bigchain_pool'] + + with pool() as planet: + block = planet.get_latest_block() + + if not block: + return make_error(404) + + return block + + class BlockApi(Resource): def get(self, block_id): """API endpoint to get details about a block. diff --git a/tests/web/test_blocks.py b/tests/web/test_blocks.py index 54aa134..7dfc00e 100644 --- a/tests/web/test_blocks.py +++ b/tests/web/test_blocks.py @@ -17,6 +17,12 @@ def test_get_block_returns_404_if_not_found(client): res = client.get(BLOCKS_ENDPOINT + '123/') assert res.status_code == 404 + res = client.get(BLOCKS_ENDPOINT + 'latest') + assert res.status_code == 200 + + res = client.get(BLOCKS_ENDPOINT + 'latest/') + assert res.status_code == 200 + @pytest.mark.bdb def test_get_blocks_by_txid_endpoint_returns_empty_list_not_found(client): From 6fc8821749515822e06442592d91ce3a584057e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Wed, 27 Apr 2022 17:15:00 +0200 Subject: [PATCH 78/93] inc version number + added twine dep (#90) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jürgen Eckel --- planetmint/version.py | 2 +- setup.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/planetmint/version.py b/planetmint/version.py index 20b4fbf..3500cb5 100644 --- a/planetmint/version.py +++ b/planetmint/version.py @@ -3,7 +3,7 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -__version__ = '0.9.1' +__version__ = '0.9.2' __short_version__ = '0.9' # Supported Tendermint versions diff --git a/setup.py b/setup.py index 6f881dc..5b623c8 100644 --- a/setup.py +++ b/setup.py @@ -43,7 +43,8 @@ dev_require = [ 'ipython', 'watchdog', 'logging_tree', - 'pre-commit' + 'pre-commit', + 'twine' ] docs_require = [ From ee504a0547181adb7f8727ad545359a35fa276f8 Mon Sep 17 00:00:00 2001 From: emotemot Date: Mon, 2 May 2022 14:58:47 +0300 Subject: [PATCH 79/93] updated .yml --- .readthedocs.yml | 35 ++++++++++++++++--- .../generate_http_server_api_documentation.py | 4 --- .../api/http-samples/api-index-response.http | 6 +--- .../api/http-samples/index-response.http | 14 ++------ docs/root/source/terminology.md | 13 +++---- 5 files changed, 39 insertions(+), 33 deletions(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 2ccc3f9..e2f0dfb 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -3,9 +3,36 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -build: - image: latest +#build: +# image: latest +#python: +# version: 3.9 +# pip_install: true + + +# Required +version: 2 + +# Set the version of Python and other tools you might need +build: + os: ubuntu-20.04 + tools: + python: "3.9" + # You can also specify other tool versions: + # nodejs: "16" + # rust: "1.55" + # golang: "1.17" + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: docs/conf.py + +# If using Sphinx, optionally build your docs in additional formats such as PDF +# formats: +# - pdf + +# Optionally declare the Python requirements required to build your docs python: - version: 3.9 - pip_install: true + install: + - requirements: docs/requirements.txt \ No newline at end of file diff --git a/docs/root/generate_http_server_api_documentation.py b/docs/root/generate_http_server_api_documentation.py index a3a94e6..1bf66ae 100644 --- a/docs/root/generate_http_server_api_documentation.py +++ b/docs/root/generate_http_server_api_documentation.py @@ -9,12 +9,8 @@ import json import os import os.path -<<<<<<< Updated upstream from planetmint.transactions.common.input import Input from planetmint.transactions.common.transaction_link import TransactionLink -======= -from planetmint.common.transaction import Transaction, Input, TransactionLink ->>>>>>> Stashed changes from planetmint import lib from planetmint.transactions.types.assets.create import Create from planetmint.transactions.types.assets.transfer import Transfer diff --git a/docs/root/source/installation/api/http-samples/api-index-response.http b/docs/root/source/installation/api/http-samples/api-index-response.http index e92cb2f..601f9ef 100644 --- a/docs/root/source/installation/api/http-samples/api-index-response.http +++ b/docs/root/source/installation/api/http-samples/api-index-response.http @@ -4,11 +4,7 @@ Content-Type: application/json { "assets": "/assets/", "blocks": "/blocks/", -<<<<<<< Updated upstream - "docs": "https://docs.planetmint.com/projects/server/en/v0.9.0/http-client-server-api.html", -======= - "docs": "https://docs.bigchaindb.com/projects/server/en/v0.9.0/http-client-server-api.html", ->>>>>>> Stashed changes + "docs": "https://docs.planetmint.com/projects/server/en/v0.9.1/http-client-server-api.html", "metadata": "/metadata/", "outputs": "/outputs/", "streams": "ws://localhost:9985/api/v1/streams/valid_transactions", diff --git a/docs/root/source/installation/api/http-samples/index-response.http b/docs/root/source/installation/api/http-samples/index-response.http index 1eff019..f7e524e 100644 --- a/docs/root/source/installation/api/http-samples/index-response.http +++ b/docs/root/source/installation/api/http-samples/index-response.http @@ -6,11 +6,7 @@ Content-Type: application/json "v1": { "assets": "/api/v1/assets/", "blocks": "/api/v1/blocks/", -<<<<<<< Updated upstream - "docs": "https://docs.planetmint.com/projects/server/en/v0.9.0/http-client-server-api.html", -======= - "docs": "https://docs.bigchaindb.com/projects/server/en/v0.9.0/http-client-server-api.html", ->>>>>>> Stashed changes + "docs": "https://docs.planetmint.com/projects/server/en/v0.9.1/http-client-server-api.html", "metadata": "/api/v1/metadata/", "outputs": "/api/v1/outputs/", "streams": "ws://localhost:9985/api/v1/streams/valid_transactions", @@ -18,11 +14,7 @@ Content-Type: application/json "validators": "/api/v1/validators" } }, -<<<<<<< Updated upstream - "docs": "https://docs.planetmint.com/projects/server/en/v0.9.0/", -======= - "docs": "https://docs.bigchaindb.com/projects/server/en/v0.9.0/", ->>>>>>> Stashed changes + "docs": "https://docs.planetmint.com/projects/server/en/v0.9.1/", "software": "Planetmint", - "version": "0.9.0" + "version": "0.9.1" } diff --git a/docs/root/source/terminology.md b/docs/root/source/terminology.md index 6f42b32..8c51eca 100644 --- a/docs/root/source/terminology.md +++ b/docs/root/source/terminology.md @@ -11,11 +11,9 @@ There is some specialized terminology associated with Planetmint. To get started ### Planetmint Node -<<<<<<< HEAD -A **Planetmint node** is a machine (or logical machine) running [Planetmint Server](https://docs.planetmint.com/projects/server/en/latest/introduction.html) and related software. Each node is controlled by one person or organization. -======= -A **Planetmint node** is a machine (or logical machine) running [Planetmint Server](https://docs.planetmint.io/projects/server/en/latest/introduction.html) and related software. Each node is controlled by one person or organization. ->>>>>>> 3bfc3298f8210b135084e823eedd47f213538088 +**Planetmint node** is a machine (or logical machine) running [Planetmint Server](https://docs.planetmint.com/projects/server/en/latest/introduction.html) and related software. Each node is controlled by one person or organization. + +**Planetmint node** is a machine (or logical machine) running [Planetmint Server](https://docs.planetmint.io/projects/server/en/latest/introduction.html) and related software. Each node is controlled by one person or organization. ### Planetmint Network @@ -80,10 +78,7 @@ You could do more elaborate things too. As one example, each time someone writes ### Role-Based Access Control (RBAC) -<<<<<<< HEAD In September 2017, we published a [blog post about how one can define an RBAC sub-system on top of Planetmint](https://blog.planetmint.com/role-based-access-control-for-planetmint-assets-b7cada491997). -======= -In September 2017, BigchainDB published a [blog post about how one can define an RBAC sub-system on top of Planetmint](https://blog.bigchaindb.com/role-based-access-control-for-planetmint-assets-b7cada491997). ->>>>>>> 3bfc3298f8210b135084e823eedd47f213538088 + At the time of writing (January 2018), doing so required the use of a plugin, so it's not possible using standard Planetmint (which is what's available on the [IPDB Testnet](https://test.ipdb.io/>). That may change in the future. If you're interested, `contact IPDB `_. From c5b04aafc4b41b39412eb940b538411d286e9fd7 Mon Sep 17 00:00:00 2001 From: enesturk Date: Mon, 2 May 2022 15:19:47 +0300 Subject: [PATCH 80/93] build changes (#86) * build changes * updated .yml --- .readthedocs.yml | 35 ++++++++++++++++--- .../api/http-samples/api-index-response.http | 2 +- .../api/http-samples/index-response.http | 6 ++-- docs/root/source/terminology.md | 13 +++---- 4 files changed, 39 insertions(+), 17 deletions(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 2ccc3f9..e2f0dfb 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -3,9 +3,36 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -build: - image: latest +#build: +# image: latest +#python: +# version: 3.9 +# pip_install: true + + +# Required +version: 2 + +# Set the version of Python and other tools you might need +build: + os: ubuntu-20.04 + tools: + python: "3.9" + # You can also specify other tool versions: + # nodejs: "16" + # rust: "1.55" + # golang: "1.17" + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: docs/conf.py + +# If using Sphinx, optionally build your docs in additional formats such as PDF +# formats: +# - pdf + +# Optionally declare the Python requirements required to build your docs python: - version: 3.9 - pip_install: true + install: + - requirements: docs/requirements.txt \ No newline at end of file diff --git a/docs/root/source/installation/api/http-samples/api-index-response.http b/docs/root/source/installation/api/http-samples/api-index-response.http index 7ba7be8..601f9ef 100644 --- a/docs/root/source/installation/api/http-samples/api-index-response.http +++ b/docs/root/source/installation/api/http-samples/api-index-response.http @@ -4,7 +4,7 @@ Content-Type: application/json { "assets": "/assets/", "blocks": "/blocks/", - "docs": "https://docs.planetmint.com/projects/server/en/v0.9.0/http-client-server-api.html", + "docs": "https://docs.planetmint.com/projects/server/en/v0.9.1/http-client-server-api.html", "metadata": "/metadata/", "outputs": "/outputs/", "streams": "ws://localhost:9985/api/v1/streams/valid_transactions", diff --git a/docs/root/source/installation/api/http-samples/index-response.http b/docs/root/source/installation/api/http-samples/index-response.http index c593a91..f7e524e 100644 --- a/docs/root/source/installation/api/http-samples/index-response.http +++ b/docs/root/source/installation/api/http-samples/index-response.http @@ -6,7 +6,7 @@ Content-Type: application/json "v1": { "assets": "/api/v1/assets/", "blocks": "/api/v1/blocks/", - "docs": "https://docs.planetmint.com/projects/server/en/v0.9.0/http-client-server-api.html", + "docs": "https://docs.planetmint.com/projects/server/en/v0.9.1/http-client-server-api.html", "metadata": "/api/v1/metadata/", "outputs": "/api/v1/outputs/", "streams": "ws://localhost:9985/api/v1/streams/valid_transactions", @@ -14,7 +14,7 @@ Content-Type: application/json "validators": "/api/v1/validators" } }, - "docs": "https://docs.planetmint.com/projects/server/en/v0.9.0/", + "docs": "https://docs.planetmint.com/projects/server/en/v0.9.1/", "software": "Planetmint", - "version": "0.9.0" + "version": "0.9.1" } diff --git a/docs/root/source/terminology.md b/docs/root/source/terminology.md index 6f42b32..8c51eca 100644 --- a/docs/root/source/terminology.md +++ b/docs/root/source/terminology.md @@ -11,11 +11,9 @@ There is some specialized terminology associated with Planetmint. To get started ### Planetmint Node -<<<<<<< HEAD -A **Planetmint node** is a machine (or logical machine) running [Planetmint Server](https://docs.planetmint.com/projects/server/en/latest/introduction.html) and related software. Each node is controlled by one person or organization. -======= -A **Planetmint node** is a machine (or logical machine) running [Planetmint Server](https://docs.planetmint.io/projects/server/en/latest/introduction.html) and related software. Each node is controlled by one person or organization. ->>>>>>> 3bfc3298f8210b135084e823eedd47f213538088 +**Planetmint node** is a machine (or logical machine) running [Planetmint Server](https://docs.planetmint.com/projects/server/en/latest/introduction.html) and related software. Each node is controlled by one person or organization. + +**Planetmint node** is a machine (or logical machine) running [Planetmint Server](https://docs.planetmint.io/projects/server/en/latest/introduction.html) and related software. Each node is controlled by one person or organization. ### Planetmint Network @@ -80,10 +78,7 @@ You could do more elaborate things too. As one example, each time someone writes ### Role-Based Access Control (RBAC) -<<<<<<< HEAD In September 2017, we published a [blog post about how one can define an RBAC sub-system on top of Planetmint](https://blog.planetmint.com/role-based-access-control-for-planetmint-assets-b7cada491997). -======= -In September 2017, BigchainDB published a [blog post about how one can define an RBAC sub-system on top of Planetmint](https://blog.bigchaindb.com/role-based-access-control-for-planetmint-assets-b7cada491997). ->>>>>>> 3bfc3298f8210b135084e823eedd47f213538088 + At the time of writing (January 2018), doing so required the use of a plugin, so it's not possible using standard Planetmint (which is what's available on the [IPDB Testnet](https://test.ipdb.io/>). That may change in the future. If you're interested, `contact IPDB `_. From a9655629197f720587c7360764223244621c4bda Mon Sep 17 00:00:00 2001 From: emotemot Date: Mon, 2 May 2022 15:44:19 +0300 Subject: [PATCH 81/93] requirements.txt updated --- .readthedocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index e2f0dfb..9819c43 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -35,4 +35,4 @@ sphinx: # Optionally declare the Python requirements required to build your docs python: install: - - requirements: docs/requirements.txt \ No newline at end of file + - requirements: docs/root/requirements.txt \ No newline at end of file From 7a3a7810fd3bf3c97878ab924c11eed9ba42220e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Mon, 9 May 2022 10:39:21 +0200 Subject: [PATCH 82/93] fixed reference to conf.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jürgen Eckel --- .readthedocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 36567cc..6d5562a 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -26,7 +26,7 @@ build: # Build documentation in the docs/ directory with Sphinx sphinx: - configuration: docs/conf.py + configuration: docs/root/source/conf.py # If using Sphinx, optionally build your docs in additional formats such as PDF # formats: From 7fbbd640d3f64c061023fd121ee77e9942f5129c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Mon, 9 May 2022 11:30:34 +0200 Subject: [PATCH 83/93] testing rtd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jürgen Eckel --- .readthedocs.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 6d5562a..e0bb5da 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -25,8 +25,8 @@ build: # golang: "1.17" # Build documentation in the docs/ directory with Sphinx -sphinx: - configuration: docs/root/source/conf.py +#sphinx: +# configuration: docs/root/source/conf.py # If using Sphinx, optionally build your docs in additional formats such as PDF # formats: @@ -34,5 +34,6 @@ sphinx: # Optionally declare the Python requirements required to build your docs python: + version: 3.9 install: - requirements: docs/root/requirements.txt From 9f81fb92b6b55c4b898891849bc554f577fd5f25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Mon, 9 May 2022 11:39:35 +0200 Subject: [PATCH 84/93] added pip_install: true MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jürgen Eckel --- .readthedocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.readthedocs.yml b/.readthedocs.yml index e0bb5da..bead17a 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -35,5 +35,6 @@ build: # Optionally declare the Python requirements required to build your docs python: version: 3.9 + pip_install: true install: - requirements: docs/root/requirements.txt From e12bfe101fd6d9ec605b6050a4e596656a5a3d28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Mon, 9 May 2022 11:41:09 +0200 Subject: [PATCH 85/93] removed python version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jürgen Eckel --- .readthedocs.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index bead17a..e81dd5d 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -34,7 +34,6 @@ build: # Optionally declare the Python requirements required to build your docs python: - version: 3.9 pip_install: true install: - requirements: docs/root/requirements.txt From cbda2a47c85b3a4b4d5672d7ac12e231ff1b3665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Mon, 9 May 2022 11:47:55 +0200 Subject: [PATCH 86/93] addes setuptools installation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jürgen Eckel --- .readthedocs.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index e81dd5d..be79e36 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -34,6 +34,7 @@ build: # Optionally declare the Python requirements required to build your docs python: - pip_install: true + version: "3.9" install: - requirements: docs/root/requirements.txt + - method: setuptools From 0c1c56e76ad7fb2a791f3013529217dce8f39b2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Mon, 9 May 2022 11:48:58 +0200 Subject: [PATCH 87/93] fixed path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jürgen Eckel --- .readthedocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.readthedocs.yml b/.readthedocs.yml index be79e36..d8e94e7 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -38,3 +38,4 @@ python: install: - requirements: docs/root/requirements.txt - method: setuptools + path: . From 48c89907050e59d5c694f4ac8fd6daa2b310dd3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Mon, 9 May 2022 11:49:47 +0200 Subject: [PATCH 88/93] rm version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jürgen Eckel --- .readthedocs.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index d8e94e7..841753b 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -34,7 +34,6 @@ build: # Optionally declare the Python requirements required to build your docs python: - version: "3.9" install: - requirements: docs/root/requirements.txt - method: setuptools From 395f078e9e2c1f297ee57c55f03e7f6bfb64fc97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Mon, 9 May 2022 11:55:40 +0200 Subject: [PATCH 89/93] changed installation order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jürgen Eckel --- .readthedocs.yml | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 841753b..d1a6b51 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -3,38 +3,17 @@ # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 -#build: -# image: latest -#python: -# version: 3.9 -# pip_install: true - - -# Required version: 2 -# Set the version of Python and other tools you might need + build: os: ubuntu-20.04 tools: python: "3.9" - # You can also specify other tool versions: - # nodejs: "16" - # rust: "1.55" - # golang: "1.17" -# Build documentation in the docs/ directory with Sphinx -#sphinx: -# configuration: docs/root/source/conf.py - -# If using Sphinx, optionally build your docs in additional formats such as PDF -# formats: -# - pdf - -# Optionally declare the Python requirements required to build your docs python: install: - - requirements: docs/root/requirements.txt - method: setuptools path: . + - requirements: docs/root/requirements.txt From 5d22dfa1149d9fe8993458051ae3d6fb8ab75c0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Tue, 10 May 2022 00:08:39 +0200 Subject: [PATCH 90/93] upgraded sphinx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jürgen Eckel --- docs/root/requirements.txt | 5 +++-- docs/root/source/conf.py | 19 ++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/docs/root/requirements.txt b/docs/root/requirements.txt index f04211f..fd9c9f9 100644 --- a/docs/root/requirements.txt +++ b/docs/root/requirements.txt @@ -1,5 +1,5 @@ -Sphinx~=1.0 -recommonmark>=0.4.0 +Sphinx>=2.1.0 +#recommonmark>=0.4.0 sphinx-rtd-theme>=0.1.9 sphinxcontrib-napoleon>=0.4.4 sphinxcontrib-httpdomain>=1.5.0 @@ -8,3 +8,4 @@ aafigure>=0.6 packaging~=18.0 wget jinja2==3.0.0 +myst-parser diff --git a/docs/root/source/conf.py b/docs/root/source/conf.py index 8dee073..0e9dc83 100644 --- a/docs/root/source/conf.py +++ b/docs/root/source/conf.py @@ -23,9 +23,7 @@ import sys import inspect from os import rename, remove -from recommonmark.parser import CommonMarkParser - - +#from recommonmark.parser import CommonMarkParser # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -51,9 +49,12 @@ sys.path.insert(0,parentdir) # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. +project = 'Planetmint' + import sphinx_rtd_theme extensions = [ + 'myst_parser', 'sphinx.ext.autosectionlabel', 'sphinx.ext.autodoc', 'sphinx.ext.intersphinx', @@ -61,6 +62,7 @@ extensions = [ 'sphinx.ext.viewcode', 'sphinx.ext.todo', 'sphinx.ext.napoleon', + #'sphinx.project', 'sphinxcontrib.httpdomain', 'aafigure.sphinxext', # Below are actually build steps made to look like sphinx extensions. @@ -99,9 +101,9 @@ autodoc_default_options = { 'members': None, } -source_parsers = { - '.md': CommonMarkParser, -} +#source_parsers = { +# '.md': CommonMarkParser, +#} # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: @@ -115,9 +117,8 @@ source_suffix = ['.rst', '.md'] # The master toctree document. master_doc = 'index' - +autosectionlabel_prefix_document = True # General information about the project. -project = 'Planetmint' now = datetime.datetime.now() copyright = str(now.year) + ', Planetmint Contributors' author = 'Planetmint Contributors' @@ -137,7 +138,7 @@ release = _version['__version__'] # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = 'en' # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: From ff897848ea567fcb07b08e6ff6d94d1809a12f22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Tue, 10 May 2022 00:15:45 +0200 Subject: [PATCH 91/93] fixed requirements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jürgen Eckel --- docs/root/requirements.txt | 51 ++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/docs/root/requirements.txt b/docs/root/requirements.txt index fd9c9f9..1f5622f 100644 --- a/docs/root/requirements.txt +++ b/docs/root/requirements.txt @@ -1,11 +1,40 @@ -Sphinx>=2.1.0 -#recommonmark>=0.4.0 -sphinx-rtd-theme>=0.1.9 -sphinxcontrib-napoleon>=0.4.4 -sphinxcontrib-httpdomain>=1.5.0 -pyyaml>=4.2b1 -aafigure>=0.6 -packaging~=18.0 -wget -jinja2==3.0.0 -myst-parser +aafigure==0.6 +alabaster==0.7.12 +Babel==2.10.1 +certifi==2021.10.8 +charset-normalizer==2.0.12 +commonmark==0.9.1 +docutils==0.17.1 +idna==3.3 +imagesize==1.3.0 +importlib-metadata==4.11.3 +Jinja2==3.0.0 +markdown-it-py==2.1.0 +MarkupSafe==2.1.1 +mdit-py-plugins==0.3.0 +mdurl==0.1.1 +myst-parser==0.17.2 +packaging==21.3 +pockets==0.9.1 +Pygments==2.12.0 +pyparsing==3.0.8 +pytz==2022.1 +PyYAML==6.0 +recommonmark==0.7.1 +requests==2.27.1 +six==1.16.0 +snowballstemmer==2.2.0 +Sphinx==4.5.0 +sphinx-rtd-theme==1.0.0 +sphinxcontrib-applehelp==1.0.2 +sphinxcontrib-devhelp==1.0.2 +sphinxcontrib-htmlhelp==2.0.0 +sphinxcontrib-httpdomain==1.8.0 +sphinxcontrib-jsmath==1.0.1 +sphinxcontrib-napoleon==0.7 +sphinxcontrib-qthelp==1.0.3 +sphinxcontrib-serializinghtml==1.1.5 +typing-extensions==4.2.0 +urllib3==1.26.9 +wget==3.2 +zipp==3.8.0 From eba8b9220977a4e7de4b15f86031efdbc2bf1987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Tue, 10 May 2022 00:16:44 +0200 Subject: [PATCH 92/93] cleaned up conf.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jürgen Eckel --- docs/root/source/conf.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/root/source/conf.py b/docs/root/source/conf.py index 0e9dc83..5c082ea 100644 --- a/docs/root/source/conf.py +++ b/docs/root/source/conf.py @@ -23,7 +23,6 @@ import sys import inspect from os import rename, remove -#from recommonmark.parser import CommonMarkParser # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -62,7 +61,6 @@ extensions = [ 'sphinx.ext.viewcode', 'sphinx.ext.todo', 'sphinx.ext.napoleon', - #'sphinx.project', 'sphinxcontrib.httpdomain', 'aafigure.sphinxext', # Below are actually build steps made to look like sphinx extensions. @@ -101,10 +99,6 @@ autodoc_default_options = { 'members': None, } -#source_parsers = { -# '.md': CommonMarkParser, -#} - # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # From 408c42a3a1f4372a8d594c1fb844c4d8ef19d789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Eckel?= Date: Thu, 12 May 2022 19:26:44 +0200 Subject: [PATCH 93/93] fixed docs to pass the build (#107) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fixed docs to pass the build Signed-off-by: Jürgen Eckel * fixed docs building issue Signed-off-by: Jürgen Eckel * removed obsolete deps Signed-off-by: Jürgen Eckel * fixed missing reference issue Signed-off-by: Jürgen Eckel * removed warning as error and redo a previous fix Signed-off-by: Jürgen Eckel --- docs/root/Makefile | 2 +- docs/root/requirements.txt | 8 +++----- .../api/http-samples/api-index-response.http | 2 +- .../api/http-samples/index-response.http | 6 +++--- docs/root/source/properties.md | 8 ++++---- docs/root/source/terminology.md | 8 ++++---- setup.py | 20 +++++++++---------- tox.ini | 2 +- 8 files changed, 26 insertions(+), 30 deletions(-) diff --git a/docs/root/Makefile b/docs/root/Makefile index 035608b..357bb5c 100644 --- a/docs/root/Makefile +++ b/docs/root/Makefile @@ -2,7 +2,7 @@ # # You can set these variables from the command line. -SPHINXOPTS = -W +SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = a4 BUILDDIR = build diff --git a/docs/root/requirements.txt b/docs/root/requirements.txt index 1f5622f..8d8ed0f 100644 --- a/docs/root/requirements.txt +++ b/docs/root/requirements.txt @@ -5,7 +5,7 @@ certifi==2021.10.8 charset-normalizer==2.0.12 commonmark==0.9.1 docutils==0.17.1 -idna==3.3 +idna imagesize==1.3.0 importlib-metadata==4.11.3 Jinja2==3.0.0 @@ -19,9 +19,8 @@ pockets==0.9.1 Pygments==2.12.0 pyparsing==3.0.8 pytz==2022.1 -PyYAML==6.0 -recommonmark==0.7.1 -requests==2.27.1 +PyYAML>=5.4.0 +requests>=2.25i.1 six==1.16.0 snowballstemmer==2.2.0 Sphinx==4.5.0 @@ -34,7 +33,6 @@ sphinxcontrib-jsmath==1.0.1 sphinxcontrib-napoleon==0.7 sphinxcontrib-qthelp==1.0.3 sphinxcontrib-serializinghtml==1.1.5 -typing-extensions==4.2.0 urllib3==1.26.9 wget==3.2 zipp==3.8.0 diff --git a/docs/root/source/installation/api/http-samples/api-index-response.http b/docs/root/source/installation/api/http-samples/api-index-response.http index 601f9ef..fe767cd 100644 --- a/docs/root/source/installation/api/http-samples/api-index-response.http +++ b/docs/root/source/installation/api/http-samples/api-index-response.http @@ -4,7 +4,7 @@ Content-Type: application/json { "assets": "/assets/", "blocks": "/blocks/", - "docs": "https://docs.planetmint.com/projects/server/en/v0.9.1/http-client-server-api.html", + "docs": "https://docs.planetmint.com/projects/server/en/v0.9.2/http-client-server-api.html", "metadata": "/metadata/", "outputs": "/outputs/", "streams": "ws://localhost:9985/api/v1/streams/valid_transactions", diff --git a/docs/root/source/installation/api/http-samples/index-response.http b/docs/root/source/installation/api/http-samples/index-response.http index f7e524e..789da5e 100644 --- a/docs/root/source/installation/api/http-samples/index-response.http +++ b/docs/root/source/installation/api/http-samples/index-response.http @@ -6,7 +6,7 @@ Content-Type: application/json "v1": { "assets": "/api/v1/assets/", "blocks": "/api/v1/blocks/", - "docs": "https://docs.planetmint.com/projects/server/en/v0.9.1/http-client-server-api.html", + "docs": "https://docs.planetmint.com/projects/server/en/v0.9.2/http-client-server-api.html", "metadata": "/api/v1/metadata/", "outputs": "/api/v1/outputs/", "streams": "ws://localhost:9985/api/v1/streams/valid_transactions", @@ -14,7 +14,7 @@ Content-Type: application/json "validators": "/api/v1/validators" } }, - "docs": "https://docs.planetmint.com/projects/server/en/v0.9.1/", + "docs": "https://docs.planetmint.com/projects/server/en/v0.9.2/", "software": "Planetmint", - "version": "0.9.1" + "version": "0.9.2" } diff --git a/docs/root/source/properties.md b/docs/root/source/properties.md index 862f464..861fe0a 100644 --- a/docs/root/source/properties.md +++ b/docs/root/source/properties.md @@ -7,7 +7,7 @@ Code is Apache-2.0 and docs are CC-BY-4.0 # Properties of Planetmint -### Decentralization +## Decentralization Decentralization means that no one owns or controls everything, and there is no single point of failure. @@ -23,12 +23,12 @@ If someone has (or gets) admin access to a node, they can mess with that node (e It’s worth noting that not even the admin or superuser of a node can transfer assets. The only way to create a valid transfer transaction is to fulfill the current crypto-conditions on the asset, and the admin/superuser can’t do that because the admin user doesn’t have the necessary information (e.g. private keys). -### Byzantine Fault Tolerance +## Byzantine Fault Tolerance [Tendermint](https://tendermint.io/) is used for consensus and transaction replication, and Tendermint is [Byzantine Fault Tolerant (BFT)](https://en.wikipedia.org/wiki/Byzantine_fault_tolerance). -### Node Diversity +## Node Diversity Steps should be taken to make it difficult for any one actor or event to control or damage “enough” of the nodes. (Because Planetmint Server uses Tendermint, "enough" is ⅓.) There are many kinds of diversity to consider, listed below. It may be quite difficult to have high diversity of all kinds. @@ -39,7 +39,7 @@ Steps should be taken to make it difficult for any one actor or event to control Note: If all the nodes are running the same code, i.e. the same implementation of Planetmint, then a bug in that code could be used to compromise all of the nodes. Ideally, there would be several different, well-maintained implementations of Planetmint Server (e.g. one in Python, one in Go, etc.), so that a consortium could also have a diversity of server implementations. Similar remarks can be made about the operating system. -### Immutability +## Immutability The blockchain community often describes blockchains as “immutable.” If we interpret that word literally, it means that blockchain data is unchangeable or permanent, which is absurd. The data _can_ be changed. For example, a plague might drive humanity extinct; the data would then get corrupted over time due to water damage, thermal noise, and the general increase of entropy. diff --git a/docs/root/source/terminology.md b/docs/root/source/terminology.md index 8c51eca..6827de7 100644 --- a/docs/root/source/terminology.md +++ b/docs/root/source/terminology.md @@ -9,17 +9,17 @@ Code is Apache-2.0 and docs are CC-BY-4.0 There is some specialized terminology associated with Planetmint. To get started, you should at least know the following: -### Planetmint Node +## Planetmint Node **Planetmint node** is a machine (or logical machine) running [Planetmint Server](https://docs.planetmint.com/projects/server/en/latest/introduction.html) and related software. Each node is controlled by one person or organization. **Planetmint node** is a machine (or logical machine) running [Planetmint Server](https://docs.planetmint.io/projects/server/en/latest/introduction.html) and related software. Each node is controlled by one person or organization. -### Planetmint Network +## Planetmint Network A set of Planetmint nodes can connect to each other to form a **Planetmint network**. Each node in the network runs the same software. A Planetmint network may have additional machines to do things such as monitoring. -### Planetmint Consortium +## Planetmint Consortium The people and organizations that run the nodes in a Planetmint network belong to a **Planetmint consortium** (i.e. another organization). A consortium must have some sort of governance structure to make decisions. If a Planetmint network is run by a single company, then the "consortium" is just that company. @@ -27,7 +27,7 @@ The people and organizations that run the nodes in a Planetmint network belong t A Planetmint network is just a bunch of connected nodes. A consortium is an organization which has a Planetmint network, and where each node in that network has a different operator. -### Transactions +## Transactions Are described in detail in `Planetmint Transactions Spec `_ . diff --git a/setup.py b/setup.py index 5b623c8..329e303 100644 --- a/setup.py +++ b/setup.py @@ -35,6 +35,15 @@ def check_setuptools_features(): ' $ pip3 install --upgrade setuptools\n' 'and then run this command again') +import pathlib +import pkg_resources + +with pathlib.Path('docs/root/requirements.txt').open() as requirements_txt: + docs_require= [ + str(requirement) + for requirement + in pkg_resources.parse_requirements(requirements_txt) + ] check_setuptools_features() @@ -47,17 +56,6 @@ dev_require = [ 'twine' ] -docs_require = [ - 'Sphinx~=1.0', - 'recommonmark>=0.4.0', - 'sphinx-rtd-theme>=0.1.9', - 'sphinxcontrib-httpdomain>=1.5.0', - 'sphinxcontrib-napoleon>=0.4.4', - 'aafigure>=0.6', - 'wget', - 'jinja2==3.0.0' -] - tests_require = [ 'coverage', 'pep8', diff --git a/tox.ini b/tox.ini index 4adc024..0cc9c26 100644 --- a/tox.ini +++ b/tox.ini @@ -35,5 +35,5 @@ deps = typing-extensions -r{toxinidir}/docs/root/requirements.txt extras = None -commands = sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html +commands = sphinx-build -b html -d {envtmpdir}/doctrees . {envtmpdir}/html