Revision 5c0277382a82ab3642ddd1de790a362e8c047837 authored by Pierre-Louis on 11 September 2023, 13:01:33 UTC, committed by Pierre-Louis on 25 September 2023, 12:16:22 UTC
1 parent 97eebdf
Raw File
contract_mini_scenarios.ml
(*****************************************************************************)
(*                                                                           *)
(* Open Source License                                                       *)
(* Copyright (c) 2021 Nomadic Labs <contact@nomadic-labs.com>                *)
(* Copyright (c) 2022 Marigold <contact@marigold.dev>                        *)
(*                                                                           *)
(* 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
   Invocation:   dune exec tezt/tests/main.exe -- --file contract_mini_scenarios.ml
   Subject:      Test mini scenarios
*)

let test_replay client ~protocol =
  Log.info "Replay 'originate'" ;
  let* _alias, contract =
    Client.originate_contract_at
      ~amount:Tez.zero
      ~src:Constant.bootstrap1.alias
      ~init:"Unit"
      ~burn_cap:Tez.one
      client
      ["mini_scenarios"; "replay"]
      protocol
  in
  Log.info "Replay transfer fail" ;
  let* () =
    Client.spawn_transfer
      ~amount:(Tez.of_int 10)
      ~giver:"bootstrap1"
      ~receiver:contract
      ~arg:"Unit"
      client
    |> Process.check_error ~msg:(rex "Internal operation replay attempt")
  in
  unit

let check_balance ~__LOC__ ~account client ~amount =
  let* contract_balance = Client.get_balance_for ~account client in
  Check.(contract_balance = Tez.of_int amount)
    Tez.typ
    ~__LOC__
    ~error_msg:"Expected balance %R, got %L" ;
  unit

let test_create_contract_balance client ~contract =
  check_balance ~__LOC__ ~account:contract ~amount:1000 client

let check_contract_storage ~__LOC__ client contract ~expected =
  let* storage = Client.contract_storage contract client in
  Check.(
    (String.trim storage = expected)
      string
      ~__LOC__
      ~error_msg:"Expected storage %R, got %L") ;
  unit

let extract_new_contract client_output =
  match client_output =~* rex "New contract ?(KT1\\w{33})" with
  | None ->
      Test.fail
        "Cannot extract new contract from client_output: %s"
        client_output
  | Some c -> return c

let test_create_contract client ~protocol =
  Log.info "Create contract 'originate'" ;
  let* _alias, create_contract =
    Client.originate_contract_at
      ~amount:(Tez.of_int 1000)
      ~src:Constant.bootstrap1.alias
      ~init:"Unit"
      ~burn_cap:Tez.one
      client
      ["mini_scenarios"; "create_contract"]
      protocol
  in
  let* () = test_create_contract_balance client ~contract:create_contract in
  Log.info "Test create contract perform creation" ;
  let* () =
    let process =
      Client.spawn_transfer
        ~burn_cap:(Tez.of_int 10)
        ~amount:Tez.zero
        ~giver:"bootstrap1"
        ~receiver:create_contract
        ~arg:"None"
        client
    in
    let* client_output = Process.check_and_read_stdout process in
    let* kt_1 = extract_new_contract client_output in
    let* () =
      check_contract_storage ~__LOC__ client kt_1 ~expected:"\"abcdefg\""
    in
    let* () = check_balance ~__LOC__ ~account:kt_1 client ~amount:100 in
    let* () =
      check_balance ~__LOC__ ~account:create_contract client ~amount:900
    in
    unit
  in
  unit

let test_default_account client ~protocol =
  Log.info "Default account 'originate'" ;
  let* _alias, default_account =
    Client.originate_contract_at
      ~amount:(Tez.of_int 1000)
      ~src:"bootstrap1"
      ~init:"Unit"
      ~burn_cap:Tez.one
      client
      ["mini_scenarios"; "default_account"]
      protocol
  in
  Log.info "Test default account transfer" ;
  let* () =
    let tz1 = Constant.bootstrap4.Account.public_key_hash in
    let arg = sf "\"%s\"" tz1 in
    let* () =
      Client.transfer
        ~burn_cap:(Tez.of_int 10)
        ~amount:Tez.zero
        ~giver:"bootstrap1"
        ~receiver:default_account
        ~arg
        client
    in
    let account = "tz1SuakBpFdG9b4twyfrSMqZzruxhpMeSrE5" in
    let arg = sf "\"%s\"" account in
    let* () =
      Client.transfer
        ~burn_cap:(Tez.of_int 10)
        ~amount:Tez.zero
        ~giver:"bootstrap1"
        ~receiver:default_account
        ~arg
        client
    in
    unit
  in
  unit

let test_preimage_and_signature client ~protocol =
  Log.info "Reveal signed preimage 'originate'" ;
  let* _alias, reveal_signed_preimage =
    let byt =
      "0x9995c2ef7bcc7ae3bd15bdd9b02dc6e877c27b26732340d641a4cbc6524813bb"
    in
    let sign = "p2pk66uq221795tFxT7jfNmXtBMdjMf6RAaxRTwv1dbuSHbH6yfqGwz" in
    let init = sf "Pair %s \"%s\"" byt sign in
    Client.originate_contract_at
      ~amount:(Tez.of_int 1000)
      ~src:"bootstrap1"
      ~init
      ~burn_cap:Tez.one
      client
      ["mini_scenarios"; "reveal_signed_preimage"]
      protocol
  in
  Log.info "Test wrong preimage" ;
  let* () =
    let byte =
      "0x050100000027566f756c657a2d766f757320636f75636865722061766563206d6f692c20636520736f6972"
    in
    let sign =
      "p2sigvgDSBnN1bUsfwyMvqpJA1cFhE5s5oi7SetJVQ6LJsbFrU2idPvnvwJhf5v9DhM9ZTX1euS9DgWozVw6BTHiK9VcQVpAU8"
    in
    let arg = sf "Pair %s \"%s\"" byte sign in
    Client.spawn_transfer
      ~amount:Tez.zero
      ~giver:"bootstrap1"
      ~receiver:reveal_signed_preimage
      ~arg
      ~burn_cap:(Tez.of_int 10)
      client
    |> Process.check_error ~msg:(rex "At line 8 characters 9 to 21")
  in
  Log.info "Test wrong signature" ;
  let* () =
    let byte =
      "0x050100000027566f756c657a2d766f757320636f75636865722061766563206d6f692c20636520736f6972203f"
    in
    let sign =
      "p2sigvgDSBnN1bUsfwyMvqpJA1cFhE5s5oi7SetJVQ6LJsbFrU2idPvnvwJhf5v9DhM9ZTX1euS9DgWozVw6BTHiK9VcQVpAU8"
    in
    let arg = sf "Pair %s \"%s\"" byte sign in
    Client.spawn_transfer
      ~amount:Tez.zero
      ~giver:"bootstrap1"
      ~receiver:reveal_signed_preimage
      ~arg
      ~burn_cap:(Tez.of_int 10)
      client
    |> Process.check_error ~msg:(rex "At line 15 characters 9 to 15")
  in
  Log.info "Test good preimage and signature" ;
  let* () =
    let byte =
      "0x050100000027566f756c657a2d766f757320636f75636865722061766563206d6f692c20636520736f6972203f"
    in
    let sign =
      "p2sigsceCzcDw2AeYDzUonj4JT341WC9Px4wdhHBxbZcG1FhfqFVuG7f2fGCzrEHSAZgrsrQWpxduDPk9qZRgrpzwJnSHC3gZJ"
    in
    let arg = sf "Pair %s \"%s\"" byte sign in
    let* () =
      Client.transfer
        ~amount:Tez.zero
        ~giver:"bootstrap1"
        ~receiver:reveal_signed_preimage
        ~arg
        ~burn_cap:(Tez.of_int 10)
        client
    in
    unit
  in
  unit

(* Test vote_for_delegate *)
let test_vote_for_delegate client ~protocol =
  Log.info "vote for delegate 'originate" ;
  let* _alias, vote_for_delegate =
    let b_3 = Constant.bootstrap3.Account.public_key_hash in
    let b_4 = Constant.bootstrap4.Account.public_key_hash in
    let init = sf {|(Pair (Pair "%s" None) (Pair "%s" None))|} b_3 b_4 in
    Client.originate_contract_at
      ~amount:(Tez.of_int 1000)
      ~src:"bootstrap1"
      ~init
      ~burn_cap:Tez.one
      client
      ["mini_scenarios"; "vote_for_delegate"]
      protocol
  in
  let* delegate_opt = Client.get_delegate ~src:vote_for_delegate client in
  let () =
    Check.((delegate_opt = None) (option string))
      ~error_msg:"expected delegate %R, got %L"
  in
  Log.info "Test vote for delegate wrong identity1" ;
  let* () =
    Client.spawn_transfer
      ~amount:Tez.zero
      ~giver:"bootstrap1"
      ~receiver:vote_for_delegate
      ~arg:"None"
      ~burn_cap:(Tez.of_int 10)
      client
    |> Process.check_error ~msg:(rex "At line 14 characters 9 to 12")
  in
  Log.info "Test vote for delegate wrong identity2" ;
  let* () =
    Client.spawn_transfer
      ~amount:Tez.zero
      ~giver:"bootstrap2"
      ~receiver:vote_for_delegate
      ~arg:"None"
      ~burn_cap:(Tez.of_int 10)
      client
    |> Process.check_error ~msg:(rex "At line 14 characters 9 to 12")
  in
  Log.info "Test vote for delegate b3 vote for b5" ;
  let* () =
    let b_5 = Constant.bootstrap5.Account.public_key_hash in
    let arg = sf {|(Some "%s")|} b_5 in
    let* () =
      Client.transfer
        ~amount:Tez.zero
        ~giver:"bootstrap3"
        ~receiver:vote_for_delegate
        ~arg
        ~burn_cap:(Tez.of_int 10)
        client
    in
    let b_3 = Constant.bootstrap3.Account.public_key_hash in
    let b_4 = Constant.bootstrap4.Account.public_key_hash in
    let expected =
      sf
        "Pair (Pair \"%s\"\n           (Some \"%s\"))\n     \"%s\"\n     None"
        b_3
        b_5
        b_4
    in
    let* () =
      check_contract_storage ~__LOC__ client vote_for_delegate ~expected
    in
    unit
  in
  Log.info "Test vote for delegate still no delegate1" ;
  let* () =
    let* delegate_opt = Client.get_delegate ~src:vote_for_delegate client in
    let () =
      Check.((delegate_opt = None) (option string))
        ~error_msg:"expected delegate %R, got %L"
    in
    unit
  in
  Log.info "Test vote for delegate b4 vote for b2" ;
  let* () =
    let b_2 = Constant.bootstrap2.Account.public_key_hash in
    let arg = sf {|(Some "%s")|} b_2 in
    let* () =
      Client.transfer
        ~amount:Tez.zero
        ~giver:"bootstrap4"
        ~receiver:vote_for_delegate
        ~arg
        ~burn_cap:(Tez.of_int 10)
        client
    in
    let b_3 = Constant.bootstrap3.Account.public_key_hash in
    let b_4 = Constant.bootstrap4.Account.public_key_hash in
    let b_5 = Constant.bootstrap5.Account.public_key_hash in
    let expected =
      sf
        "Pair (Pair \"%s\"\n\
        \           (Some \"%s\"))\n\
        \     \"%s\"\n\
        \     (Some \"%s\")"
        b_3
        b_5
        b_4
        b_2
    in
    let* () =
      check_contract_storage ~__LOC__ client vote_for_delegate ~expected
    in
    unit
  in
  Log.info "Test vote for delegate still no delegate2" ;
  let* () =
    let* delegate_opt = Client.get_delegate ~src:vote_for_delegate client in
    let () =
      Check.((delegate_opt = None) (option string))
        ~error_msg:"expected delegate %R, got %L"
    in
    unit
  in
  Log.info "Test vote for delegate b4 vote for b5" ;
  let* () =
    let b_5 = Constant.bootstrap5.Account.public_key_hash in
    let arg = sf {|(Some "%s")|} b_5 in
    let* () =
      Client.transfer
        ~amount:Tez.zero
        ~giver:"bootstrap4"
        ~receiver:vote_for_delegate
        ~arg
        ~burn_cap:(Tez.of_int 10)
        client
    in
    let b_3 = Constant.bootstrap3.Account.public_key_hash in
    let b_4 = Constant.bootstrap4.Account.public_key_hash in
    let expected =
      sf
        "Pair (Pair \"%s\"\n\
        \           (Some \"%s\"))\n\
        \     \"%s\"\n\
        \     (Some \"%s\")"
        b_3
        b_5
        b_4
        b_5
    in
    let* () =
      check_contract_storage ~__LOC__ client vote_for_delegate ~expected
    in
    unit
  in
  Log.info "Test vote for delegate has delegate" ;
  let* () =
    let b_5 = Constant.bootstrap5.Account.public_key_hash in
    let* delegate_opt = Client.get_delegate ~src:vote_for_delegate client in
    let () =
      Check.((delegate_opt = Some b_5) (option string))
        ~error_msg:"expected delegate %R, got %L"
    in
    unit
  in
  unit

let test_multiple_entrypoints_counter client ~protocol =
  let* _alias, contract =
    Client.originate_contract_at
      ~amount:Tez.zero
      ~src:"bootstrap5"
      ~init:"None"
      ~burn_cap:Tez.one
      client
      ["mini_scenarios"; "multiple_entrypoints_counter"]
      protocol
  in
  (* call contract: creates the internal contract and calls it. *)
  let* () =
    Client.transfer
      ~amount:Tez.zero
      ~giver:"bootstrap1"
      ~receiver:contract
      ~burn_cap:(Tez.of_int 10)
      client
  in
  let* () = check_contract_storage ~__LOC__ client contract ~expected:"None" in
  unit

(* Test that the [noop.tz] contract can be originated, typechecks and can
   receive a transaction. *)
let test_contract_noop client ~protocol =
  let burn_cap = Tez.one in
  let prg = Michelson_script.(find ["opcodes"; "noop"] protocol |> path) in
  let* () = Client.remember_script client ~alias:"noop" ~src:("file:" ^ prg) in
  let* () = Client.typecheck_script client ~scripts:[prg] in
  let* _contract =
    Client.originate_contract
      ~alias:"noop"
      ~amount:(Tez.of_int 1000)
      ~src:"bootstrap1"
      ~prg
      ~init:"Unit"
      ~burn_cap
      client
  in
  let* () =
    Client.transfer
      ~amount:(Tez.of_int 10)
      ~giver:"bootstrap1"
      ~receiver:"noop"
      ~burn_cap
      ~arg:"Unit"
      client
  in
  unit

(* Test that [hardlimit.tz] initialized with [3] fails after the
   third transfer *)
let test_contract_hardlimit client ~protocol =
  let burn_cap = Tez.one in
  let* hardlimit, _address =
    Client.originate_contract_at
      ~amount:(Tez.of_int 1000)
      ~src:"bootstrap1"
      ~init:"3"
      ~burn_cap
      client
      ["mini_scenarios"; "hardlimit"]
      protocol
  in
  let spawn_transfer () =
    Client.spawn_transfer
      ~amount:(Tez.of_int 10)
      ~giver:"bootstrap1"
      ~receiver:hardlimit
      ~burn_cap
      ~arg:"Unit"
      client
  in
  let* () = spawn_transfer () |> Process.check in
  let* () = spawn_transfer () |> Process.check in
  let* () = spawn_transfer () |> Process.check in
  let* () =
    spawn_transfer ()
    |> Process.check_error ~msg:(rex "script reached FAILWITH instruction")
  in
  unit

let register ~protocols =
  List.iter
    (fun (title, test_function) ->
      Protocol.register_test
        ~__FILE__
        ~title
        ~tags:["client"; "michelson"; "mini_scenarios"]
        (fun protocol ->
          let* client = Client.init_mockup ~protocol () in
          test_function client ~protocol)
        protocols)
    [
      ("test create contract balance", test_create_contract);
      ("test replay", test_replay);
      ("test default account originate and transfer", test_default_account);
      ("test preimage and signature", test_preimage_and_signature);
      ("test vote for delegate", test_vote_for_delegate);
      ("test multiple entrypoints counter", test_multiple_entrypoints_counter);
      ("test contract noop", test_contract_noop);
      ("test contract hardlimit", test_contract_hardlimit);
    ]
back to top