Raw File
run_script.ml
(*****************************************************************************)
(*                                                                           *)
(* Open Source License                                                       *)
(* Copyright (c) 2021 Nomadic Labs <contact@nomadic-labs.com>                *)
(*                                                                           *)
(* 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 octez-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 check_contract addr =
  prg
    "address"
    (Printf.sprintf "PUSH address %s; CONTRACT nat; ASSERT_SOME; ADDRESS" addr)

let test_balance_and_self_address =
  Protocol.register_test
    ~__FILE__
    ~title:"Run script with balance and self address"
    ~tags:["client"; "michelson"]
    ~uses_node:false
  @@ fun 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 with it. *)
  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 one. *)
  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.register_test
    ~__FILE__
    ~title:"Run script with source and sender"
    ~tags:["client"; "michelson"]
    ~uses_node:false
  @@ fun 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 SENDER, but SOURCE is the
     zero address. *)
  let expected_source = "0x00000000000000000000000000000000000000000000" in
  let* _storage =
    Client.run_script
      ~source:"bootstrap1"
      ~prg:check_source
      ~storage:"Unit"
      ~input:expected_source
      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 test_other_contracts =
  Protocol.register_test
    ~__FILE__
    ~title:"Run script with other_contracts"
    ~tags:["client"; "michelson"]
    ~uses_node:false
    ~supports:(Protocol.From_protocol 018)
  @@ fun protocol ->
  let* client = Client.init_mockup ~protocol () in
  let unused_address = {|"KT1Q36KWPSba7dHsH5E4ZsQHehrChc51e19d"|} in
  let* _storage =
    Client.run_script
      ~prg:(check_contract unused_address)
      ~storage:"Unit"
      ~input:unused_address
      ~other_contracts:(Printf.sprintf "{Contract %s nat}" unused_address)
      client
  in
  unit

let test_extra_big_maps =
  Protocol.register_test
    ~__FILE__
    ~title:"Run script with extra_big_maps"
    ~tags:["client"; "michelson"]
    ~uses_node:false
    ~supports:(Protocol.From_protocol 018)
  @@ fun protocol ->
  let* client = Client.init_mockup ~protocol () in
  let* {storage; _} =
    Client.run_script
      ~prg:
        {|parameter unit; storage (pair string (big_map nat string)); code {CDR; CDR; DUP; PUSH nat 42; GET; ASSERT_SOME; PAIR; NIL operation; PAIR}|}
      ~storage:{|Pair "" 4|}
      ~input:{|Unit|}
      ~extra_big_maps:{|{Big_map 4 nat string {Elt 42 "foobar"}}|}
      client
  in
  assert (storage = {|(Pair "foobar" 4)|}) ;
  unit

let register ~protocols =
  test_balance_and_self_address protocols ;
  test_source_and_sender protocols ;
  test_other_contracts protocols ;
  test_extra_big_maps protocols
back to top