diff --git a/CHANGES.rst b/CHANGES.rst index d3ccc2d1ce7fba1aadf0462c59e3e5776b593ad8..46e44c78eec8aa853f2e7dc9e371dfeb5f6fdc4a 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -39,6 +39,12 @@ Client makes the client inject the transaction in a node even if the simulation of the transaction fails. +- A new ``--self-address`` option was added to the ``run script`` + command. It makes the given address be considered the address of + the contract being run. The address must actually exist in the + context. If ``--balance`` wasn't specified, the script also + inherits the given contract's balance. + Baker / Endorser / Accuser -------------------------- diff --git a/src/proto_alpha/lib_client/client_proto_args.ml b/src/proto_alpha/lib_client/client_proto_args.ml index f933269bc855c3d9791bb3b348880b40f4749bae..d7432434452916f337f3907d7f5ee60d1fc9563c 100644 --- a/src/proto_alpha/lib_client/client_proto_args.ml +++ b/src/proto_alpha/lib_client/client_proto_args.ml @@ -247,6 +247,13 @@ let tez_arg ~default ~parameter ~doc = ~default (tez_parameter ("--" ^ parameter)) +let tez_opt_arg ~parameter ~doc = + arg + ~long:parameter + ~placeholder:"amount" + ~doc + (tez_parameter ("--" ^ parameter)) + let tez_param ~name ~desc next = Clic.param ~name diff --git a/src/proto_alpha/lib_client/client_proto_args.mli b/src/proto_alpha/lib_client/client_proto_args.mli index 3b1a2aac0594d90074a755fe4ac05b28bc5d017a..5ff707bf87459667838eba1664ade8b894bdc317 100644 --- a/src/proto_alpha/lib_client/client_proto_args.mli +++ b/src/proto_alpha/lib_client/client_proto_args.mli @@ -99,6 +99,9 @@ val no_confirmation : (bool, full) Clic.arg val tez_arg : default:string -> parameter:string -> doc:string -> (Tez.t, full) Clic.arg +val tez_opt_arg : + parameter:string -> doc:string -> (Tez.t option, full) Clic.arg + val tez_param : name:string -> desc:string -> diff --git a/src/proto_alpha/lib_client/client_proto_programs.ml b/src/proto_alpha/lib_client/client_proto_programs.ml index 3d099a41cbc25098db9543989b6f98cbaebb1bf5..518aa3c40677356220ef265c9306bbb784ce6a63 100644 --- a/src/proto_alpha/lib_client/client_proto_programs.ml +++ b/src/proto_alpha/lib_client/client_proto_programs.ml @@ -139,10 +139,11 @@ type run_view_params = { type run_params = { shared_params : simulation_params; amount : Tez.t option; - balance : Tez.t; + balance : Tez.t option; program : Michelson_v1_parser.parsed; storage : Michelson_v1_parser.parsed; entrypoint : Entrypoint.t option; + self : Contract.t option; } let run_view (cctxt : #Protocol_client_context.rpc_context) @@ -179,6 +180,7 @@ let run (cctxt : #Protocol_client_context.rpc_context) balance; storage; entrypoint; + self; } = params in @@ -193,10 +195,11 @@ let run (cctxt : #Protocol_client_context.rpc_context) ~storage:storage.expanded ~input:input.expanded ~amount - ~balance + ?balance ~chain_id ~source ~payer + ~self ~now ~level @@ -210,6 +213,7 @@ let trace (cctxt : #Protocol_client_context.rpc_context) balance; storage; entrypoint; + self; } = params in @@ -224,10 +228,11 @@ let trace (cctxt : #Protocol_client_context.rpc_context) ~storage:storage.expanded ~input:input.expanded ~amount - ~balance + ?balance ~chain_id ~source ~payer + ~self ~now ~level diff --git a/src/proto_alpha/lib_client/client_proto_programs.mli b/src/proto_alpha/lib_client/client_proto_programs.mli index 118a167a54f02da043914871382330a18842bbf5..a2e74ec6208055f6d9712a24fe01f68b23432bdc 100644 --- a/src/proto_alpha/lib_client/client_proto_programs.mli +++ b/src/proto_alpha/lib_client/client_proto_programs.mli @@ -54,10 +54,11 @@ type run_view_params = { type run_params = { shared_params : simulation_params; amount : Tez.t option; - balance : Tez.t; + balance : Tez.t option; program : Michelson_v1_parser.parsed; storage : Michelson_v1_parser.parsed; entrypoint : Entrypoint.t option; + self : Contract.t option; } val run_view : diff --git a/src/proto_alpha/lib_client_commands/client_proto_programs_commands.ml b/src/proto_alpha/lib_client_commands/client_proto_programs_commands.ml index 18048c5e4f08bb860cd65e3b30e28b39065c4a01..737b858c36e79581da9b0316db96d3af9f4fe783 100644 --- a/src/proto_alpha/lib_client_commands/client_proto_programs_commands.ml +++ b/src/proto_alpha/lib_client_commands/client_proto_programs_commands.ml @@ -96,11 +96,16 @@ let commands () = ~doc:"name of the payer (i.e. SOURCE) contract for the transaction" () in + let self_arg = + ContractAlias.destination_arg + ~name:"self-address" + ~doc:"address of the contract (i.e. SELF_ADDRESS) for the transaction" + () + in let balance_arg = - Client_proto_args.tez_arg + Client_proto_args.tez_opt_arg ~parameter:"balance" ~doc:"balance of run contract in \xEA\x9C\xA9" - ~default:"4_000_000" in let now_arg = Client_proto_args.now_arg in let level_arg = Client_proto_args.level_arg in @@ -235,12 +240,13 @@ let commands () = command ~group ~desc:"Ask the node to run a script." - (args11 + (args12 trace_stack_switch amount_arg balance_arg source_arg payer_arg + self_arg no_print_source_flag run_gas_limit_arg entrypoint_arg @@ -259,6 +265,7 @@ let commands () = balance, source, payer, + self, no_print_source, gas, entrypoint, @@ -271,6 +278,7 @@ let commands () = cctxt -> let source = Option.map snd source in let payer = Option.map snd payer in + let self = Option.map snd self in Lwt.return @@ Micheline_parser.no_parsing_error program >>=? fun program -> let show_source = not no_print_source in @@ -287,6 +295,7 @@ let commands () = shared_params = {input; unparsing_mode; now; level; source; payer; gas}; entrypoint; + self; } >>= fun res -> print_trace_result cctxt ~show_source ~parsed:program res @@ -303,6 +312,7 @@ let commands () = shared_params = {input; unparsing_mode; now; level; source; payer; gas}; entrypoint; + self; } >>= fun res -> print_run_result cctxt ~show_source ~parsed:program res); command diff --git a/src/proto_alpha/lib_plugin/plugin.ml b/src/proto_alpha/lib_plugin/plugin.ml index f496a451dd62c90b01688ab1ac98a090df508e3e..1270254f0ffbeadabb8fe1c3099deceba89bcfee 100644 --- a/src/proto_alpha/lib_plugin/plugin.ml +++ b/src/proto_alpha/lib_plugin/plugin.ml @@ -1559,14 +1559,15 @@ module RPC = struct (req "storage" Script.expr_encoding) (req "input" Script.expr_encoding) (req "amount" Tez.encoding) - (req "balance" Tez.encoding) + (opt "balance" Tez.encoding) (req "chain_id" Chain_id.encoding) (opt "source" Contract.encoding) (opt "payer" Contract.encoding) - (opt "gas" Gas.Arith.z_integral_encoding) + (opt "self" Contract.encoding) (dft "entrypoint" Entrypoint.simple_encoding Entrypoint.default)) - (obj3 + (obj4 (opt "unparsing_mode" unparsing_mode_encoding) + (opt "gas" Gas.Arith.z_integral_encoding) (opt "now" Script_timestamp.encoding) (opt "level" Script_int.n_encoding)) @@ -2127,6 +2128,21 @@ module RPC = struct let ctxt = Cache.Admin.future_cache_expectation ctxt ~time_in_blocks in run_operation_service ctxt () (op, chain_id) + let default_from_context ctxt get = function + | None -> get ctxt + | Some x -> return x + + (* A convenience type for return values of [ensure_contracts_exist] below. *) + type run_code_config = { + balance : Tez.t; + self : Contract.t; + payer : Contract.t; + source : Contract.t; + } + + (* 4_000_000 ꜩ *) + let default_balance = Tez.of_mutez_exn 4_000_000_000_000L + let register () = let originate_dummy_contract ctxt script balance = let ctxt = Origination_nonce.init ctxt Operation_hash.zero in @@ -2146,6 +2162,27 @@ module RPC = struct balance >>=? fun (ctxt, _) -> return (ctxt, dummy_contract) in + let configure_contracts ctxt script balance ~src_opt ~pay_opt ~self_opt = + (match self_opt with + | None -> + let balance = Option.value ~default:default_balance balance in + originate_dummy_contract ctxt script balance + >>=? fun (ctxt, addr) -> return (ctxt, addr, balance) + | Some addr -> + default_from_context + ctxt + (fun c -> Contract.get_balance c addr) + balance + >>=? fun bal -> return (ctxt, addr, bal)) + >>=? fun (ctxt, self, balance) -> + let (source, payer) = + match (src_opt, pay_opt) with + | (None, None) -> (self, self) + | (Some c, None) | (None, Some c) -> (c, c) + | (Some src, Some pay) -> (src, pay) + in + return (ctxt, {balance; self; source; payer}) + in let script_entrypoint_type ctxt expr entrypoint = let ctxt = Gas.set_unlimited ctxt in let legacy = false in @@ -2176,24 +2213,23 @@ module RPC = struct amount, balance, chain_id, - source, - payer, - gas, + src_opt, + pay_opt, + self_opt, entrypoint ), - (unparsing_mode, now, level) ) + (unparsing_mode, gas, now, level) ) -> let unparsing_mode = Option.value ~default:Readable unparsing_mode in let storage = Script.lazy_expr storage in let code = Script.lazy_expr code in - originate_dummy_contract ctxt {storage; code} balance - >>=? fun (ctxt, dummy_contract) -> - let (source, payer) = - match (source, payer) with - | (Some source, Some payer) -> (source, payer) - | (Some source, None) -> (source, source) - | (None, Some payer) -> (payer, payer) - | (None, None) -> (dummy_contract, dummy_contract) - in + configure_contracts + ctxt + {storage; code} + balance + ~src_opt + ~pay_opt + ~self_opt + >>=? fun (ctxt, {self; source; payer; balance}) -> let gas = match gas with | Some gas -> gas @@ -2212,16 +2248,7 @@ module RPC = struct in let step_constants = let open Script_interpreter in - { - source; - payer; - self = dummy_contract; - amount; - balance; - chain_id; - now; - level; - } + {source; payer; self; amount; balance; chain_id; now; level} in Script_interpreter.execute ctxt @@ -2251,24 +2278,23 @@ module RPC = struct amount, balance, chain_id, - source, - payer, - gas, + src_opt, + pay_opt, + self_opt, entrypoint ), - (unparsing_mode, now, level) ) + (unparsing_mode, gas, now, level) ) -> let unparsing_mode = Option.value ~default:Readable unparsing_mode in let storage = Script.lazy_expr storage in let code = Script.lazy_expr code in - originate_dummy_contract ctxt {storage; code} balance - >>=? fun (ctxt, dummy_contract) -> - let (source, payer) = - match (source, payer) with - | (Some source, Some payer) -> (source, payer) - | (Some source, None) -> (source, source) - | (None, Some payer) -> (payer, payer) - | (None, None) -> (dummy_contract, dummy_contract) - in + configure_contracts + ctxt + {storage; code} + balance + ~src_opt + ~pay_opt + ~self_opt + >>=? fun (ctxt, {self; source; payer; balance}) -> let gas = match gas with | Some gas -> gas @@ -2287,16 +2313,7 @@ module RPC = struct in let step_constants = let open Script_interpreter in - { - source; - payer; - self = dummy_contract; - amount; - balance; - chain_id; - now; - level; - } + {source; payer; self; amount; balance; chain_id; now; level} in let module Unparsing_mode = struct let unparsing_mode = unparsing_mode @@ -2565,9 +2582,9 @@ module RPC = struct map [] ) )) - let run_code ?unparsing_mode ?gas ?(entrypoint = Entrypoint.default) ~script - ~storage ~input ~amount ~balance ~chain_id ~source ~payer ~now ~level - ctxt block = + let run_code ?unparsing_mode ?gas ?(entrypoint = Entrypoint.default) + ?balance ~script ~storage ~input ~amount ~chain_id ~source ~payer ~self + ~now ~level ctxt block = RPC_context.make_call0 S.run_code ctxt @@ -2581,13 +2598,13 @@ module RPC = struct chain_id, source, payer, - gas, + self, entrypoint ), - (unparsing_mode, now, level) ) + (unparsing_mode, gas, now, level) ) let trace_code ?unparsing_mode ?gas ?(entrypoint = Entrypoint.default) - ~script ~storage ~input ~amount ~balance ~chain_id ~source ~payer ~now - ~level ctxt block = + ?balance ~script ~storage ~input ~amount ~chain_id ~source ~payer ~self + ~now ~level ctxt block = RPC_context.make_call0 S.trace_code ctxt @@ -2601,9 +2618,9 @@ module RPC = struct chain_id, source, payer, - gas, + self, entrypoint ), - (unparsing_mode, now, level) ) + (unparsing_mode, gas, now, level) ) let run_view ?gas ~contract ~entrypoint ~input ~chain_id ~now ~level ?source ?payer ~unparsing_mode ctxt block = @@ -3207,8 +3224,9 @@ module RPC = struct | (levels, cycles) -> (* explicitly fail when requested levels or cycle are in the past... or too far in the future... - TODO-TB: this old comment (from version Alpha) conflicts with - the specification of the RPCs that use this code. + TODO: https://gitlab.com/tezos/tezos/-/issues/2335 + this old comment (from version Alpha) conflicts with + the specification of the RPCs that use this code. *) List.sort_uniq Level.compare diff --git a/tezt/lib_tezos/client.ml b/tezt/lib_tezos/client.ml index 46f02e10e110153c53ea788e9f8a7eb069ebb5c0..46aa9c5845033709cc0c98a790f61b3f16c9076d 100644 --- a/tezt/lib_tezos/client.ml +++ b/tezt/lib_tezos/client.ml @@ -78,6 +78,9 @@ let address ?(hostname = false) ?from peer = | Some endpoint -> Runner.address ~hostname ?from:(runner endpoint) (runner peer) +let optional_arg ~name f = + Option.fold ~none:[] ~some:(fun x -> ["--" ^ name; f x]) + let create_with_mode ?(path = Constant.tezos_client) ?(admin_path = Constant.tezos_admin_client) ?name ?(color = Log.Color.FG.blue) ?base_dir mode = @@ -890,15 +893,30 @@ let stresstest ?endpoint ?source_aliases ?source_pkhs ?source_accounts ?seed client |> Process.check -let spawn_run_script ?hooks ~src ~storage ~input client = +let spawn_run_script ?hooks ?balance ?self_address ?source ?payer ~prg ~storage + ~input client = spawn_command ?hooks client - ["run"; "script"; src; "on"; "storage"; storage; "and"; "input"; input] + (["run"; "script"; prg; "on"; "storage"; storage; "and"; "input"; input] + @ optional_arg ~name:"payer" Fun.id payer + @ optional_arg ~name:"source" Fun.id source + @ optional_arg ~name:"balance" Tez.to_string balance + @ optional_arg ~name:"self-address" Fun.id self_address) -let run_script ?hooks ~src ~storage ~input client = +let run_script ?hooks ?balance ?self_address ?source ?payer ~prg ~storage ~input + client = let* client_output = - spawn_run_script ?hooks ~src ~storage ~input client + spawn_run_script + ?hooks + ?balance + ?source + ?payer + ?self_address + ~prg + ~storage + ~input + client |> Process.check_and_read_stdout in match client_output =~* rex "storage\n(.*)" with diff --git a/tezt/lib_tezos/client.mli b/tezt/lib_tezos/client.mli index 0664566483ee501b8d79fa8a6acb82f454df8124..5cb6999675cc19a3082cc607ce709f655c5f6270 100644 --- a/tezt/lib_tezos/client.mli +++ b/tezt/lib_tezos/client.mli @@ -372,7 +372,8 @@ val spawn_propose_for : t -> Process.t -(* TODO refactor this *) +(* TODO: https://gitlab.com/tezos/tezos/-/issues/2336 + refactor this *) (** [propose_for] *) val propose_for : @@ -561,8 +562,10 @@ val submit_ballot : val spawn_submit_ballot : ?key:string -> ?wait:string -> proto_hash:string -> ballot -> t -> Process.t -(* TODO: [amount] should be named [transferring] *) -(* TODO: [src] should be named [from] and probably have type [Account.t] *) +(* TODO: https://gitlab.com/tezos/tezos/-/issues/2336 + [amount] should be named [transferring] *) +(* TODO: https://gitlab.com/tezos/tezos/-/issues/2336 + [src] should be named [from] and probably have type [Account.t] *) (** Run [tezos-client originate contract alias transferring amount from src running prg]. Returns the originated contract hash *) @@ -660,7 +663,11 @@ val spawn_stresstest : Fails if the new storage cannot be extracted from the output. *) val run_script : ?hooks:Process.hooks -> - src:string -> + ?balance:Tez.t -> + ?self_address:string -> + ?source:string -> + ?payer:string -> + prg:string -> storage:string -> input:string -> t -> @@ -669,7 +676,11 @@ val run_script : (** Same as [run_script] but do not wait for the process to exit. *) val spawn_run_script : ?hooks:Process.hooks -> - src:string -> + ?balance:Tez.t -> + ?self_address:string -> + ?source:string -> + ?payer:string -> + prg:string -> storage:string -> input:string -> t -> diff --git a/tezt/tests/main.ml b/tezt/tests/main.ml index f29f347d270ebb472d76234b4f985b357e314aa7..dd24219d15299d3a38db2558af6e3ee289875712 100644 --- a/tezt/tests/main.ml +++ b/tezt/tests/main.ml @@ -110,5 +110,7 @@ let () = Sc_rollup.register ~protocols:[Alpha] ; Views.register ~protocols:[Alpha] () ; Runtime_script_failure.register ~protocols ; + (* Relies on a feature only available since J. *) + Run_script.register ~protocols:[Alpha] ; (* Test.run () should be the last statement, don't register afterwards! *) Test.run () diff --git a/tezt/tests/mockup.ml b/tezt/tests/mockup.ml index 6ee83ce30da45fe3e826dbf7e5ba2b0f6ce5d47a..7201e2a558ab7695740c78495b9bb223501a1eee 100644 --- a/tezt/tests/mockup.ml +++ b/tezt/tests/mockup.ml @@ -127,7 +127,7 @@ let test_calling_contract_with_global_constant_success ~protocols = let script = "file:./tezt/tests/contracts/proto_alpha/constant_999.tz" in let storage = "0" in let input = "Unit" in - let* result = Client.run_script ~src:script ~storage ~input client in + let* result = Client.run_script ~prg:script ~storage ~input client in let result = String.trim result in Log.info "Contract with constant output storage %s" result ; if result = value then return () @@ -144,7 +144,7 @@ let test_calling_contract_with_global_constant_failure ~protocols = let script = "file:./tezt/tests/contracts/proto_alpha/constant_999.tz" in let storage = "0" in let input = "Unit" in - let process = Client.spawn_run_script ~src:script ~storage ~input client in + let process = Client.spawn_run_script ~prg:script ~storage ~input client in Process.check_error ~exit_code:1 ~msg:(rex "No registered global was found") diff --git a/tezt/tests/run_script.ml b/tezt/tests/run_script.ml new file mode 100644 index 0000000000000000000000000000000000000000..1e8ccfd59b66b70c220f8c074e1e936dcc282ffa --- /dev/null +++ b/tezt/tests/run_script.ml @@ -0,0 +1,224 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 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 + Invocation: dune exec tezt/tests/main.exe -- --file run_script.ml + Subject: Check that run script command to tezos-client behaves correctly + *) + +(* This script checks result of some arbitrary instruction against the + expected value. Return type and name of the instruction should be + given by arguments [ty] and [instr] respectively. The expected + value should be passed to the contract as parameter. If the actual + state matches the expected one, the contract succeeds, otherwise it + fails with a pair consisting of the expected and the actual + values. *) +let prg_template : ('a -> 'b -> 'c -> 'd, unit, string) format = + {| +parameter %s ; /* type */ +storage unit ; +code { + UNPAIR ; + DUP ; + %s ; /* instr */ + IFCMPEQ { DROP } + { + PUSH string "expected" ; + PAIR ; + %s; /* instr */ + PUSH string "actual" ; + PAIR ; + PAIR ; + FAILWITH ; + } ; + NIL operation ; + PAIR ; + } +|} + +let prg ty instr = Format.sprintf prg_template ty instr instr + +let check_balance = prg "mutez" "BALANCE" + +let check_self_address = prg "address" "SELF_ADDRESS" + +let check_sender = prg "address" "SENDER" + +let check_source = prg "address" "SOURCE" + +let test_balance_and_self_address ~protocol () = + let* client = Client.init_mockup ~protocol () in + (* With no parameters, the default BALANCE is 4 000 000 ꜩ. *) + let* _storage = + Client.run_script + ~prg:check_balance + ~storage:"Unit" + ~input:"4000000000000" + client + in + + (* When --balance is given, BALANCE should match the expected value. *) + let* _storage = + Client.run_script + ~balance:(Tez.of_int 1) + ~prg:check_balance + ~storage:"Unit" + ~input:"1000000" + client + in + + let* self_address = + Client.originate_contract + ~burn_cap:(Tez.of_int 1) + ~alias:"test_contract" + ~amount:(Tez.of_int 100) + ~src:"bootstrap1" + ~prg:check_self_address + client + in + + (* When --self-address is given, SELF_ADDRESS should match the given. *) + let* _storage = + Client.run_script + ~self_address + ~prg:check_self_address + ~storage:"Unit" + ~input:(Format.sprintf "%S" self_address) + client + in + (* When --self-address is given, BALANCE should be equal to that of the + given account. *) + let* _storage = + Client.run_script + ~self_address + ~prg:check_balance + ~storage:"Unit" + ~input:"100000000" + client + in + + (* When both --self-address and --balance are given, the BALANCE should be + equal to the given value and SELF_ADDRESS should still match the given. *) + let* _storage = + Client.run_script + ~balance:(Tez.of_int 1) + ~self_address + ~prg:check_self_address + ~storage:"Unit" + ~input:(Format.sprintf "%S" self_address) + client + in + let* _storage = + Client.run_script + ~balance:(Tez.of_int 1) + ~self_address + ~prg:check_balance + ~storage:"Unit" + ~input:"1000000" + client + in + unit + +let test_source_and_sender ~protocol () = + let* client = Client.init_mockup ~protocol () in + let* bootstrap1 = Client.show_address ~alias:"bootstrap1" client in + let* bootstrap2 = Client.show_address ~alias:"bootstrap2" client in + + (* When --payer is absent, --source sets *both* SENDER and SOURCE. *) + let* _storage = + Client.run_script + ~source:"bootstrap1" + ~prg:check_source + ~storage:"Unit" + ~input:(Format.sprintf "%S" bootstrap1.public_key_hash) + client + in + let* _storage = + Client.run_script + ~source:"bootstrap1" + ~prg:check_sender + ~storage:"Unit" + ~input:(Format.sprintf "%S" bootstrap1.public_key_hash) + client + in + + (* When --source is absent, --payer sets *both* SENDER and SOURCE. *) + let* _storage = + Client.run_script + ~payer:"bootstrap1" + ~prg:check_source + ~storage:"Unit" + ~input:(Format.sprintf "%S" bootstrap1.public_key_hash) + client + in + let* _storage = + Client.run_script + ~payer:"bootstrap1" + ~prg:check_sender + ~storage:"Unit" + ~input:(Format.sprintf "%S" bootstrap1.public_key_hash) + client + in + + (* When both --source and --payer are given, their values may differ. *) + let* _storage = + Client.run_script + ~payer:"bootstrap1" + ~source:"bootstrap2" + ~prg:check_source + ~storage:"Unit" + ~input:(Format.sprintf "%S" bootstrap1.public_key_hash) + client + in + let* _storage = + Client.run_script + ~payer:"bootstrap1" + ~source:"bootstrap2" + ~prg:check_sender + ~storage:"Unit" + ~input:(Format.sprintf "%S" bootstrap2.public_key_hash) + client + in + unit + +let make_for ~protocol () = + List.iter + (fun (title, f) -> + Test.register ~__FILE__ ~title ~tags:["client"; "michelson"] f) + [ + ( "Run script with balance and self address", + test_balance_and_self_address ~protocol ); + ("Run script with source and sender", test_source_and_sender ~protocol); + ] + +let register ~protocols = + List.iter + (function + | Protocol.Alpha as protocol -> make_for ~protocol () + | Protocol.Hangzhou | Protocol.Ithaca -> ()) + (* Won't work prior to protocol J. *) + protocols