diff --git a/tezt/lib_tezos/RPC.ml b/tezt/lib_tezos/RPC.ml index 56905b373e1d4d70a9848e8d190df50744478f40..cbaf0619f1c01ebe2eb27a79c41957ee5a49eb87 100644 --- a/tezt/lib_tezos/RPC.ml +++ b/tezt/lib_tezos/RPC.ml @@ -493,6 +493,40 @@ let get_chain_block_context_constants_errors ?(chain = "main") ?(block = "head") ["chains"; chain; "blocks"; block; "context"; "constants"; "errors"] Fun.id +let get_chain_block_context_contract_storage_used_space ?(chain = "main") + ?(block = "head") contract = + make + GET + [ + "chains"; + chain; + "blocks"; + block; + "context"; + "contracts"; + contract; + "storage"; + "used_space"; + ] + JSON.as_int + +let get_chain_block_context_contract_storage_paid_space ?(chain = "main") + ?(block = "head") contract = + make + GET + [ + "chains"; + chain; + "blocks"; + block; + "context"; + "contracts"; + contract; + "storage"; + "paid_space"; + ] + JSON.as_int + let get_chain_block_helper_baking_rights ?(chain = "main") ?(block = "head") ?delegate ?level () = let query_string = diff --git a/tezt/lib_tezos/RPC.mli b/tezt/lib_tezos/RPC.mli index 26d84f7d23b9e59cba6c29ca873b38cc768cefa2..3e3c2d7f0886f4f0dbbf78542c6430bdec358d70 100644 --- a/tezt/lib_tezos/RPC.mli +++ b/tezt/lib_tezos/RPC.mli @@ -534,6 +534,22 @@ val get_chain_block_context_constants : val get_chain_block_context_constants_errors : ?chain:string -> ?block:string -> unit -> JSON.t t +(** RPC: [GET /chains//blocks//context/contracts//storage/used_space] + + [chain] defaults to ["main"]. + [block] defaults to ["head"]. +*) +val get_chain_block_context_contract_storage_used_space : + ?chain:string -> ?block:string -> string -> int t + +(** RPC: [GET /chains//blocks//context/contracts//storage/paid_space] + + [chain] defaults to ["main"]. + [block] defaults to ["head"]. +*) +val get_chain_block_context_contract_storage_paid_space : + ?chain:string -> ?block:string -> string -> int t + (** RPC: [GET /chains//blocks//helpers/baking_rights] [chain] defaults to ["main"]. diff --git a/tezt/lib_tezos/client.ml b/tezt/lib_tezos/client.ml index b21f3332f4d7905829e7cfc6c3c6e42bac61e0c6..0343dbb325c27f23875048ecfce3bde0a577f66c 100644 --- a/tezt/lib_tezos/client.ml +++ b/tezt/lib_tezos/client.ml @@ -996,13 +996,31 @@ let increase_paid_storage ?hooks ?endpoint ?(wait = "none") ~contract ~amount "of"; contract; "by"; - amount; + string_of_int amount; "bytes"; "from"; payer; ]) |> Process.check_and_read_stdout +let used_storage_space ?hooks ?endpoint ?(wait = "none") ~contract client = + spawn_command + ?hooks + ?endpoint + client + (["--wait"; wait] + @ ["get"; "contract"; "used"; "storage"; "space"; "for"; contract]) + |> Process.check_and_read_stdout + +let paid_storage_space ?hooks ?endpoint ?(wait = "none") ~contract client = + spawn_command + ?hooks + ?endpoint + client + (["--wait"; wait] + @ ["get"; "contract"; "paid"; "storage"; "space"; "for"; contract]) + |> Process.check_and_read_stdout + let update_consensus_key ?hooks ?endpoint ?(wait = "none") ?burn_cap ?expect_failure ~src ~pk client = spawn_command diff --git a/tezt/lib_tezos/client.mli b/tezt/lib_tezos/client.mli index d3c996c862af50655ec0f6140f62a59f79a8f52b..8d90dc59d9c335def636df798bb4f736be9f4e22 100644 --- a/tezt/lib_tezos/client.mli +++ b/tezt/lib_tezos/client.mli @@ -773,7 +773,7 @@ val submit_ballot : val spawn_submit_ballot : ?key:string -> ?wait:string -> proto_hash:string -> ballot -> t -> Process.t -(** Run [tezos-client set deposits limit for to ] *) +(** Run [tezos-client set deposits limit for to ]. *) val set_deposits_limit : ?hooks:Process.hooks -> ?endpoint:endpoint -> @@ -783,7 +783,7 @@ val set_deposits_limit : t -> string Lwt.t -(** Run [tezos-client unset deposits limit for ] *) +(** Run [tezos-client unset deposits limit for ]. *) val unset_deposits_limit : ?hooks:Process.hooks -> ?endpoint:endpoint -> @@ -792,17 +792,35 @@ val unset_deposits_limit : t -> string Lwt.t -(** Run [tezos-client increase the paid storage of by bytes from ] *) +(** Run [tezos-client increase the paid storage of by bytes from ]. *) val increase_paid_storage : ?hooks:Process.hooks -> ?endpoint:endpoint -> ?wait:string -> contract:string -> - amount:string -> + amount:int -> payer:string -> t -> string Lwt.t +(** Run [tezos-client get contract used storage space for ]. *) +val used_storage_space : + ?hooks:Process.hooks -> + ?endpoint:endpoint -> + ?wait:string -> + contract:string -> + t -> + string Lwt.t + +(** Run [tezos-client get contract paid storage space for ]. *) +val paid_storage_space : + ?hooks:Process.hooks -> + ?endpoint:endpoint -> + ?wait:string -> + contract:string -> + t -> + string Lwt.t + (** Run [tezos-client use as consensus key for delegate ] *) val update_consensus_key : ?hooks:Process.hooks -> @@ -833,7 +851,7 @@ val drain_delegate : [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 *) + running prg]. Returns the originated contract hash. *) val originate_contract : ?hooks:Process.hooks -> ?log_output:bool -> diff --git a/tezt/tests/increase_paid_storage.ml b/tezt/tests/increase_paid_storage.ml index 65f765bc8da88ce2c47c24da8298a23b23173ed9..b92bef6a3044bf9f19207235a91461a4bfd9c3eb 100644 --- a/tezt/tests/increase_paid_storage.ml +++ b/tezt/tests/increase_paid_storage.ml @@ -50,7 +50,7 @@ let test_increase_paid_storage = let* () = Client.bake_for_and_wait client in let payer = Constant.bootstrap2.alias in let* result = - Client.increase_paid_storage ~contract ~amount:"1000" ~payer client + Client.increase_paid_storage ~contract ~amount:1000 ~payer client in Regression.capture result ; unit diff --git a/tezt/tests/main.ml b/tezt/tests/main.ml index 361fc61fc1e1457de195778f6176deeace8ce345..1ff949c2ca80b6d61dc94ee9d4925a60156c27c1 100644 --- a/tezt/tests/main.ml +++ b/tezt/tests/main.ml @@ -154,10 +154,18 @@ let register_K_plus_tests () = Testnet_dictator.register ~protocols ; Vdf_test.register ~protocols +let register_L_plus_tests () = + (* Relies on a feature only available since L. + Move these to [register_protocol_agnostic_tests] once L is the smallest + protocol. *) + let protocols = Protocol.[Alpha] in + Used_paid_storage_spaces.register ~protocols + let () = register_protocol_independent_tests () ; register_protocol_migration_tests () ; register_protocol_agnostic_tests () ; register_K_plus_tests () ; + register_L_plus_tests () ; (* Test.run () should be the last statement, don't register afterwards! *) Test.run () diff --git a/tezt/tests/used_paid_storage_spaces.ml b/tezt/tests/used_paid_storage_spaces.ml new file mode 100644 index 0000000000000000000000000000000000000000..6bb2ac5c3281976a357728ff433cfbebe66b32be --- /dev/null +++ b/tezt/tests/used_paid_storage_spaces.ml @@ -0,0 +1,146 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 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: Used and paid storage spaces + Invocation: + dune exec tezt/tests/main.exe -- --file used_paid_storage_spaces.ml + Subject: Tests for requesting the used and paid storage spaces of a smart + contract. +*) + +(* The test will check the values of the used and paid storage spaces, coming + from the client CLI or RPC, and before/after some events on the blockchain. + We gather the values in a single structure. *) +type space_values = { + used_from_client : string; + used_from_RPC : int; + paid_from_client : string; + paid_from_RPC : int; +} + +(* Gather used and paid storage spaces for a [contract] and a [client], both as + a client CLI and an RPC. *) +let get_space_values contract client = + let call_rpc rpc = RPC.Client.call client @@ rpc contract in + let* used_from_client = Client.used_storage_space ~contract client in + let* used_from_RPC = + call_rpc RPC.get_chain_block_context_contract_storage_used_space + in + let* paid_from_client = Client.paid_storage_space ~contract client in + let* paid_from_RPC = + call_rpc RPC.get_chain_block_context_contract_storage_paid_space + in + Lwt.return {used_from_client; used_from_RPC; paid_from_client; paid_from_RPC} + +(* We'll read the output of the client CLI and RPC for used/paid storage spaces. + One will return an integer as a string, the other one an OCamlinteger. +*) +type space_result = Client of string | RPC of int + +(* [check level kind size ~initial_size ~increase] checks that a [kind] + of storage space has indeed the correct [size], depending on the + [initial_size] of the storage space and on the [level] at which the size was + requested relatively to an [increase] of this storage space. *) +let check (level : [`Before | `After]) (kind : [`Used | `Paid]) + (size : space_result) ~initial_size ~increase = + let increase = + match (level, kind) with + | `Before, _ | _, `Used -> 0 + | `After, `Paid -> increase + in + let level = match level with `Before -> "initial" | `After -> "new" in + let kind = match kind with `Used -> "used" | `Paid -> "paid" in + let source, value = + match size with + | Client value -> ("client CLI", int_of_string (String.trim value)) + | RPC value -> ("RPC", value) + in + Check.(value = initial_size + increase) + Check.int + ~error_msg: + ("Unexpected " ^ level ^ " " ^ kind ^ " storage space from the " ^ source + ^ ". Expected %R. Got %L") + +(* The test consists in: + 1. originating a smart contract; + 2. storing its used and paid storage spaces from client CLI and RPC; + 3. increase its paid storage space; + 4. storing the new values for the used and paid storage spaces from client + CLI and RPC; + 5. checking all the values. *) +let test_increase_paid_storage = + Protocol.register_test + ~__FILE__ + ~title:"used and paid storage spaces" + ~tags:["storage"; "used_storage"; "paid_storage"] + ~supports:(Protocol.From_protocol 015) + @@ fun protocol -> + (* 1. Originate the smart contract. We arbitrarily picked an existing file. *) + let* _, client = Client.init_with_protocol ~protocol `Client () in + let* contract = + Client.originate_contract + ~alias:"originated_contract_simple" + ~amount:Tez.zero + ~src:"bootstrap1" + ~prg:"file:./tezt/tests/contracts/proto_alpha/str_id.tz" + ~init:"Some \"initial storage\"" + ~burn_cap:Tez.(of_int 3) + client + in + let* () = Client.bake_for_and_wait client in + + (* 2. Storing the used and paid storage spaces from client CLI and RPC. *) + let* before = get_space_values contract client in + + (* 3. Increase the paid storage space. *) + let increase = 100 in + let amount = increase in + let payer = Constant.bootstrap1.alias in + let* _ = Client.increase_paid_storage ~contract ~amount ~payer client in + let* () = Client.bake_for_and_wait client in + + (* 4. Storing the new values for the used and paid storage spaces from client + CLI and RPC. *) + let* after = get_space_values contract client in + + (* 5. Checking all the values. *) + (* 62 is the initial storage space after origination, obtained by testing it. + We don't question this value here, it's the purpose of unit tests. *) + let check = check ~initial_size:62 ~increase in + check `Before `Used (Client before.used_from_client) ; + check `Before `Used (RPC before.used_from_RPC) ; + check `Before `Paid (Client before.paid_from_client) ; + check `Before `Paid (RPC before.paid_from_RPC) ; + + check `After `Used (Client after.used_from_client) ; + check `After `Used (RPC after.used_from_RPC) ; + check `After `Paid (Client after.paid_from_client) ; + check `After `Paid (RPC after.paid_from_RPC) ; + + unit + +let register ~protocols = test_increase_paid_storage protocols