Raw File
demo_protocols.ml
(*****************************************************************************)
(*                                                                           *)
(* Open Source License                                                       *)
(* Copyright (c) 2022 G.B. Fefe  <gb.fefe@protonmail.com>                    *)
(* Copyright (c) 2020 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:    Demo protocols counter and noops
   Invocation:   dune exec tezt/tests/main.exe -- --file demo_protocols.ml
   Subject:      Minimal tests of demo protocols counter and noops
*)

let check_protocol ?protocol_hash ~__LOC__ client expected =
  let* {protocol; _} =
    Client.RPC.call ?protocol_hash client @@ RPC.get_chain_block_metadata ()
  in
  Check.(
    (protocol = expected)
      string
      ~__LOC__
      ~error_msg:"Expected head protocol to be %R, got %L") ;
  unit

let check_level ?protocol_hash ~__LOC__ client expected =
  let* header =
    Client.RPC.call ?protocol_hash client @@ RPC.get_chain_block_header ()
  in
  let level = JSON.(header |-> "level" |> as_int) in
  Check.(
    (level = expected)
      int
      ~__LOC__
      ~error_msg:"Expected head level to be %R, got %L") ;
  unit

let check_known_protocols ~__LOC__ client expected_known_protocol =
  let* protocols = Client.Admin.list_protocols client in
  Check.(
    list_mem
      string
      expected_known_protocol
      protocols
      ~__LOC__
      ~error_msg:
        "Expected to find protocol hash %L to be in the list of protocols") ;
  unit

let check_understood_protocols ~__LOC__ client expected_understood_protocol =
  let* protocols = Client.list_understood_protocols client in
  Check.(
    list_mem
      string
      (String.sub expected_understood_protocol 0 12)
      protocols
      ~__LOC__
      ~error_msg:
        "Expected to find protocol hash %L to be in the list of understood \
         protocols") ;
  unit

module Demo_counter = struct
  let check_a ?__LOC__ client expected =
    let* a = Demo_client.get_a client in
    Check.((a = expected) ?__LOC__ int)
      ~error_msg:"expected amount for a = %R, got %L " ;
    unit

  let check_b ?__LOC__ client expected =
    let* b = Demo_client.get_b client in
    Check.((b = expected) ?__LOC__ int)
      ~error_msg:"expected amount for b = %R, got %L" ;
    unit

  let register () =
    Test.register ~__FILE__ ~title:"demo_counter" ~tags:["demo_counter"]
    @@ fun () ->
    let* node = Node.init [Synchronisation_threshold 0] in
    let* client = Client.init ~endpoint:(Node node) () in
    let demo_counter_hash = Protocol.demo_counter_hash in
    let* () = check_known_protocols ~__LOC__ client demo_counter_hash in
    let* () = check_understood_protocols ~__LOC__ client demo_counter_hash in
    let* () = check_protocol ~__LOC__ client Protocol.protocol_zero_hash in
    let* () = Demo_client.activate client in
    let* () = check_level ~__LOC__ client 1 in
    let* () = check_protocol ~__LOC__ client Protocol.genesis_hash in
    let* () = Demo_client.bake client ~msg:"This is block 2" in
    let* () = check_level ~__LOC__ client 2 in
    let* () = check_a ~__LOC__ client 0 in
    let* () = check_b ~__LOC__ client 0 in
    let* () = Demo_client.increment_a client in
    let* mempool = Mempool.get_mempool client in
    Check.(
      (List.length mempool.validated = 1)
        int
        ~__LOC__
        ~error_msg:"Expected %R validated operations, got %L") ;
    let* () = Demo_client.bake client in
    let* () = check_a ~__LOC__ client 1 in
    let* () = check_b ~__LOC__ client 0 in
    let* () = Demo_client.increment_a client in
    let* () = Demo_client.bake client in
    let* () = check_a ~__LOC__ client 2 in
    let* () = check_b ~__LOC__ client 0 in
    let* () = Demo_client.increment_b client in
    let* () = Demo_client.bake client in
    let* () = check_a ~__LOC__ client 2 in
    let* () = check_b ~__LOC__ client 1 in
    let* () = Demo_client.transfer client 2 in
    let* () = Demo_client.bake client in
    let* () = check_a ~__LOC__ client 0 in
    let* () = check_b ~__LOC__ client 3 in
    let* () = Demo_client.transfer client ~-1 in
    let* () = Demo_client.bake client in
    let* () = check_a ~__LOC__ client 1 in
    let* () = check_b ~__LOC__ client 2 in
    return ()
end

module Demo_noops = struct
  let forge_block_header_data (protocol_data : JSON.u) =
    match protocol_data with
    | `O [("block_header_data", `String block_header_data)] ->
        let tag = "0000" in
        let padded_hex_len =
          Printf.sprintf "%04x" (String.length block_header_data)
        in
        let block_header_data_hex =
          Hex.show (Hex.of_string block_header_data)
        in
        tag ^ padded_hex_len ^ block_header_data_hex
    | _ ->
        Test.fail
          "[forge_block_header_data] unexpected block header: %s"
          (JSON.encode_u protocol_data)

  let register () =
    Test.register ~__FILE__ ~title:"demo_noops" ~tags:["demo_noops"]
    @@ fun () ->
    let* node = Node.init [Synchronisation_threshold 0] in
    let* client = Client.init ~endpoint:(Node node) () in
    let protocol_hash = Protocol.demo_noops_hash in
    let* () = check_known_protocols ~__LOC__ client protocol_hash in
    let* () = check_protocol ~__LOC__ client Protocol.protocol_zero_hash in
    let* () =
      let parameter_file = Temp.file "demo-noops-parameters.json" in
      Base.write_file ~contents:"{}" parameter_file ;
      Client.activate_protocol_and_wait ~protocol_hash ~parameter_file client
    in
    let* () =
      check_level ~protocol_hash:Protocol.genesis_hash ~__LOC__ client 1
    in
    let* () =
      check_protocol
        ~protocol_hash:Protocol.genesis_hash
        ~__LOC__
        client
        Protocol.genesis_hash
    in
    Log.info "Forge and bake a block" ;
    let* () =
      let genesis_rpc_call =
        Client.RPC.call ~protocol_hash:Protocol.genesis_hash client
      in
      let message = "Hello world" in
      let data =
        `O
          [
            ( "protocol_data",
              `O
                [
                  ("protocol", `String protocol_hash);
                  ("block_header_data", `String message);
                ] );
            ("operations", `A []);
          ]
      in
      let* block =
        genesis_rpc_call
        @@ RPC.post_chain_block_helpers_preapply_block ~data:(Data data) ()
      in
      let protocol_data = `O [("block_header_data", `String message)] in
      let encoded = forge_block_header_data protocol_data in
      let shell_header =
        JSON.(
          block |-> "shell_header"
          |> put
               ( "protocol_data",
                 JSON.annotate ~origin:"shell_header" @@ `String encoded )
          |> unannotate)
      in
      let* encoded =
        genesis_rpc_call
        @@ RPC.post_chain_block_helpers_forge_block_header
             ~data:(Data shell_header)
             ()
      in
      let inject =
        `O
          [
            ("data", JSON.(encoded |-> "block" |> unannotate));
            ("operations", `A []);
          ]
      in
      let* (_ : JSON.t) =
        genesis_rpc_call @@ RPC.post_injection_block ~data:(Data inject)
      in
      unit
    in
    let* () =
      check_level ~protocol_hash:Protocol.genesis_hash ~__LOC__ client 2
    in
    return ()
end

let register () =
  Demo_counter.register () ;
  Demo_noops.register ()
back to top