From 294afa123f8d470dad2b0ac730cda4b36cecfee2 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Tue, 7 Mar 2017 10:56:26 +0100 Subject: [PATCH 01/11] rename validate_structure to validate_id --- bigchaindb/common/transaction.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bigchaindb/common/transaction.py b/bigchaindb/common/transaction.py index 9da2421a..02332c38 100644 --- a/bigchaindb/common/transaction.py +++ b/bigchaindb/common/transaction.py @@ -1009,7 +1009,7 @@ class Transaction(object): return asset_ids.pop() @staticmethod - def validate_structure(tx_body): + def validate_id(tx_body): """Validate the transaction ID of a transaction Args: @@ -1041,7 +1041,7 @@ class Transaction(object): Returns: :class:`~bigchaindb.common.transaction.Transaction` """ - cls.validate_structure(tx) + cls.validate_id(tx) 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, From cb6bd34744ae7c89e6ccef4c125d2d857577d10e Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Tue, 7 Mar 2017 12:58:32 +0100 Subject: [PATCH 02/11] test create tx does not have an asset id --- bigchaindb/common/schema/__init__.py | 6 ++++++ .../common/schema/transaction_create.yaml | 17 +++++++++++++++++ .../common/schema/transaction_transfer.yaml | 18 ++++++++++++++++++ bigchaindb/common/transaction.py | 3 ++- bigchaindb/models.py | 9 +++++---- tests/test_behaviours.py | 17 +++++++++++++++++ 6 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 bigchaindb/common/schema/transaction_create.yaml create mode 100644 bigchaindb/common/schema/transaction_transfer.yaml create mode 100644 tests/test_behaviours.py diff --git a/bigchaindb/common/schema/__init__.py b/bigchaindb/common/schema/__init__.py index 52c70c13..2c005ac5 100644 --- a/bigchaindb/common/schema/__init__.py +++ b/bigchaindb/common/schema/__init__.py @@ -29,6 +29,8 @@ def _load_schema(name): TX_SCHEMA_PATH, TX_SCHEMA = _load_schema('transaction') +_, TX_SCHEMA_CREATE = _load_schema('transaction_create') +_, TX_SCHEMA_TRANSFER = _load_schema('transaction_transfer') VOTE_SCHEMA_PATH, VOTE_SCHEMA = _load_schema('vote') @@ -43,6 +45,10 @@ def _validate_schema(schema, body): def validate_transaction_schema(tx): """ Validate a transaction dict """ _validate_schema(TX_SCHEMA, tx) + if tx['operation'] == 'TRANSFER': + _validate_schema(TX_SCHEMA_TRANSFER, tx) + else: + _validate_schema(TX_SCHEMA_CREATE, tx) def validate_vote_schema(vote): diff --git a/bigchaindb/common/schema/transaction_create.yaml b/bigchaindb/common/schema/transaction_create.yaml new file mode 100644 index 00000000..090d4680 --- /dev/null +++ b/bigchaindb/common/schema/transaction_create.yaml @@ -0,0 +1,17 @@ +--- +"$schema": "http://json-schema.org/draft-04/schema#" +type: object +title: Transaction Schema - CREATE/GENESIS specific properties +required: +- asset +properties: + asset: + additionalProperties: false + properties: + data: + description: | + User provided metadata associated with the asset. May also be ``null``. + anyOf: + - type: object + additionalProperties: true + - type: 'null' diff --git a/bigchaindb/common/schema/transaction_transfer.yaml b/bigchaindb/common/schema/transaction_transfer.yaml new file mode 100644 index 00000000..80abbf95 --- /dev/null +++ b/bigchaindb/common/schema/transaction_transfer.yaml @@ -0,0 +1,18 @@ +--- +"$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" + description: | + ID of the transaction that created the asset. +definitions: + sha3_hexdigest: + pattern: "[0-9a-f]{64}" + type: string diff --git a/bigchaindb/common/transaction.py b/bigchaindb/common/transaction.py index 02332c38..23b8f169 100644 --- a/bigchaindb/common/transaction.py +++ b/bigchaindb/common/transaction.py @@ -999,7 +999,8 @@ class Transaction(object): transactions = [transactions] # create a set of the transactions' asset ids - asset_ids = {tx.id if tx.operation == Transaction.CREATE else tx.asset['id'] + asset_ids = {tx.id if tx.operation == Transaction.CREATE + else tx.asset['id'] for tx in transactions} # check that all the transasctions have the same asset id diff --git a/bigchaindb/models.py b/bigchaindb/models.py index 4f7d31f2..5d4b6c9d 100644 --- a/bigchaindb/models.py +++ b/bigchaindb/models.py @@ -25,9 +25,6 @@ class Transaction(Transaction): Raises: ValidationError: If the transaction is invalid """ - if len(self.inputs) == 0: - raise ValidationError('Transaction contains no inputs') - input_conditions = [] inputs_defined = all([input_.fulfills for input_ in self.inputs]) @@ -117,8 +114,12 @@ class Transaction(Transaction): return self @classmethod - def from_dict(cls, tx_body): + def validate_structure(cls, tx_body): validate_transaction_schema(tx_body) + + @classmethod + def from_dict(cls, tx_body): + cls.validate_structure(tx_body) return super().from_dict(tx_body) diff --git a/tests/test_behaviours.py b/tests/test_behaviours.py new file mode 100644 index 00000000..72bb4f17 --- /dev/null +++ b/tests/test_behaviours.py @@ -0,0 +1,17 @@ +import pytest +from bigchaindb.common import exceptions as exc +from bigchaindb.models import Transaction + + +################################################################################ +# 1.1 - The asset ID of a CREATE transaction is the same as it's ID + + +def test_create_tx_no_asset_id(b): + tx = Transaction.create([b.me], [([b.me], 1)]) + # works + Transaction.validate_structure(tx.to_dict()) + # broken + tx.asset['id'] = 'b' * 64 + with pytest.raises(exc.SchemaValidationError): + Transaction.validate_structure(tx.to_dict()) From 31b3ad8f960b66d385fb7b8c3b6ad7258f57933c Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Tue, 7 Mar 2017 12:58:48 +0100 Subject: [PATCH 03/11] fix bad quotes in test_outputs --- tests/web/test_outputs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/web/test_outputs.py b/tests/web/test_outputs.py index b8f18d68..b5a02f76 100644 --- a/tests/web/test_outputs.py +++ b/tests/web/test_outputs.py @@ -100,7 +100,7 @@ def test_get_divisble_transactions_returns_500(b, client): asset_id = create_tx.id - url = TX_ENDPOINT + "?asset_id=" + asset_id + url = TX_ENDPOINT + '?asset_id=' + asset_id assert client.get(url).status_code == 200 assert len(client.get(url).json) == 3 From 8077956b95bd2c4772b914daf8c365d4ec018bb6 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Tue, 7 Mar 2017 15:59:23 +0100 Subject: [PATCH 04/11] test serialization hash function --- tests/common/test_transaction.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/common/test_transaction.py b/tests/common/test_transaction.py index a2782583..bc04f36a 100644 --- a/tests/common/test_transaction.py +++ b/tests/common/test_transaction.py @@ -352,6 +352,17 @@ def test_tx_serialization_with_incorrect_hash(utx): utx_dict.pop('id') +def test_tx_serialization_hash_function(tx): + import sha3 + import json + tx_dict = tx.to_dict() + tx_dict['inputs'][0]['fulfillment'] = None + del tx_dict['id'] + payload = json.dumps(tx_dict, skipkeys=False, sort_keys=True, + separators=(',', ':')) + assert sha3.sha3_256(payload.encode()).hexdigest() == tx.id + + def test_invalid_input_initialization(user_input, user_pub): from bigchaindb.common.transaction import Input From 5b2d22efd43e61c06be8f2a03f725727e6406f07 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Tue, 7 Mar 2017 16:36:25 +0100 Subject: [PATCH 05/11] test asset schema --- tests/common/schema/test_transaction_schema.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/common/schema/test_transaction_schema.py b/tests/common/schema/test_transaction_schema.py index c9545ab3..b6cf294a 100644 --- a/tests/common/schema/test_transaction_schema.py +++ b/tests/common/schema/test_transaction_schema.py @@ -29,3 +29,17 @@ def test_validate_fails_metadata_empty_dict(create_tx): create_tx.metadata = {} with raises(SchemaValidationError): validate_transaction_schema(create_tx.to_dict()) + + +def test_transfer_asset_schema(signed_transfer_tx): + from bigchaindb.common.schema import (SchemaValidationError, + validate_transaction_schema) + tx = signed_transfer_tx.to_dict() + validate_transaction_schema(tx) + tx['asset']['data'] = {} + with raises(SchemaValidationError): + validate_transaction_schema(tx) + del tx['asset']['data'] + tx['asset']['id'] = 'b' * 63 + with raises(SchemaValidationError): + validate_transaction_schema(tx) From dbf24a6065503c1c2c722a48d882fb8f9034b59b Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Tue, 7 Mar 2017 17:12:12 +0100 Subject: [PATCH 06/11] schema validates that create txes only have 1 input and that it has no fulfills --- .../common/schema/transaction_create.yaml | 17 ++++++++++++++--- .../common/schema/test_transaction_schema.py | 19 +++++++++++++++++-- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/bigchaindb/common/schema/transaction_create.yaml b/bigchaindb/common/schema/transaction_create.yaml index 090d4680..2383a102 100644 --- a/bigchaindb/common/schema/transaction_create.yaml +++ b/bigchaindb/common/schema/transaction_create.yaml @@ -1,17 +1,28 @@ --- "$schema": "http://json-schema.org/draft-04/schema#" type: object -title: Transaction Schema - CREATE/GENESIS specific properties +title: Transaction Schema - CREATE/GENESIS specific constraints required: - asset +- inputs properties: asset: additionalProperties: false properties: data: - description: | - User provided metadata associated with the asset. May also be ``null``. anyOf: - type: object additionalProperties: true - type: 'null' + inputs: + type: array + title: "Transaction inputs" + maxItems: 1 + minItems: 1 + items: + type: "object" + required: + - fulfills + properties: + fulfills: + type: "null" diff --git a/tests/common/schema/test_transaction_schema.py b/tests/common/schema/test_transaction_schema.py index b6cf294a..dca10e70 100644 --- a/tests/common/schema/test_transaction_schema.py +++ b/tests/common/schema/test_transaction_schema.py @@ -32,8 +32,6 @@ def test_validate_fails_metadata_empty_dict(create_tx): def test_transfer_asset_schema(signed_transfer_tx): - from bigchaindb.common.schema import (SchemaValidationError, - validate_transaction_schema) tx = signed_transfer_tx.to_dict() validate_transaction_schema(tx) tx['asset']['data'] = {} @@ -43,3 +41,20 @@ def test_transfer_asset_schema(signed_transfer_tx): tx['asset']['id'] = 'b' * 63 with raises(SchemaValidationError): validate_transaction_schema(tx) + + +def test_create_single_input(create_tx): + tx = create_tx.to_dict() + tx['inputs'] += tx['inputs'] + with raises(SchemaValidationError): + validate_transaction_schema(tx) + tx['inputs'] = [] + with raises(SchemaValidationError): + validate_transaction_schema(tx) + + +def test_create_tx_no_fulfills(create_tx): + tx = create_tx.to_dict() + tx['inputs'][0]['fulfills'] = {'tx': 'a' * 64, 'output': 0} + with raises(SchemaValidationError): + validate_transaction_schema(tx) From e8ee2ec0a64ce600d157f145f0f6c0417982fc1c Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Wed, 8 Mar 2017 12:52:46 +0100 Subject: [PATCH 07/11] fix tests --- tests/common/test_transaction.py | 44 +++++--------------------------- 1 file changed, 6 insertions(+), 38 deletions(-) diff --git a/tests/common/test_transaction.py b/tests/common/test_transaction.py index bc04f36a..b9d64add 100644 --- a/tests/common/test_transaction.py +++ b/tests/common/test_transaction.py @@ -456,12 +456,15 @@ def test_transaction_link_eq(): def test_add_input_to_tx(user_input, asset_definition): from bigchaindb.common.transaction import Transaction + from .utils import validate_transaction_model tx = Transaction(Transaction.CREATE, asset_definition, [], []) tx.add_input(user_input) assert len(tx.inputs) == 1 + validate_transaction_model(tx) + def test_add_input_to_tx_with_invalid_parameters(asset_definition): from bigchaindb.common.transaction import Transaction @@ -471,11 +474,11 @@ def test_add_input_to_tx_with_invalid_parameters(asset_definition): tx.add_input('somewronginput') -def test_add_output_to_tx(user_output, asset_definition): +def test_add_output_to_tx(user_output, user_input, asset_definition): from bigchaindb.common.transaction import Transaction from .utils import validate_transaction_model - tx = Transaction(Transaction.CREATE, asset_definition) + tx = Transaction(Transaction.CREATE, asset_definition, [user_input]) tx.add_output(user_output) assert len(tx.outputs) == 1 @@ -557,40 +560,6 @@ def test_validate_input_with_invalid_parameters(utx): assert not valid -def test_validate_multiple_inputs(user_input, user_output, user_priv, - asset_definition): - from copy import deepcopy - - from bigchaindb.common.crypto import PrivateKey - from bigchaindb.common.transaction import Transaction - from .utils import validate_transaction_model - - tx = Transaction(Transaction.CREATE, asset_definition, - [user_input, deepcopy(user_input)], - [user_output, deepcopy(user_output)]) - - expected_first = deepcopy(tx) - expected_second = deepcopy(tx) - expected_first.inputs = [expected_first.inputs[0]] - expected_second.inputs = [expected_second.inputs[1]] - - expected_first_bytes = str(expected_first).encode() - expected_first.inputs[0].fulfillment.sign(expected_first_bytes, - PrivateKey(user_priv)) - expected_second_bytes = str(expected_second).encode() - expected_second.inputs[0].fulfillment.sign(expected_second_bytes, - PrivateKey(user_priv)) - tx.sign([user_priv]) - - assert tx.inputs[0].to_dict()['fulfillment'] == \ - expected_first.inputs[0].fulfillment.serialize_uri() - assert tx.inputs[1].to_dict()['fulfillment'] == \ - expected_second.inputs[0].fulfillment.serialize_uri() - assert tx.inputs_valid() is True - - validate_transaction_model(tx) - - def test_validate_tx_threshold_create_signature(user_user2_threshold_input, user_user2_threshold_output, user_pub, @@ -632,8 +601,7 @@ def test_multiple_input_validation_of_transfer_tx(user_input, user_output, from cryptoconditions import Ed25519Fulfillment from .utils import validate_transaction_model - tx = Transaction(Transaction.CREATE, asset_definition, - [user_input, deepcopy(user_input)], + tx = Transaction(Transaction.CREATE, asset_definition, [user_input], [user_output, deepcopy(user_output)]) tx.sign([user_priv]) From 4050389df7a1396f9e385afee257a26ecfb8fdcd Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Mon, 13 Mar 2017 14:01:29 +0100 Subject: [PATCH 08/11] move test_create_tx_no_asset_id --- tests/common/test_transaction.py | 12 ++++++++++++ tests/test_behaviours.py | 17 ----------------- 2 files changed, 12 insertions(+), 17 deletions(-) delete mode 100644 tests/test_behaviours.py diff --git a/tests/common/test_transaction.py b/tests/common/test_transaction.py index b9d64add..e24519c9 100644 --- a/tests/common/test_transaction.py +++ b/tests/common/test_transaction.py @@ -964,3 +964,15 @@ def test_validate_version(utx): utx.version = '1.0.0' with raises(SchemaValidationError): validate_transaction_model(utx) + + +def test_create_tx_no_asset_id(b): + from bigchaindb.common.exceptions import SchemaValidationError + from bigchaindb.models import Transaction + tx = Transaction.create([b.me], [([b.me], 1)]) + # works + Transaction.validate_structure(tx.to_dict()) + # broken + tx.asset['id'] = 'b' * 64 + with raises(SchemaValidationError): + Transaction.validate_structure(tx.to_dict()) diff --git a/tests/test_behaviours.py b/tests/test_behaviours.py deleted file mode 100644 index 72bb4f17..00000000 --- a/tests/test_behaviours.py +++ /dev/null @@ -1,17 +0,0 @@ -import pytest -from bigchaindb.common import exceptions as exc -from bigchaindb.models import Transaction - - -################################################################################ -# 1.1 - The asset ID of a CREATE transaction is the same as it's ID - - -def test_create_tx_no_asset_id(b): - tx = Transaction.create([b.me], [([b.me], 1)]) - # works - Transaction.validate_structure(tx.to_dict()) - # broken - tx.asset['id'] = 'b' * 64 - with pytest.raises(exc.SchemaValidationError): - Transaction.validate_structure(tx.to_dict()) From b997057962b1209f3e69cab8dfa19bcfdff5a9b4 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Mon, 13 Mar 2017 14:25:36 +0100 Subject: [PATCH 09/11] fix tests --- bigchaindb/models.py | 6 +----- tests/common/test_transaction.py | 12 ++++-------- tests/test_models.py | 17 ----------------- 3 files changed, 5 insertions(+), 30 deletions(-) diff --git a/bigchaindb/models.py b/bigchaindb/models.py index 5d4b6c9d..a46f2b73 100644 --- a/bigchaindb/models.py +++ b/bigchaindb/models.py @@ -113,13 +113,9 @@ class Transaction(Transaction): return self - @classmethod - def validate_structure(cls, tx_body): - validate_transaction_schema(tx_body) - @classmethod def from_dict(cls, tx_body): - cls.validate_structure(tx_body) + validate_transaction_schema(tx_body) return super().from_dict(tx_body) diff --git a/tests/common/test_transaction.py b/tests/common/test_transaction.py index e24519c9..5b06f801 100644 --- a/tests/common/test_transaction.py +++ b/tests/common/test_transaction.py @@ -966,13 +966,9 @@ def test_validate_version(utx): validate_transaction_model(utx) -def test_create_tx_no_asset_id(b): +def test_create_tx_no_asset_id(b, utx): from bigchaindb.common.exceptions import SchemaValidationError - from bigchaindb.models import Transaction - tx = Transaction.create([b.me], [([b.me], 1)]) - # works - Transaction.validate_structure(tx.to_dict()) - # broken - tx.asset['id'] = 'b' * 64 + from .utils import validate_transaction_model + utx.asset['id'] = 'b' * 64 with raises(SchemaValidationError): - Transaction.validate_structure(tx.to_dict()) + validate_transaction_model(utx) diff --git a/tests/test_models.py b/tests/test_models.py index 54d407f8..982ba2ba 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,21 +1,4 @@ from pytest import raises -from bigchaindb.common.exceptions import ValidationError - - -class TestTransactionModel(object): - def test_validating_an_invalid_transaction(self, b): - from bigchaindb.models import Transaction - - tx = Transaction.create([b.me], [([b.me], 1)]) - tx.operation = 'something invalid' - - with raises(ValidationError): - tx.validate(b) - - tx.operation = 'CREATE' - tx.inputs = [] - with raises(ValidationError): - tx.validate(b) class TestBlockModel(object): From 7c461e47d7c6fb77ac3f70eb307fa979d111c083 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Tue, 14 Mar 2017 12:39:57 +0100 Subject: [PATCH 10/11] remove structural and schematic validations from Transaction.validate which is validating the spend --- .../common/schema/transaction_transfer.yaml | 11 +++++ bigchaindb/models.py | 40 ++----------------- tests/assets/test_digital_assets.py | 8 ++-- tests/assets/test_divisible_assets.py | 3 ++ tests/common/test_transaction.py | 9 +++++ tests/db/test_bigchain_api.py | 27 ------------- 6 files changed, 30 insertions(+), 68 deletions(-) diff --git a/bigchaindb/common/schema/transaction_transfer.yaml b/bigchaindb/common/schema/transaction_transfer.yaml index 80abbf95..09a5aa1b 100644 --- a/bigchaindb/common/schema/transaction_transfer.yaml +++ b/bigchaindb/common/schema/transaction_transfer.yaml @@ -12,6 +12,17 @@ properties: "$ref": "#/definitions/sha3_hexdigest" description: | ID of the transaction that created the 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}" diff --git a/bigchaindb/models.py b/bigchaindb/models.py index a46f2b73..43313a2b 100644 --- a/bigchaindb/models.py +++ b/bigchaindb/models.py @@ -3,7 +3,7 @@ from bigchaindb.common.exceptions import (InvalidHash, InvalidSignature, DoubleSpend, InputDoesNotExist, TransactionNotInValidBlock, AssetIdMismatch, AmountError, - SybilError, ValidationError, + SybilError, DuplicateTransaction) from bigchaindb.common.transaction import Transaction from bigchaindb.common.utils import gen_timestamp, serialize @@ -12,7 +12,7 @@ from bigchaindb.common.schema import validate_transaction_schema class Transaction(Transaction): def validate(self, bigchain): - """Validate a transaction. + """Validate transaction spend Args: bigchain (Bigchain): an instantiated bigchaindb.Bigchain object. @@ -26,30 +26,8 @@ class Transaction(Transaction): ValidationError: If the transaction is invalid """ input_conditions = [] - inputs_defined = all([input_.fulfills for input_ in self.inputs]) - - # validate amounts - if any(output.amount < 1 for output in self.outputs): - raise AmountError('`amount` needs to be greater than zero') - - if self.operation in (Transaction.CREATE, Transaction.GENESIS): - # validate asset - if self.asset['data'] is not None and not isinstance(self.asset['data'], dict): - raise ValidationError(('`asset.data` must be a dict instance or ' - 'None for `CREATE` transactions')) - # validate inputs - if inputs_defined: - raise ValidationError('A CREATE operation has no inputs') - elif self.operation == Transaction.TRANSFER: - # validate asset - if not isinstance(self.asset['id'], str): - raise ValidationError('`asset.id` must be a string for ' - '`TRANSFER` transations') - # check inputs - if not inputs_defined: - raise ValidationError('Only `CREATE` transactions can have ' - 'null inputs') + if self.operation == Transaction.TRANSFER: # store the inputs so that we can check if the asset ids match input_txs = [] for input_ in self.inputs: @@ -74,8 +52,6 @@ class Transaction(Transaction): output = input_tx.outputs[input_.fulfills.output] input_conditions.append(output) input_txs.append(input_tx) - if output.amount < 1: - raise AmountError('`amount` needs to be greater than zero') # Validate that all inputs are distinct links = [i.fulfills.to_uri() for i in self.inputs] @@ -89,11 +65,6 @@ class Transaction(Transaction): ' match the asset id of the' ' transaction')) - # validate the amounts - for output in self.outputs: - if output.amount < 1: - raise AmountError('`amount` needs to be greater than zero') - input_amount = sum([input_condition.amount for input_condition in input_conditions]) output_amount = sum([output_condition.amount for output_condition in self.outputs]) @@ -103,11 +74,6 @@ class Transaction(Transaction): ' in the outputs `{}`') .format(input_amount, output_amount)) - else: - allowed_operations = ', '.join(Transaction.ALLOWED_OPERATIONS) - raise ValidationError('`operation`: `{}` must be either {}.' - .format(self.operation, allowed_operations)) - if not self.inputs_valid(input_conditions): raise InvalidSignature('Transaction signature is invalid.') diff --git a/tests/assets/test_digital_assets.py b/tests/assets/test_digital_assets.py index d44bc52c..c31ec3da 100644 --- a/tests/assets/test_digital_assets.py +++ b/tests/assets/test_digital_assets.py @@ -28,7 +28,7 @@ def test_validate_bad_asset_creation(b, user_pk): tx_signed = tx.sign([b.me_private]) with pytest.raises(ValidationError): - b.validate_transaction(tx_signed) + Transaction.from_dict(tx_signed.to_dict()) @pytest.mark.bdb @@ -93,15 +93,15 @@ def test_asset_id_mismatch(b, user_pk): def test_create_invalid_divisible_asset(b, user_pk, user_sk): from bigchaindb.models import Transaction - from bigchaindb.common.exceptions import AmountError + from bigchaindb.common.exceptions import ValidationError # Asset amount must be more than 0 tx = Transaction.create([user_pk], [([user_pk], 1)]) tx.outputs[0].amount = 0 tx.sign([user_sk]) - with pytest.raises(AmountError): - b.validate_transaction(tx) + with pytest.raises(ValidationError): + Transaction.from_dict(tx.to_dict()) def test_create_valid_divisible_asset(b, user_pk, user_sk): diff --git a/tests/assets/test_divisible_assets.py b/tests/assets/test_divisible_assets.py index 31e7890f..87a29c2b 100644 --- a/tests/assets/test_divisible_assets.py +++ b/tests/assets/test_divisible_assets.py @@ -638,6 +638,7 @@ def test_divide(b, user_pk, user_sk): # Check that negative inputs are caught when creating a TRANSFER transaction +@pytest.mark.skip(reason='part of tx structural tests') @pytest.mark.bdb @pytest.mark.usefixtures('inputs') def test_non_positive_amounts_on_transfer(b, user_pk): @@ -662,6 +663,7 @@ def test_non_positive_amounts_on_transfer(b, user_pk): # Check that negative inputs are caught when validating a TRANSFER transaction +@pytest.mark.skip(reason='part of tx structural tests') @pytest.mark.bdb @pytest.mark.usefixtures('inputs') def test_non_positive_amounts_on_transfer_validate(b, user_pk, user_sk): @@ -704,6 +706,7 @@ def test_non_positive_amounts_on_create(b, user_pk): # Check that negative inputs are caught when validating a CREATE transaction +@pytest.mark.skip(reason='part of tx structural tests') @pytest.mark.bdb @pytest.mark.usefixtures('inputs') def test_non_positive_amounts_on_create_validate(b, user_pk): diff --git a/tests/common/test_transaction.py b/tests/common/test_transaction.py index 5b06f801..45cadc3b 100644 --- a/tests/common/test_transaction.py +++ b/tests/common/test_transaction.py @@ -972,3 +972,12 @@ def test_create_tx_no_asset_id(b, utx): utx.asset['id'] = 'b' * 64 with raises(SchemaValidationError): validate_transaction_model(utx) + + +def test_transfer_tx_asset_schema(transfer_utx): + from bigchaindb.common.exceptions import SchemaValidationError + from .utils import validate_transaction_model + tx = transfer_utx + tx.asset['data'] = {} + with raises(SchemaValidationError): + validate_transaction_model(tx) diff --git a/tests/db/test_bigchain_api.py b/tests/db/test_bigchain_api.py index c39a104f..f1062777 100644 --- a/tests/db/test_bigchain_api.py +++ b/tests/db/test_bigchain_api.py @@ -3,8 +3,6 @@ from time import sleep import pytest from unittest.mock import patch -from bigchaindb.common.exceptions import ValidationError - pytestmark = pytest.mark.bdb @@ -596,24 +594,6 @@ class TestBigchainApi(object): class TestTransactionValidation(object): - def test_create_operation_with_inputs(self, b, user_pk, create_tx): - from bigchaindb.common.transaction import TransactionLink - - # Manipulate input so that it has a `fulfills` defined even - # though it shouldn't have one - create_tx.inputs[0].fulfills = TransactionLink('abc', 0) - with pytest.raises(ValidationError) as excinfo: - b.validate_transaction(create_tx) - assert excinfo.value.args[0] == 'A CREATE operation has no inputs' - - def test_transfer_operation_no_inputs(self, b, user_pk, - signed_transfer_tx): - signed_transfer_tx.inputs[0].fulfills = None - with pytest.raises(ValidationError) as excinfo: - b.validate_transaction(signed_transfer_tx) - - assert excinfo.value.args[0] == 'Only `CREATE` transactions can have null inputs' - def test_non_create_input_not_found(self, b, user_pk, signed_transfer_tx): from bigchaindb.common.exceptions import InputDoesNotExist from bigchaindb.common.transaction import TransactionLink @@ -1313,10 +1293,3 @@ def test_is_new_transaction(b, genesis_block): # Tx is new because it's only found in an invalid block assert b.is_new_transaction(tx.id) assert b.is_new_transaction(tx.id, exclude_block_id=block.id) - - -def test_validate_asset_id_string(signed_transfer_tx): - from bigchaindb.common.exceptions import ValidationError - signed_transfer_tx.asset['id'] = 1 - with pytest.raises(ValidationError): - signed_transfer_tx.validate(None) From f51b40b6dcc61ab37a1525453cc5376b8a4eea12 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Tue, 14 Mar 2017 17:07:18 +0100 Subject: [PATCH 11/11] some documentation and nomenclature fixes in common.schema --- bigchaindb/common/schema/__init__.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/bigchaindb/common/schema/__init__.py b/bigchaindb/common/schema/__init__.py index 2c005ac5..a69793ad 100644 --- a/bigchaindb/common/schema/__init__.py +++ b/bigchaindb/common/schema/__init__.py @@ -28,7 +28,7 @@ def _load_schema(name): return path, schema -TX_SCHEMA_PATH, TX_SCHEMA = _load_schema('transaction') +TX_SCHEMA_PATH, TX_SCHEMA_COMMON = _load_schema('transaction') _, TX_SCHEMA_CREATE = _load_schema('transaction_create') _, TX_SCHEMA_TRANSFER = _load_schema('transaction_transfer') VOTE_SCHEMA_PATH, VOTE_SCHEMA = _load_schema('vote') @@ -43,8 +43,13 @@ def _validate_schema(schema, body): def validate_transaction_schema(tx): - """ Validate a transaction dict """ - _validate_schema(TX_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: