From d27b81098c01fe3f5c39f095363e8cbc1c245c15 Mon Sep 17 00:00:00 2001 From: Richard Davison Date: Tue, 29 Nov 2022 04:22:21 -0500 Subject: [PATCH 1/3] Tezt: add Base.rexf --- tezt/lib_core/base.ml | 2 ++ tezt/lib_core/base.mli | 3 +++ 2 files changed, 5 insertions(+) diff --git a/tezt/lib_core/base.ml b/tezt/lib_core/base.ml index f770053c1358..99599f24bb1f 100644 --- a/tezt/lib_core/base.ml +++ b/tezt/lib_core/base.ml @@ -103,6 +103,8 @@ let span pred = let rex ?opts r = (r, Re.compile (Re.Perl.re ?opts r)) +let rexf ?opts fmt = Printf.ksprintf (rex ?opts) fmt + let show_rex = fst let ( =~ ) s (_, r) = Re.execp r s diff --git a/tezt/lib_core/base.mli b/tezt/lib_core/base.mli index c45c782ed08e..f3928d93190a 100644 --- a/tezt/lib_core/base.mli +++ b/tezt/lib_core/base.mli @@ -102,6 +102,9 @@ type rex (** Compile a regular expression using Perl syntax. *) val rex : ?opts:Re.Perl.opt list -> string -> rex +(** [rexf ...] is [rex @@ sf ...] *) +val rexf : ?opts:Re.Perl.opt list -> ('a, unit, string, rex) format4 -> 'a + (** Convert a regular expression to a string using Perl syntax. *) val show_rex : rex -> string -- GitLab From ff27863e1f9948c4b32386b1ea90853969c5e02e Mon Sep 17 00:00:00 2001 From: Richard Davison Date: Tue, 29 Nov 2022 04:42:42 -0500 Subject: [PATCH 2/3] Tezt: add [Scripts_illtyped] --- tests_python/tests_014/test_contract.py | 236 +--------------------- tests_python/tests_015/test_contract.py | 236 +--------------------- tests_python/tests_alpha/test_contract.py | 236 +--------------------- tezt/tests/main.ml | 1 + tezt/tests/script_illtyped.ml | 204 +++++++++++++++++++ 5 files changed, 208 insertions(+), 705 deletions(-) create mode 100644 tezt/tests/script_illtyped.ml diff --git a/tests_python/tests_014/test_contract.py b/tests_python/tests_014/test_contract.py index ce056354b26c..ee242658dbeb 100644 --- a/tests_python/tests_014/test_contract.py +++ b/tests_python/tests_014/test_contract.py @@ -5,11 +5,7 @@ from client.client import Client from tools import utils from tools.constants import IDENTITIES from tools.utils import originate -from .contract_paths import ( - CONTRACT_PATH, - ILLTYPED_CONTRACT_PATH, - all_legacy_contracts, -) +from .contract_paths import CONTRACT_PATH ID_SCRIPT_LITERAL = ''' @@ -266,236 +262,6 @@ class TestManager: utils.bake(client, bake_for='bootstrap5') -@pytest.mark.slow -@pytest.mark.contract -class TestContracts: - """Test type checking errors""" - - @pytest.mark.parametrize("contract", all_legacy_contracts()) - def test_deprecated_typecheck_breaks(self, client, contract): - if contract in [ - "legacy/create_contract.tz", - "legacy/create_contract_flags.tz", - "legacy/create_contract_rootname.tz", - ]: - with utils.assert_run_failure(r'ill-typed script'): - client.typecheck(os.path.join(CONTRACT_PATH, contract)) - else: - with utils.assert_run_failure(r'Use of deprecated instruction'): - client.typecheck(os.path.join(CONTRACT_PATH, contract)) - - @pytest.mark.parametrize("contract", all_legacy_contracts()) - def test_deprecated_typecheck_in_legacy(self, client, contract): - if contract in [ - "legacy/create_contract.tz", - "legacy/create_contract_flags.tz", - "legacy/create_contract_rootname.tz", - ]: - with utils.assert_run_failure(r'ill-typed script'): - client.typecheck( - os.path.join(CONTRACT_PATH, contract), legacy=True - ) - else: - with utils.assert_run_failure(r'Use of deprecated instruction'): - client.typecheck( - os.path.join(CONTRACT_PATH, contract), legacy=True - ) - - @pytest.mark.parametrize( - "contract,error_pattern", - [ - # Even though the interpreter uses a nonempty stack internally, - # the typechecker should not be able to observe it. - ( - "stack_bottom_unfailwithable.tz", - r'wrong stack type for instruction FAILWITH', - ), - ( - "stack_bottom_unrightable.tz", - r'wrong stack type for instruction RIGHT', - ), - ( - "stack_bottom_unleftable.tz", - r'wrong stack type for instruction LEFT', - ), - ( - "stack_bottom_ungetable.tz", - r'wrong stack type for instruction GET', - ), - ( - "stack_bottom_unpairable.tz", - r'wrong stack type for instruction UNPAIR', - ), - ( - "stack_bottom_undug2able.tz", - r'wrong stack type for instruction DUG', - ), - ( - "stack_bottom_undugable.tz", - r'wrong stack type for instruction DUG', - ), - ( - "stack_bottom_undig2able.tz", - r'wrong stack type for instruction DIG', - ), - ( - "stack_bottom_undigable.tz", - r'wrong stack type for instruction DIG', - ), - ( - "stack_bottom_undip2able.tz", - r'wrong stack type for instruction DUP', - ), - ( - "stack_bottom_undipable.tz", - r'wrong stack type for instruction DUP', - ), - ( - "stack_bottom_undup2able.tz", - r'wrong stack type for instruction DUP', - ), - ( - "stack_bottom_undropable.tz", - r'wrong stack type for instruction DROP', - ), - ( - "stack_bottom_unpopable.tz", - r'wrong stack type for instruction DUP', - ), - ( - "stack_bottom_unpopable_in_lambda.tz", - r'wrong stack type for instruction DUP', - ), - # operations cannot be PACKed - ( - "pack_operation.tz", - r'operation type forbidden in parameter, storage and constants', - ), - # big_maps cannot be PACKed - ( - "pack_big_map.tz", - r'big_map or sapling_state type not expected here', - ), - ( - "invalid_self_entrypoint.tz", - r'Contract has no entrypoint named D', - ), - ( - "contract_annotation_default.tz", - r'unexpected_default_entrypoint', - ), - # Missing field - ( - "missing_only_storage_field.tz", - r'Missing contract field: storage', - ), - ("missing_only_code_field.tz", r'Missing contract field: code'), - ( - "missing_only_parameter_field.tz", - r'Missing contract field: parameter', - ), - ( - "missing_parameter_and_storage_fields.tz", - r'Missing contract field: parameter', - ), - # Duplicated field - ( - "multiple_parameter_field.tz", - r'duplicate contract field: parameter', - ), - ("multiple_code_field.tz", r'duplicate contract field: code'), - ("multiple_storage_field.tz", r'duplicate contract field: storage'), - # The first duplicated field is reported, storage in this case - ( - "multiple_storage_and_code_fields.tz", - r'duplicate contract field: storage', - ), - # error message for set update on non-comparable type - ( - "set_update_non_comparable.tz", - r'Type nat\s+is not compatible with type list operation', - ), - # error message for the arity of the chain_id type - ( - "chain_id_arity.tz", - r'primitive chain_id expects 0 arguments but is given 1', - ), - # error message for DIP over the limit - ("big_dip.tz", r'expected a positive 10-bit integer'), - # error message for DROP over the limit - ("big_drop.tz", r'expected a positive 10-bit integer'), - # error message for attempting to push a value of type never - ("never_literal.tz", r'type never has no inhabitant.'), - # COMB, UNCOMB, and DUP cannot take 0 as argument - ("comb0.tz", r"PAIR expects an argument of at least 2"), - ("comb1.tz", r"PAIR expects an argument of at least 2"), - ("uncomb0.tz", r"UNPAIR expects an argument of at least 2"), - ("uncomb1.tz", r"UNPAIR expects an argument of at least 2"), - ("dup0.tz", r"DUP n expects an argument of at least 1"), - ( - "push_big_map_with_id_with_parens.tz", - r"big_map or sapling_state type not expected here", - ), - ( - "push_big_map_with_id_without_parens.tz", - r"primitive PUSH expects 2 arguments but is given 4", - ), - # sapling_state is not packable - ( - "pack_sapling_state.tz", - r"big_map or sapling_state type not expected here", - ), - # sapling_state is not packable - ( - "unpack_sapling_state.tz", - r"big_map or sapling_state type not expected here", - ), - # Ticket duplication attempt - ( - "ticket_dup.tz", - r'ticket nat cannot be used here because it is not duplicable', - ), - # error message for ticket unpack - ("ticket_unpack.tz", r'Ticket in unauthorized position'), - # error message for attempting to use APPLY to capture a ticket - ("ticket_apply.tz", r'Ticket in unauthorized position'), - # error message for attempting to wrap a ticket in a ticket - ( - "ticket_in_ticket.tz", - r'comparable type expected.Type ticket unit is not comparable', - ), - # error message for DIP { FAILWITH } - ( - "dip_failwith.tz", - r'The FAIL instruction must appear in a tail position.', - ), - # error message for MAP { FAILWITH } - ( - "map_failwith.tz", - r'The proper type of the return list cannot be inferred.', - ), - ], - ) - def test_ill_typecheck(self, client: Client, contract, error_pattern): - with utils.assert_run_failure(error_pattern): - client.typecheck(os.path.join(ILLTYPED_CONTRACT_PATH, contract)) - - def test_zero_transfer_to_implicit_contract(self, client): - pubkey = IDENTITIES['bootstrap3']['identity'] - err = ( - 'Transactions of 0ꜩ towards a contract without code are ' - rf'forbidden \({pubkey}\).' - ) - with utils.assert_run_failure(err): - client.transfer(0, 'bootstrap2', 'bootstrap3', []) - - def test_zero_transfer_to_nonexistent_contract(self, client): - nonexistent = "KT1Fcq4inD44aMhmUiTEHR1QMQwJT7p2u641" - err = rf'Contract {nonexistent} does not exist' - with utils.assert_run_failure(err): - client.transfer(0, 'bootstrap2', nonexistent, []) - - @pytest.mark.contract class TestScriptHashMultiple: """Test octez-client hash script with diffent number and type of diff --git a/tests_python/tests_015/test_contract.py b/tests_python/tests_015/test_contract.py index ce056354b26c..ee242658dbeb 100644 --- a/tests_python/tests_015/test_contract.py +++ b/tests_python/tests_015/test_contract.py @@ -5,11 +5,7 @@ from client.client import Client from tools import utils from tools.constants import IDENTITIES from tools.utils import originate -from .contract_paths import ( - CONTRACT_PATH, - ILLTYPED_CONTRACT_PATH, - all_legacy_contracts, -) +from .contract_paths import CONTRACT_PATH ID_SCRIPT_LITERAL = ''' @@ -266,236 +262,6 @@ class TestManager: utils.bake(client, bake_for='bootstrap5') -@pytest.mark.slow -@pytest.mark.contract -class TestContracts: - """Test type checking errors""" - - @pytest.mark.parametrize("contract", all_legacy_contracts()) - def test_deprecated_typecheck_breaks(self, client, contract): - if contract in [ - "legacy/create_contract.tz", - "legacy/create_contract_flags.tz", - "legacy/create_contract_rootname.tz", - ]: - with utils.assert_run_failure(r'ill-typed script'): - client.typecheck(os.path.join(CONTRACT_PATH, contract)) - else: - with utils.assert_run_failure(r'Use of deprecated instruction'): - client.typecheck(os.path.join(CONTRACT_PATH, contract)) - - @pytest.mark.parametrize("contract", all_legacy_contracts()) - def test_deprecated_typecheck_in_legacy(self, client, contract): - if contract in [ - "legacy/create_contract.tz", - "legacy/create_contract_flags.tz", - "legacy/create_contract_rootname.tz", - ]: - with utils.assert_run_failure(r'ill-typed script'): - client.typecheck( - os.path.join(CONTRACT_PATH, contract), legacy=True - ) - else: - with utils.assert_run_failure(r'Use of deprecated instruction'): - client.typecheck( - os.path.join(CONTRACT_PATH, contract), legacy=True - ) - - @pytest.mark.parametrize( - "contract,error_pattern", - [ - # Even though the interpreter uses a nonempty stack internally, - # the typechecker should not be able to observe it. - ( - "stack_bottom_unfailwithable.tz", - r'wrong stack type for instruction FAILWITH', - ), - ( - "stack_bottom_unrightable.tz", - r'wrong stack type for instruction RIGHT', - ), - ( - "stack_bottom_unleftable.tz", - r'wrong stack type for instruction LEFT', - ), - ( - "stack_bottom_ungetable.tz", - r'wrong stack type for instruction GET', - ), - ( - "stack_bottom_unpairable.tz", - r'wrong stack type for instruction UNPAIR', - ), - ( - "stack_bottom_undug2able.tz", - r'wrong stack type for instruction DUG', - ), - ( - "stack_bottom_undugable.tz", - r'wrong stack type for instruction DUG', - ), - ( - "stack_bottom_undig2able.tz", - r'wrong stack type for instruction DIG', - ), - ( - "stack_bottom_undigable.tz", - r'wrong stack type for instruction DIG', - ), - ( - "stack_bottom_undip2able.tz", - r'wrong stack type for instruction DUP', - ), - ( - "stack_bottom_undipable.tz", - r'wrong stack type for instruction DUP', - ), - ( - "stack_bottom_undup2able.tz", - r'wrong stack type for instruction DUP', - ), - ( - "stack_bottom_undropable.tz", - r'wrong stack type for instruction DROP', - ), - ( - "stack_bottom_unpopable.tz", - r'wrong stack type for instruction DUP', - ), - ( - "stack_bottom_unpopable_in_lambda.tz", - r'wrong stack type for instruction DUP', - ), - # operations cannot be PACKed - ( - "pack_operation.tz", - r'operation type forbidden in parameter, storage and constants', - ), - # big_maps cannot be PACKed - ( - "pack_big_map.tz", - r'big_map or sapling_state type not expected here', - ), - ( - "invalid_self_entrypoint.tz", - r'Contract has no entrypoint named D', - ), - ( - "contract_annotation_default.tz", - r'unexpected_default_entrypoint', - ), - # Missing field - ( - "missing_only_storage_field.tz", - r'Missing contract field: storage', - ), - ("missing_only_code_field.tz", r'Missing contract field: code'), - ( - "missing_only_parameter_field.tz", - r'Missing contract field: parameter', - ), - ( - "missing_parameter_and_storage_fields.tz", - r'Missing contract field: parameter', - ), - # Duplicated field - ( - "multiple_parameter_field.tz", - r'duplicate contract field: parameter', - ), - ("multiple_code_field.tz", r'duplicate contract field: code'), - ("multiple_storage_field.tz", r'duplicate contract field: storage'), - # The first duplicated field is reported, storage in this case - ( - "multiple_storage_and_code_fields.tz", - r'duplicate contract field: storage', - ), - # error message for set update on non-comparable type - ( - "set_update_non_comparable.tz", - r'Type nat\s+is not compatible with type list operation', - ), - # error message for the arity of the chain_id type - ( - "chain_id_arity.tz", - r'primitive chain_id expects 0 arguments but is given 1', - ), - # error message for DIP over the limit - ("big_dip.tz", r'expected a positive 10-bit integer'), - # error message for DROP over the limit - ("big_drop.tz", r'expected a positive 10-bit integer'), - # error message for attempting to push a value of type never - ("never_literal.tz", r'type never has no inhabitant.'), - # COMB, UNCOMB, and DUP cannot take 0 as argument - ("comb0.tz", r"PAIR expects an argument of at least 2"), - ("comb1.tz", r"PAIR expects an argument of at least 2"), - ("uncomb0.tz", r"UNPAIR expects an argument of at least 2"), - ("uncomb1.tz", r"UNPAIR expects an argument of at least 2"), - ("dup0.tz", r"DUP n expects an argument of at least 1"), - ( - "push_big_map_with_id_with_parens.tz", - r"big_map or sapling_state type not expected here", - ), - ( - "push_big_map_with_id_without_parens.tz", - r"primitive PUSH expects 2 arguments but is given 4", - ), - # sapling_state is not packable - ( - "pack_sapling_state.tz", - r"big_map or sapling_state type not expected here", - ), - # sapling_state is not packable - ( - "unpack_sapling_state.tz", - r"big_map or sapling_state type not expected here", - ), - # Ticket duplication attempt - ( - "ticket_dup.tz", - r'ticket nat cannot be used here because it is not duplicable', - ), - # error message for ticket unpack - ("ticket_unpack.tz", r'Ticket in unauthorized position'), - # error message for attempting to use APPLY to capture a ticket - ("ticket_apply.tz", r'Ticket in unauthorized position'), - # error message for attempting to wrap a ticket in a ticket - ( - "ticket_in_ticket.tz", - r'comparable type expected.Type ticket unit is not comparable', - ), - # error message for DIP { FAILWITH } - ( - "dip_failwith.tz", - r'The FAIL instruction must appear in a tail position.', - ), - # error message for MAP { FAILWITH } - ( - "map_failwith.tz", - r'The proper type of the return list cannot be inferred.', - ), - ], - ) - def test_ill_typecheck(self, client: Client, contract, error_pattern): - with utils.assert_run_failure(error_pattern): - client.typecheck(os.path.join(ILLTYPED_CONTRACT_PATH, contract)) - - def test_zero_transfer_to_implicit_contract(self, client): - pubkey = IDENTITIES['bootstrap3']['identity'] - err = ( - 'Transactions of 0ꜩ towards a contract without code are ' - rf'forbidden \({pubkey}\).' - ) - with utils.assert_run_failure(err): - client.transfer(0, 'bootstrap2', 'bootstrap3', []) - - def test_zero_transfer_to_nonexistent_contract(self, client): - nonexistent = "KT1Fcq4inD44aMhmUiTEHR1QMQwJT7p2u641" - err = rf'Contract {nonexistent} does not exist' - with utils.assert_run_failure(err): - client.transfer(0, 'bootstrap2', nonexistent, []) - - @pytest.mark.contract class TestScriptHashMultiple: """Test octez-client hash script with diffent number and type of diff --git a/tests_python/tests_alpha/test_contract.py b/tests_python/tests_alpha/test_contract.py index ce056354b26c..ee242658dbeb 100644 --- a/tests_python/tests_alpha/test_contract.py +++ b/tests_python/tests_alpha/test_contract.py @@ -5,11 +5,7 @@ from client.client import Client from tools import utils from tools.constants import IDENTITIES from tools.utils import originate -from .contract_paths import ( - CONTRACT_PATH, - ILLTYPED_CONTRACT_PATH, - all_legacy_contracts, -) +from .contract_paths import CONTRACT_PATH ID_SCRIPT_LITERAL = ''' @@ -266,236 +262,6 @@ class TestManager: utils.bake(client, bake_for='bootstrap5') -@pytest.mark.slow -@pytest.mark.contract -class TestContracts: - """Test type checking errors""" - - @pytest.mark.parametrize("contract", all_legacy_contracts()) - def test_deprecated_typecheck_breaks(self, client, contract): - if contract in [ - "legacy/create_contract.tz", - "legacy/create_contract_flags.tz", - "legacy/create_contract_rootname.tz", - ]: - with utils.assert_run_failure(r'ill-typed script'): - client.typecheck(os.path.join(CONTRACT_PATH, contract)) - else: - with utils.assert_run_failure(r'Use of deprecated instruction'): - client.typecheck(os.path.join(CONTRACT_PATH, contract)) - - @pytest.mark.parametrize("contract", all_legacy_contracts()) - def test_deprecated_typecheck_in_legacy(self, client, contract): - if contract in [ - "legacy/create_contract.tz", - "legacy/create_contract_flags.tz", - "legacy/create_contract_rootname.tz", - ]: - with utils.assert_run_failure(r'ill-typed script'): - client.typecheck( - os.path.join(CONTRACT_PATH, contract), legacy=True - ) - else: - with utils.assert_run_failure(r'Use of deprecated instruction'): - client.typecheck( - os.path.join(CONTRACT_PATH, contract), legacy=True - ) - - @pytest.mark.parametrize( - "contract,error_pattern", - [ - # Even though the interpreter uses a nonempty stack internally, - # the typechecker should not be able to observe it. - ( - "stack_bottom_unfailwithable.tz", - r'wrong stack type for instruction FAILWITH', - ), - ( - "stack_bottom_unrightable.tz", - r'wrong stack type for instruction RIGHT', - ), - ( - "stack_bottom_unleftable.tz", - r'wrong stack type for instruction LEFT', - ), - ( - "stack_bottom_ungetable.tz", - r'wrong stack type for instruction GET', - ), - ( - "stack_bottom_unpairable.tz", - r'wrong stack type for instruction UNPAIR', - ), - ( - "stack_bottom_undug2able.tz", - r'wrong stack type for instruction DUG', - ), - ( - "stack_bottom_undugable.tz", - r'wrong stack type for instruction DUG', - ), - ( - "stack_bottom_undig2able.tz", - r'wrong stack type for instruction DIG', - ), - ( - "stack_bottom_undigable.tz", - r'wrong stack type for instruction DIG', - ), - ( - "stack_bottom_undip2able.tz", - r'wrong stack type for instruction DUP', - ), - ( - "stack_bottom_undipable.tz", - r'wrong stack type for instruction DUP', - ), - ( - "stack_bottom_undup2able.tz", - r'wrong stack type for instruction DUP', - ), - ( - "stack_bottom_undropable.tz", - r'wrong stack type for instruction DROP', - ), - ( - "stack_bottom_unpopable.tz", - r'wrong stack type for instruction DUP', - ), - ( - "stack_bottom_unpopable_in_lambda.tz", - r'wrong stack type for instruction DUP', - ), - # operations cannot be PACKed - ( - "pack_operation.tz", - r'operation type forbidden in parameter, storage and constants', - ), - # big_maps cannot be PACKed - ( - "pack_big_map.tz", - r'big_map or sapling_state type not expected here', - ), - ( - "invalid_self_entrypoint.tz", - r'Contract has no entrypoint named D', - ), - ( - "contract_annotation_default.tz", - r'unexpected_default_entrypoint', - ), - # Missing field - ( - "missing_only_storage_field.tz", - r'Missing contract field: storage', - ), - ("missing_only_code_field.tz", r'Missing contract field: code'), - ( - "missing_only_parameter_field.tz", - r'Missing contract field: parameter', - ), - ( - "missing_parameter_and_storage_fields.tz", - r'Missing contract field: parameter', - ), - # Duplicated field - ( - "multiple_parameter_field.tz", - r'duplicate contract field: parameter', - ), - ("multiple_code_field.tz", r'duplicate contract field: code'), - ("multiple_storage_field.tz", r'duplicate contract field: storage'), - # The first duplicated field is reported, storage in this case - ( - "multiple_storage_and_code_fields.tz", - r'duplicate contract field: storage', - ), - # error message for set update on non-comparable type - ( - "set_update_non_comparable.tz", - r'Type nat\s+is not compatible with type list operation', - ), - # error message for the arity of the chain_id type - ( - "chain_id_arity.tz", - r'primitive chain_id expects 0 arguments but is given 1', - ), - # error message for DIP over the limit - ("big_dip.tz", r'expected a positive 10-bit integer'), - # error message for DROP over the limit - ("big_drop.tz", r'expected a positive 10-bit integer'), - # error message for attempting to push a value of type never - ("never_literal.tz", r'type never has no inhabitant.'), - # COMB, UNCOMB, and DUP cannot take 0 as argument - ("comb0.tz", r"PAIR expects an argument of at least 2"), - ("comb1.tz", r"PAIR expects an argument of at least 2"), - ("uncomb0.tz", r"UNPAIR expects an argument of at least 2"), - ("uncomb1.tz", r"UNPAIR expects an argument of at least 2"), - ("dup0.tz", r"DUP n expects an argument of at least 1"), - ( - "push_big_map_with_id_with_parens.tz", - r"big_map or sapling_state type not expected here", - ), - ( - "push_big_map_with_id_without_parens.tz", - r"primitive PUSH expects 2 arguments but is given 4", - ), - # sapling_state is not packable - ( - "pack_sapling_state.tz", - r"big_map or sapling_state type not expected here", - ), - # sapling_state is not packable - ( - "unpack_sapling_state.tz", - r"big_map or sapling_state type not expected here", - ), - # Ticket duplication attempt - ( - "ticket_dup.tz", - r'ticket nat cannot be used here because it is not duplicable', - ), - # error message for ticket unpack - ("ticket_unpack.tz", r'Ticket in unauthorized position'), - # error message for attempting to use APPLY to capture a ticket - ("ticket_apply.tz", r'Ticket in unauthorized position'), - # error message for attempting to wrap a ticket in a ticket - ( - "ticket_in_ticket.tz", - r'comparable type expected.Type ticket unit is not comparable', - ), - # error message for DIP { FAILWITH } - ( - "dip_failwith.tz", - r'The FAIL instruction must appear in a tail position.', - ), - # error message for MAP { FAILWITH } - ( - "map_failwith.tz", - r'The proper type of the return list cannot be inferred.', - ), - ], - ) - def test_ill_typecheck(self, client: Client, contract, error_pattern): - with utils.assert_run_failure(error_pattern): - client.typecheck(os.path.join(ILLTYPED_CONTRACT_PATH, contract)) - - def test_zero_transfer_to_implicit_contract(self, client): - pubkey = IDENTITIES['bootstrap3']['identity'] - err = ( - 'Transactions of 0ꜩ towards a contract without code are ' - rf'forbidden \({pubkey}\).' - ) - with utils.assert_run_failure(err): - client.transfer(0, 'bootstrap2', 'bootstrap3', []) - - def test_zero_transfer_to_nonexistent_contract(self, client): - nonexistent = "KT1Fcq4inD44aMhmUiTEHR1QMQwJT7p2u641" - err = rf'Contract {nonexistent} does not exist' - with utils.assert_run_failure(err): - client.transfer(0, 'bootstrap2', nonexistent, []) - - @pytest.mark.contract class TestScriptHashMultiple: """Test octez-client hash script with diffent number and type of diff --git a/tezt/tests/main.ml b/tezt/tests/main.ml index 57a3db2c77ea..39acb3464a0e 100644 --- a/tezt/tests/main.ml +++ b/tezt/tests/main.ml @@ -158,6 +158,7 @@ let register_protocol_tests_that_use_supports_correctly () = Script_hash_regression.register ~protocols ; Self_address_transfer.register ~protocols ; Script_conversion.register ~protocols ; + Script_illtyped.register ~protocols ; Signer_test.register ~protocols ; Stresstest_command.register ~protocols ; Synchronisation_heuristic.register ~protocols ; diff --git a/tezt/tests/script_illtyped.ml b/tezt/tests/script_illtyped.ml new file mode 100644 index 000000000000..3d8887889300 --- /dev/null +++ b/tezt/tests/script_illtyped.ml @@ -0,0 +1,204 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Nomadic Labs *) +(* *) +(* Permission is hereby granted, free of charge, to any person obtaining a *) +(* copy of this software and associated documentation files (the "Software"),*) +(* to deal in the Software without restriction, including without limitation *) +(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) +(* and/or sell copies of the Software, and to permit persons to whom the *) +(* Software is furnished to do so, subject to the following conditions: *) +(* *) +(* The above copyright notice and this permission notice shall be included *) +(* in all copies or substantial portions of the Software. *) +(* *) +(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) +(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) +(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) +(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) +(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) +(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) +(* DEALINGS IN THE SOFTWARE. *) +(* *) +(*****************************************************************************) + +(* Testing + ------- + Component: Michelson / Contracts + Invocation: dune exec tezt/tests/main.exe -- --file script_illtyped.ml + Subject: Test Michelson script typechecking failures +*) + +(* +def test_deprecated_typecheck_breaks(self, client, contract): + if contract in [ + "legacy/create_contract.tz", + "legacy/create_contract_flags.tz", + "legacy/create_contract_rootname.tz", + ]: + with utils.assert_run_failure(r'ill-typed script'): + client.typecheck(os.path.join(CONTRACT_PATH, contract)) + else: + with utils.assert_run_failure(r'Use of deprecated instruction'): + client.typecheck(os.path.join(CONTRACT_PATH, contract)) +*) +let test_deprecated_typecheck script ~legacy = + Protocol.register_test + ~__FILE__ + ~title: + (sf + "Test Deprecated Typecheck %s - %s" + (if legacy then "in Legacy" else "Breaks") + (Michelson_script.name_s script)) + ~tags:["client"; "script"; "michelson"; "typechecking"] + @@ fun protocol -> + let* client = Client.init_mockup ~protocol () in + let ill_typed_scripts = + [ + "legacy/create_contract"; + "legacy/create_contract_flags"; + "legacy/create_contract_rootname"; + ] + in + let script_path = Michelson_script.path script in + let expected_error = + if List.mem (Michelson_script.name_s script) ill_typed_scripts then + "ill-typed script" + else "Use of deprecated instruction" + in + Client.spawn_typecheck_script ~script:script_path ~legacy client + |> Process.check_error ~msg:(rex expected_error) + +(* +def test_ill_typecheck(self, client: Client, contract, error_pattern): + with utils.assert_run_failure(error_pattern): + client.typecheck(os.path.join(ILLTYPED_CONTRACT_PATH, contract)) +*) +let test_ill_typecheck script error_pattern = + Protocol.register_test + ~__FILE__ + ~title:(sf "Test Ill Typecheck - %s" script) + ~tags:["client"; "script"; "michelson"; "typechecking"] + @@ fun protocol -> + let* client = Client.init_mockup ~protocol () in + let script_path = + Michelson_script.( + find + ~prefix: + (sf + "tests_python/contracts_%s" + (match protocol with + | Alpha -> "alpha" + | _ -> sf "%03d" (Protocol.number protocol))) + ["ill_typed"; script] + protocol + |> path) + in + Client.spawn_typecheck_script ~script:script_path client + |> Process.check_error ~msg:error_pattern + +let register ~protocols = + protocols + |> List.iter (fun protocol -> + Michelson_script.find_all_legacy + ~prefix: + (sf + "tests_python/contracts_%s" + (match protocol with + | Alpha -> "alpha" + | _ -> sf "%03d" (Protocol.number protocol))) + protocol + |> List.iter (fun michelson_script -> + test_deprecated_typecheck + michelson_script + [protocol] + ~legacy:false ; + test_deprecated_typecheck + michelson_script + [protocol] + ~legacy:true)) ; + [ + (* Even though the interpreter uses a nonempty stack internally, + the typechecker should not be able to observe it. *) + ( "stack_bottom_unfailwithable", + rex "wrong stack type for instruction FAILWITH" ); + ("stack_bottom_unrightable", rex "wrong stack type for instruction RIGHT"); + ("stack_bottom_unleftable", rex "wrong stack type for instruction LEFT"); + ("stack_bottom_ungetable", rex "wrong stack type for instruction GET"); + ("stack_bottom_unpairable", rex "wrong stack type for instruction UNPAIR"); + ("stack_bottom_undug2able", rex "wrong stack type for instruction DUG"); + ("stack_bottom_undugable", rex "wrong stack type for instruction DUG"); + ("stack_bottom_undig2able", rex "wrong stack type for instruction DIG"); + ("stack_bottom_undigable", rex "wrong stack type for instruction DIG"); + ("stack_bottom_undip2able", rex "wrong stack type for instruction DUP"); + ("stack_bottom_undipable", rex "wrong stack type for instruction DUP"); + ("stack_bottom_undup2able", rex "wrong stack type for instruction DUP"); + ("stack_bottom_undropable", rex "wrong stack type for instruction DROP"); + ("stack_bottom_unpopable", rex "wrong stack type for instruction DUP"); + ( "stack_bottom_unpopable_in_lambda", + rex "wrong stack type for instruction DUP" ); + (* operations cannot be PACKed *) + ( "pack_operation", + rex "operation type forbidden in parameter, storage and constants" ); + (* big_maps cannot be PACKed *) + ("pack_big_map", rex "big_map or sapling_state type not expected here"); + ("invalid_self_entrypoint", rex "Contract has no entrypoint named D"); + ("contract_annotation_default", rex "unexpected_default_entrypoint"); + (* Missing field *) + ("missing_only_storage_field", rex "Missing contract field: storage"); + ("missing_only_code_field", rex "Missing contract field: code"); + ("missing_only_parameter_field", rex "Missing contract field: parameter"); + ( "missing_parameter_and_storage_fields", + rex "Missing contract field: parameter" ); + (* Duplicated field *) + ("multiple_parameter_field", rex "duplicate contract field: parameter"); + ("multiple_code_field", rex "duplicate contract field: code"); + ("multiple_storage_field", rex "duplicate contract field: storage"); + (* The first duplicated field is reported, storage in this case *) + ("multiple_storage_and_code_fields", rex "duplicate contract field: storage"); + (* error message for set update on non-comparable type *) + ( "set_update_non_comparable", + rex "Type nat\\s+is not compatible with type list operation" ); + (* error message for the arity of the chain_id type *) + ( "chain_id_arity", + rex "primitive chain_id expects 0 arguments but is given 1" ); + (* error message for DIP over the limit *) + ("big_dip", rex "expected a positive 10-bit integer"); + (* error message for DROP over the limit *) + ("big_drop", rex "expected a positive 10-bit integer"); + (* error message for attempting to push a value of type never *) + ("never_literal", rex "type never has no inhabitant."); + (* COMB, UNCOMB, and DUP cannot take 0 as argument *) + ("comb0", rex "PAIR expects an argument of at least 2"); + ("comb1", rex "PAIR expects an argument of at least 2"); + ("uncomb0", rex "UNPAIR expects an argument of at least 2"); + ("uncomb1", rex "UNPAIR expects an argument of at least 2"); + ("dup0", rex "DUP n expects an argument of at least 1"); + ( "push_big_map_with_id_with_parens", + rex "big_map or sapling_state type not expected here" ); + ( "push_big_map_with_id_without_parens", + rex "primitive PUSH expects 2 arguments but is given 4" ); + (* sapling_state is not packable *) + ("pack_sapling_state", rex "big_map or sapling_state type not expected here"); + (* sapling_state is not packable *) + ( "unpack_sapling_state", + rex "big_map or sapling_state type not expected here" ); + (* Ticket duplication attempt *) + ( "ticket_dup", + rex "ticket nat cannot be used here because it is not duplicable" ); + (* error message for ticket unpack *) + ("ticket_unpack", rex "Ticket in unauthorized position"); + (* error message for attempting to use APPLY to capture a ticket *) + ("ticket_apply", rex "Ticket in unauthorized position"); + (* error message for attempting to wrap a ticket in a ticket *) + ( "ticket_in_ticket", + rex "comparable type expected.Type ticket unit is not comparable" ); + (* error message for DIP { FAILWITH } *) + ("dip_failwith", rex "The FAIL instruction must appear in a tail position."); + (* error message for MAP { FAILWITH } *) + ( "map_failwith", + rex "The proper type of the return list cannot be inferred." ); + ] + |> List.iter (fun (script, error_pattern) -> + test_ill_typecheck script error_pattern protocols) -- GitLab From 90f6d80a1825587a7896213e23c69d060da3a599 Mon Sep 17 00:00:00 2001 From: Richard Davison Date: Tue, 29 Nov 2022 05:15:25 -0500 Subject: [PATCH 3/3] Tezt: add [Transfer] --- tezt/tests/main.ml | 1 + tezt/tests/transfer.ml | 72 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 tezt/tests/transfer.ml diff --git a/tezt/tests/main.ml b/tezt/tests/main.ml index 39acb3464a0e..21ec84d237bd 100644 --- a/tezt/tests/main.ml +++ b/tezt/tests/main.ml @@ -164,6 +164,7 @@ let register_protocol_tests_that_use_supports_correctly () = Synchronisation_heuristic.register ~protocols ; Tenderbake.register ~protocols ; Testnet_dictator.register ~protocols ; + Transfer.register ~protocols ; Tickets.register ~protocols ; Timelock.register ~protocols ; Tx_rollup.register ~protocols ; diff --git a/tezt/tests/transfer.ml b/tezt/tests/transfer.ml new file mode 100644 index 000000000000..e7f7c51909c2 --- /dev/null +++ b/tezt/tests/transfer.ml @@ -0,0 +1,72 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Nomadic Labs *) +(* *) +(* Permission is hereby granted, free of charge, to any person obtaining a *) +(* copy of this software and associated documentation files (the "Software"),*) +(* to deal in the Software without restriction, including without limitation *) +(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) +(* and/or sell copies of the Software, and to permit persons to whom the *) +(* Software is furnished to do so, subject to the following conditions: *) +(* *) +(* The above copyright notice and this permission notice shall be included *) +(* in all copies or substantial portions of the Software. *) +(* *) +(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) +(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) +(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) +(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) +(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) +(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) +(* DEALINGS IN THE SOFTWARE. *) +(* *) +(*****************************************************************************) + +(* Testing + ------- + Component: Client / Transfer + Invocation: dune exec tezt/tests/main.exe -- --file transfer.ml + Subject: Test transfers +*) + +let test_zero_transfer_to_implicit_contract = + Protocol.register_test + ~__FILE__ + ~title:"Test Zero Transfer to Implicit Contract" + ~tags:["client"; "transfer"] + @@ fun protocol -> + let* client = Client.init_mockup ~protocol () in + let pubkey = Account.Bootstrap.keys.(2).public_key_hash in + let err = + rexf + "Transactions of 0ꜩ towards a contract without code are forbidden \ + \\(%s\\)." + pubkey + in + Client.spawn_transfer + ~amount:Tez.zero + ~giver:(Account.Bootstrap.alias 2) + ~receiver:(Account.Bootstrap.alias 3) + client + |> Process.check_error ~msg:err + +let test_zero_transfer_to_nonexistent_contract = + Protocol.register_test + ~__FILE__ + ~title:"Test Zero Transfer to Nonexistent Contract" + ~tags:["client"; "transfer"] + @@ fun protocol -> + let* client = Client.init_mockup ~protocol () in + let nonexistent = "KT1Fcq4inD44aMhmUiTEHR1QMQwJT7p2u641" in + let err = rexf "Contract %s does not exist" nonexistent in + Client.spawn_transfer + ~amount:Tez.zero + ~giver:(Account.Bootstrap.alias 2) + ~receiver:nonexistent + client + |> Process.check_error ~msg:err + +let register ~protocols = + test_zero_transfer_to_implicit_contract protocols ; + test_zero_transfer_to_nonexistent_contract protocols -- GitLab