diff --git a/bigchaindb/common/schema/transaction.yaml b/bigchaindb/common/schema/transaction.yaml index 72b51cf1..fbab5eb1 100644 --- a/bigchaindb/common/schema/transaction.yaml +++ b/bigchaindb/common/schema/transaction.yaml @@ -153,7 +153,9 @@ definitions: "$ref": "#/definitions/condition_details" uri: type: string - pattern: "^ni:///sha-256;([a-zA-Z0-9_-]{0,86})?(.+)$" + 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" description: | diff --git a/bigchaindb/common/transaction.py b/bigchaindb/common/transaction.py index a377b994..e4b8dc46 100644 --- a/bigchaindb/common/transaction.py +++ b/bigchaindb/common/transaction.py @@ -1,3 +1,7 @@ +"""Transaction related models to parse and construct transaction +payloads. + +""" from copy import deepcopy from functools import reduce diff --git a/setup.py b/setup.py index e2db673c..85c04b34 100644 --- a/setup.py +++ b/setup.py @@ -47,6 +47,8 @@ tests_require = [ 'pep8', 'flake8', 'flake8-quotes==0.8.1', + 'hypothesis', + 'hypothesis-regex', 'pylint', 'pytest>=3.0.0', 'pytest-catchlog>=1.2.2', diff --git a/tests/common/conftest.py b/tests/common/conftest.py index 8dfabf30..4c918a7b 100644 --- a/tests/common/conftest.py +++ b/tests/common/conftest.py @@ -175,3 +175,30 @@ def transfer_utx(user_output, user2_output, utx): @pytest.fixture def transfer_tx(transfer_utx, user_priv): return transfer_utx.sign([user_priv]) + + +@pytest.fixture +def dummy_transaction(): + return { + 'asset': {'data': None}, + 'id': 64 * 'a', + 'inputs': [{ + 'fulfillment': 'dummy', + 'fulfills': None, + 'owners_before': [58 * 'a'], + }], + 'metadata': None, + 'operation': 'CREATE', + 'outputs': [{ + 'amount': '1', + 'condition': { + 'details': { + 'public_key': 58 * 'b', + 'type': 'ed25519-sha-256' + }, + 'uri': 'dummy', + }, + 'public_keys': [58 * 'b'] + }], + 'version': '1.0' + } diff --git a/tests/common/test_schema.py b/tests/common/test_schema.py index 7f2ca397..e80ad0e2 100644 --- a/tests/common/test_schema.py +++ b/tests/common/test_schema.py @@ -3,14 +3,21 @@ This module is tests related to schema checking, but _not_ of granular schematic properties related to validation. """ -from pytest import raises from unittest.mock import patch +from hypothesis import given +from hypothesis_regex import regex +from pytest import raises + from bigchaindb.common.exceptions import SchemaValidationError from bigchaindb.common.schema import ( TX_SCHEMA_COMMON, VOTE_SCHEMA, drop_schema_descriptions, validate_transaction_schema, validate_vote_schema) +SUPPORTED_CRYPTOCONDITION_TYPES = ('threshold-sha-256', 'ed25519-sha-256') +UNSUPPORTED_CRYPTOCONDITION_TYPES = ( + 'preimage-sha-256', 'prefix-sha-256', 'rsa-sha-256') + ################################################################################ # Test of schema utils @@ -109,6 +116,63 @@ def test_validate_failure_inconsistent(): validate_transaction_schema({}) +@given(condition_uri=regex( + r'^ni:\/\/\/sha-256;([a-zA-Z0-9_-]{{0,86}})\?fpt=({})' + r'&cost=[0-9]+(?![\n])$'.format('|'.join( + t for t in SUPPORTED_CRYPTOCONDITION_TYPES)))) +def test_condition_uri_with_supported_fpt(dummy_transaction, condition_uri): + dummy_transaction['outputs'][0]['condition']['uri'] = condition_uri + validate_transaction_schema(dummy_transaction) + + +@given(condition_uri=regex(r'^ni:\/\/\/sha-256;([a-zA-Z0-9_-]{{0,86}})\?fpt=' + r'({})&cost=[0-9]+(?![\n])$'.format( + '|'.join(UNSUPPORTED_CRYPTOCONDITION_TYPES)))) +def test_condition_uri_with_unsupported_fpt(dummy_transaction, condition_uri): + dummy_transaction['outputs'][0]['condition']['uri'] = condition_uri + with raises(SchemaValidationError): + validate_transaction_schema(dummy_transaction) + + +@given(condition_uri=regex( + r'^ni:\/\/\/sha-256;([a-zA-Z0-9_-]{{0,86}})\?fpt=(?!{})' + r'&cost=[0-9]+(?![\n])$'.format('$|'.join( + t for t in SUPPORTED_CRYPTOCONDITION_TYPES)))) +def test_condition_uri_with_unknown_fpt(dummy_transaction, condition_uri): + dummy_transaction['outputs'][0]['condition']['uri'] = condition_uri + with raises(SchemaValidationError): + validate_transaction_schema(dummy_transaction) + + +@given(condition_uri=regex( + r'^ni:\/\/\/sha-256;([a-zA-Z0-9_-]{0,86})\?fpt=threshold-sha-256' + r'&cost=[0-9]+&subtypes=ed25519-sha-256(?![\n])$')) +def test_condition_uri_with_supported_subtype(dummy_transaction, + condition_uri): + dummy_transaction['outputs'][0]['condition']['uri'] = condition_uri + validate_transaction_schema(dummy_transaction) + + +@given(condition_uri=regex( + r'^ni:\/\/\/sha-256;([a-zA-Z0-9_-]{0,86})\?fpt=threshold-sha-256&cost=' + r'[0-9]+&subtypes=(preimage-sha-256|prefix-sha-256|rsa-sha-256)(?![\n])$')) +def test_condition_uri_with_unsupported_subtype(dummy_transaction, + condition_uri): + dummy_transaction['outputs'][0]['condition']['uri'] = condition_uri + with raises(SchemaValidationError): + validate_transaction_schema(dummy_transaction) + + +@given(condition_uri=regex( + r'^ni:\/\/\/sha-256;([a-zA-Z0-9_-]{{0,86}})\?fpt=threshold-sha-256' + r'&cost=[0-9]+&subtypes=(?!{})(?![\n])$'.format('$|'.join( + t for t in SUPPORTED_CRYPTOCONDITION_TYPES)))) +def test_condition_uri_with_unknown_subtype(dummy_transaction, condition_uri): + dummy_transaction['outputs'][0]['condition']['uri'] = condition_uri + with raises(SchemaValidationError): + validate_transaction_schema(dummy_transaction) + + ################################################################################ # Test call vote schema