diff --git a/planetmint/__init__.py b/planetmint/__init__.py index 1ba0f13..1fa5393 100644 --- a/planetmint/__init__.py +++ b/planetmint/__init__.py @@ -3,10 +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.transactions.common.transaction import Transaction # noqa -from planetmint.transactions.types.elections.validator_election import ValidatorElection # noqa -from planetmint.transactions.types.elections.vote import Vote # noqa -from planetmint.transactions.types.elections.chain_migration_election import ChainMigrationElection +from transactions.common.transaction import Transaction # noqa +from transactions.types.elections.validator_election import ValidatorElection # noqa +from transactions.types.elections.vote import Vote # noqa +from transactions.types.elections.chain_migration_election import ChainMigrationElection from planetmint.lib import Planetmint from planetmint.core import App diff --git a/planetmint/backend/connection.py b/planetmint/backend/connection.py index 57e5d35..2eb7797 100644 --- a/planetmint/backend/connection.py +++ b/planetmint/backend/connection.py @@ -8,10 +8,10 @@ import logging from importlib import import_module import tarantool +from transactions.common.exceptions import ConfigurationError from planetmint.config import Config from planetmint.backend.exceptions import ConnectionError -from planetmint.transactions.common.exceptions import ConfigurationError BACKENDS = { "tarantool_db": "planetmint.backend.tarantool.connection.TarantoolDBConnection", diff --git a/planetmint/backend/localmongodb/connection.py b/planetmint/backend/localmongodb/connection.py index 1851f2e..ad03455 100644 --- a/planetmint/backend/localmongodb/connection.py +++ b/planetmint/backend/localmongodb/connection.py @@ -9,7 +9,7 @@ import pymongo from planetmint.config import Config from planetmint.backend.exceptions import DuplicateKeyError, OperationError, ConnectionError -from planetmint.transactions.common.exceptions import ConfigurationError +from transactions.common.exceptions import ConfigurationError from planetmint.utils import Lazy from planetmint.backend.connection import Connection diff --git a/planetmint/backend/localmongodb/query.py b/planetmint/backend/localmongodb/query.py index 355fc1e..e4c3350 100644 --- a/planetmint/backend/localmongodb/query.py +++ b/planetmint/backend/localmongodb/query.py @@ -13,7 +13,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.transactions.common.transaction import Transaction +from 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 9d10e57..d6492f3 100644 --- a/planetmint/backend/schema.py +++ b/planetmint/backend/schema.py @@ -10,8 +10,8 @@ import logging from planetmint.config import Config from planetmint.backend.connection import connect -from planetmint.transactions.common.exceptions import ValidationError -from planetmint.transactions.common.utils import ( +from transactions.common.exceptions import ValidationError +from transactions.common.utils import ( validate_all_values_for_key_in_obj, validate_all_values_for_key_in_list, ) diff --git a/planetmint/backend/tarantool/connection.py b/planetmint/backend/tarantool/connection.py index cc6ba8d..0c719ff 100644 --- a/planetmint/backend/tarantool/connection.py +++ b/planetmint/backend/tarantool/connection.py @@ -7,7 +7,7 @@ import logging import tarantool from planetmint.config import Config -from planetmint.transactions.common.exceptions import ConfigurationError +from transactions.common.exceptions import ConfigurationError from planetmint.utils import Lazy from planetmint.backend.connection import Connection diff --git a/planetmint/backend/tarantool/transaction/tools.py b/planetmint/backend/tarantool/transaction/tools.py index 045e18c..d5ee75c 100644 --- a/planetmint/backend/tarantool/transaction/tools.py +++ b/planetmint/backend/tarantool/transaction/tools.py @@ -1,7 +1,7 @@ from secrets import token_hex import copy import json -from planetmint.transactions.common.memoize import HDict +from transactions.common.memoize import HDict def get_items(_list): diff --git a/planetmint/commands/planetmint.py b/planetmint/commands/planetmint.py index 926b0ab..5064ff6 100644 --- a/planetmint/commands/planetmint.py +++ b/planetmint/commands/planetmint.py @@ -15,11 +15,11 @@ import sys from planetmint.core import rollback 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.types.elections.vote import Vote -from planetmint.transactions.types.elections.chain_migration_election import ChainMigrationElection -from planetmint.transactions.types.elections.validator_utils import election_id_to_public_key +from transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT +from transactions.common.exceptions import DatabaseDoesNotExist, ValidationError +from transactions.types.elections.vote import Vote +from transactions.types.elections.chain_migration_election import ChainMigrationElection +from transactions.types.elections.validator_utils import election_id_to_public_key import planetmint from planetmint import ValidatorElection, Planetmint from planetmint.backend import schema diff --git a/planetmint/config_utils.py b/planetmint/config_utils.py index 9fb288c..b3bfae3 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.config import Config -from planetmint.transactions.common import exceptions +from transactions.common import exceptions from planetmint.validation import BaseValidationRules # TODO: move this to a proper configuration file for logging diff --git a/planetmint/fastquery.py b/planetmint/fastquery.py index 59f0056..7832a5c 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.transactions.common.transaction import TransactionLink +from transactions.common.transaction import TransactionLink class FastQuery: diff --git a/planetmint/lib.py b/planetmint/lib.py index d63afe4..5565f35 100644 --- a/planetmint/lib.py +++ b/planetmint/lib.py @@ -17,37 +17,21 @@ import rapidjson from hashlib import sha3_256 import requests +from transactions import Transaction, Vote +from transactions.common.crypto import public_key_from_ed25519_key +from transactions.common.exceptions import SchemaValidationError, ValidationError, DuplicateTransaction, \ + InvalidSignature, DoubleSpend, InputDoesNotExist, AssetIdMismatch, AmountError, MultipleInputsError, \ + InvalidProposer, UnequalValidatorSet, InvalidPowerChange +from transactions.common.transaction import VALIDATOR_ELECTION, CHAIN_MIGRATION_ELECTION +from transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT, BROADCAST_TX_ASYNC, BROADCAST_TX_SYNC +from transactions.types.elections.election import Election +from transactions.types.elections.validator_utils import election_id_to_public_key import planetmint from planetmint.config import Config from planetmint import backend, config_utils, fastquery -from planetmint.transactions.common.transaction import CHAIN_MIGRATION_ELECTION, VALIDATOR_ELECTION, Transaction -from planetmint.transactions.common.exceptions import ( - DuplicateTransaction, - InvalidSignature, - SchemaValidationError, - ValidationError, - DoubleSpend, - AmountError, - InputDoesNotExist, - AssetIdMismatch, - InvalidProposer, - UnequalValidatorSet, - DuplicateTransaction, - MultipleInputsError, - InvalidPowerChange -) -from planetmint.transactions.common.crypto import public_key_from_ed25519_key -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, key_from_base64, public_key_to_base64, encode_validator, new_validator_set from planetmint import exceptions as core_exceptions -from planetmint.transactions.types.elections.election import Election -from planetmint.transactions.types.elections.vote import Vote -from planetmint.transactions.types.elections.validator_utils import election_id_to_public_key from planetmint.validation import BaseValidationRules logger = logging.getLogger(__name__) diff --git a/planetmint/log.py b/planetmint/log.py index 31bd150..d24e0ed 100644 --- a/planetmint/log.py +++ b/planetmint/log.py @@ -6,7 +6,7 @@ import planetmint import logging -from planetmint.transactions.common.exceptions import ConfigurationError +from transactions.common.exceptions import ConfigurationError from logging.config import dictConfig as set_logging_config from planetmint.config import Config, DEFAULT_LOGGING_CONFIG import os diff --git a/planetmint/tendermint_utils.py b/planetmint/tendermint_utils.py index 7daef69..0856dcc 100644 --- a/planetmint/tendermint_utils.py +++ b/planetmint/tendermint_utils.py @@ -14,7 +14,7 @@ from tendermint.crypto import keys_pb2 from hashlib import sha3_256 -from planetmint.transactions.common.exceptions import InvalidPublicKey +from transactions.common.exceptions import InvalidPublicKey def encode_validator(v): ed25519_public_key = v["public_key"]["value"] diff --git a/planetmint/transactions/__init__.py b/planetmint/transactions/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/planetmint/transactions/common/__init__.py b/planetmint/transactions/common/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/planetmint/transactions/common/crypto.py b/planetmint/transactions/common/crypto.py deleted file mode 100644 index 60f0ad8..0000000 --- a/planetmint/transactions/common/crypto.py +++ /dev/null @@ -1,51 +0,0 @@ -# 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 - -# Separate all crypto code so that we can easily test several implementations -from collections import namedtuple -from hashlib import sha3_256 -from cryptoconditions import crypto - - -CryptoKeypair = namedtuple("CryptoKeypair", ("private_key", "public_key")) - - -def hash_data(data): - """Hash the provided data using SHA3-256""" - return sha3_256(data.encode()).hexdigest() - - -def generate_key_pair() -> CryptoKeypair: - """Generates a cryptographic key pair. - - Returns: - :class:`~planetmint.transactions.common.crypto.CryptoKeypair`: A - :obj:`collections.namedtuple` with named fields - :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 - return CryptoKeypair(*(k.decode() for k in crypto.ed25519_generate_key_pair())) - - -PrivateKey = crypto.Ed25519SigningKey -PublicKey = crypto.Ed25519VerifyingKey - - -def key_pair_from_ed25519_key(hex_private_key): - """Generate base58 encode public-private key pair from a hex encoded private key""" - priv_key = crypto.Ed25519SigningKey(bytes.fromhex(hex_private_key)[:32], encoding="bytes") - public_key = priv_key.get_verifying_key() - return CryptoKeypair( - private_key=priv_key.encode(encoding="base58").decode("utf-8"), - public_key=public_key.encode(encoding="base58").decode("utf-8"), - ) - - -def public_key_from_ed25519_key(hex_public_key): - """Generate base58 public key from hex encoded public key""" - public_key = crypto.Ed25519VerifyingKey(bytes.fromhex(hex_public_key), encoding="bytes") - return public_key.encode(encoding="base58").decode("utf-8") diff --git a/planetmint/transactions/common/exceptions.py b/planetmint/transactions/common/exceptions.py deleted file mode 100644 index 780fe01..0000000 --- a/planetmint/transactions/common/exceptions.py +++ /dev/null @@ -1,115 +0,0 @@ -# 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 - -"""Custom exceptions used in the `planetmint` package. -""" -from planetmint.exceptions import PlanetmintError - - -class ConfigurationError(PlanetmintError): - """Raised when there is a problem with server configuration""" - - -class DatabaseDoesNotExist(PlanetmintError): - """Raised when trying to delete the database but the db is not there""" - - -class StartupError(PlanetmintError): - """Raised when there is an error starting up the system""" - - -class CyclicBlockchainError(PlanetmintError): - """Raised when there is a cycle in the blockchain""" - - -class KeypairMismatchException(PlanetmintError): - """Raised if the private key(s) provided for signing don't match any of the - current owner(s) - """ - - -class OperationError(PlanetmintError): - """Raised when an operation cannot go through""" - - -################################################################################ -# Validation errors -# -# All validation errors (which are handleable errors, not faults) should -# subclass ValidationError. However, where possible they should also have their -# own distinct type to differentiate them from other validation errors, -# especially for the purposes of testing. - - -class ValidationError(PlanetmintError): - """Raised if there was an error in validation""" - - -class DoubleSpend(ValidationError): - """Raised if a double spend is found""" - - -class InvalidHash(ValidationError): - """Raised if there was an error checking the hash for a particular - operation - """ - - -class SchemaValidationError(ValidationError): - """Raised if there was any error validating an object's schema""" - - -class InvalidSignature(ValidationError): - """Raised if there was an error checking the signature for a particular - operation - """ - - -class AssetIdMismatch(ValidationError): - """Raised when multiple transaction inputs related to different assets""" - - -class AmountError(ValidationError): - """Raised when there is a problem with a transaction's output amounts""" - - -class InputDoesNotExist(ValidationError): - """Raised if a transaction input does not exist""" - - -class TransactionOwnerError(ValidationError): - """Raised if a user tries to transfer a transaction they don't own""" - - -class DuplicateTransaction(ValidationError): - """Raised if a duplicated transaction is found""" - - -class ThresholdTooDeep(ValidationError): - """Raised if threshold condition is too deep""" - - -class MultipleValidatorOperationError(ValidationError): - """Raised when a validator update pending but new request is submited""" - - -class MultipleInputsError(ValidationError): - """Raised if there were multiple inputs when only one was expected""" - - -class InvalidProposer(ValidationError): - """Raised if the public key is not a part of the validator set""" - - -class UnequalValidatorSet(ValidationError): - """Raised if the validator sets differ""" - - -class InvalidPowerChange(ValidationError): - """Raised if proposed power change in validator set is >=1/3 total power""" - - -class InvalidPublicKey(ValidationError): - """Raised if public key doesn't match the encoding type""" diff --git a/planetmint/transactions/common/input.py b/planetmint/transactions/common/input.py deleted file mode 100644 index 35bf503..0000000 --- a/planetmint/transactions/common/input.py +++ /dev/null @@ -1,127 +0,0 @@ -# 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 Optional -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: Fulfillment, owners_before: list[str], fulfills: Optional[TransactionLink] = 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: list[str]): - # 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: dict): - """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/transactions/common/memoize.py b/planetmint/transactions/common/memoize.py deleted file mode 100644 index 9bb13d7..0000000 --- a/planetmint/transactions/common/memoize.py +++ /dev/null @@ -1,57 +0,0 @@ -import functools -import codecs -from functools import lru_cache -from typing import Callable - -class HDict(dict): - def __hash__(self): - return hash(codecs.decode(self["id"], "hex")) - - -@lru_cache(maxsize=16384) -def from_dict(func: Callable, *args, **kwargs): - return func(*args, **kwargs) - - -def memoize_from_dict(func: Callable): - @functools.wraps(func) - def memoized_func(*args, **kwargs): - if args[1] is None: - return None - elif args[1].get("id", None): - args = list(args) - args[1] = HDict(args[1]) - new_args = tuple(args) - return from_dict(func, *new_args, **kwargs) - else: - return func(*args, **kwargs) - - return memoized_func - - -class ToDictWrapper: - def __init__(self, tx): - self.tx = tx - - def __eq__(self, other): - return self.tx.id == other.tx.id - - def __hash__(self): - return hash(self.tx.id) - - -@lru_cache(maxsize=16384) -def to_dict(func, tx_wrapped): - return func(tx_wrapped.tx) - - -def memoize_to_dict(func: Callable): - @functools.wraps(func) - def memoized_func(*args, **kwargs): - - if args[0].id: - return to_dict(func, ToDictWrapper(args[0])) - else: - return func(*args, **kwargs) - - return memoized_func diff --git a/planetmint/transactions/common/output.py b/planetmint/transactions/common/output.py deleted file mode 100644 index e575d59..0000000 --- a/planetmint/transactions/common/output.py +++ /dev/null @@ -1,211 +0,0 @@ -# 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 -from typing import Union, Optional - -import base58 -from cryptoconditions import ThresholdSha256, Ed25519Sha256, ZenroomSha256 -from cryptoconditions import Fulfillment - -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: type[Fulfillment], public_keys: Optional[list[str]] = None, amount: int = 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: - # TODO verify if a script is returned in case of zenroom fulfillments - 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: list[str], amount: int): - """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] - elif isinstance(public_keys[0], ZenroomSha256): - ffill = ZenroomSha256(public_key=base58.b58decode(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: type[ThresholdSha256], new_public_keys: Union[list[str],str]) -> type[ThresholdSha256]: - """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: - if isinstance(new_public_keys, list): - 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: dict): - """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/transactions/common/schema/README.md b/planetmint/transactions/common/schema/README.md deleted file mode 100644 index cb8db1f..0000000 --- a/planetmint/transactions/common/schema/README.md +++ /dev/null @@ -1,54 +0,0 @@ - - -# Introduction - -This directory contains the schemas for the different JSON documents Planetmint uses. - -The aim is to provide: - -- a strict definition of the data structures used in Planetmint, -- a language-independent tool to validate the structure of incoming/outcoming - data. (There are several ready to use - [implementations](http://json-schema.org/implementations.html) written in - different languages.) - -## Sources - -The files defining the JSON Schema for transactions (`transaction_*.yaml`) -are based on the [Planetmint Transactions Specs](https://github.com/planetmint/BEPs/tree/master/tx-specs). -If you want to add a new transaction version, -you must write a spec for it first. -(You can't change the JSON Schema files for old versions. -Those were used to validate old transactions -and are needed to re-check those transactions.) - -There used to be a file defining the JSON Schema for votes, named `vote.yaml`. -It was used by Planetmint version 1.3.0 and earlier. -If you want a copy of the latest `vote.yaml` file, -then you can get it from the version 1.3.0 release on GitHub, at -[https://github.com/planetmint/planetmint/blob/v1.3.0/planetmint/common/schema/vote.yaml](https://github.com/planetmint/planetmint/blob/v1.3.0/planetmint/common/schema/vote.yaml). - -## Learn about JSON Schema - -A good resource is [Understanding JSON Schema](http://spacetelescope.github.io/understanding-json-schema/index.html). -It provides a *more accessible documentation for JSON schema* than the [specs](http://json-schema.org/documentation.html). - -## If it's supposed to be JSON, why's everything in YAML D:? - -YAML is great for its conciseness and friendliness towards human-editing in comparision to JSON. - -Although YAML is a superset of JSON, at the end of the day, JSON Schema processors, like -[json-schema](http://python-jsonschema.readthedocs.io/en/latest/), take in a native object (e.g. -Python dicts or JavaScript objects) as the schema used for validation. As long as we can serialize -the YAML into what the JSON Schema processor expects (almost always as simple as loading the YAML -like you would with a JSON file), it's the same as using JSON. - -Specific advantages of using YAML: - - Legibility, especially when nesting - - Multi-line string literals, that make it easy to include descriptions that can be [auto-generated - into Sphinx documentation](/docs/server/generate_schema_documentation.py) diff --git a/planetmint/transactions/common/schema/__init__.py b/planetmint/transactions/common/schema/__init__.py deleted file mode 100644 index df644ef..0000000 --- a/planetmint/transactions/common/schema/__init__.py +++ /dev/null @@ -1,78 +0,0 @@ -# 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 validation related functions and data""" -import os.path -import logging - -import jsonschema -import yaml -import rapidjson - -from planetmint.transactions.common.exceptions import SchemaValidationError - - -logger = logging.getLogger(__name__) - - -def _load_schema(name, version, path=__file__): - """Load a schema from disk""" - 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_VERSION) -_, TX_SCHEMA_CREATE = _load_schema("transaction_create", TX_SCHEMA_VERSION) -_, TX_SCHEMA_TRANSFER = _load_schema("transaction_transfer", TX_SCHEMA_VERSION) - -_, 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_VERSION) - -_, TX_SCHEMA_VOTE = _load_schema("transaction_vote", TX_SCHEMA_VERSION) - - -def _validate_schema(schema, body): - """Validate data against a schema""" - - # Note - # - # Schema validation is currently the major CPU bottleneck of - # Planetmint. the `jsonschema` library validates python data structures - # directly and produces nice error messages, but validation takes 4+ ms - # per transaction which is pretty slow. The rapidjson library validates - # much faster at 1.5ms, however it produces _very_ poor error messages. - # For this reason we use both, rapidjson as an optimistic pathway and - # jsonschema as a fallback in case there is a failure, so we can produce - # a helpful error message. - - try: - schema[1](rapidjson.dumps(body)) - except ValueError as exc: - try: - jsonschema.validate(body, schema[0]) - except jsonschema.ValidationError as exc2: - raise SchemaValidationError(str(exc2)) from exc2 - logger.warning("code problem: jsonschema did not raise an exception, wheras rapidjson raised %s", exc) - raise SchemaValidationError(str(exc)) from exc - - -def validate_transaction_schema(tx): - """Validate a transaction dict. - - TX_SCHEMA_COMMON contains properties that are common to all types of - transaction. TX_SCHEMA_[TRANSFER|CREATE] add additional constraints on top. - """ - _validate_schema(TX_SCHEMA_COMMON, tx) - if tx["operation"] == "TRANSFER": - _validate_schema(TX_SCHEMA_TRANSFER, tx) - else: - _validate_schema(TX_SCHEMA_CREATE, tx) diff --git a/planetmint/transactions/common/schema/v1.0/transaction.yaml b/planetmint/transactions/common/schema/v1.0/transaction.yaml deleted file mode 100644 index 3546d78..0000000 --- a/planetmint/transactions/common/schema/v1.0/transaction.yaml +++ /dev/null @@ -1,168 +0,0 @@ -# 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 -- asset -- version -properties: - id: - anyOf: - - "$ref": "#/definitions/sha3_hexdigest" - - type: 'null' - operation: - "$ref": "#/definitions/operation" - asset: - "$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: "^1\\.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 - - GENESIS - 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" diff --git a/planetmint/transactions/common/schema/v1.0/transaction_create.yaml b/planetmint/transactions/common/schema/v1.0/transaction_create.yaml deleted file mode 100644 index d43b543..0000000 --- a/planetmint/transactions/common/schema/v1.0/transaction_create.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# 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/GENESIS specific constraints -required: -- asset -- inputs -properties: - asset: - additionalProperties: false - properties: - data: - anyOf: - - type: object - additionalProperties: true - - type: 'null' - required: - - data - inputs: - type: array - title: "Transaction inputs" - maxItems: 1 - minItems: 1 - items: - type: "object" - required: - - fulfills - properties: - fulfills: - type: "null" diff --git a/planetmint/transactions/common/schema/v1.0/transaction_transfer.yaml b/planetmint/transactions/common/schema/v1.0/transaction_transfer.yaml deleted file mode 100644 index 0ac4023..0000000 --- a/planetmint/transactions/common/schema/v1.0/transaction_transfer.yaml +++ /dev/null @@ -1,34 +0,0 @@ -# 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: -- asset -properties: - asset: - additionalProperties: false - properties: - id: - "$ref": "#/definitions/sha3_hexdigest" - required: - - id - 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 diff --git a/planetmint/transactions/common/schema/v2.0/transaction.yaml b/planetmint/transactions/common/schema/v2.0/transaction.yaml deleted file mode 100644 index e2acf92..0000000 --- a/planetmint/transactions/common/schema/v2.0/transaction.yaml +++ /dev/null @@ -1,215 +0,0 @@ -# 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 - - asset - - version -properties: - id: - anyOf: - - "$ref": "#/definitions/sha3_hexdigest" - - type: 'null' - operation: - "$ref": "#/definitions/operation" - asset: - "$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$" - script: - "$ref": "#/definitions/script" -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 - asset: - anyOf: - - type: 'null' - - type: object - 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|zenroom)-sha-256(&)?|cost=[0-9]+(&)?|\ - subtypes=(ed25519|zenroom)-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: string - - type: 'null' - condition_details: - anyOf: - - type: object - additionalProperties: false - required: - - type - - public_key - properties: - type: - type: string - pattern: "^(ed25519|zenroom)-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" - script: - type: object - additionalProperties: false - required: - - code - - state - - input - - output - properties: - code: - anyOf: - - type: object - additionalProperties: false - required: - - type - - raw - - parameters - properties: - type: - type: string - enum: - - zenroom - raw: - type: string - parameters: - type: array - items: - type: object - - type: object - additionalProperties: false - required: - - transaction_id - properties: - transaction_id: - "$ref": "#/definitions/sha3_hexdigest" - state: - anyOf: - - type: object - "$ref": "#/definitions/sha3_hexdigest" - input: - type: object - output: - anyOf: - - type: object - - type: array - policies: - type: object - properties: - raw: - type: object - txids: - type: object diff --git a/planetmint/transactions/common/schema/v2.0/transaction_chain_migration_election.yaml b/planetmint/transactions/common/schema/v2.0/transaction_chain_migration_election.yaml deleted file mode 100644 index d5c5f4a..0000000 --- a/planetmint/transactions/common/schema/v2.0/transaction_chain_migration_election.yaml +++ /dev/null @@ -1,45 +0,0 @@ -# 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 -- asset -- outputs -properties: - operation: - type: string - value: "CHAIN_MIGRATION_ELECTION" - asset: - additionalProperties: false - properties: - data: - additionalProperties: false - properties: - seed: - type: string - required: - - data - 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}$" diff --git a/planetmint/transactions/common/schema/v2.0/transaction_create.yaml b/planetmint/transactions/common/schema/v2.0/transaction_create.yaml deleted file mode 100644 index d69126e..0000000 --- a/planetmint/transactions/common/schema/v2.0/transaction_create.yaml +++ /dev/null @@ -1,34 +0,0 @@ -# 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: -- asset -- inputs -properties: - asset: - additionalProperties: false - properties: - data: - anyOf: - - type: string - - type: 'null' - required: - - data - inputs: - type: array - title: "Transaction inputs" - maxItems: 1 - minItems: 1 - items: - type: "object" - required: - - fulfills - properties: - fulfills: - type: "null" diff --git a/planetmint/transactions/common/schema/v2.0/transaction_transfer.yaml b/planetmint/transactions/common/schema/v2.0/transaction_transfer.yaml deleted file mode 100644 index 0ac4023..0000000 --- a/planetmint/transactions/common/schema/v2.0/transaction_transfer.yaml +++ /dev/null @@ -1,34 +0,0 @@ -# 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: -- asset -properties: - asset: - additionalProperties: false - properties: - id: - "$ref": "#/definitions/sha3_hexdigest" - required: - - id - 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 diff --git a/planetmint/transactions/common/schema/v2.0/transaction_validator_election.yaml b/planetmint/transactions/common/schema/v2.0/transaction_validator_election.yaml deleted file mode 100644 index f93353c..0000000 --- a/planetmint/transactions/common/schema/v2.0/transaction_validator_election.yaml +++ /dev/null @@ -1,68 +0,0 @@ -# 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 -- asset -- outputs -properties: - operation: - type: string - value: "VALIDATOR_ELECTION" - 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 - 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}$" diff --git a/planetmint/transactions/common/schema/v2.0/transaction_vote.yaml b/planetmint/transactions/common/schema/v2.0/transaction_vote.yaml deleted file mode 100644 index 64ed6ee..0000000 --- a/planetmint/transactions/common/schema/v2.0/transaction_vote.yaml +++ /dev/null @@ -1,34 +0,0 @@ -# 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}$" diff --git a/planetmint/transactions/common/schema/v3.0/transaction.yaml b/planetmint/transactions/common/schema/v3.0/transaction.yaml deleted file mode 100644 index 3430fdd..0000000 --- a/planetmint/transactions/common/schema/v3.0/transaction.yaml +++ /dev/null @@ -1,219 +0,0 @@ -# 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: "^3\\.0$" - script: - "$ref": "#/definitions/script" -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: - anyOf: - - type: 'null' - - type: object - 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: string - - 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" - script: - type: object - additionalProperties: false - required: - - code - - state - - input - - output - properties: - code: - anyOf: - - type: object - additionalProperties: false - required: - - type - - raw - - parameters - properties: - type: - type: string - enum: - - zenroom - raw: - type: string - parameters: - type: array - items: - type: object - - type: object - additionalProperties: false - required: - - transaction_id - properties: - transaction_id: - "$ref": "#/definitions/sha3_hexdigest" - state: - anyOf: - - type: object - "$ref": "#/definitions/sha3_hexdigest" - input: - type: object - output: - anyOf: - - type: object - - type: array - policies: - type: object - properties: - raw: - type: object - txids: - type: object 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 deleted file mode 100644 index 932c7b1..0000000 --- a/planetmint/transactions/common/schema/v3.0/transaction_chain_migration_election.yaml +++ /dev/null @@ -1,51 +0,0 @@ -# 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 deleted file mode 100644 index 05daea7..0000000 --- a/planetmint/transactions/common/schema/v3.0/transaction_create.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# 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: string - - 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 deleted file mode 100644 index 1bc74e5..0000000 --- a/planetmint/transactions/common/schema/v3.0/transaction_transfer.yaml +++ /dev/null @@ -1,39 +0,0 @@ -# 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 deleted file mode 100644 index 0d7c93b..0000000 --- a/planetmint/transactions/common/schema/v3.0/transaction_validator_election.yaml +++ /dev/null @@ -1,74 +0,0 @@ -# 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 deleted file mode 100644 index 64ed6ee..0000000 --- a/planetmint/transactions/common/schema/v3.0/transaction_vote.yaml +++ /dev/null @@ -1,34 +0,0 @@ -# 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}$" diff --git a/planetmint/transactions/common/transaction.py b/planetmint/transactions/common/transaction.py deleted file mode 100644 index 8029487..0000000 --- a/planetmint/transactions/common/transaction.py +++ /dev/null @@ -1,813 +0,0 @@ -# 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 - -"""Transaction related models to parse and construct transaction -payloads. - -Attributes: - UnspentOutput (namedtuple): Object holding the information - representing an unspent output. - -""" -from collections import namedtuple -from copy import deepcopy -from functools import lru_cache -from typing import Optional -import rapidjson - -import base58 -from cryptoconditions import Fulfillment, ThresholdSha256, Ed25519Sha256, ZenroomSha256 -from cryptoconditions.exceptions import ParsingError, ASN1DecodeError, ASN1EncodeError -from cid import is_cid - -from hashlib 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, - DuplicateTransaction, -) -from planetmint.backend.schema import validate_language_key -from planetmint.transactions.common.schema import validate_transaction_schema -from planetmint.transactions.common.utils import serialize, validate_txn_obj, validate_key -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", - ( - # TODO 'utxo_hash': sha3_256(f'{txid}{output_index}'.encode()) - # 'utxo_hash', # noqa - "transaction_id", - "output_index", - "amount", - "asset_id", - "condition_uri", - ), -) - -VALIDATOR_ELECTION = "VALIDATOR_ELECTION" -CHAIN_MIGRATION_ELECTION = "CHAIN_MIGRATION_ELECTION" -VOTE = "VOTE" - - -class Transaction(object): - """A Transaction is used to create and transfer assets. - - Note: - For adding Inputs and Outputs, this class provides methods - to do so. - - Attributes: - operation (str): Defines the operation of the Transaction. - inputs (:obj:`list` of :class:`~planetmint.transactions.common. - transaction.Input`, optional): Define the assets to - spend. - 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`` - property while ``TRANSFER`` Transactions require a dict with a - ``id`` property. - metadata (dict): - Metadata to be stored along with the Transaction. - version (string): Defines the version number of a Transaction. - """ - - CREATE: str = "CREATE" - TRANSFER: str = "TRANSFER" - VALIDATOR_ELECTION: str = VALIDATOR_ELECTION - CHAIN_MIGRATION_ELECTION: str = CHAIN_MIGRATION_ELECTION - VOTE: str = VOTE - ALLOWED_OPERATIONS: tuple[str, ...] = (CREATE, TRANSFER) - ASSET: str = "asset" - METADATA: str = "metadata" - DATA: str = "data" - VERSION: str = "2.0" - - def __init__( - self, - operation, - asset, - inputs=None, - outputs=None, - metadata=None, - version=None, - hash_id=None, - tx_dict=None, - script=None, - ): - """The constructor allows to create a customizable Transaction. - - Note: - When no `version` is provided, one is being - generated by this method. - - Args: - operation (str): Defines the operation of the Transaction. - asset (dict): Asset payload for this Transaction. - inputs (:obj:`list` of :class:`~planetmint.transactions.common. - transaction.Input`, optional): Define the assets to - 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 - Transaction. - version (string): Defines the version number of a Transaction. - hash_id (string): Hash id of the transaction. - """ - if operation not in self.ALLOWED_OPERATIONS: - allowed_ops = ", ".join(self.__class__.ALLOWED_OPERATIONS) - raise ValueError("`operation` must be one of {}".format(allowed_ops)) - - # Asset payloads for 'CREATE' operations must be None or - # dicts holding a `data` property. Asset payloads for 'TRANSFER' - # operations must be dicts holding an `id` property. - if operation == self.CREATE and asset is not None: - if not isinstance(asset, dict): - raise TypeError( - ( - "`asset` must be None or a dict holding a `data` " - " property instance for '{}' Transactions".format(operation) - ) - ) - - if "data" in asset: - if asset["data"] is not None and not isinstance(asset["data"], str): - if is_cid(asset["data"]) == False: - raise TypeError("`asset.data` not valid CID") - - raise TypeError( - ( - "`asset` must be None or a dict holding a `data` " - " property instance for '{}' Transactions".format(operation) - ) - ) - - elif operation == self.TRANSFER and not (isinstance(asset, dict) and "id" in asset): - raise TypeError(("`asset` must be a dict holding an `id` property " "for 'TRANSFER' Transactions")) - - if outputs and not isinstance(outputs, list): - raise TypeError("`outputs` must be a list instance or None") - - if inputs and not isinstance(inputs, list): - raise TypeError("`inputs` must be a list instance or None") - - if metadata is not None and not isinstance(metadata, str): - if is_cid(metadata) == False: - raise TypeError("`metadata` not valid CID") - - raise TypeError("`metadata` must be a CID string or None") - - if script is not None and not isinstance(script, dict): - raise TypeError("`script` must be a dict or None") - - self.version = version if version is not None else self.VERSION - self.operation = operation - self.asset = asset - self.inputs = inputs or [] - self.outputs = outputs or [] - self.metadata = metadata - self.script = script - self._id = hash_id - self.tx_dict = tx_dict - - - @property - def unspent_outputs(self): - """UnspentOutput: The outputs of this transaction, in a data - structure containing relevant information for storing them in - a UTXO set, and performing validation. - """ - if self.operation == self.CREATE: - self._asset_id = self._id - elif self.operation == self.TRANSFER: - self._asset_id = self.asset["id"] - return ( - UnspentOutput( - transaction_id=self._id, - output_index=output_index, - amount=output.amount, - asset_id=self._asset_id, - condition_uri=output.fulfillment.condition_uri, - ) - for output_index, output in enumerate(self.outputs) - ) - - @property - def spent_outputs(self): - """Tuple of :obj:`dict`: Inputs of this transaction. Each input - is represented as a dictionary containing a transaction id and - output index. - """ - return (input_.fulfills.to_dict() for input_ in self.inputs if input_.fulfills) - - @property - def serialized(self): - return Transaction._to_str(self.to_dict()) - - def _hash(self): - self._id = hash_data(self.serialized) - - def __eq__(self, other): - try: - other = other.to_dict() - except AttributeError: - return False - return self.to_dict() == other - - def to_inputs(self, indices: Optional[list[int]] = None) -> list[Input]: - """Converts a Transaction's outputs to spendable inputs. - - Note: - Takes the Transaction's outputs and derives inputs - from that can then be passed into `Transaction.transfer` as - `inputs`. - A list of integers can be passed to `indices` that - defines which outputs should be returned as inputs. - If no `indices` are passed (empty list or None) all - outputs of the Transaction are returned. - - Args: - indices (:obj:`list` of int): Defines which - outputs should be returned as inputs. - - Returns: - :obj:`list` of :class:`~planetmint.transactions.common.transaction. - Input` - """ - # NOTE: If no indices are passed, we just assume to take all outputs - # as inputs. - iterable_indices = indices or range(len(self.outputs)) - return [ - Input( - self.outputs[idx].fulfillment, - self.outputs[idx].public_keys, - TransactionLink(self.id, idx), - ) - for idx in iterable_indices - ] - - def add_input(self, input_: Input) -> None: - """Adds an input to a Transaction's list of inputs. - - Args: - input_ (:class:`~planetmint.transactions.common.transaction. - Input`): An Input to be added to the Transaction. - """ - if not isinstance(input_, Input): - raise TypeError("`input_` must be a Input instance") - self.inputs.append(input_) - - def add_output(self, output: Output) -> None: - """Adds an output to a Transaction's list of outputs. - - Args: - output (:class:`~planetmint.transactions.common.transaction. - Output`): An Output to be added to the - Transaction. - """ - if not isinstance(output, Output): - raise TypeError("`output` must be an Output instance or None") - self.outputs.append(output) - - def sign(self, private_keys: list[str]): - """Fulfills a previous Transaction's Output by signing Inputs. - - Note: - This method works only for the following Cryptoconditions - currently: - - Ed25519Fulfillment - - ThresholdSha256 - - ZenroomSha256 - Furthermore, note that all keys required to fully sign the - Transaction have to be passed to this method. A subset of all - will cause this method to fail. - - Args: - private_keys (:obj:`list` of :obj:`str`): A complete list of - all private keys needed to sign all Fulfillments of this - Transaction. - - Returns: - :class:`~planetmint.transactions.common.transaction.Transaction` - """ - # TODO: Singing should be possible with at least one of all private - # keys supplied to this method. - if private_keys is None or not isinstance(private_keys, list): - raise TypeError("`private_keys` must be a list instance") - - # NOTE: Generate public keys from private keys and match them in a - # dictionary: - # key: public_key - # value: private_key - def gen_public_key(private_key): - # TODO FOR CC: Adjust interface so that this function becomes - # unnecessary - - # cc now provides a single method `encode` to return the key - # in several different encodings. - public_key = private_key.get_verifying_key().encode() - # Returned values from cc are always bytestrings so here we need - # to decode to convert the bytestring into a python str - return public_key.decode() - - key_pairs = {gen_public_key(PrivateKey(private_key)): PrivateKey(private_key) for private_key in private_keys} - - tx_dict = self.to_dict() - tx_dict = Transaction._remove_signatures(tx_dict) - tx_serialized = Transaction._to_str(tx_dict) - for i, input_ in enumerate(self.inputs): - self.inputs[i] = self._sign_input(input_, tx_serialized, key_pairs) - - self._hash() - - return self - - @classmethod - def _sign_input(cls, input_: Input, message: str, key_pairs: dict) -> Input: - """Signs a single Input. - - Note: - This method works only for the following Cryptoconditions - currently: - - Ed25519Fulfillment - - ThresholdSha256. - - ZenroomSha256 - Args: - 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. - """ - if isinstance(input_.fulfillment, Ed25519Sha256): - return cls._sign_simple_signature_fulfillment(input_, message, key_pairs) - elif isinstance(input_.fulfillment, ThresholdSha256): - return cls._sign_threshold_signature_fulfillment(input_, message, key_pairs) - elif isinstance(input_.fulfillment, ZenroomSha256): - return cls._sign_zenroom_fulfillment(input_, message, key_pairs) - else: - raise ValueError("Fulfillment couldn't be matched to " "Cryptocondition fulfillment type.") - - @classmethod - def _sign_zenroom_fulfillment(cls, input_: Input, message: str, key_pairs: dict) -> Input: - """Signs a Zenroomful. - - Args: - 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. - """ - # NOTE: To eliminate the dangers of accidentally signing a condition by - # reference, we remove the reference of input_ here - # intentionally. If the user of this class knows how to use it, - # this should never happen, but then again, never say never. - input_ = deepcopy(input_) - public_key = input_.owners_before[0] - sha3_message = sha3_256(message.encode()) - if input_.fulfills: - sha3_message.update("{}{}".format(input_.fulfills.txid, input_.fulfills.output).encode()) - - try: - # cryptoconditions makes no assumptions of the encoding of the - # message to sign or verify. It only accepts bytestrings - input_.fulfillment.sign(sha3_message.digest(), base58.b58decode(key_pairs[public_key].encode())) - except KeyError: - raise KeypairMismatchException( - "Public key {} is not a pair to " "any of the private keys".format(public_key) - ) - return input_ - - @classmethod - def _sign_simple_signature_fulfillment(cls, input_: Input, message: str, key_pairs: dict) -> Input: - """Signs a Ed25519Fulfillment. - - Args: - 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. - """ - # NOTE: To eliminate the dangers of accidentally signing a condition by - # reference, we remove the reference of input_ here - # intentionally. If the user of this class knows how to use it, - # this should never happen, but then again, never say never. - input_ = deepcopy(input_) - public_key = input_.owners_before[0] - sha3_message = sha3_256(message.encode()) - if input_.fulfills: - sha3_message.update("{}{}".format(input_.fulfills.txid, input_.fulfills.output).encode()) - - try: - # cryptoconditions makes no assumptions of the encoding of the - # message to sign or verify. It only accepts bytestrings - input_.fulfillment.sign(sha3_message.digest(), base58.b58decode(key_pairs[public_key].encode())) - except KeyError: - raise KeypairMismatchException( - "Public key {} is not a pair to " "any of the private keys".format(public_key) - ) - return input_ - - @classmethod - def _sign_threshold_signature_fulfillment(cls, input_: Input, message: str, key_pairs: dict) -> Input: - """Signs a ThresholdSha256. - - Args: - 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. - """ - input_ = deepcopy(input_) - sha3_message = sha3_256(message.encode()) - if input_.fulfills: - sha3_message.update("{}{}".format(input_.fulfills.txid, input_.fulfills.output).encode()) - - for owner_before in set(input_.owners_before): - # TODO: CC should throw a KeypairMismatchException, instead of - # our manual mapping here - - # TODO FOR CC: Naming wise this is not so smart, - # `get_subcondition` in fact doesn't return a - # condition but a fulfillment - - # TODO FOR CC: `get_subcondition` is singular. One would not - # expect to get a list back. - ccffill = input_.fulfillment - subffills = ccffill.get_subcondition_from_vk(base58.b58decode(owner_before)) - if not subffills: - raise KeypairMismatchException( - "Public key {} cannot be found " "in the fulfillment".format(owner_before) - ) - try: - private_key = key_pairs[owner_before] - except KeyError: - raise KeypairMismatchException( - "Public key {} is not a pair " "to any of the private keys".format(owner_before) - ) - - # cryptoconditions makes no assumptions of the encoding of the - # message to sign or verify. It only accepts bytestrings - for subffill in subffills: - subffill.sign(sha3_message.digest(), base58.b58decode(private_key.encode())) - return input_ - - def inputs_valid(self, outputs=None) -> bool: - """Validates the Inputs in the Transaction against given - Outputs. - - Note: - Given a `CREATE` Transaction is passed, - dummy values for Outputs are submitted for validation that - evaluate parts of the validation-checks to `True`. - - Args: - outputs (:obj:`list` of :class:`~planetmint.transactions.common. - transaction.Output`): A list of Outputs to check the - Inputs against. - - Returns: - bool: If all Inputs are valid. - """ - if self.operation == self.CREATE: - # NOTE: Since in the case of a `CREATE`-transaction we do not have - # to check for outputs, we're just submitting dummy - # values to the actual method. This simplifies it's logic - # greatly, as we do not have to check against `None` values. - return self._inputs_valid(["dummyvalue" for _ in self.inputs]) - elif self.operation == self.TRANSFER: - return self._inputs_valid([output.fulfillment.condition_uri for output in outputs]) - elif self.operation == self.VALIDATOR_ELECTION: - return self._inputs_valid(["dummyvalue" for _ in self.inputs]) - elif self.operation == self.CHAIN_MIGRATION_ELECTION: - return self._inputs_valid(["dummyvalue" for _ in self.inputs]) - else: - allowed_ops = ", ".join(self.__class__.ALLOWED_OPERATIONS) - raise TypeError("`operation` must be one of {}".format(allowed_ops)) - - def _inputs_valid(self, output_condition_uris: list[str]) -> bool: - """Validates an Input against a given set of Outputs. - - Note: - The number of `output_condition_uris` must be equal to the - number of Inputs a Transaction has. - - Args: - output_condition_uris (:obj:`list` of :obj:`str`): A list of - Outputs to check the Inputs against. - - Returns: - bool: If all Outputs are valid. - """ - - if len(self.inputs) != len(output_condition_uris): - raise ValueError("Inputs and " "output_condition_uris must have the same count") - - tx_dict = self.tx_dict if self.tx_dict else self.to_dict() - tx_dict = Transaction._remove_signatures(tx_dict) - tx_dict["id"] = None - tx_serialized = Transaction._to_str(tx_dict) - - def validate(i, output_condition_uri=None): - """Validate input against output condition URI""" - return self._input_valid(self.inputs[i], self.operation, tx_serialized, output_condition_uri) - - return all(validate(i, cond) for i, cond in enumerate(output_condition_uris)) - - @lru_cache(maxsize=16384) - def _input_valid(self, input_: Input, operation: str, message: str, output_condition_uri: Optional[str] = None) -> bool: - """Validates a single Input against a single Output. - - Note: - In case of a `CREATE` Transaction, this method - does not validate against `output_condition_uri`. - - Args: - input_ (:class:`~planetmint.transactions.common.transaction. - Input`) The Input to be signed. - operation (str): The type of Transaction. - message (str): The fulfillment message. - output_condition_uri (str, optional): An Output to check the - Input against. - - Returns: - bool: If the Input is valid. - """ - ccffill = input_.fulfillment - try: - parsed_ffill = Fulfillment.from_uri(ccffill.serialize_uri()) - except TypeError as e: - print(f"Exception TypeError : {e}") - return False - except ValueError as e: - print(f"Exception ValueError : {e}") - return False - except ParsingError as e: - print(f"Exception ParsingError : {e}") - return False - except ASN1DecodeError as e: - print(f"Exception ASN1DecodeError : {e}") - return False - except ASN1EncodeError as e: - print(f"Exception ASN1EncodeError : {e}") - return False - - if operation in [self.CREATE, self.CHAIN_MIGRATION_ELECTION, self.VALIDATOR_ELECTION]: - # NOTE: In the case of a `CREATE` transaction, the - # output is always valid. - output_valid = True - else: - output_valid = output_condition_uri == ccffill.condition_uri - - ffill_valid = False - if isinstance(parsed_ffill, ZenroomSha256): - import json - - msg = json.loads(message) - ffill_valid = parsed_ffill.validate(message=json.dumps(msg["script"])) - else: - sha3_message = sha3_256(message.encode()) - if input_.fulfills: - sha3_message.update("{}{}".format(input_.fulfills.txid, input_.fulfills.output).encode()) - - # NOTE: We pass a timestamp to `.validate`, as in case of a timeout - # condition we'll have to validate against it - - # cryptoconditions makes no assumptions of the encoding of the - # message to sign or verify. It only accepts bytestrings - ffill_valid = parsed_ffill.validate(message=sha3_message.digest()) - return output_valid and ffill_valid - - # This function is required by `lru_cache` to create a key for memoization - def __hash__(self): - return hash(self.id) - - @memoize_to_dict - def to_dict(self) -> dict: - """Transforms the object to a Python dictionary. - - Returns: - dict: The Transaction as an alternative serialization format. - """ - tx_dict = { - "inputs": [input_.to_dict() for input_ in self.inputs], - "outputs": [output.to_dict() for output in self.outputs], - "operation": str(self.operation), - "metadata": self.metadata, - "asset": self.asset, - "version": self.version, - "id": self._id, - } - if self.script: - tx_dict["script"] = self.script - return tx_dict - - @staticmethod - # TODO: Remove `_dict` prefix of variable. - def _remove_signatures(tx_dict: dict) -> dict: - """Takes a Transaction dictionary and removes all signatures. - - Args: - tx_dict (dict): The Transaction to remove all signatures from. - - Returns: - dict - - """ - # NOTE: We remove the reference since we need `tx_dict` only for the - # transaction's hash - tx_dict = deepcopy(tx_dict) - for input_ in tx_dict["inputs"]: - # NOTE: Not all Cryptoconditions return a `signature` key (e.g. - # ThresholdSha256), so setting it to `None` in any - # case could yield incorrect signatures. This is why we only - # set it to `None` if it's set in the dict. - input_["fulfillment"] = None - return tx_dict - - @staticmethod - def _to_hash(value): - return hash_data(value) - - @property - def id(self): - return self._id - - def to_hash(self): - return self.to_dict()["id"] - - @staticmethod - def _to_str(value): - return serialize(value) - - # TODO: This method shouldn't call `_remove_signatures` - def __str__(self): - _tx = self.to_dict() - tx = Transaction._remove_signatures(_tx) - return Transaction._to_str(tx) - - @classmethod - def get_asset_id(cls, transactions): - """Get the asset id from a list of :class:`~.Transactions`. - - This is useful when we want to check if the multiple inputs of a - transaction are related to the same asset id. - - Args: - transactions (:obj:`list` of :class:`~planetmint.transactions.common. - transaction.Transaction`): A list of Transactions. - Usually input Transactions that should have a matching - asset ID. - - Returns: - str: ID of the asset. - - Raises: - :exc:`AssetIdMismatch`: If the inputs are related to different - assets. - """ - - if not isinstance(transactions, list): - transactions = [transactions] - - # create a set of the transactions' asset ids - asset_ids = { - tx.id if tx.operation in [tx.CREATE, tx.VALIDATOR_ELECTION] else tx.asset["id"] for tx in transactions - } - - # check that all the transasctions have the same asset id - if len(asset_ids) > 1: - raise AssetIdMismatch(("All inputs of all transactions passed" " need to have the same asset id")) - return asset_ids.pop() - - @staticmethod - def validate_id(tx_body: dict): - """Validate the transaction ID of a transaction - - Args: - tx_body (dict): The Transaction to be transformed. - """ - # NOTE: Remove reference to avoid side effects - tx_body = deepcopy(tx_body) - tx_body = rapidjson.loads(rapidjson.dumps(tx_body)) - - try: - proposed_tx_id = tx_body["id"] - except KeyError: - raise InvalidHash("No transaction id found!") - - tx_body["id"] = None - - tx_body_serialized = Transaction._to_str(tx_body) - valid_tx_id = Transaction._to_hash(tx_body_serialized) - if proposed_tx_id != valid_tx_id: - err_msg = "The transaction's id '{}' isn't equal to " "the hash of its body, i.e. it's not valid." - raise InvalidHash(err_msg.format(proposed_tx_id)) - - @classmethod - @memoize_from_dict - def from_dict(cls, tx: dict, skip_schema_validation=True): - """Transforms a Python dictionary to a Transaction object. - - Args: - tx_body (dict): The Transaction to be transformed. - - Returns: - :class:`~planetmint.transactions.common.transaction.Transaction` - """ - operation = tx.get("operation", Transaction.CREATE) if isinstance(tx, dict) else Transaction.CREATE - cls = Transaction.resolve_class(operation) - - id = None - try: - id = tx["id"] - except KeyError: - id = None - # tx['asset'] = tx['asset'][0] if isinstance( tx['asset'], list) or isinstance( tx['asset'], tuple) else tx['asset'], # noqa: E501 - local_dict = { - "inputs": tx["inputs"], - "outputs": tx["outputs"], - "operation": operation, - "metadata": tx["metadata"], - "asset": tx[ - "asset" - ], # [0] if isinstance( tx['asset'], list) or isinstance( tx['asset'], tuple) else tx['asset'], # noqa: E501 - "version": tx["version"], - "id": id, - } - try: - script_ = tx["script"] - script_dict = {"script": script_} - except KeyError: - script_ = None - pass - else: - local_dict = {**local_dict, **script_dict} - - if not skip_schema_validation: - cls.validate_id(local_dict) - cls.validate_schema(local_dict) - - inputs = [Input.from_dict(input_) for input_ in tx["inputs"]] - outputs = [Output.from_dict(output) for output in tx["outputs"]] - return cls( - tx["operation"], - tx["asset"], - inputs, - outputs, - tx["metadata"], - tx["version"], - hash_id=tx["id"], - tx_dict=tx, - script=script_, - ) - - type_registry: dict[type, type] = {} - - @staticmethod - def register_type(tx_type, tx_class): - Transaction.type_registry[tx_type] = tx_class - - def resolve_class(operation): - """For the given `tx` based on the `operation` key return its implementation class""" - - create_txn_class = Transaction.type_registry.get(Transaction.CREATE) - return Transaction.type_registry.get(operation, create_txn_class) - - @classmethod - def validate_schema(cls, tx): - validate_transaction_schema(tx) - validate_txn_obj(cls.ASSET, tx[cls.ASSET], cls.DATA, validate_key) - validate_txn_obj(cls.METADATA, tx, cls.METADATA, validate_key) - validate_language_key(tx[cls.ASSET], cls.DATA) - validate_language_key(tx, cls.METADATA) - - @classmethod - def complete_tx_i_o(self, tx_signers, recipients): - 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) diff --git a/planetmint/transactions/common/transaction_link.py b/planetmint/transactions/common/transaction_link.py deleted file mode 100644 index b58d98d..0000000 --- a/planetmint/transactions/common/transaction_link.py +++ /dev/null @@ -1,79 +0,0 @@ -# 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 Optional, Union - - -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: Optional[str] = None, output: Optional[int] = 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: dict): - """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) -> Union[dict,None]: - """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: str = "") -> Union[str,None]: - 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/transactions/common/transaction_mode_types.py b/planetmint/transactions/common/transaction_mode_types.py deleted file mode 100644 index 5821d36..0000000 --- a/planetmint/transactions/common/transaction_mode_types.py +++ /dev/null @@ -1,8 +0,0 @@ -# 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 - -BROADCAST_TX_COMMIT = "broadcast_tx_commit" -BROADCAST_TX_ASYNC = "broadcast_tx_async" -BROADCAST_TX_SYNC = "broadcast_tx_sync" diff --git a/planetmint/transactions/common/utils.py b/planetmint/transactions/common/utils.py deleted file mode 100644 index d34b33b..0000000 --- a/planetmint/transactions/common/utils.py +++ /dev/null @@ -1,232 +0,0 @@ -# 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 base58 -import time -import re -import rapidjson -from typing import Callable - -from planetmint.config import Config -from planetmint.transactions.common.exceptions import ValidationError -from cryptoconditions import ThresholdSha256, Ed25519Sha256, ZenroomSha256, Fulfillment -from planetmint.transactions.common.exceptions import ThresholdTooDeep -from cryptoconditions.exceptions import UnsupportedTypeError - - -def gen_timestamp() -> str: - """The Unix time, rounded to the nearest second. - See https://en.wikipedia.org/wiki/Unix_time - - Returns: - str: the Unix time - """ - return str(round(time.time())) - - -def serialize(data: dict) -> str: - """Serialize a dict into a JSON formatted string. - - This function enforces rules like the separator and order of keys. - This ensures that all dicts are serialized in the same way. - - This is specially important for hashing data. We need to make sure that - everyone serializes their data in the same way so that we do not have - hash mismatches for the same structure due to serialization - differences. - - Args: - data (dict): dict to serialize - - Returns: - str: JSON formatted string - - """ - return rapidjson.dumps(data, skipkeys=False, ensure_ascii=False, sort_keys=True) - - -def deserialize(data: str) -> dict: - """Deserialize a JSON formatted string into a dict. - - Args: - data (str): JSON formatted string. - - Returns: - dict: dict resulting from the serialization of a JSON formatted - string. - """ - return rapidjson.loads(data) - - -def validate_txn_obj(obj_name: str, obj: dict, key: str, validation_fun: Callable) -> None: - """Validate value of `key` in `obj` using `validation_fun`. - - Args: - obj_name (str): name for `obj` being validated. - obj (dict): dictionary object. - key (str): key to be validated in `obj`. - validation_fun (function): function used to validate the value - of `key`. - - Returns: - None: indicates validation successful - - Raises: - ValidationError: `validation_fun` will raise exception on failure - """ - backend = Config().get()["database"]["backend"] - - if backend == "localmongodb": - data = obj.get(key, {}) - if isinstance(data, dict): - validate_all_keys_in_obj(obj_name, data, validation_fun) - elif isinstance(data, list): - validate_all_items_in_list(obj_name, data, validation_fun) - - -def validate_all_items_in_list(obj_name: str, data: list, validation_fun: Callable) -> None: - for item in data: - if isinstance(item, dict): - validate_all_keys_in_obj(obj_name, item, validation_fun) - elif isinstance(item, list): - validate_all_items_in_list(obj_name, item, validation_fun) - - -def validate_all_keys_in_obj(obj_name: str, obj: dict, validation_fun: Callable) -> None: - """Validate all (nested) keys in `obj` by using `validation_fun`. - - Args: - obj_name (str): name for `obj` being validated. - obj (dict): dictionary object. - validation_fun (function): function used to validate the value - of `key`. - - Returns: - None: indicates validation successful - - Raises: - ValidationError: `validation_fun` will raise this error on failure - """ - for key, value in obj.items(): - validation_fun(obj_name, key) - if isinstance(value, dict): - validate_all_keys_in_obj(obj_name, value, validation_fun) - elif isinstance(value, list): - validate_all_items_in_list(obj_name, value, validation_fun) - - -def validate_all_values_for_key_in_obj(obj: dict, key: str, validation_fun: Callable) -> None: - """Validate value for all (nested) occurrence of `key` in `obj` - using `validation_fun`. - - Args: - obj (dict): dictionary object. - key (str): key whose value is to be validated. - validation_fun (function): function used to validate the value - of `key`. - - Raises: - ValidationError: `validation_fun` will raise this error on failure - """ - for vkey, value in obj.items(): - if vkey == key: - validation_fun(value) - elif isinstance(value, dict): - validate_all_values_for_key_in_obj(value, key, validation_fun) - elif isinstance(value, list): - validate_all_values_for_key_in_list(value, key, validation_fun) - - -def validate_all_values_for_key_in_list(input_list: list, key: str, validation_fun: Callable) -> None: - for item in input_list: - if isinstance(item, dict): - validate_all_values_for_key_in_obj(item, key, validation_fun) - elif isinstance(item, list): - validate_all_values_for_key_in_list(item, key, validation_fun) - - -def validate_key(obj_name: str, key: str) -> None: - """Check if `key` contains ".", "$" or null characters. - - https://docs.mongodb.com/manual/reference/limits/#Restrictions-on-Field-Names - - Args: - obj_name (str): object name to use when raising exception - key (str): key to validated - - Returns: - None: validation successful - - Raises: - ValidationError: will raise exception in case of regex match. - """ - if re.search(r"^[$]|\.|\x00", key): - error_str = ( - 'Invalid key name "{}" in {} object. The ' - "key name cannot contain characters " - '".", "$" or null characters' - ).format(key, obj_name) - raise ValidationError(error_str) - - -def _fulfillment_to_details(fulfillment: type[Fulfillment]) -> dict: - """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, - } - if fulfillment.type_name == "zenroom-sha-256": - return { - "type": "zenroom-sha-256", - "public_key": base58.b58encode(fulfillment.public_key).decode(), - "script": base58.b58encode(fulfillment.script).decode(), - "data": base58.b58encode(fulfillment.data).decode(), - } - - raise UnsupportedTypeError(fulfillment.type_name) - - -def _fulfillment_from_details(data: dict, _depth: int = 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 - - if data["type"] == "zenroom-sha-256": - public_key_ = base58.b58decode(data["public_key"]) - script_ = base58.b58decode(data["script"]) - data_ = base58.b58decode(data["data"]) - # TODO: assign to zenroom and evaluate the outcome - ZenroomSha256(script=script_, data=data_, keys={public_key_}) - - raise UnsupportedTypeError(data.get("type")) diff --git a/planetmint/transactions/types/__init__.py b/planetmint/transactions/types/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/planetmint/transactions/types/assets/__init__.py b/planetmint/transactions/types/assets/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/planetmint/transactions/types/assets/create.py b/planetmint/transactions/types/assets/create.py deleted file mode 100644 index 4ef21b5..0000000 --- a/planetmint/transactions/types/assets/create.py +++ /dev/null @@ -1,68 +0,0 @@ -# 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 Optional -from cid import is_cid - -from planetmint.transactions.common.transaction import Transaction - - -class Create(Transaction): - - OPERATION = "CREATE" - ALLOWED_OPERATIONS = (OPERATION,) - - @classmethod - def validate_create(self, tx_signers: list[str], recipients: list[tuple[list[str],int]], asset: Optional[dict], metadata: Optional[dict]): - 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: - if not isinstance(asset, dict): - raise TypeError("`asset` must be a CID string or None") - if "data" in asset and not is_cid(asset["data"]): - raise TypeError("`asset` must be a CID string or None") - if not (metadata is None or is_cid(metadata)): - raise TypeError("`metadata` must be a CID string or None") - - return True - - @classmethod - def generate(cls, tx_signers: list[str], recipients: list[tuple[list[str],int]], metadata: Optional[dict] = None, asset: Optional[dict] = 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` - """ - - Create.validate_create(tx_signers, recipients, asset, metadata) - (inputs, outputs) = Transaction.complete_tx_i_o(tx_signers, recipients) - return cls(cls.OPERATION, asset, inputs, outputs, metadata) diff --git a/planetmint/transactions/types/assets/transfer.py b/planetmint/transactions/types/assets/transfer.py deleted file mode 100644 index cfcfe11..0000000 --- a/planetmint/transactions/types/assets/transfer.py +++ /dev/null @@ -1,84 +0,0 @@ -# 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 Optional - -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" - ALLOWED_OPERATIONS = (OPERATION,) - - @classmethod - def validate_transfer(cls, inputs: list[Input], recipients: list[tuple[list[str],int]], asset_id: str, metadata: Optional[dict]): - 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: list[Input], recipients: list[tuple[list[str],int]], asset_id: str, metadata: Optional[dict] = 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 deleted file mode 100644 index e69de29..0000000 diff --git a/planetmint/transactions/types/elections/chain_migration_election.py b/planetmint/transactions/types/elections/chain_migration_election.py deleted file mode 100644 index 014843f..0000000 --- a/planetmint/transactions/types/elections/chain_migration_election.py +++ /dev/null @@ -1,15 +0,0 @@ -# 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.schema import TX_SCHEMA_CHAIN_MIGRATION_ELECTION -from planetmint.transactions.common.transaction import CHAIN_MIGRATION_ELECTION -from planetmint.transactions.types.elections.election import Election - - -class ChainMigrationElection(Election): - - OPERATION = CHAIN_MIGRATION_ELECTION - ALLOWED_OPERATIONS = (OPERATION,) - TX_SCHEMA_CUSTOM = TX_SCHEMA_CHAIN_MIGRATION_ELECTION diff --git a/planetmint/transactions/types/elections/election.py b/planetmint/transactions/types/elections/election.py deleted file mode 100644 index 51af81f..0000000 --- a/planetmint/transactions/types/elections/election.py +++ /dev/null @@ -1,68 +0,0 @@ -# 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 uuid import uuid4 -from typing import Optional - -from planetmint.transactions.common.transaction import Transaction -from planetmint.transactions.common.schema import _validate_schema, TX_SCHEMA_COMMON - -class Election(Transaction): - """Represents election transactions. - - To implement a custom election, create a class deriving from this one - with OPERATION set to the election operation, ALLOWED_OPERATIONS - set to (OPERATION,), CREATE set to OPERATION. - """ - - OPERATION: Optional[str] = None - # Custom validation schema - TX_SCHEMA_CUSTOM = None - # Election Statuses: - ONGOING: str = "ongoing" - CONCLUDED: str = "concluded" - INCONCLUSIVE: str = "inconclusive" - # Vote ratio to approve an election - ELECTION_THRESHOLD = 2 / 3 - - @classmethod - def validate_election(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: - if not isinstance(asset, dict): - raise TypeError("`asset` must be a CID string or None") - if not (metadata is None or isinstance(metadata, str)): - # add check if metadata is ipld marshalled CID string - raise TypeError("`metadata` must be a CID string or None") - - return True - - @classmethod - def generate(cls, initiator, voters, election_data, metadata=None): - # Break symmetry in case we need to call an election with the same properties twice - uuid = uuid4() - election_data["seed"] = str(uuid) - - Election.validate_election(initiator, voters, election_data, metadata) - (inputs, outputs) = Transaction.complete_tx_i_o(initiator, voters) - election = cls(cls.OPERATION, {"data": election_data}, inputs, outputs, metadata) - cls.validate_schema(election.to_dict()) - return election - - @classmethod - def validate_schema(cls, tx): - """Validate the election transaction. Since `ELECTION` extends `CREATE` transaction, all the validations for - `CREATE` transaction should be inherited - """ - _validate_schema(TX_SCHEMA_COMMON, tx) - if cls.TX_SCHEMA_CUSTOM: - _validate_schema(cls.TX_SCHEMA_CUSTOM, tx) diff --git a/planetmint/transactions/types/elections/validator_election.py b/planetmint/transactions/types/elections/validator_election.py deleted file mode 100644 index cc87487..0000000 --- a/planetmint/transactions/types/elections/validator_election.py +++ /dev/null @@ -1,22 +0,0 @@ -# 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.types.elections.election import Election -from planetmint.transactions.common.schema import TX_SCHEMA_VALIDATOR_ELECTION -from planetmint.transactions.common.transaction import VALIDATOR_ELECTION - -from .validator_utils import validate_asset_public_key - - -class ValidatorElection(Election): - - OPERATION = VALIDATOR_ELECTION - ALLOWED_OPERATIONS = (OPERATION,) - TX_SCHEMA_CUSTOM = TX_SCHEMA_VALIDATOR_ELECTION - - @classmethod - def validate_schema(cls, tx): - super(ValidatorElection, cls).validate_schema(tx) - validate_asset_public_key(tx["asset"]["data"]["public_key"]) diff --git a/planetmint/transactions/types/elections/validator_utils.py b/planetmint/transactions/types/elections/validator_utils.py deleted file mode 100644 index b9e801c..0000000 --- a/planetmint/transactions/types/elections/validator_utils.py +++ /dev/null @@ -1,51 +0,0 @@ -# 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 base58 -import base64 -import binascii - -from planetmint.transactions.common.exceptions import InvalidPublicKey - - -def encode_pk_to_base16(validator): - pk = validator["public_key"] - decoder = get_public_key_decoder(pk) - public_key16 = base64.b16encode(decoder(pk["value"])).decode("utf-8") - - validator["public_key"]["value"] = public_key16 - return validator - - -def validate_asset_public_key(pk): - pk_binary = pk["value"].encode("utf-8") - decoder = get_public_key_decoder(pk) - try: - pk_decoded = decoder(pk_binary) - if len(pk_decoded) != 32: - raise InvalidPublicKey("Public key should be of size 32 bytes") - - except binascii.Error: - raise InvalidPublicKey("Invalid `type` specified for public key `value`") - - -def get_public_key_decoder(pk): - encoding = pk["type"] - decoder = base64.b64decode - - if encoding == "ed25519-base16": - decoder = base64.b16decode - elif encoding == "ed25519-base32": - decoder = base64.b32decode - elif encoding == "ed25519-base64": - decoder = base64.b64decode - else: - raise InvalidPublicKey("Invalid `type` specified for public key `value`") - - return decoder - - -def election_id_to_public_key(election_id): - return base58.b58encode(bytes.fromhex(election_id)).decode() diff --git a/planetmint/transactions/types/elections/vote.py b/planetmint/transactions/types/elections/vote.py deleted file mode 100644 index ed6449e..0000000 --- a/planetmint/transactions/types/elections/vote.py +++ /dev/null @@ -1,39 +0,0 @@ -# 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.types.assets.transfer import Transfer -from planetmint.transactions.common.transaction import VOTE -from planetmint.transactions.common.schema import ( - _validate_schema, - TX_SCHEMA_COMMON, - TX_SCHEMA_TRANSFER, - TX_SCHEMA_VOTE, -) - - -class Vote(Transfer): - OPERATION = VOTE - # NOTE: This class inherits TRANSFER txn type. The `TRANSFER` property is - # overriden to re-use methods from parent class - TRANSFER = OPERATION - ALLOWED_OPERATIONS = (OPERATION,) - # Custom validation schema - TX_SCHEMA_CUSTOM = TX_SCHEMA_VOTE - - @classmethod - def generate(cls, inputs, recipients, election_id, metadata=None): - (inputs, outputs) = cls.validate_transfer(inputs, recipients, election_id, metadata) - election_vote = cls(cls.OPERATION, {"id": election_id}, inputs, outputs, metadata) - cls.validate_schema(election_vote.to_dict()) - return election_vote - - @classmethod - def validate_schema(cls, tx): - """Validate the validator election vote transaction. Since `VOTE` extends `TRANSFER` - transaction, all the validations for `CREATE` transaction should be inherited - """ - _validate_schema(TX_SCHEMA_COMMON, tx) - _validate_schema(TX_SCHEMA_TRANSFER, tx) - _validate_schema(cls.TX_SCHEMA_CUSTOM, tx) diff --git a/planetmint/utils.py b/planetmint/utils.py index eff4c25..90e41ed 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.transactions.common.crypto import key_pair_from_ed25519_key +from 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 931d34a..eb38dfc 100644 --- a/planetmint/web/views/parameters.py +++ b/planetmint/web/views/parameters.py @@ -5,7 +5,7 @@ import re -from planetmint.transactions.common.transaction_mode_types import ( +from 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 fff024b..6b67247 100644 --- a/planetmint/web/views/transactions.py +++ b/planetmint/web/views/transactions.py @@ -12,14 +12,14 @@ import logging from flask import current_app, request, jsonify from flask_restful import Resource, reqparse -from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_ASYNC -from planetmint.transactions.common.exceptions import ( +from transactions.common.transaction_mode_types import BROADCAST_TX_ASYNC +from transactions.common.exceptions import ( SchemaValidationError, ValidationError, ) from planetmint.web.views.base import make_error from planetmint.web.views import parameters -from planetmint.transactions.common.transaction import Transaction +from transactions.common.transaction import Transaction logger = logging.getLogger(__name__) diff --git a/setup.py b/setup.py index 87cd566..dd431f6 100644 --- a/setup.py +++ b/setup.py @@ -116,14 +116,14 @@ install_requires = [ "flask-restful==0.3.9", "flask==2.1.2", "gunicorn==20.1.0", - "jsonschema==3.2.0", + "jsonschema==4.16.0", "logstats==0.3.0", "packaging>=20.9", # TODO Consider not installing the db drivers, or putting them in extras. "pymongo==3.11.4", "tarantool==0.7.1", "python-rapidjson>=1.0", - "pyyaml==5.4.1", + "pyyaml==6.0.0", "requests==2.25.1", "setproctitle==1.2.2", "werkzeug==2.0.3", @@ -136,6 +136,7 @@ install_requires = [ "PyNaCl==1.4.0", "pyasn1>=0.4.8", "cryptography==3.4.7", + "planetmint-transactions==0.1.0", ] setup( @@ -176,7 +177,7 @@ setup( "docs": docs_require, }, package_data={ - "planetmint.transactions.common.schema": [ + "transactions.common.schema": [ "v1.0/*.yaml", "v2.0/*.yaml", "v3.0/*.yaml", diff --git a/tests/assets/test_digital_assets.py b/tests/assets/test_digital_assets.py index 1446a7c..9a37283 100644 --- a/tests/assets/test_digital_assets.py +++ b/tests/assets/test_digital_assets.py @@ -4,8 +4,8 @@ # 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 transactions.types.assets.create import Create +from transactions.types.assets.transfer import Transfer def test_asset_transfer(b, signed_create_tx, user_pk, user_sk): @@ -19,7 +19,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.transactions.common.exceptions import AssetIdMismatch + from transactions.common.exceptions import AssetIdMismatch tx_transfer = Transfer.generate(signed_create_tx.to_inputs(), [([user_pk], 1)], signed_create_tx.id) tx_transfer.asset["id"] = "a" * 64 @@ -32,14 +32,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.transactions.common.transaction import Transaction + from transactions.common.transaction import Transaction 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.transactions.common.transaction import Transaction + from transactions.common.transaction import Transaction tx_transfer = Transfer.generate(signed_create_tx.to_inputs(), [([user_pk], 1)], signed_create_tx.id) asset_id = Transaction.get_asset_id(tx_transfer) @@ -47,8 +47,8 @@ def test_get_asset_id_transfer_transaction(b, signed_create_tx, user_pk): def test_asset_id_mismatch(alice, user_pk): - from planetmint.transactions.common.transaction import Transaction - from planetmint.transactions.common.exceptions import AssetIdMismatch + from transactions.common.transaction import Transaction + from transactions.common.exceptions import AssetIdMismatch tx1 = Create.generate( [alice.public_key], [([user_pk], 1)], metadata="QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4" diff --git a/tests/assets/test_divisible_assets.py b/tests/assets/test_divisible_assets.py index fb7e046..f6718cd 100644 --- a/tests/assets/test_divisible_assets.py +++ b/tests/assets/test_divisible_assets.py @@ -7,9 +7,9 @@ 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 +from transactions.types.assets.create import Create +from transactions.types.assets.transfer import Transfer +from transactions.common.exceptions import DoubleSpend # CREATE divisible asset @@ -107,7 +107,7 @@ def test_single_in_single_own_multiple_out_mix_own_create(alice, user_pk, b): # Multiple owners_before # 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 + from transactions.common.utils import _fulfillment_to_details tx = Create.generate( [alice.public_key, user_pk], @@ -259,7 +259,7 @@ def test_single_in_single_own_multiple_out_mix_own_transfer(alice, b, user_pk, u # Single output # 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 + from transactions.common.utils import _fulfillment_to_details # CREATE divisible asset tx_create = Create.generate( @@ -325,7 +325,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): - from planetmint.transactions.common.utils import _fulfillment_to_details + from transactions.common.utils import _fulfillment_to_details # CREATE divisible asset tx_create = Create.generate( @@ -365,7 +365,7 @@ def test_multiple_in_multiple_own_single_out_single_own_transfer(alice, b, user_ # Single output # 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 + from transactions.common.utils import _fulfillment_to_details # CREATE divisible asset tx_create = Create.generate( @@ -404,7 +404,7 @@ def test_muiltiple_in_mix_own_multiple_out_single_own_transfer(alice, b, user_pk # Mix: one output with a single owners_after, one output with multiple # 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 + from transactions.common.utils import _fulfillment_to_details # CREATE divisible asset tx_create = Create.generate( @@ -492,7 +492,7 @@ 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 + from transactions.common.exceptions import AmountError # CREATE divisible asset tx_create = Create.generate( diff --git a/tests/assets/test_zenroom_signing.py b/tests/assets/test_zenroom_signing.py index 932bdce..eeebe64 100644 --- a/tests/assets/test_zenroom_signing.py +++ b/tests/assets/test_zenroom_signing.py @@ -1,11 +1,9 @@ -import pytest import json import base58 from hashlib import sha3_256 from zenroom import zencode_exec -from cryptoconditions.types.ed25519 import Ed25519Sha256 from cryptoconditions.types.zenroom import ZenroomSha256 -from planetmint.transactions.common.crypto import generate_key_pair +from transactions.common.crypto import generate_key_pair from ipld import multihash, marshal CONDITION_SCRIPT = """Scenario 'ecdh': create the signature of an object @@ -150,9 +148,9 @@ def test_zenroom_signing(): shared_creation_txid = sha3_256(json_str_tx.encode()).hexdigest() tx["id"] = shared_creation_txid - from planetmint.transactions.common.transaction import Transaction + from transactions.common.transaction import Transaction from planetmint.lib import Planetmint - from planetmint.transactions.common.exceptions import ( + from transactions.common.exceptions import ( SchemaValidationError, ValidationError, ) diff --git a/tests/backend/localmongodb/test_queries.py b/tests/backend/localmongodb/test_queries.py index 5804880..fff5951 100644 --- a/tests/backend/localmongodb/test_queries.py +++ b/tests/backend/localmongodb/test_queries.py @@ -4,8 +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 +# from transactions.types.assets.create import Create +# from transactions.types.assets.transfer import Transfer # # # import pytest # # import pymongo @@ -238,7 +238,7 @@ # @pytest.mark.skip # def test_get_spending_transactions_multiple_inputs(): # from planetmint.backend import connect, query -# from planetmint.transactions.common.crypto import generate_key_pair +# from 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/tarantool/test_queries.py b/tests/backend/tarantool/test_queries.py index 104fa94..d2c81c9 100644 --- a/tests/backend/tarantool/test_queries.py +++ b/tests/backend/tarantool/test_queries.py @@ -7,9 +7,9 @@ from copy import deepcopy import pytest import json -from planetmint.transactions.common.transaction import Transaction -from planetmint.transactions.types.assets.create import Create -from planetmint.transactions.types.assets.transfer import Transfer +from transactions.common.transaction import Transaction +from transactions.types.assets.create import Create +from transactions.types.assets.transfer import Transfer pytestmark = pytest.mark.bdb @@ -228,7 +228,7 @@ def test_get_spending_transactions(user_pk, user_sk, db_conn): def test_get_spending_transactions_multiple_inputs(db_conn): - from planetmint.transactions.common.crypto import generate_key_pair + from transactions.common.crypto import generate_key_pair from planetmint.backend.tarantool import query (alice_sk, alice_pk) = generate_key_pair() diff --git a/tests/backend/test_connection.py b/tests/backend/test_connection.py index 471b42c..2ab6646 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.transactions.common.exceptions import ConfigurationError + from transactions.common.exceptions import ConfigurationError from planetmint.backend.connection import connect with pytest.raises(ConfigurationError): diff --git a/tests/commands/conftest.py b/tests/commands/conftest.py index 2d72cd6..2fd8028 100644 --- a/tests/commands/conftest.py +++ b/tests/commands/conftest.py @@ -39,7 +39,7 @@ def mock_processes_start(monkeypatch): @pytest.fixture def mock_generate_key_pair(monkeypatch): - monkeypatch.setattr("planetmint.transactions.common.crypto.generate_key_pair", lambda: ("privkey", "pubkey")) + monkeypatch.setattr("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 d55b1ac..4b9e3df 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -14,9 +14,8 @@ import pytest from planetmint.config import Config from planetmint import ValidatorElection from planetmint.commands.planetmint import run_election_show -from planetmint.transactions.types.elections.election import Election from planetmint.lib import Block -from planetmint.transactions.types.elections.chain_migration_election import ChainMigrationElection +from transactions.types.elections.chain_migration_election import ChainMigrationElection from tests.utils import generate_election, generate_validators @@ -137,7 +136,7 @@ def test_drop_db_when_interactive_yes(mock_db_drop, monkeypatch): @patch("planetmint.backend.schema.drop_database") def test_drop_db_when_db_does_not_exist(mock_db_drop, capsys): - from planetmint.transactions.common.exceptions import DatabaseDoesNotExist + from transactions.common.exceptions import DatabaseDoesNotExist from planetmint.commands.planetmint import run_drop args = Namespace(config=None, yes=True) @@ -263,7 +262,7 @@ def test_recover_db_on_start(mock_run_recover, mock_start, mocked_setup_logging) @pytest.mark.bdb def test_run_recover(b, alice, bob): from planetmint.commands.planetmint import run_recover - from planetmint.transactions.types.assets.create import Create + from transactions.types.assets.create import Create from planetmint.lib import Block from planetmint.backend import query @@ -408,7 +407,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.transactions.common.exceptions import InvalidPowerChange + from 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 a55f845..fdc5ecf 100644 --- a/tests/common/conftest.py +++ b/tests/common/conftest.py @@ -89,35 +89,35 @@ def user2_Ed25519(user2_pub): @pytest.fixture def user_input(user_Ed25519, user_pub): - from planetmint.transactions.common.transaction import Input + from 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.transactions.common.transaction import Output + from 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.transactions.common.transaction import Input + from 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.transactions.common.transaction import Output + from transactions.common.transaction import Output return Output(user_Ed25519, [user_pub]) @pytest.fixture def user2_output(user2_Ed25519, user2_pub): - from planetmint.transactions.common.transaction import Output + from transactions.common.transaction import Output return Output(user2_Ed25519, [user2_pub]) @@ -134,7 +134,7 @@ def data(): @pytest.fixture def utx(user_input, user_output): - from planetmint.transactions.common.transaction import Transaction + from transactions.common.transaction import Transaction return Transaction(Transaction.CREATE, {"data": None}, [user_input], [user_output]) @@ -146,7 +146,7 @@ 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 transactions.common.transaction import Input, TransactionLink, Transaction user_output = user_output.to_dict() input = Input(utx.outputs[0].fulfillment, user_output["public_keys"], TransactionLink(utx.id, 0)) diff --git a/tests/common/test_memoize.py b/tests/common/test_memoize.py index f3b2723..89903c8 100644 --- a/tests/common/test_memoize.py +++ b/tests/common/test_memoize.py @@ -6,10 +6,10 @@ import pytest from copy import deepcopy -from planetmint.transactions.common.transaction 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 +from transactions.common.transaction import Transaction +from transactions.types.assets.create import Create +from transactions.common.crypto import generate_key_pair +from 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 478be28..cdf400e 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.transactions.common.exceptions import SchemaValidationError -from planetmint.transactions.common.schema import ( +from transactions.common.exceptions import SchemaValidationError +from 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 1c0f0e7..752e78e 100644 --- a/tests/common/test_transaction.py +++ b/tests/common/test_transaction.py @@ -10,13 +10,13 @@ import json from copy import deepcopy from base58 import b58encode, b58decode -from planetmint.transactions.types.assets.create import Create -from planetmint.transactions.types.assets.transfer import Transfer -from planetmint.transactions.common.transaction import Output -from planetmint.transactions.common.transaction import Input -from planetmint.transactions.common.exceptions import AmountError -from planetmint.transactions.common.transaction import Transaction -from planetmint.transactions.common.transaction import TransactionLink +from transactions.types.assets.create import Create +from transactions.types.assets.transfer import Transfer +from transactions.common.transaction import Output +from transactions.common.transaction import Input +from transactions.common.exceptions import AmountError +from transactions.common.transaction import Transaction +from transactions.common.transaction import TransactionLink from cryptoconditions import ThresholdSha256 from cryptoconditions import Fulfillment from cryptoconditions import PreimageSha256 @@ -52,7 +52,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.transactions.common.transaction import Input + from transactions.common.transaction import Input ffill = { "owners_before": [user_pub], @@ -64,8 +64,8 @@ def test_input_deserialization_with_invalid_input(user_pub): def test_input_deserialization_with_invalid_fulfillment_uri(user_pub): - from planetmint.transactions.common.exceptions import InvalidSignature - from planetmint.transactions.common.transaction import Input + from transactions.common.exceptions import InvalidSignature + from transactions.common.transaction import Input ffill = { "owners_before": [user_pub], @@ -89,7 +89,7 @@ def test_input_deserialization_with_unsigned_fulfillment(ffill_uri, user_pub): def test_output_serialization(user_Ed25519, user_pub): - from planetmint.transactions.common.transaction import Output + from transactions.common.transaction import Output expected = { "condition": { @@ -109,7 +109,7 @@ def test_output_serialization(user_Ed25519, user_pub): def test_output_deserialization(user_Ed25519, user_pub): - from planetmint.transactions.common.transaction import Output + from transactions.common.transaction import Output expected = Output(user_Ed25519, [user_pub], 1) cond = { @@ -229,8 +229,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.transactions.common.transaction import Output - from planetmint.transactions.common.exceptions import AmountError + from transactions.common.transaction import Output + from transactions.common.exceptions import AmountError with raises(ValueError): Output.generate([], 1) @@ -298,7 +298,7 @@ def test_transaction_deserialization(tri_state_transaction): def test_invalid_input_initialization(user_input, user_pub): - from planetmint.transactions.common.transaction import Input + from transactions.common.transaction import Input with raises(TypeError): Input(user_input, user_pub) @@ -435,7 +435,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.transactions.common.exceptions import KeypairMismatchException + from transactions.common.exceptions import KeypairMismatchException with raises(KeypairMismatchException): invalid_key_pair = {"wrong_pub_key": "wrong_priv_key"} @@ -443,7 +443,7 @@ def test_invoke_simple_signature_fulfillment_with_invalid_params(utx, user_input def test_sign_threshold_with_invalid_params(utx, user_user2_threshold_input, user3_pub, user3_priv): - from planetmint.transactions.common.exceptions import KeypairMismatchException + from transactions.common.exceptions import KeypairMismatchException with raises(KeypairMismatchException): utx._sign_threshold_signature_fulfillment(user_user2_threshold_input, "somemessage", {user3_pub: user3_priv}) @@ -845,8 +845,8 @@ def test_transaction_hash(fulfilled_transaction): def test_output_from_dict_invalid_amount(user_output): - from planetmint.transactions.common.transaction import Output - from planetmint.transactions.common.exceptions import AmountError + from transactions.common.transaction import Output + from transactions.common.exceptions import AmountError out = user_output.to_dict() out["amount"] = "a" diff --git a/tests/common/utils.py b/tests/common/utils.py index bd10303..b110984 100644 --- a/tests/common/utils.py +++ b/tests/common/utils.py @@ -5,8 +5,8 @@ def validate_transaction_model(tx): - from planetmint.transactions.common.transaction import Transaction - from planetmint.transactions.common.schema import validate_transaction_schema + from transactions.common.transaction import Transaction + from 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 2755728..5837bfa 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -11,7 +11,6 @@ Tasks: """ import json import os -import copy import random import tempfile import codecs @@ -26,16 +25,16 @@ import pytest # from pymongo import MongoClient -from planetmint.transactions.common import crypto -from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT +from transactions.common import crypto +from 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.exceptions import DatabaseDoesNotExist +from transactions.common.crypto import key_pair_from_ed25519_key, public_key_from_ed25519_key +from transactions.common.exceptions import DatabaseDoesNotExist from planetmint.lib import Block from tests.utils import gen_vote from planetmint.config import Config -from planetmint.transactions.types.elections.validator_election import ValidatorElection # noqa +from transactions.types.elections.validator_election import ValidatorElection # noqa from tendermint.abci import types_pb2 as types from tendermint.crypto import keys_pb2 @@ -140,8 +139,8 @@ def _setup_database(_configure_planetmint): # TODO Here is located setup databa @pytest.fixture def _bdb(_setup_database, _configure_planetmint): - from planetmint.transactions.common.memoize import to_dict, from_dict - from planetmint.transactions.common.transaction import Transaction + from transactions.common.memoize import to_dict, from_dict + from transactions.common.transaction import Transaction from .utils import flush_db from planetmint.config import Config @@ -198,14 +197,14 @@ def user2_pk(): @pytest.fixture def alice(): - from planetmint.transactions.common.crypto import generate_key_pair + from transactions.common.crypto import generate_key_pair return generate_key_pair() @pytest.fixture def bob(): - from planetmint.transactions.common.crypto import generate_key_pair + from transactions.common.crypto import generate_key_pair return generate_key_pair() @@ -222,7 +221,7 @@ def bob_pubkey(carol): @pytest.fixture def carol(): - from planetmint.transactions.common.crypto import generate_key_pair + from transactions.common.crypto import generate_key_pair return generate_key_pair() @@ -239,7 +238,7 @@ def carol_pubkey(carol): @pytest.fixture def merlin(): - from planetmint.transactions.common.crypto import generate_key_pair + from transactions.common.crypto import generate_key_pair return generate_key_pair() @@ -284,7 +283,7 @@ def mock_get_validators(network_validators): @pytest.fixture def create_tx(alice, user_pk): - from planetmint.transactions.types.assets.create import Create + from transactions.types.assets.create import Create name = f"I am created by the create_tx fixture. My random identifier is {random.random()}." asset = {"data": multihash(marshal({"name": name}))} @@ -305,7 +304,7 @@ def posted_create_tx(b, signed_create_tx): @pytest.fixture def signed_transfer_tx(signed_create_tx, user_pk, user_sk): - from planetmint.transactions.types.assets.transfer import Transfer + from transactions.types.assets.transfer import Transfer inputs = signed_create_tx.to_inputs() tx = Transfer.generate(inputs, [([user_pk], 1)], asset_id=signed_create_tx.id) @@ -314,7 +313,7 @@ def signed_transfer_tx(signed_create_tx, user_pk, user_sk): @pytest.fixture def double_spend_tx(signed_create_tx, carol_pubkey, user_sk): - from planetmint.transactions.types.assets.transfer import Transfer + from transactions.types.assets.transfer import Transfer inputs = signed_create_tx.to_inputs() tx = Transfer.generate(inputs, [([carol_pubkey], 1)], asset_id=signed_create_tx.id) @@ -328,7 +327,7 @@ def _get_height(b): @pytest.fixture def inputs(user_pk, b, alice): - from planetmint.transactions.types.assets.create import Create + from transactions.types.assets.create import Create # create blocks with transactions for `USER` to spend for height in range(1, 4): diff --git a/tests/db/test_planetmint_api.py b/tests/db/test_planetmint_api.py index 1faf9b6..6c67e15 100644 --- a/tests/db/test_planetmint_api.py +++ b/tests/db/test_planetmint_api.py @@ -4,8 +4,8 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 import warnings from unittest.mock import patch -from planetmint.transactions.types.assets.create import Create -from planetmint.transactions.types.assets.transfer import Transfer +from transactions.types.assets.create import Create +from transactions.types.assets.transfer import Transfer from ipld import marshal, multihash import pytest from base58 import b58decode @@ -16,7 +16,7 @@ pytestmark = pytest.mark.bdb class TestBigchainApi(object): def test_get_spent_with_double_spend_detected(self, b, alice): - from planetmint.transactions.common.exceptions import DoubleSpend + from transactions.common.exceptions import DoubleSpend from planetmint.exceptions import CriticalDoubleSpend tx = Create.generate([alice.public_key], [([alice.public_key], 1)]) @@ -85,8 +85,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.transactions.common.exceptions import InputDoesNotExist - from planetmint.transactions.common.transaction import Input, TransactionLink + from transactions.common.exceptions import InputDoesNotExist + from transactions.common.transaction import Input, TransactionLink # Create an input for a non existing transaction input = Input( @@ -116,8 +116,8 @@ class TestBigchainApi(object): class TestTransactionValidation(object): def test_non_create_input_not_found(self, b, signed_transfer_tx): - from planetmint.transactions.common.exceptions import InputDoesNotExist - from planetmint.transactions.common.transaction import TransactionLink + from transactions.common.exceptions import InputDoesNotExist + from transactions.common.transaction import TransactionLink signed_transfer_tx.inputs[0].fulfills = TransactionLink("c", 0) with pytest.raises(InputDoesNotExist): @@ -125,8 +125,8 @@ class TestTransactionValidation(object): @pytest.mark.usefixtures("inputs") 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 transactions.common.crypto import generate_key_pair + from transactions.common.exceptions import InvalidSignature input_tx = b.fastquery.get_outputs_by_public_key(user_pk).pop() input_transaction = b.get_transaction(input_tx.txid) @@ -141,7 +141,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.transactions.common.exceptions import DoubleSpend + from transactions.common.exceptions import DoubleSpend b.store_bulk_transactions([signed_create_tx, signed_transfer_tx]) @@ -151,7 +151,7 @@ class TestTransactionValidation(object): class TestMultipleInputs(object): def test_transfer_single_owner_single_input(self, b, inputs, user_pk, user_sk): - from planetmint.transactions.common import crypto + from transactions.common import crypto user2_sk, user2_pk = crypto.generate_key_pair() @@ -167,7 +167,7 @@ class TestMultipleInputs(object): assert len(tx.outputs) == 1 def test_single_owner_before_multiple_owners_after_single_input(self, b, user_sk, user_pk, inputs): - from planetmint.transactions.common import crypto + from transactions.common import crypto user2_sk, user2_pk = crypto.generate_key_pair() user3_sk, user3_pk = crypto.generate_key_pair() @@ -183,7 +183,7 @@ class TestMultipleInputs(object): @pytest.mark.usefixtures("inputs") def test_multiple_owners_before_single_owner_after_single_input(self, b, user_sk, user_pk, alice): - from planetmint.transactions.common import crypto + from transactions.common import crypto user2_sk, user2_pk = crypto.generate_key_pair() user3_sk, user3_pk = crypto.generate_key_pair() @@ -206,7 +206,7 @@ class TestMultipleInputs(object): @pytest.mark.usefixtures("inputs") def test_multiple_owners_before_multiple_owners_after_single_input(self, b, user_sk, user_pk, alice): - from planetmint.transactions.common import crypto + from transactions.common import crypto user2_sk, user2_pk = crypto.generate_key_pair() user3_sk, user3_pk = crypto.generate_key_pair() @@ -228,8 +228,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.transactions.common import crypto - from planetmint.transactions.common.transaction import TransactionLink + from transactions.common import crypto + from transactions.common.transaction import TransactionLink user2_sk, user2_pk = crypto.generate_key_pair() @@ -253,8 +253,8 @@ class TestMultipleInputs(object): assert owned_inputs_user2 == [TransactionLink(tx_transfer.id, 0)] def test_get_owned_ids_single_tx_multiple_outputs(self, b, user_sk, user_pk, alice): - from planetmint.transactions.common import crypto - from planetmint.transactions.common.transaction import TransactionLink + from transactions.common import crypto + from transactions.common.transaction import TransactionLink user2_sk, user2_pk = crypto.generate_key_pair() @@ -284,8 +284,8 @@ class TestMultipleInputs(object): assert owned_inputs_user2 == [TransactionLink(tx_transfer.id, 0), TransactionLink(tx_transfer.id, 1)] 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 transactions.common import crypto + from transactions.common.transaction import TransactionLink user2_sk, user2_pk = crypto.generate_key_pair() user3_sk, user3_pk = crypto.generate_key_pair() @@ -314,7 +314,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.transactions.common import crypto + from transactions.common import crypto user2_sk, user2_pk = crypto.generate_key_pair() @@ -338,7 +338,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.transactions.common import crypto + from transactions.common import crypto # create a new users user2_sk, user2_pk = crypto.generate_key_pair() @@ -371,7 +371,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.transactions.common import crypto + from transactions.common import crypto user2_sk, user2_pk = crypto.generate_key_pair() user3_sk, user3_pk = crypto.generate_key_pair() @@ -403,7 +403,7 @@ class TestMultipleInputs(object): def test_get_outputs_filtered_only_unspent(): - from planetmint.transactions.common.transaction import TransactionLink + from transactions.common.transaction import TransactionLink from planetmint.lib import Planetmint go = "planetmint.fastquery.FastQuery.get_outputs_by_public_key" @@ -418,7 +418,7 @@ def test_get_outputs_filtered_only_unspent(): def test_get_outputs_filtered_only_spent(): - from planetmint.transactions.common.transaction import TransactionLink + from transactions.common.transaction import TransactionLink from planetmint.lib import Planetmint go = "planetmint.fastquery.FastQuery.get_outputs_by_public_key" @@ -435,7 +435,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.transactions.common.transaction import TransactionLink + from transactions.common.transaction import TransactionLink from planetmint.lib import Planetmint go = "planetmint.fastquery.FastQuery.get_outputs_by_public_key" @@ -452,7 +452,7 @@ def test_cant_spend_same_input_twice_in_tx(b, alice): """Recreate duplicated fulfillments bug https://github.com/planetmint/planetmint/issues/1099 """ - from planetmint.transactions.common.exceptions import DoubleSpend + from transactions.common.exceptions import DoubleSpend # create a divisible asset tx_create = Create.generate([alice.public_key], [([alice.public_key], 100)]) @@ -470,7 +470,7 @@ 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 transactions.common.utils import serialize # 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 ae95a42..63626e3 100644 --- a/tests/elections/test_election.py +++ b/tests/elections/test_election.py @@ -3,9 +3,9 @@ import pytest from tests.utils import generate_election, generate_validators from planetmint.lib import Block -from planetmint.transactions.types.elections.election import Election -from planetmint.transactions.types.elections.chain_migration_election import ChainMigrationElection -from planetmint.transactions.types.elections.validator_election import ValidatorElection +from transactions.types.elections.election import Election +from transactions.types.elections.chain_migration_election import ChainMigrationElection +from transactions.types.elections.validator_election import ValidatorElection @pytest.mark.bdb diff --git a/tests/migrations/test_migration_election.py b/tests/migrations/test_migration_election.py index b83ac0c..798107b 100644 --- a/tests/migrations/test_migration_election.py +++ b/tests/migrations/test_migration_election.py @@ -1,4 +1,4 @@ -from planetmint.transactions.types.elections.chain_migration_election import ChainMigrationElection +from transactions.types.elections.chain_migration_election import ChainMigrationElection def test_valid_migration_election(b_mock, node_key): diff --git a/tests/tendermint/test_core.py b/tests/tendermint/test_core.py index bf715b5..caa6c6a 100644 --- a/tests/tendermint/test_core.py +++ b/tests/tendermint/test_core.py @@ -4,28 +4,27 @@ # 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 +import multiprocessing as mp +import pytest from tendermint.abci import types_pb2 as types from tendermint.crypto import keys_pb2 +from transactions import ValidatorElection, ChainMigrationElection +from transactions.common.crypto import generate_key_pair +from transactions.types.assets.create import Create +from transactions.types.assets.transfer import Transfer from planetmint import App from planetmint.backend import query -from planetmint.transactions.common.crypto import generate_key_pair from planetmint.core import OkCode, CodeTypeError, rollback from planetmint.lib import Block -from planetmint.transactions.types.elections.chain_migration_election import ChainMigrationElection -from planetmint.transactions.types.elections.validator_election import ValidatorElection from planetmint.tendermint_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 - pytestmark = pytest.mark.bdb @@ -197,9 +196,6 @@ def test_info(b): def test_check_tx__signed_create_is_ok(b): - from planetmint import App - from planetmint.transactions.common.crypto import generate_key_pair - alice = generate_key_pair() bob = generate_key_pair() @@ -211,9 +207,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.transactions.common.crypto import generate_key_pair - alice = generate_key_pair() bob = generate_key_pair() @@ -225,10 +218,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.transactions.common.crypto import generate_key_pair - alice = generate_key_pair() bob = generate_key_pair() events = mp.Queue() @@ -260,9 +249,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.transactions.common.crypto import generate_key_pair - alice = generate_key_pair() bob = generate_key_pair() @@ -285,9 +271,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.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 2ed98a5..710c79a 100644 --- a/tests/tendermint/test_fastquery.py +++ b/tests/tendermint/test_fastquery.py @@ -5,9 +5,9 @@ import pytest -from planetmint.transactions.common.transaction import TransactionLink -from planetmint.transactions.types.assets.create import Create -from planetmint.transactions.types.assets.transfer import Transfer +from transactions.common.transaction import TransactionLink +from transactions.types.assets.create import Create +from transactions.types.assets.transfer import Transfer pytestmark = pytest.mark.bdb diff --git a/tests/tendermint/test_integration.py b/tests/tendermint/test_integration.py index cc19d5f..77f2f2f 100644 --- a/tests/tendermint/test_integration.py +++ b/tests/tendermint/test_integration.py @@ -4,8 +4,8 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 import codecs -from planetmint.transactions.types.assets.create import Create -from planetmint.transactions.types.assets.transfer import Transfer +from transactions.types.assets.create import Create +from transactions.types.assets.transfer import Transfer from tendermint.abci import types_pb2 as types import json @@ -15,7 +15,7 @@ import pytest from abci.server import ProtocolHandler from abci.utils import read_messages -from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT, BROADCAST_TX_SYNC +from transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT, BROADCAST_TX_SYNC from planetmint.version import __tm_supported_versions__ from io import BytesIO @@ -24,7 +24,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.transactions.common.crypto import generate_key_pair + from transactions.common.crypto import generate_key_pair app = App(b, eventqueue_fixture) p = ProtocolHandler(app) @@ -111,7 +111,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 transactions.common.crypto import generate_key_pair alice = generate_key_pair() bob = generate_key_pair() diff --git a/tests/tendermint/test_lib.py b/tests/tendermint/test_lib.py index 79ca803..298f1ad 100644 --- a/tests/tendermint/test_lib.py +++ b/tests/tendermint/test_lib.py @@ -6,8 +6,8 @@ from operator import index import os from unittest.mock import patch -from planetmint.transactions.types.assets.create import Create -from planetmint.transactions.types.assets.transfer import Transfer +from transactions.types.assets.create import Create +from transactions.types.assets.transfer import Transfer from hashlib import sha3_256 @@ -15,7 +15,7 @@ import pytest from pymongo import MongoClient from planetmint import backend -from planetmint.transactions.common.transaction_mode_types import ( +from transactions.common.transaction_mode_types import ( BROADCAST_TX_COMMIT, BROADCAST_TX_ASYNC, BROADCAST_TX_SYNC, @@ -27,7 +27,7 @@ from ipld import marshal, multihash @pytest.mark.bdb def test_asset_is_separated_from_transaciton(b): import copy - from planetmint.transactions.common.crypto import generate_key_pair + from transactions.common.crypto import generate_key_pair from planetmint.backend.tarantool.connection import TarantoolDBConnection if isinstance(b.connection, TarantoolDBConnection): @@ -92,7 +92,7 @@ def test_get_empty_block(_0, _1, b): def test_validation_error(b): - from planetmint.transactions.common.crypto import generate_key_pair + from transactions.common.crypto import generate_key_pair alice = generate_key_pair() tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=None).sign([alice.private_key]).to_dict() @@ -103,7 +103,7 @@ def test_validation_error(b): @patch("requests.post") def test_write_and_post_transaction(mock_post, b): - from planetmint.transactions.common.crypto import generate_key_pair + from transactions.common.crypto import generate_key_pair from planetmint.tendermint_utils import encode_transaction alice = generate_key_pair() @@ -122,7 +122,7 @@ def test_write_and_post_transaction(mock_post, b): @patch("requests.post") @pytest.mark.parametrize("mode", [BROADCAST_TX_SYNC, BROADCAST_TX_ASYNC, BROADCAST_TX_COMMIT]) def test_post_transaction_valid_modes(mock_post, b, mode): - from planetmint.transactions.common.crypto import generate_key_pair + from transactions.common.crypto import generate_key_pair alice = generate_key_pair() tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=None).sign([alice.private_key]).to_dict() @@ -134,8 +134,8 @@ def test_post_transaction_valid_modes(mock_post, b, mode): def test_post_transaction_invalid_mode(b): - from planetmint.transactions.common.crypto import generate_key_pair - from planetmint.transactions.common.exceptions import ValidationError + from transactions.common.crypto import generate_key_pair + from transactions.common.exceptions import ValidationError alice = generate_key_pair() tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=None).sign([alice.private_key]).to_dict() @@ -405,7 +405,7 @@ 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.exceptions import CriticalDoubleSpend - from planetmint.transactions.common.exceptions import DoubleSpend + from transactions.common.exceptions import DoubleSpend asset = {"data": multihash(marshal({"test": "asset"}))} @@ -443,7 +443,7 @@ 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 transactions.common.crypto import generate_key_pair priv_key, pub_key = generate_key_pair() @@ -493,8 +493,8 @@ def test_migrate_abci_chain_generates_new_chains(b, chain, block_height, expecte @pytest.mark.bdb def test_get_spent_key_order(b, user_pk, user_sk, user2_pk, user2_sk): from planetmint import backend - from planetmint.transactions.common.crypto import generate_key_pair - from planetmint.transactions.common.exceptions import DoubleSpend + from transactions.common.crypto import generate_key_pair + from 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 dae9546..406e46c 100644 --- a/tests/test_config_utils.py +++ b/tests/test_config_utils.py @@ -289,7 +289,7 @@ def test_file_config(): def test_invalid_file_config(): from planetmint.config_utils import file_config - from planetmint.transactions.common import exceptions + from transactions.common import exceptions with patch("builtins.open", mock_open(read_data="{_INVALID_JSON_}")): with pytest.raises(exceptions.ConfigurationError): diff --git a/tests/test_core.py b/tests/test_core.py index 8a98390..6d43cc6 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -5,8 +5,8 @@ import pytest from planetmint.version import __tm_supported_versions__ -from planetmint.transactions.types.assets.create import Create -from planetmint.transactions.types.assets.transfer import Transfer +from transactions.types.assets.create import Create +from transactions.types.assets.transfer import Transfer @pytest.fixture diff --git a/tests/test_parallel_validation.py b/tests/test_parallel_validation.py index d6d9241..4c9f320 100644 --- a/tests/test_parallel_validation.py +++ b/tests/test_parallel_validation.py @@ -5,9 +5,9 @@ import pytest -from planetmint.transactions.common.crypto import generate_key_pair -from planetmint.transactions.types.assets.create import Create -from planetmint.transactions.types.assets.transfer import Transfer +from transactions.common.crypto import generate_key_pair +from transactions.types.assets.create import Create +from transactions.types.assets.transfer import Transfer pytestmark = pytest.mark.tendermint diff --git a/tests/test_txlist.py b/tests/test_txlist.py index d9e1474..ec273d1 100644 --- a/tests/test_txlist.py +++ b/tests/test_txlist.py @@ -12,8 +12,8 @@ import pytest @pytest.fixture def txlist(b, user_pk, user2_pk, user_sk, user2_sk): - from planetmint.transactions.types.assets.create import Create - from planetmint.transactions.types.assets.transfer import Transfer + from transactions.types.assets.create import Create + from transactions.types.assets.transfer import Transfer # Create two CREATE transactions create1 = Create.generate([user_pk], [([user2_pk], 6)]).sign([user_sk]) diff --git a/tests/upsert_validator/conftest.py b/tests/upsert_validator/conftest.py index 630ce10..9bfafa3 100644 --- a/tests/upsert_validator/conftest.py +++ b/tests/upsert_validator/conftest.py @@ -7,7 +7,7 @@ from unittest.mock import patch import pytest from planetmint.backend import query -from planetmint.transactions.types.elections.validator_election import ValidatorElection +from transactions.types.elections.validator_election import ValidatorElection @pytest.fixture @@ -17,7 +17,7 @@ def valid_upsert_validator_election_b(b, node_key, new_validator): @pytest.fixture -@patch("planetmint.transactions.types.elections.election.uuid4", lambda: "mock_uuid4") +@patch("transactions.types.elections.election.uuid4", lambda: "mock_uuid4") def fixed_seed_election(b_mock, node_key, new_validator): voters = b_mock.get_recipients_list() return ValidatorElection.generate([node_key.public_key], voters, new_validator, None).sign([node_key.private_key]) diff --git a/tests/upsert_validator/test_upsert_validator_vote.py b/tests/upsert_validator/test_upsert_validator_vote.py index 8ef62f7..16f15fe 100644 --- a/tests/upsert_validator/test_upsert_validator_vote.py +++ b/tests/upsert_validator/test_upsert_validator_vote.py @@ -6,15 +6,14 @@ import pytest import codecs -from planetmint.transactions.types.elections.election import Election from planetmint.tendermint_utils import public_key_to_base64 -from planetmint.transactions.types.elections.validator_election 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.transactions.types.elections.vote import Vote -from planetmint.transactions.types.elections.validator_utils import election_id_to_public_key +from transactions.types.elections.validator_election import ValidatorElection +from transactions.common.exceptions import AmountError +from transactions.common.crypto import generate_key_pair +from transactions.common.exceptions import ValidationError +from transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT +from transactions.types.elections.vote import Vote +from transactions.types.elections.validator_utils import election_id_to_public_key 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 6996f0c..6c9b39a 100644 --- a/tests/upsert_validator/test_validator_election.py +++ b/tests/upsert_validator/test_validator_election.py @@ -8,8 +8,8 @@ from unittest.mock import patch import pytest from planetmint.tendermint_utils import public_key_to_base64 -from planetmint.transactions.types.elections.validator_election import ValidatorElection -from planetmint.transactions.common.exceptions import ( +from transactions.types.elections.validator_election import ValidatorElection +from transactions.common.exceptions import ( DuplicateTransaction, UnequalValidatorSet, InvalidProposer, @@ -29,7 +29,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.transactions.common.exceptions import InvalidPublicKey + from 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.transactions.common.crypto import generate_key_pair + from transactions.common.crypto import generate_key_pair alice = generate_key_pair() voters = b_mock.get_recipients_list() @@ -61,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.transactions.common.crypto import generate_key_pair + from transactions.common.crypto import generate_key_pair alice = generate_key_pair() voters = b_mock.get_recipients_list() @@ -72,7 +72,7 @@ def test_upsert_validator_invalid_inputs_election(b_mock, new_validator, node_ke b_mock.validate_election(election) -@patch("planetmint.transactions.types.elections.election.uuid4", lambda: "mock_uuid4") +@patch("transactions.types.elections.election.uuid4", lambda: "mock_uuid4") def test_upsert_validator_invalid_election(b_mock, new_validator, node_key, fixed_seed_election): voters = b_mock.get_recipients_list() duplicate_election = ValidatorElection.generate([node_key.public_key], voters, new_validator, None).sign( diff --git a/tests/utils.py b/tests/utils.py index f330d75..5d2a47b 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -12,11 +12,11 @@ from functools import singledispatch from planetmint.backend.localmongodb.connection import LocalMongoDBConnection from planetmint.backend.tarantool.connection import TarantoolDBConnection from planetmint.backend.schema import TABLES, SPACE_NAMES -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.vote import Vote -from planetmint.transactions.types.elections.validator_utils import election_id_to_public_key +from transactions.common import crypto +from transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT +from transactions.types.assets.create import Create +from transactions.types.elections.vote import Vote +from transactions.types.elections.validator_utils import election_id_to_public_key from planetmint.tendermint_utils import key_to_base64 @@ -55,7 +55,7 @@ def flush_tarantool_db(connection, dbname): def generate_block(planet): - from planetmint.transactions.common.crypto import generate_key_pair + from transactions.common.crypto import generate_key_pair alice = generate_key_pair() tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=None).sign([alice.private_key]) diff --git a/tests/validation/test_transaction_structure.py b/tests/validation/test_transaction_structure.py index aa5df28..0efb4e4 100644 --- a/tests/validation/test_transaction_structure.py +++ b/tests/validation/test_transaction_structure.py @@ -14,9 +14,9 @@ import pytest import hashlib as sha3 from unittest.mock import MagicMock -from planetmint.transactions.common.exceptions import AmountError, SchemaValidationError, ThresholdTooDeep -from planetmint.transactions.common.transaction import Transaction -from planetmint.transactions.common.utils import _fulfillment_to_details, _fulfillment_from_details +from transactions.common.exceptions import AmountError, SchemaValidationError, ThresholdTooDeep +from transactions.common.transaction import Transaction +from transactions.common.utils import _fulfillment_to_details, _fulfillment_from_details from ipld import marshal, multihash ################################################################################ @@ -51,7 +51,7 @@ def test_tx_serialization_hash_function(signed_create_tx): def test_tx_serialization_with_incorrect_hash(signed_create_tx): - from planetmint.transactions.common.exceptions import InvalidHash + from transactions.common.exceptions import InvalidHash tx = signed_create_tx.to_dict() tx["id"] = "a" * 64 @@ -60,7 +60,7 @@ def test_tx_serialization_with_incorrect_hash(signed_create_tx): def test_tx_serialization_with_no_hash(signed_create_tx): - from planetmint.transactions.common.exceptions import InvalidHash + from transactions.common.exceptions import InvalidHash tx = signed_create_tx.to_dict() del tx["id"] @@ -105,7 +105,7 @@ def test_validate_fails_metadata_empty_dict(b, create_tx, alice): def test_transfer_asset_schema(user_sk, signed_transfer_tx): - from planetmint.transactions.common.transaction import Transaction + from transactions.common.transaction import Transaction tx = signed_transfer_tx.to_dict() validate(tx) @@ -152,7 +152,7 @@ def test_no_inputs(b, create_tx, alice): def test_create_single_input(b, create_tx, alice): - from planetmint.transactions.common.transaction import Transaction + from transactions.common.transaction import Transaction tx = create_tx.to_dict() tx["inputs"] += tx["inputs"] @@ -165,7 +165,7 @@ def test_create_single_input(b, create_tx, alice): def test_create_tx_no_fulfills(b, create_tx, alice): - from planetmint.transactions.common.transaction import Transaction + from transactions.common.transaction import Transaction tx = create_tx.to_dict() tx["inputs"][0]["fulfills"] = {"transaction_id": "a" * 64, "output_index": 0} diff --git a/tests/web/test_assets.py b/tests/web/test_assets.py index 3d9cf89..5e0760c 100644 --- a/tests/web/test_assets.py +++ b/tests/web/test_assets.py @@ -4,7 +4,7 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 import pytest -from planetmint.transactions.types.assets.create import Create +from transactions.types.assets.create import Create from ipld import marshal, multihash ASSETS_ENDPOINT = "/api/v1/assets/" diff --git a/tests/web/test_block_tendermint.py b/tests/web/test_block_tendermint.py index f0833a5..5919125 100644 --- a/tests/web/test_block_tendermint.py +++ b/tests/web/test_block_tendermint.py @@ -5,7 +5,7 @@ import pytest -from planetmint.transactions.types.assets.create import Create +from transactions.types.assets.create import Create from planetmint.lib import Block from ipld import marshal, multihash diff --git a/tests/web/test_metadata.py b/tests/web/test_metadata.py index 6ad9bf3..302b301 100644 --- a/tests/web/test_metadata.py +++ b/tests/web/test_metadata.py @@ -4,7 +4,7 @@ # Code is Apache-2.0 and docs are CC-BY-4.0 import pytest -from planetmint.transactions.types.assets.create import Create +from transactions.types.assets.create import Create from ipld import marshal, multihash METADATA_ENDPOINT = "/api/v1/metadata/" diff --git a/tests/web/test_outputs.py b/tests/web/test_outputs.py index a045851..29e6e18 100644 --- a/tests/web/test_outputs.py +++ b/tests/web/test_outputs.py @@ -5,8 +5,8 @@ import pytest -from planetmint.transactions.types.assets.create import Create -from planetmint.transactions.types.assets.transfer import Transfer +from transactions.types.assets.create import Create +from transactions.types.assets.transfer import Transfer from unittest.mock import MagicMock, patch @@ -83,7 +83,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.transactions.common import crypto + from 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 6ea6aad..6c2661e 100644 --- a/tests/web/test_transactions.py +++ b/tests/web/test_transactions.py @@ -13,10 +13,10 @@ from ipld import multihash, marshal from hashlib 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 ( +from transactions.common import crypto +from transactions.types.assets.create import Create +from transactions.types.assets.transfer import Transfer +from transactions.common.transaction_mode_types import ( BROADCAST_TX_COMMIT, BROADCAST_TX_ASYNC, BROADCAST_TX_SYNC, @@ -161,7 +161,7 @@ def test_post_create_transaction_with_invalid_key(b, client, field, value, err_k @pytest.mark.abci @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 transactions.common.exceptions import InvalidHash user_priv, user_pub = crypto.generate_key_pair() @@ -193,7 +193,7 @@ def test_post_create_transaction_with_invalid_id(mock_logger, b, client): @pytest.mark.abci @patch("planetmint.web.views.base.logger") def test_post_create_transaction_with_invalid_signature(mock_logger, b, client): - from planetmint.transactions.common.exceptions import InvalidSignature + from transactions.common.exceptions import InvalidSignature user_priv, user_pub = crypto.generate_key_pair() @@ -300,7 +300,7 @@ def test_post_invalid_transaction( msg, monkeypatch, ): - from planetmint.transactions.common import exceptions + from transactions.common import exceptions exc_cls = getattr(exceptions, exc) @@ -310,7 +310,7 @@ def test_post_invalid_transaction( TransactionMock = Mock(validate=mock_validation) monkeypatch.setattr( - "planetmint.transactions.common.transaction.Transaction.from_dict", + "transactions.common.transaction.Transaction.from_dict", lambda tx, skip_schema_validation: TransactionMock, ) res = client.post(TX_ENDPOINT, data=json.dumps({})) @@ -346,7 +346,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.transactions.common.exceptions import InvalidSignature + from transactions.common.exceptions import InvalidSignature transfer_tx = Transfer.generate(posted_create_tx.to_inputs(), [([user_pk], 1)], asset_id=posted_create_tx.id) transfer_tx._hash() @@ -362,7 +362,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.transactions.common.exceptions import AmountError + from transactions.common.exceptions import AmountError priv_key, pub_key = crypto.generate_key_pair() @@ -448,7 +448,7 @@ def test_transactions_get_list_bad(client): ], ) def test_post_transaction_valid_modes(mock_post, client, mode): - from planetmint.transactions.common.crypto import generate_key_pair + from transactions.common.crypto import generate_key_pair def _mock_post(*args, **kwargs): return Mock(json=Mock(return_value={"result": {"code": 0}})) @@ -465,7 +465,7 @@ def test_post_transaction_valid_modes(mock_post, client, mode): @pytest.mark.abci def test_post_transaction_invalid_mode(client): - from planetmint.transactions.common.crypto import generate_key_pair + from transactions.common.crypto import generate_key_pair alice = generate_key_pair() 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 557b14e..7e61231 100644 --- a/tests/web/test_websocket_server.py +++ b/tests/web/test_websocket_server.py @@ -9,8 +9,8 @@ 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 +from transactions.types.assets.create import Create +from transactions.types.assets.transfer import Transfer from ipld import multihash, marshal import pytest @@ -26,7 +26,7 @@ class MockWebSocket: def test_eventify_block_works_with_any_transaction(): from planetmint.web.websocket_dispatcher import Dispatcher - from planetmint.transactions.common.crypto import generate_key_pair + from transactions.common.crypto import generate_key_pair alice = generate_key_pair() @@ -48,7 +48,7 @@ def test_eventify_block_works_with_any_transaction(): def test_simplified_block_works(): from planetmint.web.websocket_dispatcher import Dispatcher - from planetmint.transactions.common.crypto import generate_key_pair + from transactions.common.crypto import generate_key_pair alice = generate_key_pair() @@ -138,7 +138,7 @@ async def test_bridge_sync_async_queue(event_loop): async def test_websocket_block_event(aiohttp_client, event_loop): from planetmint import events from planetmint.web.websocket_server import init_app, EVENTS_ENDPOINT_BLOCKS - from planetmint.transactions.common import crypto + from transactions.common import crypto user_priv, user_pub = crypto.generate_key_pair() tx = Create.generate([user_pub], [([user_pub], 1)]) @@ -172,7 +172,7 @@ async def test_websocket_block_event(aiohttp_client, event_loop): async def test_websocket_transaction_event(aiohttp_client, event_loop): from planetmint import events from planetmint.web.websocket_server import init_app, EVENTS_ENDPOINT - from planetmint.transactions.common import crypto + from transactions.common import crypto user_priv, user_pub = crypto.generate_key_pair() tx = Create.generate([user_pub], [([user_pub], 1)]) @@ -241,7 +241,7 @@ def test_integration_from_webapi_to_websocket(monkeypatch, client, loop): import random import aiohttp - from planetmint.transactions.common import crypto + from transactions.common import crypto # TODO processes does not exist anymore, when reactivating this test it # will fail because of this