From 7abbbd3d26ccd72b57d977a7172213445f48841a Mon Sep 17 00:00:00 2001 From: lin Date: Thu, 1 Dec 2022 17:22:22 +0000 Subject: [PATCH 1/3] Tezt/Client: Add ?force option to originate_contract --- tezt/lib_tezos/client.ml | 9 ++++++--- tezt/lib_tezos/client.mli | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tezt/lib_tezos/client.ml b/tezt/lib_tezos/client.ml index ecc7712b0885..32aed11655b3 100644 --- a/tezt/lib_tezos/client.ml +++ b/tezt/lib_tezos/client.ml @@ -1149,7 +1149,8 @@ let drain_delegate ?hooks ?endpoint ?(wait = "none") ?expect_failure ~delegate |> Process.check ?expect_failure let spawn_originate_contract ?hooks ?log_output ?endpoint ?(wait = "none") ?init - ?burn_cap ?gas_limit ?(dry_run = false) ~alias ~amount ~src ~prg client = + ?burn_cap ?gas_limit ?(dry_run = false) ?(force = false) ~alias ~amount ~src + ~prg client = spawn_command ?hooks ?log_output @@ -1170,7 +1171,8 @@ let spawn_originate_contract ?hooks ?log_output ?endpoint ?(wait = "none") ?init @ optional_arg "init" Fun.id init @ optional_arg "burn-cap" Tez.to_string burn_cap @ optional_arg "gas-limit" string_of_int gas_limit - @ optional_switch "dry-run" dry_run) + @ optional_switch "dry-run" dry_run + @ optional_switch "force" force) type conversion_kind = Script | Data @@ -1221,7 +1223,7 @@ let convert_data_to_json ?endpoint ~data client = convert_michelson_to_json ~kind:Data ?endpoint ~input:data client let originate_contract ?hooks ?log_output ?endpoint ?wait ?init ?burn_cap - ?gas_limit ?dry_run ~alias ~amount ~src ~prg client = + ?gas_limit ?dry_run ?force ~alias ~amount ~src ~prg client = let* client_output = spawn_originate_contract ?endpoint @@ -1232,6 +1234,7 @@ let originate_contract ?hooks ?log_output ?endpoint ?wait ?init ?burn_cap ?burn_cap ?gas_limit ?dry_run + ?force ~alias ~amount ~src diff --git a/tezt/lib_tezos/client.mli b/tezt/lib_tezos/client.mli index b0f970c8fb03..d80c592b8c08 100644 --- a/tezt/lib_tezos/client.mli +++ b/tezt/lib_tezos/client.mli @@ -925,6 +925,7 @@ val originate_contract : ?burn_cap:Tez.t -> ?gas_limit:int -> ?dry_run:bool -> + ?force:bool -> alias:string -> amount:Tez.t -> src:string -> @@ -942,6 +943,7 @@ val spawn_originate_contract : ?burn_cap:Tez.t -> ?gas_limit:int -> ?dry_run:bool -> + ?force:bool -> alias:string -> amount:Tez.t -> src:string -> -- GitLab From e62adedef00270e9c909ad50cd29bc5434aea795 Mon Sep 17 00:00:00 2001 From: lin Date: Thu, 1 Dec 2022 18:05:16 +0000 Subject: [PATCH 2/3] Tezt: Migrate TestExecutionOrdering to Tezt --- tezt/tests/main.ml | 1 + tezt/tests/script_execution_ordering.ml | 147 ++++++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 tezt/tests/script_execution_ordering.ml diff --git a/tezt/tests/main.ml b/tezt/tests/main.ml index eef13e70d441..b1937981c2ba 100644 --- a/tezt/tests/main.ml +++ b/tezt/tests/main.ml @@ -153,6 +153,7 @@ let register_protocol_tests_that_use_supports_correctly () = Run_script.register ~protocols ; Runtime_script_failure.register ~protocols ; Sapling.register ~protocols ; + Script_execution_ordering.register ~protocols ; Script_hash_regression.register ~protocols ; Self_address_transfer.register ~protocols ; Script_conversion.register ~protocols ; diff --git a/tezt/tests/script_execution_ordering.ml b/tezt/tests/script_execution_ordering.ml new file mode 100644 index 000000000000..6441b97f7ad3 --- /dev/null +++ b/tezt/tests/script_execution_ordering.ml @@ -0,0 +1,147 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs *) +(* Copyright (c) 2022 Marigold *) +(* *) +(* 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: Script execution ordering + Invocation: dune exec tezt/tests/main.exe -- --file script_execution_ordering.ml + Subject: Tests for contract execution order. +*) + +let contract_path protocol kind contract = + sf + "tests_python/contracts_%s/%s/%s" + (match protocol with + | Protocol.Alpha -> "alpha" + | _ -> sf "%03d" @@ Protocol.number protocol) + kind + contract + +type 'a tree = Leaf of 'a | Node of 'a tree list + +(* This test to verifies contract execution order. + There are 3 contracts: + - Storer: Appends its argument to storage. + - Caller: Calls the list of unit contracts in its storage. + - Appender: Calls the string contract in its storage with a stored argument. + + For each test, there is one unique Storer. Each test is + parameterized by a tree and the expected final storage of the + Storer. A leaf in the tree is a string. Inner nodes are lists of + leafs/inner nodes. The test maps maps over this tree to build a + tree of contracts. Leaf nodes map to Appender contracts calling + the Storer. Inner nodes map to Caller contract that calling + children. + + Example. Given the tree: ["A", ["B"], "C"], we obtain + Caller([Appender("A"), Caller([Appender("B")]), Appender("C")]) + Before the protocol 009, contract execution order was in BFS + In BFS, Storer would've ended up with storage ACB. + In DFS, Storer will end up with storage ABC. *) +let test_execution_ordering = + Protocol.register_test + ~__FILE__ + ~title:"Test contract execution order." + ~tags:["client"; "script"] + @@ fun protocol -> + let* client = Client.init_mockup ~protocol () in + let originate_storer () = + Client.originate_contract + ~alias:"storer" + ~amount:Tez.zero + ~src:Constant.bootstrap1.alias + ~prg:(contract_path protocol "mini_scenarios" "execution_order_storer.tz") + ~init:{|""|} + ~burn_cap:Tez.one + ~force:true + client + in + let originate_appender ~storer ~argument = + Client.originate_contract + ~alias:(sf "appender-%s" argument) + ~amount:Tez.zero + ~src:Constant.bootstrap1.alias + ~prg: + (contract_path protocol "mini_scenarios" "execution_order_appender.tz") + ~init:(sf "Pair %S %S" storer argument) + ~burn_cap:Tez.one + ~force:true + client + in + let originate_caller callees = + let storage = sf "{%s}" (String.concat "; " (List.map (sf "%S") callees)) in + Client.originate_contract + ~alias:(sf "caller-%d" (Hashtbl.hash storage)) + ~amount:Tez.zero + ~src:Constant.bootstrap1.alias + ~prg:(contract_path protocol "mini_scenarios" "execution_order_caller.tz") + ~init:storage + ~burn_cap:Tez.one + ~force:true + client + in + let* () = + [ + (* before 009, the result should be "DABCEFG". *) + ( Node + [ + Node [Leaf "A"; Leaf "B"; Leaf "C"]; + Leaf "D"; + Node [Leaf "E"; Leaf "F"; Leaf "G"]; + ], + "ABCDEFG" ); + (* before 009; the result should be "ACB". *) + (Node [Leaf "A"; Node [Leaf "B"]; Leaf "C"], "ABC"); + (* before 009; the result should be "ABDC". *) + (Node [Leaf "A"; Node [Leaf "B"; Node [Leaf "C"]; Leaf "D"]], "ABCD"); + (Node [], ""); + ] + |> Lwt_list.iter_s @@ fun (tree, expected) -> + let* storer = originate_storer () in + let rec deploy_tree = function + | Leaf s -> originate_appender ~storer ~argument:s + | Node tree -> + let* children = Lwt_list.map_s deploy_tree tree in + originate_caller children + in + let* root = deploy_tree tree in + let* () = + Client.transfer + ~burn_cap:(Tez.of_int 5) + ~amount:Tez.zero + ~giver:Constant.bootstrap2.alias + ~receiver:root + client + in + let* storer_storage = Client.contract_storage storer client in + return + @@ Check.( + (String.trim storer_storage = sf "%S" expected) ~__LOC__ string) + ~error_msg:"expected %R, got %L" + in + unit + +let register ~protocols = test_execution_ordering protocols -- GitLab From e7a54b631297e824cb8fbf875f9bc7b52824af36 Mon Sep 17 00:00:00 2001 From: lin Date: Fri, 2 Dec 2022 11:20:10 +0000 Subject: [PATCH 3/3] Pytest: Remove TestExecutionOrdering from pytest --- tests_python/tests_014/test_contract.py | 109 ---------------------- tests_python/tests_015/test_contract.py | 109 ---------------------- tests_python/tests_alpha/test_contract.py | 109 ---------------------- 3 files changed, 327 deletions(-) diff --git a/tests_python/tests_014/test_contract.py b/tests_python/tests_014/test_contract.py index 6fcf5d5c66e0..3de6b39c49b8 100644 --- a/tests_python/tests_014/test_contract.py +++ b/tests_python/tests_014/test_contract.py @@ -1,5 +1,4 @@ import os -from typing import List, Union, Any import pytest from client.client import Client @@ -267,114 +266,6 @@ class TestManager: utils.bake(client, bake_for='bootstrap5') -# This test to verifies contract execution order. There are 3 -# contracts: Storer, Caller, and Appender. Storer appends its argument -# to storage. Caller calls the list of unit contracts in its -# storage. Appender calls the string contract in its storage with a -# stored argument. -# -# For each test, there is one unique Storer. Each test is -# parameterized by a tree and the expected final storage of the -# Storer. A leaf in the tree is a string. Inner nodes are lists of -# leafs/inner nodes. The test maps maps over this tree to build a -# tree of contracts. Leaf nodes map to Appender contracts calling -# the Storer. Inner nodes map to Caller contract that calling -# children. -# -# Example. Given the tree: ["A", ["B"], "C"], we obtain -# Caller([Appender("A"), Caller([Appender("B")]), Appender("C")]) -# Before the protocol 009, contract execution order was in BFS -# In BFS, Storer would've ended up with storage ACB. -# In DFS, Storer will end up with storage ABC. -@pytest.mark.contract -@pytest.mark.incremental -class TestExecutionOrdering: - STORER = f'{CONTRACT_PATH}/mini_scenarios/execution_order_storer.tz' - CALLER = f'{CONTRACT_PATH}/mini_scenarios/execution_order_caller.tz' - APPENDER = f'{CONTRACT_PATH}/mini_scenarios/execution_order_appender.tz' - - def originate_storer(self, client: Client, session: dict): - origination = originate( - client, session, self.STORER, '""', 0, arguments=['--force'] - ) - session['storer'] = origination.contract - utils.bake(client, bake_for='bootstrap3') - return origination.contract - - def originate_appender( - self, client: Client, session: dict, storer: str, argument: str - ): - origination = originate( - client, - session, - self.APPENDER, - f'Pair "{storer}" "{argument}"', - 0, - contract_name=f'appender-{argument}', - arguments=['--force'], - ) - session[f'appender.{argument}'] = origination.contract - utils.bake(client, bake_for='bootstrap3') - return origination.contract - - def originate_caller( - self, client: Client, session: dict, callees: List[str] - ): - storage = "{" + '; '.join(map('"{}"'.format, callees)) + "}" - origination = originate( - client, - session, - self.CALLER, - storage, - 0, - contract_name=f'caller-{hash(storage)}', - ) - utils.bake(client, bake_for='bootstrap3') - return origination.contract - - @pytest.mark.parametrize( - "tree, expected", - [ - # before 009, the result should be "DABCEFG". - ([["A", "B", "C"], "D", ["E", "F", "G"]], "ABCDEFG"), - # before 009, the result should be "ACB". - ([["A", ["B"], "C"]], "ABC"), - # before 009, the result should be "ABDC". - ([["A", ["B", ["C"], "D"]]], "ABCD"), - ([], ""), - ], - ) - def test_ordering( - self, - client: Client, - session: dict, - # approximation of recursive type annotation - tree: Union[str, List[Any]], - expected: str, - ): - storer = self.originate_storer(client, session) - - def deploy_tree(tree: Union[str, List[Any]]) -> str: - # leaf - if isinstance(tree, str): - # deploy and return caller str - return self.originate_appender(client, session, storer, tree) - # inner node - children = list(map(deploy_tree, tree)) - return self.originate_caller(client, session, children) - - root = deploy_tree(tree) - - client.transfer( - 0, - 'bootstrap2', - root, - ["--burn-cap", "5"], - ) - utils.bake(client, bake_for='bootstrap3') - assert client.get_storage(storer) == '"{}"'.format(expected) - - @pytest.mark.slow @pytest.mark.contract class TestContracts: diff --git a/tests_python/tests_015/test_contract.py b/tests_python/tests_015/test_contract.py index 6fcf5d5c66e0..3de6b39c49b8 100644 --- a/tests_python/tests_015/test_contract.py +++ b/tests_python/tests_015/test_contract.py @@ -1,5 +1,4 @@ import os -from typing import List, Union, Any import pytest from client.client import Client @@ -267,114 +266,6 @@ class TestManager: utils.bake(client, bake_for='bootstrap5') -# This test to verifies contract execution order. There are 3 -# contracts: Storer, Caller, and Appender. Storer appends its argument -# to storage. Caller calls the list of unit contracts in its -# storage. Appender calls the string contract in its storage with a -# stored argument. -# -# For each test, there is one unique Storer. Each test is -# parameterized by a tree and the expected final storage of the -# Storer. A leaf in the tree is a string. Inner nodes are lists of -# leafs/inner nodes. The test maps maps over this tree to build a -# tree of contracts. Leaf nodes map to Appender contracts calling -# the Storer. Inner nodes map to Caller contract that calling -# children. -# -# Example. Given the tree: ["A", ["B"], "C"], we obtain -# Caller([Appender("A"), Caller([Appender("B")]), Appender("C")]) -# Before the protocol 009, contract execution order was in BFS -# In BFS, Storer would've ended up with storage ACB. -# In DFS, Storer will end up with storage ABC. -@pytest.mark.contract -@pytest.mark.incremental -class TestExecutionOrdering: - STORER = f'{CONTRACT_PATH}/mini_scenarios/execution_order_storer.tz' - CALLER = f'{CONTRACT_PATH}/mini_scenarios/execution_order_caller.tz' - APPENDER = f'{CONTRACT_PATH}/mini_scenarios/execution_order_appender.tz' - - def originate_storer(self, client: Client, session: dict): - origination = originate( - client, session, self.STORER, '""', 0, arguments=['--force'] - ) - session['storer'] = origination.contract - utils.bake(client, bake_for='bootstrap3') - return origination.contract - - def originate_appender( - self, client: Client, session: dict, storer: str, argument: str - ): - origination = originate( - client, - session, - self.APPENDER, - f'Pair "{storer}" "{argument}"', - 0, - contract_name=f'appender-{argument}', - arguments=['--force'], - ) - session[f'appender.{argument}'] = origination.contract - utils.bake(client, bake_for='bootstrap3') - return origination.contract - - def originate_caller( - self, client: Client, session: dict, callees: List[str] - ): - storage = "{" + '; '.join(map('"{}"'.format, callees)) + "}" - origination = originate( - client, - session, - self.CALLER, - storage, - 0, - contract_name=f'caller-{hash(storage)}', - ) - utils.bake(client, bake_for='bootstrap3') - return origination.contract - - @pytest.mark.parametrize( - "tree, expected", - [ - # before 009, the result should be "DABCEFG". - ([["A", "B", "C"], "D", ["E", "F", "G"]], "ABCDEFG"), - # before 009, the result should be "ACB". - ([["A", ["B"], "C"]], "ABC"), - # before 009, the result should be "ABDC". - ([["A", ["B", ["C"], "D"]]], "ABCD"), - ([], ""), - ], - ) - def test_ordering( - self, - client: Client, - session: dict, - # approximation of recursive type annotation - tree: Union[str, List[Any]], - expected: str, - ): - storer = self.originate_storer(client, session) - - def deploy_tree(tree: Union[str, List[Any]]) -> str: - # leaf - if isinstance(tree, str): - # deploy and return caller str - return self.originate_appender(client, session, storer, tree) - # inner node - children = list(map(deploy_tree, tree)) - return self.originate_caller(client, session, children) - - root = deploy_tree(tree) - - client.transfer( - 0, - 'bootstrap2', - root, - ["--burn-cap", "5"], - ) - utils.bake(client, bake_for='bootstrap3') - assert client.get_storage(storer) == '"{}"'.format(expected) - - @pytest.mark.slow @pytest.mark.contract class TestContracts: diff --git a/tests_python/tests_alpha/test_contract.py b/tests_python/tests_alpha/test_contract.py index 6fcf5d5c66e0..3de6b39c49b8 100644 --- a/tests_python/tests_alpha/test_contract.py +++ b/tests_python/tests_alpha/test_contract.py @@ -1,5 +1,4 @@ import os -from typing import List, Union, Any import pytest from client.client import Client @@ -267,114 +266,6 @@ class TestManager: utils.bake(client, bake_for='bootstrap5') -# This test to verifies contract execution order. There are 3 -# contracts: Storer, Caller, and Appender. Storer appends its argument -# to storage. Caller calls the list of unit contracts in its -# storage. Appender calls the string contract in its storage with a -# stored argument. -# -# For each test, there is one unique Storer. Each test is -# parameterized by a tree and the expected final storage of the -# Storer. A leaf in the tree is a string. Inner nodes are lists of -# leafs/inner nodes. The test maps maps over this tree to build a -# tree of contracts. Leaf nodes map to Appender contracts calling -# the Storer. Inner nodes map to Caller contract that calling -# children. -# -# Example. Given the tree: ["A", ["B"], "C"], we obtain -# Caller([Appender("A"), Caller([Appender("B")]), Appender("C")]) -# Before the protocol 009, contract execution order was in BFS -# In BFS, Storer would've ended up with storage ACB. -# In DFS, Storer will end up with storage ABC. -@pytest.mark.contract -@pytest.mark.incremental -class TestExecutionOrdering: - STORER = f'{CONTRACT_PATH}/mini_scenarios/execution_order_storer.tz' - CALLER = f'{CONTRACT_PATH}/mini_scenarios/execution_order_caller.tz' - APPENDER = f'{CONTRACT_PATH}/mini_scenarios/execution_order_appender.tz' - - def originate_storer(self, client: Client, session: dict): - origination = originate( - client, session, self.STORER, '""', 0, arguments=['--force'] - ) - session['storer'] = origination.contract - utils.bake(client, bake_for='bootstrap3') - return origination.contract - - def originate_appender( - self, client: Client, session: dict, storer: str, argument: str - ): - origination = originate( - client, - session, - self.APPENDER, - f'Pair "{storer}" "{argument}"', - 0, - contract_name=f'appender-{argument}', - arguments=['--force'], - ) - session[f'appender.{argument}'] = origination.contract - utils.bake(client, bake_for='bootstrap3') - return origination.contract - - def originate_caller( - self, client: Client, session: dict, callees: List[str] - ): - storage = "{" + '; '.join(map('"{}"'.format, callees)) + "}" - origination = originate( - client, - session, - self.CALLER, - storage, - 0, - contract_name=f'caller-{hash(storage)}', - ) - utils.bake(client, bake_for='bootstrap3') - return origination.contract - - @pytest.mark.parametrize( - "tree, expected", - [ - # before 009, the result should be "DABCEFG". - ([["A", "B", "C"], "D", ["E", "F", "G"]], "ABCDEFG"), - # before 009, the result should be "ACB". - ([["A", ["B"], "C"]], "ABC"), - # before 009, the result should be "ABDC". - ([["A", ["B", ["C"], "D"]]], "ABCD"), - ([], ""), - ], - ) - def test_ordering( - self, - client: Client, - session: dict, - # approximation of recursive type annotation - tree: Union[str, List[Any]], - expected: str, - ): - storer = self.originate_storer(client, session) - - def deploy_tree(tree: Union[str, List[Any]]) -> str: - # leaf - if isinstance(tree, str): - # deploy and return caller str - return self.originate_appender(client, session, storer, tree) - # inner node - children = list(map(deploy_tree, tree)) - return self.originate_caller(client, session, children) - - root = deploy_tree(tree) - - client.transfer( - 0, - 'bootstrap2', - root, - ["--burn-cap", "5"], - ) - utils.bake(client, bake_for='bootstrap3') - assert client.get_storage(storer) == '"{}"'.format(expected) - - @pytest.mark.slow @pytest.mark.contract class TestContracts: -- GitLab