diff --git a/devtools/get_contracts/get_contracts_alpha.ml b/devtools/get_contracts/get_contracts_alpha.ml index bf6e08d7f09211973bab31e911e172f1ee52af4f..8e71ee0d7c05ff83eac6f6d47866f2c4632a7ce3 100644 --- a/devtools/get_contracts/get_contracts_alpha.ml +++ b/devtools/get_contracts/get_contracts_alpha.ml @@ -138,8 +138,13 @@ module Proto = struct let id_to_z = Lazy_storage_kind.Big_map.Id.unparse_to_z let list_values ?offset ?length (ctxt, id) = - Lwt.map wrap_tzresult - @@ Storage.Big_map.Contents.list_values ?offset ?length (ctxt, id) + let open Lwt_result_syntax in + let* ctxt, key_values = + Lwt.map wrap_tzresult + @@ Storage.Big_map.Contents.list_key_values ?offset ?length (ctxt, id) + in + let values = List.map snd key_values in + return (ctxt, values) let get ctxt id = Lwt.map wrap_tzresult @@ Storage.Big_map.Value_type.get ctxt id diff --git a/docs/protocols/alpha.rst b/docs/protocols/alpha.rst index 7852c0bbbea151e05f9048619fafddef0823ed61..c54a78b20647acea090fcabeb14fc87bb4474fe2 100644 --- a/docs/protocols/alpha.rst +++ b/docs/protocols/alpha.rst @@ -71,3 +71,8 @@ Internal function from ``Validate_operation.TMP_for_plugin`` and to no longer expose ``apply_contents_list`` and ``apply_manager_operations`` in ``apply.mli``. (MR :gl:`!5770`) + +- Rename the function ``Big_map.list_values`` to ``list_key_values`` and make + it return a list of key-value pairs. Also change the name of the signature + ``Non_iterable_indexed_carbonated_data_storage_with_values`` to + ``Indexed_carbonated_data_storage``. (MR :gl:`!3491`) diff --git a/manifest/main.ml b/manifest/main.ml index e29faed72cf1167df8ae7bb176efa852c06e6b17..142f1fc585f61116054862f20d98940d4283e0c9 100644 --- a/manifest/main.ml +++ b/manifest/main.ml @@ -4608,7 +4608,7 @@ module Protocol = Protocol octez_base |> open_ |> open_ ~m:"TzPervasives" |> open_ ~m:"TzPervasives.Error_monad.Legacy_monad_globals"; octez_error_monad |> open_; - parameters |> if_some; + parameters |> if_some |> open_; octez_benchmark |> open_; benchmark |> if_some |> open_; benchmark_type_inference |> if_some |> open_; diff --git a/src/proto_012_Psithaca/lib_benchmarks_proto/dune b/src/proto_012_Psithaca/lib_benchmarks_proto/dune index 08b76ef44d76c498239d543b79d97846024e6944..f7f573602523668a13cef348fe34223ef606a68a 100644 --- a/src/proto_012_Psithaca/lib_benchmarks_proto/dune +++ b/src/proto_012_Psithaca/lib_benchmarks_proto/dune @@ -30,6 +30,7 @@ -open Tezos_base.TzPervasives -open Tezos_base.TzPervasives.Error_monad.Legacy_monad_globals -open Tezos_error_monad + -open Tezos_protocol_012_Psithaca_parameters -open Tezos_benchmark -open Tezos_benchmark_012_Psithaca -open Tezos_benchmark_type_inference_012_Psithaca diff --git a/src/proto_013_PtJakart/lib_benchmarks_proto/dune b/src/proto_013_PtJakart/lib_benchmarks_proto/dune index 502bf84fb185a1f204eda03e0145d44db457923f..94adeeac5821e595c6f9f622f429e71092898ed0 100644 --- a/src/proto_013_PtJakart/lib_benchmarks_proto/dune +++ b/src/proto_013_PtJakart/lib_benchmarks_proto/dune @@ -30,6 +30,7 @@ -open Tezos_base.TzPervasives -open Tezos_base.TzPervasives.Error_monad.Legacy_monad_globals -open Tezos_error_monad + -open Tezos_protocol_013_PtJakart_parameters -open Tezos_benchmark -open Tezos_benchmark_013_PtJakart -open Tezos_benchmark_type_inference_013_PtJakart diff --git a/src/proto_014_PtKathma/lib_benchmarks_proto/dune b/src/proto_014_PtKathma/lib_benchmarks_proto/dune index e7c177f8172f74f33fbad55cb74cc67bf320a1b1..e0d884826e8de6dc6b41c7e88d0a48d4fd53c745 100644 --- a/src/proto_014_PtKathma/lib_benchmarks_proto/dune +++ b/src/proto_014_PtKathma/lib_benchmarks_proto/dune @@ -30,6 +30,7 @@ -open Tezos_base.TzPervasives -open Tezos_base.TzPervasives.Error_monad.Legacy_monad_globals -open Tezos_error_monad + -open Tezos_protocol_014_PtKathma_parameters -open Tezos_benchmark -open Tezos_benchmark_014_PtKathma -open Tezos_benchmark_type_inference_014_PtKathma diff --git a/src/proto_alpha/lib_benchmarks_proto/dune b/src/proto_alpha/lib_benchmarks_proto/dune index f31b8568ca1449c8d6c9d7b685862d7c05f7eaa6..0431bf92cca9e2597665d8d36e388ba00eed04fe 100644 --- a/src/proto_alpha/lib_benchmarks_proto/dune +++ b/src/proto_alpha/lib_benchmarks_proto/dune @@ -30,6 +30,7 @@ -open Tezos_base.TzPervasives -open Tezos_base.TzPervasives.Error_monad.Legacy_monad_globals -open Tezos_error_monad + -open Tezos_protocol_alpha_parameters -open Tezos_benchmark -open Tezos_benchmark_alpha -open Tezos_benchmark_type_inference_alpha diff --git a/src/proto_alpha/lib_benchmarks_proto/storage_benchmarks.ml b/src/proto_alpha/lib_benchmarks_proto/storage_benchmarks.ml new file mode 100644 index 0000000000000000000000000000000000000000..ff55ca43fac7fb363348a34647b8f4e83f0de276 --- /dev/null +++ b/src/proto_alpha/lib_benchmarks_proto/storage_benchmarks.ml @@ -0,0 +1,239 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Trili Tech, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** {2 [Storage_functors] benchmarks}. + + This module registers a benchmark [List_key_values_benchmark]. Its result + is used to fill in the corresponding value, [list_key_values_step] + defined in [Storage_costs]. + *) + +open Tezos_benchmark +open Storage_functors +open Protocol + +(** Creates a dummy raw-context value. *) +let default_raw_context () = + let initial_accounts = + Account.generate_accounts ~initial_balances:[100_000_000_000L] 1 + in + let bootstrap_accounts = + List.map + (fun (Account.{pk; pkh; _}, amount, delegate_to) -> + Default_parameters.make_bootstrap_account (pkh, pk, amount, delegate_to)) + initial_accounts + in + Block.prepare_initial_context_params initial_accounts + >>=? fun (constants, _, _) -> + let parameters = + Default_parameters.parameters_of_constants + ~bootstrap_accounts + ~commitments:[] + constants + in + let json = Default_parameters.json_of_parameters parameters in + let proto_params = + Data_encoding.Binary.to_bytes_exn Data_encoding.json json + in + let protocol_param_key = ["protocol_parameters"] in + Tezos_protocol_environment.Context.( + let empty = Tezos_protocol_environment.Memory_context.empty in + add empty ["version"] (Bytes.of_string "genesis") >>= fun ctxt -> + add ctxt protocol_param_key proto_params) + >>= fun context -> + let typecheck ctxt script_repr = return ((script_repr, None), ctxt) in + Init_storage.prepare_first_block + Chain_id.zero + context + ~level:0l + ~timestamp:(Time.Protocol.of_seconds 1643125688L) + ~typecheck + >>= fun e -> Lwt.return @@ Environment.wrap_tzresult e + +module String = struct + type t = string + + let encoding = Data_encoding.string +end + +module Int32 = struct + type t = int32 + + let encoding = Data_encoding.int32 + + module Index = struct + type t = int + + let path_length = 1 + + let to_path c l = string_of_int c :: l + + let of_path = function + | [] | _ :: _ :: _ -> None + | [c] -> int_of_string_opt c + + type 'a ipath = 'a * t + + let args = + Storage_description.One + { + rpc_arg = Environment.RPC_arg.int; + encoding = Data_encoding.int31; + compare = Compare.Int.compare; + } + end +end + +module Root_raw_context = + Make_subcontext (Registered) (Raw_context) + (struct + let name = ["benchmark_storage_functors"] + end) + +module Indexed_context = + Make_indexed_subcontext + (Make_subcontext (Registered) (Root_raw_context) + (struct + let name = ["index"] + end)) + (Int32.Index) + +module Table = + Make_indexed_carbonated_data_storage + (Make_subcontext (Registered) (Raw_context) + (struct + let name = ["table_for_list_key_values"] + end)) + (Int32.Index) + (struct + type t = string + + let encoding = Data_encoding.string + end) + +module List_key_values_benchmark_boilerplate = struct + type config = {max_size : int} + + let name = "List_key_values" + + let info = "List key values" + + let config_encoding = + let open Data_encoding in + conv + (fun {max_size} -> max_size) + (fun max_size -> {max_size}) + (obj1 (req "max_size" int31)) + + let default_config = {max_size = 100_000} + + type workload = {size : int} + + let tags = ["big_map"] + + let workload_encoding = + let open Data_encoding in + conv (fun {size} -> size) (fun size -> {size}) (obj1 (req "size" int31)) + + let workload_to_vector {size} = + Sparse_vec.String.of_list [("size", float_of_int size)] + + let models = + [ + ( "list_key_values", + Model.make + ~conv:(fun {size} -> (size, ())) + ~model: + (Model.affine_split_const + ~intercept1:Builtin_benchmarks.timer_variable + ~intercept2:(Free_variable.of_string "list_key_values_intercept") + ~coeff:(Free_variable.of_string "list_key_values_step")) ); + ] +end + +module List_key_values_benchmark = struct + include List_key_values_benchmark_boilerplate + + let benchmark rng_state {max_size} () = + let wrap m = m >|= Environment.wrap_tzresult in + let size = + Base_samplers.sample_in_interval + ~range:{min = 1; max = max_size} + rng_state + in + let ctxt = + let fill_table = + let open Lwt_result_syntax in + let* ctxt = default_raw_context () in + List.fold_left_es + (fun ctxt (key, value) -> + let* ctxt, _, _ = wrap @@ Table.add ctxt key value in + return ctxt) + ctxt + (Stdlib.List.init size (fun key -> (key, string_of_int key))) + in + match Lwt_main.run fill_table with Ok ctxt -> ctxt | _ -> assert false + in + let workload = {size} in + let closure () = + (* We pass length [0] so that none of the steps of the fold over the + key-value pairs load any values. That is isolate the cost of iterating + over the tree without loading values. *) + Table.list_key_values ~length:0 ctxt |> Lwt_main.run |> ignore + in + Generator.Plain {workload; closure} + + let create_benchmarks ~rng_state ~bench_num config = + List.repeat bench_num (benchmark rng_state config) +end + +module List_key_values_benchmark_intercept = struct + include List_key_values_benchmark_boilerplate + + let name = name ^ "_intercept" + + let benchmark _rng_state _config () = + let ctxt = + match Lwt_main.run (default_raw_context ()) with + | Ok ctxt -> ctxt + | _ -> assert false + in + let workload = {size = 0} in + let closure () = + (* We pass length [0] so that none of the steps of the fold over the + key-value pairs load any values. That is isolate the cost of iterating + over the tree without loading values. *) + Table.list_key_values ~length:0 ctxt |> Lwt_main.run |> ignore + in + Generator.Plain {workload; closure} + + let create_benchmarks ~rng_state ~bench_num config = + List.repeat bench_num (benchmark rng_state config) +end + +let () = Registration_helpers.register (module List_key_values_benchmark) + +let () = + Registration_helpers.register (module List_key_values_benchmark_intercept) diff --git a/src/proto_alpha/lib_protocol/alpha_context.ml b/src/proto_alpha/lib_protocol/alpha_context.ml index 04b2d6c0abaeaa327f795f351068cdef9e3ade2d..e53d0fe1f178fd7ecf8037bb1291dca3b5b9c608 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.ml +++ b/src/proto_alpha/lib_protocol/alpha_context.ml @@ -375,8 +375,8 @@ module Big_map = struct let get_opt c m k = Storage.Big_map.Contents.find (c, m) k - let list_values ?offset ?length c m = - Storage.Big_map.Contents.list_values ?offset ?length (c, m) + let list_key_values ?offset ?length c m = + Storage.Big_map.Contents.list_key_values ?offset ?length (c, m) let exists c id = Raw_context.consume_gas c (Gas_limit_repr.read_bytes_cost 0) >>?= fun c -> diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index bc6330b10b0e854193870a05d16ea7d362486860..ea9b416626292e4e38811d591b9f4d7f905dd247 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -1373,21 +1373,20 @@ module Big_map : sig Id.t -> (context * (Script.expr * Script.expr) option) tzresult Lwt.t - (** [list_values ?offset ?length ctxt id] lists all values stored in big map [id]. - - The first [offset] values are ignored (if passed). Negative offsets are treated as [0]. - - There will be no more than [length] values in the result list (if passed). - Negative values are treated as [0]. - - The returned {!context} takes into account gas consumption of loading values. - *) - val list_values : + (** [list_key_values ?offset ?length ctxt id] lists the key hash and value for + each entry in big map [id]. The first [offset] values are ignored (if + passed). Negative offsets are treated as [0]. There will be no more than + [length] values in the result list (if passed). Negative values are + treated as [0]. + + The returned {!context} takes into account gas consumption of traversing + the keys and loading values. *) + val list_key_values : ?offset:int -> ?length:int -> context -> Id.t -> - (context * Script.expr list) tzresult Lwt.t + (context * (Script_expr_hash.t * Script.expr) list) tzresult Lwt.t type update = { key : Script_repr.expr; diff --git a/src/proto_alpha/lib_protocol/contract_services.ml b/src/proto_alpha/lib_protocol/contract_services.ml index 8804e19b0edc0f5131eb2be4c8cbc2bc7b392266..681d46b998495e7fd28677c4a24bac9e55d085a2 100644 --- a/src/proto_alpha/lib_protocol/contract_services.ml +++ b/src/proto_alpha/lib_protocol/contract_services.ml @@ -366,9 +366,10 @@ let register () = | Some (_, value_type) -> parse_big_map_value_ty ctxt ~legacy:true (Micheline.root value_type) >>?= fun (Ex_ty value_type, ctxt) -> - Big_map.list_values ?offset ?length ctxt id >>=? fun (ctxt, values) -> + Big_map.list_key_values ?offset ?length ctxt id + >>=? fun (ctxt, key_values) -> List.fold_left_s - (fun acc value -> + (fun acc (_key_hash, value) -> acc >>?= fun (ctxt, rev_values) -> parse_data ctxt @@ -381,7 +382,7 @@ let register () = >|=? fun (value, ctxt) -> (ctxt, Micheline.strip_locations value :: rev_values)) (Ok (ctxt, [])) - values + key_values >|=? fun (_ctxt, rev_values) -> List.rev rev_values in register_field ~chunked:false S.balance Contract.get_balance ; diff --git a/src/proto_alpha/lib_protocol/storage.ml b/src/proto_alpha/lib_protocol/storage.ml index 10f10fc1fe0d8395e91a805e85f93730fc9e6a7e..e6209b925feb1bb83c0ed39869a5b7982f6ddea2 100644 --- a/src/proto_alpha/lib_protocol/storage.ml +++ b/src/proto_alpha/lib_protocol/storage.ml @@ -516,10 +516,7 @@ module Big_map = struct let add = I.add - let list_values ?offset ?length (ctxt, id) = - let open Lwt_tzresult_syntax in - let* ctxt, values = I.list_values ?offset ?length (ctxt, id) in - return (ctxt, List.map snd values) + let list_key_values = I.list_key_values let consume_deserialize_gas ctxt value = Raw_context.consume_gas ctxt (Script_repr.deserialized_cost value) @@ -1679,7 +1676,7 @@ module Sc_rollup = struct end) let stakers (ctxt : Raw_context.t) (rollup : Sc_rollup_repr.t) = - Stakers.list_values (ctxt, rollup) + Stakers.list_key_values (ctxt, rollup) module Staker_count = Indexed_context.Make_carbonated_map diff --git a/src/proto_alpha/lib_protocol/storage.mli b/src/proto_alpha/lib_protocol/storage.mli index 3968316767d2e0446e4262625e5687aa578efa97..2af5281a4f46fbb55d9b6fa85c5aae3a3ea8bbff 100644 --- a/src/proto_alpha/lib_protocol/storage.mli +++ b/src/proto_alpha/lib_protocol/storage.mli @@ -237,12 +237,12 @@ module Big_map : sig and type value = Script_repr.expr and type t := key - (** HACK *) - val list_values : + val list_key_values : ?offset:int -> ?length:int -> Raw_context.t * id -> - (Raw_context.t * Script_repr.expr list) tzresult Lwt.t + (Raw_context.t * (Script_expr_hash.t * Script_repr.expr) list) tzresult + Lwt.t end module Total_bytes : diff --git a/src/proto_alpha/lib_protocol/storage_costs.ml b/src/proto_alpha/lib_protocol/storage_costs.ml index dae9e12456fec9eb0f2278b2a320fb05f93863ce..17c4c892acd448bf3f7e16d79963331f4d16dade 100644 --- a/src/proto_alpha/lib_protocol/storage_costs.ml +++ b/src/proto_alpha/lib_protocol/storage_costs.ml @@ -41,3 +41,17 @@ let write_access ~written_bytes = let open Saturation_repr in Gas_limit_repr.atomic_step_cost (add (safe_int 200_000) (mul (safe_int 4) (safe_int written_bytes))) + +(* TODO: https://gitlab.com/tezos/tezos/-/issues/2397 + Fill in real benchmarked values. + Benchmark defined in [Storage_benchmarks]. +*) +let list_key_values_step_cost = Saturation_repr.safe_int 117 + +let list_key_values_intercept = Saturation_repr.safe_int 470 + +let list_key_values_traverse ~size = + Saturation_repr.( + add + list_key_values_intercept + (mul (safe_int size) list_key_values_step_cost)) diff --git a/src/proto_alpha/lib_protocol/storage_costs.mli b/src/proto_alpha/lib_protocol/storage_costs.mli index 0b91ce04eaaeef355cb5c30393331439c413ccf4..8c4e4c703ea8a5ba86d2411a00bbc4ad67b253d8 100644 --- a/src/proto_alpha/lib_protocol/storage_costs.mli +++ b/src/proto_alpha/lib_protocol/storage_costs.mli @@ -28,3 +28,7 @@ val read_access : path_length:int -> read_bytes:int -> Gas_limit_repr.cost (** Cost of performing a single write access, writing [written_bytes] bytes. *) val write_access : written_bytes:int -> Gas_limit_repr.cost + +(** [list_key_values_traverse ~size] returns the cost of traversing a context + with [size] number of elements. *) +val list_key_values_traverse : size:int -> Gas_limit_repr.cost diff --git a/src/proto_alpha/lib_protocol/storage_functors.ml b/src/proto_alpha/lib_protocol/storage_functors.ml index b07dcbe31d9ed40f66ca4e3306a54f8d9c3777e7..c16ef987af57838d3ca9e2873633b98bac835b5d 100644 --- a/src/proto_alpha/lib_protocol/storage_functors.ml +++ b/src/proto_alpha/lib_protocol/storage_functors.ml @@ -357,7 +357,7 @@ module Make_indexed_carbonated_data_storage_INTERNAL (C : Raw_context.T) (I : INDEX) (V : VALUE) : - Non_iterable_indexed_carbonated_data_storage_INTERNAL + Indexed_carbonated_data_storage_INTERNAL with type t = C.t and type key = I.t and type value = V.t = struct @@ -463,18 +463,21 @@ module Make_indexed_carbonated_data_storage_INTERNAL let add_or_remove s i v = match v with None -> remove s i | Some v -> add s i v - (** Because big map values are not stored under some common key, - we have no choice but to fold over all nodes with a path of length - [I.path_length] to retrieve actual keys and then paginate. - - While this is inefficient and will traverse the whole tree ([O(n)]), there - currently isn't a better decent alternative. - - Once https://gitlab.com/tezos/tezos/-/merge_requests/2771 which flattens paths is done, - {!C.list} could be used instead here. *) - let list_values ?(offset = 0) ?(length = max_int) s = + (* TODO https://gitlab.com/tezos/tezos/-/issues/3318 + Switch implementation to use [C.list]. + Given that MR !2771 which flattens paths is done, we should use + [C.list] to avoid having to iterate over all keys when [length] and/or + [offset] is passed. + *) + let list_key_values ?(offset = 0) ?(length = max_int) s = let root = [] in let depth = `Eq I.path_length in + C.length s root >>= fun size -> + (* Regardless of the [length] argument, all elements stored in the context + are traversed. We therefore pay a gas cost proportional to the number of + elements, given by [size], upfront. We also pay gas for decoding elements + whenever they are loaded in the body of the fold. *) + C.consume_gas s (Storage_costs.list_key_values_traverse ~size) >>?= fun s -> C.fold s root @@ -496,9 +499,14 @@ module Make_indexed_carbonated_data_storage_INTERNAL match I.of_path file with | None -> assert false | Some key -> + (* This also accounts for gas for loading the element. *) get_unprojected s key >|=? fun (s, value) -> (s, (key, value) :: rev_values, 0, pred length)) - | _ -> Lwt.return acc) + | _ -> + (* Even if we run out of gas or fail in some other way, we still + traverse the whole tree. In this case there is no context to + update. *) + Lwt.return acc) >|=? fun (s, rev_values, _offset, _length) -> (C.project s, List.rev rev_values) @@ -545,7 +553,7 @@ module Make_indexed_carbonated_data_storage : functor (I : INDEX) (V : VALUE) -> - Non_iterable_indexed_carbonated_data_storage_with_values + Indexed_carbonated_data_storage with type t = C.t and type key = I.t and type value = V.t = diff --git a/src/proto_alpha/lib_protocol/storage_functors.mli b/src/proto_alpha/lib_protocol/storage_functors.mli index e83a1f9da791173b079b1700c6c97939dfbd9ac6..8ab39501caf3357ccef958c78ff1e864c70d821d 100644 --- a/src/proto_alpha/lib_protocol/storage_functors.mli +++ b/src/proto_alpha/lib_protocol/storage_functors.mli @@ -84,7 +84,7 @@ module Make_indexed_carbonated_data_storage (C : Raw_context.T) (I : INDEX) (V : VALUE) : - Non_iterable_indexed_carbonated_data_storage_with_values + Indexed_carbonated_data_storage with type t = C.t and type key = I.t and type value = V.t diff --git a/src/proto_alpha/lib_protocol/storage_sigs.ml b/src/proto_alpha/lib_protocol/storage_sigs.ml index d6c0a2886083bc6ce72bf2782e1d894fbbd7c882..206b7f7dc86e53ef3145fc5b623829cc6d7c1f27 100644 --- a/src/proto_alpha/lib_protocol/storage_sigs.ml +++ b/src/proto_alpha/lib_protocol/storage_sigs.ml @@ -215,19 +215,26 @@ module type Non_iterable_indexed_carbonated_data_storage = sig val keys_unaccounted : context -> key list Lwt.t end -module type Non_iterable_indexed_carbonated_data_storage_with_values = sig +module type Indexed_carbonated_data_storage = sig include Non_iterable_indexed_carbonated_data_storage - (* HACK *) - val list_values : + (** [list_key_values ?offset ?length storage] lists the key and value pairs of + each entry in the given [storage]. The first [offset] values are ignored + (if passed). Negative offsets are treated as [0]. There will be no more + than [length] values in the result list (if passed). Negative values are + treated as [0]. + + The returned {!context} takes into account gas consumption of traversing + the keys and loading values. *) + val list_key_values : ?offset:int -> ?length:int -> t -> (Raw_context.t * (key * value) list) tzresult Lwt.t end -module type Non_iterable_indexed_carbonated_data_storage_INTERNAL = sig - include Non_iterable_indexed_carbonated_data_storage_with_values +module type Indexed_carbonated_data_storage_INTERNAL = sig + include Indexed_carbonated_data_storage val fold_keys_unaccounted : context -> diff --git a/src/proto_alpha/lib_protocol/test/helpers/big_map_helpers.ml b/src/proto_alpha/lib_protocol/test/helpers/big_map_helpers.ml new file mode 100644 index 0000000000000000000000000000000000000000..45d025ea31dcff30207feffa8b444a06c911801a --- /dev/null +++ b/src/proto_alpha/lib_protocol/test/helpers/big_map_helpers.ml @@ -0,0 +1,74 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Trili Tech, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +let wrap m = m >|= Environment.wrap_tzresult + +let make_big_map block ~source ~key_type ~value_type key_values = + let open Lwt_result_syntax in + let key_type = Expr.from_string key_type in + let value_type = Expr.from_string value_type in + let* operation, originated = + Op.contract_origination (B block) source ~script:Op.dummy_script + in + let* block = Block.bake ~operation block in + let* incr = Incremental.begin_construction block in + let ctxt = Incremental.alpha_ctxt incr in + let* ctxt, big_map_id = wrap @@ Big_map.fresh ~temporary:false ctxt in + let* updates, ctxt = + List.fold_left_es + (fun (kvs, ctxt) (key, value) -> + let key_hash = + match + Data_encoding.Binary.to_bytes_opt Script_repr.expr_encoding key + with + | Some bytes -> Script_expr_hash.hash_bytes [bytes] + | None -> assert false + in + return ({Big_map.key; key_hash; value = Some value} :: kvs, ctxt)) + ([], ctxt) + key_values + in + let* ctxt = + wrap + (Contract.update_script_storage + ctxt + originated + key_type + (Some + [ + Lazy_storage.make + Lazy_storage.Kind.Big_map + big_map_id + (Update + { + init = Lazy_storage.Alloc Big_map.{key_type; value_type}; + updates; + }); + ])) + in + return (big_map_id, ctxt) diff --git a/src/proto_alpha/lib_protocol/test/helpers/big_map_helpers.mli b/src/proto_alpha/lib_protocol/test/helpers/big_map_helpers.mli new file mode 100644 index 0000000000000000000000000000000000000000..eca8c1dbd083b9cd5f639af9bf5327612eb01361 --- /dev/null +++ b/src/proto_alpha/lib_protocol/test/helpers/big_map_helpers.mli @@ -0,0 +1,40 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Trili Tech, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +(** [make_big_map block ~source ~key_type ~value_type key_values] constructs a + new big-map with the given key-type [key_type] and value type [value_type]. + + The big-map is owned by a new contract that is originated from [source], + with script {!Op.dummy_script}, and consists of a list of key-value pairs + according to the given [key_values] list of Micheline expressions. *) +val make_big_map : + Block.t -> + source:Alpha_context.Contract.t -> + key_type:string -> + value_type:string -> + (Script_repr.expr * Script_repr.expr) list -> + (Lazy_storage_kind.Big_map.Id.t * Alpha_context.context) tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/test/unit/test_alpha_context.ml b/src/proto_alpha/lib_protocol/test/unit/test_alpha_context.ml index ef7f84ba9a0e429cd9da6fda016f41ef05c2ff17..6a0b0a735d5e0746b528c189e76e30c96bb7affe 100644 --- a/src/proto_alpha/lib_protocol/test/unit/test_alpha_context.ml +++ b/src/proto_alpha/lib_protocol/test/unit/test_alpha_context.ml @@ -28,8 +28,9 @@ open Alpha_context (** Testing ------- - Component: Alpha_context - Invocation: dune exec ./src/proto_alpha/lib_protocol/test/unit/main.exe -- test Alpha_context + Component: Alpha_context + Invocation: dune exec ./src/proto_alpha/lib_protocol/test/unit/main.exe \ + -- test Alpha_context Dependencies: helpers/block.ml Subject: To test the modules (including the top-level) in alpha_context.ml as individual units, particularly @@ -41,6 +42,21 @@ let create () = let accounts = Account.generate_accounts 1 in Block.alpha_context accounts +let assert_equal_key_values ~loc kvs1 kvs2 = + let sort_by_key_hash = + List.sort (fun (k1, _) (k2, _) -> Script_expr_hash.compare k1 k2) + in + Assert.assert_equal_list + ~loc + (fun (k1, v1) (k2, v2) -> + Script_expr_hash.equal k1 k2 + && String.equal (Expr.to_string v1) (Expr.to_string v2)) + "Compare key-value list" + (fun fmt (k, v) -> + Format.fprintf fmt "(%a, %s)" Script_expr_hash.pp k (Expr.to_string v)) + (sort_by_key_hash kvs1) + (sort_by_key_hash kvs2) + module Test_Script = struct (** Force serialise of lazy [Big_map.t] in a given [alpha_context] *) let test_force_bytes_in_context () = @@ -104,6 +120,139 @@ module Test_Big_map = struct | Some _ -> failwith "exists should have failed looking for a non-existent big_map" | None -> return_unit + + (** Test that [Big_map.list_key_values] retrieves hashed keys and values. *) + let test_list_key_values () = + let open Lwt_result_syntax in + let* block, source = Context.init1 () in + let key_values = + [ + ("1", {|"A"|}); + ("2", {|"B"|}); + ("3", {|"C"|}); + ("4", {|"D"|}); + ("5", {|"E"|}); + ] + |> List.map (fun (k, v) -> (Expr.from_string k, Expr.from_string v)) + in + let* big_map_id, ctxt = + Big_map_helpers.make_big_map + block + ~source + ~key_type:"int" + ~value_type:"string" + key_values + in + let* _ctxt, retrieved_key_values = + Big_map.list_key_values ctxt big_map_id >|= Environment.wrap_tzresult + in + let expected_key_hash_values = + List.map + (fun (key, value) -> + let bytes = + Data_encoding.Binary.to_bytes_exn Script_repr.expr_encoding key + in + let key_hash = Script_expr_hash.hash_bytes [bytes] in + (key_hash, value)) + key_values + in + assert_equal_key_values + ~loc:__LOC__ + expected_key_hash_values + retrieved_key_values + + (** Test [Big_map.list_key_values] with [length] and [offset] arguments. *) + let test_list_key_values_parameters () = + let open Lwt_result_syntax in + let* block, source = Context.init1 () in + let hash_key key = + let bytes = + Data_encoding.Binary.to_bytes_exn Script_repr.expr_encoding key + in + Script_expr_hash.hash_bytes [bytes] + in + let check_key_values ~loc ~num_elements ?offset ?length () = + let key_values = + WithExceptions.List.init ~loc:__LOC__ num_elements (fun n -> + (string_of_int n, Printf.sprintf {|"Value %d"|} n)) + |> List.map (fun (k, v) -> (Expr.from_string k, Expr.from_string v)) + in + let sorted_key_values = + List.sort + (fun (k1, _) (k2, _) -> + Script_expr_hash.compare (hash_key k1) (hash_key k2)) + key_values + in + let* big_map_id, ctxt = + Big_map_helpers.make_big_map + block + ~source + ~key_type:"int" + ~value_type:"string" + key_values + in + let* _ctxt, retrieved_key_values = + Big_map.list_key_values ?offset ?length ctxt big_map_id + >|= Environment.wrap_tzresult + in + let expected_key_hash_values = + (* A negative length is interpreted as 0 *) + let length = + match length with + | Some l -> max l 0 + | None -> List.length sorted_key_values + in + let offset = match offset with Some o -> max o 0 | None -> 0 in + let expected = + List.take_n length @@ List.drop_n offset sorted_key_values + in + List.map + (fun (key, value) -> + let bytes = + Data_encoding.Binary.to_bytes_exn Script_repr.expr_encoding key + in + let key_hash = Script_expr_hash.hash_bytes [bytes] in + (key_hash, value)) + expected + in + let* () = + assert_equal_key_values + ~loc + retrieved_key_values + expected_key_hash_values + in + return retrieved_key_values + in + (* The following combinations should yield the same key-values. *) + let* kvs1 = check_key_values ~loc:__LOC__ ~num_elements:10 () in + let* kvs2 = check_key_values ~loc:__LOC__ ~num_elements:10 ~offset:0 () in + let* kvs3 = check_key_values ~loc:__LOC__ ~num_elements:10 ~length:10 () in + let* kvs4 = + check_key_values ~loc:__LOC__ ~num_elements:10 ~offset:0 ~length:10 () + in + let* () = assert_equal_key_values ~loc:__LOC__ kvs1 kvs2 in + let* () = assert_equal_key_values ~loc:__LOC__ kvs2 kvs3 in + let* () = assert_equal_key_values ~loc:__LOC__ kvs3 kvs4 in + (* Attempt to consume more elements then the length. *) + let* kvs1 = check_key_values ~loc:__LOC__ ~num_elements:20 () in + let* kvs2 = check_key_values ~loc:__LOC__ ~num_elements:20 ~length:100 () in + let* () = assert_equal_key_values ~loc:__LOC__ kvs1 kvs2 in + let* _ = + check_key_values ~loc:__LOC__ ~num_elements:100 ~offset:100 ~length:1 () + in + (* Offset greater than the length. *) + let* kvs = check_key_values ~loc:__LOC__ ~num_elements:10 ~offset:100 () in + let* () = assert_equal_key_values ~loc:__LOC__ kvs [] in + (* Negative length is treated as zero. *) + let* kvs = check_key_values ~loc:__LOC__ ~num_elements:10 ~length:(-1) () in + let* () = assert_equal_key_values ~loc:__LOC__ kvs [] in + (* Negative offset is treated as zero. *) + let* kvs1 = + check_key_values ~loc:__LOC__ ~num_elements:10 ~offset:(-5) () + in + let* kvs2 = check_key_values ~loc:__LOC__ ~num_elements:10 () in + let* () = assert_equal_key_values ~loc:__LOC__ kvs1 kvs2 in + return_unit end let tests = @@ -126,4 +275,12 @@ let tests = "Big_map.exists: failure case - looking up big_map that doesn't exist" `Quick Test_Big_map.test_exists; + Tztest.tztest + "Big_map.list_key_values basic tests" + `Quick + Test_Big_map.test_list_key_values; + Tztest.tztest + "Big_map.list_key_values: combinations of parameters" + `Quick + Test_Big_map.test_list_key_values_parameters; ] diff --git a/src/proto_alpha/lib_protocol/ticket_lazy_storage_diff.ml b/src/proto_alpha/lib_protocol/ticket_lazy_storage_diff.ml index b76f582767fe90f5f39cb3a5aa334aca9ebe569b..cb495f2c4f161a5e2a24eb2944a2d21dbe695d7b 100644 --- a/src/proto_alpha/lib_protocol/ticket_lazy_storage_diff.ml +++ b/src/proto_alpha/lib_protocol/ticket_lazy_storage_diff.ml @@ -208,14 +208,9 @@ let collect_token_diffs_of_big_map ctxt ~get_token_and_amount big_map_id acc = Ticket_scanner.type_has_tickets ctxt value_type >>?= fun (has_tickets, ctxt) -> (* Iterate over big-map items. *) - (* TODO: #2316 - Verify gas-model for [Big_map.list_values]. - This is to make sure that we pay sufficient gas for traversing the - values. - *) - Big_map.list_values ctxt big_map_id >>=? fun (ctxt, exprs) -> + Big_map.list_key_values ctxt big_map_id >>=? fun (ctxt, exprs) -> List.fold_left_es - (fun (acc, ctxt) node -> + (fun (acc, ctxt) (_key_hash, node) -> collect_token_diffs_of_node ctxt has_tickets diff --git a/src/proto_alpha/lib_protocol/ticket_scanner.ml b/src/proto_alpha/lib_protocol/ticket_scanner.ml index 992f01194c778d34eb29e9e6f6960e6bb0e53a52..b975e3abfc3d76eb5cd22fbeaa93631d79eafa44 100644 --- a/src/proto_alpha/lib_protocol/ticket_scanner.ml +++ b/src/proto_alpha/lib_protocol/ticket_scanner.ml @@ -526,7 +526,7 @@ module Ticket_collection = struct (* Accumulate tickets from values of the big-map stored in the context *) match id with | Some id -> - let accum (values, ctxt) exp = + let accum (values, ctxt) (_key_hash, exp) = Script_ir_translator.parse_data ~legacy:true ctxt @@ -535,7 +535,7 @@ module Ticket_collection = struct (Micheline.root exp) >|=? fun (v, ctxt) -> (v :: values, ctxt) in - Big_map.list_values ctxt id >>=? fun (ctxt, exps) -> + Big_map.list_key_values ctxt id >>=? fun (ctxt, exps) -> List.fold_left_es accum ([], ctxt) exps >>=? fun (values, ctxt) -> (tickets_of_list [@ocaml.tailcall]) ~include_lazy:true diff --git a/tests_python/contracts_alpha/mini_scenarios/receive_tickets_in_big_map.tz b/tests_python/contracts_alpha/mini_scenarios/receive_tickets_in_big_map.tz new file mode 100644 index 0000000000000000000000000000000000000000..f8af0da0173a8ed78123a365c7610bdf32c0e543 --- /dev/null +++ b/tests_python/contracts_alpha/mini_scenarios/receive_tickets_in_big_map.tz @@ -0,0 +1,3 @@ +parameter (big_map int (ticket string)); +storage (big_map int (ticket string)); +code { CAR; NIL operation ; PAIR } diff --git a/tests_python/contracts_alpha/mini_scenarios/send_tickets_in_big_map.tz b/tests_python/contracts_alpha/mini_scenarios/send_tickets_in_big_map.tz new file mode 100644 index 0000000000000000000000000000000000000000..e8c27faf309805d39b5c8948e9d67f10bbad24ac --- /dev/null +++ b/tests_python/contracts_alpha/mini_scenarios/send_tickets_in_big_map.tz @@ -0,0 +1,46 @@ +# This contract takes an address, mints 100 string tickets, puts them in a +# big-map and sends the big-map to the given address. +parameter address ; +storage unit ; +code { CAR ; + CONTRACT (big_map int (ticket string)) ; + IF_NONE + { PUSH string "Contract of type `big_map(ticket(string))` not found" ; + FAILWITH } + { EMPTY_BIG_MAP int (ticket string) ; + PUSH int 100 ; + SWAP ; + PAIR ; + LEFT (big_map int (ticket string)) ; + LOOP_LEFT + { UNPAIR ; + SWAP ; + DUP ; + DUG 2 ; + PUSH int 0 ; + COMPARE ; + LT ; + IF { PUSH int 1 ; + DUP 3 ; + SUB ; + SWAP ; + PUSH nat 1 ; + PUSH string "BLUE" ; + TICKET ; + DIG 3 ; + SWAP ; + SOME ; + SWAP ; + UPDATE ; + PAIR ; + LEFT (big_map int (ticket string)) } + { SWAP ; DROP ; RIGHT (pair (big_map int (ticket string)) int) } } ; + SWAP ; + PUSH mutez 0 ; + DIG 2 ; + TRANSFER_TOKENS ; + PUSH unit Unit ; + NIL operation ; + DIG 2 ; + CONS ; + PAIR } } diff --git a/tests_python/tests_alpha/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[client_regtest_custom_scrubber0].out b/tests_python/tests_alpha/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[client_regtest_custom_scrubber0].out index 26cbbd0594a0c02a872477c17a99099d4bd07568..6e1011f1cd578876fdcd2bf84445bdd059034479 100644 --- a/tests_python/tests_alpha/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[client_regtest_custom_scrubber0].out +++ b/tests_python/tests_alpha/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[client_regtest_custom_scrubber0].out @@ -87,10 +87,12 @@ expruBi6wgss7SRmpBCseBzcu3L283Jfx2CpUjgfuT2MgsozUsvBwt [CONTRACT_PATH]/mini_scen exprtgxcdQP1EVvEYN2BHjbqTvwzywuYAdCmnfVgeP9zcgkxUrmScN [CONTRACT_PATH]/mini_scenarios/multiple_entrypoints_counter.tz exprtzYM9ERr612k6ZBwGFJYHYcFbrG44y3KsanKg6Rz5VtEV7vUZK [CONTRACT_PATH]/mini_scenarios/originate_contract.tz exprucgYdABPRbbq2yy2rpyt4Z8fv7PN4yhkch3QYZ5QQ5ehbtNA4K [CONTRACT_PATH]/mini_scenarios/parameterized_multisig.tz +expruyXnWo3aJfqo9Z6ycLDjyJygYCeH5JUrchAfFHZcvU1ebtDBXx [CONTRACT_PATH]/mini_scenarios/receive_tickets_in_big_map.tz exprvJ8zXaBkyXMhJ2eKtPwdwbg5NLrggvW8MEpVK3hk3nAe215PQ6 [CONTRACT_PATH]/mini_scenarios/replay.tz exprtuiYUMjM6d8XxPda1yfKeN61ko6riom35PzybC31NKXkVhgBQy [CONTRACT_PATH]/mini_scenarios/reveal_signed_preimage.tz expruB4maBvk1y4JaeSLpDXWC3zKiXK5QFYv4B3R5KfdGEt4B5VvTT [CONTRACT_PATH]/mini_scenarios/self_address_receiver.tz exprvTG7hjtWXeogStj3pzM1MCVcNg1q6KnivqNVzQjviUrJvsjfQn [CONTRACT_PATH]/mini_scenarios/self_address_sender.tz +expru1Ks3BYyWcJeiRxtPC2htppzguP4vDCh5ULwtvHxD8sbP24pQb [CONTRACT_PATH]/mini_scenarios/send_tickets_in_big_map.tz expru9ASRmfbXX8Ajf5uDeiZDbNwonrCiS1e6UaDXUstKU3yuwQwdZ [CONTRACT_PATH]/mini_scenarios/ticket_builder_fungible.tz exprtXrMgaXhLsw6ioNNPThqPF1yDyLjqGdJeB6yMRKLUQZfkTD6jy [CONTRACT_PATH]/mini_scenarios/ticket_builder_non_fungible.tz expruryVEK55xjeHpeGgHjuLr9jtRS2D1gzAgYXpzGfripoX8qFhNK [CONTRACT_PATH]/mini_scenarios/ticket_wallet_fungible.tz diff --git a/tests_python/tests_alpha/_regtest_outputs/test_contract.TestSendTicketsInBigMap::test_receive_tickets_in_big_map_originate.out b/tests_python/tests_alpha/_regtest_outputs/test_contract.TestSendTicketsInBigMap::test_receive_tickets_in_big_map_originate.out new file mode 100644 index 0000000000000000000000000000000000000000..2a51b4d15277fe60ff068ef9aa73b4d20412b926 --- /dev/null +++ b/tests_python/tests_alpha/_regtest_outputs/test_contract.TestSendTicketsInBigMap::test_receive_tickets_in_big_map_originate.out @@ -0,0 +1,50 @@ +tests_alpha/test_contract.py::TestSendTicketsInBigMap::test_receive_tickets_in_big_map_originate + +Node is bootstrapped. +Estimated gas: 1411.468 units (will add 100 for safety) +Estimated storage: 340 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 1 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000435 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1512 + Storage limit: 360 bytes + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.000435 + payload fees(the block proposer) ....... +ꜩ0.000435 + Origination: + From: [CONTRACT_HASH] + Credit: ꜩ200 + Script: + { parameter (big_map int (ticket string)) ; + storage (big_map int (ticket string)) ; + code { CAR ; NIL operation ; PAIR } } + Initial storage: {} + No delegate for this contract + This origination was successfully applied + Originated contracts: + [CONTRACT_HASH] + Storage size: 83 bytes + Updated big_maps: + New map(4) of type (big_map int (ticket string)) + Paid storage size diff: 83 bytes + Consumed gas: 1411.468 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.02075 + storage fees ........................... +ꜩ0.02075 + [CONTRACT_HASH] ... -ꜩ0.06425 + storage fees ........................... +ꜩ0.06425 + [CONTRACT_HASH] ... -ꜩ200 + [CONTRACT_HASH] ... +ꜩ200 + +New contract [CONTRACT_HASH] originated. +Contract memorized as receive_tickets_in_big_map. +Injected block at minimal timestamp +[ [], [], [], [ "[BLOCK_HASH]" ] ] diff --git a/tests_python/tests_alpha/_regtest_outputs/test_contract.TestSendTicketsInBigMap::test_send_tickets_in_big_map.out b/tests_python/tests_alpha/_regtest_outputs/test_contract.TestSendTicketsInBigMap::test_send_tickets_in_big_map.out new file mode 100644 index 0000000000000000000000000000000000000000..cc140c41d588eac89b7d24db2b4f30bcb5fc7680 --- /dev/null +++ b/tests_python/tests_alpha/_regtest_outputs/test_contract.TestSendTicketsInBigMap::test_send_tickets_in_big_map.out @@ -0,0 +1,155 @@ +tests_alpha/test_contract.py::TestSendTicketsInBigMap::test_send_tickets_in_big_map + +Node is bootstrapped. +Estimated gas: 100143.097 units (will add 100 for safety) +Estimated storage: 10767 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 1 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.010321 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 100244 + Storage limit: 10787 bytes + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.010321 + payload fees(the block proposer) ....... +ꜩ0.010321 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: "[CONTRACT_HASH]" + This transaction was successfully applied + Updated storage: Unit + Updated big_maps: + New temp(1) of type (big_map int (ticket string)) + Set temp(1)[22] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[48] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[20] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[67] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[30] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[33] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[42] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[13] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[50] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[84] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[44] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[41] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[4] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[73] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[5] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[28] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[19] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[9] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[86] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[76] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[8] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[97] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[80] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[45] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[87] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[1] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[26] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[38] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[65] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[99] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[69] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[2] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[81] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[82] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[64] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[92] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[90] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[98] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[37] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[66] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[32] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[71] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[51] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[56] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[14] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[12] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[85] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[47] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[74] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[18] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[10] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[35] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[96] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[27] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[77] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[62] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[58] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[25] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[94] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[60] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[7] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[53] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[11] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[17] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[83] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[72] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[6] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[88] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[75] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[3] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[70] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[52] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[95] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[68] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[78] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[23] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[79] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[59] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[100] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[24] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[21] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[49] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[93] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[39] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[63] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[55] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[15] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[16] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[31] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[43] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[29] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[54] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[89] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[36] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[46] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[91] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[61] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[34] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[57] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Set temp(1)[40] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) + Storage size: 294 bytes + Paid storage size diff: 67 bytes + Consumed gas: 50522.278 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.01675 + storage fees ........................... +ꜩ0.01675 + Internal operations: + Internal Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: -1 + This transaction was successfully applied + Updated storage: 5 + Updated big_maps: + Clear map(4) + Copy temp(1) to map(5) + Storage size: 10783 bytes + Paid storage size diff: 10700 bytes + Consumed gas: 49620.819 + Balance updates: + [CONTRACT_HASH] ... -ꜩ2.675 + storage fees ........................... +ꜩ2.675 + +Injected block at minimal timestamp diff --git a/tests_python/tests_alpha/_regtest_outputs/test_contract.TestSendTicketsInBigMap::test_send_tickets_in_big_map_originate.out b/tests_python/tests_alpha/_regtest_outputs/test_contract.TestSendTicketsInBigMap::test_send_tickets_in_big_map_originate.out new file mode 100644 index 0000000000000000000000000000000000000000..99158ccb64d4d14c7de1a996e85089e6801d5708 --- /dev/null +++ b/tests_python/tests_alpha/_regtest_outputs/test_contract.TestSendTicketsInBigMap::test_send_tickets_in_big_map_originate.out @@ -0,0 +1,90 @@ +tests_alpha/test_contract.py::TestSendTicketsInBigMap::test_send_tickets_in_big_map_originate + +Node is bootstrapped. +Estimated gas: 1479.998 units (will add 100 for safety) +Estimated storage: 551 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 1 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000682 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1580 + Storage limit: 571 bytes + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.000682 + payload fees(the block proposer) ....... +ꜩ0.000682 + Origination: + From: [CONTRACT_HASH] + Credit: ꜩ200 + Script: + { parameter address ; + storage unit ; + code { CAR ; + CONTRACT (big_map int (ticket string)) ; + IF_NONE + { PUSH string "Contract of type `big_map(ticket(string))` not found" ; + FAILWITH } + { EMPTY_BIG_MAP int (ticket string) ; + PUSH int 100 ; + SWAP ; + PAIR ; + LEFT (big_map int (ticket string)) ; + LOOP_LEFT + { UNPAIR ; + SWAP ; + DUP ; + DUG 2 ; + PUSH int 0 ; + COMPARE ; + LT ; + IF { PUSH int 1 ; + DUP 3 ; + SUB ; + SWAP ; + PUSH nat 1 ; + PUSH string "BLUE" ; + TICKET ; + DIG 3 ; + SWAP ; + SOME ; + SWAP ; + UPDATE ; + PAIR ; + LEFT (big_map int (ticket string)) } + { SWAP ; DROP ; RIGHT (pair (big_map int (ticket string)) int) } } ; + SWAP ; + PUSH mutez 0 ; + DIG 2 ; + TRANSFER_TOKENS ; + PUSH unit Unit ; + NIL operation ; + DIG 2 ; + CONS ; + PAIR } } } + Initial storage: Unit + No delegate for this contract + This origination was successfully applied + Originated contracts: + [CONTRACT_HASH] + Storage size: 294 bytes + Paid storage size diff: 294 bytes + Consumed gas: 1479.998 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.0735 + storage fees ........................... +ꜩ0.0735 + [CONTRACT_HASH] ... -ꜩ0.06425 + storage fees ........................... +ꜩ0.06425 + [CONTRACT_HASH] ... -ꜩ200 + [CONTRACT_HASH] ... +ꜩ200 + +New contract [CONTRACT_HASH] originated. +Contract memorized as send_tickets_in_big_map. +Injected block at minimal timestamp +[ [ "[BLOCK_HASH]" ], [], [], + [ "[BLOCK_HASH]" ] ] diff --git a/tests_python/tests_alpha/_regtest_outputs/test_contract.TestTypecheck::test_typecheck[mini_scenarios--receive_tickets_in_big_map.tz].out b/tests_python/tests_alpha/_regtest_outputs/test_contract.TestTypecheck::test_typecheck[mini_scenarios--receive_tickets_in_big_map.tz].out new file mode 100644 index 0000000000000000000000000000000000000000..ee5fc76c0c4cf54a4af887de3f9c9d333da742cb --- /dev/null +++ b/tests_python/tests_alpha/_regtest_outputs/test_contract.TestTypecheck::test_typecheck[mini_scenarios--receive_tickets_in_big_map.tz].out @@ -0,0 +1,12 @@ +tests_alpha/test_contract.py::TestTypecheck::test_typecheck[mini_scenarios/receive_tickets_in_big_map.tz] + +Well typed +Gas remaining: 1039997.029 units remaining +{ parameter (big_map int (ticket string)) ; + storage (big_map int (ticket string)) ; + code { CAR + /* [ big_map int (ticket string) ] */ ; + NIL operation + /* [ list operation : big_map int (ticket string) ] */ ; + PAIR + /* [ pair (list operation) (big_map int (ticket string)) ] */ } } diff --git a/tests_python/tests_alpha/_regtest_outputs/test_contract.TestTypecheck::test_typecheck[mini_scenarios--send_tickets_in_big_map.tz].out b/tests_python/tests_alpha/_regtest_outputs/test_contract.TestTypecheck::test_typecheck[mini_scenarios--send_tickets_in_big_map.tz].out new file mode 100644 index 0000000000000000000000000000000000000000..bdfe87e4c2c8014356aa55145be8e7d3f31f34ae --- /dev/null +++ b/tests_python/tests_alpha/_regtest_outputs/test_contract.TestTypecheck::test_typecheck[mini_scenarios--send_tickets_in_big_map.tz].out @@ -0,0 +1,132 @@ +tests_alpha/test_contract.py::TestTypecheck::test_typecheck[mini_scenarios/send_tickets_in_big_map.tz] + +Well typed +Gas remaining: 1039969.352 units remaining +{ parameter address ; + storage unit ; + code { CAR + /* [ address ] */ ; + CONTRACT + (big_map int (ticket string)) + /* [ option (contract (big_map int (ticket string))) ] */ ; + IF_NONE + { PUSH string "Contract of type `big_map(ticket(string))` not found" + /* [ string ] */ ; + FAILWITH + /* [] */ } + { EMPTY_BIG_MAP + int + (ticket string) + /* [ big_map int (ticket string) : contract (big_map int (ticket string)) ] */ ; + PUSH int + 100 + /* [ int : big_map int (ticket string) + : contract (big_map int (ticket string)) ] */ ; + SWAP + /* [ big_map int (ticket string) : int + : contract (big_map int (ticket string)) ] */ ; + PAIR + /* [ pair (big_map int (ticket string)) int + : contract (big_map int (ticket string)) ] */ ; + LEFT (big_map int (ticket string)) + /* [ or (pair (big_map int (ticket string)) int) (big_map int (ticket string)) + : contract (big_map int (ticket string)) ] */ ; + LOOP_LEFT + { UNPAIR + /* [ big_map int (ticket string) : int + : contract (big_map int (ticket string)) ] */ ; + SWAP + /* [ int : big_map int (ticket string) + : contract (big_map int (ticket string)) ] */ ; + DUP + /* [ int : int : big_map int (ticket string) + : contract (big_map int (ticket string)) ] */ ; + DUG 2 + /* [ int : big_map int (ticket string) : int + : contract (big_map int (ticket string)) ] */ ; + PUSH int + 0 + /* [ int : int : big_map int (ticket string) : int + : contract (big_map int (ticket string)) ] */ ; + COMPARE + /* [ int : big_map int (ticket string) : int + : contract (big_map int (ticket string)) ] */ ; + LT + /* [ bool : big_map int (ticket string) : int + : contract (big_map int (ticket string)) ] */ ; + IF { PUSH int + 1 + /* [ int : big_map int (ticket string) : int + : contract (big_map int (ticket string)) ] */ ; + DUP 3 + /* [ int : int : big_map int (ticket string) : int + : contract (big_map int (ticket string)) ] */ ; + SUB + /* [ int : big_map int (ticket string) : int + : contract (big_map int (ticket string)) ] */ ; + SWAP + /* [ big_map int (ticket string) : int : int + : contract (big_map int (ticket string)) ] */ ; + PUSH nat + 1 + /* [ nat : big_map int (ticket string) : int : int + : contract (big_map int (ticket string)) ] */ ; + PUSH string + "BLUE" + /* [ string : nat : big_map int (ticket string) : int : int + : contract (big_map int (ticket string)) ] */ ; + TICKET + /* [ ticket string : big_map int (ticket string) : int : int + : contract (big_map int (ticket string)) ] */ ; + DIG 3 + /* [ int : ticket string : big_map int (ticket string) : int + : contract (big_map int (ticket string)) ] */ ; + SWAP + /* [ ticket string : int : big_map int (ticket string) : int + : contract (big_map int (ticket string)) ] */ ; + SOME + /* [ option (ticket string) : int : big_map int (ticket string) : int + : contract (big_map int (ticket string)) ] */ ; + SWAP + /* [ int : option (ticket string) : big_map int (ticket string) : int + : contract (big_map int (ticket string)) ] */ ; + UPDATE + /* [ big_map int (ticket string) : int + : contract (big_map int (ticket string)) ] */ ; + PAIR + /* [ pair (big_map int (ticket string)) int + : contract (big_map int (ticket string)) ] */ ; + LEFT (big_map int (ticket string)) + /* [ or (pair (big_map int (ticket string)) int) (big_map int (ticket string)) + : contract (big_map int (ticket string)) ] */ } + { SWAP + /* [ int : big_map int (ticket string) + : contract (big_map int (ticket string)) ] */ ; + DROP + /* [ big_map int (ticket string) : contract (big_map int (ticket string)) ] */ ; + RIGHT + (pair (big_map int (ticket string)) int) + /* [ or (pair (big_map int (ticket string)) int) (big_map int (ticket string)) + : contract (big_map int (ticket string)) ] */ } } + /* [ big_map int (ticket string) : contract (big_map int (ticket string)) ] */ ; + SWAP + /* [ contract (big_map int (ticket string)) : big_map int (ticket string) ] */ ; + PUSH mutez + 0 + /* [ mutez : contract (big_map int (ticket string)) + : big_map int (ticket string) ] */ ; + DIG 2 + /* [ big_map int (ticket string) : mutez + : contract (big_map int (ticket string)) ] */ ; + TRANSFER_TOKENS + /* [ operation ] */ ; + PUSH unit Unit + /* [ unit : operation ] */ ; + NIL operation + /* [ list operation : unit : operation ] */ ; + DIG 2 + /* [ operation : list operation : unit ] */ ; + CONS + /* [ list operation : unit ] */ ; + PAIR + /* [ pair (list operation) unit ] */ } } } diff --git a/tests_python/tests_alpha/test_contract.py b/tests_python/tests_alpha/test_contract.py index 6dbec261d24aa60e3c25cb0736bc74cc7437d42a..36ca7bc4df59c2dd6cd05353db5c24db5b7bb8c4 100644 --- a/tests_python/tests_alpha/test_contract.py +++ b/tests_python/tests_alpha/test_contract.py @@ -2402,3 +2402,50 @@ class TestCreateRemoveTickets: ['--entrypoint', 'add', '--arg', 'Pair 1 "C"', '--burn-cap', '2'], ) utils.bake(client, 'bootstrap5') + + +# This test originates two contracts. One for receiving a big-map with string +# tickets. Another for creating and sending a big-map with string tickets. +# Scanning the big-map for tickets uses the function [Big_map.list_key_values] +# so the regression tests include gas costs associated with calling this +# function. +@pytest.mark.incremental +@pytest.mark.contract +@pytest.mark.regression +class TestSendTicketsInBigMap: + def test_receive_tickets_in_big_map_originate( + self, client_regtest_scrubbed, session + ): + client = client_regtest_scrubbed + path = os.path.join( + CONTRACT_PATH, 'mini_scenarios', 'receive_tickets_in_big_map.tz' + ) + originate(client, session, path, '{}', 200) + session['receiver_address'] = session['contract'] + + def test_send_tickets_in_big_map_originate( + self, client_regtest_scrubbed, session + ): + client = client_regtest_scrubbed + path = os.path.join( + CONTRACT_PATH, 'mini_scenarios', 'send_tickets_in_big_map.tz' + ) + originate(client, session, path, 'Unit', 200) + + def test_send_tickets_in_big_map(self, client_regtest_scrubbed, session): + receiver_address = session['receiver_address'] + client = client_regtest_scrubbed + client.transfer( + 0, + 'bootstrap2', + 'send_tickets_in_big_map', + [ + '--arg', + f'"{receiver_address}"', + '--burn-cap', + '30', + '-storage-limit', + '1000000', + ], + ) + utils.bake(client, 'bootstrap5') diff --git a/tezt/lib_tezos/snoop.ml b/tezt/lib_tezos/snoop.ml index d874f8b5e45b60526b102a20b865d182fe223869..93fb4d6f961080792acf84120be0761c31c2ef25 100644 --- a/tezt/lib_tezos/snoop.ml +++ b/tezt/lib_tezos/snoop.ml @@ -44,6 +44,7 @@ type tag = | Carbonated_map | Tx_rollup | Tickets + | Big_map type michelson_term_kind = Data | Code @@ -350,6 +351,7 @@ let string_of_tag (tag : tag) = | Carbonated_map -> "carbonated_map" | Tx_rollup -> "tx_rollup" | Tickets -> "tickets" + | Big_map -> "big_map" let list_benchmarks_command mode tags = let tags = List.map string_of_tag tags in diff --git a/tezt/lib_tezos/snoop.mli b/tezt/lib_tezos/snoop.mli index 4ec097ed4a8c273adbb433fa6d532f442880a17c..1df7c470e7417d978863540e5dbbf8a7b1f55dcb 100644 --- a/tezt/lib_tezos/snoop.mli +++ b/tezt/lib_tezos/snoop.mli @@ -137,6 +137,7 @@ type tag = | Carbonated_map | Tx_rollup | Tickets + | Big_map type list_mode = All | Any | Exactly diff --git a/tezt/snoop/perform_benchmarks.ml b/tezt/snoop/perform_benchmarks.ml index cc43ca469f0522f5645b45dac8cd3b4b5a42bc87..75028ea5fb47647c726af9acad10a349b07ac047 100644 --- a/tezt/snoop/perform_benchmarks.ml +++ b/tezt/snoop/perform_benchmarks.ml @@ -270,6 +270,12 @@ let perform_tx_rollup_benchmarks snoop proto = in perform_benchmarks [] snoop benches +let perform_big_map_benchmarks snoop proto = + let* benches = + Snoop.(list_benchmarks ~mode:All ~tags:[Big_map; Proto proto] snoop) + in + perform_benchmarks [] snoop benches + let main protocol = Log.info "Entering Perform_inference.main" ; let snoop = Snoop.create () in @@ -281,4 +287,5 @@ let main protocol = let* () = perform_cache_benchmarks snoop in let* () = perform_encoding_benchmarks snoop protocol in let* () = perform_tx_rollup_benchmarks snoop protocol in + let* () = perform_big_map_benchmarks snoop protocol in perform_carbonated_map_benchmarks snoop protocol diff --git a/tezt/snoop/perform_inference.ml b/tezt/snoop/perform_inference.ml index 190227a9904273250692de541e01a7c6d8444f81..b6f8de0f48e3b0b74f775b3a9e096835a8c0f500 100644 --- a/tezt/snoop/perform_inference.ml +++ b/tezt/snoop/perform_inference.ml @@ -67,6 +67,7 @@ let main () = "size_collect_tickets_step_model"; "size_has_tickets_model"; "compare_tickets"; + "list_key_values"; ] in Lwt_list.iter_s